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/LedgerToJson.h>
4#include <xrpld/app/ledger/PendingSaves.h>
5#include <xrpld/app/ledger/TransactionMaster.h>
6#include <xrpld/app/rdb/RelationalDatabase.h>
7#include <xrpld/app/rdb/backend/detail/Node.h>
8#include <xrpld/core/DatabaseCon.h>
9#include <xrpld/core/SociDB.h>
10
11#include <xrpl/basics/BasicConfig.h>
12#include <xrpl/basics/StringUtilities.h>
13#include <xrpl/json/to_string.h>
14
15#include <boost/range/adaptor/transformed.hpp>
16
17#include <soci/sqlite3/soci-sqlite3.h>
18
19namespace ripple {
20namespace detail {
21
27static std::string
29{
30 static_assert(
31 TableTypeCount == 3,
32 "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("ripple::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 == Config::LOAD ||
74 setup.startUp == Config::LOAD_FILE ||
75 setup.startUp == Config::REPLAY)
76 {
77 // Check if AccountTransactions has primary key
78 std::string cid, name, type;
79 std::size_t notnull, dflt_value, pk;
80 soci::indicator ind;
81 soci::statement st =
82 (tx->getSession().prepare
83 << ("PRAGMA table_info(AccountTransactions);"),
84 soci::into(cid),
85 soci::into(name),
86 soci::into(type),
87 soci::into(notnull),
88 soci::into(dflt_value, ind),
89 soci::into(pk));
90
91 st.execute();
92 while (st.fetch())
93 {
94 if (pk == 1)
95 {
96 return {std::move(lgr), std::move(tx), false};
97 }
98 }
99 }
100
101 return {std::move(lgr), std::move(tx), true};
102 }
103 else
104 return {std::move(lgr), {}, true};
105}
106
108getMinLedgerSeq(soci::session& session, TableType type)
109{
110 std::string query = "SELECT MIN(LedgerSeq) FROM " + to_string(type) + ";";
111 // SOCI requires boost::optional (not std::optional) as the parameter.
112 boost::optional<LedgerIndex> m;
113 session << query, soci::into(m);
114 return m ? *m : std::optional<LedgerIndex>();
115}
116
118getMaxLedgerSeq(soci::session& session, TableType type)
119{
120 std::string query = "SELECT MAX(LedgerSeq) FROM " + to_string(type) + ";";
121 // SOCI requires boost::optional (not std::optional) as the parameter.
122 boost::optional<LedgerIndex> m;
123 session << query, soci::into(m);
124 return m ? *m : std::optional<LedgerIndex>();
125}
126
127void
128deleteByLedgerSeq(soci::session& session, TableType type, LedgerIndex ledgerSeq)
129{
130 session << "DELETE FROM " << to_string(type)
131 << " WHERE LedgerSeq == " << ledgerSeq << ";";
132}
133
134void
136 soci::session& session,
137 TableType type,
138 LedgerIndex ledgerSeq)
139{
140 session << "DELETE FROM " << to_string(type) << " WHERE LedgerSeq < "
141 << ledgerSeq << ";";
142}
143
145getRows(soci::session& session, TableType type)
146{
147 std::size_t rows;
148 session << "SELECT COUNT(*) AS rows "
149 "FROM "
150 << to_string(type) << ";",
151 soci::into(rows);
152
153 return rows;
154}
155
157getRowsMinMax(soci::session& session, TableType type)
158{
160 session << "SELECT COUNT(*) AS rows, "
161 "MIN(LedgerSeq) AS first, "
162 "MAX(LedgerSeq) AS last "
163 "FROM "
164 << to_string(type) << ";",
165 soci::into(res.numberOfRows), soci::into(res.minLedgerSequence),
166 soci::into(res.maxLedgerSequence);
167
168 return res;
169}
170
171bool
173 DatabaseCon& ldgDB,
174 DatabaseCon& txnDB,
175 Application& app,
176 std::shared_ptr<Ledger const> const& ledger,
177 bool current)
178{
179 auto j = app.journal("Ledger");
180 auto seq = ledger->info().seq;
181
182 // TODO(tom): Fix this hard-coded SQL!
183 JLOG(j.trace()) << "saveValidatedLedger " << (current ? "" : "fromAcquire ")
184 << seq;
185
186 if (!ledger->info().accountHash.isNonZero())
187 {
188 // LCOV_EXCL_START
189 JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}});
190 UNREACHABLE("ripple::detail::saveValidatedLedger : zero account hash");
191 // LCOV_EXCL_STOP
192 }
193
194 if (ledger->info().accountHash != ledger->stateMap().getHash().as_uint256())
195 {
196 // LCOV_EXCL_START
197 JLOG(j.fatal()) << "sAL: " << ledger->info().accountHash
198 << " != " << ledger->stateMap().getHash();
199 JLOG(j.fatal()) << "saveAcceptedLedger: seq=" << seq
200 << ", current=" << current;
201 UNREACHABLE(
202 "ripple::detail::saveValidatedLedger : mismatched account hash");
203 // LCOV_EXCL_STOP
204 }
205
206 XRPL_ASSERT(
207 ledger->info().txHash == ledger->txMap().getHash().as_uint256(),
208 "ripple::detail::saveValidatedLedger : transaction hash match");
209
210 // Save the ledger header in the hashed object store
211 {
212 Serializer s(128);
214 addRaw(ledger->info(), s);
215 app.getNodeStore().store(
216 hotLEDGER, std::move(s.modData()), ledger->info().hash, seq);
217 }
218
220 try
221 {
222 aLedger = app.getAcceptedLedgerCache().fetch(ledger->info().hash);
223 if (!aLedger)
224 {
225 aLedger = std::make_shared<AcceptedLedger>(ledger, app);
226 app.getAcceptedLedgerCache().canonicalize_replace_client(
227 ledger->info().hash, aLedger);
228 }
229 }
230 catch (std::exception const&)
231 {
232 JLOG(j.warn()) << "An accepted ledger was missing nodes";
233 app.getLedgerMaster().failedSave(seq, ledger->info().hash);
234 // Clients can now trust the database for information about this
235 // ledger sequence.
236 app.pendingSaves().finishWork(seq);
237 return false;
238 }
239
240 {
241 static boost::format deleteLedger(
242 "DELETE FROM Ledgers WHERE LedgerSeq = %u;");
243 static boost::format deleteTrans1(
244 "DELETE FROM Transactions WHERE LedgerSeq = %u;");
245 static boost::format deleteTrans2(
246 "DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
247 static boost::format deleteAcctTrans(
248 "DELETE FROM AccountTransactions WHERE TransID = '%s';");
249
250 {
251 auto db = ldgDB.checkoutDb();
252 *db << boost::str(deleteLedger % seq);
253 }
254
255 if (app.config().useTxTables())
256 {
257 auto db = txnDB.checkoutDb();
258
259 soci::transaction tr(*db);
260
261 *db << boost::str(deleteTrans1 % seq);
262 *db << boost::str(deleteTrans2 % seq);
263
264 std::string const ledgerSeq(std::to_string(seq));
265
266 for (auto const& acceptedLedgerTx : *aLedger)
267 {
268 uint256 transactionID = acceptedLedgerTx->getTransactionID();
269
270 std::string const txnId(to_string(transactionID));
271 std::string const txnSeq(
272 std::to_string(acceptedLedgerTx->getTxnSeq()));
273
274 *db << boost::str(deleteAcctTrans % transactionID);
275
276 auto const& accts = acceptedLedgerTx->getAffected();
277
278 if (!accts.empty())
279 {
280 std::string sql(
281 "INSERT INTO AccountTransactions "
282 "(TransID, Account, LedgerSeq, TxnSeq) VALUES ");
283
284 // Try to make an educated guess on how much space we'll
285 // need for our arguments. In argument order we have: 64
286 // + 34 + 10 + 10 = 118 + 10 extra = 128 bytes
287 sql.reserve(sql.length() + (accts.size() * 128));
288
289 bool first = true;
290 for (auto const& account : accts)
291 {
292 if (!first)
293 sql += ", ('";
294 else
295 {
296 sql += "('";
297 first = false;
298 }
299
300 sql += txnId;
301 sql += "','";
302 sql += toBase58(account);
303 sql += "',";
304 sql += ledgerSeq;
305 sql += ",";
306 sql += txnSeq;
307 sql += ")";
308 }
309 sql += ";";
310 JLOG(j.trace()) << "ActTx: " << sql;
311 *db << sql;
312 }
313 else if (auto const& sleTxn = acceptedLedgerTx->getTxn();
314 !isPseudoTx(*sleTxn))
315 {
316 // It's okay for pseudo transactions to not affect any
317 // accounts. But otherwise...
318 JLOG(j.warn()) << "Transaction in ledger " << seq
319 << " affects no accounts";
320 JLOG(j.warn()) << sleTxn->getJson(JsonOptions::none);
321 }
322
323 *db
325 acceptedLedgerTx->getTxn()->getMetaSQL(
326 seq, acceptedLedgerTx->getEscMeta()) +
327 ";");
328
331 seq,
332 acceptedLedgerTx->getTxnSeq(),
333 app.config().NETWORK_ID);
334 }
335
336 tr.commit();
337 }
338
339 {
340 static std::string addLedger(
341 R"sql(INSERT OR REPLACE INTO Ledgers
342 (LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,
343 CloseTimeRes,CloseFlags,AccountSetHash,TransSetHash)
344 VALUES
345 (:ledgerHash,:ledgerSeq,:prevHash,:totalCoins,:closingTime,:prevClosingTime,
346 :closeTimeRes,:closeFlags,:accountSetHash,:transSetHash);)sql");
347
348 auto db(ldgDB.checkoutDb());
349
350 soci::transaction tr(*db);
351
352 auto const hash = to_string(ledger->info().hash);
353 auto const parentHash = to_string(ledger->info().parentHash);
354 auto const drops = to_string(ledger->info().drops);
355 auto const closeTime =
356 ledger->info().closeTime.time_since_epoch().count();
357 auto const parentCloseTime =
358 ledger->info().parentCloseTime.time_since_epoch().count();
359 auto const closeTimeResolution =
360 ledger->info().closeTimeResolution.count();
361 auto const closeFlags = ledger->info().closeFlags;
362 auto const accountHash = to_string(ledger->info().accountHash);
363 auto const txHash = to_string(ledger->info().txHash);
364
365 *db << addLedger, soci::use(hash), soci::use(seq),
366 soci::use(parentHash), soci::use(drops), soci::use(closeTime),
367 soci::use(parentCloseTime), soci::use(closeTimeResolution),
368 soci::use(closeFlags), soci::use(accountHash),
369 soci::use(txHash);
370
371 tr.commit();
372 }
373 }
374
375 return true;
376}
377
388 soci::session& session,
389 std::string const& sqlSuffix,
391{
392 // SOCI requires boost::optional (not std::optional) as parameters.
393 boost::optional<std::string> hash, parentHash, accountHash, txHash;
394 boost::optional<std::uint64_t> seq, drops, closeTime, parentCloseTime,
395 closeTimeResolution, closeFlags;
396
397 std::string const sql =
398 "SELECT "
399 "LedgerHash, PrevHash, AccountSetHash, TransSetHash, "
400 "TotalCoins,"
401 "ClosingTime, PrevClosingTime, CloseTimeRes, CloseFlags,"
402 "LedgerSeq FROM Ledgers " +
403 sqlSuffix + ";";
404
405 session << sql, soci::into(hash), soci::into(parentHash),
406 soci::into(accountHash), soci::into(txHash), soci::into(drops),
407 soci::into(closeTime), soci::into(parentCloseTime),
408 soci::into(closeTimeResolution), soci::into(closeFlags),
409 soci::into(seq);
410
411 if (!session.got_data())
412 {
413 JLOG(j.debug()) << "Ledger not found: " << sqlSuffix;
414 return {};
415 }
416
417 using time_point = NetClock::time_point;
418 using duration = NetClock::duration;
419
420 LedgerInfo info;
421
422 if (hash && !info.hash.parseHex(*hash))
423 {
424 JLOG(j.debug()) << "Hash parse error for ledger: " << sqlSuffix;
425 return {};
426 }
427
428 if (parentHash && !info.parentHash.parseHex(*parentHash))
429 {
430 JLOG(j.debug()) << "parentHash parse error for ledger: " << sqlSuffix;
431 return {};
432 }
433
434 if (accountHash && !info.accountHash.parseHex(*accountHash))
435 {
436 JLOG(j.debug()) << "accountHash parse error for ledger: " << sqlSuffix;
437 return {};
438 }
439
440 if (txHash && !info.txHash.parseHex(*txHash))
441 {
442 JLOG(j.debug()) << "txHash parse error for ledger: " << sqlSuffix;
443 return {};
444 }
445
446 info.seq = rangeCheckedCast<std::uint32_t>(seq.value_or(0));
447 info.drops = drops.value_or(0);
448 info.closeTime = time_point{duration{closeTime.value_or(0)}};
449 info.parentCloseTime = time_point{duration{parentCloseTime.value_or(0)}};
450 info.closeFlags = closeFlags.value_or(0);
451 info.closeTimeResolution = duration{closeTimeResolution.value_or(0)};
453 return info;
454}
455
458 soci::session& session,
459 LedgerIndex ledgerSeq,
461{
463 s << "WHERE LedgerSeq = " << ledgerSeq;
464 return getLedgerInfo(session, s.str(), j);
465}
466
468getNewestLedgerInfo(soci::session& session, beast::Journal j)
469{
471 s << "ORDER BY LedgerSeq DESC LIMIT 1";
472 return getLedgerInfo(session, s.str(), j);
473}
474
477 soci::session& session,
478 LedgerIndex ledgerFirstIndex,
480{
482 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
483 " ORDER BY LedgerSeq ASC LIMIT 1";
484 return getLedgerInfo(session, s.str(), j);
485}
486
489 soci::session& session,
490 LedgerIndex ledgerFirstIndex,
492{
494 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
495 " ORDER BY LedgerSeq DESC LIMIT 1";
496 return getLedgerInfo(session, s.str(), j);
497}
498
501 soci::session& session,
502 uint256 const& ledgerHash,
504{
506 s << "WHERE LedgerHash = '" << ledgerHash << "'";
507 return getLedgerInfo(session, s.str(), j);
508}
509
511getHashByIndex(soci::session& session, LedgerIndex ledgerIndex)
512{
513 uint256 ret;
514
515 std::string sql =
516 "SELECT LedgerHash FROM Ledgers INDEXED BY SeqLedger WHERE LedgerSeq='";
517 sql.append(std::to_string(ledgerIndex));
518 sql.append("';");
519
520 std::string hash;
521 {
522 // SOCI requires boost::optional (not std::optional) as the parameter.
523 boost::optional<std::string> lh;
524 session << sql, soci::into(lh);
525
526 if (!session.got_data() || !lh)
527 return ret;
528
529 hash = *lh;
530 if (hash.empty())
531 return ret;
532 }
533
534 if (!ret.parseHex(hash))
535 return ret;
537 return ret;
538}
539
542 soci::session& session,
543 LedgerIndex ledgerIndex,
545{
546 // SOCI requires boost::optional (not std::optional) as the parameter.
547 boost::optional<std::string> lhO, phO;
548
549 session << "SELECT LedgerHash,PrevHash FROM Ledgers "
550 "INDEXED BY SeqLedger WHERE LedgerSeq = :ls;",
551 soci::into(lhO), soci::into(phO), soci::use(ledgerIndex);
552
553 if (!lhO || !phO)
554 {
555 auto stream = j.trace();
556 JLOG(stream) << "Don't have ledger " << ledgerIndex;
557 return {};
558 }
559
560 LedgerHashPair hashes;
561 if (!hashes.ledgerHash.parseHex(*lhO) || !hashes.parentHash.parseHex(*phO))
562 {
563 auto stream = j.trace();
564 JLOG(stream) << "Error parse hashes for ledger " << ledgerIndex;
565 return {};
566 }
568 return hashes;
569}
570
573 soci::session& session,
574 LedgerIndex minSeq,
575 LedgerIndex maxSeq,
577{
578 std::string sql =
579 "SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq >= ";
580 sql.append(std::to_string(minSeq));
581 sql.append(" AND LedgerSeq <= ");
582 sql.append(std::to_string(maxSeq));
583 sql.append(";");
584
585 std::uint64_t ls;
586 std::string lh;
587 // SOCI requires boost::optional (not std::optional) as the parameter.
588 boost::optional<std::string> ph;
589 soci::statement st =
590 (session.prepare << sql,
591 soci::into(ls),
592 soci::into(lh),
593 soci::into(ph));
594
595 st.execute();
597 while (st.fetch())
598 {
599 LedgerHashPair& hashes = res[rangeCheckedCast<LedgerIndex>(ls)];
600 if (!hashes.ledgerHash.parseHex(lh))
601 {
602 JLOG(j.warn()) << "Error parsed hash for ledger seq: " << ls;
603 }
604 if (!ph)
605 {
606 JLOG(j.warn()) << "Null prev hash for ledger seq: " << ls;
607 }
608 else if (!hashes.parentHash.parseHex(*ph))
609 {
610 JLOG(j.warn()) << "Error parsed prev hash for ledger seq: " << ls;
611 }
613 return res;
614}
615
618 soci::session& session,
619 Application& app,
620 LedgerIndex startIndex,
621 int quantity)
622{
623 std::string sql = boost::str(
624 boost::format(
625 "SELECT LedgerSeq, Status, RawTxn "
626 "FROM Transactions ORDER BY LedgerSeq DESC LIMIT %u,%u;") %
627 startIndex % quantity);
628
630 int total = 0;
631
632 {
633 // SOCI requires boost::optional (not std::optional) as parameters.
634 boost::optional<std::uint64_t> ledgerSeq;
635 boost::optional<std::string> status;
636 soci::blob sociRawTxnBlob(session);
637 soci::indicator rti;
638 Blob rawTxn;
639
640 soci::statement st =
641 (session.prepare << sql,
642 soci::into(ledgerSeq),
643 soci::into(status),
644 soci::into(sociRawTxnBlob, rti));
645
646 st.execute();
647 while (st.fetch())
648 {
649 if (soci::i_ok == rti)
650 convert(sociRawTxnBlob, rawTxn);
651 else
652 rawTxn.clear();
653
654 if (auto trans = Transaction::transactionFromSQL(
655 ledgerSeq, status, rawTxn, app))
656 {
657 total++;
658 txs.push_back(trans);
659 }
660 }
661 }
662
663 return {txs, total};
664}
665
683static std::string
685 Application& app,
686 std::string selection,
687 RelationalDatabase::AccountTxOptions const& options,
688 bool descending,
689 bool binary,
690 bool count,
692{
693 constexpr std::uint32_t NONBINARY_PAGE_LENGTH = 200;
694 constexpr std::uint32_t BINARY_PAGE_LENGTH = 500;
695
696 std::uint32_t numberOfResults;
697
698 if (count)
699 {
700 numberOfResults = std::numeric_limits<std::uint32_t>::max();
701 }
702 else if (options.limit == UINT32_MAX)
703 {
704 numberOfResults = binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH;
705 }
706 else if (!options.bUnlimited)
707 {
708 numberOfResults = std::min(
709 binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH, options.limit);
710 }
711 else
712 {
713 numberOfResults = options.limit;
714 }
715
716 std::string maxClause = "";
717 std::string minClause = "";
718
719 if (options.maxLedger)
720 {
721 maxClause = boost::str(
722 boost::format("AND AccountTransactions.LedgerSeq <= '%u'") %
723 options.maxLedger);
724 }
725
726 if (options.minLedger)
727 {
728 minClause = boost::str(
729 boost::format("AND AccountTransactions.LedgerSeq >= '%u'") %
730 options.minLedger);
731 }
732
733 std::string sql;
734
735 if (count)
736 sql = boost::str(
737 boost::format("SELECT %s FROM AccountTransactions "
738 "WHERE Account = '%s' %s %s LIMIT %u, %u;") %
739 selection % toBase58(options.account) % maxClause % minClause %
740 options.offset % numberOfResults);
741 else
742 sql = boost::str(
743 boost::format(
744 "SELECT %s FROM "
745 "AccountTransactions INNER JOIN Transactions "
746 "ON Transactions.TransID = AccountTransactions.TransID "
747 "WHERE Account = '%s' %s %s "
748 "ORDER BY AccountTransactions.LedgerSeq %s, "
749 "AccountTransactions.TxnSeq %s, AccountTransactions.TransID %s "
750 "LIMIT %u, %u;") %
751 selection % toBase58(options.account) % maxClause % minClause %
752 (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") %
753 (descending ? "DESC" : "ASC") % options.offset % numberOfResults);
754 JLOG(j.trace()) << "txSQL query: " << sql;
755 return sql;
756}
757
781 soci::session& session,
782 Application& app,
783 LedgerMaster& ledgerMaster,
784 RelationalDatabase::AccountTxOptions const& options,
785 bool descending,
787{
789
791 app,
792 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
793 options,
794 descending,
795 false,
796 false,
797 j);
798 if (sql == "")
799 return {ret, 0};
800
801 int total = 0;
802 {
803 // SOCI requires boost::optional (not std::optional) as parameters.
804 boost::optional<std::uint64_t> ledgerSeq;
805 boost::optional<std::string> status;
806 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
807 soci::indicator rti, tmi;
808 Blob rawTxn, txnMeta;
809
810 soci::statement st =
811 (session.prepare << sql,
812 soci::into(ledgerSeq),
813 soci::into(status),
814 soci::into(sociTxnBlob, rti),
815 soci::into(sociTxnMetaBlob, tmi));
816
817 st.execute();
818 while (st.fetch())
819 {
820 if (soci::i_ok == rti)
821 convert(sociTxnBlob, rawTxn);
822 else
823 rawTxn.clear();
824
825 if (soci::i_ok == tmi)
826 convert(sociTxnMetaBlob, txnMeta);
827 else
828 txnMeta.clear();
829
830 auto txn =
831 Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
832
833 if (txnMeta.empty())
834 { // Work around a bug that could leave the metadata missing
835 auto const seq =
836 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
837
838 JLOG(j.warn())
839 << "Recovering ledger " << seq << ", txn " << txn->getID();
840
841 if (auto l = ledgerMaster.getLedgerBySeq(seq))
842 pendSaveValidated(app, l, false, false);
843 }
844
845 if (txn)
846 {
847 ret.emplace_back(
848 txn,
850 txn->getID(), txn->getLedger(), txnMeta));
851 total++;
852 }
853 }
854 }
856 return {ret, total};
857}
858
861 soci::session& session,
862 Application& app,
863 LedgerMaster& ledgerMaster,
864 RelationalDatabase::AccountTxOptions const& options,
867 return getAccountTxs(session, app, ledgerMaster, options, false, j);
868}
869
872 soci::session& session,
873 Application& app,
877{
878 return getAccountTxs(session, app, ledgerMaster, options, true, j);
879}
880
903 soci::session& session,
904 Application& app,
905 RelationalDatabase::AccountTxOptions const& options,
906 bool descending,
908{
910
912 app,
913 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
914 options,
915 descending,
916 true /*binary*/,
917 false,
918 j);
919 if (sql == "")
920 return {ret, 0};
921
922 int total = 0;
923
924 {
925 // SOCI requires boost::optional (not std::optional) as parameters.
926 boost::optional<std::uint64_t> ledgerSeq;
927 boost::optional<std::string> status;
928 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
929 soci::indicator rti, tmi;
930
931 soci::statement st =
932 (session.prepare << sql,
933 soci::into(ledgerSeq),
934 soci::into(status),
935 soci::into(sociTxnBlob, rti),
936 soci::into(sociTxnMetaBlob, tmi));
937
938 st.execute();
939 while (st.fetch())
940 {
941 Blob rawTxn;
942 if (soci::i_ok == rti)
943 convert(sociTxnBlob, rawTxn);
944 Blob txnMeta;
945 if (soci::i_ok == tmi)
946 convert(sociTxnMetaBlob, txnMeta);
947
948 auto const seq =
949 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
950
951 ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq);
952 total++;
953 }
954 }
956 return {ret, total};
957}
958
961 soci::session& session,
962 Application& app,
963 RelationalDatabase::AccountTxOptions const& options,
966 return getAccountTxsB(session, app, options, false, j);
967}
968
971 soci::session& session,
972 Application& app,
975{
976 return getAccountTxsB(session, app, options, true, j);
977}
978
1000 soci::session& session,
1001 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1003 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1004 onTransaction,
1005 RelationalDatabase::AccountTxPageOptions const& options,
1006 std::uint32_t page_length,
1007 bool forward)
1008{
1009 int total = 0;
1010
1011 bool lookingForMarker = options.marker.has_value();
1012
1013 std::uint32_t numberOfResults;
1014
1015 if (options.limit == 0 || options.limit == UINT32_MAX ||
1016 (options.limit > page_length && !options.bAdmin))
1017 numberOfResults = page_length;
1018 else
1019 numberOfResults = options.limit;
1020
1021 // As an account can have many thousands of transactions, there is a limit
1022 // placed on the amount of transactions returned. If the limit is reached
1023 // before the result set has been exhausted (we always query for one more
1024 // than the limit), then we return an opaque marker that can be supplied in
1025 // a subsequent query.
1026 std::uint32_t queryLimit = numberOfResults + 1;
1027 std::uint32_t findLedger = 0, findSeq = 0;
1028
1029 if (lookingForMarker)
1030 {
1031 findLedger = options.marker->ledgerSeq;
1032 findSeq = options.marker->txnSeq;
1033 }
1034
1036
1037 static std::string const prefix(
1038 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1039 Status,RawTxn,TxnMeta
1040 FROM AccountTransactions INNER JOIN Transactions
1041 ON Transactions.TransID = AccountTransactions.TransID
1042 AND AccountTransactions.Account = '%s' WHERE
1043 )");
1044
1045 std::string sql;
1046
1047 // SQL's BETWEEN uses a closed interval ([a,b])
1048
1049 char const* const order = forward ? "ASC" : "DESC";
1050
1051 if (findLedger == 0)
1052 {
1053 sql = boost::str(
1054 boost::format(
1055 prefix + (R"(AccountTransactions.LedgerSeq BETWEEN %u AND %u
1056 ORDER BY AccountTransactions.LedgerSeq %s,
1057 AccountTransactions.TxnSeq %s
1058 LIMIT %u;)")) %
1059 toBase58(options.account) % options.minLedger % options.maxLedger %
1060 order % order % queryLimit);
1061 }
1062 else
1063 {
1064 char const* const compare = forward ? ">=" : "<=";
1065 std::uint32_t const minLedger =
1066 forward ? findLedger + 1 : options.minLedger;
1067 std::uint32_t const maxLedger =
1068 forward ? options.maxLedger : findLedger - 1;
1069
1070 auto b58acct = toBase58(options.account);
1071 sql = boost::str(
1072 boost::format((
1073 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1074 Status,RawTxn,TxnMeta
1075 FROM AccountTransactions, Transactions WHERE
1076 (AccountTransactions.TransID = Transactions.TransID AND
1077 AccountTransactions.Account = '%s' AND
1078 AccountTransactions.LedgerSeq BETWEEN %u AND %u)
1079 UNION
1080 SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,Status,RawTxn,TxnMeta
1081 FROM AccountTransactions, Transactions WHERE
1082 (AccountTransactions.TransID = Transactions.TransID AND
1083 AccountTransactions.Account = '%s' AND
1084 AccountTransactions.LedgerSeq = %u AND
1085 AccountTransactions.TxnSeq %s %u)
1086 ORDER BY AccountTransactions.LedgerSeq %s,
1087 AccountTransactions.TxnSeq %s
1088 LIMIT %u;
1089 )")) %
1090 b58acct % minLedger % maxLedger % b58acct % findLedger % compare %
1091 findSeq % order % order % queryLimit);
1092 }
1093
1094 {
1095 Blob rawData;
1096 Blob rawMeta;
1097
1098 // SOCI requires boost::optional (not std::optional) as parameters.
1099 boost::optional<std::uint64_t> ledgerSeq;
1100 boost::optional<std::uint32_t> txnSeq;
1101 boost::optional<std::string> status;
1102 soci::blob txnData(session);
1103 soci::blob txnMeta(session);
1104 soci::indicator dataPresent, metaPresent;
1105
1106 soci::statement st =
1107 (session.prepare << sql,
1108 soci::into(ledgerSeq),
1109 soci::into(txnSeq),
1110 soci::into(status),
1111 soci::into(txnData, dataPresent),
1112 soci::into(txnMeta, metaPresent));
1113
1114 st.execute();
1115
1116 while (st.fetch())
1117 {
1118 if (lookingForMarker)
1119 {
1120 if (findLedger == ledgerSeq.value_or(0) &&
1121 findSeq == txnSeq.value_or(0))
1122 {
1123 lookingForMarker = false;
1124 }
1125 else
1126 continue;
1127 }
1128 else if (numberOfResults == 0)
1129 {
1130 newmarker = {
1131 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1132 txnSeq.value_or(0)};
1133 break;
1134 }
1135
1136 if (dataPresent == soci::i_ok)
1137 convert(txnData, rawData);
1138 else
1139 rawData.clear();
1140
1141 if (metaPresent == soci::i_ok)
1142 convert(txnMeta, rawMeta);
1143 else
1144 rawMeta.clear();
1145
1146 // Work around a bug that could leave the metadata missing
1147 if (rawMeta.size() == 0)
1148 onUnsavedLedger(ledgerSeq.value_or(0));
1149
1150 // `rawData` and `rawMeta` will be used after they are moved.
1151 // That's OK.
1152 onTransaction(
1153 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1154 *status,
1155 std::move(rawData),
1156 std::move(rawMeta));
1157 // Note some callbacks will move the data, some will not. Clear
1158 // them so code doesn't depend on if the data was actually moved
1159 // or not. The code will be more efficient if `rawData` and
1160 // `rawMeta` don't have to allocate in `convert`, so don't
1161 // refactor my moving these variables into loop scope.
1162 rawData.clear();
1163 rawMeta.clear();
1164
1165 --numberOfResults;
1166 total++;
1167 }
1168 }
1169
1170 return {newmarker, total};
1171}
1172
1175 soci::session& session,
1176 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1178 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1179 onTransaction,
1181 std::uint32_t page_length)
1182{
1183 return accountTxPage(
1184 session, onUnsavedLedger, onTransaction, options, page_length, true);
1185}
1186
1189 soci::session& session,
1190 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1192 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1193 onTransaction,
1195 std::uint32_t page_length)
1196{
1197 return accountTxPage(
1198 session, onUnsavedLedger, onTransaction, options, page_length, false);
1199}
1200
1203 soci::session& session,
1204 Application& app,
1205 uint256 const& id,
1206 std::optional<ClosedInterval<uint32_t>> const& range,
1207 error_code_i& ec)
1208{
1209 std::string sql =
1210 "SELECT LedgerSeq,Status,RawTxn,TxnMeta "
1211 "FROM Transactions WHERE TransID='";
1212
1213 sql.append(to_string(id));
1214 sql.append("';");
1215
1216 // SOCI requires boost::optional (not std::optional) as parameters.
1217 boost::optional<std::uint64_t> ledgerSeq;
1218 boost::optional<std::string> status;
1219 Blob rawTxn, rawMeta;
1220 {
1221 soci::blob sociRawTxnBlob(session), sociRawMetaBlob(session);
1222 soci::indicator txn, meta;
1223
1224 session << sql, soci::into(ledgerSeq), soci::into(status),
1225 soci::into(sociRawTxnBlob, txn), soci::into(sociRawMetaBlob, meta);
1226
1227 auto const got_data = session.got_data();
1228
1229 if ((!got_data || txn != soci::i_ok || meta != soci::i_ok) && !range)
1230 return TxSearched::unknown;
1231
1232 if (!got_data)
1233 {
1234 uint64_t count = 0;
1235 soci::indicator rti;
1236
1237 session
1238 << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
1239 "LedgerSeq BETWEEN "
1240 << range->first() << " AND " << range->last() << ";",
1241 soci::into(count, rti);
1242
1243 if (!session.got_data() || rti != soci::i_ok)
1244 return TxSearched::some;
1245
1246 return count == (range->last() - range->first() + 1)
1248 : TxSearched::some;
1249 }
1250
1251 convert(sociRawTxnBlob, rawTxn);
1252 convert(sociRawMetaBlob, rawMeta);
1253 }
1254
1255 try
1256 {
1257 auto txn =
1258 Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
1259
1260 if (!ledgerSeq)
1261 return std::pair{std::move(txn), nullptr};
1262
1263 std::uint32_t inLedger =
1264 rangeCheckedCast<std::uint32_t>(ledgerSeq.value());
1265
1266 auto txMeta = std::make_shared<TxMeta>(id, inLedger, rawMeta);
1267
1268 return std::pair{std::move(txn), std::move(txMeta)};
1269 }
1270 catch (std::exception& e)
1271 {
1272 JLOG(app.journal("Ledger").warn())
1273 << "Unable to deserialize transaction from raw SQL value. Error: "
1274 << e.what();
1275
1277 }
1278
1279 return TxSearched::unknown;
1280}
1281
1282bool
1283dbHasSpace(soci::session& session, Config const& config, beast::Journal j)
1284{
1285 boost::filesystem::space_info space =
1286 boost::filesystem::space(config.legacy("database_path"));
1287
1288 if (space.available < megabytes(512))
1289 {
1290 JLOG(j.fatal()) << "Remaining free disk space is less than 512MB";
1291 return false;
1292 }
1293
1294 if (config.useTxTables())
1295 {
1296 DatabaseCon::Setup dbSetup = setup_DatabaseCon(config);
1297 boost::filesystem::path dbPath = dbSetup.dataDir / TxDBName;
1298 boost::system::error_code ec;
1300 boost::filesystem::file_size(dbPath, ec);
1301 if (ec)
1302 {
1303 JLOG(j.error())
1304 << "Error checking transaction db file size: " << ec.message();
1305 dbSize.reset();
1306 }
1307
1308 static auto const pageSize = [&] {
1309 std::uint32_t ps;
1310 session << "PRAGMA page_size;", soci::into(ps);
1311 return ps;
1312 }();
1313 static auto const maxPages = [&] {
1314 std::uint32_t mp;
1315 session << "PRAGMA max_page_count;", soci::into(mp);
1316 return mp;
1317 }();
1318 std::uint32_t pageCount;
1319 session << "PRAGMA page_count;", soci::into(pageCount);
1320 std::uint32_t freePages = maxPages - pageCount;
1321 std::uint64_t freeSpace =
1322 safe_cast<std::uint64_t>(freePages) * pageSize;
1323 JLOG(j.info())
1324 << "Transaction DB pathname: " << dbPath.string()
1325 << "; file size: " << dbSize.value_or(-1) << " bytes"
1326 << "; SQLite page size: " << pageSize << " bytes"
1327 << "; Free pages: " << freePages << "; Free space: " << freeSpace
1328 << " bytes; "
1329 << "Note that this does not take into account available disk "
1330 "space.";
1331
1332 if (freeSpace < megabytes(512))
1333 {
1334 JLOG(j.fatal())
1335 << "Free SQLite space for transaction db is less than "
1336 "512MB. To fix this, rippled must be executed with the "
1337 "vacuum parameter before restarting. "
1338 "Note that this activity can take multiple days, "
1339 "depending on database size.";
1340 return false;
1341 }
1342 }
1343
1344 return true;
1345}
1346
1347} // namespace detail
1348} // namespace ripple
T append(T... args)
A generic endpoint for log messages.
Definition Journal.h:41
Stream fatal() const
Definition Journal.h:333
Stream error() const
Definition Journal.h:327
Stream debug() const
Definition Journal.h:309
Stream info() const
Definition Journal.h:315
Stream trace() const
Severity stream access functions.
Definition Journal.h:303
Stream warn() const
Definition Journal.h:321
virtual Config & config()=0
virtual beast::Journal journal(std::string const &name)=0
virtual NodeStore::Database & getNodeStore()=0
virtual TaggedCache< uint256, AcceptedLedger > & getAcceptedLedgerCache()=0
virtual LedgerMaster & getLedgerMaster()=0
virtual TransactionMaster & getMasterTransaction()=0
virtual PendingSaves & pendingSaves()=0
uint32_t NETWORK_ID
Definition Config.h:137
bool useTxTables() const
Definition Config.h:323
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:1097
LockedSociSession checkoutDb()
void failedSave(std::uint32_t seq, uint256 const &hash)
std::chrono::time_point< NetClock > time_point
Definition chrono.h:50
std::chrono::duration< rep, period > duration
Definition chrono.h:49
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:356
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:484
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.
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:897
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:157
uint256 getHashByIndex(soci::session &session, LedgerIndex ledgerIndex)
getHashByIndex Returns hash of ledger with given sequence.
Definition Node.cpp:506
std::optional< LedgerInfo > getLimitedNewestLedgerInfo(soci::session &session, LedgerIndex ledgerFirstIndex, beast::Journal j)
getLimitedNewestLedgerInfo Returns info of newest ledger from ledgers with sequences greather or equa...
Definition Node.cpp:483
static std::string to_string(TableType type)
to_string Returns the name of a table according to its TableType.
Definition Node.cpp:28
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:1162
std::optional< LedgerInfo > getNewestLedgerInfo(soci::session &session, beast::Journal j)
getNewestLedgerInfo Returns info of newest saved ledger.
Definition Node.cpp:463
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:775
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:1148
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
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:128
std::size_t getRows(soci::session &session, TableType type)
getRows Returns number of rows in given table.
Definition Node.cpp:145
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:135
bool saveValidatedLedger(DatabaseCon &ldgDB, DatabaseCon &txnDB, Application &app, std::shared_ptr< Ledger const > const &ledger, bool current)
saveValidatedLedger Saves ledger into database.
Definition Node.cpp:172
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:855
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:612
constexpr int TableTypeCount
Definition Node.h:13
std::optional< LedgerInfo > getLimitedOldestLedgerInfo(soci::session &session, LedgerIndex ledgerFirstIndex, beast::Journal j)
getLimitedOldestLedgerInfo Returns info of oldest ledger from ledgers with sequences greather or equa...
Definition Node.cpp:471
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:955
std::optional< LedgerInfo > getLedgerInfoByIndex(soci::session &session, LedgerIndex ledgerSeq, beast::Journal j)
getLedgerInfoByIndex Returns ledger by its sequence.
Definition Node.cpp:452
bool dbHasSpace(soci::session &session, Config const &config, beast::Journal j)
dbHasSpace Checks if given database has available space.
Definition Node.cpp:1257
std::optional< LedgerInfo > getLedgerInfoByHash(soci::session &session, uint256 const &ledgerHash, beast::Journal j)
getLedgerInfoByHash Returns info of ledger with given hash.
Definition Node.cpp:495
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:679
std::optional< LedgerIndex > getMinLedgerSeq(soci::session &session, TableType type)
getMinLedgerSeq Returns minimum ledger sequence in given table.
Definition Node.cpp:108
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:866
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:965
static std::optional< LedgerInfo > 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:382
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:536
std::optional< LedgerIndex > getMaxLedgerSeq(soci::session &session, TableType type)
getMaxLedgerSeq Returns maximum ledger sequence in given table.
Definition Node.cpp:118
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:994
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:1176
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:6
constexpr std::array< char const *, 8 > TxDBInit
Definition DBInit.h:53
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:95
std::uint32_t LedgerIndex
A ledger index.
Definition Protocol.h:120
constexpr auto megabytes(T value) noexcept
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition STTx.cpp:851
@ rpcDB_DESERIALIZATION
Definition ErrorCodes.h:115
base_uint< 256 > uint256
Definition base_uint.h:539
@ hotLEDGER
Definition NodeObject.h:15
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition SociDB.cpp:138
constexpr auto LgrDBName
Definition DBInit.h:24
@ current
This was a new validation and was added.
constexpr std::array< char const *, 5 > LgrDBInit
Definition DBInit.h:26
constexpr auto kilobytes(T value) noexcept
constexpr auto TxDBName
Definition DBInit.h:51
LedgerHeader LedgerInfo
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition Blob.h:11
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition RangeSet.h:35
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
@ ledgerMaster
ledger master data for signing
@ transactionID
transaction plus signature to give transaction ID
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
bool pendSaveValidated(Application &app, std::shared_ptr< Ledger const > const &ledger, bool isSynchronous, bool isCurrent)
Save, or arrange to save, a fully-validated ledger Returns false on error.
Definition Ledger.cpp:978
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, 1 > lgrPragma
Definition DatabaseCon.h:93
Config::StartUpType startUp
Definition DatabaseCon.h:73
std::array< std::string, 4 > txPragma
Definition DatabaseCon.h:92
T to_string(T... args)
T value_or(T... args)
T what(T... args)