rippled
Loading...
Searching...
No Matches
Node.cpp
1#include <xrpld/app/ledger/AcceptedLedger.h>
2#include <xrpld/app/ledger/LedgerMaster.h>
3#include <xrpld/app/ledger/LedgerPersistence.h>
4#include <xrpld/app/ledger/LedgerToJson.h>
5#include <xrpld/app/ledger/TransactionMaster.h>
6#include <xrpld/app/rdb/backend/detail/Node.h>
7
8#include <xrpl/basics/BasicConfig.h>
9#include <xrpl/basics/StringUtilities.h>
10#include <xrpl/core/NetworkIDService.h>
11#include <xrpl/json/to_string.h>
12#include <xrpl/ledger/PendingSaves.h>
13#include <xrpl/rdb/DatabaseCon.h>
14#include <xrpl/rdb/RelationalDatabase.h>
15#include <xrpl/rdb/SociDB.h>
16
17#include <boost/range/adaptor/transformed.hpp>
18
19#include <soci/sqlite3/soci-sqlite3.h>
20
21namespace xrpl {
22namespace detail {
23
29static std::string
31{
32 static_assert(TableTypeCount == 3, "Need to modify switch statement if enum is modified");
33
34 switch (type)
35 {
37 return "Ledgers";
39 return "Transactions";
41 return "AccountTransactions";
42 // LCOV_EXCL_START
43 default:
44 UNREACHABLE("xrpl::detail::to_string : invalid TableType");
45 return "Unknown";
46 // LCOV_EXCL_STOP
47 }
48}
49
50DatabasePairValid
52 Config const& config,
53 DatabaseCon::Setup const& setup,
54 DatabaseCon::CheckpointerSetup const& checkpointerSetup,
56{
57 // ledger database
59 setup, LgrDBName, setup.lgrPragma, LgrDBInit, checkpointerSetup, j)};
60 lgr->getSession() << boost::str(
61 boost::format("PRAGMA cache_size=-%d;") %
63
64 if (config.useTxTables())
65 {
66 // transaction database
68 setup, TxDBName, setup.txPragma, TxDBInit, checkpointerSetup, j)};
69 tx->getSession() << boost::str(
70 boost::format("PRAGMA cache_size=-%d;") %
72
73 if (!setup.standAlone || setup.startUp == StartUpType::Load ||
75 {
76 // Check if AccountTransactions has primary key
77 std::string cid, name, type;
78 std::size_t notnull = 0, dflt_value = 0, pk = 0;
79 soci::indicator ind = soci::i_null;
80 soci::statement st =
81 (tx->getSession().prepare << ("PRAGMA table_info(AccountTransactions);"),
82 soci::into(cid),
83 soci::into(name),
84 soci::into(type),
85 soci::into(notnull),
86 soci::into(dflt_value, ind),
87 soci::into(pk));
88
89 st.execute();
90 while (st.fetch())
91 {
92 if (pk == 1)
93 {
94 return {std::move(lgr), std::move(tx), false};
95 }
96 }
97 }
98
99 return {std::move(lgr), std::move(tx), true};
100 }
101
102 return {std::move(lgr), {}, true};
103}
104
106getMinLedgerSeq(soci::session& session, TableType type)
107{
108 std::string const query = "SELECT MIN(LedgerSeq) FROM " + to_string(type) + ";";
109 // SOCI requires boost::optional (not std::optional) as the parameter.
110 boost::optional<LedgerIndex> m;
111 session << query, soci::into(m);
112 return m ? *m : std::optional<LedgerIndex>();
113}
114
116getMaxLedgerSeq(soci::session& session, TableType type)
117{
118 std::string const query = "SELECT MAX(LedgerSeq) FROM " + to_string(type) + ";";
119 // SOCI requires boost::optional (not std::optional) as the parameter.
120 boost::optional<LedgerIndex> m;
121 session << query, soci::into(m);
122 return m ? *m : std::optional<LedgerIndex>();
123}
124
125void
126deleteByLedgerSeq(soci::session& session, TableType type, LedgerIndex ledgerSeq)
127{
128 session << "DELETE FROM " << to_string(type) << " WHERE LedgerSeq == " << ledgerSeq << ";";
129}
130
131void
132deleteBeforeLedgerSeq(soci::session& session, TableType type, LedgerIndex ledgerSeq)
133{
134 session << "DELETE FROM " << to_string(type) << " WHERE LedgerSeq < " << ledgerSeq << ";";
135}
136
138getRows(soci::session& session, TableType type)
139{
140 std::size_t rows = 0;
141 session << "SELECT COUNT(*) AS rows "
142 "FROM "
143 << to_string(type) << ";",
144 soci::into(rows);
145
146 return rows;
147}
148
150getRowsMinMax(soci::session& session, TableType type)
151{
153 session << "SELECT COUNT(*) AS rows, "
154 "MIN(LedgerSeq) AS first, "
155 "MAX(LedgerSeq) AS last "
156 "FROM "
157 << to_string(type) << ";",
158 soci::into(res.numberOfRows), soci::into(res.minLedgerSequence),
159 soci::into(res.maxLedgerSequence);
160
161 return res;
162}
163
164bool
166 DatabaseCon& ldgDB,
167 std::unique_ptr<DatabaseCon> const& txnDB,
168 Application& app,
169 std::shared_ptr<Ledger const> const& ledger,
170 bool current)
171{
172 auto j = app.getJournal("Ledger");
173 auto seq = ledger->header().seq;
174
175 // TODO(tom): Fix this hard-coded SQL!
176 JLOG(j.trace()) << "saveValidatedLedger " << (current ? "" : "fromAcquire ") << seq;
177
178 if (!ledger->header().accountHash.isNonZero())
179 {
180 // LCOV_EXCL_START
181 JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}});
182 UNREACHABLE("xrpl::detail::saveValidatedLedger : zero account hash");
183 // LCOV_EXCL_STOP
184 }
185
186 if (ledger->header().accountHash != ledger->stateMap().getHash().as_uint256())
187 {
188 // LCOV_EXCL_START
189 JLOG(j.fatal()) << "sAL: " << ledger->header().accountHash
190 << " != " << ledger->stateMap().getHash();
191 JLOG(j.fatal()) << "saveAcceptedLedger: seq=" << seq << ", current=" << current;
192 UNREACHABLE("xrpl::detail::saveValidatedLedger : mismatched account hash");
193 // LCOV_EXCL_STOP
194 }
195
196 XRPL_ASSERT(
197 ledger->header().txHash == ledger->txMap().getHash().as_uint256(),
198 "xrpl::detail::saveValidatedLedger : transaction hash match");
199
200 // Save the ledger header in the hashed object store
201 {
202 Serializer s(128);
204 addRaw(ledger->header(), s);
205 app.getNodeStore().store(hotLEDGER, std::move(s.modData()), ledger->header().hash, seq);
206 }
207
209 try
210 {
211 aLedger = app.getAcceptedLedgerCache().fetch(ledger->header().hash);
212 if (!aLedger)
213 {
214 aLedger = std::make_shared<AcceptedLedger>(ledger);
215 app.getAcceptedLedgerCache().canonicalize_replace_client(
216 ledger->header().hash, aLedger);
217 }
218 }
219 catch (std::exception const&)
220 {
221 JLOG(j.warn()) << "An accepted ledger was missing nodes";
222 app.getLedgerMaster().failedSave(seq, ledger->header().hash);
223 // Clients can now trust the database for information about this
224 // ledger sequence.
225 app.getPendingSaves().finishWork(seq);
226 return false;
227 }
228
229 {
230 static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %u;");
231 static boost::format deleteTrans1("DELETE FROM Transactions WHERE LedgerSeq = %u;");
232 static boost::format deleteTrans2("DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
233 static boost::format deleteAcctTrans(
234 "DELETE FROM AccountTransactions WHERE TransID = '%s';");
235
236 {
237 auto db = ldgDB.checkoutDb();
238 *db << boost::str(deleteLedger % seq);
239 }
240
241 if (app.config().useTxTables())
242 {
243 if (!txnDB)
244 {
245 // LCOV_EXCL_START
246 JLOG(j.fatal()) << "TxTables db isn't available";
247 Throw<std::runtime_error>("TxTables db isn't available");
248 // LCOV_EXCL_STOP
249 }
250
251 auto db = txnDB->checkoutDb();
252
253 soci::transaction tr(*db);
254
255 *db << boost::str(deleteTrans1 % seq);
256 *db << boost::str(deleteTrans2 % seq);
257
258 std::string const ledgerSeq(std::to_string(seq));
259
260 for (auto const& acceptedLedgerTx : *aLedger)
261 {
262 uint256 transactionID = acceptedLedgerTx->getTransactionID();
263
264 std::string const txnId(to_string(transactionID));
265 std::string const txnSeq(std::to_string(acceptedLedgerTx->getTxnSeq()));
266
267 *db << boost::str(deleteAcctTrans % transactionID);
268
269 auto const& accts = acceptedLedgerTx->getAffected();
270
271 if (!accts.empty())
272 {
273 std::string sql(
274 "INSERT INTO AccountTransactions "
275 "(TransID, Account, LedgerSeq, TxnSeq) VALUES ");
276
277 // Try to make an educated guess on how much space we'll
278 // need for our arguments. In argument order we have: 64
279 // + 34 + 10 + 10 = 118 + 10 extra = 128 bytes
280 sql.reserve(sql.length() + (accts.size() * 128));
281
282 bool first = true;
283 for (auto const& account : accts)
284 {
285 if (!first)
286 {
287 sql += ", ('";
288 }
289 else
290 {
291 sql += "('";
292 first = false;
293 }
294
295 sql += txnId;
296 sql += "','";
297 sql += toBase58(account);
298 sql += "',";
299 sql += ledgerSeq;
300 sql += ",";
301 sql += txnSeq;
302 sql += ")";
303 }
304 sql += ";";
305 JLOG(j.trace()) << "ActTx: " << sql;
306 *db << sql;
307 }
308 else if (auto const& sleTxn = acceptedLedgerTx->getTxn(); !isPseudoTx(*sleTxn))
309 {
310 // It's okay for pseudo transactions to not affect any
311 // accounts. But otherwise...
312 JLOG(j.warn()) << "Transaction in ledger " << seq << " affects no accounts";
313 JLOG(j.warn()) << sleTxn->getJson(JsonOptions::none);
314 }
315
316 *db
318 acceptedLedgerTx->getTxn()->getMetaSQL(
319 seq, acceptedLedgerTx->getEscMeta()) +
320 ";");
321
324 seq,
325 acceptedLedgerTx->getTxnSeq(),
327 }
328
329 tr.commit();
330 }
331
332 {
333 static std::string const addLedger(
334 R"sql(INSERT OR REPLACE INTO Ledgers
335 (LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,
336 CloseTimeRes,CloseFlags,AccountSetHash,TransSetHash)
337 VALUES
338 (:ledgerHash,:ledgerSeq,:prevHash,:totalCoins,:closingTime,:prevClosingTime,
339 :closeTimeRes,:closeFlags,:accountSetHash,:transSetHash);)sql");
340
341 auto db(ldgDB.checkoutDb());
342
343 soci::transaction tr(*db);
344
345 auto const hash = to_string(ledger->header().hash);
346 auto const parentHash = to_string(ledger->header().parentHash);
347 auto const drops = to_string(ledger->header().drops);
348 auto const closeTime = ledger->header().closeTime.time_since_epoch().count();
349 auto const parentCloseTime =
350 ledger->header().parentCloseTime.time_since_epoch().count();
351 auto const closeTimeResolution = ledger->header().closeTimeResolution.count();
352 auto const closeFlags = ledger->header().closeFlags;
353 auto const accountHash = to_string(ledger->header().accountHash);
354 auto const txHash = to_string(ledger->header().txHash);
355
356 *db << addLedger, soci::use(hash), soci::use(seq), soci::use(parentHash),
357 soci::use(drops), soci::use(closeTime), soci::use(parentCloseTime),
358 soci::use(closeTimeResolution), soci::use(closeFlags), soci::use(accountHash),
359 soci::use(txHash);
360
361 tr.commit();
362 }
363 }
364
365 return true;
366}
367
377getLedgerInfo(soci::session& session, std::string const& sqlSuffix, beast::Journal j)
378{
379 // SOCI requires boost::optional (not std::optional) as parameters.
380 boost::optional<std::string> hash, parentHash, accountHash, txHash;
381 boost::optional<std::uint64_t> seq, drops, closeTime, parentCloseTime, closeTimeResolution,
382 closeFlags;
383
384 std::string const sql =
385 "SELECT "
386 "LedgerHash, PrevHash, AccountSetHash, TransSetHash, "
387 "TotalCoins,"
388 "ClosingTime, PrevClosingTime, CloseTimeRes, CloseFlags,"
389 "LedgerSeq FROM Ledgers " +
390 sqlSuffix + ";";
391
392 session << sql, soci::into(hash), soci::into(parentHash), soci::into(accountHash),
393 soci::into(txHash), soci::into(drops), soci::into(closeTime), soci::into(parentCloseTime),
394 soci::into(closeTimeResolution), soci::into(closeFlags), soci::into(seq);
395
396 if (!session.got_data())
397 {
398 JLOG(j.debug()) << "Ledger not found: " << sqlSuffix;
399 return {};
400 }
401
402 using time_point = NetClock::time_point;
403 using duration = NetClock::duration;
404
405 LedgerHeader info;
406
407 if (hash && !info.hash.parseHex(*hash))
408 {
409 JLOG(j.debug()) << "Hash parse error for ledger: " << sqlSuffix;
410 return {};
411 }
412
413 if (parentHash && !info.parentHash.parseHex(*parentHash))
414 {
415 JLOG(j.debug()) << "parentHash parse error for ledger: " << sqlSuffix;
416 return {};
417 }
418
419 if (accountHash && !info.accountHash.parseHex(*accountHash))
420 {
421 JLOG(j.debug()) << "accountHash parse error for ledger: " << sqlSuffix;
422 return {};
423 }
424
425 if (txHash && !info.txHash.parseHex(*txHash))
426 {
427 JLOG(j.debug()) << "txHash parse error for ledger: " << sqlSuffix;
428 return {};
429 }
430
431 info.seq = rangeCheckedCast<std::uint32_t>(seq.value_or(0));
432 info.drops = drops.value_or(0);
433 info.closeTime = time_point{duration{closeTime.value_or(0)}};
434 info.parentCloseTime = time_point{duration{parentCloseTime.value_or(0)}};
435 info.closeFlags = closeFlags.value_or(0);
436 info.closeTimeResolution = duration{closeTimeResolution.value_or(0)};
438 return info;
439}
440
442getLedgerInfoByIndex(soci::session& session, LedgerIndex ledgerSeq, beast::Journal j)
443{
445 s << "WHERE LedgerSeq = " << ledgerSeq;
446 return getLedgerInfo(session, s.str(), j);
447}
448
450getNewestLedgerInfo(soci::session& session, beast::Journal j)
451{
453 s << "ORDER BY LedgerSeq DESC LIMIT 1";
454 return getLedgerInfo(session, s.str(), j);
455}
456
458getLimitedOldestLedgerInfo(soci::session& session, LedgerIndex ledgerFirstIndex, beast::Journal j)
459{
461 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
462 " ORDER BY LedgerSeq ASC LIMIT 1";
463 return getLedgerInfo(session, s.str(), j);
464}
465
467getLimitedNewestLedgerInfo(soci::session& session, LedgerIndex ledgerFirstIndex, beast::Journal j)
468{
470 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
471 " ORDER BY LedgerSeq DESC LIMIT 1";
472 return getLedgerInfo(session, s.str(), j);
473}
474
476getLedgerInfoByHash(soci::session& session, uint256 const& ledgerHash, beast::Journal j)
477{
479 s << "WHERE LedgerHash = '" << ledgerHash << "'";
480 return getLedgerInfo(session, s.str(), j);
481}
482
484getHashByIndex(soci::session& session, LedgerIndex ledgerIndex)
485{
486 uint256 ret;
487
488 std::string sql = "SELECT LedgerHash FROM Ledgers INDEXED BY SeqLedger WHERE LedgerSeq='";
489 sql.append(std::to_string(ledgerIndex));
490 sql.append("';");
491
492 std::string hash;
493 {
494 // SOCI requires boost::optional (not std::optional) as the parameter.
495 boost::optional<std::string> lh;
496 session << sql, soci::into(lh);
497
498 if (!session.got_data() || !lh)
499 return ret;
500
501 hash = *lh;
502 if (hash.empty())
503 return ret;
504 }
505
506 if (!ret.parseHex(hash))
507 return ret;
509 return ret;
510}
511
513getHashesByIndex(soci::session& session, LedgerIndex ledgerIndex, beast::Journal j)
514{
515 // SOCI requires boost::optional (not std::optional) as the parameter.
516 boost::optional<std::string> lhO, phO;
517
518 session << "SELECT LedgerHash,PrevHash FROM Ledgers "
519 "INDEXED BY SeqLedger WHERE LedgerSeq = :ls;",
520 soci::into(lhO), soci::into(phO), soci::use(ledgerIndex);
521
522 if (!lhO || !phO)
523 {
524 auto stream = j.trace();
525 JLOG(stream) << "Don't have ledger " << ledgerIndex;
526 return {};
527 }
528
529 LedgerHashPair hashes;
530 if (!hashes.ledgerHash.parseHex(*lhO) || !hashes.parentHash.parseHex(*phO))
531 {
532 auto stream = j.trace();
533 JLOG(stream) << "Error parse hashes for ledger " << ledgerIndex;
534 return {};
535 }
537 return hashes;
538}
539
541getHashesByIndex(soci::session& session, LedgerIndex minSeq, LedgerIndex maxSeq, beast::Journal j)
542{
543 std::string sql = "SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq >= ";
544 sql.append(std::to_string(minSeq));
545 sql.append(" AND LedgerSeq <= ");
546 sql.append(std::to_string(maxSeq));
547 sql.append(";");
548
549 std::uint64_t ls = 0;
550 std::string lh;
551 // SOCI requires boost::optional (not std::optional) as the parameter.
552 boost::optional<std::string> ph;
553 soci::statement st = (session.prepare << sql, soci::into(ls), soci::into(lh), soci::into(ph));
554
555 st.execute();
557 while (st.fetch())
558 {
559 LedgerHashPair& hashes = res[rangeCheckedCast<LedgerIndex>(ls)];
560 if (!hashes.ledgerHash.parseHex(lh))
561 {
562 JLOG(j.warn()) << "Error parsed hash for ledger seq: " << ls;
563 }
564 if (!ph)
565 {
566 JLOG(j.warn()) << "Null prev hash for ledger seq: " << ls;
567 }
568 else if (!hashes.parentHash.parseHex(*ph))
569 {
570 JLOG(j.warn()) << "Error parsed prev hash for ledger seq: " << ls;
571 }
573 return res;
574}
575
577getTxHistory(soci::session& session, Application& app, LedgerIndex startIndex, int quantity)
578{
579 std::string const sql = boost::str(
580 boost::format(
581 "SELECT LedgerSeq, Status, RawTxn "
582 "FROM Transactions ORDER BY LedgerSeq DESC LIMIT %u,%u;") %
583 startIndex % quantity);
584
586 int total = 0;
587
588 {
589 // SOCI requires boost::optional (not std::optional) as parameters.
590 boost::optional<std::uint64_t> ledgerSeq;
591 boost::optional<std::string> status;
592 soci::blob sociRawTxnBlob(session);
593 soci::indicator rti = soci::i_null;
594 Blob rawTxn;
595
596 soci::statement st =
597 (session.prepare << sql,
598 soci::into(ledgerSeq),
599 soci::into(status),
600 soci::into(sociRawTxnBlob, rti));
601
602 st.execute();
603 while (st.fetch())
604 {
605 if (soci::i_ok == rti)
606 {
607 convert(sociRawTxnBlob, rawTxn);
608 }
609 else
610 {
611 rawTxn.clear();
612 }
613
614 if (auto trans = Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app))
615 {
616 total++;
617 txs.push_back(trans);
618 }
619 }
620 }
621
622 return {txs, total};
623}
624
642static std::string
644 Application& app,
645 std::string selection,
646 RelationalDatabase::AccountTxOptions const& options,
647 bool descending,
648 bool binary,
649 bool count,
651{
652 constexpr std::uint32_t NONBINARY_PAGE_LENGTH = 200;
653 constexpr std::uint32_t BINARY_PAGE_LENGTH = 500;
654
655 std::uint32_t numberOfResults = 0;
656
657 if (count)
658 {
659 numberOfResults = std::numeric_limits<std::uint32_t>::max();
660 }
661 else if (options.limit == UINT32_MAX)
662 {
663 numberOfResults = binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH;
664 }
665 else if (!options.bUnlimited)
666 {
667 numberOfResults =
668 std::min(binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH, options.limit);
669 }
670 else
671 {
672 numberOfResults = options.limit;
673 }
674
675 std::string maxClause;
676 std::string minClause;
677
678 if (options.ledgerRange.max != 0u)
679 {
680 maxClause = boost::str(
681 boost::format("AND AccountTransactions.LedgerSeq <= '%u'") % options.ledgerRange.max);
682 }
683
684 if (options.ledgerRange.min != 0u)
685 {
686 minClause = boost::str(
687 boost::format("AND AccountTransactions.LedgerSeq >= '%u'") % options.ledgerRange.min);
688 }
689
690 std::string sql;
691
692 if (count)
693 {
694 sql = boost::str(
695 boost::format(
696 "SELECT %s FROM AccountTransactions "
697 "WHERE Account = '%s' %s %s LIMIT %u, %u;") %
698 selection % toBase58(options.account) % maxClause % minClause % options.offset %
699 numberOfResults);
700 }
701 else
702 {
703 sql = boost::str(
704 boost::format(
705 "SELECT %s FROM "
706 "AccountTransactions INNER JOIN Transactions "
707 "ON Transactions.TransID = AccountTransactions.TransID "
708 "WHERE Account = '%s' %s %s "
709 "ORDER BY AccountTransactions.LedgerSeq %s, "
710 "AccountTransactions.TxnSeq %s, AccountTransactions.TransID %s "
711 "LIMIT %u, %u;") %
712 selection % toBase58(options.account) % maxClause % minClause %
713 (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") %
714 (descending ? "DESC" : "ASC") % options.offset % numberOfResults);
715 }
716 JLOG(j.trace()) << "txSQL query: " << sql;
717 return sql;
718}
719
743 soci::session& session,
744 Application& app,
745 LedgerMaster& ledgerMaster,
746 RelationalDatabase::AccountTxOptions const& options,
747 bool descending,
749{
751
752 std::string const sql = transactionsSQL(
753 app,
754 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
755 options,
756 descending,
757 false,
758 false,
759 j);
760 if (sql.empty())
761 return {ret, 0};
762
763 int total = 0;
764 {
765 // SOCI requires boost::optional (not std::optional) as parameters.
766 boost::optional<std::uint64_t> ledgerSeq;
767 boost::optional<std::string> status;
768 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
769 soci::indicator rti = soci::i_null, tmi = soci::i_null;
770 Blob rawTxn, txnMeta;
771
772 soci::statement st =
773 (session.prepare << sql,
774 soci::into(ledgerSeq),
775 soci::into(status),
776 soci::into(sociTxnBlob, rti),
777 soci::into(sociTxnMetaBlob, tmi));
778
779 st.execute();
780 while (st.fetch())
781 {
782 if (soci::i_ok == rti)
783 {
784 convert(sociTxnBlob, rawTxn);
785 }
786 else
787 {
788 rawTxn.clear();
789 }
790
791 if (soci::i_ok == tmi)
792 {
793 convert(sociTxnMetaBlob, txnMeta);
794 }
795 else
796 {
797 txnMeta.clear();
798 }
799
800 auto txn = Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
801
802 if (txnMeta.empty())
803 { // Work around a bug that could leave the metadata missing
804 auto const seq = rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
805
806 JLOG(j.warn()) << "Recovering ledger " << seq << ", txn " << txn->getID();
807
808 if (auto l = ledgerMaster.getLedgerBySeq(seq))
809 pendSaveValidated(app, l, false, false);
810 }
811
812 if (txn)
813 {
814 ret.emplace_back(
815 txn, std::make_shared<TxMeta>(txn->getID(), txn->getLedger(), txnMeta));
816 total++;
817 }
818 }
819 }
821 return {ret, total};
822}
823
826 soci::session& session,
827 Application& app,
828 LedgerMaster& ledgerMaster,
829 RelationalDatabase::AccountTxOptions const& options,
832 return getAccountTxs(session, app, ledgerMaster, options, false, j);
833}
834
837 soci::session& session,
838 Application& app,
842{
843 return getAccountTxs(session, app, ledgerMaster, options, true, j);
844}
845
868 soci::session& session,
869 Application& app,
870 RelationalDatabase::AccountTxOptions const& options,
871 bool descending,
873{
875
876 std::string const sql = transactionsSQL(
877 app,
878 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
879 options,
880 descending,
881 true /*binary*/,
882 false,
883 j);
884 if (sql.empty())
885 return {ret, 0};
886
887 int total = 0;
888
889 {
890 // SOCI requires boost::optional (not std::optional) as parameters.
891 boost::optional<std::uint64_t> ledgerSeq;
892 boost::optional<std::string> status;
893 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
894 soci::indicator rti = soci::i_null, tmi = soci::i_null;
895
896 soci::statement st =
897 (session.prepare << sql,
898 soci::into(ledgerSeq),
899 soci::into(status),
900 soci::into(sociTxnBlob, rti),
901 soci::into(sociTxnMetaBlob, tmi));
902
903 st.execute();
904 while (st.fetch())
905 {
906 Blob rawTxn;
907 if (soci::i_ok == rti)
908 convert(sociTxnBlob, rawTxn);
909 Blob txnMeta;
910 if (soci::i_ok == tmi)
911 convert(sociTxnMetaBlob, txnMeta);
912
913 auto const seq = rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
914
915 ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq);
916 total++;
917 }
918 }
920 return {ret, total};
921}
922
925 soci::session& session,
926 Application& app,
927 RelationalDatabase::AccountTxOptions const& options,
930 return getAccountTxsB(session, app, options, false, j);
931}
932
935 soci::session& session,
936 Application& app,
939{
940 return getAccountTxsB(session, app, options, true, j);
941}
942
964 soci::session& session,
965 std::function<void(std::uint32_t)> const& onUnsavedLedger,
966 std::function<void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction,
967 RelationalDatabase::AccountTxPageOptions const& options,
968 std::uint32_t page_length,
969 bool forward)
970{
971 int total = 0;
972
973 bool lookingForMarker = options.marker.has_value();
974
975 std::uint32_t numberOfResults = 0;
976
977 if (options.limit == 0 || options.limit == UINT32_MAX ||
978 (options.limit > page_length && !options.bAdmin))
979 {
980 numberOfResults = page_length;
981 }
982 else
983 {
984 numberOfResults = options.limit;
985 }
986
987 // As an account can have many thousands of transactions, there is a limit
988 // placed on the amount of transactions returned. If the limit is reached
989 // before the result set has been exhausted (we always query for one more
990 // than the limit), then we return an opaque marker that can be supplied in
991 // a subsequent query.
992 std::uint32_t queryLimit = numberOfResults + 1;
993 std::uint32_t findLedger = 0, findSeq = 0;
994
995 if (lookingForMarker)
996 {
997 findLedger = options.marker->ledgerSeq;
998 findSeq = options.marker->txnSeq;
999 }
1000
1002
1003 static std::string const prefix(
1004 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1005 Status,RawTxn,TxnMeta
1006 FROM AccountTransactions INNER JOIN Transactions
1007 ON Transactions.TransID = AccountTransactions.TransID
1008 AND AccountTransactions.Account = '%s' WHERE
1009 )");
1010
1011 std::string sql;
1012
1013 // SQL's BETWEEN uses a closed interval ([a,b])
1014
1015 char const* const order = forward ? "ASC" : "DESC";
1016
1017 if (findLedger == 0)
1018 {
1019 sql = boost::str(
1020 boost::format(prefix + (R"(AccountTransactions.LedgerSeq BETWEEN %u AND %u
1021 ORDER BY AccountTransactions.LedgerSeq %s,
1022 AccountTransactions.TxnSeq %s
1023 LIMIT %u;)")) %
1024 toBase58(options.account) % options.ledgerRange.min % options.ledgerRange.max % order %
1025 order % queryLimit);
1026 }
1027 else
1028 {
1029 char const* const compare = forward ? ">=" : "<=";
1030 std::uint32_t const minLedger = forward ? findLedger + 1 : options.ledgerRange.min;
1031 std::uint32_t const maxLedger = forward ? options.ledgerRange.max : findLedger - 1;
1032
1033 auto b58acct = toBase58(options.account);
1034 sql = boost::str(
1035 boost::format((
1036 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1037 Status,RawTxn,TxnMeta
1038 FROM AccountTransactions, Transactions WHERE
1039 (AccountTransactions.TransID = Transactions.TransID AND
1040 AccountTransactions.Account = '%s' AND
1041 AccountTransactions.LedgerSeq BETWEEN %u AND %u)
1042 UNION
1043 SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,Status,RawTxn,TxnMeta
1044 FROM AccountTransactions, Transactions WHERE
1045 (AccountTransactions.TransID = Transactions.TransID AND
1046 AccountTransactions.Account = '%s' AND
1047 AccountTransactions.LedgerSeq = %u AND
1048 AccountTransactions.TxnSeq %s %u)
1049 ORDER BY AccountTransactions.LedgerSeq %s,
1050 AccountTransactions.TxnSeq %s
1051 LIMIT %u;
1052 )")) %
1053 b58acct % minLedger % maxLedger % b58acct % findLedger % compare % findSeq % order %
1054 order % queryLimit);
1055 }
1056
1057 {
1058 Blob rawData;
1059 Blob rawMeta;
1060
1061 // SOCI requires boost::optional (not std::optional) as parameters.
1062 boost::optional<std::uint64_t> ledgerSeq;
1063 boost::optional<std::uint32_t> txnSeq;
1064 boost::optional<std::string> status;
1065 soci::blob txnData(session);
1066 soci::blob txnMeta(session);
1067 soci::indicator dataPresent = soci::i_null, metaPresent = soci::i_null;
1068
1069 soci::statement st =
1070 (session.prepare << sql,
1071 soci::into(ledgerSeq),
1072 soci::into(txnSeq),
1073 soci::into(status),
1074 soci::into(txnData, dataPresent),
1075 soci::into(txnMeta, metaPresent));
1076
1077 st.execute();
1078
1079 while (st.fetch())
1080 {
1081 if (lookingForMarker)
1082 {
1083 if (findLedger == ledgerSeq.value_or(0) && findSeq == txnSeq.value_or(0))
1084 {
1085 lookingForMarker = false;
1086 }
1087 else
1088 {
1089 continue;
1090 }
1091 }
1092 else if (numberOfResults == 0)
1093 {
1094 newmarker = {
1095 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)), txnSeq.value_or(0)};
1096 break;
1097 }
1098
1099 if (dataPresent == soci::i_ok)
1100 {
1101 convert(txnData, rawData);
1102 }
1103 else
1104 {
1105 rawData.clear();
1106 }
1107
1108 if (metaPresent == soci::i_ok)
1109 {
1110 convert(txnMeta, rawMeta);
1111 }
1112 else
1113 {
1114 rawMeta.clear();
1115 }
1116
1117 // Work around a bug that could leave the metadata missing
1118 if (rawMeta.empty())
1119 onUnsavedLedger(ledgerSeq.value_or(0));
1120
1121 // `rawData` and `rawMeta` will be used after they are moved.
1122 // That's OK.
1123 onTransaction(
1124 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1125 *status,
1126 std::move(rawData),
1127 std::move(rawMeta));
1128 // Note some callbacks will move the data, some will not. Clear
1129 // them so code doesn't depend on if the data was actually moved
1130 // or not. The code will be more efficient if `rawData` and
1131 // `rawMeta` don't have to allocate in `convert`, so don't
1132 // refactor my moving these variables into loop scope.
1133 rawData.clear();
1134 rawMeta.clear();
1135
1136 --numberOfResults;
1137 total++;
1138 }
1139 }
1140
1141 return {newmarker, total};
1142}
1143
1146 soci::session& session,
1147 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1148 std::function<void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction,
1149 RelationalDatabase::AccountTxPageOptions const& options,
1150 std::uint32_t page_length)
1151{
1152 return accountTxPage(session, onUnsavedLedger, onTransaction, options, page_length, true);
1153}
1154
1157 soci::session& session,
1158 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1159 std::function<void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction,
1160 RelationalDatabase::AccountTxPageOptions const& options,
1161 std::uint32_t page_length)
1162{
1163 return accountTxPage(session, onUnsavedLedger, onTransaction, options, page_length, false);
1164}
1165
1168 soci::session& session,
1169 Application& app,
1170 uint256 const& id,
1171 std::optional<ClosedInterval<uint32_t>> const& range,
1172 error_code_i& ec)
1173{
1174 std::string sql =
1175 "SELECT LedgerSeq,Status,RawTxn,TxnMeta "
1176 "FROM Transactions WHERE TransID='";
1177
1178 sql.append(to_string(id));
1179 sql.append("';");
1180
1181 // SOCI requires boost::optional (not std::optional) as parameters.
1182 boost::optional<std::uint64_t> ledgerSeq;
1183 boost::optional<std::string> status;
1184 Blob rawTxn, rawMeta;
1185 {
1186 soci::blob sociRawTxnBlob(session), sociRawMetaBlob(session);
1187 soci::indicator txn = soci::i_null, meta = soci::i_null;
1188
1189 session << sql, soci::into(ledgerSeq), soci::into(status), soci::into(sociRawTxnBlob, txn),
1190 soci::into(sociRawMetaBlob, meta);
1191
1192 auto const got_data = session.got_data();
1193
1194 if ((!got_data || txn != soci::i_ok || meta != soci::i_ok) && !range)
1195 return TxSearched::Unknown;
1196
1197 if (!got_data)
1198 {
1199 uint64_t count = 0;
1200 soci::indicator rti = soci::i_null;
1201
1202 session << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
1203 "LedgerSeq BETWEEN "
1204 << range->first() << " AND " << range->last() << ";",
1205 soci::into(count, rti);
1206
1207 if (!session.got_data() || rti != soci::i_ok)
1208 return TxSearched::Some;
1209
1210 return count == (range->last() - range->first() + 1) ? TxSearched::All
1211 : TxSearched::Some;
1212 }
1213
1214 convert(sociRawTxnBlob, rawTxn);
1215 convert(sociRawMetaBlob, rawMeta);
1216 }
1218 try
1219 {
1220 auto txn = Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
1221
1222 if (!ledgerSeq)
1223 return std::pair{std::move(txn), nullptr};
1224
1225 std::uint32_t const inLedger = rangeCheckedCast<std::uint32_t>(ledgerSeq.value());
1226
1227 auto txMeta = std::make_shared<TxMeta>(id, inLedger, rawMeta);
1228
1229 return std::pair{std::move(txn), std::move(txMeta)};
1230 }
1231 catch (std::exception& e)
1232 {
1233 JLOG(app.getJournal("Ledger").warn())
1234 << "Unable to deserialize transaction from raw SQL value. Error: " << e.what();
1235
1237 }
1238
1239 return TxSearched::Unknown;
1240}
1241
1242bool
1243dbHasSpace(soci::session& session, Config const& config, beast::Journal j)
1244{
1245 boost::filesystem::space_info const space =
1246 boost::filesystem::space(config.legacy("database_path"));
1247
1248 if (space.available < megabytes(512))
1249 {
1250 JLOG(j.fatal()) << "Remaining free disk space is less than 512MB";
1251 return false;
1252 }
1253
1254 if (config.useTxTables())
1255 {
1256 DatabaseCon::Setup const dbSetup = setup_DatabaseCon(config);
1257 boost::filesystem::path const dbPath = dbSetup.dataDir / TxDBName;
1258 boost::system::error_code ec;
1259 std::optional<std::uint64_t> dbSize = boost::filesystem::file_size(dbPath, ec);
1260 if (ec)
1261 {
1262 JLOG(j.error()) << "Error checking transaction db file size: " << ec.message();
1263 dbSize.reset();
1264 }
1265
1266 static auto const pageSize = [&] {
1267 std::uint32_t ps = 0;
1268 session << "PRAGMA page_size;", soci::into(ps);
1269 return ps;
1270 }();
1271 static auto const maxPages = [&] {
1272 std::uint32_t mp = 0;
1273 session << "PRAGMA max_page_count;", soci::into(mp);
1274 return mp;
1275 }();
1276 std::uint32_t pageCount = 0;
1277 session << "PRAGMA page_count;", soci::into(pageCount);
1278 std::uint32_t const freePages = maxPages - pageCount;
1279 std::uint64_t const freeSpace = safe_cast<std::uint64_t>(freePages) * pageSize;
1280 JLOG(j.info()) << "Transaction DB pathname: " << dbPath.string()
1281 << "; file size: " << dbSize.value_or(-1) << " bytes"
1282 << "; SQLite page size: " << pageSize << " bytes"
1283 << "; Free pages: " << freePages << "; Free space: " << freeSpace
1284 << " bytes; "
1285 << "Note that this does not take into account available disk "
1286 "space.";
1287
1288 if (freeSpace < megabytes(512))
1289 {
1290 JLOG(j.fatal()) << "Free SQLite space for transaction db is less than "
1291 "512MB. To fix this, rippled must be executed with the "
1292 "vacuum parameter before restarting. "
1293 "Note that this activity can take multiple days, "
1294 "depending on database size.";
1295 return false;
1296 }
1297 }
1298
1299 return true;
1300}
1301
1302} // namespace detail
1303} // namespace xrpl
T append(T... args)
A generic endpoint for log messages.
Definition Journal.h:40
Stream fatal() const
Definition Journal.h:325
Stream error() const
Definition Journal.h:319
Stream debug() const
Definition Journal.h:301
Stream info() const
Definition Journal.h:307
Stream trace() const
Severity stream access functions.
Definition Journal.h:295
Stream warn() const
Definition Journal.h:313
virtual Config & config()=0
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:1150
LockedSociSession checkoutDb()
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:354
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)
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:476
T count(T... args)
T emplace_back(T... args)
T empty(T... args)
T is_same_v
T max(T... args)
T min(T... args)
int compare(SemanticVersion const &lhs, SemanticVersion const &rhs)
Compare two SemanticVersions against each other.
std::optional< LedgerHeader > getLedgerInfoByHash(soci::session &session, uint256 const &ledgerHash, beast::Journal j)
getLedgerInfoByHash Returns info of ledger with given hash.
Definition Node.cpp:471
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:165
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:132
std::optional< LedgerIndex > getMinLedgerSeq(soci::session &session, TableType type)
getMinLedgerSeq Returns minimum ledger sequence in given table.
Definition Node.cpp:106
std::optional< LedgerIndex > getMaxLedgerSeq(soci::session &session, TableType type)
getMaxLedgerSeq Returns maximum ledger sequence in given table.
Definition Node.cpp:116
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:831
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:572
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:919
std::optional< LedgerHeader > getNewestLedgerInfo(soci::session &session, beast::Journal j)
getNewestLedgerInfo Returns info of newest saved ledger.
Definition Node.cpp:445
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:453
std::variant< RelationalDatabase::AccountTx, TxSearched > getTransaction(soci::session &session, Application &app, uint256 const &id, std::optional< ClosedInterval< uint32_t > > const &range, error_code_i &ec)
getTransaction Returns transaction with given hash.
Definition Node.cpp:1141
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:51
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:150
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:737
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:372
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 page_length, bool forward)
accountTxPage Searches for the oldest or newest transactions for the account that matches the given c...
Definition Node.cpp:958
std::size_t getRows(soci::session &session, TableType type)
getRows Returns number of rows in given table.
Definition Node.cpp:138
std::optional< LedgerHeader > getLedgerInfoByIndex(soci::session &session, LedgerIndex ledgerSeq, beast::Journal j)
getLedgerInfoByIndex Returns ledger by its sequence.
Definition Node.cpp:437
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:929
uint256 getHashByIndex(soci::session &session, LedgerIndex ledgerIndex)
getHashByIndex Returns hash of ledger with given sequence.
Definition Node.cpp:479
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:126
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:820
bool dbHasSpace(soci::session &session, Config const &config, beast::Journal j)
dbHasSpace Checks if given database has available space.
Definition Node.cpp:1217
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:462
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:862
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 page_length)
oldestAccountTxPage Searches oldest transactions for given account which match given criteria startin...
Definition Node.cpp:1119
static std::string to_string(TableType type)
to_string Returns the name of a table according to its TableType.
Definition Node.cpp:30
constexpr int TableTypeCount
Definition Node.h:13
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 page_length)
newestAccountTxPage Searches newest transactions for given account which match given criteria startin...
Definition Node.cpp:1130
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:638
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:508
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
bool pendSaveValidated(ServiceRegistry &registry, std::shared_ptr< Ledger const > const &ledger, bool isSynchronous, bool isCurrent)
Save, or arrange to save, a fully-validated ledger.
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition RangeSet.h:34
constexpr std::array< char const *, 8 > TxDBInit
Definition DBInit.h:52
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:92
@ hotLEDGER
Definition NodeObject.h:14
@ current
This was a new validation and was added.
base_uint< 256 > uint256
Definition base_uint.h:531
constexpr auto megabytes(T value) noexcept
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
Definition Config.cpp:1179
std::uint32_t LedgerIndex
A ledger index.
Definition Protocol.h:255
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition Blob.h:10
constexpr auto TxDBName
Definition DBInit.h:50
constexpr auto kilobytes(T value) noexcept
TxSearched
Definition TxSearched.h:5
@ ledgerMaster
ledger master data for signing
@ transactionID
transaction plus signature to give transaction ID
constexpr auto LgrDBName
Definition DBInit.h:23
constexpr std::array< char const *, 5 > LgrDBInit
Definition DBInit.h:25
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition STTx.cpp:809
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition SociDB.cpp:130
error_code_i
Definition ErrorCodes.h:20
@ rpcDB_DESERIALIZATION
Definition ErrorCodes.h:114
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
T to_string(T... args)
T value_or(T... args)
T what(T... args)