rippled
Loading...
Searching...
No Matches
Node.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2020 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/ledger/AcceptedLedger.h>
21#include <xrpld/app/ledger/LedgerMaster.h>
22#include <xrpld/app/ledger/LedgerToJson.h>
23#include <xrpld/app/ledger/PendingSaves.h>
24#include <xrpld/app/ledger/TransactionMaster.h>
25#include <xrpld/app/rdb/RelationalDatabase.h>
26#include <xrpld/app/rdb/backend/detail/Node.h>
27#include <xrpld/core/DatabaseCon.h>
28#include <xrpld/core/SociDB.h>
29
30#include <xrpl/basics/BasicConfig.h>
31#include <xrpl/basics/StringUtilities.h>
32#include <xrpl/json/to_string.h>
33
34#include <boost/range/adaptor/transformed.hpp>
35
36#include <soci/sqlite3/soci-sqlite3.h>
37
38namespace ripple {
39namespace detail {
40
46static std::string
48{
49 static_assert(
50 TableTypeCount == 3,
51 "Need to modify switch statement if enum is modified");
52
53 switch (type)
54 {
56 return "Ledgers";
58 return "Transactions";
60 return "AccountTransactions";
61 // LCOV_EXCL_START
62 default:
63 UNREACHABLE("ripple::detail::to_string : invalid TableType");
64 return "Unknown";
65 // LCOV_EXCL_STOP
66 }
67}
68
69DatabasePairValid
71 Config const& config,
72 DatabaseCon::Setup const& setup,
73 DatabaseCon::CheckpointerSetup const& checkpointerSetup,
75{
76 // ledger database
78 setup, LgrDBName, setup.lgrPragma, LgrDBInit, checkpointerSetup, j)};
79 lgr->getSession() << boost::str(
80 boost::format("PRAGMA cache_size=-%d;") %
82
83 if (config.useTxTables())
84 {
85 // transaction database
87 setup, TxDBName, setup.txPragma, TxDBInit, checkpointerSetup, j)};
88 tx->getSession() << boost::str(
89 boost::format("PRAGMA cache_size=-%d;") %
91
92 if (!setup.standAlone || setup.startUp == Config::LOAD ||
93 setup.startUp == Config::LOAD_FILE ||
94 setup.startUp == Config::REPLAY)
95 {
96 // Check if AccountTransactions has primary key
97 std::string cid, name, type;
98 std::size_t notnull, dflt_value, pk;
99 soci::indicator ind;
100 soci::statement st =
101 (tx->getSession().prepare
102 << ("PRAGMA table_info(AccountTransactions);"),
103 soci::into(cid),
104 soci::into(name),
105 soci::into(type),
106 soci::into(notnull),
107 soci::into(dflt_value, ind),
108 soci::into(pk));
109
110 st.execute();
111 while (st.fetch())
112 {
113 if (pk == 1)
114 {
115 return {std::move(lgr), std::move(tx), false};
116 }
117 }
118 }
119
120 return {std::move(lgr), std::move(tx), true};
121 }
122 else
123 return {std::move(lgr), {}, true};
124}
125
127getMinLedgerSeq(soci::session& session, TableType type)
128{
129 std::string query = "SELECT MIN(LedgerSeq) FROM " + to_string(type) + ";";
130 // SOCI requires boost::optional (not std::optional) as the parameter.
131 boost::optional<LedgerIndex> m;
132 session << query, soci::into(m);
133 return m ? *m : std::optional<LedgerIndex>();
134}
135
137getMaxLedgerSeq(soci::session& session, TableType type)
138{
139 std::string query = "SELECT MAX(LedgerSeq) FROM " + to_string(type) + ";";
140 // SOCI requires boost::optional (not std::optional) as the parameter.
141 boost::optional<LedgerIndex> m;
142 session << query, soci::into(m);
143 return m ? *m : std::optional<LedgerIndex>();
144}
145
146void
147deleteByLedgerSeq(soci::session& session, TableType type, LedgerIndex ledgerSeq)
148{
149 session << "DELETE FROM " << to_string(type)
150 << " WHERE LedgerSeq == " << ledgerSeq << ";";
151}
152
153void
155 soci::session& session,
156 TableType type,
157 LedgerIndex ledgerSeq)
158{
159 session << "DELETE FROM " << to_string(type) << " WHERE LedgerSeq < "
160 << ledgerSeq << ";";
161}
162
164getRows(soci::session& session, TableType type)
165{
166 std::size_t rows;
167 session << "SELECT COUNT(*) AS rows "
168 "FROM "
169 << to_string(type) << ";",
170 soci::into(rows);
171
172 return rows;
173}
174
176getRowsMinMax(soci::session& session, TableType type)
177{
179 session << "SELECT COUNT(*) AS rows, "
180 "MIN(LedgerSeq) AS first, "
181 "MAX(LedgerSeq) AS last "
182 "FROM "
183 << to_string(type) << ";",
184 soci::into(res.numberOfRows), soci::into(res.minLedgerSequence),
185 soci::into(res.maxLedgerSequence);
186
187 return res;
188}
189
190bool
192 DatabaseCon& ldgDB,
193 DatabaseCon& txnDB,
194 Application& app,
195 std::shared_ptr<Ledger const> const& ledger,
196 bool current)
197{
198 auto j = app.journal("Ledger");
199 auto seq = ledger->info().seq;
200
201 // TODO(tom): Fix this hard-coded SQL!
202 JLOG(j.trace()) << "saveValidatedLedger " << (current ? "" : "fromAcquire ")
203 << seq;
204
205 if (!ledger->info().accountHash.isNonZero())
206 {
207 // LCOV_EXCL_START
208 JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}});
209 UNREACHABLE("ripple::detail::saveValidatedLedger : zero account hash");
210 // LCOV_EXCL_STOP
211 }
212
213 if (ledger->info().accountHash != ledger->stateMap().getHash().as_uint256())
214 {
215 // LCOV_EXCL_START
216 JLOG(j.fatal()) << "sAL: " << ledger->info().accountHash
217 << " != " << ledger->stateMap().getHash();
218 JLOG(j.fatal()) << "saveAcceptedLedger: seq=" << seq
219 << ", current=" << current;
220 UNREACHABLE(
221 "ripple::detail::saveValidatedLedger : mismatched account hash");
222 // LCOV_EXCL_STOP
223 }
224
225 XRPL_ASSERT(
226 ledger->info().txHash == ledger->txMap().getHash().as_uint256(),
227 "ripple::detail::saveValidatedLedger : transaction hash match");
228
229 // Save the ledger header in the hashed object store
230 {
231 Serializer s(128);
233 addRaw(ledger->info(), s);
234 app.getNodeStore().store(
235 hotLEDGER, std::move(s.modData()), ledger->info().hash, seq);
236 }
237
239 try
240 {
241 aLedger = app.getAcceptedLedgerCache().fetch(ledger->info().hash);
242 if (!aLedger)
243 {
244 aLedger = std::make_shared<AcceptedLedger>(ledger, app);
245 app.getAcceptedLedgerCache().canonicalize_replace_client(
246 ledger->info().hash, aLedger);
247 }
248 }
249 catch (std::exception const&)
250 {
251 JLOG(j.warn()) << "An accepted ledger was missing nodes";
252 app.getLedgerMaster().failedSave(seq, ledger->info().hash);
253 // Clients can now trust the database for information about this
254 // ledger sequence.
255 app.pendingSaves().finishWork(seq);
256 return false;
257 }
258
259 {
260 static boost::format deleteLedger(
261 "DELETE FROM Ledgers WHERE LedgerSeq = %u;");
262 static boost::format deleteTrans1(
263 "DELETE FROM Transactions WHERE LedgerSeq = %u;");
264 static boost::format deleteTrans2(
265 "DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
266 static boost::format deleteAcctTrans(
267 "DELETE FROM AccountTransactions WHERE TransID = '%s';");
268
269 {
270 auto db = ldgDB.checkoutDb();
271 *db << boost::str(deleteLedger % seq);
272 }
273
274 if (app.config().useTxTables())
275 {
276 auto db = txnDB.checkoutDb();
277
278 soci::transaction tr(*db);
279
280 *db << boost::str(deleteTrans1 % seq);
281 *db << boost::str(deleteTrans2 % seq);
282
283 std::string const ledgerSeq(std::to_string(seq));
284
285 for (auto const& acceptedLedgerTx : *aLedger)
286 {
287 uint256 transactionID = acceptedLedgerTx->getTransactionID();
288
289 std::string const txnId(to_string(transactionID));
290 std::string const txnSeq(
291 std::to_string(acceptedLedgerTx->getTxnSeq()));
292
293 *db << boost::str(deleteAcctTrans % transactionID);
294
295 auto const& accts = acceptedLedgerTx->getAffected();
296
297 if (!accts.empty())
298 {
299 std::string sql(
300 "INSERT INTO AccountTransactions "
301 "(TransID, Account, LedgerSeq, TxnSeq) VALUES ");
302
303 // Try to make an educated guess on how much space we'll
304 // need for our arguments. In argument order we have: 64
305 // + 34 + 10 + 10 = 118 + 10 extra = 128 bytes
306 sql.reserve(sql.length() + (accts.size() * 128));
307
308 bool first = true;
309 for (auto const& account : accts)
310 {
311 if (!first)
312 sql += ", ('";
313 else
314 {
315 sql += "('";
316 first = false;
317 }
318
319 sql += txnId;
320 sql += "','";
321 sql += toBase58(account);
322 sql += "',";
323 sql += ledgerSeq;
324 sql += ",";
325 sql += txnSeq;
326 sql += ")";
327 }
328 sql += ";";
329 JLOG(j.trace()) << "ActTx: " << sql;
330 *db << sql;
331 }
332 else if (auto const& sleTxn = acceptedLedgerTx->getTxn();
333 !isPseudoTx(*sleTxn))
334 {
335 // It's okay for pseudo transactions to not affect any
336 // accounts. But otherwise...
337 JLOG(j.warn()) << "Transaction in ledger " << seq
338 << " affects no accounts";
339 JLOG(j.warn()) << sleTxn->getJson(JsonOptions::none);
340 }
341
342 *db
344 acceptedLedgerTx->getTxn()->getMetaSQL(
345 seq, acceptedLedgerTx->getEscMeta()) +
346 ";");
347
350 seq,
351 acceptedLedgerTx->getTxnSeq(),
352 app.config().NETWORK_ID);
353 }
354
355 tr.commit();
356 }
357
358 {
359 static std::string addLedger(
360 R"sql(INSERT OR REPLACE INTO Ledgers
361 (LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,
362 CloseTimeRes,CloseFlags,AccountSetHash,TransSetHash)
363 VALUES
364 (:ledgerHash,:ledgerSeq,:prevHash,:totalCoins,:closingTime,:prevClosingTime,
365 :closeTimeRes,:closeFlags,:accountSetHash,:transSetHash);)sql");
366
367 auto db(ldgDB.checkoutDb());
368
369 soci::transaction tr(*db);
370
371 auto const hash = to_string(ledger->info().hash);
372 auto const parentHash = to_string(ledger->info().parentHash);
373 auto const drops = to_string(ledger->info().drops);
374 auto const closeTime =
375 ledger->info().closeTime.time_since_epoch().count();
376 auto const parentCloseTime =
377 ledger->info().parentCloseTime.time_since_epoch().count();
378 auto const closeTimeResolution =
379 ledger->info().closeTimeResolution.count();
380 auto const closeFlags = ledger->info().closeFlags;
381 auto const accountHash = to_string(ledger->info().accountHash);
382 auto const txHash = to_string(ledger->info().txHash);
383
384 *db << addLedger, soci::use(hash), soci::use(seq),
385 soci::use(parentHash), soci::use(drops), soci::use(closeTime),
386 soci::use(parentCloseTime), soci::use(closeTimeResolution),
387 soci::use(closeFlags), soci::use(accountHash),
388 soci::use(txHash);
389
390 tr.commit();
391 }
392 }
393
394 return true;
395}
396
407 soci::session& session,
408 std::string const& sqlSuffix,
410{
411 // SOCI requires boost::optional (not std::optional) as parameters.
412 boost::optional<std::string> hash, parentHash, accountHash, txHash;
413 boost::optional<std::uint64_t> seq, drops, closeTime, parentCloseTime,
414 closeTimeResolution, closeFlags;
415
416 std::string const sql =
417 "SELECT "
418 "LedgerHash, PrevHash, AccountSetHash, TransSetHash, "
419 "TotalCoins,"
420 "ClosingTime, PrevClosingTime, CloseTimeRes, CloseFlags,"
421 "LedgerSeq FROM Ledgers " +
422 sqlSuffix + ";";
423
424 session << sql, soci::into(hash), soci::into(parentHash),
425 soci::into(accountHash), soci::into(txHash), soci::into(drops),
426 soci::into(closeTime), soci::into(parentCloseTime),
427 soci::into(closeTimeResolution), soci::into(closeFlags),
428 soci::into(seq);
429
430 if (!session.got_data())
431 {
432 JLOG(j.debug()) << "Ledger not found: " << sqlSuffix;
433 return {};
434 }
435
436 using time_point = NetClock::time_point;
437 using duration = NetClock::duration;
438
439 LedgerInfo info;
440
441 if (hash && !info.hash.parseHex(*hash))
442 {
443 JLOG(j.debug()) << "Hash parse error for ledger: " << sqlSuffix;
444 return {};
445 }
446
447 if (parentHash && !info.parentHash.parseHex(*parentHash))
448 {
449 JLOG(j.debug()) << "parentHash parse error for ledger: " << sqlSuffix;
450 return {};
451 }
452
453 if (accountHash && !info.accountHash.parseHex(*accountHash))
454 {
455 JLOG(j.debug()) << "accountHash parse error for ledger: " << sqlSuffix;
456 return {};
457 }
458
459 if (txHash && !info.txHash.parseHex(*txHash))
460 {
461 JLOG(j.debug()) << "txHash parse error for ledger: " << sqlSuffix;
462 return {};
463 }
464
465 info.seq = rangeCheckedCast<std::uint32_t>(seq.value_or(0));
466 info.drops = drops.value_or(0);
467 info.closeTime = time_point{duration{closeTime.value_or(0)}};
468 info.parentCloseTime = time_point{duration{parentCloseTime.value_or(0)}};
469 info.closeFlags = closeFlags.value_or(0);
470 info.closeTimeResolution = duration{closeTimeResolution.value_or(0)};
472 return info;
473}
474
477 soci::session& session,
478 LedgerIndex ledgerSeq,
480{
482 s << "WHERE LedgerSeq = " << ledgerSeq;
483 return getLedgerInfo(session, s.str(), j);
484}
485
487getNewestLedgerInfo(soci::session& session, beast::Journal j)
488{
490 s << "ORDER BY LedgerSeq DESC LIMIT 1";
491 return getLedgerInfo(session, s.str(), j);
492}
493
496 soci::session& session,
497 LedgerIndex ledgerFirstIndex,
499{
501 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
502 " ORDER BY LedgerSeq ASC LIMIT 1";
503 return getLedgerInfo(session, s.str(), j);
504}
505
508 soci::session& session,
509 LedgerIndex ledgerFirstIndex,
511{
513 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
514 " ORDER BY LedgerSeq DESC LIMIT 1";
515 return getLedgerInfo(session, s.str(), j);
516}
517
520 soci::session& session,
521 uint256 const& ledgerHash,
523{
525 s << "WHERE LedgerHash = '" << ledgerHash << "'";
526 return getLedgerInfo(session, s.str(), j);
527}
528
530getHashByIndex(soci::session& session, LedgerIndex ledgerIndex)
531{
532 uint256 ret;
533
534 std::string sql =
535 "SELECT LedgerHash FROM Ledgers INDEXED BY SeqLedger WHERE LedgerSeq='";
536 sql.append(std::to_string(ledgerIndex));
537 sql.append("';");
538
539 std::string hash;
540 {
541 // SOCI requires boost::optional (not std::optional) as the parameter.
542 boost::optional<std::string> lh;
543 session << sql, soci::into(lh);
544
545 if (!session.got_data() || !lh)
546 return ret;
547
548 hash = *lh;
549 if (hash.empty())
550 return ret;
551 }
552
553 if (!ret.parseHex(hash))
554 return ret;
556 return ret;
557}
558
561 soci::session& session,
562 LedgerIndex ledgerIndex,
564{
565 // SOCI requires boost::optional (not std::optional) as the parameter.
566 boost::optional<std::string> lhO, phO;
567
568 session << "SELECT LedgerHash,PrevHash FROM Ledgers "
569 "INDEXED BY SeqLedger WHERE LedgerSeq = :ls;",
570 soci::into(lhO), soci::into(phO), soci::use(ledgerIndex);
571
572 if (!lhO || !phO)
573 {
574 auto stream = j.trace();
575 JLOG(stream) << "Don't have ledger " << ledgerIndex;
576 return {};
577 }
578
579 LedgerHashPair hashes;
580 if (!hashes.ledgerHash.parseHex(*lhO) || !hashes.parentHash.parseHex(*phO))
581 {
582 auto stream = j.trace();
583 JLOG(stream) << "Error parse hashes for ledger " << ledgerIndex;
584 return {};
585 }
587 return hashes;
588}
589
592 soci::session& session,
593 LedgerIndex minSeq,
594 LedgerIndex maxSeq,
596{
597 std::string sql =
598 "SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq >= ";
599 sql.append(std::to_string(minSeq));
600 sql.append(" AND LedgerSeq <= ");
601 sql.append(std::to_string(maxSeq));
602 sql.append(";");
603
604 std::uint64_t ls;
605 std::string lh;
606 // SOCI requires boost::optional (not std::optional) as the parameter.
607 boost::optional<std::string> ph;
608 soci::statement st =
609 (session.prepare << sql,
610 soci::into(ls),
611 soci::into(lh),
612 soci::into(ph));
613
614 st.execute();
616 while (st.fetch())
617 {
618 LedgerHashPair& hashes = res[rangeCheckedCast<LedgerIndex>(ls)];
619 if (!hashes.ledgerHash.parseHex(lh))
620 {
621 JLOG(j.warn()) << "Error parsed hash for ledger seq: " << ls;
622 }
623 if (!ph)
624 {
625 JLOG(j.warn()) << "Null prev hash for ledger seq: " << ls;
626 }
627 else if (!hashes.parentHash.parseHex(*ph))
628 {
629 JLOG(j.warn()) << "Error parsed prev hash for ledger seq: " << ls;
630 }
632 return res;
633}
634
637 soci::session& session,
638 Application& app,
639 LedgerIndex startIndex,
640 int quantity)
641{
642 std::string sql = boost::str(
643 boost::format(
644 "SELECT LedgerSeq, Status, RawTxn "
645 "FROM Transactions ORDER BY LedgerSeq DESC LIMIT %u,%u;") %
646 startIndex % quantity);
647
649 int total = 0;
650
651 {
652 // SOCI requires boost::optional (not std::optional) as parameters.
653 boost::optional<std::uint64_t> ledgerSeq;
654 boost::optional<std::string> status;
655 soci::blob sociRawTxnBlob(session);
656 soci::indicator rti;
657 Blob rawTxn;
658
659 soci::statement st =
660 (session.prepare << sql,
661 soci::into(ledgerSeq),
662 soci::into(status),
663 soci::into(sociRawTxnBlob, rti));
664
665 st.execute();
666 while (st.fetch())
667 {
668 if (soci::i_ok == rti)
669 convert(sociRawTxnBlob, rawTxn);
670 else
671 rawTxn.clear();
672
673 if (auto trans = Transaction::transactionFromSQL(
674 ledgerSeq, status, rawTxn, app))
675 {
676 total++;
677 txs.push_back(trans);
678 }
679 }
680 }
681
682 return {txs, total};
683}
684
702static std::string
704 Application& app,
705 std::string selection,
706 RelationalDatabase::AccountTxOptions const& options,
707 bool descending,
708 bool binary,
709 bool count,
711{
712 constexpr std::uint32_t NONBINARY_PAGE_LENGTH = 200;
713 constexpr std::uint32_t BINARY_PAGE_LENGTH = 500;
714
715 std::uint32_t numberOfResults;
716
717 if (count)
718 {
719 numberOfResults = std::numeric_limits<std::uint32_t>::max();
720 }
721 else if (options.limit == UINT32_MAX)
722 {
723 numberOfResults = binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH;
724 }
725 else if (!options.bUnlimited)
726 {
727 numberOfResults = std::min(
728 binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH, options.limit);
729 }
730 else
731 {
732 numberOfResults = options.limit;
733 }
734
735 std::string maxClause = "";
736 std::string minClause = "";
737
738 if (options.maxLedger)
739 {
740 maxClause = boost::str(
741 boost::format("AND AccountTransactions.LedgerSeq <= '%u'") %
742 options.maxLedger);
743 }
744
745 if (options.minLedger)
746 {
747 minClause = boost::str(
748 boost::format("AND AccountTransactions.LedgerSeq >= '%u'") %
749 options.minLedger);
750 }
751
752 std::string sql;
753
754 if (count)
755 sql = boost::str(
756 boost::format("SELECT %s FROM AccountTransactions "
757 "WHERE Account = '%s' %s %s LIMIT %u, %u;") %
758 selection % toBase58(options.account) % maxClause % minClause %
759 options.offset % numberOfResults);
760 else
761 sql = boost::str(
762 boost::format(
763 "SELECT %s FROM "
764 "AccountTransactions INNER JOIN Transactions "
765 "ON Transactions.TransID = AccountTransactions.TransID "
766 "WHERE Account = '%s' %s %s "
767 "ORDER BY AccountTransactions.LedgerSeq %s, "
768 "AccountTransactions.TxnSeq %s, AccountTransactions.TransID %s "
769 "LIMIT %u, %u;") %
770 selection % toBase58(options.account) % maxClause % minClause %
771 (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") %
772 (descending ? "DESC" : "ASC") % options.offset % numberOfResults);
773 JLOG(j.trace()) << "txSQL query: " << sql;
774 return sql;
775}
776
800 soci::session& session,
801 Application& app,
802 LedgerMaster& ledgerMaster,
803 RelationalDatabase::AccountTxOptions const& options,
804 bool descending,
806{
808
810 app,
811 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
812 options,
813 descending,
814 false,
815 false,
816 j);
817 if (sql == "")
818 return {ret, 0};
819
820 int total = 0;
821 {
822 // SOCI requires boost::optional (not std::optional) as parameters.
823 boost::optional<std::uint64_t> ledgerSeq;
824 boost::optional<std::string> status;
825 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
826 soci::indicator rti, tmi;
827 Blob rawTxn, txnMeta;
828
829 soci::statement st =
830 (session.prepare << sql,
831 soci::into(ledgerSeq),
832 soci::into(status),
833 soci::into(sociTxnBlob, rti),
834 soci::into(sociTxnMetaBlob, tmi));
835
836 st.execute();
837 while (st.fetch())
838 {
839 if (soci::i_ok == rti)
840 convert(sociTxnBlob, rawTxn);
841 else
842 rawTxn.clear();
843
844 if (soci::i_ok == tmi)
845 convert(sociTxnMetaBlob, txnMeta);
846 else
847 txnMeta.clear();
848
849 auto txn =
850 Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
851
852 if (txnMeta.empty())
853 { // Work around a bug that could leave the metadata missing
854 auto const seq =
855 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
856
857 JLOG(j.warn())
858 << "Recovering ledger " << seq << ", txn " << txn->getID();
859
860 if (auto l = ledgerMaster.getLedgerBySeq(seq))
861 pendSaveValidated(app, l, false, false);
862 }
863
864 if (txn)
865 {
866 ret.emplace_back(
867 txn,
869 txn->getID(), txn->getLedger(), txnMeta));
870 total++;
871 }
872 }
873 }
875 return {ret, total};
876}
877
880 soci::session& session,
881 Application& app,
882 LedgerMaster& ledgerMaster,
883 RelationalDatabase::AccountTxOptions const& options,
886 return getAccountTxs(session, app, ledgerMaster, options, false, j);
887}
888
891 soci::session& session,
892 Application& app,
896{
897 return getAccountTxs(session, app, ledgerMaster, options, true, j);
898}
899
922 soci::session& session,
923 Application& app,
924 RelationalDatabase::AccountTxOptions const& options,
925 bool descending,
927{
929
931 app,
932 "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
933 options,
934 descending,
935 true /*binary*/,
936 false,
937 j);
938 if (sql == "")
939 return {ret, 0};
940
941 int total = 0;
942
943 {
944 // SOCI requires boost::optional (not std::optional) as parameters.
945 boost::optional<std::uint64_t> ledgerSeq;
946 boost::optional<std::string> status;
947 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
948 soci::indicator rti, tmi;
949
950 soci::statement st =
951 (session.prepare << sql,
952 soci::into(ledgerSeq),
953 soci::into(status),
954 soci::into(sociTxnBlob, rti),
955 soci::into(sociTxnMetaBlob, tmi));
956
957 st.execute();
958 while (st.fetch())
959 {
960 Blob rawTxn;
961 if (soci::i_ok == rti)
962 convert(sociTxnBlob, rawTxn);
963 Blob txnMeta;
964 if (soci::i_ok == tmi)
965 convert(sociTxnMetaBlob, txnMeta);
966
967 auto const seq =
968 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
969
970 ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq);
971 total++;
972 }
973 }
975 return {ret, total};
976}
977
980 soci::session& session,
981 Application& app,
982 RelationalDatabase::AccountTxOptions const& options,
985 return getAccountTxsB(session, app, options, false, j);
986}
987
990 soci::session& session,
991 Application& app,
994{
995 return getAccountTxsB(session, app, options, true, j);
996}
997
1019 soci::session& session,
1020 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1022 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1023 onTransaction,
1024 RelationalDatabase::AccountTxPageOptions const& options,
1025 std::uint32_t page_length,
1026 bool forward)
1027{
1028 int total = 0;
1029
1030 bool lookingForMarker = options.marker.has_value();
1031
1032 std::uint32_t numberOfResults;
1033
1034 if (options.limit == 0 || options.limit == UINT32_MAX ||
1035 (options.limit > page_length && !options.bAdmin))
1036 numberOfResults = page_length;
1037 else
1038 numberOfResults = options.limit;
1039
1040 // As an account can have many thousands of transactions, there is a limit
1041 // placed on the amount of transactions returned. If the limit is reached
1042 // before the result set has been exhausted (we always query for one more
1043 // than the limit), then we return an opaque marker that can be supplied in
1044 // a subsequent query.
1045 std::uint32_t queryLimit = numberOfResults + 1;
1046 std::uint32_t findLedger = 0, findSeq = 0;
1047
1048 if (lookingForMarker)
1049 {
1050 findLedger = options.marker->ledgerSeq;
1051 findSeq = options.marker->txnSeq;
1052 }
1053
1055
1056 static std::string const prefix(
1057 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1058 Status,RawTxn,TxnMeta
1059 FROM AccountTransactions INNER JOIN Transactions
1060 ON Transactions.TransID = AccountTransactions.TransID
1061 AND AccountTransactions.Account = '%s' WHERE
1062 )");
1063
1064 std::string sql;
1065
1066 // SQL's BETWEEN uses a closed interval ([a,b])
1067
1068 char const* const order = forward ? "ASC" : "DESC";
1069
1070 if (findLedger == 0)
1071 {
1072 sql = boost::str(
1073 boost::format(
1074 prefix + (R"(AccountTransactions.LedgerSeq BETWEEN %u AND %u
1075 ORDER BY AccountTransactions.LedgerSeq %s,
1076 AccountTransactions.TxnSeq %s
1077 LIMIT %u;)")) %
1078 toBase58(options.account) % options.minLedger % options.maxLedger %
1079 order % order % queryLimit);
1080 }
1081 else
1082 {
1083 char const* const compare = forward ? ">=" : "<=";
1084 std::uint32_t const minLedger =
1085 forward ? findLedger + 1 : options.minLedger;
1086 std::uint32_t const maxLedger =
1087 forward ? options.maxLedger : findLedger - 1;
1088
1089 auto b58acct = toBase58(options.account);
1090 sql = boost::str(
1091 boost::format((
1092 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1093 Status,RawTxn,TxnMeta
1094 FROM AccountTransactions, Transactions WHERE
1095 (AccountTransactions.TransID = Transactions.TransID AND
1096 AccountTransactions.Account = '%s' AND
1097 AccountTransactions.LedgerSeq BETWEEN %u AND %u)
1098 UNION
1099 SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,Status,RawTxn,TxnMeta
1100 FROM AccountTransactions, Transactions WHERE
1101 (AccountTransactions.TransID = Transactions.TransID AND
1102 AccountTransactions.Account = '%s' AND
1103 AccountTransactions.LedgerSeq = %u AND
1104 AccountTransactions.TxnSeq %s %u)
1105 ORDER BY AccountTransactions.LedgerSeq %s,
1106 AccountTransactions.TxnSeq %s
1107 LIMIT %u;
1108 )")) %
1109 b58acct % minLedger % maxLedger % b58acct % findLedger % compare %
1110 findSeq % order % order % queryLimit);
1111 }
1112
1113 {
1114 Blob rawData;
1115 Blob rawMeta;
1116
1117 // SOCI requires boost::optional (not std::optional) as parameters.
1118 boost::optional<std::uint64_t> ledgerSeq;
1119 boost::optional<std::uint32_t> txnSeq;
1120 boost::optional<std::string> status;
1121 soci::blob txnData(session);
1122 soci::blob txnMeta(session);
1123 soci::indicator dataPresent, metaPresent;
1124
1125 soci::statement st =
1126 (session.prepare << sql,
1127 soci::into(ledgerSeq),
1128 soci::into(txnSeq),
1129 soci::into(status),
1130 soci::into(txnData, dataPresent),
1131 soci::into(txnMeta, metaPresent));
1132
1133 st.execute();
1134
1135 while (st.fetch())
1136 {
1137 if (lookingForMarker)
1138 {
1139 if (findLedger == ledgerSeq.value_or(0) &&
1140 findSeq == txnSeq.value_or(0))
1141 {
1142 lookingForMarker = false;
1143 }
1144 else
1145 continue;
1146 }
1147 else if (numberOfResults == 0)
1148 {
1149 newmarker = {
1150 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1151 txnSeq.value_or(0)};
1152 break;
1153 }
1154
1155 if (dataPresent == soci::i_ok)
1156 convert(txnData, rawData);
1157 else
1158 rawData.clear();
1159
1160 if (metaPresent == soci::i_ok)
1161 convert(txnMeta, rawMeta);
1162 else
1163 rawMeta.clear();
1164
1165 // Work around a bug that could leave the metadata missing
1166 if (rawMeta.size() == 0)
1167 onUnsavedLedger(ledgerSeq.value_or(0));
1168
1169 // `rawData` and `rawMeta` will be used after they are moved.
1170 // That's OK.
1171 onTransaction(
1172 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1173 *status,
1174 std::move(rawData),
1175 std::move(rawMeta));
1176 // Note some callbacks will move the data, some will not. Clear
1177 // them so code doesn't depend on if the data was actually moved
1178 // or not. The code will be more efficient if `rawData` and
1179 // `rawMeta` don't have to allocate in `convert`, so don't
1180 // refactor my moving these variables into loop scope.
1181 rawData.clear();
1182 rawMeta.clear();
1183
1184 --numberOfResults;
1185 total++;
1186 }
1187 }
1188
1189 return {newmarker, total};
1190}
1191
1194 soci::session& session,
1195 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1197 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1198 onTransaction,
1200 std::uint32_t page_length)
1201{
1202 return accountTxPage(
1203 session, onUnsavedLedger, onTransaction, options, page_length, true);
1204}
1205
1208 soci::session& session,
1209 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1211 void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1212 onTransaction,
1214 std::uint32_t page_length)
1215{
1216 return accountTxPage(
1217 session, onUnsavedLedger, onTransaction, options, page_length, false);
1218}
1219
1222 soci::session& session,
1223 Application& app,
1224 uint256 const& id,
1225 std::optional<ClosedInterval<uint32_t>> const& range,
1226 error_code_i& ec)
1227{
1228 std::string sql =
1229 "SELECT LedgerSeq,Status,RawTxn,TxnMeta "
1230 "FROM Transactions WHERE TransID='";
1231
1232 sql.append(to_string(id));
1233 sql.append("';");
1234
1235 // SOCI requires boost::optional (not std::optional) as parameters.
1236 boost::optional<std::uint64_t> ledgerSeq;
1237 boost::optional<std::string> status;
1238 Blob rawTxn, rawMeta;
1239 {
1240 soci::blob sociRawTxnBlob(session), sociRawMetaBlob(session);
1241 soci::indicator txn, meta;
1242
1243 session << sql, soci::into(ledgerSeq), soci::into(status),
1244 soci::into(sociRawTxnBlob, txn), soci::into(sociRawMetaBlob, meta);
1245
1246 auto const got_data = session.got_data();
1247
1248 if ((!got_data || txn != soci::i_ok || meta != soci::i_ok) && !range)
1249 return TxSearched::unknown;
1250
1251 if (!got_data)
1252 {
1253 uint64_t count = 0;
1254 soci::indicator rti;
1255
1256 session
1257 << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
1258 "LedgerSeq BETWEEN "
1259 << range->first() << " AND " << range->last() << ";",
1260 soci::into(count, rti);
1261
1262 if (!session.got_data() || rti != soci::i_ok)
1263 return TxSearched::some;
1264
1265 return count == (range->last() - range->first() + 1)
1267 : TxSearched::some;
1268 }
1269
1270 convert(sociRawTxnBlob, rawTxn);
1271 convert(sociRawMetaBlob, rawMeta);
1272 }
1273
1274 try
1275 {
1276 auto txn =
1277 Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
1278
1279 if (!ledgerSeq)
1280 return std::pair{std::move(txn), nullptr};
1281
1282 std::uint32_t inLedger =
1283 rangeCheckedCast<std::uint32_t>(ledgerSeq.value());
1284
1285 auto txMeta = std::make_shared<TxMeta>(id, inLedger, rawMeta);
1286
1287 return std::pair{std::move(txn), std::move(txMeta)};
1288 }
1289 catch (std::exception& e)
1290 {
1291 JLOG(app.journal("Ledger").warn())
1292 << "Unable to deserialize transaction from raw SQL value. Error: "
1293 << e.what();
1294
1296 }
1297
1298 return TxSearched::unknown;
1299}
1300
1301bool
1302dbHasSpace(soci::session& session, Config const& config, beast::Journal j)
1303{
1304 boost::filesystem::space_info space =
1305 boost::filesystem::space(config.legacy("database_path"));
1306
1307 if (space.available < megabytes(512))
1308 {
1309 JLOG(j.fatal()) << "Remaining free disk space is less than 512MB";
1310 return false;
1311 }
1312
1313 if (config.useTxTables())
1314 {
1315 DatabaseCon::Setup dbSetup = setup_DatabaseCon(config);
1316 boost::filesystem::path dbPath = dbSetup.dataDir / TxDBName;
1317 boost::system::error_code ec;
1319 boost::filesystem::file_size(dbPath, ec);
1320 if (ec)
1321 {
1322 JLOG(j.error())
1323 << "Error checking transaction db file size: " << ec.message();
1324 dbSize.reset();
1325 }
1326
1327 static auto const pageSize = [&] {
1328 std::uint32_t ps;
1329 session << "PRAGMA page_size;", soci::into(ps);
1330 return ps;
1331 }();
1332 static auto const maxPages = [&] {
1333 std::uint32_t mp;
1334 session << "PRAGMA max_page_count;", soci::into(mp);
1335 return mp;
1336 }();
1337 std::uint32_t pageCount;
1338 session << "PRAGMA page_count;", soci::into(pageCount);
1339 std::uint32_t freePages = maxPages - pageCount;
1340 std::uint64_t freeSpace =
1341 safe_cast<std::uint64_t>(freePages) * pageSize;
1342 JLOG(j.info())
1343 << "Transaction DB pathname: " << dbPath.string()
1344 << "; file size: " << dbSize.value_or(-1) << " bytes"
1345 << "; SQLite page size: " << pageSize << " bytes"
1346 << "; Free pages: " << freePages << "; Free space: " << freeSpace
1347 << " bytes; "
1348 << "Note that this does not take into account available disk "
1349 "space.";
1350
1351 if (freeSpace < megabytes(512))
1352 {
1353 JLOG(j.fatal())
1354 << "Free SQLite space for transaction db is less than "
1355 "512MB. To fix this, rippled must be executed with the "
1356 "vacuum parameter before restarting. "
1357 "Note that this activity can take multiple days, "
1358 "depending on database size.";
1359 return false;
1360 }
1361 }
1362
1363 return true;
1364}
1365
1366} // namespace detail
1367} // namespace ripple
T append(T... args)
A generic endpoint for log messages.
Definition Journal.h:60
Stream fatal() const
Definition Journal.h:352
Stream error() const
Definition Journal.h:346
Stream debug() const
Definition Journal.h:328
Stream info() const
Definition Journal.h:334
Stream trace() const
Severity stream access functions.
Definition Journal.h:322
Stream warn() const
Definition Journal.h:340
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:156
bool useTxTables() const
Definition Config.h:342
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:1116
LockedSociSession checkoutDb()
void failedSave(std::uint32_t seq, uint256 const &hash)
std::chrono::time_point< NetClock > time_point
Definition chrono.h:69
std::chrono::duration< rep, period > duration
Definition chrono.h:68
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:342
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:503
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:916
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:176
uint256 getHashByIndex(soci::session &session, LedgerIndex ledgerIndex)
getHashByIndex Returns hash of ledger with given sequence.
Definition Node.cpp:525
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:502
static std::string to_string(TableType type)
to_string Returns the name of a table according to its TableType.
Definition Node.cpp:47
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:1181
std::optional< LedgerInfo > getNewestLedgerInfo(soci::session &session, beast::Journal j)
getNewestLedgerInfo Returns info of newest saved ledger.
Definition Node.cpp:482
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:794
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:1167
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:70
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:147
std::size_t getRows(soci::session &session, TableType type)
getRows Returns number of rows in given table.
Definition Node.cpp:164
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:154
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:191
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:874
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:631
constexpr int TableTypeCount
Definition Node.h:32
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:490
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:974
std::optional< LedgerInfo > getLedgerInfoByIndex(soci::session &session, LedgerIndex ledgerSeq, beast::Journal j)
getLedgerInfoByIndex Returns ledger by its sequence.
Definition Node.cpp:471
bool dbHasSpace(soci::session &session, Config const &config, beast::Journal j)
dbHasSpace Checks if given database has available space.
Definition Node.cpp:1276
std::optional< LedgerInfo > getLedgerInfoByHash(soci::session &session, uint256 const &ledgerHash, beast::Journal j)
getLedgerInfoByHash Returns info of ledger with given hash.
Definition Node.cpp:514
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:698
std::optional< LedgerIndex > getMinLedgerSeq(soci::session &session, TableType type)
getMinLedgerSeq Returns minimum ledger sequence in given table.
Definition Node.cpp:127
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:885
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:984
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:401
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:555
std::optional< LedgerIndex > getMaxLedgerSeq(soci::session &session, TableType type)
getMaxLedgerSeq Returns maximum ledger sequence in given table.
Definition Node.cpp:137
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:1013
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:1195
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:25
constexpr std::array< char const *, 8 > TxDBInit
Definition DBInit.h:72
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::uint32_t LedgerIndex
A ledger index.
Definition Protocol.h:136
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:820
@ rpcDB_DESERIALIZATION
Definition ErrorCodes.h:134
base_uint< 256 > uint256
Definition base_uint.h:558
@ hotLEDGER
Definition NodeObject.h:34
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition SociDB.cpp:157
constexpr auto LgrDBName
Definition DBInit.h:43
@ current
This was a new validation and was added.
constexpr std::array< char const *, 5 > LgrDBInit
Definition DBInit.h:45
constexpr auto kilobytes(T value) noexcept
constexpr auto TxDBName
Definition DBInit.h:70
LedgerHeader LedgerInfo
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition Blob.h:30
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition RangeSet.h:54
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:997
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
Config::StartUpType startUp
Definition DatabaseCon.h:92
std::array< std::string, 4 > txPragma
T to_string(T... args)
T value_or(T... args)
T what(T... args)