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 xrpl {
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("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 == 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 std::unique_ptr<DatabaseCon> const& 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->header().seq;
181
182 // TODO(tom): Fix this hard-coded SQL!
183 JLOG(j.trace()) << "saveValidatedLedger " << (current ? "" : "fromAcquire ")
184 << seq;
185
186 if (!ledger->header().accountHash.isNonZero())
187 {
188 // LCOV_EXCL_START
189 JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}});
190 UNREACHABLE("xrpl::detail::saveValidatedLedger : zero account hash");
191 // LCOV_EXCL_STOP
192 }
193
194 if (ledger->header().accountHash !=
195 ledger->stateMap().getHash().as_uint256())
196 {
197 // LCOV_EXCL_START
198 JLOG(j.fatal()) << "sAL: " << ledger->header().accountHash
199 << " != " << ledger->stateMap().getHash();
200 JLOG(j.fatal()) << "saveAcceptedLedger: seq=" << seq
201 << ", current=" << current;
202 UNREACHABLE(
203 "xrpl::detail::saveValidatedLedger : mismatched account hash");
204 // LCOV_EXCL_STOP
205 }
206
207 XRPL_ASSERT(
208 ledger->header().txHash == ledger->txMap().getHash().as_uint256(),
209 "xrpl::detail::saveValidatedLedger : transaction hash match");
210
211 // Save the ledger header in the hashed object store
212 {
213 Serializer s(128);
215 addRaw(ledger->header(), s);
216 app.getNodeStore().store(
217 hotLEDGER, std::move(s.modData()), ledger->header().hash, seq);
218 }
219
221 try
222 {
223 aLedger = app.getAcceptedLedgerCache().fetch(ledger->header().hash);
224 if (!aLedger)
225 {
226 aLedger = std::make_shared<AcceptedLedger>(ledger, app);
227 app.getAcceptedLedgerCache().canonicalize_replace_client(
228 ledger->header().hash, aLedger);
229 }
230 }
231 catch (std::exception const&)
232 {
233 JLOG(j.warn()) << "An accepted ledger was missing nodes";
234 app.getLedgerMaster().failedSave(seq, ledger->header().hash);
235 // Clients can now trust the database for information about this
236 // ledger sequence.
237 app.pendingSaves().finishWork(seq);
238 return false;
239 }
240
241 {
242 static boost::format deleteLedger(
243 "DELETE FROM Ledgers WHERE LedgerSeq = %u;");
244 static boost::format deleteTrans1(
245 "DELETE FROM Transactions WHERE LedgerSeq = %u;");
246 static boost::format deleteTrans2(
247 "DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
248 static boost::format deleteAcctTrans(
249 "DELETE FROM AccountTransactions WHERE TransID = '%s';");
250
251 {
252 auto db = ldgDB.checkoutDb();
253 *db << boost::str(deleteLedger % seq);
254 }
255
256 if (app.config().useTxTables())
257 {
258 if (!txnDB)
259 {
260 // LCOV_EXCL_START
261 JLOG(j.fatal()) << "TxTables db isn't available";
262 Throw<std::runtime_error>("TxTables db isn't available");
263 // LCOV_EXCL_STOP
264 }
265
266 auto db = txnDB->checkoutDb();
267
268 soci::transaction tr(*db);
269
270 *db << boost::str(deleteTrans1 % seq);
271 *db << boost::str(deleteTrans2 % seq);
272
273 std::string const ledgerSeq(std::to_string(seq));
274
275 for (auto const& acceptedLedgerTx : *aLedger)
276 {
277 uint256 transactionID = acceptedLedgerTx->getTransactionID();
278
279 std::string const txnId(to_string(transactionID));
280 std::string const txnSeq(
281 std::to_string(acceptedLedgerTx->getTxnSeq()));
282
283 *db << boost::str(deleteAcctTrans % transactionID);
284
285 auto const& accts = acceptedLedgerTx->getAffected();
286
287 if (!accts.empty())
288 {
289 std::string sql(
290 "INSERT INTO AccountTransactions "
291 "(TransID, Account, LedgerSeq, TxnSeq) VALUES ");
292
293 // Try to make an educated guess on how much space we'll
294 // need for our arguments. In argument order we have: 64
295 // + 34 + 10 + 10 = 118 + 10 extra = 128 bytes
296 sql.reserve(sql.length() + (accts.size() * 128));
297
298 bool first = true;
299 for (auto const& account : accts)
300 {
301 if (!first)
302 sql += ", ('";
303 else
304 {
305 sql += "('";
306 first = false;
307 }
308
309 sql += txnId;
310 sql += "','";
311 sql += toBase58(account);
312 sql += "',";
313 sql += ledgerSeq;
314 sql += ",";
315 sql += txnSeq;
316 sql += ")";
317 }
318 sql += ";";
319 JLOG(j.trace()) << "ActTx: " << sql;
320 *db << sql;
321 }
322 else if (auto const& sleTxn = acceptedLedgerTx->getTxn();
323 !isPseudoTx(*sleTxn))
324 {
325 // It's okay for pseudo transactions to not affect any
326 // accounts. But otherwise...
327 JLOG(j.warn()) << "Transaction in ledger " << seq
328 << " affects no accounts";
329 JLOG(j.warn()) << sleTxn->getJson(JsonOptions::none);
330 }
331
332 *db
334 acceptedLedgerTx->getTxn()->getMetaSQL(
335 seq, acceptedLedgerTx->getEscMeta()) +
336 ";");
337
340 seq,
341 acceptedLedgerTx->getTxnSeq(),
342 app.config().NETWORK_ID);
343 }
344
345 tr.commit();
346 }
347
348 {
349 static std::string addLedger(
350 R"sql(INSERT OR REPLACE INTO Ledgers
351 (LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,
352 CloseTimeRes,CloseFlags,AccountSetHash,TransSetHash)
353 VALUES
354 (:ledgerHash,:ledgerSeq,:prevHash,:totalCoins,:closingTime,:prevClosingTime,
355 :closeTimeRes,:closeFlags,:accountSetHash,:transSetHash);)sql");
356
357 auto db(ldgDB.checkoutDb());
358
359 soci::transaction tr(*db);
360
361 auto const hash = to_string(ledger->header().hash);
362 auto const parentHash = to_string(ledger->header().parentHash);
363 auto const drops = to_string(ledger->header().drops);
364 auto const closeTime =
365 ledger->header().closeTime.time_since_epoch().count();
366 auto const parentCloseTime =
367 ledger->header().parentCloseTime.time_since_epoch().count();
368 auto const closeTimeResolution =
369 ledger->header().closeTimeResolution.count();
370 auto const closeFlags = ledger->header().closeFlags;
371 auto const accountHash = to_string(ledger->header().accountHash);
372 auto const txHash = to_string(ledger->header().txHash);
373
374 *db << addLedger, soci::use(hash), soci::use(seq),
375 soci::use(parentHash), soci::use(drops), soci::use(closeTime),
376 soci::use(parentCloseTime), soci::use(closeTimeResolution),
377 soci::use(closeFlags), soci::use(accountHash),
378 soci::use(txHash);
379
380 tr.commit();
381 }
382 }
383
384 return true;
385}
386
397 soci::session& session,
398 std::string const& sqlSuffix,
400{
401 // SOCI requires boost::optional (not std::optional) as parameters.
402 boost::optional<std::string> hash, parentHash, accountHash, txHash;
403 boost::optional<std::uint64_t> seq, drops, closeTime, parentCloseTime,
404 closeTimeResolution, closeFlags;
405
406 std::string const sql =
407 "SELECT "
408 "LedgerHash, PrevHash, AccountSetHash, TransSetHash, "
409 "TotalCoins,"
410 "ClosingTime, PrevClosingTime, CloseTimeRes, CloseFlags,"
411 "LedgerSeq FROM Ledgers " +
412 sqlSuffix + ";";
413
414 session << sql, soci::into(hash), soci::into(parentHash),
415 soci::into(accountHash), soci::into(txHash), soci::into(drops),
416 soci::into(closeTime), soci::into(parentCloseTime),
417 soci::into(closeTimeResolution), soci::into(closeFlags),
418 soci::into(seq);
419
420 if (!session.got_data())
421 {
422 JLOG(j.debug()) << "Ledger not found: " << sqlSuffix;
423 return {};
424 }
425
426 using time_point = NetClock::time_point;
427 using duration = NetClock::duration;
428
429 LedgerHeader info;
430
431 if (hash && !info.hash.parseHex(*hash))
432 {
433 JLOG(j.debug()) << "Hash parse error for ledger: " << sqlSuffix;
434 return {};
435 }
436
437 if (parentHash && !info.parentHash.parseHex(*parentHash))
438 {
439 JLOG(j.debug()) << "parentHash parse error for ledger: " << sqlSuffix;
440 return {};
441 }
442
443 if (accountHash && !info.accountHash.parseHex(*accountHash))
444 {
445 JLOG(j.debug()) << "accountHash parse error for ledger: " << sqlSuffix;
446 return {};
447 }
448
449 if (txHash && !info.txHash.parseHex(*txHash))
450 {
451 JLOG(j.debug()) << "txHash parse error for ledger: " << sqlSuffix;
452 return {};
453 }
454
455 info.seq = rangeCheckedCast<std::uint32_t>(seq.value_or(0));
456 info.drops = drops.value_or(0);
457 info.closeTime = time_point{duration{closeTime.value_or(0)}};
458 info.parentCloseTime = time_point{duration{parentCloseTime.value_or(0)}};
459 info.closeFlags = closeFlags.value_or(0);
460 info.closeTimeResolution = duration{closeTimeResolution.value_or(0)};
462 return info;
463}
464
467 soci::session& session,
468 LedgerIndex ledgerSeq,
470{
472 s << "WHERE LedgerSeq = " << ledgerSeq;
473 return getLedgerInfo(session, s.str(), j);
474}
475
477getNewestLedgerInfo(soci::session& session, beast::Journal j)
478{
480 s << "ORDER BY LedgerSeq DESC LIMIT 1";
481 return getLedgerInfo(session, s.str(), j);
482}
483
486 soci::session& session,
487 LedgerIndex ledgerFirstIndex,
489{
491 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
492 " ORDER BY LedgerSeq ASC LIMIT 1";
493 return getLedgerInfo(session, s.str(), j);
494}
495
498 soci::session& session,
499 LedgerIndex ledgerFirstIndex,
501{
503 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
504 " ORDER BY LedgerSeq DESC LIMIT 1";
505 return getLedgerInfo(session, s.str(), j);
506}
507
510 soci::session& session,
511 uint256 const& ledgerHash,
513{
515 s << "WHERE LedgerHash = '" << ledgerHash << "'";
516 return getLedgerInfo(session, s.str(), j);
517}
518
520getHashByIndex(soci::session& session, LedgerIndex ledgerIndex)
521{
522 uint256 ret;
523
524 std::string sql =
525 "SELECT LedgerHash FROM Ledgers INDEXED BY SeqLedger WHERE LedgerSeq='";
526 sql.append(std::to_string(ledgerIndex));
527 sql.append("';");
528
529 std::string hash;
530 {
531 // SOCI requires boost::optional (not std::optional) as the parameter.
532 boost::optional<std::string> lh;
533 session << sql, soci::into(lh);
534
535 if (!session.got_data() || !lh)
536 return ret;
537
538 hash = *lh;
539 if (hash.empty())
540 return ret;
541 }
542
543 if (!ret.parseHex(hash))
544 return ret;
546 return ret;
547}
548
551 soci::session& session,
552 LedgerIndex ledgerIndex,
554{
555 // SOCI requires boost::optional (not std::optional) as the parameter.
556 boost::optional<std::string> lhO, phO;
557
558 session << "SELECT LedgerHash,PrevHash FROM Ledgers "
559 "INDEXED BY SeqLedger WHERE LedgerSeq = :ls;",
560 soci::into(lhO), soci::into(phO), soci::use(ledgerIndex);
561
562 if (!lhO || !phO)
563 {
564 auto stream = j.trace();
565 JLOG(stream) << "Don't have ledger " << ledgerIndex;
566 return {};
567 }
568
569 LedgerHashPair hashes;
570 if (!hashes.ledgerHash.parseHex(*lhO) || !hashes.parentHash.parseHex(*phO))
571 {
572 auto stream = j.trace();
573 JLOG(stream) << "Error parse hashes for ledger " << ledgerIndex;
574 return {};
575 }
577 return hashes;
578}
579
582 soci::session& session,
583 LedgerIndex minSeq,
584 LedgerIndex maxSeq,
586{
587 std::string sql =
588 "SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq >= ";
589 sql.append(std::to_string(minSeq));
590 sql.append(" AND LedgerSeq <= ");
591 sql.append(std::to_string(maxSeq));
592 sql.append(";");
593
594 std::uint64_t ls;
595 std::string lh;
596 // SOCI requires boost::optional (not std::optional) as the parameter.
597 boost::optional<std::string> ph;
598 soci::statement st =
599 (session.prepare << sql,
600 soci::into(ls),
601 soci::into(lh),
602 soci::into(ph));
603
604 st.execute();
606 while (st.fetch())
607 {
608 LedgerHashPair& hashes = res[rangeCheckedCast<LedgerIndex>(ls)];
609 if (!hashes.ledgerHash.parseHex(lh))
610 {
611 JLOG(j.warn()) << "Error parsed hash for ledger seq: " << ls;
612 }
613 if (!ph)
614 {
615 JLOG(j.warn()) << "Null prev hash for ledger seq: " << ls;
616 }
617 else if (!hashes.parentHash.parseHex(*ph))
618 {
619 JLOG(j.warn()) << "Error parsed prev hash for ledger seq: " << ls;
620 }
622 return res;
623}
624
627 soci::session& session,
628 Application& app,
629 LedgerIndex startIndex,
630 int quantity)
631{
632 std::string sql = boost::str(
633 boost::format(
634 "SELECT LedgerSeq, Status, RawTxn "
635 "FROM Transactions ORDER BY LedgerSeq DESC LIMIT %u,%u;") %
636 startIndex % quantity);
637
639 int total = 0;
640
641 {
642 // SOCI requires boost::optional (not std::optional) as parameters.
643 boost::optional<std::uint64_t> ledgerSeq;
644 boost::optional<std::string> status;
645 soci::blob sociRawTxnBlob(session);
646 soci::indicator rti;
647 Blob rawTxn;
648
649 soci::statement st =
650 (session.prepare << sql,
651 soci::into(ledgerSeq),
652 soci::into(status),
653 soci::into(sociRawTxnBlob, rti));
654
655 st.execute();
656 while (st.fetch())
657 {
658 if (soci::i_ok == rti)
659 convert(sociRawTxnBlob, rawTxn);
660 else
661 rawTxn.clear();
662
663 if (auto trans = Transaction::transactionFromSQL(
664 ledgerSeq, status, rawTxn, app))
665 {
666 total++;
667 txs.push_back(trans);
668 }
669 }
670 }
671
672 return {txs, total};
673}
674
692static std::string
694 Application& app,
695 std::string selection,
696 RelationalDatabase::AccountTxOptions const& options,
697 bool descending,
698 bool binary,
699 bool count,
701{
702 constexpr std::uint32_t NONBINARY_PAGE_LENGTH = 200;
703 constexpr std::uint32_t BINARY_PAGE_LENGTH = 500;
704
705 std::uint32_t numberOfResults;
706
707 if (count)
708 {
709 numberOfResults = std::numeric_limits<std::uint32_t>::max();
710 }
711 else if (options.limit == UINT32_MAX)
712 {
713 numberOfResults = binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH;
714 }
715 else if (!options.bUnlimited)
716 {
717 numberOfResults = std::min(
718 binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH, options.limit);
719 }
720 else
721 {
722 numberOfResults = options.limit;
723 }
724
725 std::string maxClause = "";
726 std::string minClause = "";
727
728 if (options.maxLedger)
729 {
730 maxClause = boost::str(
731 boost::format("AND AccountTransactions.LedgerSeq <= '%u'") %
732 options.maxLedger);
733 }
734
735 if (options.minLedger)
736 {
737 minClause = boost::str(
738 boost::format("AND AccountTransactions.LedgerSeq >= '%u'") %
739 options.minLedger);
740 }
741
742 std::string sql;
743
744 if (count)
745 sql = boost::str(
746 boost::format("SELECT %s FROM AccountTransactions "
747 "WHERE Account = '%s' %s %s LIMIT %u, %u;") %
748 selection % toBase58(options.account) % maxClause % minClause %
749 options.offset % numberOfResults);
750 else
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 JLOG(j.trace()) << "txSQL query: " << sql;
764 return sql;
765}
766
790 soci::session& session,
791 Application& app,
792 LedgerMaster& ledgerMaster,
793 RelationalDatabase::AccountTxOptions const& options,
794 bool descending,
796{
798
800 app,
801 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
802 options,
803 descending,
804 false,
805 false,
806 j);
807 if (sql == "")
808 return {ret, 0};
809
810 int total = 0;
811 {
812 // SOCI requires boost::optional (not std::optional) as parameters.
813 boost::optional<std::uint64_t> ledgerSeq;
814 boost::optional<std::string> status;
815 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
816 soci::indicator rti, tmi;
817 Blob rawTxn, txnMeta;
818
819 soci::statement st =
820 (session.prepare << sql,
821 soci::into(ledgerSeq),
822 soci::into(status),
823 soci::into(sociTxnBlob, rti),
824 soci::into(sociTxnMetaBlob, tmi));
825
826 st.execute();
827 while (st.fetch())
828 {
829 if (soci::i_ok == rti)
830 convert(sociTxnBlob, rawTxn);
831 else
832 rawTxn.clear();
833
834 if (soci::i_ok == tmi)
835 convert(sociTxnMetaBlob, txnMeta);
836 else
837 txnMeta.clear();
838
839 auto txn =
840 Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
841
842 if (txnMeta.empty())
843 { // Work around a bug that could leave the metadata missing
844 auto const seq =
845 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
846
847 JLOG(j.warn())
848 << "Recovering ledger " << seq << ", txn " << txn->getID();
849
850 if (auto l = ledgerMaster.getLedgerBySeq(seq))
851 pendSaveValidated(app, l, false, false);
852 }
853
854 if (txn)
855 {
856 ret.emplace_back(
857 txn,
859 txn->getID(), txn->getLedger(), txnMeta));
860 total++;
861 }
862 }
863 }
865 return {ret, total};
866}
867
870 soci::session& session,
871 Application& app,
872 LedgerMaster& ledgerMaster,
873 RelationalDatabase::AccountTxOptions const& options,
876 return getAccountTxs(session, app, ledgerMaster, options, false, j);
877}
878
881 soci::session& session,
882 Application& app,
886{
887 return getAccountTxs(session, app, ledgerMaster, options, true, j);
888}
889
912 soci::session& session,
913 Application& app,
914 RelationalDatabase::AccountTxOptions const& options,
915 bool descending,
917{
919
921 app,
922 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
923 options,
924 descending,
925 true /*binary*/,
926 false,
927 j);
928 if (sql == "")
929 return {ret, 0};
930
931 int total = 0;
932
933 {
934 // SOCI requires boost::optional (not std::optional) as parameters.
935 boost::optional<std::uint64_t> ledgerSeq;
936 boost::optional<std::string> status;
937 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
938 soci::indicator rti, tmi;
939
940 soci::statement st =
941 (session.prepare << sql,
942 soci::into(ledgerSeq),
943 soci::into(status),
944 soci::into(sociTxnBlob, rti),
945 soci::into(sociTxnMetaBlob, tmi));
946
947 st.execute();
948 while (st.fetch())
949 {
950 Blob rawTxn;
951 if (soci::i_ok == rti)
952 convert(sociTxnBlob, rawTxn);
953 Blob txnMeta;
954 if (soci::i_ok == tmi)
955 convert(sociTxnMetaBlob, txnMeta);
956
957 auto const seq =
958 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
959
960 ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq);
961 total++;
962 }
963 }
965 return {ret, total};
966}
967
970 soci::session& session,
971 Application& app,
972 RelationalDatabase::AccountTxOptions const& options,
975 return getAccountTxsB(session, app, options, false, j);
976}
977
980 soci::session& session,
981 Application& app,
984{
985 return getAccountTxsB(session, app, options, true, j);
986}
987
1009 soci::session& session,
1010 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1012 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1013 onTransaction,
1014 RelationalDatabase::AccountTxPageOptions const& options,
1015 std::uint32_t page_length,
1016 bool forward)
1017{
1018 int total = 0;
1019
1020 bool lookingForMarker = options.marker.has_value();
1021
1022 std::uint32_t numberOfResults;
1023
1024 if (options.limit == 0 || options.limit == UINT32_MAX ||
1025 (options.limit > page_length && !options.bAdmin))
1026 numberOfResults = page_length;
1027 else
1028 numberOfResults = options.limit;
1029
1030 // As an account can have many thousands of transactions, there is a limit
1031 // placed on the amount of transactions returned. If the limit is reached
1032 // before the result set has been exhausted (we always query for one more
1033 // than the limit), then we return an opaque marker that can be supplied in
1034 // a subsequent query.
1035 std::uint32_t queryLimit = numberOfResults + 1;
1036 std::uint32_t findLedger = 0, findSeq = 0;
1037
1038 if (lookingForMarker)
1039 {
1040 findLedger = options.marker->ledgerSeq;
1041 findSeq = options.marker->txnSeq;
1042 }
1043
1045
1046 static std::string const prefix(
1047 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1048 Status,RawTxn,TxnMeta
1049 FROM AccountTransactions INNER JOIN Transactions
1050 ON Transactions.TransID = AccountTransactions.TransID
1051 AND AccountTransactions.Account = '%s' WHERE
1052 )");
1053
1054 std::string sql;
1055
1056 // SQL's BETWEEN uses a closed interval ([a,b])
1057
1058 char const* const order = forward ? "ASC" : "DESC";
1059
1060 if (findLedger == 0)
1061 {
1062 sql = boost::str(
1063 boost::format(
1064 prefix + (R"(AccountTransactions.LedgerSeq BETWEEN %u AND %u
1065 ORDER BY AccountTransactions.LedgerSeq %s,
1066 AccountTransactions.TxnSeq %s
1067 LIMIT %u;)")) %
1068 toBase58(options.account) % options.minLedger % options.maxLedger %
1069 order % order % queryLimit);
1070 }
1071 else
1072 {
1073 char const* const compare = forward ? ">=" : "<=";
1074 std::uint32_t const minLedger =
1075 forward ? findLedger + 1 : options.minLedger;
1076 std::uint32_t const maxLedger =
1077 forward ? options.maxLedger : findLedger - 1;
1078
1079 auto b58acct = toBase58(options.account);
1080 sql = boost::str(
1081 boost::format((
1082 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1083 Status,RawTxn,TxnMeta
1084 FROM AccountTransactions, Transactions WHERE
1085 (AccountTransactions.TransID = Transactions.TransID AND
1086 AccountTransactions.Account = '%s' AND
1087 AccountTransactions.LedgerSeq BETWEEN %u AND %u)
1088 UNION
1089 SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,Status,RawTxn,TxnMeta
1090 FROM AccountTransactions, Transactions WHERE
1091 (AccountTransactions.TransID = Transactions.TransID AND
1092 AccountTransactions.Account = '%s' AND
1093 AccountTransactions.LedgerSeq = %u AND
1094 AccountTransactions.TxnSeq %s %u)
1095 ORDER BY AccountTransactions.LedgerSeq %s,
1096 AccountTransactions.TxnSeq %s
1097 LIMIT %u;
1098 )")) %
1099 b58acct % minLedger % maxLedger % b58acct % findLedger % compare %
1100 findSeq % order % order % queryLimit);
1101 }
1102
1103 {
1104 Blob rawData;
1105 Blob rawMeta;
1106
1107 // SOCI requires boost::optional (not std::optional) as parameters.
1108 boost::optional<std::uint64_t> ledgerSeq;
1109 boost::optional<std::uint32_t> txnSeq;
1110 boost::optional<std::string> status;
1111 soci::blob txnData(session);
1112 soci::blob txnMeta(session);
1113 soci::indicator dataPresent, metaPresent;
1114
1115 soci::statement st =
1116 (session.prepare << sql,
1117 soci::into(ledgerSeq),
1118 soci::into(txnSeq),
1119 soci::into(status),
1120 soci::into(txnData, dataPresent),
1121 soci::into(txnMeta, metaPresent));
1122
1123 st.execute();
1124
1125 while (st.fetch())
1126 {
1127 if (lookingForMarker)
1128 {
1129 if (findLedger == ledgerSeq.value_or(0) &&
1130 findSeq == txnSeq.value_or(0))
1131 {
1132 lookingForMarker = false;
1133 }
1134 else
1135 continue;
1136 }
1137 else if (numberOfResults == 0)
1138 {
1139 newmarker = {
1140 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1141 txnSeq.value_or(0)};
1142 break;
1143 }
1144
1145 if (dataPresent == soci::i_ok)
1146 convert(txnData, rawData);
1147 else
1148 rawData.clear();
1149
1150 if (metaPresent == soci::i_ok)
1151 convert(txnMeta, rawMeta);
1152 else
1153 rawMeta.clear();
1154
1155 // Work around a bug that could leave the metadata missing
1156 if (rawMeta.size() == 0)
1157 onUnsavedLedger(ledgerSeq.value_or(0));
1158
1159 // `rawData` and `rawMeta` will be used after they are moved.
1160 // That's OK.
1161 onTransaction(
1162 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1163 *status,
1164 std::move(rawData),
1165 std::move(rawMeta));
1166 // Note some callbacks will move the data, some will not. Clear
1167 // them so code doesn't depend on if the data was actually moved
1168 // or not. The code will be more efficient if `rawData` and
1169 // `rawMeta` don't have to allocate in `convert`, so don't
1170 // refactor my moving these variables into loop scope.
1171 rawData.clear();
1172 rawMeta.clear();
1173
1174 --numberOfResults;
1175 total++;
1176 }
1177 }
1178
1179 return {newmarker, total};
1180}
1181
1184 soci::session& session,
1185 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1187 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1188 onTransaction,
1190 std::uint32_t page_length)
1191{
1192 return accountTxPage(
1193 session, onUnsavedLedger, onTransaction, options, page_length, true);
1194}
1195
1198 soci::session& session,
1199 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1201 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1202 onTransaction,
1204 std::uint32_t page_length)
1205{
1206 return accountTxPage(
1207 session, onUnsavedLedger, onTransaction, options, page_length, false);
1208}
1209
1212 soci::session& session,
1213 Application& app,
1214 uint256 const& id,
1215 std::optional<ClosedInterval<uint32_t>> const& range,
1216 error_code_i& ec)
1217{
1218 std::string sql =
1219 "SELECT LedgerSeq,Status,RawTxn,TxnMeta "
1220 "FROM Transactions WHERE TransID='";
1221
1222 sql.append(to_string(id));
1223 sql.append("';");
1224
1225 // SOCI requires boost::optional (not std::optional) as parameters.
1226 boost::optional<std::uint64_t> ledgerSeq;
1227 boost::optional<std::string> status;
1228 Blob rawTxn, rawMeta;
1229 {
1230 soci::blob sociRawTxnBlob(session), sociRawMetaBlob(session);
1231 soci::indicator txn, meta;
1232
1233 session << sql, soci::into(ledgerSeq), soci::into(status),
1234 soci::into(sociRawTxnBlob, txn), soci::into(sociRawMetaBlob, meta);
1235
1236 auto const got_data = session.got_data();
1237
1238 if ((!got_data || txn != soci::i_ok || meta != soci::i_ok) && !range)
1239 return TxSearched::unknown;
1240
1241 if (!got_data)
1242 {
1243 uint64_t count = 0;
1244 soci::indicator rti;
1245
1246 session
1247 << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
1248 "LedgerSeq BETWEEN "
1249 << range->first() << " AND " << range->last() << ";",
1250 soci::into(count, rti);
1251
1252 if (!session.got_data() || rti != soci::i_ok)
1253 return TxSearched::some;
1254
1255 return count == (range->last() - range->first() + 1)
1257 : TxSearched::some;
1258 }
1259
1260 convert(sociRawTxnBlob, rawTxn);
1261 convert(sociRawMetaBlob, rawMeta);
1262 }
1263
1264 try
1265 {
1266 auto txn =
1267 Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
1268
1269 if (!ledgerSeq)
1270 return std::pair{std::move(txn), nullptr};
1271
1272 std::uint32_t inLedger =
1273 rangeCheckedCast<std::uint32_t>(ledgerSeq.value());
1274
1275 auto txMeta = std::make_shared<TxMeta>(id, inLedger, rawMeta);
1276
1277 return std::pair{std::move(txn), std::move(txMeta)};
1278 }
1279 catch (std::exception& e)
1280 {
1281 JLOG(app.journal("Ledger").warn())
1282 << "Unable to deserialize transaction from raw SQL value. Error: "
1283 << 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 space =
1295 boost::filesystem::space(config.legacy("database_path"));
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 dbSetup = setup_DatabaseCon(config);
1306 boost::filesystem::path dbPath = dbSetup.dataDir / TxDBName;
1307 boost::system::error_code ec;
1309 boost::filesystem::file_size(dbPath, ec);
1310 if (ec)
1311 {
1312 JLOG(j.error())
1313 << "Error checking transaction db file size: " << ec.message();
1314 dbSize.reset();
1315 }
1316
1317 static auto const pageSize = [&] {
1318 std::uint32_t ps;
1319 session << "PRAGMA page_size;", soci::into(ps);
1320 return ps;
1321 }();
1322 static auto const maxPages = [&] {
1323 std::uint32_t mp;
1324 session << "PRAGMA max_page_count;", soci::into(mp);
1325 return mp;
1326 }();
1327 std::uint32_t pageCount;
1328 session << "PRAGMA page_count;", soci::into(pageCount);
1329 std::uint32_t freePages = maxPages - pageCount;
1330 std::uint64_t freeSpace =
1331 safe_cast<std::uint64_t>(freePages) * pageSize;
1332 JLOG(j.info())
1333 << "Transaction DB pathname: " << dbPath.string()
1334 << "; file size: " << dbSize.value_or(-1) << " bytes"
1335 << "; SQLite page size: " << pageSize << " bytes"
1336 << "; Free pages: " << freePages << "; Free space: " << freeSpace
1337 << " bytes; "
1338 << "Note that this does not take into account available disk "
1339 "space.";
1340
1341 if (freeSpace < megabytes(512))
1342 {
1343 JLOG(j.fatal())
1344 << "Free SQLite space for transaction db is less than "
1345 "512MB. To fix this, rippled must be executed with the "
1346 "vacuum parameter before restarting. "
1347 "Note that this activity can take multiple days, "
1348 "depending on database size.";
1349 return false;
1350 }
1351 }
1352
1353 return true;
1354}
1355
1356} // namespace detail
1357} // namespace xrpl
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 TaggedCache< uint256, AcceptedLedger > & getAcceptedLedgerCache()=0
virtual Config & config()=0
virtual PendingSaves & pendingSaves()=0
virtual LedgerMaster & getLedgerMaster()=0
virtual beast::Journal journal(std::string const &name)=0
virtual NodeStore::Database & getNodeStore()=0
virtual TransactionMaster & getMasterTransaction()=0
uint32_t NETWORK_ID
Definition Config.h:138
bool useTxTables() const
Definition Config.h:324
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:1098
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:345
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.
std::optional< LedgerHeader > getLedgerInfoByHash(soci::session &session, uint256 const &ledgerHash, beast::Journal j)
getLedgerInfoByHash Returns info of ledger with given hash.
Definition Node.cpp:504
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:172
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
std::optional< LedgerIndex > getMinLedgerSeq(soci::session &session, TableType type)
getMinLedgerSeq Returns minimum ledger sequence in given table.
Definition Node.cpp:108
std::optional< LedgerIndex > getMaxLedgerSeq(soci::session &session, TableType type)
getMaxLedgerSeq Returns maximum ledger sequence in given table.
Definition Node.cpp:118
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:875
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:621
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:964
std::optional< LedgerHeader > getNewestLedgerInfo(soci::session &session, beast::Journal j)
getNewestLedgerInfo Returns info of newest saved ledger.
Definition Node.cpp:472
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:480
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:1185
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:157
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:784
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:391
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:1003
std::size_t getRows(soci::session &session, TableType type)
getRows Returns number of rows in given table.
Definition Node.cpp:145
std::optional< LedgerHeader > getLedgerInfoByIndex(soci::session &session, LedgerIndex ledgerSeq, beast::Journal j)
getLedgerInfoByIndex Returns ledger by its sequence.
Definition Node.cpp:461
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:974
uint256 getHashByIndex(soci::session &session, LedgerIndex ledgerIndex)
getHashByIndex Returns hash of ledger with given sequence.
Definition Node.cpp:515
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::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:864
bool dbHasSpace(soci::session &session, Config const &config, beast::Journal j)
dbHasSpace Checks if given database has available space.
Definition Node.cpp:1266
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:492
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:906
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:1157
static std::string to_string(TableType type)
to_string Returns the name of a table according to its TableType.
Definition Node.cpp:28
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:1171
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:688
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:545
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
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:35
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
@ hotLEDGER
Definition NodeObject.h:15
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:981
@ current
This was a new validation and was added.
base_uint< 256 > uint256
Definition base_uint.h:539
constexpr auto megabytes(T value) noexcept
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
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:11
constexpr auto TxDBName
Definition DBInit.h:51
constexpr auto kilobytes(T value) noexcept
@ ledgerMaster
ledger master data for signing
@ transactionID
transaction plus signature to give transaction ID
constexpr auto LgrDBName
Definition DBInit.h:24
constexpr std::array< char const *, 5 > LgrDBInit
Definition DBInit.h:26
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition STTx.cpp:810
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition SociDB.cpp:138
error_code_i
Definition ErrorCodes.h:21
@ rpcDB_DESERIALIZATION
Definition ErrorCodes.h:115
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:93
Config::StartUpType startUp
Definition DatabaseCon.h:74
std::array< std::string, 1 > lgrPragma
Definition DatabaseCon.h:94
T to_string(T... args)
T value_or(T... args)
T what(T... args)