rippled
Loading...
Searching...
No Matches
Node.cpp
1#include <xrpld/app/ledger/AcceptedLedger.h>
2#include <xrpld/app/ledger/LedgerMaster.h>
3#include <xrpld/app/ledger/LedgerToJson.h>
4#include <xrpld/app/ledger/PendingSaves.h>
5#include <xrpld/app/ledger/TransactionMaster.h>
6#include <xrpld/app/rdb/RelationalDatabase.h>
7#include <xrpld/app/rdb/backend/detail/Node.h>
8#include <xrpld/core/DatabaseCon.h>
9#include <xrpld/core/SociDB.h>
10
11#include <xrpl/basics/BasicConfig.h>
12#include <xrpl/basics/StringUtilities.h>
13#include <xrpl/json/to_string.h>
14
15#include <boost/range/adaptor/transformed.hpp>
16
17#include <soci/sqlite3/soci-sqlite3.h>
18
19namespace xrpl {
20namespace detail {
21
27static std::string
29{
30 static_assert(TableTypeCount == 3, "Need to modify switch statement if enum is modified");
31
32 switch (type)
33 {
35 return "Ledgers";
37 return "Transactions";
39 return "AccountTransactions";
40 // LCOV_EXCL_START
41 default:
42 UNREACHABLE("xrpl::detail::to_string : invalid TableType");
43 return "Unknown";
44 // LCOV_EXCL_STOP
45 }
46}
47
48DatabasePairValid
50 Config const& config,
51 DatabaseCon::Setup const& setup,
52 DatabaseCon::CheckpointerSetup const& checkpointerSetup,
54{
55 // ledger database
56 auto lgr{std::make_unique<DatabaseCon>(setup, LgrDBName, setup.lgrPragma, LgrDBInit, checkpointerSetup, j)};
57 lgr->getSession() << boost::str(
58 boost::format("PRAGMA cache_size=-%d;") % kilobytes(config.getValueFor(SizedItem::lgrDBCache)));
59
60 if (config.useTxTables())
61 {
62 // transaction database
63 auto tx{std::make_unique<DatabaseCon>(setup, TxDBName, setup.txPragma, TxDBInit, checkpointerSetup, j)};
64 tx->getSession() << boost::str(
65 boost::format("PRAGMA cache_size=-%d;") % kilobytes(config.getValueFor(SizedItem::txnDBCache)));
66
67 if (!setup.standAlone || setup.startUp == Config::LOAD || setup.startUp == Config::LOAD_FILE ||
68 setup.startUp == Config::REPLAY)
69 {
70 // Check if AccountTransactions has primary key
71 std::string cid, name, type;
72 std::size_t notnull, dflt_value, pk;
73 soci::indicator ind;
74 soci::statement st =
75 (tx->getSession().prepare << ("PRAGMA table_info(AccountTransactions);"),
76 soci::into(cid),
77 soci::into(name),
78 soci::into(type),
79 soci::into(notnull),
80 soci::into(dflt_value, ind),
81 soci::into(pk));
82
83 st.execute();
84 while (st.fetch())
85 {
86 if (pk == 1)
87 {
88 return {std::move(lgr), std::move(tx), false};
89 }
90 }
91 }
92
93 return {std::move(lgr), std::move(tx), true};
94 }
95 else
96 return {std::move(lgr), {}, true};
97}
98
100getMinLedgerSeq(soci::session& session, TableType type)
101{
102 std::string query = "SELECT MIN(LedgerSeq) FROM " + to_string(type) + ";";
103 // SOCI requires boost::optional (not std::optional) as the parameter.
104 boost::optional<LedgerIndex> m;
105 session << query, soci::into(m);
106 return m ? *m : std::optional<LedgerIndex>();
107}
108
110getMaxLedgerSeq(soci::session& session, TableType type)
111{
112 std::string query = "SELECT MAX(LedgerSeq) FROM " + to_string(type) + ";";
113 // SOCI requires boost::optional (not std::optional) as the parameter.
114 boost::optional<LedgerIndex> m;
115 session << query, soci::into(m);
116 return m ? *m : std::optional<LedgerIndex>();
117}
118
119void
120deleteByLedgerSeq(soci::session& session, TableType type, LedgerIndex ledgerSeq)
121{
122 session << "DELETE FROM " << to_string(type) << " WHERE LedgerSeq == " << ledgerSeq << ";";
123}
124
125void
126deleteBeforeLedgerSeq(soci::session& session, TableType type, LedgerIndex ledgerSeq)
127{
128 session << "DELETE FROM " << to_string(type) << " WHERE LedgerSeq < " << ledgerSeq << ";";
129}
130
132getRows(soci::session& session, TableType type)
133{
134 std::size_t rows;
135 session << "SELECT COUNT(*) AS rows "
136 "FROM "
137 << to_string(type) << ";",
138 soci::into(rows);
139
140 return rows;
141}
142
144getRowsMinMax(soci::session& session, TableType type)
145{
147 session << "SELECT COUNT(*) AS rows, "
148 "MIN(LedgerSeq) AS first, "
149 "MAX(LedgerSeq) AS last "
150 "FROM "
151 << to_string(type) << ";",
152 soci::into(res.numberOfRows), soci::into(res.minLedgerSequence), soci::into(res.maxLedgerSequence);
153
154 return res;
155}
156
157bool
159 DatabaseCon& ldgDB,
160 std::unique_ptr<DatabaseCon> const& txnDB,
161 Application& app,
162 std::shared_ptr<Ledger const> const& ledger,
163 bool current)
164{
165 auto j = app.journal("Ledger");
166 auto seq = ledger->header().seq;
167
168 // TODO(tom): Fix this hard-coded SQL!
169 JLOG(j.trace()) << "saveValidatedLedger " << (current ? "" : "fromAcquire ") << seq;
170
171 if (!ledger->header().accountHash.isNonZero())
172 {
173 // LCOV_EXCL_START
174 JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}});
175 UNREACHABLE("xrpl::detail::saveValidatedLedger : zero account hash");
176 // LCOV_EXCL_STOP
177 }
178
179 if (ledger->header().accountHash != ledger->stateMap().getHash().as_uint256())
180 {
181 // LCOV_EXCL_START
182 JLOG(j.fatal()) << "sAL: " << ledger->header().accountHash << " != " << ledger->stateMap().getHash();
183 JLOG(j.fatal()) << "saveAcceptedLedger: seq=" << seq << ", current=" << current;
184 UNREACHABLE("xrpl::detail::saveValidatedLedger : mismatched account hash");
185 // LCOV_EXCL_STOP
186 }
187
188 XRPL_ASSERT(
189 ledger->header().txHash == ledger->txMap().getHash().as_uint256(),
190 "xrpl::detail::saveValidatedLedger : transaction hash match");
191
192 // Save the ledger header in the hashed object store
193 {
194 Serializer s(128);
196 addRaw(ledger->header(), s);
197 app.getNodeStore().store(hotLEDGER, std::move(s.modData()), ledger->header().hash, seq);
198 }
199
201 try
202 {
203 aLedger = app.getAcceptedLedgerCache().fetch(ledger->header().hash);
204 if (!aLedger)
205 {
206 aLedger = std::make_shared<AcceptedLedger>(ledger, app);
207 app.getAcceptedLedgerCache().canonicalize_replace_client(ledger->header().hash, aLedger);
208 }
209 }
210 catch (std::exception const&)
211 {
212 JLOG(j.warn()) << "An accepted ledger was missing nodes";
213 app.getLedgerMaster().failedSave(seq, ledger->header().hash);
214 // Clients can now trust the database for information about this
215 // ledger sequence.
216 app.pendingSaves().finishWork(seq);
217 return false;
218 }
219
220 {
221 static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %u;");
222 static boost::format deleteTrans1("DELETE FROM Transactions WHERE LedgerSeq = %u;");
223 static boost::format deleteTrans2("DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
224 static boost::format deleteAcctTrans("DELETE FROM AccountTransactions WHERE TransID = '%s';");
225
226 {
227 auto db = ldgDB.checkoutDb();
228 *db << boost::str(deleteLedger % seq);
229 }
230
231 if (app.config().useTxTables())
232 {
233 if (!txnDB)
234 {
235 // LCOV_EXCL_START
236 JLOG(j.fatal()) << "TxTables db isn't available";
237 Throw<std::runtime_error>("TxTables db isn't available");
238 // LCOV_EXCL_STOP
239 }
240
241 auto db = txnDB->checkoutDb();
242
243 soci::transaction tr(*db);
244
245 *db << boost::str(deleteTrans1 % seq);
246 *db << boost::str(deleteTrans2 % seq);
247
248 std::string const ledgerSeq(std::to_string(seq));
249
250 for (auto const& acceptedLedgerTx : *aLedger)
251 {
252 uint256 transactionID = acceptedLedgerTx->getTransactionID();
253
254 std::string const txnId(to_string(transactionID));
255 std::string const txnSeq(std::to_string(acceptedLedgerTx->getTxnSeq()));
256
257 *db << boost::str(deleteAcctTrans % transactionID);
258
259 auto const& accts = acceptedLedgerTx->getAffected();
260
261 if (!accts.empty())
262 {
263 std::string sql(
264 "INSERT INTO AccountTransactions "
265 "(TransID, Account, LedgerSeq, TxnSeq) VALUES ");
266
267 // Try to make an educated guess on how much space we'll
268 // need for our arguments. In argument order we have: 64
269 // + 34 + 10 + 10 = 118 + 10 extra = 128 bytes
270 sql.reserve(sql.length() + (accts.size() * 128));
271
272 bool first = true;
273 for (auto const& account : accts)
274 {
275 if (!first)
276 sql += ", ('";
277 else
278 {
279 sql += "('";
280 first = false;
281 }
282
283 sql += txnId;
284 sql += "','";
285 sql += toBase58(account);
286 sql += "',";
287 sql += ledgerSeq;
288 sql += ",";
289 sql += txnSeq;
290 sql += ")";
291 }
292 sql += ";";
293 JLOG(j.trace()) << "ActTx: " << sql;
294 *db << sql;
295 }
296 else if (auto const& sleTxn = acceptedLedgerTx->getTxn(); !isPseudoTx(*sleTxn))
297 {
298 // It's okay for pseudo transactions to not affect any
299 // accounts. But otherwise...
300 JLOG(j.warn()) << "Transaction in ledger " << seq << " affects no accounts";
301 JLOG(j.warn()) << sleTxn->getJson(JsonOptions::none);
302 }
303
304 *db
306 acceptedLedgerTx->getTxn()->getMetaSQL(seq, acceptedLedgerTx->getEscMeta()) + ";");
307
309 transactionID, seq, acceptedLedgerTx->getTxnSeq(), app.config().NETWORK_ID);
310 }
311
312 tr.commit();
313 }
314
315 {
316 static std::string addLedger(
317 R"sql(INSERT OR REPLACE INTO Ledgers
318 (LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,
319 CloseTimeRes,CloseFlags,AccountSetHash,TransSetHash)
320 VALUES
321 (:ledgerHash,:ledgerSeq,:prevHash,:totalCoins,:closingTime,:prevClosingTime,
322 :closeTimeRes,:closeFlags,:accountSetHash,:transSetHash);)sql");
323
324 auto db(ldgDB.checkoutDb());
325
326 soci::transaction tr(*db);
327
328 auto const hash = to_string(ledger->header().hash);
329 auto const parentHash = to_string(ledger->header().parentHash);
330 auto const drops = to_string(ledger->header().drops);
331 auto const closeTime = ledger->header().closeTime.time_since_epoch().count();
332 auto const parentCloseTime = ledger->header().parentCloseTime.time_since_epoch().count();
333 auto const closeTimeResolution = ledger->header().closeTimeResolution.count();
334 auto const closeFlags = ledger->header().closeFlags;
335 auto const accountHash = to_string(ledger->header().accountHash);
336 auto const txHash = to_string(ledger->header().txHash);
337
338 *db << addLedger, soci::use(hash), soci::use(seq), soci::use(parentHash), soci::use(drops),
339 soci::use(closeTime), soci::use(parentCloseTime), soci::use(closeTimeResolution), soci::use(closeFlags),
340 soci::use(accountHash), soci::use(txHash);
341
342 tr.commit();
343 }
344 }
345
346 return true;
347}
348
358getLedgerInfo(soci::session& session, std::string const& sqlSuffix, beast::Journal j)
359{
360 // SOCI requires boost::optional (not std::optional) as parameters.
361 boost::optional<std::string> hash, parentHash, accountHash, txHash;
362 boost::optional<std::uint64_t> seq, drops, closeTime, parentCloseTime, closeTimeResolution, closeFlags;
363
364 std::string const sql =
365 "SELECT "
366 "LedgerHash, PrevHash, AccountSetHash, TransSetHash, "
367 "TotalCoins,"
368 "ClosingTime, PrevClosingTime, CloseTimeRes, CloseFlags,"
369 "LedgerSeq FROM Ledgers " +
370 sqlSuffix + ";";
371
372 session << sql, soci::into(hash), soci::into(parentHash), soci::into(accountHash), soci::into(txHash),
373 soci::into(drops), soci::into(closeTime), soci::into(parentCloseTime), soci::into(closeTimeResolution),
374 soci::into(closeFlags), soci::into(seq);
375
376 if (!session.got_data())
377 {
378 JLOG(j.debug()) << "Ledger not found: " << sqlSuffix;
379 return {};
380 }
381
382 using time_point = NetClock::time_point;
383 using duration = NetClock::duration;
384
385 LedgerHeader info;
386
387 if (hash && !info.hash.parseHex(*hash))
388 {
389 JLOG(j.debug()) << "Hash parse error for ledger: " << sqlSuffix;
390 return {};
391 }
392
393 if (parentHash && !info.parentHash.parseHex(*parentHash))
394 {
395 JLOG(j.debug()) << "parentHash parse error for ledger: " << sqlSuffix;
396 return {};
397 }
398
399 if (accountHash && !info.accountHash.parseHex(*accountHash))
400 {
401 JLOG(j.debug()) << "accountHash parse error for ledger: " << sqlSuffix;
402 return {};
403 }
404
405 if (txHash && !info.txHash.parseHex(*txHash))
406 {
407 JLOG(j.debug()) << "txHash parse error for ledger: " << sqlSuffix;
408 return {};
409 }
410
411 info.seq = rangeCheckedCast<std::uint32_t>(seq.value_or(0));
412 info.drops = drops.value_or(0);
413 info.closeTime = time_point{duration{closeTime.value_or(0)}};
414 info.parentCloseTime = time_point{duration{parentCloseTime.value_or(0)}};
415 info.closeFlags = closeFlags.value_or(0);
416 info.closeTimeResolution = duration{closeTimeResolution.value_or(0)};
418 return info;
419}
420
422getLedgerInfoByIndex(soci::session& session, LedgerIndex ledgerSeq, beast::Journal j)
423{
425 s << "WHERE LedgerSeq = " << ledgerSeq;
426 return getLedgerInfo(session, s.str(), j);
427}
428
430getNewestLedgerInfo(soci::session& session, beast::Journal j)
431{
433 s << "ORDER BY LedgerSeq DESC LIMIT 1";
434 return getLedgerInfo(session, s.str(), j);
435}
436
438getLimitedOldestLedgerInfo(soci::session& session, LedgerIndex ledgerFirstIndex, beast::Journal j)
439{
441 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) + " ORDER BY LedgerSeq ASC LIMIT 1";
442 return getLedgerInfo(session, s.str(), j);
443}
444
446getLimitedNewestLedgerInfo(soci::session& session, LedgerIndex ledgerFirstIndex, beast::Journal j)
447{
449 s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) + " ORDER BY LedgerSeq DESC LIMIT 1";
450 return getLedgerInfo(session, s.str(), j);
451}
452
454getLedgerInfoByHash(soci::session& session, uint256 const& ledgerHash, beast::Journal j)
455{
457 s << "WHERE LedgerHash = '" << ledgerHash << "'";
458 return getLedgerInfo(session, s.str(), j);
459}
460
462getHashByIndex(soci::session& session, LedgerIndex ledgerIndex)
463{
464 uint256 ret;
465
466 std::string sql = "SELECT LedgerHash FROM Ledgers INDEXED BY SeqLedger WHERE LedgerSeq='";
467 sql.append(std::to_string(ledgerIndex));
468 sql.append("';");
469
470 std::string hash;
471 {
472 // SOCI requires boost::optional (not std::optional) as the parameter.
473 boost::optional<std::string> lh;
474 session << sql, soci::into(lh);
475
476 if (!session.got_data() || !lh)
477 return ret;
478
479 hash = *lh;
480 if (hash.empty())
481 return ret;
482 }
483
484 if (!ret.parseHex(hash))
485 return ret;
487 return ret;
488}
489
491getHashesByIndex(soci::session& session, LedgerIndex ledgerIndex, beast::Journal j)
492{
493 // SOCI requires boost::optional (not std::optional) as the parameter.
494 boost::optional<std::string> lhO, phO;
495
496 session << "SELECT LedgerHash,PrevHash FROM Ledgers "
497 "INDEXED BY SeqLedger WHERE LedgerSeq = :ls;",
498 soci::into(lhO), soci::into(phO), soci::use(ledgerIndex);
499
500 if (!lhO || !phO)
501 {
502 auto stream = j.trace();
503 JLOG(stream) << "Don't have ledger " << ledgerIndex;
504 return {};
505 }
506
507 LedgerHashPair hashes;
508 if (!hashes.ledgerHash.parseHex(*lhO) || !hashes.parentHash.parseHex(*phO))
509 {
510 auto stream = j.trace();
511 JLOG(stream) << "Error parse hashes for ledger " << ledgerIndex;
512 return {};
513 }
515 return hashes;
516}
517
519getHashesByIndex(soci::session& session, LedgerIndex minSeq, LedgerIndex maxSeq, beast::Journal j)
520{
521 std::string sql = "SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq >= ";
522 sql.append(std::to_string(minSeq));
523 sql.append(" AND LedgerSeq <= ");
524 sql.append(std::to_string(maxSeq));
525 sql.append(";");
526
527 std::uint64_t ls;
528 std::string lh;
529 // SOCI requires boost::optional (not std::optional) as the parameter.
530 boost::optional<std::string> ph;
531 soci::statement st = (session.prepare << sql, soci::into(ls), soci::into(lh), soci::into(ph));
532
533 st.execute();
535 while (st.fetch())
536 {
537 LedgerHashPair& hashes = res[rangeCheckedCast<LedgerIndex>(ls)];
538 if (!hashes.ledgerHash.parseHex(lh))
539 {
540 JLOG(j.warn()) << "Error parsed hash for ledger seq: " << ls;
541 }
542 if (!ph)
543 {
544 JLOG(j.warn()) << "Null prev hash for ledger seq: " << ls;
545 }
546 else if (!hashes.parentHash.parseHex(*ph))
547 {
548 JLOG(j.warn()) << "Error parsed prev hash for ledger seq: " << ls;
549 }
551 return res;
552}
553
555getTxHistory(soci::session& session, Application& app, LedgerIndex startIndex, int quantity)
556{
557 std::string sql = boost::str(
558 boost::format("SELECT LedgerSeq, Status, RawTxn "
559 "FROM Transactions ORDER BY LedgerSeq DESC LIMIT %u,%u;") %
560 startIndex % quantity);
561
563 int total = 0;
564
565 {
566 // SOCI requires boost::optional (not std::optional) as parameters.
567 boost::optional<std::uint64_t> ledgerSeq;
568 boost::optional<std::string> status;
569 soci::blob sociRawTxnBlob(session);
570 soci::indicator rti;
571 Blob rawTxn;
572
573 soci::statement st =
574 (session.prepare << sql, soci::into(ledgerSeq), soci::into(status), soci::into(sociRawTxnBlob, rti));
575
576 st.execute();
577 while (st.fetch())
578 {
579 if (soci::i_ok == rti)
580 convert(sociRawTxnBlob, rawTxn);
581 else
582 rawTxn.clear();
583
584 if (auto trans = Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app))
585 {
586 total++;
587 txs.push_back(trans);
588 }
589 }
590 }
591
592 return {txs, total};
593}
594
612static std::string
614 Application& app,
615 std::string selection,
616 RelationalDatabase::AccountTxOptions const& options,
617 bool descending,
618 bool binary,
619 bool count,
621{
622 constexpr std::uint32_t NONBINARY_PAGE_LENGTH = 200;
623 constexpr std::uint32_t BINARY_PAGE_LENGTH = 500;
624
625 std::uint32_t numberOfResults;
626
627 if (count)
628 {
629 numberOfResults = std::numeric_limits<std::uint32_t>::max();
630 }
631 else if (options.limit == UINT32_MAX)
632 {
633 numberOfResults = binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH;
634 }
635 else if (!options.bUnlimited)
636 {
637 numberOfResults = std::min(binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH, options.limit);
638 }
639 else
640 {
641 numberOfResults = options.limit;
642 }
643
644 std::string maxClause = "";
645 std::string minClause = "";
646
647 if (options.maxLedger)
648 {
649 maxClause = boost::str(boost::format("AND AccountTransactions.LedgerSeq <= '%u'") % options.maxLedger);
650 }
651
652 if (options.minLedger)
653 {
654 minClause = boost::str(boost::format("AND AccountTransactions.LedgerSeq >= '%u'") % options.minLedger);
655 }
656
657 std::string sql;
658
659 if (count)
660 sql = boost::str(
661 boost::format("SELECT %s FROM AccountTransactions "
662 "WHERE Account = '%s' %s %s LIMIT %u, %u;") %
663 selection % toBase58(options.account) % maxClause % minClause % options.offset % numberOfResults);
664 else
665 sql = boost::str(
666 boost::format("SELECT %s FROM "
667 "AccountTransactions INNER JOIN Transactions "
668 "ON Transactions.TransID = AccountTransactions.TransID "
669 "WHERE Account = '%s' %s %s "
670 "ORDER BY AccountTransactions.LedgerSeq %s, "
671 "AccountTransactions.TxnSeq %s, AccountTransactions.TransID %s "
672 "LIMIT %u, %u;") %
673 selection % toBase58(options.account) % maxClause % minClause % (descending ? "DESC" : "ASC") %
674 (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") % options.offset % numberOfResults);
675 JLOG(j.trace()) << "txSQL query: " << sql;
676 return sql;
677}
678
702 soci::session& session,
703 Application& app,
704 LedgerMaster& ledgerMaster,
705 RelationalDatabase::AccountTxOptions const& options,
706 bool descending,
708{
710
712 app, "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta", options, descending, false, false, j);
713 if (sql == "")
714 return {ret, 0};
715
716 int total = 0;
717 {
718 // SOCI requires boost::optional (not std::optional) as parameters.
719 boost::optional<std::uint64_t> ledgerSeq;
720 boost::optional<std::string> status;
721 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
722 soci::indicator rti, tmi;
723 Blob rawTxn, txnMeta;
724
725 soci::statement st =
726 (session.prepare << sql,
727 soci::into(ledgerSeq),
728 soci::into(status),
729 soci::into(sociTxnBlob, rti),
730 soci::into(sociTxnMetaBlob, tmi));
731
732 st.execute();
733 while (st.fetch())
734 {
735 if (soci::i_ok == rti)
736 convert(sociTxnBlob, rawTxn);
737 else
738 rawTxn.clear();
739
740 if (soci::i_ok == tmi)
741 convert(sociTxnMetaBlob, txnMeta);
742 else
743 txnMeta.clear();
744
745 auto txn = Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
746
747 if (txnMeta.empty())
748 { // Work around a bug that could leave the metadata missing
749 auto const seq = rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
750
751 JLOG(j.warn()) << "Recovering ledger " << seq << ", txn " << txn->getID();
752
753 if (auto l = ledgerMaster.getLedgerBySeq(seq))
754 pendSaveValidated(app, l, false, false);
755 }
756
757 if (txn)
758 {
759 ret.emplace_back(txn, std::make_shared<TxMeta>(txn->getID(), txn->getLedger(), txnMeta));
760 total++;
761 }
762 }
763 }
765 return {ret, total};
766}
767
770 soci::session& session,
771 Application& app,
772 LedgerMaster& ledgerMaster,
773 RelationalDatabase::AccountTxOptions const& options,
776 return getAccountTxs(session, app, ledgerMaster, options, false, j);
777}
778
781 soci::session& session,
782 Application& app,
786{
787 return getAccountTxs(session, app, ledgerMaster, options, true, j);
788}
789
812 soci::session& session,
813 Application& app,
814 RelationalDatabase::AccountTxOptions const& options,
815 bool descending,
817{
819
821 app, "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta", options, descending, true /*binary*/, false, j);
822 if (sql == "")
823 return {ret, 0};
824
825 int total = 0;
826
827 {
828 // SOCI requires boost::optional (not std::optional) as parameters.
829 boost::optional<std::uint64_t> ledgerSeq;
830 boost::optional<std::string> status;
831 soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
832 soci::indicator rti, tmi;
833
834 soci::statement st =
835 (session.prepare << sql,
836 soci::into(ledgerSeq),
837 soci::into(status),
838 soci::into(sociTxnBlob, rti),
839 soci::into(sociTxnMetaBlob, tmi));
840
841 st.execute();
842 while (st.fetch())
843 {
844 Blob rawTxn;
845 if (soci::i_ok == rti)
846 convert(sociTxnBlob, rawTxn);
847 Blob txnMeta;
848 if (soci::i_ok == tmi)
849 convert(sociTxnMetaBlob, txnMeta);
850
851 auto const seq = rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
852
853 ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq);
854 total++;
855 }
856 }
858 return {ret, total};
859}
860
863 soci::session& session,
864 Application& app,
865 RelationalDatabase::AccountTxOptions const& options,
868 return getAccountTxsB(session, app, options, false, j);
869}
870
873 soci::session& session,
874 Application& app,
877{
878 return getAccountTxsB(session, app, options, true, j);
879}
880
902 soci::session& session,
903 std::function<void(std::uint32_t)> const& onUnsavedLedger,
904 std::function<void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction,
905 RelationalDatabase::AccountTxPageOptions const& options,
906 std::uint32_t page_length,
907 bool forward)
908{
909 int total = 0;
910
911 bool lookingForMarker = options.marker.has_value();
912
913 std::uint32_t numberOfResults;
914
915 if (options.limit == 0 || options.limit == UINT32_MAX || (options.limit > page_length && !options.bAdmin))
916 numberOfResults = page_length;
917 else
918 numberOfResults = options.limit;
919
920 // As an account can have many thousands of transactions, there is a limit
921 // placed on the amount of transactions returned. If the limit is reached
922 // before the result set has been exhausted (we always query for one more
923 // than the limit), then we return an opaque marker that can be supplied in
924 // a subsequent query.
925 std::uint32_t queryLimit = numberOfResults + 1;
926 std::uint32_t findLedger = 0, findSeq = 0;
927
928 if (lookingForMarker)
929 {
930 findLedger = options.marker->ledgerSeq;
931 findSeq = options.marker->txnSeq;
932 }
933
935
936 static std::string const prefix(
937 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
938 Status,RawTxn,TxnMeta
939 FROM AccountTransactions INNER JOIN Transactions
940 ON Transactions.TransID = AccountTransactions.TransID
941 AND AccountTransactions.Account = '%s' WHERE
942 )");
943
944 std::string sql;
945
946 // SQL's BETWEEN uses a closed interval ([a,b])
947
948 char const* const order = forward ? "ASC" : "DESC";
949
950 if (findLedger == 0)
951 {
952 sql = boost::str(
953 boost::format(prefix + (R"(AccountTransactions.LedgerSeq BETWEEN %u AND %u
954 ORDER BY AccountTransactions.LedgerSeq %s,
955 AccountTransactions.TxnSeq %s
956 LIMIT %u;)")) %
957 toBase58(options.account) % options.minLedger % options.maxLedger % order % order % queryLimit);
958 }
959 else
960 {
961 char const* const compare = forward ? ">=" : "<=";
962 std::uint32_t const minLedger = forward ? findLedger + 1 : options.minLedger;
963 std::uint32_t const maxLedger = forward ? options.maxLedger : findLedger - 1;
964
965 auto b58acct = toBase58(options.account);
966 sql = boost::str(
967 boost::format((
968 R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
969 Status,RawTxn,TxnMeta
970 FROM AccountTransactions, Transactions WHERE
971 (AccountTransactions.TransID = Transactions.TransID AND
972 AccountTransactions.Account = '%s' AND
973 AccountTransactions.LedgerSeq BETWEEN %u AND %u)
974 UNION
975 SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,Status,RawTxn,TxnMeta
976 FROM AccountTransactions, Transactions WHERE
977 (AccountTransactions.TransID = Transactions.TransID AND
978 AccountTransactions.Account = '%s' AND
979 AccountTransactions.LedgerSeq = %u AND
980 AccountTransactions.TxnSeq %s %u)
981 ORDER BY AccountTransactions.LedgerSeq %s,
982 AccountTransactions.TxnSeq %s
983 LIMIT %u;
984 )")) %
985 b58acct % minLedger % maxLedger % b58acct % findLedger % compare % findSeq % order % order % queryLimit);
986 }
987
988 {
989 Blob rawData;
990 Blob rawMeta;
991
992 // SOCI requires boost::optional (not std::optional) as parameters.
993 boost::optional<std::uint64_t> ledgerSeq;
994 boost::optional<std::uint32_t> txnSeq;
995 boost::optional<std::string> status;
996 soci::blob txnData(session);
997 soci::blob txnMeta(session);
998 soci::indicator dataPresent, metaPresent;
999
1000 soci::statement st =
1001 (session.prepare << sql,
1002 soci::into(ledgerSeq),
1003 soci::into(txnSeq),
1004 soci::into(status),
1005 soci::into(txnData, dataPresent),
1006 soci::into(txnMeta, metaPresent));
1007
1008 st.execute();
1009
1010 while (st.fetch())
1011 {
1012 if (lookingForMarker)
1013 {
1014 if (findLedger == ledgerSeq.value_or(0) && findSeq == txnSeq.value_or(0))
1015 {
1016 lookingForMarker = false;
1017 }
1018 else
1019 continue;
1020 }
1021 else if (numberOfResults == 0)
1022 {
1023 newmarker = {rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)), txnSeq.value_or(0)};
1024 break;
1025 }
1026
1027 if (dataPresent == soci::i_ok)
1028 convert(txnData, rawData);
1029 else
1030 rawData.clear();
1031
1032 if (metaPresent == soci::i_ok)
1033 convert(txnMeta, rawMeta);
1034 else
1035 rawMeta.clear();
1036
1037 // Work around a bug that could leave the metadata missing
1038 if (rawMeta.size() == 0)
1039 onUnsavedLedger(ledgerSeq.value_or(0));
1040
1041 // `rawData` and `rawMeta` will be used after they are moved.
1042 // That's OK.
1043 onTransaction(
1044 rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1045 *status,
1046 std::move(rawData),
1047 std::move(rawMeta));
1048 // Note some callbacks will move the data, some will not. Clear
1049 // them so code doesn't depend on if the data was actually moved
1050 // or not. The code will be more efficient if `rawData` and
1051 // `rawMeta` don't have to allocate in `convert`, so don't
1052 // refactor my moving these variables into loop scope.
1053 rawData.clear();
1054 rawMeta.clear();
1055
1056 --numberOfResults;
1057 total++;
1058 }
1059 }
1060
1061 return {newmarker, total};
1062}
1063
1066 soci::session& session,
1067 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1068 std::function<void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction,
1069 RelationalDatabase::AccountTxPageOptions const& options,
1070 std::uint32_t page_length)
1071{
1072 return accountTxPage(session, onUnsavedLedger, onTransaction, options, page_length, true);
1073}
1074
1077 soci::session& session,
1078 std::function<void(std::uint32_t)> const& onUnsavedLedger,
1079 std::function<void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const& onTransaction,
1080 RelationalDatabase::AccountTxPageOptions const& options,
1081 std::uint32_t page_length)
1082{
1083 return accountTxPage(session, onUnsavedLedger, onTransaction, options, page_length, false);
1084}
1085
1088 soci::session& session,
1089 Application& app,
1090 uint256 const& id,
1091 std::optional<ClosedInterval<uint32_t>> const& range,
1092 error_code_i& ec)
1093{
1094 std::string sql =
1095 "SELECT LedgerSeq,Status,RawTxn,TxnMeta "
1096 "FROM Transactions WHERE TransID='";
1097
1098 sql.append(to_string(id));
1099 sql.append("';");
1100
1101 // SOCI requires boost::optional (not std::optional) as parameters.
1102 boost::optional<std::uint64_t> ledgerSeq;
1103 boost::optional<std::string> status;
1104 Blob rawTxn, rawMeta;
1105 {
1106 soci::blob sociRawTxnBlob(session), sociRawMetaBlob(session);
1107 soci::indicator txn, meta;
1108
1109 session << sql, soci::into(ledgerSeq), soci::into(status), soci::into(sociRawTxnBlob, txn),
1110 soci::into(sociRawMetaBlob, meta);
1111
1112 auto const got_data = session.got_data();
1113
1114 if ((!got_data || txn != soci::i_ok || meta != soci::i_ok) && !range)
1115 return TxSearched::unknown;
1116
1117 if (!got_data)
1118 {
1119 uint64_t count = 0;
1120 soci::indicator rti;
1121
1122 session << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
1123 "LedgerSeq BETWEEN "
1124 << range->first() << " AND " << range->last() << ";",
1125 soci::into(count, rti);
1126
1127 if (!session.got_data() || rti != soci::i_ok)
1128 return TxSearched::some;
1129
1130 return count == (range->last() - range->first() + 1) ? TxSearched::all : TxSearched::some;
1131 }
1132
1133 convert(sociRawTxnBlob, rawTxn);
1134 convert(sociRawMetaBlob, rawMeta);
1135 }
1137 try
1138 {
1139 auto txn = Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
1140
1141 if (!ledgerSeq)
1142 return std::pair{std::move(txn), nullptr};
1143
1144 std::uint32_t inLedger = rangeCheckedCast<std::uint32_t>(ledgerSeq.value());
1145
1146 auto txMeta = std::make_shared<TxMeta>(id, inLedger, rawMeta);
1147
1148 return std::pair{std::move(txn), std::move(txMeta)};
1149 }
1150 catch (std::exception& e)
1151 {
1152 JLOG(app.journal("Ledger").warn())
1153 << "Unable to deserialize transaction from raw SQL value. Error: " << e.what();
1154
1156 }
1157
1158 return TxSearched::unknown;
1159}
1160
1161bool
1162dbHasSpace(soci::session& session, Config const& config, beast::Journal j)
1163{
1164 boost::filesystem::space_info space = boost::filesystem::space(config.legacy("database_path"));
1165
1166 if (space.available < megabytes(512))
1167 {
1168 JLOG(j.fatal()) << "Remaining free disk space is less than 512MB";
1169 return false;
1170 }
1171
1172 if (config.useTxTables())
1173 {
1174 DatabaseCon::Setup dbSetup = setup_DatabaseCon(config);
1175 boost::filesystem::path dbPath = dbSetup.dataDir / TxDBName;
1176 boost::system::error_code ec;
1177 std::optional<std::uint64_t> dbSize = boost::filesystem::file_size(dbPath, ec);
1178 if (ec)
1179 {
1180 JLOG(j.error()) << "Error checking transaction db file size: " << ec.message();
1181 dbSize.reset();
1182 }
1183
1184 static auto const pageSize = [&] {
1185 std::uint32_t ps;
1186 session << "PRAGMA page_size;", soci::into(ps);
1187 return ps;
1188 }();
1189 static auto const maxPages = [&] {
1190 std::uint32_t mp;
1191 session << "PRAGMA max_page_count;", soci::into(mp);
1192 return mp;
1193 }();
1194 std::uint32_t pageCount;
1195 session << "PRAGMA page_count;", soci::into(pageCount);
1196 std::uint32_t freePages = maxPages - pageCount;
1197 std::uint64_t freeSpace = safe_cast<std::uint64_t>(freePages) * pageSize;
1198 JLOG(j.info()) << "Transaction DB pathname: " << dbPath.string() << "; file size: " << dbSize.value_or(-1)
1199 << " bytes"
1200 << "; SQLite page size: " << pageSize << " bytes"
1201 << "; Free pages: " << freePages << "; Free space: " << freeSpace << " bytes; "
1202 << "Note that this does not take into account available disk "
1203 "space.";
1204
1205 if (freeSpace < megabytes(512))
1206 {
1207 JLOG(j.fatal()) << "Free SQLite space for transaction db is less than "
1208 "512MB. To fix this, rippled must be executed with the "
1209 "vacuum parameter before restarting. "
1210 "Note that this activity can take multiple days, "
1211 "depending on database size.";
1212 return false;
1213 }
1214 }
1215
1216 return true;
1217}
1218
1219} // namespace detail
1220} // namespace xrpl
T append(T... args)
A generic endpoint for log messages.
Definition Journal.h:41
Stream fatal() const
Definition Journal.h:325
Stream error() const
Definition Journal.h:319
Stream debug() const
Definition Journal.h:301
Stream info() const
Definition Journal.h:307
Stream trace() const
Severity stream access functions.
Definition Journal.h:295
Stream warn() const
Definition Journal.h:313
virtual TaggedCache< uint256, AcceptedLedger > & getAcceptedLedgerCache()=0
virtual Config & config()=0
virtual PendingSaves & pendingSaves()=0
virtual LedgerMaster & getLedgerMaster()=0
virtual beast::Journal journal(std::string const &name)=0
virtual NodeStore::Database & getNodeStore()=0
virtual TransactionMaster & getMasterTransaction()=0
uint32_t NETWORK_ID
Definition Config.h:138
bool useTxTables() const
Definition Config.h:318
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:1013
LockedSociSession checkoutDb()
void failedSave(std::uint32_t seq, uint256 const &hash)
std::chrono::time_point< NetClock > time_point
Definition chrono.h:46
std::chrono::duration< rep, period > duration
Definition chrono.h:45
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:336
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:472
T count(T... args)
T emplace_back(T... args)
T empty(T... args)
T is_same_v
T max(T... args)
T min(T... args)
int compare(SemanticVersion const &lhs, SemanticVersion const &rhs)
Compare two SemanticVersions against each other.
std::optional< LedgerHeader > getLedgerInfoByHash(soci::session &session, uint256 const &ledgerHash, beast::Journal j)
getLedgerInfoByHash Returns info of ledger with given hash.
Definition Node.cpp:449
bool saveValidatedLedger(DatabaseCon &ldgDB, std::unique_ptr< DatabaseCon > const &txnDB, Application &app, std::shared_ptr< Ledger const > const &ledger, bool current)
saveValidatedLedger Saves ledger into database.
Definition Node.cpp:158
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:126
std::optional< LedgerIndex > getMinLedgerSeq(soci::session &session, TableType type)
getMinLedgerSeq Returns minimum ledger sequence in given table.
Definition Node.cpp:100
std::optional< LedgerIndex > getMaxLedgerSeq(soci::session &session, TableType type)
getMaxLedgerSeq Returns maximum ledger sequence in given table.
Definition Node.cpp:110
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:775
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:550
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:857
std::optional< LedgerHeader > getNewestLedgerInfo(soci::session &session, beast::Journal j)
getNewestLedgerInfo Returns info of newest saved ledger.
Definition Node.cpp:425
std::optional< LedgerHeader > getLimitedOldestLedgerInfo(soci::session &session, LedgerIndex ledgerFirstIndex, beast::Journal j)
getLimitedOldestLedgerInfo Returns info of oldest ledger from ledgers with sequences greater or equal...
Definition Node.cpp:433
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:1061
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:49
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:144
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:696
static std::optional< LedgerHeader > getLedgerInfo(soci::session &session, std::string const &sqlSuffix, beast::Journal j)
getLedgerInfo Returns the info of the ledger retrieved from the database by using the provided SQL qu...
Definition Node.cpp:353
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:896
std::size_t getRows(soci::session &session, TableType type)
getRows Returns number of rows in given table.
Definition Node.cpp:132
std::optional< LedgerHeader > getLedgerInfoByIndex(soci::session &session, LedgerIndex ledgerSeq, beast::Journal j)
getLedgerInfoByIndex Returns ledger by its sequence.
Definition Node.cpp:417
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:867
uint256 getHashByIndex(soci::session &session, LedgerIndex ledgerIndex)
getHashByIndex Returns hash of ledger with given sequence.
Definition Node.cpp:457
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:120
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:764
bool dbHasSpace(soci::session &session, Config const &config, beast::Journal j)
dbHasSpace Checks if given database has available space.
Definition Node.cpp:1136
std::optional< LedgerHeader > getLimitedNewestLedgerInfo(soci::session &session, LedgerIndex ledgerFirstIndex, beast::Journal j)
getLimitedNewestLedgerInfo Returns info of newest ledger from ledgers with sequences greater or equal...
Definition Node.cpp:441
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:806
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:1039
static std::string to_string(TableType type)
to_string Returns the name of a table according to its TableType.
Definition Node.cpp:28
constexpr int TableTypeCount
Definition Node.h:13
std::pair< std::optional< RelationalDatabase::AccountTxMarker >, int > newestAccountTxPage(soci::session &session, std::function< void(std::uint32_t)> const &onUnsavedLedger, std::function< void(std::uint32_t, std::string const &, Blob &&, Blob &&)> const &onTransaction, RelationalDatabase::AccountTxPageOptions const &options, std::uint32_t page_length)
newestAccountTxPage Searches newest transactions for given account which match given criteria startin...
Definition Node.cpp:1050
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:608
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:486
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition RangeSet.h:35
constexpr std::array< char const *, 8 > TxDBInit
Definition DBInit.h:53
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:92
@ hotLEDGER
Definition NodeObject.h:15
bool pendSaveValidated(Application &app, std::shared_ptr< Ledger const > const &ledger, bool isSynchronous, bool isCurrent)
Save, or arrange to save, a fully-validated ledger Returns false on error.
Definition Ledger.cpp:924
@ current
This was a new validation and was added.
base_uint< 256 > uint256
Definition base_uint.h:527
constexpr auto megabytes(T value) noexcept
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
std::uint32_t LedgerIndex
A ledger index.
Definition Protocol.h:255
void addRaw(LedgerHeader const &, Serializer &, bool includeHash=false)
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition Blob.h:11
constexpr auto TxDBName
Definition DBInit.h:51
constexpr auto kilobytes(T value) noexcept
@ ledgerMaster
ledger master data for signing
@ transactionID
transaction plus signature to give transaction ID
constexpr auto LgrDBName
Definition DBInit.h:24
constexpr std::array< char const *, 5 > LgrDBInit
Definition DBInit.h:26
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition STTx.cpp:776
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition SociDB.cpp:126
error_code_i
Definition ErrorCodes.h:21
@ rpcDB_DESERIALIZATION
Definition ErrorCodes.h:115
T push_back(T... args)
T reserve(T... args)
T reset(T... args)
T length(T... args)
T str(T... args)
std::array< std::string, 4 > txPragma
Definition DatabaseCon.h:90
Config::StartUpType startUp
Definition DatabaseCon.h:72
std::array< std::string, 1 > lgrPragma
Definition DatabaseCon.h:91
T to_string(T... args)
T value_or(T... args)
T what(T... args)