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 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->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 if (!txnDB)
258 {
259 // LCOV_EXCL_START
260 JLOG(j.fatal()) << "TxTables db isn't available";
261 Throw<std::runtime_error>("TxTables db isn't available");
262 // LCOV_EXCL_STOP
263 }
264
265 auto db = txnDB->checkoutDb();
266
267 soci::transaction tr(*db);
268
269 *db << boost::str(deleteTrans1 % seq);
270 *db << boost::str(deleteTrans2 % seq);
271
272 std::string const ledgerSeq(std::to_string(seq));
273
274 for (auto const& acceptedLedgerTx : *aLedger)
275 {
276 uint256 transactionID = acceptedLedgerTx->getTransactionID();
277
278 std::string const txnId(to_string(transactionID));
279 std::string const txnSeq(
280 std::to_string(acceptedLedgerTx->getTxnSeq()));
281
282 *db << boost::str(deleteAcctTrans % transactionID);
283
284 auto const& accts = acceptedLedgerTx->getAffected();
285
286 if (!accts.empty())
287 {
288 std::string sql(
289 "INSERT INTO AccountTransactions "
290 "(TransID, Account, LedgerSeq, TxnSeq) VALUES ");
291
292 // Try to make an educated guess on how much space we'll
293 // need for our arguments. In argument order we have: 64
294 // + 34 + 10 + 10 = 118 + 10 extra = 128 bytes
295 sql.reserve(sql.length() + (accts.size() * 128));
296
297 bool first = true;
298 for (auto const& account : accts)
299 {
300 if (!first)
301 sql += ", ('";
302 else
303 {
304 sql += "('";
305 first = false;
306 }
307
308 sql += txnId;
309 sql += "','";
310 sql += toBase58(account);
311 sql += "',";
312 sql += ledgerSeq;
313 sql += ",";
314 sql += txnSeq;
315 sql += ")";
316 }
317 sql += ";";
318 JLOG(j.trace()) << "ActTx: " << sql;
319 *db << sql;
320 }
321 else if (auto const& sleTxn = acceptedLedgerTx->getTxn();
322 !isPseudoTx(*sleTxn))
323 {
324 // It's okay for pseudo transactions to not affect any
325 // accounts. But otherwise...
326 JLOG(j.warn()) << "Transaction in ledger " << seq
327 << " affects no accounts";
328 JLOG(j.warn()) << sleTxn->getJson(JsonOptions::none);
329 }
330
331 *db
333 acceptedLedgerTx->getTxn()->getMetaSQL(
334 seq, acceptedLedgerTx->getEscMeta()) +
335 ";");
336
339 seq,
340 acceptedLedgerTx->getTxnSeq(),
341 app.config().NETWORK_ID);
342 }
343
344 tr.commit();
345 }
346
347 {
348 static std::string addLedger(
349 R"sql(INSERT OR REPLACE INTO Ledgers
350 (LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,
351 CloseTimeRes,CloseFlags,AccountSetHash,TransSetHash)
352 VALUES
353 (:ledgerHash,:ledgerSeq,:prevHash,:totalCoins,:closingTime,:prevClosingTime,
354 :closeTimeRes,:closeFlags,:accountSetHash,:transSetHash);)sql");
355
356 auto db(ldgDB.checkoutDb());
357
358 soci::transaction tr(*db);
359
360 auto const hash = to_string(ledger->info().hash);
361 auto const parentHash = to_string(ledger->info().parentHash);
362 auto const drops = to_string(ledger->info().drops);
363 auto const closeTime =
364 ledger->info().closeTime.time_since_epoch().count();
365 auto const parentCloseTime =
366 ledger->info().parentCloseTime.time_since_epoch().count();
367 auto const closeTimeResolution =
368 ledger->info().closeTimeResolution.count();
369 auto const closeFlags = ledger->info().closeFlags;
370 auto const accountHash = to_string(ledger->info().accountHash);
371 auto const txHash = to_string(ledger->info().txHash);
372
373 *db << addLedger, soci::use(hash), soci::use(seq),
374 soci::use(parentHash), soci::use(drops), soci::use(closeTime),
375 soci::use(parentCloseTime), soci::use(closeTimeResolution),
376 soci::use(closeFlags), soci::use(accountHash),
377 soci::use(txHash);
378
379 tr.commit();
380 }
381 }
382
383 return true;
384}
385
396 soci::session& session,
397 std::string const& sqlSuffix,
399{
400 // SOCI requires boost::optional (not std::optional) as parameters.
401 boost::optional<std::string> hash, parentHash, accountHash, txHash;
402 boost::optional<std::uint64_t> seq, drops, closeTime, parentCloseTime,
403 closeTimeResolution, closeFlags;
404
405 std::string const sql =
406 "SELECT "
407 "LedgerHash, PrevHash, AccountSetHash, TransSetHash, "
408 "TotalCoins,"
409 "ClosingTime, PrevClosingTime, CloseTimeRes, CloseFlags,"
410 "LedgerSeq FROM Ledgers " +
411 sqlSuffix + ";";
412
413 session << sql, soci::into(hash), soci::into(parentHash),
414 soci::into(accountHash), soci::into(txHash), soci::into(drops),
415 soci::into(closeTime), soci::into(parentCloseTime),
416 soci::into(closeTimeResolution), soci::into(closeFlags),
417 soci::into(seq);
418
419 if (!session.got_data())
420 {
421 JLOG(j.debug()) << "Ledger not found: " << sqlSuffix;
422 return {};
423 }
424
425 using time_point = NetClock::time_point;
426 using duration = NetClock::duration;
427
428 LedgerInfo info;
429
430 if (hash && !info.hash.parseHex(*hash))
431 {
432 JLOG(j.debug()) << "Hash parse error for ledger: " << sqlSuffix;
433 return {};
434 }
435
436 if (parentHash && !info.parentHash.parseHex(*parentHash))
437 {
438 JLOG(j.debug()) << "parentHash parse error for ledger: " << sqlSuffix;
439 return {};
440 }
441
442 if (accountHash && !info.accountHash.parseHex(*accountHash))
443 {
444 JLOG(j.debug()) << "accountHash parse error for ledger: " << sqlSuffix;
445 return {};
446 }
447
448 if (txHash && !info.txHash.parseHex(*txHash))
449 {
450 JLOG(j.debug()) << "txHash parse error for ledger: " << sqlSuffix;
451 return {};
452 }
453
454 info.seq = rangeCheckedCast<std::uint32_t>(seq.value_or(0));
455 info.drops = drops.value_or(0);
456 info.closeTime = time_point{duration{closeTime.value_or(0)}};
457 info.parentCloseTime = time_point{duration{parentCloseTime.value_or(0)}};
458 info.closeFlags = closeFlags.value_or(0);
459 info.closeTimeResolution = duration{closeTimeResolution.value_or(0)};
461 return info;
462}
463
466 soci::session& session,
467 LedgerIndex ledgerSeq,
469{
471 s << "WHERE LedgerSeq = " << ledgerSeq;
472 return getLedgerInfo(session, s.str(), j);
473}
474
476getNewestLedgerInfo(soci::session& session, beast::Journal j)
477{
479 s << "ORDER BY LedgerSeq DESC LIMIT 1";
480 return getLedgerInfo(session, s.str(), j);
481}
482
485 soci::session& session,
486 LedgerIndex ledgerFirstIndex,
488{
490 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
491 " ORDER BY LedgerSeq ASC LIMIT 1";
492 return getLedgerInfo(session, s.str(), j);
493}
494
497 soci::session& session,
498 LedgerIndex ledgerFirstIndex,
500{
502 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
503 " ORDER BY LedgerSeq DESC LIMIT 1";
504 return getLedgerInfo(session, s.str(), j);
505}
506
509 soci::session& session,
510 uint256 const& ledgerHash,
512{
514 s << "WHERE LedgerHash = '" << ledgerHash << "'";
515 return getLedgerInfo(session, s.str(), j);
516}
517
519getHashByIndex(soci::session& session, LedgerIndex ledgerIndex)
520{
521 uint256 ret;
522
523 std::string sql =
524 "SELECT LedgerHash FROM Ledgers INDEXED BY SeqLedger WHERE LedgerSeq='";
525 sql.append(std::to_string(ledgerIndex));
526 sql.append("';");
527
528 std::string hash;
529 {
530 // SOCI requires boost::optional (not std::optional) as the parameter.
531 boost::optional<std::string> lh;
532 session << sql, soci::into(lh);
533
534 if (!session.got_data() || !lh)
535 return ret;
536
537 hash = *lh;
538 if (hash.empty())
539 return ret;
540 }
541
542 if (!ret.parseHex(hash))
543 return ret;
545 return ret;
546}
547
550 soci::session& session,
551 LedgerIndex ledgerIndex,
553{
554 // SOCI requires boost::optional (not std::optional) as the parameter.
555 boost::optional<std::string> lhO, phO;
556
557 session << "SELECT LedgerHash,PrevHash FROM Ledgers "
558 "INDEXED BY SeqLedger WHERE LedgerSeq = :ls;",
559 soci::into(lhO), soci::into(phO), soci::use(ledgerIndex);
560
561 if (!lhO || !phO)
562 {
563 auto stream = j.trace();
564 JLOG(stream) << "Don't have ledger " << ledgerIndex;
565 return {};
566 }
567
568 LedgerHashPair hashes;
569 if (!hashes.ledgerHash.parseHex(*lhO) || !hashes.parentHash.parseHex(*phO))
570 {
571 auto stream = j.trace();
572 JLOG(stream) << "Error parse hashes for ledger " << ledgerIndex;
573 return {};
574 }
576 return hashes;
577}
578
581 soci::session& session,
582 LedgerIndex minSeq,
583 LedgerIndex maxSeq,
585{
586 std::string sql =
587 "SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq >= ";
588 sql.append(std::to_string(minSeq));
589 sql.append(" AND LedgerSeq <= ");
590 sql.append(std::to_string(maxSeq));
591 sql.append(";");
592
593 std::uint64_t ls;
594 std::string lh;
595 // SOCI requires boost::optional (not std::optional) as the parameter.
596 boost::optional<std::string> ph;
597 soci::statement st =
598 (session.prepare << sql,
599 soci::into(ls),
600 soci::into(lh),
601 soci::into(ph));
602
603 st.execute();
605 while (st.fetch())
606 {
607 LedgerHashPair& hashes = res[rangeCheckedCast<LedgerIndex>(ls)];
608 if (!hashes.ledgerHash.parseHex(lh))
609 {
610 JLOG(j.warn()) << "Error parsed hash for ledger seq: " << ls;
611 }
612 if (!ph)
613 {
614 JLOG(j.warn()) << "Null prev hash for ledger seq: " << ls;
615 }
616 else if (!hashes.parentHash.parseHex(*ph))
617 {
618 JLOG(j.warn()) << "Error parsed prev hash for ledger seq: " << ls;
619 }
621 return res;
622}
623
626 soci::session& session,
627 Application& app,
628 LedgerIndex startIndex,
629 int quantity)
630{
631 std::string sql = boost::str(
632 boost::format(
633 "SELECT LedgerSeq, Status, RawTxn "
634 "FROM Transactions ORDER BY LedgerSeq DESC LIMIT %u,%u;") %
635 startIndex % quantity);
636
638 int total = 0;
639
640 {
641 // SOCI requires boost::optional (not std::optional) as parameters.
642 boost::optional<std::uint64_t> ledgerSeq;
643 boost::optional<std::string> status;
644 soci::blob sociRawTxnBlob(session);
645 soci::indicator rti;
646 Blob rawTxn;
647
648 soci::statement st =
649 (session.prepare << sql,
650 soci::into(ledgerSeq),
651 soci::into(status),
652 soci::into(sociRawTxnBlob, rti));
653
654 st.execute();
655 while (st.fetch())
656 {
657 if (soci::i_ok == rti)
658 convert(sociRawTxnBlob, rawTxn);
659 else
660 rawTxn.clear();
661
662 if (auto trans = Transaction::transactionFromSQL(
663 ledgerSeq, status, rawTxn, app))
664 {
665 total++;
666 txs.push_back(trans);
667 }
668 }
669 }
670
671 return {txs, total};
672}
673
691static std::string
693 Application& app,
694 std::string selection,
695 RelationalDatabase::AccountTxOptions const& options,
696 bool descending,
697 bool binary,
698 bool count,
700{
701 constexpr std::uint32_t NONBINARY_PAGE_LENGTH = 200;
702 constexpr std::uint32_t BINARY_PAGE_LENGTH = 500;
703
704 std::uint32_t numberOfResults;
705
706 if (count)
707 {
708 numberOfResults = std::numeric_limits<std::uint32_t>::max();
709 }
710 else if (options.limit == UINT32_MAX)
711 {
712 numberOfResults = binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH;
713 }
714 else if (!options.bUnlimited)
715 {
716 numberOfResults = std::min(
717 binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH, options.limit);
718 }
719 else
720 {
721 numberOfResults = options.limit;
722 }
723
724 std::string maxClause = "";
725 std::string minClause = "";
726
727 if (options.maxLedger)
728 {
729 maxClause = boost::str(
730 boost::format("AND AccountTransactions.LedgerSeq <= '%u'") %
731 options.maxLedger);
732 }
733
734 if (options.minLedger)
735 {
736 minClause = boost::str(
737 boost::format("AND AccountTransactions.LedgerSeq >= '%u'") %
738 options.minLedger);
739 }
740
741 std::string sql;
742
743 if (count)
744 sql = boost::str(
745 boost::format("SELECT %s FROM AccountTransactions "
746 "WHERE Account = '%s' %s %s LIMIT %u, %u;") %
747 selection % toBase58(options.account) % maxClause % minClause %
748 options.offset % numberOfResults);
749 else
750 sql = boost::str(
751 boost::format(
752 "SELECT %s FROM "
753 "AccountTransactions INNER JOIN Transactions "
754 "ON Transactions.TransID = AccountTransactions.TransID "
755 "WHERE Account = '%s' %s %s "
756 "ORDER BY AccountTransactions.LedgerSeq %s, "
757 "AccountTransactions.TxnSeq %s, AccountTransactions.TransID %s "
758 "LIMIT %u, %u;") %
759 selection % toBase58(options.account) % maxClause % minClause %
760 (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") %
761 (descending ? "DESC" : "ASC") % options.offset % numberOfResults);
762 JLOG(j.trace()) << "txSQL query: " << sql;
763 return sql;
764}
765
789 soci::session& session,
790 Application& app,
791 LedgerMaster& ledgerMaster,
792 RelationalDatabase::AccountTxOptions const& options,
793 bool descending,
795{
797
799 app,
800 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
801 options,
802 descending,
803 false,
804 false,
805 j);
806 if (sql == "")
807 return {ret, 0};
808
809 int total = 0;
810 {
811 // SOCI requires boost::optional (not std::optional) as parameters.
812 boost::optional<std::uint64_t> ledgerSeq;
813 boost::optional<std::string> status;
814 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
815 soci::indicator rti, tmi;
816 Blob rawTxn, txnMeta;
817
818 soci::statement st =
819 (session.prepare << sql,
820 soci::into(ledgerSeq),
821 soci::into(status),
822 soci::into(sociTxnBlob, rti),
823 soci::into(sociTxnMetaBlob, tmi));
824
825 st.execute();
826 while (st.fetch())
827 {
828 if (soci::i_ok == rti)
829 convert(sociTxnBlob, rawTxn);
830 else
831 rawTxn.clear();
832
833 if (soci::i_ok == tmi)
834 convert(sociTxnMetaBlob, txnMeta);
835 else
836 txnMeta.clear();
837
838 auto txn =
839 Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
840
841 if (txnMeta.empty())
842 { // Work around a bug that could leave the metadata missing
843 auto const seq =
844 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
845
846 JLOG(j.warn())
847 << "Recovering ledger " << seq << ", txn " << txn->getID();
848
849 if (auto l = ledgerMaster.getLedgerBySeq(seq))
850 pendSaveValidated(app, l, false, false);
851 }
852
853 if (txn)
854 {
855 ret.emplace_back(
856 txn,
858 txn->getID(), txn->getLedger(), txnMeta));
859 total++;
860 }
861 }
862 }
864 return {ret, total};
865}
866
869 soci::session& session,
870 Application& app,
871 LedgerMaster& ledgerMaster,
872 RelationalDatabase::AccountTxOptions const& options,
875 return getAccountTxs(session, app, ledgerMaster, options, false, j);
876}
877
880 soci::session& session,
881 Application& app,
885{
886 return getAccountTxs(session, app, ledgerMaster, options, true, j);
887}
888
911 soci::session& session,
912 Application& app,
913 RelationalDatabase::AccountTxOptions const& options,
914 bool descending,
916{
918
920 app,
921 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
922 options,
923 descending,
924 true /*binary*/,
925 false,
926 j);
927 if (sql == "")
928 return {ret, 0};
929
930 int total = 0;
931
932 {
933 // SOCI requires boost::optional (not std::optional) as parameters.
934 boost::optional<std::uint64_t> ledgerSeq;
935 boost::optional<std::string> status;
936 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
937 soci::indicator rti, tmi;
938
939 soci::statement st =
940 (session.prepare << sql,
941 soci::into(ledgerSeq),
942 soci::into(status),
943 soci::into(sociTxnBlob, rti),
944 soci::into(sociTxnMetaBlob, tmi));
945
946 st.execute();
947 while (st.fetch())
948 {
949 Blob rawTxn;
950 if (soci::i_ok == rti)
951 convert(sociTxnBlob, rawTxn);
952 Blob txnMeta;
953 if (soci::i_ok == tmi)
954 convert(sociTxnMetaBlob, txnMeta);
955
956 auto const seq =
957 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
958
959 ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq);
960 total++;
961 }
962 }
964 return {ret, total};
965}
966
969 soci::session& session,
970 Application& app,
971 RelationalDatabase::AccountTxOptions const& options,
974 return getAccountTxsB(session, app, options, false, j);
975}
976
979 soci::session& session,
980 Application& app,
983{
984 return getAccountTxsB(session, app, options, true, j);
985}
986
1008 soci::session& session,
1009 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1011 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1012 onTransaction,
1013 RelationalDatabase::AccountTxPageOptions const& options,
1014 std::uint32_t page_length,
1015 bool forward)
1016{
1017 int total = 0;
1018
1019 bool lookingForMarker = options.marker.has_value();
1020
1021 std::uint32_t numberOfResults;
1022
1023 if (options.limit == 0 || options.limit == UINT32_MAX ||
1024 (options.limit > page_length && !options.bAdmin))
1025 numberOfResults = page_length;
1026 else
1027 numberOfResults = options.limit;
1028
1029 // As an account can have many thousands of transactions, there is a limit
1030 // placed on the amount of transactions returned. If the limit is reached
1031 // before the result set has been exhausted (we always query for one more
1032 // than the limit), then we return an opaque marker that can be supplied in
1033 // a subsequent query.
1034 std::uint32_t queryLimit = numberOfResults + 1;
1035 std::uint32_t findLedger = 0, findSeq = 0;
1036
1037 if (lookingForMarker)
1038 {
1039 findLedger = options.marker->ledgerSeq;
1040 findSeq = options.marker->txnSeq;
1041 }
1042
1044
1045 static std::string const prefix(
1046 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1047 Status,RawTxn,TxnMeta
1048 FROM AccountTransactions INNER JOIN Transactions
1049 ON Transactions.TransID = AccountTransactions.TransID
1050 AND AccountTransactions.Account = '%s' WHERE
1051 )");
1052
1053 std::string sql;
1054
1055 // SQL's BETWEEN uses a closed interval ([a,b])
1056
1057 char const* const order = forward ? "ASC" : "DESC";
1058
1059 if (findLedger == 0)
1060 {
1061 sql = boost::str(
1062 boost::format(
1063 prefix + (R"(AccountTransactions.LedgerSeq BETWEEN %u AND %u
1064 ORDER BY AccountTransactions.LedgerSeq %s,
1065 AccountTransactions.TxnSeq %s
1066 LIMIT %u;)")) %
1067 toBase58(options.account) % options.minLedger % options.maxLedger %
1068 order % order % queryLimit);
1069 }
1070 else
1071 {
1072 char const* const compare = forward ? ">=" : "<=";
1073 std::uint32_t const minLedger =
1074 forward ? findLedger + 1 : options.minLedger;
1075 std::uint32_t const maxLedger =
1076 forward ? options.maxLedger : findLedger - 1;
1077
1078 auto b58acct = toBase58(options.account);
1079 sql = boost::str(
1080 boost::format((
1081 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1082 Status,RawTxn,TxnMeta
1083 FROM AccountTransactions, Transactions WHERE
1084 (AccountTransactions.TransID = Transactions.TransID AND
1085 AccountTransactions.Account = '%s' AND
1086 AccountTransactions.LedgerSeq BETWEEN %u AND %u)
1087 UNION
1088 SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,Status,RawTxn,TxnMeta
1089 FROM AccountTransactions, Transactions WHERE
1090 (AccountTransactions.TransID = Transactions.TransID AND
1091 AccountTransactions.Account = '%s' AND
1092 AccountTransactions.LedgerSeq = %u AND
1093 AccountTransactions.TxnSeq %s %u)
1094 ORDER BY AccountTransactions.LedgerSeq %s,
1095 AccountTransactions.TxnSeq %s
1096 LIMIT %u;
1097 )")) %
1098 b58acct % minLedger % maxLedger % b58acct % findLedger % compare %
1099 findSeq % order % order % queryLimit);
1100 }
1101
1102 {
1103 Blob rawData;
1104 Blob rawMeta;
1105
1106 // SOCI requires boost::optional (not std::optional) as parameters.
1107 boost::optional<std::uint64_t> ledgerSeq;
1108 boost::optional<std::uint32_t> txnSeq;
1109 boost::optional<std::string> status;
1110 soci::blob txnData(session);
1111 soci::blob txnMeta(session);
1112 soci::indicator dataPresent, metaPresent;
1113
1114 soci::statement st =
1115 (session.prepare << sql,
1116 soci::into(ledgerSeq),
1117 soci::into(txnSeq),
1118 soci::into(status),
1119 soci::into(txnData, dataPresent),
1120 soci::into(txnMeta, metaPresent));
1121
1122 st.execute();
1123
1124 while (st.fetch())
1125 {
1126 if (lookingForMarker)
1127 {
1128 if (findLedger == ledgerSeq.value_or(0) &&
1129 findSeq == txnSeq.value_or(0))
1130 {
1131 lookingForMarker = false;
1132 }
1133 else
1134 continue;
1135 }
1136 else if (numberOfResults == 0)
1137 {
1138 newmarker = {
1139 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1140 txnSeq.value_or(0)};
1141 break;
1142 }
1143
1144 if (dataPresent == soci::i_ok)
1145 convert(txnData, rawData);
1146 else
1147 rawData.clear();
1148
1149 if (metaPresent == soci::i_ok)
1150 convert(txnMeta, rawMeta);
1151 else
1152 rawMeta.clear();
1153
1154 // Work around a bug that could leave the metadata missing
1155 if (rawMeta.size() == 0)
1156 onUnsavedLedger(ledgerSeq.value_or(0));
1157
1158 // `rawData` and `rawMeta` will be used after they are moved.
1159 // That's OK.
1160 onTransaction(
1161 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1162 *status,
1163 std::move(rawData),
1164 std::move(rawMeta));
1165 // Note some callbacks will move the data, some will not. Clear
1166 // them so code doesn't depend on if the data was actually moved
1167 // or not. The code will be more efficient if `rawData` and
1168 // `rawMeta` don't have to allocate in `convert`, so don't
1169 // refactor my moving these variables into loop scope.
1170 rawData.clear();
1171 rawMeta.clear();
1172
1173 --numberOfResults;
1174 total++;
1175 }
1176 }
1177
1178 return {newmarker, total};
1179}
1180
1183 soci::session& session,
1184 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1186 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1187 onTransaction,
1189 std::uint32_t page_length)
1190{
1191 return accountTxPage(
1192 session, onUnsavedLedger, onTransaction, options, page_length, true);
1193}
1194
1197 soci::session& session,
1198 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1200 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1201 onTransaction,
1203 std::uint32_t page_length)
1204{
1205 return accountTxPage(
1206 session, onUnsavedLedger, onTransaction, options, page_length, false);
1207}
1208
1211 soci::session& session,
1212 Application& app,
1213 uint256 const& id,
1214 std::optional<ClosedInterval<uint32_t>> const& range,
1215 error_code_i& ec)
1216{
1217 std::string sql =
1218 "SELECT LedgerSeq,Status,RawTxn,TxnMeta "
1219 "FROM Transactions WHERE TransID='";
1220
1221 sql.append(to_string(id));
1222 sql.append("';");
1223
1224 // SOCI requires boost::optional (not std::optional) as parameters.
1225 boost::optional<std::uint64_t> ledgerSeq;
1226 boost::optional<std::string> status;
1227 Blob rawTxn, rawMeta;
1228 {
1229 soci::blob sociRawTxnBlob(session), sociRawMetaBlob(session);
1230 soci::indicator txn, meta;
1231
1232 session << sql, soci::into(ledgerSeq), soci::into(status),
1233 soci::into(sociRawTxnBlob, txn), soci::into(sociRawMetaBlob, meta);
1234
1235 auto const got_data = session.got_data();
1236
1237 if ((!got_data || txn != soci::i_ok || meta != soci::i_ok) && !range)
1238 return TxSearched::unknown;
1239
1240 if (!got_data)
1241 {
1242 uint64_t count = 0;
1243 soci::indicator rti;
1244
1245 session
1246 << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
1247 "LedgerSeq BETWEEN "
1248 << range->first() << " AND " << range->last() << ";",
1249 soci::into(count, rti);
1250
1251 if (!session.got_data() || rti != soci::i_ok)
1252 return TxSearched::some;
1253
1254 return count == (range->last() - range->first() + 1)
1256 : TxSearched::some;
1257 }
1258
1259 convert(sociRawTxnBlob, rawTxn);
1260 convert(sociRawMetaBlob, rawMeta);
1261 }
1262
1263 try
1264 {
1265 auto txn =
1266 Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
1267
1268 if (!ledgerSeq)
1269 return std::pair{std::move(txn), nullptr};
1270
1271 std::uint32_t inLedger =
1272 rangeCheckedCast<std::uint32_t>(ledgerSeq.value());
1273
1274 auto txMeta = std::make_shared<TxMeta>(id, inLedger, rawMeta);
1275
1276 return std::pair{std::move(txn), std::move(txMeta)};
1277 }
1278 catch (std::exception& e)
1279 {
1280 JLOG(app.journal("Ledger").warn())
1281 << "Unable to deserialize transaction from raw SQL value. Error: "
1282 << e.what();
1283
1285 }
1286
1287 return TxSearched::unknown;
1288}
1289
1290bool
1291dbHasSpace(soci::session& session, Config const& config, beast::Journal j)
1292{
1293 boost::filesystem::space_info space =
1294 boost::filesystem::space(config.legacy("database_path"));
1295
1296 if (space.available < megabytes(512))
1297 {
1298 JLOG(j.fatal()) << "Remaining free disk space is less than 512MB";
1299 return false;
1300 }
1301
1302 if (config.useTxTables())
1303 {
1304 DatabaseCon::Setup dbSetup = setup_DatabaseCon(config);
1305 boost::filesystem::path dbPath = dbSetup.dataDir / TxDBName;
1306 boost::system::error_code ec;
1308 boost::filesystem::file_size(dbPath, ec);
1309 if (ec)
1310 {
1311 JLOG(j.error())
1312 << "Error checking transaction db file size: " << ec.message();
1313 dbSize.reset();
1314 }
1315
1316 static auto const pageSize = [&] {
1317 std::uint32_t ps;
1318 session << "PRAGMA page_size;", soci::into(ps);
1319 return ps;
1320 }();
1321 static auto const maxPages = [&] {
1322 std::uint32_t mp;
1323 session << "PRAGMA max_page_count;", soci::into(mp);
1324 return mp;
1325 }();
1326 std::uint32_t pageCount;
1327 session << "PRAGMA page_count;", soci::into(pageCount);
1328 std::uint32_t freePages = maxPages - pageCount;
1329 std::uint64_t freeSpace =
1330 safe_cast<std::uint64_t>(freePages) * pageSize;
1331 JLOG(j.info())
1332 << "Transaction DB pathname: " << dbPath.string()
1333 << "; file size: " << dbSize.value_or(-1) << " bytes"
1334 << "; SQLite page size: " << pageSize << " bytes"
1335 << "; Free pages: " << freePages << "; Free space: " << freeSpace
1336 << " bytes; "
1337 << "Note that this does not take into account available disk "
1338 "space.";
1339
1340 if (freeSpace < megabytes(512))
1341 {
1342 JLOG(j.fatal())
1343 << "Free SQLite space for transaction db is less than "
1344 "512MB. To fix this, rippled must be executed with the "
1345 "vacuum parameter before restarting. "
1346 "Note that this activity can take multiple days, "
1347 "depending on database size.";
1348 return false;
1349 }
1350 }
1351
1352 return true;
1353}
1354
1355} // namespace detail
1356} // 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:905
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:514
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:491
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:1170
std::optional< LedgerInfo > getNewestLedgerInfo(soci::session &session, beast::Journal j)
getNewestLedgerInfo Returns info of newest saved ledger.
Definition Node.cpp:471
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:783
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:1156
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
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:863
std::pair< std::vector< std::shared_ptr< Transaction > >, int > getTxHistory(soci::session &session, Application &app, LedgerIndex startIndex, int quantity)
getTxHistory Returns given number of most recent transactions starting from given number of entry.
Definition Node.cpp:620
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
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:479
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:963
std::optional< LedgerInfo > getLedgerInfoByIndex(soci::session &session, LedgerIndex ledgerSeq, beast::Journal j)
getLedgerInfoByIndex Returns ledger by its sequence.
Definition Node.cpp:460
bool dbHasSpace(soci::session &session, Config const &config, beast::Journal j)
dbHasSpace Checks if given database has available space.
Definition Node.cpp:1265
std::optional< LedgerInfo > getLedgerInfoByHash(soci::session &session, uint256 const &ledgerHash, beast::Journal j)
getLedgerInfoByHash Returns info of ledger with given hash.
Definition Node.cpp:503
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:687
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:874
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:973
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:390
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:544
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:1002
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:1184
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)