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 
805  soci::session& session,
806  Application& app,
807  LedgerMaster& ledgerMaster,
808  RelationalDBInterface::AccountTxOptions const& options,
809  std::optional<int> const& limit_used,
810  bool descending,
811  beast::Journal j)
812 {
814 
816  app,
817  "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
818  options,
819  limit_used,
820  descending,
821  false,
822  false,
823  j);
824  if (sql == "")
825  return {ret, 0};
826 
827  int total = 0;
828  {
829  // SOCI requires boost::optional (not std::optional) as parameters.
830  boost::optional<std::uint64_t> ledgerSeq;
831  boost::optional<std::string> status;
832  soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
833  soci::indicator rti, tmi;
834  Blob rawTxn, txnMeta;
835 
836  soci::statement st =
837  (session.prepare << sql,
838  soci::into(ledgerSeq),
839  soci::into(status),
840  soci::into(sociTxnBlob, rti),
841  soci::into(sociTxnMetaBlob, tmi));
842 
843  st.execute();
844  while (st.fetch())
845  {
846  if (soci::i_ok == rti)
847  convert(sociTxnBlob, rawTxn);
848  else
849  rawTxn.clear();
850 
851  if (soci::i_ok == tmi)
852  convert(sociTxnMetaBlob, txnMeta);
853  else
854  txnMeta.clear();
855 
856  auto txn =
857  Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
858 
859  if (txnMeta.empty())
860  { // Work around a bug that could leave the metadata missing
861  auto const seq =
862  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
863 
864  JLOG(j.warn())
865  << "Recovering ledger " << seq << ", txn " << txn->getID();
866 
867  if (auto l = ledgerMaster.getLedgerBySeq(seq))
868  pendSaveValidated(app, l, false, false);
869  }
870 
871  if (txn)
872  {
873  ret.emplace_back(
874  txn,
875  std::make_shared<TxMeta>(
876  txn->getID(), txn->getLedger(), txnMeta));
877  total++;
878  }
879  }
880 
881  if (!total && limit_used)
882  {
883  RelationalDBInterface::AccountTxOptions opt = options;
884  opt.offset = 0;
886  app, "COUNT(*)", opt, limit_used, descending, false, false, j);
887 
888  session << sql1, soci::into(total);
889 
890  total = ~total;
891  }
892  }
893 
894  return {ret, total};
895 }
896 
899  soci::session& session,
900  Application& app,
901  LedgerMaster& ledgerMaster,
902  RelationalDBInterface::AccountTxOptions const& options,
903  std::optional<int> const& limit_used,
904  beast::Journal j)
905 {
907  session, app, ledgerMaster, options, limit_used, false, j);
908 }
909 
912  soci::session& session,
913  Application& app,
914  LedgerMaster& ledgerMaster,
915  RelationalDBInterface::AccountTxOptions const& options,
916  std::optional<int> const& limit_used,
917  beast::Journal j)
918 {
919  return getAccountTxs(
920  session, app, ledgerMaster, options, limit_used, true, j);
921 }
922 
944  soci::session& session,
945  Application& app,
946  RelationalDBInterface::AccountTxOptions const& options,
947  std::optional<int> const& limit_used,
948  bool descending,
949  beast::Journal j)
950 {
952 
954  app,
955  "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
956  options,
957  limit_used,
958  descending,
959  true /*binary*/,
960  false,
961  j);
962  if (sql == "")
963  return {ret, 0};
964 
965  int total = 0;
966 
967  {
968  // SOCI requires boost::optional (not std::optional) as parameters.
969  boost::optional<std::uint64_t> ledgerSeq;
970  boost::optional<std::string> status;
971  soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
972  soci::indicator rti, tmi;
973 
974  soci::statement st =
975  (session.prepare << sql,
976  soci::into(ledgerSeq),
977  soci::into(status),
978  soci::into(sociTxnBlob, rti),
979  soci::into(sociTxnMetaBlob, tmi));
980 
981  st.execute();
982  while (st.fetch())
983  {
984  Blob rawTxn;
985  if (soci::i_ok == rti)
986  convert(sociTxnBlob, rawTxn);
987  Blob txnMeta;
988  if (soci::i_ok == tmi)
989  convert(sociTxnMetaBlob, txnMeta);
990 
991  auto const seq =
992  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
993 
994  ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq);
995  total++;
996  }
997 
998  if (!total && limit_used)
999  {
1000  RelationalDBInterface::AccountTxOptions opt = options;
1001  opt.offset = 0;
1003  app, "COUNT(*)", opt, limit_used, descending, true, false, j);
1004 
1005  session << sql1, soci::into(total);
1006 
1007  total = ~total;
1008  }
1009  }
1011  return {ret, total};
1012 }
1013 
1016  soci::session& session,
1017  Application& app,
1018  RelationalDBInterface::AccountTxOptions const& options,
1019  std::optional<int> const& limit_used,
1020  beast::Journal j)
1022  return getAccountTxsB(session, app, options, limit_used, false, j);
1023 }
1024 
1027  soci::session& session,
1028  Application& app,
1029  RelationalDBInterface::AccountTxOptions const& options,
1030  std::optional<int> const& limit_used,
1031  beast::Journal j)
1032 {
1033  return getAccountTxsB(session, app, options, limit_used, true, j);
1034 }
1035 
1060  soci::session& session,
1061  AccountIDCache const& idCache,
1062  std::function<void(std::uint32_t)> const& onUnsavedLedger,
1063  std::function<
1064  void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1065  onTransaction,
1066  RelationalDBInterface::AccountTxPageOptions const& options,
1067  int limit_used,
1068  std::uint32_t page_length,
1069  bool forward)
1070 {
1071  int total = 0;
1072 
1073  bool lookingForMarker = options.marker.has_value();
1074 
1075  std::uint32_t numberOfResults;
1076 
1077  if (options.limit == 0 || options.limit == UINT32_MAX ||
1078  (options.limit > page_length && !options.bAdmin))
1079  numberOfResults = page_length;
1080  else
1081  numberOfResults = options.limit;
1082 
1083  if (numberOfResults < limit_used)
1084  return {options.marker, -1};
1085  numberOfResults -= limit_used;
1086 
1087  // As an account can have many thousands of transactions, there is a limit
1088  // placed on the amount of transactions returned. If the limit is reached
1089  // before the result set has been exhausted (we always query for one more
1090  // than the limit), then we return an opaque marker that can be supplied in
1091  // a subsequent query.
1092  std::uint32_t queryLimit = numberOfResults + 1;
1093  std::uint32_t findLedger = 0, findSeq = 0;
1094 
1095  if (lookingForMarker)
1096  {
1097  findLedger = options.marker->ledgerSeq;
1098  findSeq = options.marker->txnSeq;
1099  }
1100 
1102  if (limit_used > 0)
1103  newmarker = options.marker;
1104 
1105  static std::string const prefix(
1106  R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1107  Status,RawTxn,TxnMeta
1108  FROM AccountTransactions INNER JOIN Transactions
1109  ON Transactions.TransID = AccountTransactions.TransID
1110  AND AccountTransactions.Account = '%s' WHERE
1111  )");
1112 
1113  std::string sql;
1114 
1115  // SQL's BETWEEN uses a closed interval ([a,b])
1116 
1117  const char* const order = forward ? "ASC" : "DESC";
1118 
1119  if (findLedger == 0)
1120  {
1121  sql = boost::str(
1122  boost::format(
1123  prefix + (R"(AccountTransactions.LedgerSeq BETWEEN '%u' AND '%u'
1124  ORDER BY AccountTransactions.LedgerSeq %s,
1125  AccountTransactions.TxnSeq %s
1126  LIMIT %u;)")) %
1127  idCache.toBase58(options.account) % options.minLedger %
1128  options.maxLedger % order % order % queryLimit);
1129  }
1130  else
1131  {
1132  const char* const compare = forward ? ">=" : "<=";
1133  const std::uint32_t minLedger =
1134  forward ? findLedger + 1 : options.minLedger;
1135  const std::uint32_t maxLedger =
1136  forward ? options.maxLedger : findLedger - 1;
1137 
1138  auto b58acct = idCache.toBase58(options.account);
1139  sql = boost::str(
1140  boost::format((
1141  R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1142  Status,RawTxn,TxnMeta
1143  FROM AccountTransactions, Transactions WHERE
1144  (AccountTransactions.TransID = Transactions.TransID AND
1145  AccountTransactions.Account = '%s' AND
1146  AccountTransactions.LedgerSeq BETWEEN '%u' AND '%u')
1147  OR
1148  (AccountTransactions.TransID = Transactions.TransID AND
1149  AccountTransactions.Account = '%s' AND
1150  AccountTransactions.LedgerSeq = '%u' AND
1151  AccountTransactions.TxnSeq %s '%u')
1152  ORDER BY AccountTransactions.LedgerSeq %s,
1153  AccountTransactions.TxnSeq %s
1154  LIMIT %u;
1155  )")) %
1156  b58acct % minLedger % maxLedger % b58acct % findLedger % compare %
1157  findSeq % order % order % queryLimit);
1158  }
1159 
1160  {
1161  Blob rawData;
1162  Blob rawMeta;
1163 
1164  // SOCI requires boost::optional (not std::optional) as parameters.
1165  boost::optional<std::uint64_t> ledgerSeq;
1166  boost::optional<std::uint32_t> txnSeq;
1167  boost::optional<std::string> status;
1168  soci::blob txnData(session);
1169  soci::blob txnMeta(session);
1170  soci::indicator dataPresent, metaPresent;
1171 
1172  soci::statement st =
1173  (session.prepare << sql,
1174  soci::into(ledgerSeq),
1175  soci::into(txnSeq),
1176  soci::into(status),
1177  soci::into(txnData, dataPresent),
1178  soci::into(txnMeta, metaPresent));
1179 
1180  st.execute();
1181 
1182  while (st.fetch())
1183  {
1184  if (lookingForMarker)
1185  {
1186  if (findLedger == ledgerSeq.value_or(0) &&
1187  findSeq == txnSeq.value_or(0))
1188  {
1189  lookingForMarker = false;
1190  }
1191  else
1192  continue;
1193  }
1194  else if (numberOfResults == 0)
1195  {
1196  newmarker = {
1197  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1198  txnSeq.value_or(0)};
1199  break;
1200  }
1201 
1202  if (dataPresent == soci::i_ok)
1203  convert(txnData, rawData);
1204  else
1205  rawData.clear();
1206 
1207  if (metaPresent == soci::i_ok)
1208  convert(txnMeta, rawMeta);
1209  else
1210  rawMeta.clear();
1211 
1212  // Work around a bug that could leave the metadata missing
1213  if (rawMeta.size() == 0)
1214  onUnsavedLedger(ledgerSeq.value_or(0));
1215 
1216  // `rawData` and `rawMeta` will be used after they are moved.
1217  // That's OK.
1218  onTransaction(
1219  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1220  *status,
1221  std::move(rawData),
1222  std::move(rawMeta));
1223  // Note some callbacks will move the data, some will not. Clear
1224  // them so code doesn't depend on if the data was actually moved
1225  // or not. The code will be more efficient if `rawData` and
1226  // `rawMeta` don't have to allocate in `convert`, so don't
1227  // refactor my moving these variables into loop scope.
1228  rawData.clear();
1229  rawMeta.clear();
1230 
1231  --numberOfResults;
1232  total++;
1233  }
1234  }
1235 
1236  return {newmarker, total};
1237 }
1238 
1241  soci::session& session,
1242  AccountIDCache const& idCache,
1243  std::function<void(std::uint32_t)> const& onUnsavedLedger,
1244  std::function<
1245  void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1246  onTransaction,
1248  int limit_used,
1249  std::uint32_t page_length)
1250 {
1251  return accountTxPage(
1252  session,
1253  idCache,
1254  onUnsavedLedger,
1255  onTransaction,
1256  options,
1257  limit_used,
1258  page_length,
1259  true);
1260 }
1261 
1264  soci::session& session,
1265  AccountIDCache const& idCache,
1266  std::function<void(std::uint32_t)> const& onUnsavedLedger,
1267  std::function<
1268  void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1269  onTransaction,
1271  int limit_used,
1272  std::uint32_t page_length)
1273 {
1274  return accountTxPage(
1275  session,
1276  idCache,
1277  onUnsavedLedger,
1278  onTransaction,
1279  options,
1280  limit_used,
1281  page_length,
1282  false);
1283 }
1284 
1287  soci::session& session,
1288  Application& app,
1289  uint256 const& id,
1290  std::optional<ClosedInterval<uint32_t>> const& range,
1291  error_code_i& ec)
1292 {
1293  std::string sql =
1294  "SELECT LedgerSeq,Status,RawTxn,TxnMeta "
1295  "FROM Transactions WHERE TransID='";
1296 
1297  sql.append(to_string(id));
1298  sql.append("';");
1299 
1300  // SOCI requires boost::optional (not std::optional) as parameters.
1301  boost::optional<std::uint64_t> ledgerSeq;
1302  boost::optional<std::string> status;
1303  Blob rawTxn, rawMeta;
1304  {
1305  soci::blob sociRawTxnBlob(session), sociRawMetaBlob(session);
1306  soci::indicator txn, meta;
1307 
1308  session << sql, soci::into(ledgerSeq), soci::into(status),
1309  soci::into(sociRawTxnBlob, txn), soci::into(sociRawMetaBlob, meta);
1310 
1311  auto const got_data = session.got_data();
1312 
1313  if ((!got_data || txn != soci::i_ok || meta != soci::i_ok) && !range)
1314  return TxSearched::unknown;
1315 
1316  if (!got_data)
1317  {
1318  uint64_t count = 0;
1319  soci::indicator rti;
1320 
1321  session
1322  << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
1323  "LedgerSeq BETWEEN "
1324  << range->first() << " AND " << range->last() << ";",
1325  soci::into(count, rti);
1326 
1327  if (!session.got_data() || rti != soci::i_ok)
1328  return TxSearched::some;
1329 
1330  return count == (range->last() - range->first() + 1)
1331  ? TxSearched::all
1332  : TxSearched::some;
1333  }
1334 
1335  convert(sociRawTxnBlob, rawTxn);
1336  convert(sociRawMetaBlob, rawMeta);
1337  }
1338 
1339  try
1340  {
1341  auto txn =
1342  Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
1344  if (!ledgerSeq)
1345  return std::pair{std::move(txn), nullptr};
1346 
1347  std::uint32_t inLedger =
1348  rangeCheckedCast<std::uint32_t>(ledgerSeq.value());
1349 
1350  auto txMeta = std::make_shared<TxMeta>(id, inLedger, rawMeta);
1351 
1352  return std::pair{std::move(txn), std::move(txMeta)};
1353  }
1354  catch (std::exception& e)
1355  {
1356  JLOG(app.journal("Ledger").warn())
1357  << "Unable to deserialize transaction from raw SQL value. Error: "
1358  << e.what();
1359 
1360  ec = rpcDB_DESERIALIZATION;
1361  }
1362 
1363  return TxSearched::unknown;
1364 }
1365 
1366 bool
1367 dbHasSpace(soci::session& session, Config const& config, beast::Journal j)
1368 {
1369  boost::filesystem::space_info space =
1370  boost::filesystem::space(config.legacy("database_path"));
1371 
1372  if (space.available < megabytes(512))
1373  {
1374  JLOG(j.fatal()) << "Remaining free disk space is less than 512MB";
1375  return false;
1376  }
1377 
1378  if (config.useTxTables())
1379  {
1380  DatabaseCon::Setup dbSetup = setup_DatabaseCon(config);
1381  boost::filesystem::path dbPath = dbSetup.dataDir / TxDBName;
1382  boost::system::error_code ec;
1384  boost::filesystem::file_size(dbPath, ec);
1385  if (ec)
1386  {
1387  JLOG(j.error())
1388  << "Error checking transaction db file size: " << ec.message();
1389  dbSize.reset();
1390  }
1391 
1392  static auto const pageSize = [&] {
1393  std::uint32_t ps;
1394  session << "PRAGMA page_size;", soci::into(ps);
1395  return ps;
1396  }();
1397  static auto const maxPages = [&] {
1398  std::uint32_t mp;
1399  session << "PRAGMA max_page_count;", soci::into(mp);
1400  return mp;
1401  }();
1402  std::uint32_t pageCount;
1403  session << "PRAGMA page_count;", soci::into(pageCount);
1404  std::uint32_t freePages = maxPages - pageCount;
1405  std::uint64_t freeSpace =
1406  safe_cast<std::uint64_t>(freePages) * pageSize;
1407  JLOG(j.info())
1408  << "Transaction DB pathname: " << dbPath.string()
1409  << "; file size: " << dbSize.value_or(-1) << " bytes"
1410  << "; SQLite page size: " << pageSize << " bytes"
1411  << "; Free pages: " << freePages << "; Free space: " << freeSpace
1412  << " bytes; "
1413  << "Note that this does not take into account available disk "
1414  "space.";
1415 
1416  if (freeSpace < megabytes(512))
1417  {
1418  JLOG(j.fatal())
1419  << "Free SQLite space for transaction db is less than "
1420  "512MB. To fix this, rippled must be executed with the "
1421  "vacuum parameter before restarting. "
1422  "Note that this activity can take multiple days, "
1423  "depending on database size.";
1424  return false;
1425  }
1426  }
1427 
1428  return true;
1429 }
1430 
1431 } // 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:103
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:783
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:893
std::exception
STL class.
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:513
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:799
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:1010
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:44
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:1239
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:231
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:526
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:906
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:74
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:539
ripple::saveValidatedLedger
static bool saveValidatedLedger(Application &app, std::shared_ptr< Ledger const > const &ledger, bool current)
Definition: Ledger.cpp:916
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:931
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:530
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:282
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:938
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:1021
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:1262
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:1216
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:39
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: SHAMapTreeNode.h:59
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:1343
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:944
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:1054
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