rippled
Loading...
Searching...
No Matches
SHAMapStore_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2015 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <test/jtx.h>
21#include <test/jtx/envconfig.h>
22#include <xrpld/app/main/Application.h>
23#include <xrpld/app/main/NodeStoreScheduler.h>
24#include <xrpld/app/misc/SHAMapStore.h>
25#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
26#include <xrpld/core/ConfigSections.h>
27#include <xrpld/nodestore/detail/DatabaseRotatingImp.h>
28#include <xrpl/protocol/jss.h>
29
30namespace ripple {
31namespace test {
32
34{
35 static auto const deleteInterval = 8;
36
37 static auto
39 {
40 cfg->LEDGER_HISTORY = deleteInterval;
41 auto& section = cfg->section(ConfigSection::nodeDatabase());
42 section.set("online_delete", std::to_string(deleteInterval));
43 return cfg;
44 }
45
46 static auto
48 {
49 cfg = onlineDelete(std::move(cfg));
50 cfg->section(ConfigSection::nodeDatabase()).set("advisory_delete", "1");
51 return cfg;
52 }
53
54 bool
56 jtx::Env& env,
57 Json::Value const& json,
58 std::string ledgerID,
59 bool checkDB = false)
60 {
61 auto good = json.isMember(jss::result) &&
62 !RPC::contains_error(json[jss::result]) &&
63 json[jss::result][jss::ledger][jss::ledger_index] == ledgerID;
64 if (!good || !checkDB)
65 return good;
66
67 auto const seq = json[jss::result][jss::ledger_index].asUInt();
68
71 if (!oinfo)
72 return false;
73 const LedgerInfo& info = oinfo.value();
74
75 const std::string outHash = to_string(info.hash);
76 const LedgerIndex outSeq = info.seq;
77 const std::string outParentHash = to_string(info.parentHash);
78 const std::string outDrops = to_string(info.drops);
79 const std::uint64_t outCloseTime =
80 info.closeTime.time_since_epoch().count();
81 const std::uint64_t outParentCloseTime =
82 info.parentCloseTime.time_since_epoch().count();
83 const std::uint64_t outCloseTimeResolution =
85 const std::uint64_t outCloseFlags = info.closeFlags;
86 const std::string outAccountHash = to_string(info.accountHash);
87 const std::string outTxHash = to_string(info.txHash);
88
89 auto const& ledger = json[jss::result][jss::ledger];
90 return outHash == ledger[jss::ledger_hash].asString() &&
91 outSeq == seq &&
92 outParentHash == ledger[jss::parent_hash].asString() &&
93 outDrops == ledger[jss::total_coins].asString() &&
94 outCloseTime == ledger[jss::close_time].asUInt() &&
95 outParentCloseTime == ledger[jss::parent_close_time].asUInt() &&
96 outCloseTimeResolution ==
97 ledger[jss::close_time_resolution].asUInt() &&
98 outCloseFlags == ledger[jss::close_flags].asUInt() &&
99 outAccountHash == ledger[jss::account_hash].asString() &&
100 outTxHash == ledger[jss::transaction_hash].asString();
101 }
102
103 bool
105 {
106 return json.isMember(jss::result) &&
107 RPC::contains_error(json[jss::result]) &&
108 json[jss::result][jss::error_code] == error;
109 }
110
113 {
114 BEAST_EXPECT(
115 json.isMember(jss::result) &&
116 json[jss::result].isMember(jss::ledger) &&
117 json[jss::result][jss::ledger].isMember(jss::ledger_hash) &&
118 json[jss::result][jss::ledger][jss::ledger_hash].isString());
119 return json[jss::result][jss::ledger][jss::ledger_hash].asString();
120 }
121
122 void
123 ledgerCheck(jtx::Env& env, int const rows, int const first)
124 {
125 const auto [actualRows, actualFirst, actualLast] =
126 dynamic_cast<SQLiteDatabase*>(&env.app().getRelationalDatabase())
127 ->getLedgerCountMinMax();
128
129 BEAST_EXPECT(actualRows == rows);
130 BEAST_EXPECT(actualFirst == first);
131 BEAST_EXPECT(actualLast == first + rows - 1);
132 }
133
134 void
135 transactionCheck(jtx::Env& env, int const rows)
136 {
137 BEAST_EXPECT(
138 dynamic_cast<SQLiteDatabase*>(&env.app().getRelationalDatabase())
139 ->getTransactionCount() == rows);
140 }
141
142 void
143 accountTransactionCheck(jtx::Env& env, int const rows)
144 {
145 BEAST_EXPECT(
146 dynamic_cast<SQLiteDatabase*>(&env.app().getRelationalDatabase())
147 ->getAccountTransactionCount() == rows);
148 }
149
150 int
152 {
153 using namespace std::chrono_literals;
154
155 auto& store = env.app().getSHAMapStore();
156
157 int ledgerSeq = 3;
158 store.rendezvous();
159 BEAST_EXPECT(!store.getLastRotated());
160
161 env.close();
162 store.rendezvous();
163
164 auto ledger = env.rpc("ledger", "validated");
165 BEAST_EXPECT(goodLedger(env, ledger, std::to_string(ledgerSeq++)));
166
167 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
168 return ledgerSeq;
169 }
170
171public:
172 void
174 {
175 using namespace std::chrono_literals;
176
177 testcase("clearPrior");
178 using namespace jtx;
179
180 Env env(*this, envconfig(onlineDelete));
181
182 auto& store = env.app().getSHAMapStore();
183 env.fund(XRP(10000), noripple("alice"));
184
185 ledgerCheck(env, 1, 2);
186 transactionCheck(env, 0);
188
190
191 auto ledgerTmp = env.rpc("ledger", "0");
192 BEAST_EXPECT(bad(ledgerTmp));
193
194 ledgers.emplace(std::make_pair(1, env.rpc("ledger", "1")));
195 BEAST_EXPECT(goodLedger(env, ledgers[1], "1"));
196
197 ledgers.emplace(std::make_pair(2, env.rpc("ledger", "2")));
198 BEAST_EXPECT(goodLedger(env, ledgers[2], "2"));
199
200 ledgerTmp = env.rpc("ledger", "current");
201 BEAST_EXPECT(goodLedger(env, ledgerTmp, "3"));
202
203 ledgerTmp = env.rpc("ledger", "4");
204 BEAST_EXPECT(bad(ledgerTmp));
205
206 ledgerTmp = env.rpc("ledger", "100");
207 BEAST_EXPECT(bad(ledgerTmp));
208
209 auto const firstSeq = waitForReady(env);
210 auto lastRotated = firstSeq - 1;
211
212 for (auto i = firstSeq + 1; i < deleteInterval + firstSeq; ++i)
213 {
214 env.fund(XRP(10000), noripple("test" + std::to_string(i)));
215 env.close();
216
217 ledgerTmp = env.rpc("ledger", "current");
218 BEAST_EXPECT(goodLedger(env, ledgerTmp, std::to_string(i)));
219 }
220 BEAST_EXPECT(store.getLastRotated() == lastRotated);
221
222 for (auto i = 3; i < deleteInterval + lastRotated; ++i)
223 {
224 ledgers.emplace(
225 std::make_pair(i, env.rpc("ledger", std::to_string(i))));
226 BEAST_EXPECT(
227 goodLedger(env, ledgers[i], std::to_string(i), true) &&
228 getHash(ledgers[i]).length());
229 }
230
231 ledgerCheck(env, deleteInterval + 1, 2);
234
235 {
236 // Closing one more ledger triggers a rotate
237 env.close();
238
239 auto ledger = env.rpc("ledger", "current");
240 BEAST_EXPECT(
241 goodLedger(env, ledger, std::to_string(deleteInterval + 4)));
242 }
243
244 store.rendezvous();
245
246 BEAST_EXPECT(store.getLastRotated() == deleteInterval + 3);
247 lastRotated = store.getLastRotated();
248 BEAST_EXPECT(lastRotated == 11);
249
250 // That took care of the fake hashes
251 ledgerCheck(env, deleteInterval + 1, 3);
254
255 // The last iteration of this loop should trigger a rotate
256 for (auto i = lastRotated - 1; i < lastRotated + deleteInterval - 1;
257 ++i)
258 {
259 env.close();
260
261 ledgerTmp = env.rpc("ledger", "current");
262 BEAST_EXPECT(goodLedger(env, ledgerTmp, std::to_string(i + 3)));
263
264 ledgers.emplace(
265 std::make_pair(i, env.rpc("ledger", std::to_string(i))));
266 BEAST_EXPECT(
267 store.getLastRotated() == lastRotated ||
268 i == lastRotated + deleteInterval - 2);
269 BEAST_EXPECT(
270 goodLedger(env, ledgers[i], std::to_string(i), true) &&
271 getHash(ledgers[i]).length());
272 }
273
274 store.rendezvous();
275
276 BEAST_EXPECT(store.getLastRotated() == deleteInterval + lastRotated);
277
278 ledgerCheck(env, deleteInterval + 1, lastRotated);
279 transactionCheck(env, 0);
281 }
282
283 void
285 {
286 testcase("automatic online_delete");
287 using namespace jtx;
288 using namespace std::chrono_literals;
289
290 Env env(*this, envconfig(onlineDelete));
291 auto& store = env.app().getSHAMapStore();
292
293 auto ledgerSeq = waitForReady(env);
294 auto lastRotated = ledgerSeq - 1;
295 BEAST_EXPECT(store.getLastRotated() == lastRotated);
296 BEAST_EXPECT(lastRotated != 2);
297
298 // Because advisory_delete is unset,
299 // "can_delete" is disabled.
300 auto const canDelete = env.rpc("can_delete");
301 BEAST_EXPECT(bad(canDelete, rpcNOT_ENABLED));
302
303 // Close ledgers without triggering a rotate
304 for (; ledgerSeq < lastRotated + deleteInterval; ++ledgerSeq)
305 {
306 env.close();
307
308 auto ledger = env.rpc("ledger", "validated");
309 BEAST_EXPECT(
310 goodLedger(env, ledger, std::to_string(ledgerSeq), true));
311 }
312
313 store.rendezvous();
314
315 // The database will always have back to ledger 2,
316 // regardless of lastRotated.
317 ledgerCheck(env, ledgerSeq - 2, 2);
318 BEAST_EXPECT(lastRotated == store.getLastRotated());
319
320 {
321 // Closing one more ledger triggers a rotate
322 env.close();
323
324 auto ledger = env.rpc("ledger", "validated");
325 BEAST_EXPECT(
326 goodLedger(env, ledger, std::to_string(ledgerSeq++), true));
327 }
328
329 store.rendezvous();
330
331 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
332 BEAST_EXPECT(lastRotated != store.getLastRotated());
333
334 lastRotated = store.getLastRotated();
335
336 // Close enough ledgers to trigger another rotate
337 for (; ledgerSeq < lastRotated + deleteInterval + 1; ++ledgerSeq)
338 {
339 env.close();
340
341 auto ledger = env.rpc("ledger", "validated");
342 BEAST_EXPECT(
343 goodLedger(env, ledger, std::to_string(ledgerSeq), true));
344 }
345
346 store.rendezvous();
347
348 ledgerCheck(env, deleteInterval + 1, lastRotated);
349 BEAST_EXPECT(lastRotated != store.getLastRotated());
350 }
351
352 void
354 {
355 testcase("online_delete with advisory_delete");
356 using namespace jtx;
357 using namespace std::chrono_literals;
358
359 // Same config with advisory_delete enabled
360 Env env(*this, envconfig(advisoryDelete));
361 auto& store = env.app().getSHAMapStore();
362
363 auto ledgerSeq = waitForReady(env);
364 auto lastRotated = ledgerSeq - 1;
365 BEAST_EXPECT(store.getLastRotated() == lastRotated);
366 BEAST_EXPECT(lastRotated != 2);
367
368 auto canDelete = env.rpc("can_delete");
369 BEAST_EXPECT(!RPC::contains_error(canDelete[jss::result]));
370 BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == 0);
371
372 canDelete = env.rpc("can_delete", "never");
373 BEAST_EXPECT(!RPC::contains_error(canDelete[jss::result]));
374 BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == 0);
375
376 auto const firstBatch = deleteInterval + ledgerSeq;
377 for (; ledgerSeq < firstBatch; ++ledgerSeq)
378 {
379 env.close();
380
381 auto ledger = env.rpc("ledger", "validated");
382 BEAST_EXPECT(
383 goodLedger(env, ledger, std::to_string(ledgerSeq), true));
384 }
385
386 store.rendezvous();
387
388 ledgerCheck(env, ledgerSeq - 2, 2);
389 BEAST_EXPECT(lastRotated == store.getLastRotated());
390
391 // This does not kick off a cleanup
392 canDelete = env.rpc(
393 "can_delete", std::to_string(ledgerSeq + deleteInterval / 2));
394 BEAST_EXPECT(!RPC::contains_error(canDelete[jss::result]));
395 BEAST_EXPECT(
396 canDelete[jss::result][jss::can_delete] ==
397 ledgerSeq + deleteInterval / 2);
398
399 store.rendezvous();
400
401 ledgerCheck(env, ledgerSeq - 2, 2);
402 BEAST_EXPECT(store.getLastRotated() == lastRotated);
403
404 {
405 // This kicks off a cleanup, but it stays small.
406 env.close();
407
408 auto ledger = env.rpc("ledger", "validated");
409 BEAST_EXPECT(
410 goodLedger(env, ledger, std::to_string(ledgerSeq++), true));
411 }
412
413 store.rendezvous();
414
415 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
416
417 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
418 lastRotated = ledgerSeq - 1;
419
420 for (; ledgerSeq < lastRotated + deleteInterval; ++ledgerSeq)
421 {
422 // No cleanups in this loop.
423 env.close();
424
425 auto ledger = env.rpc("ledger", "validated");
426 BEAST_EXPECT(
427 goodLedger(env, ledger, std::to_string(ledgerSeq), true));
428 }
429
430 store.rendezvous();
431
432 BEAST_EXPECT(store.getLastRotated() == lastRotated);
433
434 {
435 // This kicks off another cleanup.
436 env.close();
437
438 auto ledger = env.rpc("ledger", "validated");
439 BEAST_EXPECT(
440 goodLedger(env, ledger, std::to_string(ledgerSeq++), true));
441 }
442
443 store.rendezvous();
444
445 ledgerCheck(env, ledgerSeq - firstBatch, firstBatch);
446
447 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
448 lastRotated = ledgerSeq - 1;
449
450 // This does not kick off a cleanup
451 canDelete = env.rpc("can_delete", "always");
452 BEAST_EXPECT(!RPC::contains_error(canDelete[jss::result]));
453 BEAST_EXPECT(
454 canDelete[jss::result][jss::can_delete] ==
456
457 for (; ledgerSeq < lastRotated + deleteInterval; ++ledgerSeq)
458 {
459 // No cleanups in this loop.
460 env.close();
461
462 auto ledger = env.rpc("ledger", "validated");
463 BEAST_EXPECT(
464 goodLedger(env, ledger, std::to_string(ledgerSeq), true));
465 }
466
467 store.rendezvous();
468
469 BEAST_EXPECT(store.getLastRotated() == lastRotated);
470
471 {
472 // This kicks off another cleanup.
473 env.close();
474
475 auto ledger = env.rpc("ledger", "validated");
476 BEAST_EXPECT(
477 goodLedger(env, ledger, std::to_string(ledgerSeq++), true));
478 }
479
480 store.rendezvous();
481
482 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
483
484 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
485 lastRotated = ledgerSeq - 1;
486
487 // This does not kick off a cleanup
488 canDelete = env.rpc("can_delete", "now");
489 BEAST_EXPECT(!RPC::contains_error(canDelete[jss::result]));
490 BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == ledgerSeq - 1);
491
492 for (; ledgerSeq < lastRotated + deleteInterval; ++ledgerSeq)
493 {
494 // No cleanups in this loop.
495 env.close();
496
497 auto ledger = env.rpc("ledger", "validated");
498 BEAST_EXPECT(
499 goodLedger(env, ledger, std::to_string(ledgerSeq), true));
500 }
501
502 store.rendezvous();
503
504 BEAST_EXPECT(store.getLastRotated() == lastRotated);
505
506 {
507 // This kicks off another cleanup.
508 env.close();
509
510 auto ledger = env.rpc("ledger", "validated");
511 BEAST_EXPECT(
512 goodLedger(env, ledger, std::to_string(ledgerSeq++), true));
513 }
514
515 store.rendezvous();
516
517 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
518
519 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
520 lastRotated = ledgerSeq - 1;
521 }
522
525 jtx::Env& env,
526 NodeStoreScheduler& scheduler,
528 {
529 Section section{
531 boost::filesystem::path newPath;
532
533 if (!BEAST_EXPECT(path.size()))
534 return {};
535 newPath = path;
536 section.set("path", newPath.string());
537
539 section,
541 SizedItem::burstSize, std::nullopt)),
542 scheduler,
543 env.app().logs().journal("NodeStoreTest"))};
544 backend->open();
545 return backend;
546 }
547
548 void
550 {
551 // The only purpose of this test is to ensure that if something that
552 // should never happen happens, we don't get a deadlock.
553 testcase("rotate with lock contention");
554
555 using namespace jtx;
556 Env env(*this, envconfig(onlineDelete));
557
559 // Create the backend. Normally, SHAMapStoreImp handles all these
560 // details
561 auto nscfg = env.app().config().section(ConfigSection::nodeDatabase());
562
563 // Provide default values:
564 if (!nscfg.exists("cache_size"))
565 nscfg.set(
566 "cache_size",
568 SizedItem::treeCacheSize, std::nullopt)));
569
570 if (!nscfg.exists("cache_age"))
571 nscfg.set(
572 "cache_age",
574 SizedItem::treeCacheAge, std::nullopt)));
575
576 NodeStoreScheduler scheduler(env.app().getJobQueue());
577
578 std::string const writableDb = "write";
579 std::string const archiveDb = "archive";
580 auto writableBackend = makeBackendRotating(env, scheduler, writableDb);
581 auto archiveBackend = makeBackendRotating(env, scheduler, archiveDb);
582
583 // Create NodeStore with two backends to allow online deletion of
584 // data
585 constexpr int readThreads = 4;
586 auto dbr = std::make_unique<NodeStore::DatabaseRotatingImp>(
587 scheduler,
588 readThreads,
589 std::move(writableBackend),
590 std::move(archiveBackend),
591 nscfg,
592 env.app().logs().journal("NodeStoreTest"));
593
595 // Check basic functionality
596 using namespace std::chrono_literals;
597 std::atomic<int> threadNum = 0;
598
599 {
600 auto newBackend = makeBackendRotating(
601 env, scheduler, std::to_string(++threadNum));
602
603 auto const cb = [&](std::string const& writableName,
604 std::string const& archiveName) {
605 BEAST_EXPECT(writableName == "1");
606 BEAST_EXPECT(archiveName == "write");
607 // Ensure that dbr functions can be called from within the
608 // callback
609 BEAST_EXPECT(dbr->getName() == "1");
610 };
611
612 dbr->rotate(std::move(newBackend), cb);
613 }
614 BEAST_EXPECT(threadNum == 1);
615 BEAST_EXPECT(dbr->getName() == "1");
616
618 // Do something stupid. Try to re-enter rotate from inside the callback.
619 {
620 auto const cb = [&](std::string const& writableName,
621 std::string const& archiveName) {
622 BEAST_EXPECT(writableName == "3");
623 BEAST_EXPECT(archiveName == "2");
624 // Ensure that dbr functions can be called from within the
625 // callback
626 BEAST_EXPECT(dbr->getName() == "3");
627 };
628 auto const cbReentrant = [&](std::string const& writableName,
629 std::string const& archiveName) {
630 BEAST_EXPECT(writableName == "2");
631 BEAST_EXPECT(archiveName == "1");
632 auto newBackend = makeBackendRotating(
633 env, scheduler, std::to_string(++threadNum));
634 // Reminder: doing this is stupid and should never happen
635 dbr->rotate(std::move(newBackend), cb);
636 };
637 auto newBackend = makeBackendRotating(
638 env, scheduler, std::to_string(++threadNum));
639 dbr->rotate(std::move(newBackend), cbReentrant);
640 }
641
642 BEAST_EXPECT(threadNum == 3);
643 BEAST_EXPECT(dbr->getName() == "3");
644 }
645
646 void
647 run() override
648 {
649 testClear();
652 testRotate();
653 }
654};
655
656// VFALCO This test fails because of thread asynchronous issues
657BEAST_DEFINE_TESTSUITE(SHAMapStore, app, ripple);
658
659} // namespace test
660} // namespace ripple
Represents a JSON value.
Definition: json_value.h:147
A testsuite class.
Definition: suite.h:53
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:153
virtual Config & config()=0
virtual SHAMapStore & getSHAMapStore()=0
virtual JobQueue & getJobQueue()=0
virtual RelationalDatabase & getRelationalDatabase()=0
virtual Logs & logs()=0
Section & section(std::string const &name)
Returns the section with the given name.
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
Definition: Config.cpp:1077
beast::Journal journal(std::string const &name)
Definition: Log.cpp:144
A NodeStore::Scheduler which uses the JobQueue.
virtual std::unique_ptr< Backend > make_Backend(Section const &parameters, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal)=0
Create a backend.
static Manager & instance()
Returns the instance of the manager singleton.
Definition: ManagerImp.cpp:116
virtual std::optional< LedgerInfo > getLedgerInfoByIndex(LedgerIndex ledgerSeq)=0
getLedgerInfoByIndex Returns a ledger by its sequence.
class to create database, launch online delete thread, and related SQLite database
Definition: SHAMapStore.h:37
virtual void rendezvous() const =0
virtual std::size_t getAccountTransactionCount()=0
getAccountTransactionCount Returns the number of account transactions.
virtual std::size_t getTransactionCount()=0
getTransactionCount Returns the number of transactions.
Holds a collection of configuration values.
Definition: BasicConfig.h:46
void set(std::string const &key, std::string const &value)
Set a key/value pair.
Definition: BasicConfig.cpp:32
void ledgerCheck(jtx::Env &env, int const rows, int const first)
std::string getHash(Json::Value const &json)
static auto advisoryDelete(std::unique_ptr< Config > cfg)
bool bad(Json::Value const &json, error_code_i error=rpcLGR_NOT_FOUND)
void run() override
Runs the suite.
void accountTransactionCheck(jtx::Env &env, int const rows)
static auto onlineDelete(std::unique_ptr< Config > cfg)
std::unique_ptr< NodeStore::Backend > makeBackendRotating(jtx::Env &env, NodeStoreScheduler &scheduler, std::string path)
void transactionCheck(jtx::Env &env, int const rows)
bool goodLedger(jtx::Env &env, Json::Value const &json, std::string ledgerID, bool checkDB=false)
A transaction testing environment.
Definition: Env.h:117
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
Application & app()
Definition: Env.h:255
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:764
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:237
Inject raw JSON.
Definition: jtx_json.h:32
Add a path.
Definition: paths.h:56
T emplace(T... args)
T make_pair(T... args)
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:197
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:54
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition: amount.cpp:104
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
constexpr auto megabytes(T value) noexcept
Definition: ByteUtilities.h:34
error_code_i
Definition: ErrorCodes.h:40
@ rpcLGR_NOT_FOUND
Definition: ErrorCodes.h:72
@ rpcNOT_ENABLED
Definition: ErrorCodes.h:59
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:629
static std::string nodeDatabase()
Information about the notional ledger backing the view.
Definition: LedgerHeader.h:34
NetClock::time_point closeTime
Definition: LedgerHeader.h:72
NetClock::duration closeTimeResolution
Definition: LedgerHeader.h:66
NetClock::time_point parentCloseTime
Definition: LedgerHeader.h:42
Set the sequence number on a JTx.
Definition: seq.h:34
T time_since_epoch(T... args)
T to_string(T... args)
T value(T... args)