20 #include <ripple/app/ledger/LedgerMaster.h>
21 #include <ripple/app/ledger/LedgerToJson.h>
22 #include <ripple/beast/hash/hash_append.h>
23 #include <ripple/beast/utility/temp_dir.h>
24 #include <ripple/core/ConfigSections.h>
25 #include <ripple/nodestore/DatabaseShard.h>
26 #include <ripple/nodestore/DummyScheduler.h>
27 #include <ripple/nodestore/impl/DecodedBlob.h>
28 #include <ripple/nodestore/impl/Shard.h>
29 #include <ripple/protocol/digest.h>
30 #include <boost/algorithm/hex.hpp>
35 #include <openssl/ripemd.h>
37 #include <test/nodestore/TestBase.h>
52 template <
class IntType =
int>
76 :
A(params.
A),
B(params.
B)
80 template <
class Generator>
87 template <
class Generator>
91 return rnd(g, params.
A, params.
B);
119 template <
class Generator>
128 Generator::min() == 0,
"If non-zero we have handle the offset");
130 assert(Generator::max() >=
range);
135 while (n <= rejectLim);
140 template <
class Engine,
class Integral>
142 randInt(Engine& engine, Integral min, Integral max)
152 template <
class Engine,
class Integral>
156 return randInt(engine, Integral(0), max);
220 for (
int j = 0; j < p; ++j)
227 }
while (from == to);
237 for (
int j = 0; j < 8; ++j)
258 using namespace test::jtx;
283 if (ledger->info().seq != i)
312 using namespace test::jtx;
317 for (
auto const& sles : ledger->sles)
323 const auto id = sles->getAccountID(
sfAccount);
325 for (
int i = 0; i < data.accounts_.size(); ++i)
327 if (
id == data.accounts_[i].id())
330 for (
int j = 0; j <= seq; ++j)
331 if (data.nAccounts_[j] > i + 1 ||
332 (data.nAccounts_[j] == i + 1 &&
333 !data.isNewAccounts(j)))
335 for (
int k = 0; k < data.payAccounts_[j].size();
337 if (data.payAccounts_[j][k].first == i)
348 reqsq = data.nAccounts_[seq] + 1;
351 BEAST_EXPECT(sq == reqsq);
356 BEAST_EXPECT(rootCount == 1);
357 BEAST_EXPECT(accCount == data.nAccounts_[seq]);
358 BEAST_EXPECT(sothCount == 3);
364 for (
auto const& tx : ledger->txs)
369 tx.first->getFieldAmount(
sfAmount).xrp().decimalXRP();
375 BEAST_EXPECT(xrpAmount == data.xrpAmount_[seq]);
383 int newacc = data.isNewAccounts(seq) ? 1 : 0;
384 BEAST_EXPECT(iniCount == newacc);
385 BEAST_EXPECT(setCount == newacc);
386 BEAST_EXPECT(payCount == data.payAccounts_[seq].size());
387 BEAST_EXPECT(tothCount == !seq);
403 std::move(s.modData()),
411 node.serializeWithPrefix(s);
416 node.getHash().as_uint256(),
425 if (next && next->info().parentHash == ledger.
info().
hash)
427 auto have = next->stateMap().snapShot(
false);
436 auto visitTx = [&](SHAMapTreeNode& node) {
438 node.serializeWithPrefix(s);
442 std::move(s.modData()),
443 node.getHash().as_uint256(),
462 if (!BEAST_EXPECT(fetched))
483 node.serializeWithPrefix(s);
488 node.getHash().as_uint256())};
489 if (!BEAST_EXPECT(nSrc))
493 node.getHash().as_uint256(), ledger.
info().
seq);
494 if (!BEAST_EXPECT(nDst))
497 BEAST_EXPECT(
isSame(nSrc, nDst));
506 node.serializeWithPrefix(s);
511 node.getHash().as_uint256())};
512 if (!BEAST_EXPECT(nSrc))
516 node.getHash().as_uint256(), ledger.
info().
seq);
517 if (!BEAST_EXPECT(nDst))
520 BEAST_EXPECT(
isSame(nSrc, nDst));
538 if (bitmask & (1ll << i))
557 using namespace test::jtx;
564 "max_historical_shards",
596 auto end = start + timeout;
598 !boost::icl::contains(rs, shardIndex))
612 int maxShardNumber = 1,
613 int ledgerOffset = 0)
619 auto const ledgerSeq{
621 if (!BEAST_EXPECT(ledgerSeq != std::nullopt))
630 BEAST_EXPECT(
saveLedger(db, *data.ledgers_[arrInd]));
638 s.
addRaw(data.ledgers_[arrInd]->info().hash.data(), 256 / 8);
651 testcase(
"Standalone");
653 using namespace test::jtx;
664 BEAST_EXPECT(db->ledgersPerShard() == db->ledgersPerShardDefault);
665 BEAST_EXPECT(db->init());
674 BEAST_EXPECT(db->getRootDir().string() == shardDir.
path());
680 testcase(
"Create shard");
682 using namespace test::jtx;
690 if (!BEAST_EXPECT(data.makeLedgers(env)))
703 testcase(
"Reopen shard store");
705 using namespace test::jtx;
714 if (!BEAST_EXPECT(data.makeLedgers(env)))
727 if (!BEAST_EXPECT(data.makeLedgers(env)))
741 testcase(
"Get complete shards");
743 using namespace test::jtx;
751 if (!BEAST_EXPECT(data.makeLedgers(env)))
761 if (!BEAST_EXPECT(n && *n >= 1 && *n <=
nTestShards))
763 bitMask |= 1ll << *n;
771 testcase(
"Prepare shards");
773 using namespace test::jtx;
781 if (!BEAST_EXPECT(data.makeLedgers(env)))
790 if (bitMask & (1ll << n))
793 bitMask &= ~(1ll << n);
820 if (!BEAST_EXPECT(n && *n >= 1 && *n <=
nTestShards))
822 bitMask2 |= 1ll << *n;
825 BEAST_EXPECT((bitMask & bitMask2) == 0);
826 if ((bitMask | bitMask2) == ((1ll <<
nTestShards) - 1) << 1)
839 testcase(
"Import shard");
841 using namespace test::jtx;
851 if (!BEAST_EXPECT(data.makeLedgers(env)))
860 data.ledgers_.clear();
863 boost::filesystem::path importPath(importDir.
path());
872 if (!BEAST_EXPECT(data.makeLedgers(env)))
878 using namespace boost::filesystem;
888 if (!BEAST_EXPECT(n && *n == 1))
899 testcase(
"Corrupted shard store");
901 using namespace test::jtx;
911 if (!BEAST_EXPECT(data.makeLedgers(env)))
919 boost::filesystem::path path = shardDir.
path();
923 FILE* f = fopen(path.string().c_str(),
"r+b");
924 if (!BEAST_EXPECT(f))
928 BEAST_EXPECT(fwrite(buf, 1, 256, f) == 256);
937 if (!BEAST_EXPECT(data.makeLedgers(env)))
952 testcase(
"Illegal finalKey");
954 using namespace test::jtx;
956 for (
int i = 0; i < 5; ++i)
965 if (!BEAST_EXPECT(data.makeLedgers(env)))
971 auto const ledgerSeq{
973 if (!BEAST_EXPECT(ledgerSeq != std::nullopt))
979 BEAST_EXPECT(
saveLedger(*db, *data.ledgers_[arrInd]));
988 data.ledgers_[arrInd - (i == 4)]
1005 boost::filesystem::path path(shardDir.
path());
1007 boost::system::error_code ec;
1011 boost::filesystem::exists(path, ec))
1028 if (!BEAST_EXPECT(data.makeLedgers(env)))
1050 testcase(
"Import node store");
1052 using namespace test::jtx;
1059 Database& ndb = env.app().getNodeStore();
1063 if (!BEAST_EXPECT(data.makeLedgers(env)))
1067 BEAST_EXPECT(
saveLedger(ndb, *data.ledgers_[i]));
1081 if (!BEAST_EXPECT(data.makeLedgers(env)))
1098 std::ifstream input(filename, std::ios::in | std::ios::binary);
1102 while (input.
read(buf, 4096), input.
gcount() > 0)
1106 const auto charDigest = binResult.
data();
1108 boost::algorithm::hex(
1110 charDigest +
sizeof(binResult),
1119 testcase(
"Deterministic shards");
1121 using namespace test::jtx;
1123 std::string ripemd160Key(
"B2F9DB61F714A82889966F097CD615C36DB2B01D"),
1124 ripemd160Dat(
"6DB1D02CD019F09198FE80DB5A7D707F0C6BFF4C");
1126 for (
int i = 0; i < 2; i++)
1135 if (!BEAST_EXPECT(data.makeLedgers(env)))
1147 if (!BEAST_EXPECT(data.makeLedgers(env)))
1156 boost::filesystem::path path(shardDir.
path());
1158 boost::filesystem::path keypath = path /
"nudb.key";
1160 boost::filesystem::path datpath = path /
"nudb.dat";
1163 std::cerr <<
"Iteration " << i <<
": RIPEMD160[nudb.key] = " << key
1165 std::cerr <<
"Iteration " << i <<
": RIPEMD160[nudb.dat] = " << dat
1168 BEAST_EXPECT(key == ripemd160Key);
1169 BEAST_EXPECT(dat == ripemd160Dat);
1176 testcase(
"Import with historical paths");
1178 using namespace test::jtx;
1188 historicalDirs.
begin(),
1189 historicalDirs.
end(),
1190 historicalPaths.
begin(),
1196 auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS);
1197 historyPaths.append(
1198 {historicalPaths[0].string(),
1199 historicalPaths[1].
string(),
1200 historicalPaths[2].
string(),
1201 historicalPaths[3].
string()});
1203 Env env{*
this, std::move(c)};
1205 Database& ndb = env.app().getNodeStore();
1208 auto const ledgerCount = 4;
1210 TestData data(seedValue, 4, ledgerCount);
1211 if (!BEAST_EXPECT(data.makeLedgers(env)))
1215 BEAST_EXPECT(
saveLedger(ndb, *data.ledgers_[i]));
1226 boost::filesystem::directory_iterator(shardDir.
path()),
1227 boost::filesystem::directory_iterator());
1231 BEAST_EXPECT(mainPathCount == 2);
1234 historicalPaths.
begin(),
1235 historicalPaths.
end(),
1237 [](
int const sum, boost::filesystem::path
const& path) {
1240 boost::filesystem::directory_iterator(path),
1241 boost::filesystem::directory_iterator());
1246 BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1258 auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS);
1259 historyPaths.append({historicalDir.
path()});
1261 Env env{*
this, std::move(c)};
1263 Database& ndb = env.app().getNodeStore();
1266 auto const ledgerCount = 4;
1268 TestData data(seedValue * 2, 4, ledgerCount);
1269 if (!BEAST_EXPECT(data.makeLedgers(env)))
1273 BEAST_EXPECT(
saveLedger(ndb, *data.ledgers_[i]));
1284 boost::filesystem::directory_iterator(shardDir.
path()),
1285 boost::filesystem::directory_iterator());
1289 BEAST_EXPECT(mainPathCount == 2);
1292 boost::filesystem::directory_iterator(historicalDir.
path()),
1293 boost::filesystem::directory_iterator());
1297 BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1304 testcase(
"Prepare with historical paths");
1306 using namespace test::jtx;
1316 historicalDirs.
begin(),
1317 historicalDirs.
end(),
1318 historicalPaths.
begin(),
1324 auto& historyPaths = c->section(SECTION_HISTORICAL_SHARD_PATHS);
1325 historyPaths.append(
1326 {historicalPaths[0].string(),
1327 historicalPaths[1].
string(),
1328 historicalPaths[2].
string(),
1329 historicalPaths[3].
string()});
1331 Env env{*
this, std::move(c)};
1335 auto const ledgerCount = 4;
1337 TestData data(seedValue, 4, ledgerCount);
1338 if (!BEAST_EXPECT(data.makeLedgers(env)))
1348 if (!BEAST_EXPECT(n && *n >= 1 && *n <= ledgerCount))
1350 bitMask |= 1ll << *n;
1356 boost::filesystem::directory_iterator(shardDir.
path()),
1357 boost::filesystem::directory_iterator());
1361 BEAST_EXPECT(mainPathCount == 2);
1365 shardDir.
path() / boost::filesystem::path(
"3"),
1366 shardDir.
path() / boost::filesystem::path(
"4")};
1368 boost::filesystem::directory_iterator(shardDir.
path()),
1369 boost::filesystem::directory_iterator());
1371 BEAST_EXPECT(mainPathShards == actual);
1373 const auto generateHistoricalStems = [&historicalPaths, &actual] {
1374 for (
auto const& path : historicalPaths)
1376 for (
auto const& shard :
1377 boost::filesystem::directory_iterator(path))
1379 actual.
insert(boost::filesystem::path(shard).stem());
1388 historicalPathShards, historicalPathShards.
begin()),
1390 [n = 1]()
mutable { return std::to_string(n++); });
1392 generateHistoricalStems();
1394 BEAST_EXPECT(historicalPathShards == actual);
1397 historicalPaths.
begin(),
1398 historicalPaths.
end(),
1400 [](
int const sum, boost::filesystem::path
const& path) {
1403 boost::filesystem::directory_iterator(path),
1404 boost::filesystem::directory_iterator());
1409 BEAST_EXPECT(historicalPathCount == ledgerCount - 2);
1411 data =
TestData(seedValue * 2, 4, ledgerCount);
1412 if (!BEAST_EXPECT(data.makeLedgers(env, ledgerCount)))
1419 auto n =
createShard(data, *db, ledgerCount * 2, ledgerCount);
1421 n && *n >= 1 + ledgerCount && *n <= ledgerCount * 2))
1423 bitMask |= 1ll << *n;
1429 boost::filesystem::directory_iterator(shardDir.
path()),
1430 boost::filesystem::directory_iterator());
1434 BEAST_EXPECT(mainPathCount == 2);
1438 shardDir.
path() / boost::filesystem::path(
"7"),
1439 shardDir.
path() / boost::filesystem::path(
"8")};
1441 boost::filesystem::directory_iterator(shardDir.
path()),
1442 boost::filesystem::directory_iterator()};
1444 BEAST_EXPECT(mainPathShards == actual);
1447 historicalPathShards.
clear();
1450 historicalPathShards, historicalPathShards.
begin()),
1452 [n = 1]()
mutable { return std::to_string(n++); });
1454 generateHistoricalStems();
1456 BEAST_EXPECT(historicalPathShards == actual);
1459 historicalPaths.
begin(),
1460 historicalPaths.
end(),
1462 [](
int const sum, boost::filesystem::path
const& path) {
1465 boost::filesystem::directory_iterator(path),
1466 boost::filesystem::directory_iterator());
1471 BEAST_EXPECT(historicalPathCount == (ledgerCount * 2) - 2);
1478 testcase(
"Open shard management");
1480 using namespace test::jtx;
1485 auto shardStore{env.app().getShardStore()};
1486 BEAST_EXPECT(shardStore);
1493 TestData data(seedValue, 2, numShards);
1494 if (!BEAST_EXPECT(data.makeLedgers(env)))
1497 BEAST_EXPECT(shardStore->getCompleteShards().empty());
1499 int oldestShardIndex{-1};
1501 for (
auto i = 0; i < numShards; ++i)
1503 auto shardIndex{
createShard(data, *shardStore, numShards)};
1505 shardIndex && *shardIndex >= 1 && *shardIndex <= numShards))
1508 bitMask |= (1ll << *shardIndex);
1510 if (oldestShardIndex == -1)
1511 oldestShardIndex = *shardIndex;
1516 shardStore->sweep();
1519 auto const ledgerSeq{shardStore->lastLedgerSeq(oldestShardIndex)};
1521 BEAST_EXPECT(shardStore->fetchNodeObject(
1522 data.ledgers_[index]->info().hash, ledgerSeq));