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/misc/Manifest.h>
26#include <xrpld/app/rdb/RelationalDatabase.h>
27#include <xrpld/app/rdb/backend/detail/Node.h>
28#include <xrpld/core/DatabaseCon.h>
29#include <xrpld/core/SociDB.h>
30#include <xrpl/basics/BasicConfig.h>
31#include <xrpl/basics/StringUtilities.h>
32#include <xrpl/json/to_string.h>
33#include <boost/algorithm/string.hpp>
34#include <boost/range/adaptor/transformed.hpp>
35#include <soci/sqlite3/soci-sqlite3.h>
36
37namespace ripple {
38namespace detail {
39
45static std::string
47{
48 static_assert(
49 TableTypeCount == 3,
50 "Need to modify switch statement if enum is modified");
51
52 switch (type)
53 {
55 return "Ledgers";
57 return "Transactions";
59 return "AccountTransactions";
60 default:
61 UNREACHABLE("ripple::detail::to_string : invalid TableType");
62 return "Unknown";
63 }
64}
65
66DatabasePairValid
68 Config const& config,
69 DatabaseCon::Setup const& setup,
70 DatabaseCon::CheckpointerSetup const& checkpointerSetup,
72{
73 // ledger database
74 auto lgr{std::make_unique<DatabaseCon>(
75 setup, LgrDBName, setup.lgrPragma, LgrDBInit, checkpointerSetup, j)};
76 lgr->getSession() << boost::str(
77 boost::format("PRAGMA cache_size=-%d;") %
79
80 if (config.useTxTables())
81 {
82 // transaction database
83 auto tx{std::make_unique<DatabaseCon>(
84 setup, TxDBName, setup.txPragma, TxDBInit, checkpointerSetup, j)};
85 tx->getSession() << boost::str(
86 boost::format("PRAGMA cache_size=-%d;") %
88
89 if (!setup.standAlone || setup.startUp == Config::LOAD ||
90 setup.startUp == Config::LOAD_FILE ||
91 setup.startUp == Config::REPLAY)
92 {
93 // Check if AccountTransactions has primary key
94 std::string cid, name, type;
95 std::size_t notnull, dflt_value, pk;
96 soci::indicator ind;
97 soci::statement st =
98 (tx->getSession().prepare
99 << ("PRAGMA table_info(AccountTransactions);"),
100 soci::into(cid),
101 soci::into(name),
102 soci::into(type),
103 soci::into(notnull),
104 soci::into(dflt_value, ind),
105 soci::into(pk));
106
107 st.execute();
108 while (st.fetch())
109 {
110 if (pk == 1)
111 {
112 return {std::move(lgr), std::move(tx), false};
113 }
114 }
115 }
116
117 return {std::move(lgr), std::move(tx), true};
118 }
119 else
120 return {std::move(lgr), {}, true};
121}
122
124getMinLedgerSeq(soci::session& session, TableType type)
125{
126 std::string query = "SELECT MIN(LedgerSeq) FROM " + to_string(type) + ";";
127 // SOCI requires boost::optional (not std::optional) as the parameter.
128 boost::optional<LedgerIndex> m;
129 session << query, soci::into(m);
130 return m ? *m : std::optional<LedgerIndex>();
131}
132
134getMaxLedgerSeq(soci::session& session, TableType type)
135{
136 std::string query = "SELECT MAX(LedgerSeq) FROM " + to_string(type) + ";";
137 // SOCI requires boost::optional (not std::optional) as the parameter.
138 boost::optional<LedgerIndex> m;
139 session << query, soci::into(m);
140 return m ? *m : std::optional<LedgerIndex>();
141}
142
143void
144deleteByLedgerSeq(soci::session& session, TableType type, LedgerIndex ledgerSeq)
145{
146 session << "DELETE FROM " << to_string(type)
147 << " WHERE LedgerSeq == " << ledgerSeq << ";";
148}
149
150void
152 soci::session& session,
153 TableType type,
154 LedgerIndex ledgerSeq)
155{
156 session << "DELETE FROM " << to_string(type) << " WHERE LedgerSeq < "
157 << ledgerSeq << ";";
158}
159
161getRows(soci::session& session, TableType type)
162{
163 std::size_t rows;
164 session << "SELECT COUNT(*) AS rows "
165 "FROM "
166 << to_string(type) << ";",
167 soci::into(rows);
168
169 return rows;
170}
171
173getRowsMinMax(soci::session& session, TableType type)
174{
176 session << "SELECT COUNT(*) AS rows, "
177 "MIN(LedgerSeq) AS first, "
178 "MAX(LedgerSeq) AS last "
179 "FROM "
180 << to_string(type) << ";",
181 soci::into(res.numberOfRows), soci::into(res.minLedgerSequence),
182 soci::into(res.maxLedgerSequence);
183
184 return res;
185}
186
187bool
189 DatabaseCon& ldgDB,
190 DatabaseCon& txnDB,
191 Application& app,
192 std::shared_ptr<Ledger const> const& ledger,
193 bool current)
194{
195 auto j = app.journal("Ledger");
196 auto seq = ledger->info().seq;
197
198 // TODO(tom): Fix this hard-coded SQL!
199 JLOG(j.trace()) << "saveValidatedLedger " << (current ? "" : "fromAcquire ")
200 << seq;
201
202 if (!ledger->info().accountHash.isNonZero())
203 {
204 JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}});
205 UNREACHABLE("ripple::detail::saveValidatedLedger : zero account hash");
206 }
207
208 if (ledger->info().accountHash != ledger->stateMap().getHash().as_uint256())
209 {
210 JLOG(j.fatal()) << "sAL: " << ledger->info().accountHash
211 << " != " << ledger->stateMap().getHash();
212 JLOG(j.fatal()) << "saveAcceptedLedger: seq=" << seq
213 << ", current=" << current;
214 UNREACHABLE(
215 "ripple::detail::saveValidatedLedger : mismatched account hash");
216 }
217
218 XRPL_ASSERT(
219 ledger->info().txHash == ledger->txMap().getHash().as_uint256(),
220 "ripple::detail::saveValidatedLedger : transaction hash match");
221
222 // Save the ledger header in the hashed object store
223 {
224 Serializer s(128);
226 addRaw(ledger->info(), s);
227 app.getNodeStore().store(
228 hotLEDGER, std::move(s.modData()), ledger->info().hash, seq);
229 }
230
232 try
233 {
234 aLedger = app.getAcceptedLedgerCache().fetch(ledger->info().hash);
235 if (!aLedger)
236 {
237 aLedger = std::make_shared<AcceptedLedger>(ledger, app);
238 app.getAcceptedLedgerCache().canonicalize_replace_client(
239 ledger->info().hash, aLedger);
240 }
241 }
242 catch (std::exception const&)
243 {
244 JLOG(j.warn()) << "An accepted ledger was missing nodes";
245 app.getLedgerMaster().failedSave(seq, ledger->info().hash);
246 // Clients can now trust the database for information about this
247 // ledger sequence.
248 app.pendingSaves().finishWork(seq);
249 return false;
250 }
251
252 {
253 static boost::format deleteLedger(
254 "DELETE FROM Ledgers WHERE LedgerSeq = %u;");
255 static boost::format deleteTrans1(
256 "DELETE FROM Transactions WHERE LedgerSeq = %u;");
257 static boost::format deleteTrans2(
258 "DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
259 static boost::format deleteAcctTrans(
260 "DELETE FROM AccountTransactions WHERE TransID = '%s';");
261
262 {
263 auto db = ldgDB.checkoutDb();
264 *db << boost::str(deleteLedger % seq);
265 }
266
267 if (app.config().useTxTables())
268 {
269 auto db = txnDB.checkoutDb();
270
271 soci::transaction tr(*db);
272
273 *db << boost::str(deleteTrans1 % seq);
274 *db << boost::str(deleteTrans2 % seq);
275
276 std::string const ledgerSeq(std::to_string(seq));
277
278 for (auto const& acceptedLedgerTx : *aLedger)
279 {
280 uint256 transactionID = acceptedLedgerTx->getTransactionID();
281
282 std::string const txnId(to_string(transactionID));
283 std::string const txnSeq(
284 std::to_string(acceptedLedgerTx->getTxnSeq()));
285
286 *db << boost::str(deleteAcctTrans % transactionID);
287
288 auto const& accts = acceptedLedgerTx->getAffected();
289
290 if (!accts.empty())
291 {
292 std::string sql(
293 "INSERT INTO AccountTransactions "
294 "(TransID, Account, LedgerSeq, TxnSeq) VALUES ");
295
296 // Try to make an educated guess on how much space we'll
297 // need for our arguments. In argument order we have: 64
298 // + 34 + 10 + 10 = 118 + 10 extra = 128 bytes
299 sql.reserve(sql.length() + (accts.size() * 128));
300
301 bool first = true;
302 for (auto const& account : accts)
303 {
304 if (!first)
305 sql += ", ('";
306 else
307 {
308 sql += "('";
309 first = false;
310 }
311
312 sql += txnId;
313 sql += "','";
314 sql += toBase58(account);
315 sql += "',";
316 sql += ledgerSeq;
317 sql += ",";
318 sql += txnSeq;
319 sql += ")";
320 }
321 sql += ";";
322 JLOG(j.trace()) << "ActTx: " << sql;
323 *db << sql;
324 }
325 else if (auto const& sleTxn = acceptedLedgerTx->getTxn();
326 !isPseudoTx(*sleTxn))
327 {
328 // It's okay for pseudo transactions to not affect any
329 // accounts. But otherwise...
330 JLOG(j.warn()) << "Transaction in ledger " << seq
331 << " affects no accounts";
332 JLOG(j.warn()) << sleTxn->getJson(JsonOptions::none);
333 }
334
335 *db
337 acceptedLedgerTx->getTxn()->getMetaSQL(
338 seq, acceptedLedgerTx->getEscMeta()) +
339 ";");
340
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,
857 std::make_shared<TxMeta>(
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 const char* 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 const char* const compare = forward ? ">=" : "<=";
1073 const std::uint32_t minLedger =
1074 forward ? findLedger + 1 : options.minLedger;
1075 const std::uint32_t 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)
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:59
Stream fatal() const
Definition: Journal.h:341
Stream error() const
Definition: Journal.h:335
Stream debug() const
Definition: Journal.h:317
Stream info() const
Definition: Journal.h:323
Stream trace() const
Severity stream access functions.
Definition: Journal.h:311
Stream warn() const
Definition: Journal.h:329
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
bool useTxTables() const
Definition: Config.h:350
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:1077
LockedSociSession checkoutDb()
Definition: DatabaseCon.h:188
void failedSave(std::uint32_t seq, uint256 const &hash)
std::chrono::time_point< NetClock > time_point
Definition: chrono.h:70
std::chrono::duration< rep, period > duration
Definition: chrono.h:69
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.
Definition: PendingSaves.h:74
std::vector< AccountTx > AccountTxs
static std::string const & getMetaSQLInsertReplaceHeader()
Definition: STTx.cpp:270
bool inLedger(uint256 const &hash, std::uint32_t ledger)
static Transaction::pointer transactionFromSQL(boost::optional< std::uint64_t > const &ledgerSeq, boost::optional< std::string > const &status, Blob const &rawTxn, Application &app)
Definition: Transaction.cpp:93
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:502
T emplace_back(T... args)
T empty(T... args)
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:173
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:46
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:67
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:144
std::size_t getRows(soci::session &session, TableType type)
getRows Returns number of rows in given table.
Definition: Node.cpp:161
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:151
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:188
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
constexpr int TableTypeCount
Definition: Node.h:36
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:124
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:134
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:26
constexpr std::array< char const *, 8 > TxDBInit
Definition: DBInit.h:72
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:106
std::uint32_t LedgerIndex
A ledger index.
Definition: Protocol.h:119
constexpr auto megabytes(T value) noexcept
Definition: ByteUtilities.h:34
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:613
error_code_i
Definition: ErrorCodes.h:40
@ rpcDB_DESERIALIZATION
Definition: ErrorCodes.h:134
base_uint< 256 > uint256
Definition: base_uint.h:557
@ hotLEDGER
Definition: NodeObject.h:34
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition: SociDB.cpp:154
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
Definition: ByteUtilities.h:27
constexpr auto TxDBName
Definition: DBInit.h:70
LedgerHeader LedgerInfo
Definition: LedgerHeader.h:79
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:1002
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:110
Config::StartUpType startUp
Definition: DatabaseCon.h:90
std::array< std::string, 4 > txPragma
Definition: DatabaseCon.h:109
T to_string(T... args)
T value_or(T... args)
T what(T... args)