1#include <test/jtx/Env.h>
2#include <test/jtx/amount.h>
3#include <test/jtx/envconfig.h>
5#include <xrpld/app/main/Application.h>
6#include <xrpld/app/main/NodeStoreScheduler.h>
7#include <xrpld/app/misc/SHAMapStore.h>
8#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
9#include <xrpld/core/Config.h>
11#include <xrpl/basics/ByteUtilities.h>
12#include <xrpl/basics/base_uint.h>
13#include <xrpl/beast/unit_test/suite.h>
14#include <xrpl/config/BasicConfig.h>
15#include <xrpl/config/Constants.h>
16#include <xrpl/json/json_value.h>
17#include <xrpl/nodestore/Backend.h>
18#include <xrpl/nodestore/detail/DatabaseRotatingImp.h>
19#include <xrpl/protocol/ErrorCodes.h>
20#include <xrpl/protocol/LedgerHeader.h>
21#include <xrpl/protocol/Protocol.h>
22#include <xrpl/protocol/XRPAmount.h>
23#include <xrpl/protocol/jss.h>
25#include <boost/filesystem/path.hpp>
63 json[jss::result][jss::ledger][jss::ledger_index] == ledgerID;
64 if (!good || !checkDB)
67 auto const seq =
json[jss::result][jss::ledger_index].asUInt();
86 auto const& ledger =
json[jss::result][jss::ledger];
87 return outHash == ledger[jss::ledger_hash].asString() && outSeq == seq &&
88 outParentHash == ledger[jss::parent_hash].asString() &&
89 outDrops == ledger[jss::total_coins].asString() &&
90 outCloseTime == ledger[jss::close_time].asUInt() &&
91 outParentCloseTime == ledger[jss::parent_close_time].asUInt() &&
92 outCloseTimeResolution == ledger[jss::close_time_resolution].asUInt() &&
93 outCloseFlags == ledger[jss::close_flags].asUInt() &&
94 outAccountHash == ledger[jss::account_hash].asString() &&
95 outTxHash == ledger[jss::transaction_hash].asString();
102 json[jss::result][jss::error_code] == error;
109 json.isMember(jss::result) &&
json[jss::result].isMember(jss::ledger) &&
110 json[jss::result][jss::ledger].isMember(jss::ledger_hash) &&
111 json[jss::result][jss::ledger][jss::ledger_hash].isString());
112 return json[jss::result][jss::ledger][jss::ledger_hash].asString();
118 auto const [actualRows, actualFirst, actualLast] =
121 BEAST_EXPECT(actualRows == rows);
122 BEAST_EXPECT(actualFirst == first);
123 BEAST_EXPECT(actualLast == first + rows - 1);
141 using namespace std::chrono_literals;
147 BEAST_EXPECT(!store.getLastRotated());
152 auto ledger = env.
rpc(
"ledger",
"validated");
155 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
163 using namespace std::chrono_literals;
179 auto ledgerTmp = env.
rpc(
"ledger",
"0");
180 BEAST_EXPECT(
bad(ledgerTmp));
183 BEAST_EXPECT(
goodLedger(env, ledgers[1],
"1"));
186 BEAST_EXPECT(
goodLedger(env, ledgers[2],
"2"));
188 ledgerTmp = env.
rpc(
"ledger",
"current");
189 BEAST_EXPECT(
goodLedger(env, ledgerTmp,
"3"));
191 ledgerTmp = env.
rpc(
"ledger",
"4");
192 BEAST_EXPECT(
bad(ledgerTmp));
194 ledgerTmp = env.
rpc(
"ledger",
"100");
195 BEAST_EXPECT(
bad(ledgerTmp));
198 auto lastRotated = firstSeq - 1;
205 ledgerTmp = env.
rpc(
"ledger",
"current");
208 BEAST_EXPECT(store.getLastRotated() == lastRotated);
226 auto ledger = env.
rpc(
"ledger",
"current");
233 lastRotated = store.getLastRotated();
234 BEAST_EXPECT(lastRotated == 11);
242 for (
auto i = lastRotated - 1; i < lastRotated +
kDeleteInterval - 1; ++i)
246 ledgerTmp = env.
rpc(
"ledger",
"current");
251 store.getLastRotated() == lastRotated || i == lastRotated +
kDeleteInterval - 2);
269 testcase(
"automatic online_delete");
271 using namespace std::chrono_literals;
277 auto lastRotated = ledgerSeq - 1;
278 BEAST_EXPECT(store.getLastRotated() == lastRotated);
279 BEAST_EXPECT(lastRotated != 2);
283 auto const canDelete = env.
rpc(
"can_delete");
291 auto ledger = env.
rpc(
"ledger",
"validated");
300 BEAST_EXPECT(lastRotated == store.getLastRotated());
306 auto ledger = env.
rpc(
"ledger",
"validated");
312 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
313 BEAST_EXPECT(lastRotated != store.getLastRotated());
315 lastRotated = store.getLastRotated();
322 auto ledger = env.
rpc(
"ledger",
"validated");
329 BEAST_EXPECT(lastRotated != store.getLastRotated());
335 testcase(
"online_delete with advisory_delete");
337 using namespace std::chrono_literals;
344 auto lastRotated = ledgerSeq - 1;
345 BEAST_EXPECT(store.getLastRotated() == lastRotated);
346 BEAST_EXPECT(lastRotated != 2);
348 auto canDelete = env.
rpc(
"can_delete");
350 BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == 0);
352 canDelete = env.
rpc(
"can_delete",
"never");
354 BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == 0);
357 for (; ledgerSeq < firstBatch; ++ledgerSeq)
361 auto ledger = env.
rpc(
"ledger",
"validated");
368 BEAST_EXPECT(lastRotated == store.getLastRotated());
373 BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == ledgerSeq + (
kDeleteInterval / 2));
378 BEAST_EXPECT(store.getLastRotated() == lastRotated);
384 auto ledger = env.
rpc(
"ledger",
"validated");
390 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
392 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
393 lastRotated = ledgerSeq - 1;
400 auto ledger = env.
rpc(
"ledger",
"validated");
406 BEAST_EXPECT(store.getLastRotated() == lastRotated);
412 auto ledger = env.
rpc(
"ledger",
"validated");
418 ledgerCheck(env, ledgerSeq - firstBatch, firstBatch);
420 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
421 lastRotated = ledgerSeq - 1;
424 canDelete = env.
rpc(
"can_delete",
"always");
434 auto ledger = env.
rpc(
"ledger",
"validated");
440 BEAST_EXPECT(store.getLastRotated() == lastRotated);
446 auto ledger = env.
rpc(
"ledger",
"validated");
452 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
454 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
455 lastRotated = ledgerSeq - 1;
458 canDelete = env.
rpc(
"can_delete",
"now");
460 BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == ledgerSeq - 1);
467 auto ledger = env.
rpc(
"ledger",
"validated");
473 BEAST_EXPECT(store.getLastRotated() == lastRotated);
479 auto ledger = env.
rpc(
"ledger",
"validated");
485 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
487 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
488 lastRotated = ledgerSeq - 1;
495 boost::filesystem::path newPath;
497 if (!BEAST_EXPECT(
path.size()))
516 testcase(
"rotate with lock contention");
550 static constexpr int kReadThreads = 4;
554 std::move(writableBackend),
555 std::move(archiveBackend),
561 using namespace std::chrono_literals;
568 BEAST_EXPECT(writableName ==
"1");
569 BEAST_EXPECT(archiveName ==
"write");
572 BEAST_EXPECT(dbr->getName() ==
"1");
575 dbr->rotate(std::move(newBackend), cb);
577 BEAST_EXPECT(threadNum == 1);
578 BEAST_EXPECT(dbr->getName() ==
"1");
584 BEAST_EXPECT(writableName ==
"3");
585 BEAST_EXPECT(archiveName ==
"2");
588 BEAST_EXPECT(dbr->getName() ==
"3");
590 auto const cbReentrant = [&](
std::string const& writableName,
592 BEAST_EXPECT(writableName ==
"2");
593 BEAST_EXPECT(archiveName ==
"1");
596 dbr->rotate(std::move(newBackend), cb);
599 dbr->rotate(std::move(newBackend), cbReentrant);
602 BEAST_EXPECT(threadNum == 3);
603 BEAST_EXPECT(dbr->getName() ==
"3");
TestcaseT testcase
Memberspace for declaring test cases.
virtual Config & config()=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.
A NodeStore::Scheduler which uses the JobQueue.
virtual std::unique_ptr< Backend > makeBackend(Section const ¶meters, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal)=0
Create a backend.
static Manager & instance()
Returns the instance of the manager singleton.
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.
virtual CountMinMax getLedgerCountMinMax()=0
getLedgerCountMinMax Returns the minimum ledger sequence, maximum ledger sequence and total number of...
virtual std::optional< LedgerHeader > getLedgerInfoByIndex(LedgerIndex ledgerSeq)=0
getLedgerInfoByIndex Returns a ledger by its sequence.
class to create database, launch online delete thread, and related SQLite database
virtual void rendezvous() const =0
Holds a collection of configuration values.
void set(std::string const &key, std::string const &value)
Set a key/value pair.
virtual JobQueue & getJobQueue()=0
virtual RelationalDatabase & getRelationalDatabase()=0
virtual beast::Journal getJournal(std::string const &name)=0
virtual SHAMapStore & getSHAMapStore()=0
static auto onlineDelete(std::unique_ptr< Config > cfg)
static auto advisoryDelete(std::unique_ptr< Config > cfg)
static bool bad(json::Value const &json, ErrorCodeI error=RpcLgrNotFound)
std::unique_ptr< NodeStore::Backend > makeBackendRotating(jtx::Env &env, NodeStoreScheduler &scheduler, std::string path)
void ledgerCheck(jtx::Env &env, int const rows, int const first)
void accountTransactionCheck(jtx::Env &env, int const rows)
void run() override
Runs the suite.
void transactionCheck(jtx::Env &env, int const rows)
int waitForReady(jtx::Env &env)
std::string getHash(json::Value const &json)
static auto const kDeleteInterval
static bool goodLedger(jtx::Env &env, json::Value const &json, std::string ledgerID, bool checkDB=false)
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
JSON (JavaScript Object Notation).
bool containsError(json::Value const &json)
Returns true if the json contains an rpc error specification.
XrpT const XRP
Converts to XRP Issue or STAmount.
std::array< Account, 1+sizeof...(Args)> noripple(Account const &account, Args const &... args)
Designate accounts as no-ripple in Env::fund.
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::uint32_t LedgerIndex
A ledger index.
std::string to_string(BaseUInt< Bits, Tag > const &a)
constexpr auto megabytes(T value) noexcept
static constexpr auto kAdvisoryDelete
static constexpr auto kCacheSize
static constexpr auto kPath
static constexpr auto kCacheAge
static constexpr auto kOnlineDelete
static constexpr auto kNodeDatabase
T time_since_epoch(T... args)