rippled
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 <ripple/app/ledger/AcceptedLedger.h>
21 #include <ripple/app/ledger/LedgerMaster.h>
22 #include <ripple/app/ledger/LedgerToJson.h>
23 #include <ripple/app/ledger/PendingSaves.h>
24 #include <ripple/app/ledger/TransactionMaster.h>
25 #include <ripple/app/misc/Manifest.h>
26 #include <ripple/app/rdb/RelationalDatabase.h>
27 #include <ripple/app/rdb/backend/detail/Node.h>
28 #include <ripple/basics/BasicConfig.h>
29 #include <ripple/basics/StringUtilities.h>
30 #include <ripple/core/DatabaseCon.h>
31 #include <ripple/core/SociDB.h>
32 #include <ripple/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 
37 namespace ripple {
38 namespace detail {
39 
45 static std::string
47 {
48  static_assert(
49  TableTypeCount == 3,
50  "Need to modify switch statement if enum is modified");
51 
52  switch (type)
53  {
54  case TableType::Ledgers:
55  return "Ledgers";
57  return "Transactions";
59  return "AccountTransactions";
60  default:
61  assert(false);
62  return "Unknown";
63  }
64 }
65 
66 DatabasePairValid
68  Config const& config,
69  DatabaseCon::Setup const& setup,
70  DatabaseCon::CheckpointerSetup const& checkpointerSetup)
71 {
72  // ledger database
73  auto lgr{std::make_unique<DatabaseCon>(
74  setup, LgrDBName, LgrDBPragma, LgrDBInit, checkpointerSetup)};
75  lgr->getSession() << boost::str(
76  boost::format("PRAGMA cache_size=-%d;") %
78 
79  if (config.useTxTables())
80  {
81  // transaction database
82  auto tx{std::make_unique<DatabaseCon>(
83  setup, TxDBName, TxDBPragma, TxDBInit, checkpointerSetup)};
84  tx->getSession() << boost::str(
85  boost::format("PRAGMA cache_size=-%d;") %
87 
88  if (!setup.standAlone || setup.startUp == Config::LOAD ||
89  setup.startUp == Config::LOAD_FILE ||
90  setup.startUp == Config::REPLAY)
91  {
92  // Check if AccountTransactions has primary key
93  std::string cid, name, type;
94  std::size_t notnull, dflt_value, pk;
95  soci::indicator ind;
96  soci::statement st =
97  (tx->getSession().prepare
98  << ("PRAGMA table_info(AccountTransactions);"),
99  soci::into(cid),
100  soci::into(name),
101  soci::into(type),
102  soci::into(notnull),
103  soci::into(dflt_value, ind),
104  soci::into(pk));
105 
106  st.execute();
107  while (st.fetch())
108  {
109  if (pk == 1)
110  {
111  return {std::move(lgr), std::move(tx), false};
112  }
113  }
114  }
115 
116  return {std::move(lgr), std::move(tx), true};
117  }
118  else
119  return {std::move(lgr), {}, true};
120 }
121 
123 getMinLedgerSeq(soci::session& session, TableType type)
124 {
125  std::string query = "SELECT MIN(LedgerSeq) FROM " + to_string(type) + ";";
126  // SOCI requires boost::optional (not std::optional) as the parameter.
127  boost::optional<LedgerIndex> m;
128  session << query, soci::into(m);
129  return m ? *m : std::optional<LedgerIndex>();
130 }
131 
133 getMaxLedgerSeq(soci::session& session, TableType type)
134 {
135  std::string query = "SELECT MAX(LedgerSeq) FROM " + to_string(type) + ";";
136  // SOCI requires boost::optional (not std::optional) as the parameter.
137  boost::optional<LedgerIndex> m;
138  session << query, soci::into(m);
139  return m ? *m : std::optional<LedgerIndex>();
140 }
141 
142 void
143 deleteByLedgerSeq(soci::session& session, TableType type, LedgerIndex ledgerSeq)
144 {
145  session << "DELETE FROM " << to_string(type)
146  << " WHERE LedgerSeq == " << ledgerSeq << ";";
147 }
148 
149 void
151  soci::session& session,
152  TableType type,
153  LedgerIndex ledgerSeq)
154 {
155  session << "DELETE FROM " << to_string(type) << " WHERE LedgerSeq < "
156  << ledgerSeq << ";";
157 }
158 
160 getRows(soci::session& session, TableType type)
161 {
162  std::size_t rows;
163  session << "SELECT COUNT(*) AS rows "
164  "FROM "
165  << to_string(type) << ";",
166  soci::into(rows);
167 
168  return rows;
169 }
170 
172 getRowsMinMax(soci::session& session, TableType type)
173 {
175  session << "SELECT COUNT(*) AS rows, "
176  "MIN(LedgerSeq) AS first, "
177  "MAX(LedgerSeq) AS last "
178  "FROM "
179  << to_string(type) << ";",
180  soci::into(res.numberOfRows), soci::into(res.minLedgerSequence),
181  soci::into(res.maxLedgerSequence);
182 
183  return res;
184 }
185 
186 bool
188  DatabaseCon& ldgDB,
189  DatabaseCon& txnDB,
190  Application& app,
191  std::shared_ptr<Ledger const> const& ledger,
192  bool current)
193 {
194  auto j = app.journal("Ledger");
195  auto seq = ledger->info().seq;
196 
197  // TODO(tom): Fix this hard-coded SQL!
198  JLOG(j.trace()) << "saveValidatedLedger " << (current ? "" : "fromAcquire ")
199  << seq;
200 
201  if (!ledger->info().accountHash.isNonZero())
202  {
203  JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}});
204  assert(false);
205  }
206 
207  if (ledger->info().accountHash != ledger->stateMap().getHash().as_uint256())
208  {
209  JLOG(j.fatal()) << "sAL: " << ledger->info().accountHash
210  << " != " << ledger->stateMap().getHash();
211  JLOG(j.fatal()) << "saveAcceptedLedger: seq=" << seq
212  << ", current=" << current;
213  assert(false);
214  }
215 
216  assert(ledger->info().txHash == ledger->txMap().getHash().as_uint256());
217 
218  // Save the ledger header in the hashed object store
219  {
220  Serializer s(128);
222  addRaw(ledger->info(), s);
223  app.getNodeStore().store(
224  hotLEDGER, std::move(s.modData()), ledger->info().hash, seq);
225  }
226 
228  try
229  {
230  aLedger = app.getAcceptedLedgerCache().fetch(ledger->info().hash);
231  if (!aLedger)
232  {
233  aLedger = std::make_shared<AcceptedLedger>(ledger, app);
234  app.getAcceptedLedgerCache().canonicalize_replace_client(
235  ledger->info().hash, aLedger);
236  }
237  }
238  catch (std::exception const&)
239  {
240  JLOG(j.warn()) << "An accepted ledger was missing nodes";
241  app.getLedgerMaster().failedSave(seq, ledger->info().hash);
242  // Clients can now trust the database for information about this
243  // ledger sequence.
244  app.pendingSaves().finishWork(seq);
245  return false;
246  }
247 
248  {
249  static boost::format deleteLedger(
250  "DELETE FROM Ledgers WHERE LedgerSeq = %u;");
251  static boost::format deleteTrans1(
252  "DELETE FROM Transactions WHERE LedgerSeq = %u;");
253  static boost::format deleteTrans2(
254  "DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
255  static boost::format deleteAcctTrans(
256  "DELETE FROM AccountTransactions WHERE TransID = '%s';");
257 
258  {
259  auto db = ldgDB.checkoutDb();
260  *db << boost::str(deleteLedger % seq);
261  }
262 
263  if (app.config().useTxTables())
264  {
265  auto db = txnDB.checkoutDb();
266 
267  soci::transaction tr(*db);
268 
269  *db << boost::str(deleteTrans1 % seq);
270  *db << boost::str(deleteTrans2 % seq);
271 
272  std::string const ledgerSeq(std::to_string(seq));
273 
274  for (auto const& acceptedLedgerTx : *aLedger)
275  {
276  uint256 transactionID = acceptedLedgerTx->getTransactionID();
277 
278  std::string const txnId(to_string(transactionID));
279  std::string const txnSeq(
280  std::to_string(acceptedLedgerTx->getTxnSeq()));
281 
282  *db << boost::str(deleteAcctTrans % transactionID);
283 
284  auto const& accts = acceptedLedgerTx->getAffected();
285 
286  if (!accts.empty())
287  {
288  std::string sql(
289  "INSERT INTO AccountTransactions "
290  "(TransID, Account, LedgerSeq, TxnSeq) VALUES ");
291 
292  // Try to make an educated guess on how much space we'll
293  // need for our arguments. In argument order we have: 64
294  // + 34 + 10 + 10 = 118 + 10 extra = 128 bytes
295  sql.reserve(sql.length() + (accts.size() * 128));
296 
297  bool first = true;
298  for (auto const& account : accts)
299  {
300  if (!first)
301  sql += ", ('";
302  else
303  {
304  sql += "('";
305  first = false;
306  }
307 
308  sql += txnId;
309  sql += "','";
310  sql += toBase58(account);
311  sql += "',";
312  sql += ledgerSeq;
313  sql += ",";
314  sql += txnSeq;
315  sql += ")";
316  }
317  sql += ";";
318  JLOG(j.trace()) << "ActTx: " << sql;
319  *db << sql;
320  }
321  else if (auto const& sleTxn = acceptedLedgerTx->getTxn();
322  !isPseudoTx(*sleTxn))
323  {
324  // It's okay for pseudo transactions to not affect any
325  // accounts. But otherwise...
326  JLOG(j.warn()) << "Transaction in ledger " << seq
327  << " affects no accounts";
328  JLOG(j.warn()) << sleTxn->getJson(JsonOptions::none);
329  }
330 
331  *db
333  acceptedLedgerTx->getTxn()->getMetaSQL(
334  seq, acceptedLedgerTx->getEscMeta()) +
335  ";");
336 
338  }
339 
340  tr.commit();
341  }
342 
343  {
344  static std::string addLedger(
345  R"sql(INSERT OR REPLACE INTO Ledgers
346  (LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,
347  CloseTimeRes,CloseFlags,AccountSetHash,TransSetHash)
348  VALUES
349  (:ledgerHash,:ledgerSeq,:prevHash,:totalCoins,:closingTime,:prevClosingTime,
350  :closeTimeRes,:closeFlags,:accountSetHash,:transSetHash);)sql");
351 
352  auto db(ldgDB.checkoutDb());
353 
354  soci::transaction tr(*db);
355 
356  auto const hash = to_string(ledger->info().hash);
357  auto const parentHash = to_string(ledger->info().parentHash);
358  auto const drops = to_string(ledger->info().drops);
359  auto const closeTime =
360  ledger->info().closeTime.time_since_epoch().count();
361  auto const parentCloseTime =
362  ledger->info().parentCloseTime.time_since_epoch().count();
363  auto const closeTimeResolution =
364  ledger->info().closeTimeResolution.count();
365  auto const closeFlags = ledger->info().closeFlags;
366  auto const accountHash = to_string(ledger->info().accountHash);
367  auto const txHash = to_string(ledger->info().txHash);
368 
369  *db << addLedger, soci::use(hash), soci::use(seq),
370  soci::use(parentHash), soci::use(drops), soci::use(closeTime),
371  soci::use(parentCloseTime), soci::use(closeTimeResolution),
372  soci::use(closeFlags), soci::use(accountHash),
373  soci::use(txHash);
374 
375  tr.commit();
376  }
377  }
378 
379  return true;
380 }
381 
392  soci::session& session,
393  std::string const& sqlSuffix,
394  beast::Journal j)
395 {
396  // SOCI requires boost::optional (not std::optional) as parameters.
397  boost::optional<std::string> hash, parentHash, accountHash, txHash;
398  boost::optional<std::uint64_t> seq, drops, closeTime, parentCloseTime,
399  closeTimeResolution, closeFlags;
400 
401  std::string const sql =
402  "SELECT "
403  "LedgerHash, PrevHash, AccountSetHash, TransSetHash, "
404  "TotalCoins,"
405  "ClosingTime, PrevClosingTime, CloseTimeRes, CloseFlags,"
406  "LedgerSeq FROM Ledgers " +
407  sqlSuffix + ";";
408 
409  session << sql, soci::into(hash), soci::into(parentHash),
410  soci::into(accountHash), soci::into(txHash), soci::into(drops),
411  soci::into(closeTime), soci::into(parentCloseTime),
412  soci::into(closeTimeResolution), soci::into(closeFlags),
413  soci::into(seq);
414 
415  if (!session.got_data())
416  {
417  JLOG(j.debug()) << "Ledger not found: " << sqlSuffix;
418  return {};
419  }
420 
421  using time_point = NetClock::time_point;
422  using duration = NetClock::duration;
423 
424  LedgerInfo info;
425 
426  if (hash && !info.hash.parseHex(*hash))
427  {
428  JLOG(j.debug()) << "Hash parse error for ledger: " << sqlSuffix;
429  return {};
430  }
431 
432  if (parentHash && !info.parentHash.parseHex(*parentHash))
433  {
434  JLOG(j.debug()) << "parentHash parse error for ledger: " << sqlSuffix;
435  return {};
436  }
437 
438  if (accountHash && !info.accountHash.parseHex(*accountHash))
439  {
440  JLOG(j.debug()) << "accountHash parse error for ledger: " << sqlSuffix;
441  return {};
442  }
443 
444  if (txHash && !info.txHash.parseHex(*txHash))
445  {
446  JLOG(j.debug()) << "txHash parse error for ledger: " << sqlSuffix;
447  return {};
448  }
449 
450  info.seq = rangeCheckedCast<std::uint32_t>(seq.value_or(0));
451  info.drops = drops.value_or(0);
452  info.closeTime = time_point{duration{closeTime.value_or(0)}};
453  info.parentCloseTime = time_point{duration{parentCloseTime.value_or(0)}};
454  info.closeFlags = closeFlags.value_or(0);
455  info.closeTimeResolution = duration{closeTimeResolution.value_or(0)};
456 
457  return info;
458 }
459 
462  soci::session& session,
463  LedgerIndex ledgerSeq,
464  beast::Journal j)
465 {
467  s << "WHERE LedgerSeq = " << ledgerSeq;
468  return getLedgerInfo(session, s.str(), j);
469 }
470 
472 getNewestLedgerInfo(soci::session& session, beast::Journal j)
473 {
475  s << "ORDER BY LedgerSeq DESC LIMIT 1";
476  return getLedgerInfo(session, s.str(), j);
477 }
478 
481  soci::session& session,
482  LedgerIndex ledgerFirstIndex,
483  beast::Journal j)
484 {
486  s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
487  " ORDER BY LedgerSeq ASC LIMIT 1";
488  return getLedgerInfo(session, s.str(), j);
489 }
490 
493  soci::session& session,
494  LedgerIndex ledgerFirstIndex,
495  beast::Journal j)
496 {
498  s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
499  " ORDER BY LedgerSeq DESC LIMIT 1";
500  return getLedgerInfo(session, s.str(), j);
501 }
502 
505  soci::session& session,
506  uint256 const& ledgerHash,
507  beast::Journal j)
508 {
510  s << "WHERE LedgerHash = '" << ledgerHash << "'";
511  return getLedgerInfo(session, s.str(), j);
512 }
513 
514 uint256
515 getHashByIndex(soci::session& session, LedgerIndex ledgerIndex)
516 {
517  uint256 ret;
518 
519  std::string sql =
520  "SELECT LedgerHash FROM Ledgers INDEXED BY SeqLedger WHERE LedgerSeq='";
521  sql.append(beast::lexicalCastThrow<std::string>(ledgerIndex));
522  sql.append("';");
523 
524  std::string hash;
525  {
526  // SOCI requires boost::optional (not std::optional) as the parameter.
527  boost::optional<std::string> lh;
528  session << sql, soci::into(lh);
529 
530  if (!session.got_data() || !lh)
531  return ret;
532 
533  hash = *lh;
534  if (hash.empty())
535  return ret;
536  }
537 
538  if (!ret.parseHex(hash))
539  return ret;
540 
541  return ret;
542 }
543 
546  soci::session& session,
547  LedgerIndex ledgerIndex,
548  beast::Journal j)
549 {
550  // SOCI requires boost::optional (not std::optional) as the parameter.
551  boost::optional<std::string> lhO, phO;
552 
553  session << "SELECT LedgerHash,PrevHash FROM Ledgers "
554  "INDEXED BY SeqLedger WHERE LedgerSeq = :ls;",
555  soci::into(lhO), soci::into(phO), soci::use(ledgerIndex);
556 
557  if (!lhO || !phO)
558  {
559  auto stream = j.trace();
560  JLOG(stream) << "Don't have ledger " << ledgerIndex;
561  return {};
562  }
563 
564  LedgerHashPair hashes;
565  if (!hashes.ledgerHash.parseHex(*lhO) || !hashes.parentHash.parseHex(*phO))
566  {
567  auto stream = j.trace();
568  JLOG(stream) << "Error parse hashes for ledger " << ledgerIndex;
569  return {};
570  }
571 
572  return hashes;
573 }
574 
577  soci::session& session,
578  LedgerIndex minSeq,
579  LedgerIndex maxSeq,
580  beast::Journal j)
581 {
582  std::string sql =
583  "SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq >= ";
584  sql.append(beast::lexicalCastThrow<std::string>(minSeq));
585  sql.append(" AND LedgerSeq <= ");
586  sql.append(beast::lexicalCastThrow<std::string>(maxSeq));
587  sql.append(";");
588 
589  std::uint64_t ls;
590  std::string lh;
591  // SOCI requires boost::optional (not std::optional) as the parameter.
592  boost::optional<std::string> ph;
593  soci::statement st =
594  (session.prepare << sql,
595  soci::into(ls),
596  soci::into(lh),
597  soci::into(ph));
598 
599  st.execute();
601  while (st.fetch())
602  {
603  LedgerHashPair& hashes = res[rangeCheckedCast<LedgerIndex>(ls)];
604  if (!hashes.ledgerHash.parseHex(lh))
605  {
606  JLOG(j.warn()) << "Error parsed hash for ledger seq: " << ls;
607  }
608  if (!ph)
609  {
610  JLOG(j.warn()) << "Null prev hash for ledger seq: " << ls;
611  }
612  else if (!hashes.parentHash.parseHex(*ph))
613  {
614  JLOG(j.warn()) << "Error parsed prev hash for ledger seq: " << ls;
615  }
616  }
617  return res;
618 }
619 
622  soci::session& session,
623  Application& app,
624  LedgerIndex startIndex,
625  int quantity,
626  bool count)
627 {
628  std::string sql = boost::str(
629  boost::format(
630  "SELECT LedgerSeq, Status, RawTxn "
631  "FROM Transactions ORDER BY LedgerSeq DESC LIMIT %u,%u;") %
632  startIndex % quantity);
633 
635  int total = 0;
636 
637  {
638  // SOCI requires boost::optional (not std::optional) as parameters.
639  boost::optional<std::uint64_t> ledgerSeq;
640  boost::optional<std::string> status;
641  soci::blob sociRawTxnBlob(session);
642  soci::indicator rti;
643  Blob rawTxn;
644 
645  soci::statement st =
646  (session.prepare << sql,
647  soci::into(ledgerSeq),
648  soci::into(status),
649  soci::into(sociRawTxnBlob, rti));
650 
651  st.execute();
652  while (st.fetch())
653  {
654  if (soci::i_ok == rti)
655  convert(sociRawTxnBlob, rawTxn);
656  else
657  rawTxn.clear();
658 
659  if (auto trans = Transaction::transactionFromSQL(
660  ledgerSeq, status, rawTxn, app))
661  {
662  total++;
663  txs.push_back(trans);
664  }
665  }
666 
667  if (!total && count)
668  {
669  session << "SELECT COUNT(*) FROM Transactions;", soci::into(total);
670 
671  total = -total;
672  }
673  }
674 
675  return {txs, total};
676 }
677 
698 static std::string
700  Application& app,
701  std::string selection,
702  RelationalDatabase::AccountTxOptions const& options,
703  std::optional<int> const& limit_used,
704  bool descending,
705  bool binary,
706  bool count,
707  beast::Journal j)
708 {
709  constexpr std::uint32_t NONBINARY_PAGE_LENGTH = 200;
710  constexpr std::uint32_t BINARY_PAGE_LENGTH = 500;
711 
712  std::uint32_t numberOfResults;
713 
714  if (count)
715  {
716  numberOfResults = std::numeric_limits<std::uint32_t>::max();
717  }
718  else if (options.limit == UINT32_MAX)
719  {
720  numberOfResults = binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH;
721  }
722  else if (!options.bUnlimited)
723  {
724  numberOfResults = std::min(
725  binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH, options.limit);
726  }
727  else
728  {
729  numberOfResults = options.limit;
730  }
731 
732  if (limit_used)
733  {
734  if (numberOfResults <= *limit_used)
735  return "";
736  else
737  numberOfResults -= *limit_used;
738  }
739 
740  std::string maxClause = "";
741  std::string minClause = "";
742 
743  if (options.maxLedger)
744  {
745  maxClause = boost::str(
746  boost::format("AND AccountTransactions.LedgerSeq <= '%u'") %
747  options.maxLedger);
748  }
749 
750  if (options.minLedger)
751  {
752  minClause = boost::str(
753  boost::format("AND AccountTransactions.LedgerSeq >= '%u'") %
754  options.minLedger);
755  }
756 
757  std::string sql;
758 
759  if (count)
760  sql = boost::str(
761  boost::format("SELECT %s FROM AccountTransactions "
762  "WHERE Account = '%s' %s %s LIMIT %u, %u;") %
763  selection % toBase58(options.account) % maxClause % minClause %
764  beast::lexicalCastThrow<std::string>(options.offset) %
765  beast::lexicalCastThrow<std::string>(numberOfResults));
766  else
767  sql = boost::str(
768  boost::format(
769  "SELECT %s FROM "
770  "AccountTransactions INNER JOIN Transactions "
771  "ON Transactions.TransID = AccountTransactions.TransID "
772  "WHERE Account = '%s' %s %s "
773  "ORDER BY AccountTransactions.LedgerSeq %s, "
774  "AccountTransactions.TxnSeq %s, AccountTransactions.TransID %s "
775  "LIMIT %u, %u;") %
776  selection % toBase58(options.account) % maxClause % minClause %
777  (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") %
778  (descending ? "DESC" : "ASC") %
779  beast::lexicalCastThrow<std::string>(options.offset) %
780  beast::lexicalCastThrow<std::string>(numberOfResults));
781  JLOG(j.trace()) << "txSQL query: " << sql;
782  return sql;
783 }
784 
811  soci::session& session,
812  Application& app,
813  LedgerMaster& ledgerMaster,
814  RelationalDatabase::AccountTxOptions const& options,
815  std::optional<int> const& limit_used,
816  bool descending,
817  beast::Journal j)
818 {
820 
822  app,
823  "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
824  options,
825  limit_used,
826  descending,
827  false,
828  false,
829  j);
830  if (sql == "")
831  return {ret, 0};
832 
833  int total = 0;
834  {
835  // SOCI requires boost::optional (not std::optional) as parameters.
836  boost::optional<std::uint64_t> ledgerSeq;
837  boost::optional<std::string> status;
838  soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
839  soci::indicator rti, tmi;
840  Blob rawTxn, txnMeta;
841 
842  soci::statement st =
843  (session.prepare << sql,
844  soci::into(ledgerSeq),
845  soci::into(status),
846  soci::into(sociTxnBlob, rti),
847  soci::into(sociTxnMetaBlob, tmi));
848 
849  st.execute();
850  while (st.fetch())
851  {
852  if (soci::i_ok == rti)
853  convert(sociTxnBlob, rawTxn);
854  else
855  rawTxn.clear();
856 
857  if (soci::i_ok == tmi)
858  convert(sociTxnMetaBlob, txnMeta);
859  else
860  txnMeta.clear();
861 
862  auto txn =
863  Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
864 
865  if (txnMeta.empty())
866  { // Work around a bug that could leave the metadata missing
867  auto const seq =
868  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
869 
870  JLOG(j.warn())
871  << "Recovering ledger " << seq << ", txn " << txn->getID();
872 
873  if (auto l = ledgerMaster.getLedgerBySeq(seq))
874  pendSaveValidated(app, l, false, false);
875  }
876 
877  if (txn)
878  {
879  ret.emplace_back(
880  txn,
881  std::make_shared<TxMeta>(
882  txn->getID(), txn->getLedger(), txnMeta));
883  total++;
884  }
885  }
886 
887  if (!total && limit_used)
888  {
889  RelationalDatabase::AccountTxOptions opt = options;
890  opt.offset = 0;
892  app, "COUNT(*)", opt, limit_used, descending, false, false, j);
893 
894  session << sql1, soci::into(total);
895 
896  total = -total;
897  }
898  }
899 
900  return {ret, total};
901 }
902 
905  soci::session& session,
906  Application& app,
907  LedgerMaster& ledgerMaster,
908  RelationalDatabase::AccountTxOptions const& options,
909  std::optional<int> const& limit_used,
910  beast::Journal j)
911 {
913  session, app, ledgerMaster, options, limit_used, false, j);
914 }
915 
918  soci::session& session,
919  Application& app,
920  LedgerMaster& ledgerMaster,
922  std::optional<int> const& limit_used,
923  beast::Journal j)
924 {
925  return getAccountTxs(
926  session, app, ledgerMaster, options, limit_used, true, j);
927 }
928 
954  soci::session& session,
955  Application& app,
956  RelationalDatabase::AccountTxOptions const& options,
957  std::optional<int> const& limit_used,
958  bool descending,
959  beast::Journal j)
960 {
962 
964  app,
965  "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
966  options,
967  limit_used,
968  descending,
969  true /*binary*/,
970  false,
971  j);
972  if (sql == "")
973  return {ret, 0};
974 
975  int total = 0;
976 
977  {
978  // SOCI requires boost::optional (not std::optional) as parameters.
979  boost::optional<std::uint64_t> ledgerSeq;
980  boost::optional<std::string> status;
981  soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
982  soci::indicator rti, tmi;
983 
984  soci::statement st =
985  (session.prepare << sql,
986  soci::into(ledgerSeq),
987  soci::into(status),
988  soci::into(sociTxnBlob, rti),
989  soci::into(sociTxnMetaBlob, tmi));
990 
991  st.execute();
992  while (st.fetch())
993  {
994  Blob rawTxn;
995  if (soci::i_ok == rti)
996  convert(sociTxnBlob, rawTxn);
997  Blob txnMeta;
998  if (soci::i_ok == tmi)
999  convert(sociTxnMetaBlob, txnMeta);
1000 
1001  auto const seq =
1002  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
1003 
1004  ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq);
1005  total++;
1006  }
1007 
1008  if (!total && limit_used)
1009  {
1010  RelationalDatabase::AccountTxOptions opt = options;
1011  opt.offset = 0;
1013  app, "COUNT(*)", opt, limit_used, descending, true, false, j);
1014 
1015  session << sql1, soci::into(total);
1016 
1017  total = -total;
1018  }
1019  }
1021  return {ret, total};
1022 }
1023 
1026  soci::session& session,
1027  Application& app,
1028  RelationalDatabase::AccountTxOptions const& options,
1029  std::optional<int> const& limit_used,
1030  beast::Journal j)
1032  return getAccountTxsB(session, app, options, limit_used, false, j);
1033 }
1034 
1037  soci::session& session,
1038  Application& app,
1039  RelationalDatabase::AccountTxOptions const& options,
1040  std::optional<int> const& limit_used,
1041  beast::Journal j)
1042 {
1043  return getAccountTxsB(session, app, options, limit_used, true, j);
1044 }
1045 
1069  soci::session& session,
1070  std::function<void(std::uint32_t)> const& onUnsavedLedger,
1071  std::function<
1072  void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1073  onTransaction,
1074  RelationalDatabase::AccountTxPageOptions const& options,
1075  int limit_used,
1076  std::uint32_t page_length,
1077  bool forward)
1078 {
1079  int total = 0;
1080 
1081  bool lookingForMarker = options.marker.has_value();
1082 
1083  std::uint32_t numberOfResults;
1084 
1085  if (options.limit == 0 || options.limit == UINT32_MAX ||
1086  (options.limit > page_length && !options.bAdmin))
1087  numberOfResults = page_length;
1088  else
1089  numberOfResults = options.limit;
1090 
1091  if (numberOfResults < limit_used)
1092  return {options.marker, -1};
1093  numberOfResults -= limit_used;
1094 
1095  // As an account can have many thousands of transactions, there is a limit
1096  // placed on the amount of transactions returned. If the limit is reached
1097  // before the result set has been exhausted (we always query for one more
1098  // than the limit), then we return an opaque marker that can be supplied in
1099  // a subsequent query.
1100  std::uint32_t queryLimit = numberOfResults + 1;
1101  std::uint32_t findLedger = 0, findSeq = 0;
1102 
1103  if (lookingForMarker)
1104  {
1105  findLedger = options.marker->ledgerSeq;
1106  findSeq = options.marker->txnSeq;
1107  }
1108 
1110  if (limit_used > 0)
1111  newmarker = options.marker;
1112 
1113  static std::string const prefix(
1114  R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1115  Status,RawTxn,TxnMeta
1116  FROM AccountTransactions INNER JOIN Transactions
1117  ON Transactions.TransID = AccountTransactions.TransID
1118  AND AccountTransactions.Account = '%s' WHERE
1119  )");
1120 
1121  std::string sql;
1122 
1123  // SQL's BETWEEN uses a closed interval ([a,b])
1124 
1125  const char* const order = forward ? "ASC" : "DESC";
1126 
1127  if (findLedger == 0)
1128  {
1129  sql = boost::str(
1130  boost::format(
1131  prefix + (R"(AccountTransactions.LedgerSeq BETWEEN '%u' AND '%u'
1132  ORDER BY AccountTransactions.LedgerSeq %s,
1133  AccountTransactions.TxnSeq %s
1134  LIMIT %u;)")) %
1135  toBase58(options.account) % options.minLedger % options.maxLedger %
1136  order % order % queryLimit);
1137  }
1138  else
1139  {
1140  const char* const compare = forward ? ">=" : "<=";
1141  const std::uint32_t minLedger =
1142  forward ? findLedger + 1 : options.minLedger;
1143  const std::uint32_t maxLedger =
1144  forward ? options.maxLedger : findLedger - 1;
1145 
1146  auto b58acct = toBase58(options.account);
1147  sql = boost::str(
1148  boost::format((
1149  R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1150  Status,RawTxn,TxnMeta
1151  FROM AccountTransactions, Transactions WHERE
1152  (AccountTransactions.TransID = Transactions.TransID AND
1153  AccountTransactions.Account = '%s' AND
1154  AccountTransactions.LedgerSeq BETWEEN '%u' AND '%u')
1155  OR
1156  (AccountTransactions.TransID = Transactions.TransID AND
1157  AccountTransactions.Account = '%s' AND
1158  AccountTransactions.LedgerSeq = '%u' AND
1159  AccountTransactions.TxnSeq %s '%u')
1160  ORDER BY AccountTransactions.LedgerSeq %s,
1161  AccountTransactions.TxnSeq %s
1162  LIMIT %u;
1163  )")) %
1164  b58acct % minLedger % maxLedger % b58acct % findLedger % compare %
1165  findSeq % order % order % queryLimit);
1166  }
1167 
1168  {
1169  Blob rawData;
1170  Blob rawMeta;
1171 
1172  // SOCI requires boost::optional (not std::optional) as parameters.
1173  boost::optional<std::uint64_t> ledgerSeq;
1174  boost::optional<std::uint32_t> txnSeq;
1175  boost::optional<std::string> status;
1176  soci::blob txnData(session);
1177  soci::blob txnMeta(session);
1178  soci::indicator dataPresent, metaPresent;
1179 
1180  soci::statement st =
1181  (session.prepare << sql,
1182  soci::into(ledgerSeq),
1183  soci::into(txnSeq),
1184  soci::into(status),
1185  soci::into(txnData, dataPresent),
1186  soci::into(txnMeta, metaPresent));
1187 
1188  st.execute();
1189 
1190  while (st.fetch())
1191  {
1192  if (lookingForMarker)
1193  {
1194  if (findLedger == ledgerSeq.value_or(0) &&
1195  findSeq == txnSeq.value_or(0))
1196  {
1197  lookingForMarker = false;
1198  }
1199  else
1200  continue;
1201  }
1202  else if (numberOfResults == 0)
1203  {
1204  newmarker = {
1205  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1206  txnSeq.value_or(0)};
1207  break;
1208  }
1209 
1210  if (dataPresent == soci::i_ok)
1211  convert(txnData, rawData);
1212  else
1213  rawData.clear();
1214 
1215  if (metaPresent == soci::i_ok)
1216  convert(txnMeta, rawMeta);
1217  else
1218  rawMeta.clear();
1219 
1220  // Work around a bug that could leave the metadata missing
1221  if (rawMeta.size() == 0)
1222  onUnsavedLedger(ledgerSeq.value_or(0));
1223 
1224  // `rawData` and `rawMeta` will be used after they are moved.
1225  // That's OK.
1226  onTransaction(
1227  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1228  *status,
1229  std::move(rawData),
1230  std::move(rawMeta));
1231  // Note some callbacks will move the data, some will not. Clear
1232  // them so code doesn't depend on if the data was actually moved
1233  // or not. The code will be more efficient if `rawData` and
1234  // `rawMeta` don't have to allocate in `convert`, so don't
1235  // refactor my moving these variables into loop scope.
1236  rawData.clear();
1237  rawMeta.clear();
1238 
1239  --numberOfResults;
1240  total++;
1241  }
1242  }
1243 
1244  return {newmarker, total};
1246 
1249  soci::session& session,
1250  std::function<void(std::uint32_t)> const& onUnsavedLedger,
1251  std::function<
1252  void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1253  onTransaction,
1255  int limit_used,
1256  std::uint32_t page_length)
1257 {
1258  return accountTxPage(
1259  session,
1260  onUnsavedLedger,
1261  onTransaction,
1262  options,
1263  limit_used,
1264  page_length,
1265  true);
1267 
1270  soci::session& session,
1271  std::function<void(std::uint32_t)> const& onUnsavedLedger,
1272  std::function<
1273  void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1274  onTransaction,
1276  int limit_used,
1277  std::uint32_t page_length)
1278 {
1279  return accountTxPage(
1280  session,
1281  onUnsavedLedger,
1282  onTransaction,
1283  options,
1284  limit_used,
1285  page_length,
1286  false);
1287 }
1288 
1291  soci::session& session,
1292  Application& app,
1293  uint256 const& id,
1294  std::optional<ClosedInterval<uint32_t>> const& range,
1295  error_code_i& ec)
1296 {
1297  std::string sql =
1298  "SELECT LedgerSeq,Status,RawTxn,TxnMeta "
1299  "FROM Transactions WHERE TransID='";
1300 
1301  sql.append(to_string(id));
1302  sql.append("';");
1303 
1304  // SOCI requires boost::optional (not std::optional) as parameters.
1305  boost::optional<std::uint64_t> ledgerSeq;
1306  boost::optional<std::string> status;
1307  Blob rawTxn, rawMeta;
1308  {
1309  soci::blob sociRawTxnBlob(session), sociRawMetaBlob(session);
1310  soci::indicator txn, meta;
1311 
1312  session << sql, soci::into(ledgerSeq), soci::into(status),
1313  soci::into(sociRawTxnBlob, txn), soci::into(sociRawMetaBlob, meta);
1314 
1315  auto const got_data = session.got_data();
1316 
1317  if ((!got_data || txn != soci::i_ok || meta != soci::i_ok) && !range)
1318  return TxSearched::unknown;
1319 
1320  if (!got_data)
1321  {
1322  uint64_t count = 0;
1323  soci::indicator rti;
1324 
1325  session
1326  << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
1327  "LedgerSeq BETWEEN "
1328  << range->first() << " AND " << range->last() << ";",
1329  soci::into(count, rti);
1330 
1331  if (!session.got_data() || rti != soci::i_ok)
1332  return TxSearched::some;
1333 
1334  return count == (range->last() - range->first() + 1)
1335  ? TxSearched::all
1336  : TxSearched::some;
1337  }
1338 
1339  convert(sociRawTxnBlob, rawTxn);
1340  convert(sociRawMetaBlob, rawMeta);
1341  }
1342 
1343  try
1344  {
1345  auto txn =
1346  Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
1348  if (!ledgerSeq)
1349  return std::pair{std::move(txn), nullptr};
1350 
1351  std::uint32_t inLedger =
1352  rangeCheckedCast<std::uint32_t>(ledgerSeq.value());
1353 
1354  auto txMeta = std::make_shared<TxMeta>(id, inLedger, rawMeta);
1355 
1356  return std::pair{std::move(txn), std::move(txMeta)};
1357  }
1358  catch (std::exception& e)
1359  {
1360  JLOG(app.journal("Ledger").warn())
1361  << "Unable to deserialize transaction from raw SQL value. Error: "
1362  << e.what();
1363 
1364  ec = rpcDB_DESERIALIZATION;
1365  }
1366 
1367  return TxSearched::unknown;
1368 }
1369 
1370 bool
1371 dbHasSpace(soci::session& session, Config const& config, beast::Journal j)
1372 {
1373  boost::filesystem::space_info space =
1374  boost::filesystem::space(config.legacy("database_path"));
1375 
1376  if (space.available < megabytes(512))
1377  {
1378  JLOG(j.fatal()) << "Remaining free disk space is less than 512MB";
1379  return false;
1380  }
1381 
1382  if (config.useTxTables())
1383  {
1384  DatabaseCon::Setup dbSetup = setup_DatabaseCon(config);
1385  boost::filesystem::path dbPath = dbSetup.dataDir / TxDBName;
1386  boost::system::error_code ec;
1388  boost::filesystem::file_size(dbPath, ec);
1389  if (ec)
1390  {
1391  JLOG(j.error())
1392  << "Error checking transaction db file size: " << ec.message();
1393  dbSize.reset();
1394  }
1395 
1396  static auto const pageSize = [&] {
1397  std::uint32_t ps;
1398  session << "PRAGMA page_size;", soci::into(ps);
1399  return ps;
1400  }();
1401  static auto const maxPages = [&] {
1402  std::uint32_t mp;
1403  session << "PRAGMA max_page_count;", soci::into(mp);
1404  return mp;
1405  }();
1406  std::uint32_t pageCount;
1407  session << "PRAGMA page_count;", soci::into(pageCount);
1408  std::uint32_t freePages = maxPages - pageCount;
1409  std::uint64_t freeSpace =
1410  safe_cast<std::uint64_t>(freePages) * pageSize;
1411  JLOG(j.info())
1412  << "Transaction DB pathname: " << dbPath.string()
1413  << "; file size: " << dbSize.value_or(-1) << " bytes"
1414  << "; SQLite page size: " << pageSize << " bytes"
1415  << "; Free pages: " << freePages << "; Free space: " << freeSpace
1416  << " bytes; "
1417  << "Note that this does not take into account available disk "
1418  "space.";
1419 
1420  if (freeSpace < megabytes(512))
1421  {
1422  JLOG(j.fatal())
1423  << "Free SQLite space for transaction db is less than "
1424  "512MB. To fix this, rippled must be executed with the "
1425  "vacuum parameter before restarting. "
1426  "Note that this activity can take multiple days, "
1427  "depending on database size.";
1428  return false;
1429  }
1430  }
1431 
1432  return true;
1433 }
1434 
1435 } // namespace detail
1436 } // namespace ripple
ripple::detail::deleteByLedgerSeq
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:143
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::Application
Definition: Application.h:115
ripple::Transaction::transactionFromSQL
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:92
ripple::detail::TableType::Ledgers
@ Ledgers
ripple::rpcDB_DESERIALIZATION
@ rpcDB_DESERIALIZATION
Definition: ErrorCodes.h:134
ripple::HashPrefix::ledgerMaster
@ ledgerMaster
ledger master data for signing
ripple::detail::getNewestLedgerInfo
std::optional< LedgerInfo > getNewestLedgerInfo(soci::session &session, beast::Journal j)
getNewestLedgerInfo Returns info of newest saved ledger.
Definition: Node.cpp:467
ripple::detail::newestAccountTxPage
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, int limit_used, std::uint32_t page_length)
newestAccountTxPage Searches newest transactions for given account which match given criteria startin...
Definition: Node.cpp:1245
ripple::Blob
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition: Blob.h:30
ripple::detail::dbHasSpace
bool dbHasSpace(soci::session &session, Config const &config, beast::Journal j)
dbHasSpace Checks if given database has available space.
Definition: Node.cpp:1347
ripple::TxSearched::unknown
@ unknown
ripple::Application::getAcceptedLedgerCache
virtual TaggedCache< uint256, AcceptedLedger > & getAcceptedLedgerCache()=0
ripple::LedgerIndex
std::uint32_t LedgerIndex
A ledger index.
Definition: Protocol.h:90
std::string
STL class.
std::shared_ptr
STL class.
ripple::detail::TableType
TableType
Definition: Node.h:35
ripple::TxDBPragma
constexpr std::array< char const *, 4 > TxDBPragma
Definition: DBInit.h:78
std::exception
STL class.
ripple::test::jtx::drops
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
ripple::DatabaseCon::Setup
Definition: DatabaseCon.h:84
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
ripple::detail::deleteBeforeLedgerSeq
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:150
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:178
std::pair
std::string::reserve
T reserve(T... args)
ripple::TxSearched::all
@ all
ripple::LedgerMaster
Definition: LedgerMaster.h:70
ripple::detail::to_string
static std::string to_string(TableType type)
to_string Returns the name of a table according to its TableType.
Definition: Node.cpp:46
ripple::convert
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition: SociDB.cpp:154
ripple::addRaw
void addRaw(LedgerInfo const &info, Serializer &s, bool includeHash)
Definition: View.cpp:162
ripple::setup_DatabaseCon
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
Definition: DatabaseCon.cpp:106
ripple::DatabaseCon::Setup::startUp
Config::StartUpType startUp
Definition: DatabaseCon.h:88
std::vector
STL class.
std::string::length
T length(T... args)
ripple::detail::getRowsMinMax
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:172
std::optional::value_or
T value_or(T... args)
ripple::detail::getNewestAccountTxsB
std::pair< std::vector< RelationalDatabase::txnMetaLedgerType >, int > getNewestAccountTxsB(soci::session &session, Application &app, RelationalDatabase::AccountTxOptions const &options, std::optional< int > const &limit_used, beast::Journal j)
getNewestAccountTxsB Returns newest transactions in binary form for given account which match given c...
Definition: Node.cpp:1031
ripple::RelationalDatabase::CountMinMax::minLedgerSequence
LedgerIndex minLedgerSequence
Definition: RelationalDatabase.h:54
ripple::detail::getAccountTxsB
static std::pair< std::vector< RelationalDatabase::txnMetaLedgerType >, int > getAccountTxsB(soci::session &session, Application &app, RelationalDatabase::AccountTxOptions const &options, std::optional< int > const &limit_used, bool descending, beast::Journal j)
getAccountTxsB Returns the oldest or newest transactions in binary form for the account that matches ...
Definition: Node.cpp:948
ripple::RelationalDatabase::AccountTxs
std::vector< AccountTx > AccountTxs
Definition: RelationalDatabase.h:86
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:104
ripple::DatabaseCon::CheckpointerSetup
Definition: DatabaseCon.h:107
ripple::Config::LOAD
@ LOAD
Definition: Config.h:153
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::detail::TableType::Transactions
@ Transactions
beast::compare
int compare(SemanticVersion const &lhs, SemanticVersion const &rhs)
Compare two SemanticVersions against each other.
Definition: SemanticVersion.cpp:259
ripple::kilobytes
constexpr auto kilobytes(T value) noexcept
Definition: ByteUtilities.h:27
ripple::RelationalDatabase::AccountTxOptions
Definition: RelationalDatabase.h:64
ripple::STTx::getMetaSQLInsertReplaceHeader
static std::string const & getMetaSQLInsertReplaceHeader()
Definition: STTx.cpp:251
std::function
ripple::NodeStore::Database::store
virtual void store(NodeObjectType type, Blob &&data, uint256 const &hash, std::uint32_t ledgerSeq)=0
Store the object.
ripple::detail::getLimitedOldestLedgerInfo
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:475
ripple::detail::getHashByIndex
uint256 getHashByIndex(soci::session &session, LedgerIndex ledgerIndex)
getHashByIndex Returns hash of ledger with given sequence.
Definition: Node.cpp:510
ripple::detail::getLedgerInfoByHash
std::optional< LedgerInfo > getLedgerInfoByHash(soci::session &session, uint256 const &ledgerHash, beast::Journal j)
getLedgerInfoByHash Returns info of ledger with given hash.
Definition: Node.cpp:499
std::optional::reset
T reset(T... args)
ripple::LgrDBInit
constexpr std::array< char const *, 5 > LgrDBInit
Definition: DBInit.h:48
ripple::error_code_i
error_code_i
Definition: ErrorCodes.h:40
ripple::detail::getTransaction
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:1266
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:550
ripple::detail::saveValidatedLedger
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:187
std::vector::push_back
T push_back(T... args)
ripple::detail::getLimitedNewestLedgerInfo
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:487
ripple::RelationalDatabase::CountMinMax
Definition: RelationalDatabase.h:51
ripple::TxDBName
constexpr auto TxDBName
Definition: DBInit.h:73
ripple::base_uint< 256 >
ripple::isPseudoTx
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition: STTx.cpp:559
ripple::detail::getTxHistory
std::pair< std::vector< std::shared_ptr< Transaction > >, int > getTxHistory(soci::session &session, Application &app, LedgerIndex startIndex, int quantity, bool count)
getTxHistory Returns given number of most recent transactions starting from given number of entry.
Definition: Node.cpp:616
ripple::DatabaseCon::Setup::standAlone
bool standAlone
Definition: DatabaseCon.h:89
ripple::Config::getValueFor
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:1022
ripple::DatabaseCon::checkoutDb
LockedSociSession checkoutDb()
Definition: DatabaseCon.h:178
ripple::LedgerHashPair::ledgerHash
uint256 ledgerHash
Definition: RelationalDatabase.h:38
ripple::LgrDBPragma
constexpr std::array< char const *, 1 > LgrDBPragma
Definition: DBInit.h:45
ripple::LedgerMaster::failedSave
void failedSave(std::uint32_t seq, uint256 const &hash)
Definition: LedgerMaster.cpp:972
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::Config
Definition: Config.h:89
ripple::Application::pendingSaves
virtual PendingSaves & pendingSaves()=0
ripple::LedgerHashPair
Definition: RelationalDatabase.h:36
std::forward
T forward(T... args)
ripple::JsonOptions::none
@ none
ripple::Application::config
virtual Config & config()=0
ripple::megabytes
constexpr auto megabytes(T value) noexcept
Definition: ByteUtilities.h:34
ripple::detail::makeLedgerDBs
DatabasePairValid makeLedgerDBs(Config const &config, DatabaseCon::Setup const &setup, DatabaseCon::CheckpointerSetup const &checkpointerSetup)
makeLedgerDBs Opens ledger and transactions databases.
Definition: Node.cpp:67
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:343
std::to_string
T to_string(T... args)
ripple::detail::getLedgerInfo
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:386
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::ValStatus::current
@ current
This was a new validation and was added.
ripple::SizedItem::lgrDBCache
@ lgrDBCache
ripple::PendingSaves::finishWork
void finishWork(LedgerIndex seq)
Finish working on a ledger.
Definition: PendingSaves.h:74
ripple::HashPrefix::transactionID
@ transactionID
transaction plus signature to give transaction ID
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::uint32_t
ripple::detail::oldestAccountTxPage
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, int limit_used, std::uint32_t page_length)
oldestAccountTxPage Searches oldest transactions for given account which match given criteria startin...
Definition: Node.cpp:1224
std::map
STL class.
ripple::RelationalDatabase::CountMinMax::maxLedgerSequence
LedgerIndex maxLedgerSequence
Definition: RelationalDatabase.h:55
ripple::range
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition: RangeSet.h:53
ripple::detail::getRows
std::size_t getRows(soci::session &session, TableType type)
getRows Returns number of rows in given table.
Definition: Node.cpp:160
ripple::SizedItem::txnDBCache
@ txnDBCache
ripple::detail::getOldestAccountTxsB
std::pair< std::vector< RelationalDatabase::txnMetaLedgerType >, int > getOldestAccountTxsB(soci::session &session, Application &app, RelationalDatabase::AccountTxOptions const &options, std::optional< int > const &limit_used, beast::Journal j)
getOldestAccountTxsB Returns oldest transactions in binary form for given account which match given c...
Definition: Node.cpp:1020
std::string::append
T append(T... args)
ripple::detail::getLedgerInfoByIndex
std::optional< LedgerInfo > getLedgerInfoByIndex(soci::session &session, LedgerIndex ledgerSeq, beast::Journal j)
getLedgerInfoByIndex Returns ledger by its sequence.
Definition: Node.cpp:456
std::experimental::filesystem::status
T status(T... args)
ripple::detail::accountTxPage
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, int limit_used, 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:1063
std::experimental::filesystem::space
T space(T... args)
std::min
T min(T... args)
ripple::Serializer
Definition: Serializer.h:39
ripple::getJson
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
Definition: LedgerToJson.cpp:296
std::ostringstream
STL class.
ripple::detail::transactionsSQL
static std::string transactionsSQL(Application &app, std::string selection, RelationalDatabase::AccountTxOptions const &options, std::optional< int > const &limit_used, 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:694
ripple::TransactionMaster::inLedger
bool inLedger(uint256 const &hash, std::uint32_t ledger)
Definition: TransactionMaster.cpp:40
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::detail::getMinLedgerSeq
std::optional< LedgerIndex > getMinLedgerSeq(soci::session &session, TableType type)
getMinLedgerSeq Returns minimum ledger sequence in given table.
Definition: Node.cpp:123
ripple::Application::getNodeStore
virtual NodeStore::Database & getNodeStore()=0
ripple::Application::journal
virtual beast::Journal journal(std::string const &name)=0
ripple::detail::TableTypeCount
constexpr int TableTypeCount
Definition: Node.h:36
ripple::Config::REPLAY
@ REPLAY
Definition: Config.h:153
ripple::detail::TableType::AccountTransactions
@ AccountTransactions
ripple::LedgerHashPair::parentHash
uint256 parentHash
Definition: RelationalDatabase.h:39
ripple::DatabaseCon
Definition: DatabaseCon.h:81
std::string::empty
T empty(T... args)
std::optional
std::ostringstream::str
T str(T... args)
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::size_t
ripple::hotLEDGER
@ hotLEDGER
Definition: NodeObject.h:34
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::RelationalDatabase::CountMinMax::numberOfRows
std::size_t numberOfRows
Definition: RelationalDatabase.h:53
ripple::NetClock::duration
std::chrono::duration< rep, period > duration
Definition: chrono.h:55
ripple::TxDBInit
constexpr std::array< char const *, 8 > TxDBInit
Definition: DBInit.h:94
std::numeric_limits::max
T max(T... args)
ripple::base_uint::parseHex
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition: base_uint.h:496
ripple::detail::getOldestAccountTxs
std::pair< RelationalDatabase::AccountTxs, int > getOldestAccountTxs(soci::session &session, Application &app, LedgerMaster &ledgerMaster, RelationalDatabase::AccountTxOptions const &options, std::optional< int > const &limit_used, beast::Journal j)
getOldestAccountTxs Returns oldest transactions for given account which match given criteria starting...
Definition: Node.cpp:899
ripple::detail::getMaxLedgerSeq
std::optional< LedgerIndex > getMaxLedgerSeq(soci::session &session, TableType type)
getMaxLedgerSeq Returns maximum ledger sequence in given table.
Definition: Node.cpp:133
ripple::pendSaveValidated
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:1005
ripple::detail::getNewestAccountTxs
std::pair< RelationalDatabase::AccountTxs, int > getNewestAccountTxs(soci::session &session, Application &app, LedgerMaster &ledgerMaster, RelationalDatabase::AccountTxOptions const &options, std::optional< int > const &limit_used, beast::Journal j)
getNewestAccountTxs Returns newest transactions for given account which match given criteria starting...
Definition: Node.cpp:912
ripple::detail::getHashesByIndex
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:540
ripple::NetClock::time_point
std::chrono::time_point< NetClock > time_point
Definition: chrono.h:56
ripple::Config::LOAD_FILE
@ LOAD_FILE
Definition: Config.h:153
ripple::detail::getAccountTxs
static std::pair< RelationalDatabase::AccountTxs, int > getAccountTxs(soci::session &session, Application &app, LedgerMaster &ledgerMaster, RelationalDatabase::AccountTxOptions const &options, std::optional< int > const &limit_used, bool descending, beast::Journal j)
getAccountTxs Returns the oldest or newest transactions for the account that matches the given criter...
Definition: Node.cpp:805
ripple::RelationalDatabase::AccountTxPageOptions
Definition: RelationalDatabase.h:74
std::exception::what
T what(T... args)
ripple::TxSearched::some
@ some
std::variant
ripple::LgrDBName
constexpr auto LgrDBName
Definition: DBInit.h:43
ripple::Application::getMasterTransaction
virtual TransactionMaster & getMasterTransaction()=0