xrpld
Loading...
Searching...
No Matches
Node.cpp
1#include <xrpld/app/rdb/backend/detail/Node.h>
2
3#include <xrpld/app/ledger/AcceptedLedger.h>
4#include <xrpld/app/ledger/LedgerMaster.h>
5#include <xrpld/app/ledger/LedgerPersistence.h>
6#include <xrpld/app/ledger/LedgerToJson.h>
7#include <xrpld/app/ledger/TransactionMaster.h>
8#include <xrpld/core/Config.h>
9
10#include <xrpl/basics/Blob.h>
11#include <xrpl/basics/ByteUtilities.h>
12#include <xrpl/basics/Log.h>
13#include <xrpl/basics/RangeSet.h>
14#include <xrpl/basics/base_uint.h>
15#include <xrpl/basics/chrono.h>
16#include <xrpl/basics/contract.h>
17#include <xrpl/basics/safe_cast.h>
18#include <xrpl/beast/utility/Journal.h>
19#include <xrpl/beast/utility/instrumentation.h>
20#include <xrpl/config/Constants.h>
21#include <xrpl/core/NetworkIDService.h>
22#include <xrpl/core/StartUpType.h>
23#include <xrpl/json/to_string.h> // IWYU pragma: keep
24#include <xrpl/ledger/PendingSaves.h>
25#include <xrpl/nodestore/NodeObject.h>
26#include <xrpl/protocol/AccountID.h>
27#include <xrpl/protocol/ErrorCodes.h>
28#include <xrpl/protocol/HashPrefix.h>
29#include <xrpl/protocol/LedgerHeader.h>
30#include <xrpl/protocol/Protocol.h>
31#include <xrpl/protocol/STTx.h>
32#include <xrpl/protocol/Serializer.h>
33#include <xrpl/protocol/TxMeta.h>
34#include <xrpl/protocol/TxSearched.h>
35#include <xrpl/protocol/XRPAmount.h>
36#include <xrpl/rdb/DBInit.h>
37#include <xrpl/rdb/DatabaseCon.h>
38#include <xrpl/rdb/RelationalDatabase.h>
39#include <xrpl/rdb/SociDB.h>
40
41#include <boost/filesystem/operations.hpp>
42#include <boost/format/free_funcs.hpp>
43#include <boost/optional/optional.hpp> // IWYU pragma: keep
44#include <boost/system/detail/error_code.hpp>
45
46#include <soci/blob.h>
47#include <soci/into.h>
48#include <soci/soci-backend.h>
49#include <soci/statement.h>
50#include <soci/transaction.h>
51#include <soci/use.h>
52
53#include <algorithm>
54#include <cstddef>
55#include <cstdint>
56#include <exception>
57#include <functional>
58#include <limits>
59#include <map>
60#include <memory>
61#include <optional>
62#include <sstream>
63#include <stdexcept>
64#include <string>
65#include <utility>
66#include <variant>
67#include <vector>
68
69namespace xrpl::detail {
70
76static std::string
78{
79 static_assert(kTableTypeCount == 3, "Need to modify switch statement if enum is modified");
80
81 switch (type)
82 {
84 return "Ledgers";
86 return "Transactions";
88 return "AccountTransactions";
89 // LCOV_EXCL_START
90 default:
91 UNREACHABLE("xrpl::detail::toString : invalid TableType");
92 return "Unknown";
93 // LCOV_EXCL_STOP
94 }
95}
96
97DatabasePairValid
99 Config const& config,
100 DatabaseCon::Setup const& setup,
101 DatabaseCon::CheckpointerSetup const& checkpointerSetup,
103{
104 // ledger database
106 setup, kLgrDbName, setup.lgrPragma, kLgrDbInit, checkpointerSetup, j)};
107 lgr->getSession() << boost::str(
108 boost::format("PRAGMA cache_size=-%d;") %
110
111 if (config.useTxTables())
112 {
113 // transaction database
115 setup, kTxDbName, setup.txPragma, kTxDbInit, checkpointerSetup, j)};
116 tx->getSession() << boost::str(
117 boost::format("PRAGMA cache_size=-%d;") %
119
120 if (!setup.standAlone || setup.startUp == StartUpType::Load ||
122 {
123 // Check if AccountTransactions has primary key
124 std::string cid, name, type;
125 std::size_t notnull = 0, dfltValue = 0, pk = 0;
126 soci::indicator ind = soci::i_null;
127 soci::statement st =
128 (tx->getSession().prepare << "PRAGMA table_info(AccountTransactions);",
129 soci::into(cid),
130 soci::into(name),
131 soci::into(type),
132 soci::into(notnull),
133 soci::into(dfltValue, ind),
134 soci::into(pk));
135
136 st.execute();
137 while (st.fetch())
138 {
139 if (pk == 1)
140 {
141 return {
142 .ledgerDb = std::move(lgr), .transactionDb = std::move(tx), .valid = false};
143 }
144 }
145 }
146
147 return {.ledgerDb = std::move(lgr), .transactionDb = std::move(tx), .valid = true};
148 }
149
150 return {.ledgerDb = std::move(lgr), .transactionDb = {}, .valid = true};
151}
152
154getMinLedgerSeq(soci::session& session, TableType type)
155{
156 std::string const query = "SELECT MIN(LedgerSeq) FROM " + toString(type) + ";";
157 // SOCI requires boost::optional (not std::optional) as the parameter.
158 boost::optional<LedgerIndex> m;
159 session << query, soci::into(m);
160 return m ? *m : std::optional<LedgerIndex>();
161}
162
164getMaxLedgerSeq(soci::session& session, TableType type)
165{
166 std::string const query = "SELECT MAX(LedgerSeq) FROM " + toString(type) + ";";
167 // SOCI requires boost::optional (not std::optional) as the parameter.
168 boost::optional<LedgerIndex> m;
169 session << query, soci::into(m);
170 return m ? *m : std::optional<LedgerIndex>();
171}
172
173void
174deleteByLedgerSeq(soci::session& session, TableType type, LedgerIndex ledgerSeq)
175{
176 session << "DELETE FROM " << toString(type) << " WHERE LedgerSeq == " << ledgerSeq << ";";
177}
178
179void
180deleteBeforeLedgerSeq(soci::session& session, TableType type, LedgerIndex ledgerSeq)
181{
182 session << "DELETE FROM " << toString(type) << " WHERE LedgerSeq < " << ledgerSeq << ";";
183}
184
186getRows(soci::session& session, TableType type)
187{
188 std::size_t rows = 0;
189 session << "SELECT COUNT(*) AS rows "
190 "FROM "
191 << toString(type) << ";",
192 soci::into(rows);
193
194 return rows;
195}
196
198getRowsMinMax(soci::session& session, TableType type)
199{
201 session << "SELECT COUNT(*) AS rows, "
202 "MIN(LedgerSeq) AS first, "
203 "MAX(LedgerSeq) AS last "
204 "FROM "
205 << toString(type) << ";",
206 soci::into(res.numberOfRows), soci::into(res.minLedgerSequence),
207 soci::into(res.maxLedgerSequence);
208
209 return res;
210}
211
212bool
214 DatabaseCon& ldgDB,
215 std::unique_ptr<DatabaseCon> const& txnDB,
216 Application& app,
217 std::shared_ptr<Ledger const> const& ledger,
218 bool current)
219{
220 auto j = app.getJournal("Ledger");
221 auto seq = ledger->header().seq;
222
223 // TODO(tom): Fix this hard-coded SQL!
224 JLOG(j.trace()) << "saveValidatedLedger " << (current ? "" : "fromAcquire ") << seq;
225
226 if (!ledger->header().accountHash.isNonZero())
227 {
228 // LCOV_EXCL_START
229 JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}});
230 UNREACHABLE("xrpl::detail::saveValidatedLedger : zero account hash");
231 // LCOV_EXCL_STOP
232 }
233
234 if (ledger->header().accountHash != ledger->stateMap().getHash().asUInt256())
235 {
236 // LCOV_EXCL_START
237 JLOG(j.fatal()) << "sAL: " << ledger->header().accountHash
238 << " != " << ledger->stateMap().getHash();
239 JLOG(j.fatal()) << "saveAcceptedLedger: seq=" << seq << ", current=" << current;
240 UNREACHABLE("xrpl::detail::saveValidatedLedger : mismatched account hash");
241 // LCOV_EXCL_STOP
242 }
243
244 XRPL_ASSERT(
245 ledger->header().txHash == ledger->txMap().getHash().asUInt256(),
246 "xrpl::detail::saveValidatedLedger : transaction hash match");
247
248 // Save the ledger header in the hashed object store
249 {
250 Serializer s(128);
252 addRaw(ledger->header(), s);
253 app.getNodeStore().store(
254 NodeObjectType::Ledger, std::move(s.modData()), ledger->header().hash, seq);
255 }
256
258 try
259 {
260 aLedger = app.getAcceptedLedgerCache().fetch(ledger->header().hash);
261 if (!aLedger)
262 {
263 aLedger = std::make_shared<AcceptedLedger>(ledger);
264 app.getAcceptedLedgerCache().canonicalizeReplaceClient(ledger->header().hash, aLedger);
265 }
266 }
267 catch (std::exception const&)
268 {
269 JLOG(j.warn()) << "An accepted ledger was missing nodes";
270 app.getLedgerMaster().failedSave(seq, ledger->header().hash);
271 // Clients can now trust the database for information about this
272 // ledger sequence.
273 app.getPendingSaves().finishWork(seq);
274 return false;
275 }
276
277 {
278 static boost::format kDeleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %u;");
279 static boost::format kDeleteTranS1("DELETE FROM Transactions WHERE LedgerSeq = %u;");
280 static boost::format kDeleteTranS2("DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
281 static boost::format kDeleteAcctTrans(
282 "DELETE FROM AccountTransactions WHERE TransID = '%s';");
283
284 {
285 auto db = ldgDB.checkoutDb();
286 *db << boost::str(kDeleteLedger % seq);
287 }
288
289 if (app.config().useTxTables())
290 {
291 if (!txnDB)
292 {
293 // LCOV_EXCL_START
294 JLOG(j.fatal()) << "TxTables db isn't available";
295 Throw<std::runtime_error>("TxTables db isn't available");
296 // LCOV_EXCL_STOP
297 }
298
299 auto db = txnDB->checkoutDb();
300
301 soci::transaction tr(*db);
302
303 *db << boost::str(kDeleteTranS1 % seq);
304 *db << boost::str(kDeleteTranS2 % seq);
305
306 std::string const ledgerSeq(std::to_string(seq));
307
308 for (auto const& acceptedLedgerTx : *aLedger)
309 {
310 uint256 transactionID = acceptedLedgerTx->getTransactionID();
311
312 std::string const txnId(to_string(transactionID));
313 std::string const txnSeq(std::to_string(acceptedLedgerTx->getTxnSeq()));
314
315 *db << boost::str(kDeleteAcctTrans % transactionID);
316
317 auto const& accts = acceptedLedgerTx->getAffected();
318
319 if (!accts.empty())
320 {
321 std::string sql(
322 "INSERT INTO AccountTransactions "
323 "(TransID, Account, LedgerSeq, TxnSeq) VALUES ");
324
325 // Try to make an educated guess on how much space we'll
326 // need for our arguments. In argument order we have: 64
327 // + 34 + 10 + 10 = 118 + 10 extra = 128 bytes
328 sql.reserve(sql.length() + (accts.size() * 128));
329
330 bool first = true;
331 for (auto const& account : accts)
332 {
333 if (!first)
334 {
335 sql += ", ('";
336 }
337 else
338 {
339 sql += "('";
340 first = false;
341 }
342
343 sql += txnId;
344 sql += "','";
345 sql += toBase58(account);
346 sql += "',";
347 sql += ledgerSeq;
348 sql += ",";
349 sql += txnSeq;
350 sql += ")";
351 }
352 sql += ";";
353 JLOG(j.trace()) << "ActTx: " << sql;
354 *db << sql;
355 }
356 else if (auto const& sleTxn = acceptedLedgerTx->getTxn(); !isPseudoTx(*sleTxn))
357 {
358 // It's okay for pseudo transactions to not affect any
359 // accounts. But otherwise...
360 JLOG(j.warn()) << "Transaction in ledger " << seq << " affects no accounts";
361 JLOG(j.warn()) << sleTxn->getJson(JsonOptions::Values::None);
362 }
363
364 *db
366 acceptedLedgerTx->getTxn()->getMetaSQL(
367 seq, acceptedLedgerTx->getEscMeta()) +
368 ";");
369
371 transactionID,
372 seq,
373 acceptedLedgerTx->getTxnSeq(),
375 }
376
377 tr.commit();
378 }
379
380 {
381 static std::string const kAddLedger(
382 R"sql(INSERT OR REPLACE INTO Ledgers
383 (LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,
384 CloseTimeRes,CloseFlags,AccountSetHash,TransSetHash)
385 VALUES
386 (:ledgerHash,:ledgerSeq,:prevHash,:totalCoins,:closingTime,:prevClosingTime,
387 :closeTimeRes,:closeFlags,:accountSetHash,:transSetHash);)sql");
388
389 auto db(ldgDB.checkoutDb());
390
391 soci::transaction tr(*db);
392
393 auto const hash = to_string(ledger->header().hash);
394 auto const parentHash = to_string(ledger->header().parentHash);
395 auto const drops = to_string(ledger->header().drops);
396 auto const closeTime = ledger->header().closeTime.time_since_epoch().count();
397 auto const parentCloseTime =
398 ledger->header().parentCloseTime.time_since_epoch().count();
399 auto const closeTimeResolution = ledger->header().closeTimeResolution.count();
400 auto const closeFlags = ledger->header().closeFlags;
401 auto const accountHash = to_string(ledger->header().accountHash);
402 auto const txHash = to_string(ledger->header().txHash);
403
404 *db << kAddLedger, soci::use(hash), soci::use(seq), soci::use(parentHash),
405 soci::use(drops), soci::use(closeTime), soci::use(parentCloseTime),
406 soci::use(closeTimeResolution), soci::use(closeFlags), soci::use(accountHash),
407 soci::use(txHash);
408
409 tr.commit();
410 }
411 }
412
413 return true;
414}
415
420 * @param sqlSuffix SQL string used to specify the sought ledger.
421 * @param j Journal.
422 * @return Ledger info or no value if the ledger was not found.
423 */
425getLedgerInfo(soci::session& session, std::string const& sqlSuffix, beast::Journal j)
426{
427 // SOCI requires boost::optional (not std::optional) as parameters.
428 boost::optional<std::string> hash, parentHash, accountHash, txHash;
429 boost::optional<std::uint64_t> seq, drops, closeTime, parentCloseTime, closeTimeResolution,
430 closeFlags;
431
432 std::string const sql =
433 "SELECT "
434 "LedgerHash, PrevHash, AccountSetHash, TransSetHash, "
435 "TotalCoins,"
436 "ClosingTime, PrevClosingTime, CloseTimeRes, CloseFlags,"
437 "LedgerSeq FROM Ledgers " +
438 sqlSuffix + ";";
439
440 session << sql, soci::into(hash), soci::into(parentHash), soci::into(accountHash),
441 soci::into(txHash), soci::into(drops), soci::into(closeTime), soci::into(parentCloseTime),
442 soci::into(closeTimeResolution), soci::into(closeFlags), soci::into(seq);
443
444 if (!session.got_data())
445 {
446 JLOG(j.debug()) << "Ledger not found: " << sqlSuffix;
447 return {};
448 }
449
450 using time_point = NetClock::time_point;
451 using duration = NetClock::duration;
452
453 LedgerHeader info;
454
455 if (hash && !info.hash.parseHex(*hash))
456 {
457 JLOG(j.debug()) << "Hash parse error for ledger: " << sqlSuffix;
458 return {};
459 }
460
461 if (parentHash && !info.parentHash.parseHex(*parentHash))
462 {
463 JLOG(j.debug()) << "parentHash parse error for ledger: " << sqlSuffix;
464 return {};
465 }
466
467 if (accountHash && !info.accountHash.parseHex(*accountHash))
468 {
469 JLOG(j.debug()) << "accountHash parse error for ledger: " << sqlSuffix;
470 return {};
471 }
472
473 if (txHash && !info.txHash.parseHex(*txHash))
474 {
475 JLOG(j.debug()) << "txHash parse error for ledger: " << sqlSuffix;
476 return {};
477 }
478
479 info.seq = rangeCheckedCast<std::uint32_t>(seq.value_or(0));
480 info.drops = drops.value_or(0);
481 info.closeTime = time_point{duration{closeTime.value_or(0)}};
482 info.parentCloseTime = time_point{duration{parentCloseTime.value_or(0)}};
483 info.closeFlags = closeFlags.value_or(0);
484 info.closeTimeResolution = duration{closeTimeResolution.value_or(0)};
486 return info;
487}
488
490getLedgerInfoByIndex(soci::session& session, LedgerIndex ledgerSeq, beast::Journal j)
491{
493 s << "WHERE LedgerSeq = " << ledgerSeq;
494 return getLedgerInfo(session, s.str(), j);
495}
496
498getNewestLedgerInfo(soci::session& session, beast::Journal j)
499{
501 s << "ORDER BY LedgerSeq DESC LIMIT 1";
502 return getLedgerInfo(session, s.str(), j);
503}
504
506getLimitedOldestLedgerInfo(soci::session& session, LedgerIndex ledgerFirstIndex, beast::Journal j)
507{
509 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
510 " ORDER BY LedgerSeq ASC LIMIT 1";
511 return getLedgerInfo(session, s.str(), j);
512}
513
515getLimitedNewestLedgerInfo(soci::session& session, LedgerIndex ledgerFirstIndex, beast::Journal j)
516{
518 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
519 " ORDER BY LedgerSeq DESC LIMIT 1";
520 return getLedgerInfo(session, s.str(), j);
521}
522
524getLedgerInfoByHash(soci::session& session, uint256 const& ledgerHash, beast::Journal j)
525{
527 s << "WHERE LedgerHash = '" << ledgerHash << "'";
528 return getLedgerInfo(session, s.str(), j);
529}
530
532getHashByIndex(soci::session& session, LedgerIndex ledgerIndex)
533{
534 uint256 ret;
535
536 std::string sql = "SELECT LedgerHash FROM Ledgers INDEXED BY SeqLedger WHERE LedgerSeq='";
537 sql.append(std::to_string(ledgerIndex));
538 sql.append("';");
539
540 std::string hash;
541 {
542 // SOCI requires boost::optional (not std::optional) as the parameter.
543 boost::optional<std::string> lh;
544 session << sql, soci::into(lh);
545
546 if (!session.got_data() || !lh)
547 return ret;
548
549 hash = *lh;
550 if (hash.empty())
551 return ret;
552 }
553
554 if (!ret.parseHex(hash))
555 return ret;
557 return ret;
558}
559
561getHashesByIndex(soci::session& session, LedgerIndex ledgerIndex, beast::Journal j)
562{
563 // SOCI requires boost::optional (not std::optional) as the parameter.
564 boost::optional<std::string> lhO, phO;
565
566 session << "SELECT LedgerHash,PrevHash FROM Ledgers "
567 "INDEXED BY SeqLedger WHERE LedgerSeq = :ls;",
568 soci::into(lhO), soci::into(phO), soci::use(ledgerIndex);
569
570 if (!lhO || !phO)
571 {
572 auto stream = j.trace();
573 JLOG(stream) << "Don't have ledger " << ledgerIndex;
574 return {};
575 }
576
577 LedgerHashPair hashes;
578 if (!hashes.ledgerHash.parseHex(*lhO) || !hashes.parentHash.parseHex(*phO))
579 {
580 auto stream = j.trace();
581 JLOG(stream) << "Error parse hashes for ledger " << ledgerIndex;
582 return {};
583 }
585 return hashes;
586}
587
589getHashesByIndex(soci::session& session, LedgerIndex minSeq, LedgerIndex maxSeq, beast::Journal j)
590{
591 std::string sql = "SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq >= ";
592 sql.append(std::to_string(minSeq));
593 sql.append(" AND LedgerSeq <= ");
594 sql.append(std::to_string(maxSeq));
595 sql.append(";");
596
597 std::uint64_t ls = 0;
598 std::string lh;
599 // SOCI requires boost::optional (not std::optional) as the parameter.
600 boost::optional<std::string> ph;
601 soci::statement st = (session.prepare << sql, soci::into(ls), soci::into(lh), soci::into(ph));
602
603 st.execute();
605 while (st.fetch())
606 {
608 if (!hashes.ledgerHash.parseHex(lh))
609 {
610 JLOG(j.warn()) << "Error parsed hash for ledger seq: " << ls;
611 }
612 if (!ph)
613 {
614 JLOG(j.warn()) << "Null prev hash for ledger seq: " << ls;
615 }
616 else if (!hashes.parentHash.parseHex(*ph))
617 {
618 JLOG(j.warn()) << "Error parsed prev hash for ledger seq: " << ls;
619 }
621 return res;
622}
623
625getTxHistory(soci::session& session, Application& app, LedgerIndex startIndex, int quantity)
626{
627 std::string const sql = boost::str(
628 boost::format(
629 "SELECT LedgerSeq, Status, RawTxn "
630 "FROM Transactions ORDER BY LedgerSeq DESC LIMIT %u,%u;") %
631 startIndex % quantity);
632
634 int total = 0;
635
636 {
637 // SOCI requires boost::optional (not std::optional) as parameters.
638 boost::optional<std::uint64_t> ledgerSeq;
639 boost::optional<std::string> status;
640 soci::blob sociRawTxnBlob(session);
641 soci::indicator rti = soci::i_null;
642 Blob rawTxn;
643
644 soci::statement st =
645 (session.prepare << sql,
646 soci::into(ledgerSeq),
647 soci::into(status),
648 soci::into(sociRawTxnBlob, rti));
649
650 st.execute();
651 while (st.fetch())
652 {
653 if (soci::i_ok == rti)
654 {
655 convert(sociRawTxnBlob, rawTxn);
656 }
657 else
658 {
659 rawTxn.clear();
660 }
661
662 if (auto trans = Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app))
663 {
664 total++;
665 txs.push_back(trans);
666 }
667 }
668 }
669
670 return {txs, total};
671}
672
686 * selecting them.
687 * @param j Journal.
688 * @return SQL query string.
689 */
690static std::string
692 Application& app,
693 std::string selection,
695 bool descending,
696 bool binary,
697 bool count,
699{
700 static constexpr std::uint32_t kNonbinaryPageLength = 200;
701 static constexpr std::uint32_t kBinaryPageLength = 500;
702
703 std::uint32_t numberOfResults = 0;
704
705 if (count)
706 {
707 numberOfResults = std::numeric_limits<std::uint32_t>::max();
708 }
709 else if (options.limit == UINT32_MAX)
710 {
711 numberOfResults = binary ? kBinaryPageLength : kNonbinaryPageLength;
712 }
713 else if (!options.bUnlimited)
714 {
715 numberOfResults =
716 std::min(binary ? kBinaryPageLength : kNonbinaryPageLength, options.limit);
717 }
718 else
719 {
720 numberOfResults = options.limit;
721 }
722
723 std::string maxClause;
724 std::string minClause;
725
726 if (options.ledgerRange.max != 0u)
727 {
728 maxClause = boost::str(
729 boost::format("AND AccountTransactions.LedgerSeq <= '%u'") % options.ledgerRange.max);
730 }
731
732 if (options.ledgerRange.min != 0u)
733 {
734 minClause = boost::str(
735 boost::format("AND AccountTransactions.LedgerSeq >= '%u'") % options.ledgerRange.min);
736 }
737
738 std::string sql;
739
740 if (count)
741 {
742 sql = boost::str(
743 boost::format(
744 "SELECT %s FROM AccountTransactions "
745 "WHERE Account = '%s' %s %s LIMIT %u, %u;") %
746 selection % toBase58(options.account) % maxClause % minClause % options.offset %
747 numberOfResults);
748 }
749 else
750 {
751 sql = boost::str(
752 boost::format(
753 "SELECT %s FROM "
754 "AccountTransactions INNER JOIN Transactions "
755 "ON Transactions.TransID = AccountTransactions.TransID "
756 "WHERE Account = '%s' %s %s "
757 "ORDER BY AccountTransactions.LedgerSeq %s, "
758 "AccountTransactions.TxnSeq %s, AccountTransactions.TransID %s "
759 "LIMIT %u, %u;") %
760 selection % toBase58(options.account) % maxClause % minClause %
761 (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") %
762 (descending ? "DESC" : "ASC") % options.offset % numberOfResults);
763 }
764 JLOG(j.trace()) << "txSQL query: " << sql;
765 return sql;
766}
767
785 * -number represents the number of transactions skipped. We need to
786 * skip some number of transactions if option offset is > 0 in the
787 * options structure.
788 */
791 soci::session& session,
792 Application& app,
793 LedgerMaster& ledgerMaster,
795 bool descending,
797{
799
800 std::string const sql = transactionsSQL(
801 app,
802 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
803 options,
804 descending,
805 false,
806 false,
807 j);
808 if (sql.empty())
809 return {ret, 0};
810
811 int total = 0;
812 {
813 // SOCI requires boost::optional (not std::optional) as parameters.
814 boost::optional<std::uint64_t> ledgerSeq;
815 boost::optional<std::string> status;
816 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
817 soci::indicator rti = soci::i_null, tmi = soci::i_null;
818 Blob rawTxn, txnMeta;
819
820 soci::statement st =
821 (session.prepare << sql,
822 soci::into(ledgerSeq),
823 soci::into(status),
824 soci::into(sociTxnBlob, rti),
825 soci::into(sociTxnMetaBlob, tmi));
826
827 st.execute();
828 while (st.fetch())
829 {
830 if (soci::i_ok == rti)
831 {
832 convert(sociTxnBlob, rawTxn);
833 }
834 else
835 {
836 rawTxn.clear();
837 }
838
839 if (soci::i_ok == tmi)
840 {
841 convert(sociTxnMetaBlob, txnMeta);
842 }
843 else
844 {
845 txnMeta.clear();
846 }
847
848 auto txn = Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
849
850 if (txnMeta.empty())
851 { // Work around a bug that could leave the metadata missing
852 auto const seq = rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
853
854 JLOG(j.warn()) << "Recovering ledger " << seq << ", txn " << txn->getID();
855
856 if (auto l = ledgerMaster.getLedgerBySeq(seq))
857 pendSaveValidated(app, l, false, false);
858 }
859
860 if (txn)
861 {
862 ret.emplace_back(
863 txn, std::make_shared<TxMeta>(txn->getID(), txn->getLedger(), txnMeta));
864 total++;
865 }
866 }
867 }
869 return {ret, total};
870}
871
874 soci::session& session,
875 Application& app,
876 LedgerMaster& ledgerMaster,
877 RelationalDatabase::AccountTxOptions const& options,
880 return getAccountTxs(session, app, ledgerMaster, options, false, j);
881}
882
885 soci::session& session,
886 Application& app,
887 LedgerMaster& ledgerMaster,
890{
891 return getAccountTxs(session, app, ledgerMaster, options, true, j);
892}
893
910 * transactions processed, if it is < 0, then -number represents the
911 * number of transactions skipped. We need to skip some number of
912 * transactions if option offset is > 0 in the options structure.
913 */
916 soci::session& session,
917 Application& app,
919 bool descending,
921{
923
924 std::string const sql = transactionsSQL(
925 app,
926 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
927 options,
928 descending,
929 true /*binary*/,
930 false,
931 j);
932 if (sql.empty())
933 return {ret, 0};
934
935 int total = 0;
936
937 {
938 // SOCI requires boost::optional (not std::optional) as parameters.
939 boost::optional<std::uint64_t> ledgerSeq;
940 boost::optional<std::string> status;
941 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
942 soci::indicator rti = soci::i_null, tmi = soci::i_null;
943
944 soci::statement st =
945 (session.prepare << sql,
946 soci::into(ledgerSeq),
947 soci::into(status),
948 soci::into(sociTxnBlob, rti),
949 soci::into(sociTxnMetaBlob, tmi));
950
951 st.execute();
952 while (st.fetch())
953 {
954 Blob rawTxn;
955 if (soci::i_ok == rti)
956 convert(sociTxnBlob, rawTxn);
957 Blob txnMeta;
958 if (soci::i_ok == tmi)
959 convert(sociTxnMetaBlob, txnMeta);
960
961 auto const seq = rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
962
963 ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq);
964 total++;
965 }
966 }
968 return {ret, total};
969}
970
973 soci::session& session,
974 Application& app,
975 RelationalDatabase::AccountTxOptions const& options,
978 return getAccountTxsB(session, app, options, false, j);
979}
980
983 soci::session& session,
984 Application& app,
987{
988 return getAccountTxsB(session, app, options, true, j);
989}
990
1006 * sequences sorted in the specified order by account sequence, a marker
1007 * for the next search if the search was not finished and the number of
1008 * transactions processed during this call.
1009 */
1012 soci::session& session,
1013 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1014 std::function<void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction,
1016 std::uint32_t pageLength,
1017 bool forward)
1018{
1019 int total = 0;
1020
1021 bool lookingForMarker = options.marker.has_value();
1022
1023 std::uint32_t numberOfResults = 0;
1024
1025 if (options.limit == 0 || options.limit == UINT32_MAX ||
1026 (options.limit > pageLength && !options.bAdmin))
1027 {
1028 numberOfResults = pageLength;
1029 }
1030 else
1031 {
1032 numberOfResults = options.limit;
1033 }
1034
1035 // As an account can have many thousands of transactions, there is a limit
1036 // placed on the amount of transactions returned. If the limit is reached
1037 // before the result set has been exhausted (we always query for one more
1038 // than the limit), then we return an opaque marker that can be supplied in
1039 // a subsequent query.
1040 std::uint32_t queryLimit = numberOfResults + 1;
1041 std::uint32_t findLedger = 0, findSeq = 0;
1042
1043 if (lookingForMarker)
1044 {
1045 findLedger = options.marker->ledgerSeq;
1046 findSeq = options.marker->txnSeq;
1047 }
1048
1050
1051 static std::string const kPrefix(
1052 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1053 Status,RawTxn,TxnMeta
1054 FROM AccountTransactions INNER JOIN Transactions
1055 ON Transactions.TransID = AccountTransactions.TransID
1056 AND AccountTransactions.Account = '%s' WHERE
1057 )");
1058
1059 std::string sql;
1060
1061 // SQL's BETWEEN uses a closed interval ([a,b])
1062
1063 char const* const order = forward ? "ASC" : "DESC";
1064
1065 if (findLedger == 0)
1066 {
1067 sql = boost::str(
1068 boost::format(kPrefix + R"(AccountTransactions.LedgerSeq BETWEEN %u AND %u
1069 ORDER BY AccountTransactions.LedgerSeq %s,
1070 AccountTransactions.TxnSeq %s
1071 LIMIT %u;)") %
1072 toBase58(options.account) % options.ledgerRange.min % options.ledgerRange.max % order %
1073 order % queryLimit);
1074 }
1075 else
1076 {
1077 char const* const compare = forward ? ">=" : "<=";
1078 std::uint32_t const minLedger = forward ? findLedger + 1 : options.ledgerRange.min;
1079 std::uint32_t const maxLedger = forward ? options.ledgerRange.max : findLedger - 1;
1080
1081 auto b58acct = toBase58(options.account);
1082 sql = boost::str(
1083 boost::format(
1084 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1085 Status,RawTxn,TxnMeta
1086 FROM AccountTransactions, Transactions WHERE
1087 (AccountTransactions.TransID = Transactions.TransID AND
1088 AccountTransactions.Account = '%s' AND
1089 AccountTransactions.LedgerSeq BETWEEN %u AND %u)
1090 UNION
1091 SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,Status,RawTxn,TxnMeta
1092 FROM AccountTransactions, Transactions WHERE
1093 (AccountTransactions.TransID = Transactions.TransID AND
1094 AccountTransactions.Account = '%s' AND
1095 AccountTransactions.LedgerSeq = %u AND
1096 AccountTransactions.TxnSeq %s %u)
1097 ORDER BY AccountTransactions.LedgerSeq %s,
1098 AccountTransactions.TxnSeq %s
1099 LIMIT %u;
1100 )") %
1101 b58acct % minLedger % maxLedger % b58acct % findLedger % compare % findSeq % order %
1102 order % queryLimit);
1103 }
1104
1105 {
1106 Blob rawData;
1107 Blob rawMeta;
1108
1109 // SOCI requires boost::optional (not std::optional) as parameters.
1110 boost::optional<std::uint64_t> ledgerSeq;
1111 boost::optional<std::uint32_t> txnSeq;
1112 boost::optional<std::string> status;
1113 soci::blob txnData(session);
1114 soci::blob txnMeta(session);
1115 soci::indicator dataPresent = soci::i_null, metaPresent = soci::i_null;
1116
1117 soci::statement st =
1118 (session.prepare << sql,
1119 soci::into(ledgerSeq),
1120 soci::into(txnSeq),
1121 soci::into(status),
1122 soci::into(txnData, dataPresent),
1123 soci::into(txnMeta, metaPresent));
1124
1125 st.execute();
1126
1127 while (st.fetch())
1128 {
1129 if (lookingForMarker)
1130 {
1131 if (findLedger == ledgerSeq.value_or(0) && findSeq == txnSeq.value_or(0))
1132 {
1133 lookingForMarker = false;
1134 }
1135 else
1136 {
1137 continue;
1138 }
1139 }
1140 else if (numberOfResults == 0)
1141 {
1142 newmarker = {
1143 .ledgerSeq = rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1144 .txnSeq = txnSeq.value_or(0)};
1145 break;
1146 }
1147
1148 if (dataPresent == soci::i_ok)
1149 {
1150 convert(txnData, rawData);
1151 }
1152 else
1153 {
1154 rawData.clear();
1155 }
1156
1157 if (metaPresent == soci::i_ok)
1158 {
1159 convert(txnMeta, rawMeta);
1160 }
1161 else
1162 {
1163 rawMeta.clear();
1164 }
1166 // Work around a bug that could leave the metadata missing
1167 if (rawMeta.empty())
1168 onUnsavedLedger(ledgerSeq.value_or(0));
1169
1170 // `rawData` and `rawMeta` will be used after they are moved.
1171 // That's OK.
1172 onTransaction(
1173 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1174 *status,
1175 std::move(rawData),
1176 std::move(rawMeta));
1177 // Note some callbacks will move the data, some will not. Clear
1178 // them so code doesn't depend on if the data was actually moved
1179 // or not. The code will be more efficient if `rawData` and
1180 // `rawMeta` don't have to allocate in `convert`, so don't
1181 // refactor my moving these variables into loop scope.
1182 rawData.clear();
1183 rawMeta.clear();
1184
1185 --numberOfResults;
1186 total++;
1188 }
1189
1190 return {newmarker, total};
1191}
1192
1193std::pair<std::optional<RelationalDatabase::AccountTxMarker>, int>
1195 soci::session& session,
1196 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1197 std::function<void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction,
1198 RelationalDatabase::AccountTxPageOptions const& options,
1199 std::uint32_t pageLength)
1200{
1201 return accountTxPage(session, onUnsavedLedger, onTransaction, options, pageLength, true);
1202}
1203
1204std::pair<std::optional<RelationalDatabase::AccountTxMarker>, int>
1206 soci::session& session,
1207 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1208 std::function<void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction,
1209 RelationalDatabase::AccountTxPageOptions const& options,
1210 std::uint32_t pageLength)
1211{
1212 return accountTxPage(session, onUnsavedLedger, onTransaction, options, pageLength, false);
1213}
1214
1215std::variant<RelationalDatabase::AccountTx, TxSearched>
1217 soci::session& session,
1218 Application& app,
1219 uint256 const& id,
1220 std::optional<ClosedInterval<uint32_t>> const& range,
1221 ErrorCodeI& ec)
1222{
1223 std::string sql =
1224 "SELECT LedgerSeq,Status,RawTxn,TxnMeta "
1225 "FROM Transactions WHERE TransID='";
1226
1227 sql.append(to_string(id));
1228 sql.append("';");
1229
1230 // SOCI requires boost::optional (not std::optional) as parameters.
1231 boost::optional<std::uint64_t> ledgerSeq;
1232 boost::optional<std::string> status;
1233 Blob rawTxn, rawMeta;
1234 {
1235 soci::blob sociRawTxnBlob(session), sociRawMetaBlob(session);
1236 soci::indicator txn = soci::i_null, meta = soci::i_null;
1237
1238 session << sql, soci::into(ledgerSeq), soci::into(status), soci::into(sociRawTxnBlob, txn),
1239 soci::into(sociRawMetaBlob, meta);
1240
1241 auto const gotData = session.got_data();
1242
1243 if ((!gotData || txn != soci::i_ok || meta != soci::i_ok) && !range)
1244 return TxSearched::Unknown;
1245
1246 if (!gotData)
1247 {
1248 uint64_t count = 0;
1249 soci::indicator rti = soci::i_null;
1250
1251 session << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
1252 "LedgerSeq BETWEEN "
1253 << range->first() << " AND " << range->last() << ";",
1254 soci::into(count, rti);
1255
1256 if (!session.got_data() || rti != soci::i_ok)
1257 return TxSearched::Some;
1258
1259 return count == (range->last() - range->first() + 1) ? TxSearched::All
1261 }
1262
1263 convert(sociRawTxnBlob, rawTxn);
1264 convert(sociRawMetaBlob, rawMeta);
1265 }
1266
1267 try
1268 {
1269 auto txn = Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
1270
1271 if (!ledgerSeq)
1272 return std::pair{std::move(txn), nullptr};
1273
1274 std::uint32_t const inLedger = rangeCheckedCast<std::uint32_t>(ledgerSeq.value());
1275
1276 auto txMeta = std::make_shared<TxMeta>(id, inLedger, rawMeta);
1277
1278 return std::pair{std::move(txn), std::move(txMeta)};
1279 }
1280 catch (std::exception& e)
1281 {
1282 JLOG(app.getJournal("Ledger").warn())
1283 << "Unable to deserialize transaction from raw SQL value. Error: " << e.what();
1284
1286 }
1287
1288 return TxSearched::Unknown;
1289}
1290
1291bool
1292dbHasSpace(soci::session& session, Config const& config, beast::Journal j)
1293{
1294 boost::filesystem::space_info const space =
1295 boost::filesystem::space(config.legacy(Sections::kDatabasePath));
1296
1297 if (space.available < megabytes(512))
1298 {
1299 JLOG(j.fatal()) << "Remaining free disk space is less than 512MB";
1300 return false;
1301 }
1302
1303 if (config.useTxTables())
1304 {
1305 DatabaseCon::Setup const dbSetup = setupDatabaseCon(config);
1306 boost::filesystem::path const dbPath = dbSetup.dataDir / kTxDbName;
1307 boost::system::error_code ec;
1308 std::optional<std::uint64_t> dbSize = boost::filesystem::file_size(dbPath, ec);
1309 if (ec)
1310 {
1311 JLOG(j.error()) << "Error checking transaction db file size: " << ec.message();
1312 dbSize.reset();
1313 }
1314
1315 static auto const kPageSize = [&] {
1316 std::uint32_t ps = 0;
1317 session << "PRAGMA page_size;", soci::into(ps);
1318 return ps;
1319 }();
1320 static auto const kMaxPages = [&] {
1321 std::uint32_t mp = 0;
1322 session << "PRAGMA max_page_count;", soci::into(mp);
1323 return mp;
1324 }();
1325 std::uint32_t pageCount = 0;
1326 session << "PRAGMA page_count;", soci::into(pageCount);
1327 std::uint32_t const freePages = kMaxPages - pageCount;
1328 std::uint64_t const freeSpace = safeCast<std::uint64_t>(freePages) * kPageSize;
1329 JLOG(j.info()) << "Transaction DB pathname: " << dbPath.string()
1330 << "; file size: " << dbSize.value_or(-1) << " bytes"
1331 << "; SQLite page size: " << kPageSize << " bytes"
1332 << "; Free pages: " << freePages << "; Free space: " << freeSpace
1333 << " bytes; "
1334 << "Note that this does not take into account available disk "
1335 "space.";
1336
1337 if (freeSpace < megabytes(512))
1338 {
1339 JLOG(j.fatal()) << "Free SQLite space for transaction db is less than "
1340 "512MB. To fix this, xrpld must be executed with the "
1341 "vacuum parameter before restarting. "
1342 "Note that this activity can take multiple days, "
1343 "depending on database size.";
1344 return false;
1345 }
1346 }
1347
1348 return true;
1349}
1350
1351} // namespace xrpl::detail
T append(T... args)
A generic endpoint for log messages.
Definition Journal.h:38
Stream fatal() const
Definition Journal.h:321
Stream error() const
Definition Journal.h:315
Stream debug() const
Definition Journal.h:297
Stream info() const
Definition Journal.h:303
Stream trace() const
Severity stream access functions.
Definition Journal.h:291
Stream warn() const
Definition Journal.h:309
virtual Config & config()=0
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:507
bool useTxTables() const
Definition Config.h:322
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:1190
LockedSociSession checkoutDb()
std::shared_ptr< Ledger const > getLedgerBySeq(std::uint32_t index)
void failedSave(std::uint32_t seq, uint256 const &hash)
std::chrono::time_point< NetClock > time_point
Definition chrono.h:46
std::chrono::duration< rep, period > duration
Definition chrono.h:45
virtual std::uint32_t getNetworkID() const noexcept=0
Get the configured network ID.
virtual void store(NodeObjectType type, Blob &&data, uint256 const &hash, std::uint32_t ledgerSeq)=0
Store the object.
void finishWork(LedgerIndex seq)
Finish working on a ledger.
std::vector< AccountTx > AccountTxs
static std::string const & getMetaSQLInsertReplaceHeader()
Definition STTx.cpp:353
virtual PendingSaves & getPendingSaves()=0
virtual beast::Journal getJournal(std::string const &name)=0
virtual TransactionMaster & getMasterTransaction()=0
virtual NodeStore::Database & getNodeStore()=0
virtual NetworkIDService & getNetworkIDService()=0
virtual LedgerMaster & getLedgerMaster()=0
virtual TaggedCache< uint256, AcceptedLedger > & getAcceptedLedgerCache()=0
bool inLedger(uint256 const &hash, std::uint32_t ledger, std::optional< uint32_t > tseq, std::optional< uint32_t > netID)
static Transaction::pointer transactionFromSQL(boost::optional< std::uint64_t > const &ledgerSeq, boost::optional< std::string > const &status, Blob const &rawTxn, Application &app)
T clear(T... args)
T count(T... args)
T emplace_back(T... args)
T empty(T... args)
T make_shared(T... args)
T make_unique(T... args)
T max(T... args)
T min(T... args)
std::optional< LedgerHeader > getLedgerInfoByHash(soci::session &session, uint256 const &ledgerHash, beast::Journal j)
getLedgerInfoByHash Returns info of ledger with given hash.
Definition Node.cpp:519
static std::pair< std::optional< RelationalDatabase::AccountTxMarker >, int > accountTxPage(soci::session &session, std::function< void(std::uint32_t)> const &onUnsavedLedger, std::function< void(std::uint32_t, std::string const &, Blob &&, Blob &&)> const &onTransaction, RelationalDatabase::AccountTxPageOptions const &options, std::uint32_t pageLength, bool forward)
accountTxPage Searches for the oldest or newest transactions for the account that matches the given c...
Definition Node.cpp:1006
std::pair< std::optional< RelationalDatabase::AccountTxMarker >, int > newestAccountTxPage(soci::session &session, std::function< void(std::uint32_t)> const &onUnsavedLedger, std::function< void(std::uint32_t, std::string const &, Blob &&, Blob &&)> const &onTransaction, RelationalDatabase::AccountTxPageOptions const &options, std::uint32_t pageLength)
newestAccountTxPage Searches newest transactions for given account which match given criteria startin...
Definition Node.cpp:1176
constexpr int kTableTypeCount
Definition Node.h:12
bool saveValidatedLedger(DatabaseCon &ldgDB, std::unique_ptr< DatabaseCon > const &txnDB, Application &app, std::shared_ptr< Ledger const > const &ledger, bool current)
saveValidatedLedger Saves ledger into database.
Definition Node.cpp:213
std::pair< std::optional< RelationalDatabase::AccountTxMarker >, int > oldestAccountTxPage(soci::session &session, std::function< void(std::uint32_t)> const &onUnsavedLedger, std::function< void(std::uint32_t, std::string const &, Blob &&, Blob &&)> const &onTransaction, RelationalDatabase::AccountTxPageOptions const &options, std::uint32_t pageLength)
oldestAccountTxPage Searches oldest transactions for given account which match given criteria startin...
Definition Node.cpp:1165
void deleteBeforeLedgerSeq(soci::session &session, TableType type, LedgerIndex ledgerSeq)
deleteBeforeLedgerSeq Deletes all entries in given table for the ledgers with given sequence and all ...
Definition Node.cpp:180
std::optional< LedgerIndex > getMinLedgerSeq(soci::session &session, TableType type)
getMinLedgerSeq Returns minimum ledger sequence in given table.
Definition Node.cpp:154
std::optional< LedgerIndex > getMaxLedgerSeq(soci::session &session, TableType type)
getMaxLedgerSeq Returns maximum ledger sequence in given table.
Definition Node.cpp:164
std::pair< RelationalDatabase::AccountTxs, int > getNewestAccountTxs(soci::session &session, Application &app, LedgerMaster &ledgerMaster, RelationalDatabase::AccountTxOptions const &options, beast::Journal j)
getNewestAccountTxs Returns newest transactions for given account which match given criteria starting...
Definition Node.cpp:879
std::pair< std::vector< std::shared_ptr< Transaction > >, int > getTxHistory(soci::session &session, Application &app, LedgerIndex startIndex, int quantity)
getTxHistory Returns given number of most recent transactions starting from given number of entry.
Definition Node.cpp:620
std::pair< std::vector< RelationalDatabase::txnMetaLedgerType >, int > getOldestAccountTxsB(soci::session &session, Application &app, RelationalDatabase::AccountTxOptions const &options, beast::Journal j)
getOldestAccountTxsB Returns oldest transactions in binary form for given account which match given c...
Definition Node.cpp:967
std::optional< LedgerHeader > getNewestLedgerInfo(soci::session &session, beast::Journal j)
getNewestLedgerInfo Returns info of newest saved ledger.
Definition Node.cpp:493
std::optional< LedgerHeader > getLimitedOldestLedgerInfo(soci::session &session, LedgerIndex ledgerFirstIndex, beast::Journal j)
getLimitedOldestLedgerInfo Returns info of oldest ledger from ledgers with sequences greater or equal...
Definition Node.cpp:501
DatabasePairValid makeLedgerDBs(Config const &config, DatabaseCon::Setup const &setup, DatabaseCon::CheckpointerSetup const &checkpointerSetup, beast::Journal j)
makeLedgerDBs Opens ledger and transactions databases.
Definition Node.cpp:98
RelationalDatabase::CountMinMax getRowsMinMax(soci::session &session, TableType type)
getRowsMinMax Returns minimum ledger sequence, maximum ledger sequence and total number of rows in gi...
Definition Node.cpp:198
static std::pair< RelationalDatabase::AccountTxs, int > getAccountTxs(soci::session &session, Application &app, LedgerMaster &ledgerMaster, RelationalDatabase::AccountTxOptions const &options, bool descending, beast::Journal j)
getAccountTxs Returns the oldest or newest transactions for the account that matches the given criter...
Definition Node.cpp:785
static std::optional< LedgerHeader > getLedgerInfo(soci::session &session, std::string const &sqlSuffix, beast::Journal j)
getLedgerInfo Returns the info of the ledger retrieved from the database by using the provided SQL qu...
Definition Node.cpp:420
std::size_t getRows(soci::session &session, TableType type)
getRows Returns number of rows in given table.
Definition Node.cpp:186
std::optional< LedgerHeader > getLedgerInfoByIndex(soci::session &session, LedgerIndex ledgerSeq, beast::Journal j)
getLedgerInfoByIndex Returns ledger by its sequence.
Definition Node.cpp:485
std::pair< std::vector< RelationalDatabase::txnMetaLedgerType >, int > getNewestAccountTxsB(soci::session &session, Application &app, RelationalDatabase::AccountTxOptions const &options, beast::Journal j)
getNewestAccountTxsB Returns newest transactions in binary form for given account which match given c...
Definition Node.cpp:977
uint256 getHashByIndex(soci::session &session, LedgerIndex ledgerIndex)
getHashByIndex Returns hash of ledger with given sequence.
Definition Node.cpp:527
void deleteByLedgerSeq(soci::session &session, TableType type, LedgerIndex ledgerSeq)
deleteByLedgerSeq Deletes all entries in given table for the ledger with given sequence.
Definition Node.cpp:174
std::pair< RelationalDatabase::AccountTxs, int > getOldestAccountTxs(soci::session &session, Application &app, LedgerMaster &ledgerMaster, RelationalDatabase::AccountTxOptions const &options, beast::Journal j)
getOldestAccountTxs Returns oldest transactions for given account which match given criteria starting...
Definition Node.cpp:868
bool dbHasSpace(soci::session &session, Config const &config, beast::Journal j)
dbHasSpace Checks if given database has available space.
Definition Node.cpp:1263
std::optional< LedgerHeader > getLimitedNewestLedgerInfo(soci::session &session, LedgerIndex ledgerFirstIndex, beast::Journal j)
getLimitedNewestLedgerInfo Returns info of newest ledger from ledgers with sequences greater or equal...
Definition Node.cpp:510
static std::pair< std::vector< RelationalDatabase::txnMetaLedgerType >, int > getAccountTxsB(soci::session &session, Application &app, RelationalDatabase::AccountTxOptions const &options, bool descending, beast::Journal j)
getAccountTxsB Returns the oldest or newest transactions in binary form for the account that matches ...
Definition Node.cpp:910
std::variant< RelationalDatabase::AccountTx, TxSearched > getTransaction(soci::session &session, Application &app, uint256 const &id, std::optional< ClosedInterval< uint32_t > > const &range, ErrorCodeI &ec)
getTransaction Returns transaction with given hash.
Definition Node.cpp:1187
static std::string toString(TableType type)
to_string Returns the name of a table according to its TableType.
Definition Node.cpp:77
static std::string transactionsSQL(Application &app, std::string selection, RelationalDatabase::AccountTxOptions const &options, bool descending, bool binary, bool count, beast::Journal j)
transactionsSQL Returns a SQL query for selecting the oldest or newest transactions in decoded or bin...
Definition Node.cpp:686
std::optional< LedgerHashPair > getHashesByIndex(soci::session &session, LedgerIndex ledgerIndex, beast::Journal j)
getHashesByIndex Returns hash of the ledger and hash of parent ledger for the ledger of given sequenc...
Definition Node.cpp:556
constexpr std::array< char const *, 5 > kLgrDbInit
Definition DBInit.h:25
ErrorCodeI
Definition ErrorCodes.h:22
@ RpcDbDeserialization
Definition ErrorCodes.h:116
bool pendSaveValidated(ServiceRegistry &registry, std::shared_ptr< Ledger const > const &ledger, bool isSynchronous, bool isCurrent)
Save, or arrange to save, a fully-validated ledger.
std::uint32_t LedgerIndex
A ledger index.
Definition Protocol.h:259
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition RangeSet.h:34
constexpr std::array< char const *, 8 > kTxDbInit
Definition DBInit.h:52
T rangeCheckedCast(C c)
constexpr std::enable_if_t< std::is_integral_v< Dest > &&std::is_integral_v< Src >, Dest > safeCast(Src s) noexcept
Definition safe_cast.h:21
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:93
constexpr auto kLgrDbName
Definition DBInit.h:23
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
constexpr auto megabytes(T value) noexcept
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
json::Value getJson(LedgerFill const &fill)
Return a new json::Value representing the ledger with given options.
boost::icl::closed_interval< T > ClosedInterval
A closed interval over the domain T.
Definition RangeSet.h:25
constexpr auto kilobytes(T value) noexcept
@ LedgerMaster
ledger master data for signing
Definition HashPrefix.h:48
DatabaseCon::Setup setupDatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
Definition Config.cpp:1219
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition Blob.h:10
constexpr auto kTxDbName
Definition DBInit.h:50
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition STTx.cpp:810
BaseUInt< 256 > uint256
Definition base_uint.h:562
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition SociDB.cpp:147
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:49
T push_back(T... args)
T reserve(T... args)
T reset(T... args)
T length(T... args)
T str(T... args)
std::array< std::string, 4 > txPragma
Definition DatabaseCon.h:91
std::array< std::string, 1 > lgrPragma
Definition DatabaseCon.h:92
Information about the notional ledger backing the view.
NetClock::time_point parentCloseTime
NetClock::duration closeTimeResolution
NetClock::time_point closeTime
LedgerRange ledgerRange
Ledger sequence range to search.
static constexpr auto kDatabasePath
Definition Constants.h:13
T to_string(T... args)
T value_or(T... args)
T what(T... args)