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