rippled
RelationalDBInterface_nodes.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/RelationalDBInterface.h>
27 #include <ripple/app/rdb/RelationalDBInterface_nodes.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 
44 static std::string
46 {
47  static_assert(
48  TableTypeCount == 3,
49  "Need to modify switch statement if enum is modified");
50  switch (type)
51  {
52  case TableType::Ledgers:
53  return "Ledgers";
55  return "Transactions";
57  return "AccountTransactions";
58  default:
59  assert(0);
60  return "Unknown";
61  }
62 }
63 
64 DatabasePairValid
66  Config const& config,
67  DatabaseCon::Setup const& setup,
68  DatabaseCon::CheckpointerSetup const& checkpointerSetup)
69 {
70  // ledger database
71  auto lgr{std::make_unique<DatabaseCon>(
72  setup, LgrDBName, LgrDBPragma, LgrDBInit, checkpointerSetup)};
73  lgr->getSession() << boost::str(
74  boost::format("PRAGMA cache_size=-%d;") %
76 
77  if (config.useTxTables())
78  {
79  // transaction database
80  auto tx{std::make_unique<DatabaseCon>(
81  setup, TxDBName, TxDBPragma, TxDBInit, checkpointerSetup)};
82  tx->getSession() << boost::str(
83  boost::format("PRAGMA cache_size=-%d;") %
85 
86  if (!setup.standAlone || setup.startUp == Config::LOAD ||
87  setup.startUp == Config::LOAD_FILE ||
88  setup.startUp == Config::REPLAY)
89  {
90  // Check if AccountTransactions has primary key
91  std::string cid, name, type;
92  std::size_t notnull, dflt_value, pk;
93  soci::indicator ind;
94  soci::statement st =
95  (tx->getSession().prepare
96  << ("PRAGMA table_info(AccountTransactions);"),
97  soci::into(cid),
98  soci::into(name),
99  soci::into(type),
100  soci::into(notnull),
101  soci::into(dflt_value, ind),
102  soci::into(pk));
103 
104  st.execute();
105  while (st.fetch())
106  {
107  if (pk == 1)
108  {
109  return {std::move(lgr), std::move(tx), false};
110  }
111  }
112  }
113 
114  return {std::move(lgr), std::move(tx), true};
115  }
116  else
117  return {std::move(lgr), {}, true};
118 }
119 
121 getMinLedgerSeq(soci::session& session, TableType type)
122 {
123  std::string query = "SELECT MIN(LedgerSeq) FROM " + to_string(type) + ";";
124  // SOCI requires boost::optional (not std::optional) as the parameter.
125  boost::optional<LedgerIndex> m;
126  session << query, soci::into(m);
127  return m ? *m : std::optional<LedgerIndex>();
128 }
129 
131 getMaxLedgerSeq(soci::session& session, TableType type)
132 {
133  std::string query = "SELECT MAX(LedgerSeq) FROM " + to_string(type) + ";";
134  // SOCI requires boost::optional (not std::optional) as the parameter.
135  boost::optional<LedgerIndex> m;
136  session << query, soci::into(m);
137  return m ? *m : std::optional<LedgerIndex>();
138 }
139 
140 void
141 deleteByLedgerSeq(soci::session& session, TableType type, LedgerIndex ledgerSeq)
142 {
143  session << "DELETE FROM " << to_string(type)
144  << " WHERE LedgerSeq == " << ledgerSeq << ";";
145 }
146 
147 void
149  soci::session& session,
150  TableType type,
151  LedgerIndex ledgerSeq)
152 {
153  session << "DELETE FROM " << to_string(type) << " WHERE LedgerSeq < "
154  << ledgerSeq << ";";
155 }
156 
158 getRows(soci::session& session, TableType type)
159 {
160  std::size_t rows;
161  session << "SELECT COUNT(*) AS rows "
162  "FROM "
163  << to_string(type) << ";",
164  soci::into(rows);
165 
166  return rows;
167 }
168 
169 RelationalDBInterface::CountMinMax
170 getRowsMinMax(soci::session& session, TableType type)
171 {
173  session << "SELECT COUNT(*) AS rows, "
174  "MIN(LedgerSeq) AS first, "
175  "MAX(LedgerSeq) AS last "
176  "FROM "
177  << to_string(type) << ";",
178  soci::into(res.numberOfRows), soci::into(res.minLedgerSequence),
179  soci::into(res.maxLedgerSequence);
180 
181  return res;
182 }
183 
184 bool
186  DatabaseCon& ldgDB,
187  DatabaseCon& txnDB,
188  Application& app,
189  std::shared_ptr<Ledger const> const& ledger,
190  bool current)
191 {
192  auto j = app.journal("Ledger");
193  auto seq = ledger->info().seq;
194 
195  // TODO(tom): Fix this hard-coded SQL!
196  JLOG(j.trace()) << "saveValidatedLedger " << (current ? "" : "fromAcquire ")
197  << seq;
198 
199  if (!ledger->info().accountHash.isNonZero())
200  {
201  JLOG(j.fatal()) << "AH is zero: " << getJson({*ledger, {}});
202  assert(false);
203  }
204 
205  if (ledger->info().accountHash != ledger->stateMap().getHash().as_uint256())
206  {
207  JLOG(j.fatal()) << "sAL: " << ledger->info().accountHash
208  << " != " << ledger->stateMap().getHash();
209  JLOG(j.fatal()) << "saveAcceptedLedger: seq=" << seq
210  << ", current=" << current;
211  assert(false);
212  }
213 
214  assert(ledger->info().txHash == ledger->txMap().getHash().as_uint256());
215 
216  // Save the ledger header in the hashed object store
217  {
218  Serializer s(128);
220  addRaw(ledger->info(), s);
221  app.getNodeStore().store(
222  hotLEDGER, std::move(s.modData()), ledger->info().hash, seq);
223  }
224 
225  AcceptedLedger::pointer aLedger;
226  try
227  {
228  aLedger = app.getAcceptedLedgerCache().fetch(ledger->info().hash);
229  if (!aLedger)
230  {
231  aLedger = std::make_shared<AcceptedLedger>(ledger, app);
232  app.getAcceptedLedgerCache().canonicalize_replace_client(
233  ledger->info().hash, aLedger);
234  }
235  }
236  catch (std::exception const&)
237  {
238  JLOG(j.warn()) << "An accepted ledger was missing nodes";
239  app.getLedgerMaster().failedSave(seq, ledger->info().hash);
240  // Clients can now trust the database for information about this
241  // ledger sequence.
242  app.pendingSaves().finishWork(seq);
243  return false;
244  }
245 
246  {
247  static boost::format deleteLedger(
248  "DELETE FROM Ledgers WHERE LedgerSeq = %u;");
249  static boost::format deleteTrans1(
250  "DELETE FROM Transactions WHERE LedgerSeq = %u;");
251  static boost::format deleteTrans2(
252  "DELETE FROM AccountTransactions WHERE LedgerSeq = %u;");
253  static boost::format deleteAcctTrans(
254  "DELETE FROM AccountTransactions WHERE TransID = '%s';");
255 
256  {
257  auto db = ldgDB.checkoutDb();
258  *db << boost::str(deleteLedger % seq);
259  }
260 
261  if (app.config().useTxTables())
262  {
263  auto db = txnDB.checkoutDb();
264 
265  soci::transaction tr(*db);
266 
267  *db << boost::str(deleteTrans1 % seq);
268  *db << boost::str(deleteTrans2 % seq);
269 
270  std::string const ledgerSeq(std::to_string(seq));
271 
272  for (auto const& [_, acceptedLedgerTx] : aLedger->getMap())
273  {
274  (void)_;
275  uint256 transactionID = acceptedLedgerTx->getTransactionID();
276 
277  std::string const txnId(to_string(transactionID));
278  std::string const txnSeq(
279  std::to_string(acceptedLedgerTx->getTxnSeq()));
280 
281  *db << boost::str(deleteAcctTrans % transactionID);
282 
283  auto const& accts = acceptedLedgerTx->getAffected();
284 
285  if (!accts.empty())
286  {
287  std::string sql(
288  "INSERT INTO AccountTransactions "
289  "(TransID, Account, LedgerSeq, TxnSeq) VALUES ");
290 
291  // Try to make an educated guess on how much space we'll
292  // need for our arguments. In argument order we have: 64
293  // + 34 + 10 + 10 = 118 + 10 extra = 128 bytes
294  sql.reserve(sql.length() + (accts.size() * 128));
295 
296  bool first = true;
297  for (auto const& account : accts)
298  {
299  if (!first)
300  sql += ", ('";
301  else
302  {
303  sql += "('";
304  first = false;
305  }
306 
307  sql += txnId;
308  sql += "','";
309  sql += app.accountIDCache().toBase58(account);
310  sql += "',";
311  sql += ledgerSeq;
312  sql += ",";
313  sql += txnSeq;
314  sql += ")";
315  }
316  sql += ";";
317  JLOG(j.trace()) << "ActTx: " << sql;
318  *db << sql;
319  }
320  else if (auto const sleTxn = acceptedLedgerTx->getTxn();
321  !isPseudoTx(*sleTxn))
322  {
323  // It's okay for pseudo transactions to not affect any
324  // accounts. But otherwise...
325  JLOG(j.warn()) << "Transaction in ledger " << seq
326  << " affects no accounts";
327  JLOG(j.warn()) << sleTxn->getJson(JsonOptions::none);
328  }
329 
330  *db
332  acceptedLedgerTx->getTxn()->getMetaSQL(
333  seq, acceptedLedgerTx->getEscMeta()) +
334  ";");
335 
337  }
338 
339  tr.commit();
340  }
341 
342  {
343  static std::string addLedger(
344  R"sql(INSERT OR REPLACE INTO Ledgers
345  (LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,
346  CloseTimeRes,CloseFlags,AccountSetHash,TransSetHash)
347  VALUES
348  (:ledgerHash,:ledgerSeq,:prevHash,:totalCoins,:closingTime,:prevClosingTime,
349  :closeTimeRes,:closeFlags,:accountSetHash,:transSetHash);)sql");
350 
351  auto db(ldgDB.checkoutDb());
352 
353  soci::transaction tr(*db);
354 
355  auto const hash = to_string(ledger->info().hash);
356  auto const parentHash = to_string(ledger->info().parentHash);
357  auto const drops = to_string(ledger->info().drops);
358  auto const closeTime =
359  ledger->info().closeTime.time_since_epoch().count();
360  auto const parentCloseTime =
361  ledger->info().parentCloseTime.time_since_epoch().count();
362  auto const closeTimeResolution =
363  ledger->info().closeTimeResolution.count();
364  auto const closeFlags = ledger->info().closeFlags;
365  auto const accountHash = to_string(ledger->info().accountHash);
366  auto const txHash = to_string(ledger->info().txHash);
367 
368  *db << addLedger, soci::use(hash), soci::use(seq),
369  soci::use(parentHash), soci::use(drops), soci::use(closeTime),
370  soci::use(parentCloseTime), soci::use(closeTimeResolution),
371  soci::use(closeFlags), soci::use(accountHash),
372  soci::use(txHash);
373 
374  tr.commit();
375  }
376  }
377 
378  return true;
379 }
380 
391  soci::session& session,
392  std::string const& sqlSuffix,
393  beast::Journal j)
394 {
395  // SOCI requires boost::optional (not std::optional) as parameters.
396  boost::optional<std::string> hash, parentHash, accountHash, txHash;
397  boost::optional<std::uint64_t> seq, drops, closeTime, parentCloseTime,
398  closeTimeResolution, closeFlags;
399 
400  std::string const sql =
401  "SELECT "
402  "LedgerHash, PrevHash, AccountSetHash, TransSetHash, "
403  "TotalCoins,"
404  "ClosingTime, PrevClosingTime, CloseTimeRes, CloseFlags,"
405  "LedgerSeq FROM Ledgers " +
406  sqlSuffix + ";";
407 
408  session << sql, soci::into(hash), soci::into(parentHash),
409  soci::into(accountHash), soci::into(txHash), soci::into(drops),
410  soci::into(closeTime), soci::into(parentCloseTime),
411  soci::into(closeTimeResolution), soci::into(closeFlags),
412  soci::into(seq);
413 
414  if (!session.got_data())
415  {
416  JLOG(j.debug()) << "Ledger not found: " << sqlSuffix;
417  return {};
418  }
419 
420  using time_point = NetClock::time_point;
421  using duration = NetClock::duration;
422 
423  LedgerInfo info;
424 
425  if (hash && !info.hash.parseHex(*hash))
426  {
427  JLOG(j.debug()) << "Hash parse error for ledger: " << sqlSuffix;
428  return {};
429  }
430 
431  if (parentHash && !info.parentHash.parseHex(*parentHash))
432  {
433  JLOG(j.debug()) << "parentHash parse error for ledger: " << sqlSuffix;
434  return {};
435  }
436 
437  if (accountHash && !info.accountHash.parseHex(*accountHash))
438  {
439  JLOG(j.debug()) << "accountHash parse error for ledger: " << sqlSuffix;
440  return {};
441  }
442 
443  if (txHash && !info.txHash.parseHex(*txHash))
444  {
445  JLOG(j.debug()) << "txHash parse error for ledger: " << sqlSuffix;
446  return {};
447  }
448 
449  info.seq = rangeCheckedCast<std::uint32_t>(seq.value_or(0));
450  info.drops = drops.value_or(0);
451  info.closeTime = time_point{duration{closeTime.value_or(0)}};
452  info.parentCloseTime = time_point{duration{parentCloseTime.value_or(0)}};
453  info.closeFlags = closeFlags.value_or(0);
454  info.closeTimeResolution = duration{closeTimeResolution.value_or(0)};
455 
456  return info;
457 }
458 
461  soci::session& session,
462  LedgerIndex ledgerSeq,
463  beast::Journal j)
464 {
466  s << "WHERE LedgerSeq = " << ledgerSeq;
467  return getLedgerInfo(session, s.str(), j);
468 }
469 
471 getNewestLedgerInfo(soci::session& session, beast::Journal j)
472 {
474  s << "ORDER BY LedgerSeq DESC LIMIT 1";
475  return getLedgerInfo(session, s.str(), j);
476 }
477 
480  soci::session& session,
481  LedgerIndex ledgerFirstIndex,
482  beast::Journal j)
483 {
485  s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
486  " ORDER BY LedgerSeq ASC LIMIT 1";
487  return getLedgerInfo(session, s.str(), j);
488 }
489 
492  soci::session& session,
493  LedgerIndex ledgerFirstIndex,
494  beast::Journal j)
495 {
497  s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
498  " ORDER BY LedgerSeq DESC LIMIT 1";
499  return getLedgerInfo(session, s.str(), j);
500 }
501 
504  soci::session& session,
505  uint256 const& ledgerHash,
506  beast::Journal j)
507 {
509  s << "WHERE LedgerHash = '" << ledgerHash << "'";
510  return getLedgerInfo(session, s.str(), j);
511 }
512 
513 uint256
514 getHashByIndex(soci::session& session, LedgerIndex ledgerIndex)
515 {
516  uint256 ret;
517 
518  std::string sql =
519  "SELECT LedgerHash FROM Ledgers INDEXED BY SeqLedger WHERE LedgerSeq='";
520  sql.append(beast::lexicalCastThrow<std::string>(ledgerIndex));
521  sql.append("';");
522 
523  std::string hash;
524  {
525  // SOCI requires boost::optional (not std::optional) as the parameter.
526  boost::optional<std::string> lh;
527  session << sql, soci::into(lh);
528 
529  if (!session.got_data() || !lh)
530  return ret;
531 
532  hash = *lh;
533  if (hash.empty())
534  return ret;
535  }
536 
537  if (!ret.parseHex(hash))
538  return ret;
539 
540  return ret;
541 }
542 
545  soci::session& session,
546  LedgerIndex ledgerIndex,
547  beast::Journal j)
548 {
549  // SOCI requires boost::optional (not std::optional) as the parameter.
550  boost::optional<std::string> lhO, phO;
551 
552  session << "SELECT LedgerHash,PrevHash FROM Ledgers "
553  "INDEXED BY SeqLedger WHERE LedgerSeq = :ls;",
554  soci::into(lhO), soci::into(phO), soci::use(ledgerIndex);
555 
556  if (!lhO || !phO)
557  {
558  auto stream = j.trace();
559  JLOG(stream) << "Don't have ledger " << ledgerIndex;
560  return {};
561  }
562 
563  LedgerHashPair hashes;
564  if (!hashes.ledgerHash.parseHex(*lhO) || !hashes.parentHash.parseHex(*phO))
565  {
566  auto stream = j.trace();
567  JLOG(stream) << "Error parse hashes for ledger " << ledgerIndex;
568  return {};
569  }
570 
571  return hashes;
572 }
573 
576  soci::session& session,
577  LedgerIndex minSeq,
578  LedgerIndex maxSeq,
579  beast::Journal j)
580 {
581  std::string sql =
582  "SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq >= ";
583  sql.append(beast::lexicalCastThrow<std::string>(minSeq));
584  sql.append(" AND LedgerSeq <= ");
585  sql.append(beast::lexicalCastThrow<std::string>(maxSeq));
586  sql.append(";");
587 
588  std::uint64_t ls;
589  std::string lh;
590  // SOCI requires boost::optional (not std::optional) as the parameter.
591  boost::optional<std::string> ph;
592  soci::statement st =
593  (session.prepare << sql,
594  soci::into(ls),
595  soci::into(lh),
596  soci::into(ph));
597 
598  st.execute();
600  while (st.fetch())
601  {
602  LedgerHashPair& hashes = res[rangeCheckedCast<LedgerIndex>(ls)];
603  if (!hashes.ledgerHash.parseHex(lh))
604  {
605  JLOG(j.warn()) << "Error parsed hash for ledger seq: " << ls;
606  }
607  if (!ph)
608  {
609  JLOG(j.warn()) << "Null prev hash for ledger seq: " << ls;
610  }
611  else if (!hashes.parentHash.parseHex(*ph))
612  {
613  JLOG(j.warn()) << "Error parsed prev hash for ledger seq: " << ls;
614  }
615  }
616  return res;
617 }
618 
621  soci::session& session,
622  Application& app,
623  LedgerIndex startIndex,
624  int quantity,
625  bool count)
626 {
627  std::string sql = boost::str(
628  boost::format(
629  "SELECT LedgerSeq, Status, RawTxn "
630  "FROM Transactions ORDER BY LedgerSeq DESC LIMIT %u,%u;") %
631  startIndex % quantity);
632 
634  int total = 0;
635 
636  {
637  // SOCI requires boost::optional (not std::optional) as parameters.
638  boost::optional<std::uint64_t> ledgerSeq;
639  boost::optional<std::string> status;
640  soci::blob sociRawTxnBlob(session);
641  soci::indicator rti;
642  Blob rawTxn;
643 
644  soci::statement st =
645  (session.prepare << sql,
646  soci::into(ledgerSeq),
647  soci::into(status),
648  soci::into(sociRawTxnBlob, rti));
649 
650  st.execute();
651  while (st.fetch())
652  {
653  if (soci::i_ok == rti)
654  convert(sociRawTxnBlob, rawTxn);
655  else
656  rawTxn.clear();
657 
658  if (auto trans = Transaction::transactionFromSQL(
659  ledgerSeq, status, rawTxn, app))
660  {
661  total++;
662  txs.push_back(trans);
663  }
664  }
665 
666  if (!total && count)
667  {
668  session << "SELECT COUNT(*) FROM Transactions;", soci::into(total);
669 
670  total = -total;
671  }
672  }
673 
674  return {txs, total};
675 }
676 
696 static std::string
698  Application& app,
699  std::string selection,
700  RelationalDBInterface::AccountTxOptions const& options,
701  std::optional<int> const& limit_used,
702  bool descending,
703  bool binary,
704  bool count,
705  beast::Journal j)
706 {
707  constexpr std::uint32_t NONBINARY_PAGE_LENGTH = 200;
708  constexpr std::uint32_t BINARY_PAGE_LENGTH = 500;
709 
710  std::uint32_t numberOfResults;
711 
712  if (count)
713  {
714  numberOfResults = std::numeric_limits<std::uint32_t>::max();
715  }
716  else if (options.limit == UINT32_MAX)
717  {
718  numberOfResults = binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH;
719  }
720  else if (!options.bUnlimited)
721  {
722  numberOfResults = std::min(
723  binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH, options.limit);
724  }
725  else
726  {
727  numberOfResults = options.limit;
728  }
729 
730  if (limit_used)
731  {
732  if (numberOfResults <= *limit_used)
733  return "";
734  else
735  numberOfResults -= *limit_used;
736  }
737 
738  std::string maxClause = "";
739  std::string minClause = "";
740 
741  if (options.maxLedger)
742  {
743  maxClause = boost::str(
744  boost::format("AND AccountTransactions.LedgerSeq <= '%u'") %
745  options.maxLedger);
746  }
747 
748  if (options.minLedger)
749  {
750  minClause = boost::str(
751  boost::format("AND AccountTransactions.LedgerSeq >= '%u'") %
752  options.minLedger);
753  }
754 
755  std::string sql;
756 
757  if (count)
758  sql = boost::str(
759  boost::format("SELECT %s FROM AccountTransactions "
760  "WHERE Account = '%s' %s %s LIMIT %u, %u;") %
761  selection % app.accountIDCache().toBase58(options.account) %
762  maxClause % minClause %
763  beast::lexicalCastThrow<std::string>(options.offset) %
764  beast::lexicalCastThrow<std::string>(numberOfResults));
765  else
766  sql = boost::str(
767  boost::format(
768  "SELECT %s FROM "
769  "AccountTransactions INNER JOIN Transactions "
770  "ON Transactions.TransID = AccountTransactions.TransID "
771  "WHERE Account = '%s' %s %s "
772  "ORDER BY AccountTransactions.LedgerSeq %s, "
773  "AccountTransactions.TxnSeq %s, AccountTransactions.TransID %s "
774  "LIMIT %u, %u;") %
775  selection % app.accountIDCache().toBase58(options.account) %
776  maxClause % minClause % (descending ? "DESC" : "ASC") %
777  (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") %
778  beast::lexicalCastThrow<std::string>(options.offset) %
779  beast::lexicalCastThrow<std::string>(numberOfResults));
780  JLOG(j.trace()) << "txSQL query: " << sql;
781  return sql;
782 }
783 
809  soci::session& session,
810  Application& app,
811  LedgerMaster& ledgerMaster,
812  RelationalDBInterface::AccountTxOptions const& options,
813  std::optional<int> const& limit_used,
814  bool descending,
815  beast::Journal j)
816 {
818 
820  app,
821  "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
822  options,
823  limit_used,
824  descending,
825  false,
826  false,
827  j);
828  if (sql == "")
829  return {ret, 0};
830 
831  int total = 0;
832  {
833  // SOCI requires boost::optional (not std::optional) as parameters.
834  boost::optional<std::uint64_t> ledgerSeq;
835  boost::optional<std::string> status;
836  soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
837  soci::indicator rti, tmi;
838  Blob rawTxn, txnMeta;
839 
840  soci::statement st =
841  (session.prepare << sql,
842  soci::into(ledgerSeq),
843  soci::into(status),
844  soci::into(sociTxnBlob, rti),
845  soci::into(sociTxnMetaBlob, tmi));
846 
847  st.execute();
848  while (st.fetch())
849  {
850  if (soci::i_ok == rti)
851  convert(sociTxnBlob, rawTxn);
852  else
853  rawTxn.clear();
854 
855  if (soci::i_ok == tmi)
856  convert(sociTxnMetaBlob, txnMeta);
857  else
858  txnMeta.clear();
859 
860  auto txn =
861  Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
862 
863  if (txnMeta.empty())
864  { // Work around a bug that could leave the metadata missing
865  auto const seq =
866  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
867 
868  JLOG(j.warn())
869  << "Recovering ledger " << seq << ", txn " << txn->getID();
870 
871  if (auto l = ledgerMaster.getLedgerBySeq(seq))
872  pendSaveValidated(app, l, false, false);
873  }
874 
875  if (txn)
876  {
877  ret.emplace_back(
878  txn,
879  std::make_shared<TxMeta>(
880  txn->getID(), txn->getLedger(), txnMeta));
881  total++;
882  }
883  }
884 
885  if (!total && limit_used)
886  {
887  RelationalDBInterface::AccountTxOptions opt = options;
888  opt.offset = 0;
890  app, "COUNT(*)", opt, limit_used, descending, false, false, j);
891 
892  session << sql1, soci::into(total);
893 
894  total = -total;
895  }
896  }
897 
898  return {ret, total};
899 }
900 
903  soci::session& session,
904  Application& app,
905  LedgerMaster& ledgerMaster,
906  RelationalDBInterface::AccountTxOptions const& options,
907  std::optional<int> const& limit_used,
908  beast::Journal j)
909 {
911  session, app, ledgerMaster, options, limit_used, false, j);
912 }
913 
916  soci::session& session,
917  Application& app,
918  LedgerMaster& ledgerMaster,
919  RelationalDBInterface::AccountTxOptions const& options,
920  std::optional<int> const& limit_used,
921  beast::Journal j)
922 {
923  return getAccountTxs(
924  session, app, ledgerMaster, options, limit_used, true, j);
925 }
926 
952  soci::session& session,
953  Application& app,
954  RelationalDBInterface::AccountTxOptions const& options,
955  std::optional<int> const& limit_used,
956  bool descending,
957  beast::Journal j)
958 {
960 
962  app,
963  "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
964  options,
965  limit_used,
966  descending,
967  true /*binary*/,
968  false,
969  j);
970  if (sql == "")
971  return {ret, 0};
972 
973  int total = 0;
974 
975  {
976  // SOCI requires boost::optional (not std::optional) as parameters.
977  boost::optional<std::uint64_t> ledgerSeq;
978  boost::optional<std::string> status;
979  soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
980  soci::indicator rti, tmi;
981 
982  soci::statement st =
983  (session.prepare << sql,
984  soci::into(ledgerSeq),
985  soci::into(status),
986  soci::into(sociTxnBlob, rti),
987  soci::into(sociTxnMetaBlob, tmi));
988 
989  st.execute();
990  while (st.fetch())
991  {
992  Blob rawTxn;
993  if (soci::i_ok == rti)
994  convert(sociTxnBlob, rawTxn);
995  Blob txnMeta;
996  if (soci::i_ok == tmi)
997  convert(sociTxnMetaBlob, txnMeta);
998 
999  auto const seq =
1000  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
1001 
1002  ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq);
1003  total++;
1004  }
1005 
1006  if (!total && limit_used)
1007  {
1008  RelationalDBInterface::AccountTxOptions opt = options;
1009  opt.offset = 0;
1011  app, "COUNT(*)", opt, limit_used, descending, true, false, j);
1012 
1013  session << sql1, soci::into(total);
1014 
1015  total = -total;
1016  }
1017  }
1019  return {ret, total};
1020 }
1021 
1024  soci::session& session,
1025  Application& app,
1026  RelationalDBInterface::AccountTxOptions const& options,
1027  std::optional<int> const& limit_used,
1028  beast::Journal j)
1030  return getAccountTxsB(session, app, options, limit_used, false, j);
1031 }
1032 
1035  soci::session& session,
1036  Application& app,
1037  RelationalDBInterface::AccountTxOptions const& options,
1038  std::optional<int> const& limit_used,
1039  beast::Journal j)
1040 {
1041  return getAccountTxsB(session, app, options, limit_used, true, j);
1042 }
1043 
1068  soci::session& session,
1069  AccountIDCache const& idCache,
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  RelationalDBInterface::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  idCache.toBase58(options.account) % options.minLedger %
1136  options.maxLedger % 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 = idCache.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};
1245 }
1246 
1249  soci::session& session,
1250  AccountIDCache const& idCache,
1251  std::function<void(std::uint32_t)> const& onUnsavedLedger,
1252  std::function<
1253  void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1254  onTransaction,
1256  int limit_used,
1257  std::uint32_t page_length)
1258 {
1259  return accountTxPage(
1260  session,
1261  idCache,
1262  onUnsavedLedger,
1263  onTransaction,
1264  options,
1265  limit_used,
1266  page_length,
1267  true);
1268 }
1269 
1272  soci::session& session,
1273  AccountIDCache const& idCache,
1274  std::function<void(std::uint32_t)> const& onUnsavedLedger,
1275  std::function<
1276  void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1277  onTransaction,
1279  int limit_used,
1280  std::uint32_t page_length)
1281 {
1282  return accountTxPage(
1283  session,
1284  idCache,
1285  onUnsavedLedger,
1286  onTransaction,
1287  options,
1288  limit_used,
1289  page_length,
1290  false);
1291 }
1292 
1295  soci::session& session,
1296  Application& app,
1297  uint256 const& id,
1298  std::optional<ClosedInterval<uint32_t>> const& range,
1299  error_code_i& ec)
1300 {
1301  std::string sql =
1302  "SELECT LedgerSeq,Status,RawTxn,TxnMeta "
1303  "FROM Transactions WHERE TransID='";
1304 
1305  sql.append(to_string(id));
1306  sql.append("';");
1307 
1308  // SOCI requires boost::optional (not std::optional) as parameters.
1309  boost::optional<std::uint64_t> ledgerSeq;
1310  boost::optional<std::string> status;
1311  Blob rawTxn, rawMeta;
1312  {
1313  soci::blob sociRawTxnBlob(session), sociRawMetaBlob(session);
1314  soci::indicator txn, meta;
1315 
1316  session << sql, soci::into(ledgerSeq), soci::into(status),
1317  soci::into(sociRawTxnBlob, txn), soci::into(sociRawMetaBlob, meta);
1318 
1319  auto const got_data = session.got_data();
1320 
1321  if ((!got_data || txn != soci::i_ok || meta != soci::i_ok) && !range)
1322  return TxSearched::unknown;
1323 
1324  if (!got_data)
1325  {
1326  uint64_t count = 0;
1327  soci::indicator rti;
1328 
1329  session
1330  << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
1331  "LedgerSeq BETWEEN "
1332  << range->first() << " AND " << range->last() << ";",
1333  soci::into(count, rti);
1334 
1335  if (!session.got_data() || rti != soci::i_ok)
1336  return TxSearched::some;
1337 
1338  return count == (range->last() - range->first() + 1)
1339  ? TxSearched::all
1340  : TxSearched::some;
1341  }
1342 
1343  convert(sociRawTxnBlob, rawTxn);
1344  convert(sociRawMetaBlob, rawMeta);
1345  }
1346 
1347  try
1348  {
1349  auto txn =
1350  Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
1352  if (!ledgerSeq)
1353  return std::pair{std::move(txn), nullptr};
1354 
1355  std::uint32_t inLedger =
1356  rangeCheckedCast<std::uint32_t>(ledgerSeq.value());
1357 
1358  auto txMeta = std::make_shared<TxMeta>(id, inLedger, rawMeta);
1359 
1360  return std::pair{std::move(txn), std::move(txMeta)};
1361  }
1362  catch (std::exception& e)
1363  {
1364  JLOG(app.journal("Ledger").warn())
1365  << "Unable to deserialize transaction from raw SQL value. Error: "
1366  << e.what();
1367 
1368  ec = rpcDB_DESERIALIZATION;
1369  }
1370 
1371  return TxSearched::unknown;
1372 }
1373 
1374 bool
1375 dbHasSpace(soci::session& session, Config const& config, beast::Journal j)
1376 {
1377  boost::filesystem::space_info space =
1378  boost::filesystem::space(config.legacy("database_path"));
1379 
1380  if (space.available < megabytes(512))
1381  {
1382  JLOG(j.fatal()) << "Remaining free disk space is less than 512MB";
1383  return false;
1384  }
1385 
1386  if (config.useTxTables())
1387  {
1388  DatabaseCon::Setup dbSetup = setup_DatabaseCon(config);
1389  boost::filesystem::path dbPath = dbSetup.dataDir / TxDBName;
1390  boost::system::error_code ec;
1392  boost::filesystem::file_size(dbPath, ec);
1393  if (ec)
1394  {
1395  JLOG(j.error())
1396  << "Error checking transaction db file size: " << ec.message();
1397  dbSize.reset();
1398  }
1399 
1400  static auto const pageSize = [&] {
1401  std::uint32_t ps;
1402  session << "PRAGMA page_size;", soci::into(ps);
1403  return ps;
1404  }();
1405  static auto const maxPages = [&] {
1406  std::uint32_t mp;
1407  session << "PRAGMA max_page_count;", soci::into(mp);
1408  return mp;
1409  }();
1410  std::uint32_t pageCount;
1411  session << "PRAGMA page_count;", soci::into(pageCount);
1412  std::uint32_t freePages = maxPages - pageCount;
1413  std::uint64_t freeSpace =
1414  safe_cast<std::uint64_t>(freePages) * pageSize;
1415  JLOG(j.info())
1416  << "Transaction DB pathname: " << dbPath.string()
1417  << "; file size: " << dbSize.value_or(-1) << " bytes"
1418  << "; SQLite page size: " << pageSize << " bytes"
1419  << "; Free pages: " << freePages << "; Free space: " << freeSpace
1420  << " bytes; "
1421  << "Note that this does not take into account available disk "
1422  "space.";
1423 
1424  if (freeSpace < megabytes(512))
1425  {
1426  JLOG(j.fatal())
1427  << "Free SQLite space for transaction db is less than "
1428  "512MB. To fix this, rippled must be executed with the "
1429  "vacuum parameter before restarting. "
1430  "Note that this activity can take multiple days, "
1431  "depending on database size.";
1432  return false;
1433  }
1434  }
1435 
1436  return true;
1437 }
1438 
1439 } // namespace ripple
beast::Journal::fatal
Stream fatal() const
Definition: Journal.h:339
ripple::getLedgerInfoByIndex
std::optional< LedgerInfo > getLedgerInfoByIndex(soci::session &session, LedgerIndex ledgerSeq, beast::Journal j)
getLedgerInfoByIndex Returns ledger by its sequence.
Definition: RelationalDBInterface_nodes.cpp:455
ripple::Application
Definition: Application.h:115
ripple::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: RelationalDBInterface_nodes.cpp:148
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:93
ripple::rpcDB_DESERIALIZATION
@ rpcDB_DESERIALIZATION
Definition: ErrorCodes.h:134
ripple::HashPrefix::ledgerMaster
@ ledgerMaster
ledger master data for signing
ripple::Blob
std::vector< unsigned char > Blob
Storage for linear binary data.
Definition: Blob.h:30
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:57
std::string
STL class.
std::shared_ptr
STL class.
ripple::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: RelationalDBInterface_nodes.cpp:615
ripple::LedgerInfo::parentHash
uint256 parentHash
Definition: ReadView.h:103
ripple::getHashByIndex
uint256 getHashByIndex(soci::session &session, LedgerIndex ledgerIndex)
getHashByIndex Returns hash of ledger with given sequence.
Definition: RelationalDBInterface_nodes.cpp:509
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:845
ripple::getOldestAccountTxs
std::pair< RelationalDBInterface::AccountTxs, int > getOldestAccountTxs(soci::session &session, Application &app, LedgerMaster &ledgerMaster, RelationalDBInterface::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: RelationalDBInterface_nodes.cpp:897
std::exception
STL class.
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:516
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
ripple::getAccountTxs
static std::pair< RelationalDBInterface::AccountTxs, int > getAccountTxs(soci::session &session, Application &app, LedgerMaster &ledgerMaster, RelationalDBInterface::AccountTxOptions const &options, std::optional< int > const &limit_used, bool descending, beast::Journal j)
getAccountTxs Returns oldest or newest transactions for given account which match given criteria star...
Definition: RelationalDBInterface_nodes.cpp:803
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:309
Json::stream
void stream(Json::Value const &jv, Write const &write)
Stream compact JSON to the specified function.
Definition: json_writer.h:300
ripple::getOldestAccountTxsB
std::pair< std::vector< RelationalDBInterface::txnMetaLedgerType >, int > getOldestAccountTxsB(soci::session &session, Application &app, RelationalDBInterface::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: RelationalDBInterface_nodes.cpp:1018
ripple::Serializer::modData
Blob & modData()
Definition: Serializer.h:178
std::pair
std::string::reserve
T reserve(T... args)
ripple::LedgerInfo::hash
uint256 hash
Definition: ReadView.h:100
ripple::TxSearched::all
@ all
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:164
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)
std::optional::value_or
T value_or(T... args)
ripple::getRowsMinMax
RelationalDBInterface::CountMinMax getRowsMinMax(soci::session &session, TableType type)
getRowsMinMax Returns minumum ledger sequence, maximum ledger sequence and total number of rows in gi...
Definition: RelationalDBInterface_nodes.cpp:170
ripple::DatabaseCon::CheckpointerSetup
Definition: DatabaseCon.h:107
ripple::newestAccountTxPage
std::pair< std::optional< RelationalDBInterface::AccountTxMarker >, int > newestAccountTxPage(soci::session &session, AccountIDCache const &idCache, std::function< void(std::uint32_t)> const &onUnsavedLedger, std::function< void(std::uint32_t, std::string const &, Blob &&, Blob &&)> const &onTransaction, RelationalDBInterface::AccountTxPageOptions const &options, int limit_used, std::uint32_t page_length)
newestAccountTxPage Searches newest transactions for given account which match given criteria startin...
Definition: RelationalDBInterface_nodes.cpp:1247
ripple::getLedgerInfoByHash
std::optional< LedgerInfo > getLedgerInfoByHash(soci::session &session, uint256 const &ledgerHash, beast::Journal j)
getLedgerInfoByHash Returns info of ledger with given hash.
Definition: RelationalDBInterface_nodes.cpp:498
ripple::Config::LOAD
@ LOAD
Definition: Config.h:132
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::kilobytes
constexpr auto kilobytes(T value) noexcept
Definition: ByteUtilities.h:27
ripple::STTx::getMetaSQLInsertReplaceHeader
static std::string const & getMetaSQLInsertReplaceHeader()
Definition: STTx.cpp:248
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::LedgerInfo::seq
LedgerIndex seq
Definition: ReadView.h:92
ripple::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: RelationalDBInterface_nodes.cpp:486
ripple::LedgerInfo::txHash
uint256 txHash
Definition: ReadView.h:101
std::optional::reset
T reset(T... args)
ripple::LgrDBInit
constexpr std::array< char const *, 5 > LgrDBInit
Definition: DBInit.h:48
ripple::AccountIDCache
Caches the base58 representations of AccountIDs.
Definition: AccountID.h:118
ripple::error_code_i
error_code_i
Definition: ErrorCodes.h:40
ripple::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: RelationalDBInterface_nodes.cpp:474
ripple::Application::accountIDCache
virtual AccountIDCache const & accountIDCache() const =0
ripple::getLedgerInfo
static std::optional< LedgerInfo > getLedgerInfo(soci::session &session, std::string const &sqlSuffix, beast::Journal j)
getLedgerInfo Returns info of ledger with special condition given as SQL query.
Definition: RelationalDBInterface_nodes.cpp:385
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:529
std::vector::push_back
T push_back(T... args)
ripple::getNewestAccountTxs
std::pair< RelationalDBInterface::AccountTxs, int > getNewestAccountTxs(soci::session &session, Application &app, LedgerMaster &ledgerMaster, RelationalDBInterface::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: RelationalDBInterface_nodes.cpp:910
ripple::LedgerInfo::closeTime
NetClock::time_point closeTime
Definition: ReadView.h:123
ripple::RelationalDBInterface::CountMinMax
Definition: RelationalDBInterface.h:51
ripple::TxDBName
constexpr auto TxDBName
Definition: DBInit.h:73
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:75
ripple::Ledger::info
LedgerInfo const & info() const override
Returns information about the ledger.
Definition: Ledger.h:148
std::chrono::time_point::time_since_epoch
T time_since_epoch(T... args)
ripple::isPseudoTx
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition: STTx.cpp:554
ripple::saveValidatedLedger
static bool saveValidatedLedger(Application &app, std::shared_ptr< Ledger const > const &ledger, bool current)
Definition: Ledger.cpp:919
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:990
ripple::DatabaseCon::checkoutDb
LockedSociSession checkoutDb()
Definition: DatabaseCon.h:178
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:962
ripple::Application::getLedgerMaster
virtual LedgerMaster & getLedgerMaster()=0
ripple::Config
Definition: Config.h:68
ripple::Application::pendingSaves
virtual PendingSaves & pendingSaves()=0
std::forward
T forward(T... args)
ripple::compare
int compare(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:533
ripple::JsonOptions::none
@ none
ripple::Application::config
virtual Config & config()=0
ripple::megabytes
constexpr auto megabytes(T value) noexcept
Definition: ByteUtilities.h:34
ripple::Ledger::stateMap
SHAMap const & stateMap() const
Definition: Ledger.h:307
ripple::Config::useTxTables
bool useTxTables() const
Definition: Config.h:322
ripple::LedgerInfo::closeFlags
int closeFlags
Definition: ReadView.h:114
std::to_string
T to_string(T... args)
ripple::deleteByLedgerSeq
void deleteByLedgerSeq(soci::session &session, TableType type, LedgerIndex ledgerSeq)
deleteByLedgerSeq Deletes all entries in given table for the ledger with given sequence.
Definition: RelationalDBInterface_nodes.cpp:141
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::TableType::Transactions
@ Transactions
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
std::map
STL class.
ripple::range
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition: RangeSet.h:53
ripple::getAccountTxsB
static std::pair< std::vector< RelationalDBInterface::txnMetaLedgerType >, int > getAccountTxsB(soci::session &session, Application &app, RelationalDBInterface::AccountTxOptions const &options, std::optional< int > const &limit_used, bool descending, beast::Journal j)
getAccountTxsB Returns oldest or newset transactions in binary form for given account which match giv...
Definition: RelationalDBInterface_nodes.cpp:946
ripple::SizedItem::txnDBCache
@ txnDBCache
ripple::RelationalDBInterface::CountMinMax::maxLedgerSequence
LedgerIndex maxLedgerSequence
Definition: RelationalDBInterface.h:55
std::string::append
T append(T... args)
ripple::TableType::Ledgers
@ Ledgers
ripple::LedgerInfo::drops
XRPAmount drops
Definition: ReadView.h:105
std::experimental::filesystem::status
T status(T... args)
ripple::TableType::AccountTransactions
@ AccountTransactions
std::experimental::filesystem::space
T space(T... args)
std::min
T min(T... args)
ripple::getNewestAccountTxsB
std::pair< std::vector< RelationalDBInterface::txnMetaLedgerType >, int > getNewestAccountTxsB(soci::session &session, Application &app, RelationalDBInterface::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: RelationalDBInterface_nodes.cpp:1029
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:291
std::ostringstream
STL class.
ripple::Ledger::txMap
SHAMap const & txMap() const
Definition: Ledger.h:319
ripple::TransactionMaster::inLedger
bool inLedger(uint256 const &hash, std::uint32_t ledger)
Definition: TransactionMaster.cpp:40
ripple::TableTypeCount
constexpr int TableTypeCount
Definition: RelationalDBInterface_nodes.h:35
std::vector::emplace_back
T emplace_back(T... args)
ripple::getTransaction
std::variant< RelationalDBInterface::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: RelationalDBInterface_nodes.cpp:1270
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::getRows
std::size_t getRows(soci::session &session, TableType type)
getRows Returns number of rows in given table.
Definition: RelationalDBInterface_nodes.cpp:158
ripple::Application::getNodeStore
virtual NodeStore::Database & getNodeStore()=0
ripple::Application::journal
virtual beast::Journal journal(std::string const &name)=0
ripple::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: RelationalDBInterface_nodes.cpp:539
ripple::RelationalDBInterface::CountMinMax::minLedgerSequence
LedgerIndex minLedgerSequence
Definition: RelationalDBInterface.h:54
ripple::LedgerInfo::closeTimeResolution
NetClock::duration closeTimeResolution
Definition: ReadView.h:117
ripple::Config::REPLAY
@ REPLAY
Definition: Config.h:132
ripple::DatabaseCon
Definition: DatabaseCon.h:81
ripple::TxDBPragma
constexpr std::array TxDBPragma
Definition: DBInit.h:76
std::chrono::duration::count
T count(T... args)
ripple::makeLedgerDBs
DatabasePairValid makeLedgerDBs(Config const &config, DatabaseCon::Setup const &setup, DatabaseCon::CheckpointerSetup const &checkpointerSetup)
makeLedgerDBs Opens ledger and transactions databases.
Definition: RelationalDBInterface_nodes.cpp:65
ripple::oldestAccountTxPage
std::pair< std::optional< RelationalDBInterface::AccountTxMarker >, int > oldestAccountTxPage(soci::session &session, AccountIDCache const &idCache, std::function< void(std::uint32_t)> const &onUnsavedLedger, std::function< void(std::uint32_t, std::string const &, Blob &&, Blob &&)> const &onTransaction, RelationalDBInterface::AccountTxPageOptions const &options, int limit_used, std::uint32_t page_length)
oldestAccountTxPage Searches oldest transactions for given account which match given criteria startin...
Definition: RelationalDBInterface_nodes.cpp:1224
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::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:38
ripple::hotLEDGER
@ hotLEDGER
Definition: NodeObject.h:34
ripple::Serializer::add32
int add32(std::uint32_t i)
Definition: Serializer.cpp:38
ripple::RelationalDBInterface::AccountTxPageOptions
Definition: RelationalDBInterface.h:74
ripple::transactionsSQL
static std::string transactionsSQL(Application &app, std::string selection, RelationalDBInterface::AccountTxOptions const &options, std::optional< int > const &limit_used, bool descending, bool binary, bool count, beast::Journal j)
transactionsSQL Returns SQL query to select oldest or newest transactions in decoded or binary form f...
Definition: RelationalDBInterface_nodes.cpp:692
ripple::NetClock::duration
std::chrono::duration< rep, period > duration
Definition: chrono.h:55
ripple::RelationalDBInterface::CountMinMax::numberOfRows
std::size_t numberOfRows
Definition: RelationalDBInterface.h:53
ripple::SHAMapHash::as_uint256
uint256 const & as_uint256() const
Definition: SHAMapHash.h:43
ripple::TxDBInit
constexpr std::array< char const *, 8 > TxDBInit
Definition: DBInit.h:84
std::numeric_limits::max
T max(T... args)
ripple::TableType
TableType
Definition: RelationalDBInterface_nodes.h:34
ripple::dbHasSpace
bool dbHasSpace(soci::session &session, Config const &config, beast::Journal j)
dbHasSpace Checks if given database has available space.
Definition: RelationalDBInterface_nodes.cpp:1351
ripple::getMinLedgerSeq
std::optional< LedgerIndex > getMinLedgerSeq(soci::session &session, TableType type)
getMinLedgerSeq Returns minimum ledger sequence in given table.
Definition: RelationalDBInterface_nodes.cpp:121
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:947
ripple::accountTxPage
static std::pair< std::optional< RelationalDBInterface::AccountTxMarker >, int > accountTxPage(soci::session &session, AccountIDCache const &idCache, std::function< void(std::uint32_t)> const &onUnsavedLedger, std::function< void(std::uint32_t, std::string const &, Blob &&, Blob &&)> const &onTransaction, RelationalDBInterface::AccountTxPageOptions const &options, int limit_used, std::uint32_t page_length, bool forward)
accountTxPage Searches oldest or newest transactions for given account which match given criteria sta...
Definition: RelationalDBInterface_nodes.cpp:1062
ripple::NetClock::time_point
std::chrono::time_point< NetClock > time_point
Definition: chrono.h:56
ripple::Config::LOAD_FILE
@ LOAD_FILE
Definition: Config.h:132
ripple::getNewestLedgerInfo
std::optional< LedgerInfo > getNewestLedgerInfo(soci::session &session, beast::Journal j)
getNewestLedgerInfo Returns info of newest saved ledger.
Definition: RelationalDBInterface_nodes.cpp:466
ripple::LedgerInfo::accountHash
uint256 accountHash
Definition: ReadView.h:102
ripple::getMaxLedgerSeq
std::optional< LedgerIndex > getMaxLedgerSeq(soci::session &session, TableType type)
getMaxLedgerSeq Returns maximum ledger sequence in given table.
Definition: RelationalDBInterface_nodes.cpp:131
std::exception::what
T what(T... args)
ripple::TxSearched::some
@ some
std::variant
ripple::AccountIDCache::toBase58
std::string toBase58(AccountID const &) const
Return ripple::toBase58 for the AccountID.
Definition: AccountID.cpp:134
ripple::RelationalDBInterface::AccountTxs
std::vector< AccountTx > AccountTxs
Definition: RelationalDBInterface.h:86
ripple::LedgerInfo::parentCloseTime
NetClock::time_point parentCloseTime
Definition: ReadView.h:93
ripple::LgrDBName
constexpr auto LgrDBName
Definition: DBInit.h:43
ripple::Application::getMasterTransaction
virtual TransactionMaster & getMasterTransaction()=0