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 
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)
273  {
274  uint256 transactionID = acceptedLedgerTx->getTransactionID();
275 
276  std::string const txnId(to_string(transactionID));
277  std::string const txnSeq(
278  std::to_string(acceptedLedgerTx->getTxnSeq()));
279 
280  *db << boost::str(deleteAcctTrans % transactionID);
281 
282  auto const& accts = acceptedLedgerTx->getAffected();
283 
284  if (!accts.empty())
285  {
286  std::string sql(
287  "INSERT INTO AccountTransactions "
288  "(TransID, Account, LedgerSeq, TxnSeq) VALUES ");
289 
290  // Try to make an educated guess on how much space we'll
291  // need for our arguments. In argument order we have: 64
292  // + 34 + 10 + 10 = 118 + 10 extra = 128 bytes
293  sql.reserve(sql.length() + (accts.size() * 128));
294 
295  bool first = true;
296  for (auto const& account : accts)
297  {
298  if (!first)
299  sql += ", ('";
300  else
301  {
302  sql += "('";
303  first = false;
304  }
305 
306  sql += txnId;
307  sql += "','";
308  sql += app.accountIDCache().toBase58(account);
309  sql += "',";
310  sql += ledgerSeq;
311  sql += ",";
312  sql += txnSeq;
313  sql += ")";
314  }
315  sql += ";";
316  JLOG(j.trace()) << "ActTx: " << sql;
317  *db << sql;
318  }
319  else if (auto const& sleTxn = acceptedLedgerTx->getTxn();
320  !isPseudoTx(*sleTxn))
321  {
322  // It's okay for pseudo transactions to not affect any
323  // accounts. But otherwise...
324  JLOG(j.warn()) << "Transaction in ledger " << seq
325  << " affects no accounts";
326  JLOG(j.warn()) << sleTxn->getJson(JsonOptions::none);
327  }
328 
329  *db
331  acceptedLedgerTx->getTxn()->getMetaSQL(
332  seq, acceptedLedgerTx->getEscMeta()) +
333  ";");
334 
336  }
337 
338  tr.commit();
339  }
340 
341  {
342  static std::string addLedger(
343  R"sql(INSERT OR REPLACE INTO Ledgers
344  (LedgerHash,LedgerSeq,PrevHash,TotalCoins,ClosingTime,PrevClosingTime,
345  CloseTimeRes,CloseFlags,AccountSetHash,TransSetHash)
346  VALUES
347  (:ledgerHash,:ledgerSeq,:prevHash,:totalCoins,:closingTime,:prevClosingTime,
348  :closeTimeRes,:closeFlags,:accountSetHash,:transSetHash);)sql");
349 
350  auto db(ldgDB.checkoutDb());
351 
352  soci::transaction tr(*db);
353 
354  auto const hash = to_string(ledger->info().hash);
355  auto const parentHash = to_string(ledger->info().parentHash);
356  auto const drops = to_string(ledger->info().drops);
357  auto const closeTime =
358  ledger->info().closeTime.time_since_epoch().count();
359  auto const parentCloseTime =
360  ledger->info().parentCloseTime.time_since_epoch().count();
361  auto const closeTimeResolution =
362  ledger->info().closeTimeResolution.count();
363  auto const closeFlags = ledger->info().closeFlags;
364  auto const accountHash = to_string(ledger->info().accountHash);
365  auto const txHash = to_string(ledger->info().txHash);
366 
367  *db << addLedger, soci::use(hash), soci::use(seq),
368  soci::use(parentHash), soci::use(drops), soci::use(closeTime),
369  soci::use(parentCloseTime), soci::use(closeTimeResolution),
370  soci::use(closeFlags), soci::use(accountHash),
371  soci::use(txHash);
372 
373  tr.commit();
374  }
375  }
376 
377  return true;
378 }
379 
390  soci::session& session,
391  std::string const& sqlSuffix,
392  beast::Journal j)
393 {
394  // SOCI requires boost::optional (not std::optional) as parameters.
395  boost::optional<std::string> hash, parentHash, accountHash, txHash;
396  boost::optional<std::uint64_t> seq, drops, closeTime, parentCloseTime,
397  closeTimeResolution, closeFlags;
398 
399  std::string const sql =
400  "SELECT "
401  "LedgerHash, PrevHash, AccountSetHash, TransSetHash, "
402  "TotalCoins,"
403  "ClosingTime, PrevClosingTime, CloseTimeRes, CloseFlags,"
404  "LedgerSeq FROM Ledgers " +
405  sqlSuffix + ";";
406 
407  session << sql, soci::into(hash), soci::into(parentHash),
408  soci::into(accountHash), soci::into(txHash), soci::into(drops),
409  soci::into(closeTime), soci::into(parentCloseTime),
410  soci::into(closeTimeResolution), soci::into(closeFlags),
411  soci::into(seq);
412 
413  if (!session.got_data())
414  {
415  JLOG(j.debug()) << "Ledger not found: " << sqlSuffix;
416  return {};
417  }
418 
419  using time_point = NetClock::time_point;
420  using duration = NetClock::duration;
421 
422  LedgerInfo info;
423 
424  if (hash && !info.hash.parseHex(*hash))
425  {
426  JLOG(j.debug()) << "Hash parse error for ledger: " << sqlSuffix;
427  return {};
428  }
429 
430  if (parentHash && !info.parentHash.parseHex(*parentHash))
431  {
432  JLOG(j.debug()) << "parentHash parse error for ledger: " << sqlSuffix;
433  return {};
434  }
435 
436  if (accountHash && !info.accountHash.parseHex(*accountHash))
437  {
438  JLOG(j.debug()) << "accountHash parse error for ledger: " << sqlSuffix;
439  return {};
440  }
441 
442  if (txHash && !info.txHash.parseHex(*txHash))
443  {
444  JLOG(j.debug()) << "txHash parse error for ledger: " << sqlSuffix;
445  return {};
446  }
447 
448  info.seq = rangeCheckedCast<std::uint32_t>(seq.value_or(0));
449  info.drops = drops.value_or(0);
450  info.closeTime = time_point{duration{closeTime.value_or(0)}};
451  info.parentCloseTime = time_point{duration{parentCloseTime.value_or(0)}};
452  info.closeFlags = closeFlags.value_or(0);
453  info.closeTimeResolution = duration{closeTimeResolution.value_or(0)};
454 
455  return info;
456 }
457 
460  soci::session& session,
461  LedgerIndex ledgerSeq,
462  beast::Journal j)
463 {
465  s << "WHERE LedgerSeq = " << ledgerSeq;
466  return getLedgerInfo(session, s.str(), j);
467 }
468 
470 getNewestLedgerInfo(soci::session& session, beast::Journal j)
471 {
473  s << "ORDER BY LedgerSeq DESC LIMIT 1";
474  return getLedgerInfo(session, s.str(), j);
475 }
476 
479  soci::session& session,
480  LedgerIndex ledgerFirstIndex,
481  beast::Journal j)
482 {
484  s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
485  " ORDER BY LedgerSeq ASC LIMIT 1";
486  return getLedgerInfo(session, s.str(), j);
487 }
488 
491  soci::session& session,
492  LedgerIndex ledgerFirstIndex,
493  beast::Journal j)
494 {
496  s << "WHERE LedgerSeq >= " + std::to_string(ledgerFirstIndex) +
497  " ORDER BY LedgerSeq DESC LIMIT 1";
498  return getLedgerInfo(session, s.str(), j);
499 }
500 
503  soci::session& session,
504  uint256 const& ledgerHash,
505  beast::Journal j)
506 {
508  s << "WHERE LedgerHash = '" << ledgerHash << "'";
509  return getLedgerInfo(session, s.str(), j);
510 }
511 
512 uint256
513 getHashByIndex(soci::session& session, LedgerIndex ledgerIndex)
514 {
515  uint256 ret;
516 
517  std::string sql =
518  "SELECT LedgerHash FROM Ledgers INDEXED BY SeqLedger WHERE LedgerSeq='";
519  sql.append(beast::lexicalCastThrow<std::string>(ledgerIndex));
520  sql.append("';");
521 
522  std::string hash;
523  {
524  // SOCI requires boost::optional (not std::optional) as the parameter.
525  boost::optional<std::string> lh;
526  session << sql, soci::into(lh);
527 
528  if (!session.got_data() || !lh)
529  return ret;
530 
531  hash = *lh;
532  if (hash.empty())
533  return ret;
534  }
535 
536  if (!ret.parseHex(hash))
537  return ret;
538 
539  return ret;
540 }
541 
544  soci::session& session,
545  LedgerIndex ledgerIndex,
546  beast::Journal j)
547 {
548  // SOCI requires boost::optional (not std::optional) as the parameter.
549  boost::optional<std::string> lhO, phO;
550 
551  session << "SELECT LedgerHash,PrevHash FROM Ledgers "
552  "INDEXED BY SeqLedger WHERE LedgerSeq = :ls;",
553  soci::into(lhO), soci::into(phO), soci::use(ledgerIndex);
554 
555  if (!lhO || !phO)
556  {
557  auto stream = j.trace();
558  JLOG(stream) << "Don't have ledger " << ledgerIndex;
559  return {};
560  }
561 
562  LedgerHashPair hashes;
563  if (!hashes.ledgerHash.parseHex(*lhO) || !hashes.parentHash.parseHex(*phO))
564  {
565  auto stream = j.trace();
566  JLOG(stream) << "Error parse hashes for ledger " << ledgerIndex;
567  return {};
568  }
569 
570  return hashes;
571 }
572 
575  soci::session& session,
576  LedgerIndex minSeq,
577  LedgerIndex maxSeq,
578  beast::Journal j)
579 {
580  std::string sql =
581  "SELECT LedgerSeq,LedgerHash,PrevHash FROM Ledgers WHERE LedgerSeq >= ";
582  sql.append(beast::lexicalCastThrow<std::string>(minSeq));
583  sql.append(" AND LedgerSeq <= ");
584  sql.append(beast::lexicalCastThrow<std::string>(maxSeq));
585  sql.append(";");
586 
587  std::uint64_t ls;
588  std::string lh;
589  // SOCI requires boost::optional (not std::optional) as the parameter.
590  boost::optional<std::string> ph;
591  soci::statement st =
592  (session.prepare << sql,
593  soci::into(ls),
594  soci::into(lh),
595  soci::into(ph));
596 
597  st.execute();
599  while (st.fetch())
600  {
601  LedgerHashPair& hashes = res[rangeCheckedCast<LedgerIndex>(ls)];
602  if (!hashes.ledgerHash.parseHex(lh))
603  {
604  JLOG(j.warn()) << "Error parsed hash for ledger seq: " << ls;
605  }
606  if (!ph)
607  {
608  JLOG(j.warn()) << "Null prev hash for ledger seq: " << ls;
609  }
610  else if (!hashes.parentHash.parseHex(*ph))
611  {
612  JLOG(j.warn()) << "Error parsed prev hash for ledger seq: " << ls;
613  }
614  }
615  return res;
616 }
617 
620  soci::session& session,
621  Application& app,
622  LedgerIndex startIndex,
623  int quantity,
624  bool count)
625 {
626  std::string sql = boost::str(
627  boost::format(
628  "SELECT LedgerSeq, Status, RawTxn "
629  "FROM Transactions ORDER BY LedgerSeq DESC LIMIT %u,%u;") %
630  startIndex % quantity);
631 
633  int total = 0;
634 
635  {
636  // SOCI requires boost::optional (not std::optional) as parameters.
637  boost::optional<std::uint64_t> ledgerSeq;
638  boost::optional<std::string> status;
639  soci::blob sociRawTxnBlob(session);
640  soci::indicator rti;
641  Blob rawTxn;
642 
643  soci::statement st =
644  (session.prepare << sql,
645  soci::into(ledgerSeq),
646  soci::into(status),
647  soci::into(sociRawTxnBlob, rti));
648 
649  st.execute();
650  while (st.fetch())
651  {
652  if (soci::i_ok == rti)
653  convert(sociRawTxnBlob, rawTxn);
654  else
655  rawTxn.clear();
656 
657  if (auto trans = Transaction::transactionFromSQL(
658  ledgerSeq, status, rawTxn, app))
659  {
660  total++;
661  txs.push_back(trans);
662  }
663  }
664 
665  if (!total && count)
666  {
667  session << "SELECT COUNT(*) FROM Transactions;", soci::into(total);
668 
669  total = -total;
670  }
671  }
672 
673  return {txs, total};
674 }
675 
695 static std::string
697  Application& app,
698  std::string selection,
699  RelationalDBInterface::AccountTxOptions const& options,
700  std::optional<int> const& limit_used,
701  bool descending,
702  bool binary,
703  bool count,
704  beast::Journal j)
705 {
706  constexpr std::uint32_t NONBINARY_PAGE_LENGTH = 200;
707  constexpr std::uint32_t BINARY_PAGE_LENGTH = 500;
708 
709  std::uint32_t numberOfResults;
710 
711  if (count)
712  {
713  numberOfResults = std::numeric_limits<std::uint32_t>::max();
714  }
715  else if (options.limit == UINT32_MAX)
716  {
717  numberOfResults = binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH;
718  }
719  else if (!options.bUnlimited)
720  {
721  numberOfResults = std::min(
722  binary ? BINARY_PAGE_LENGTH : NONBINARY_PAGE_LENGTH, options.limit);
723  }
724  else
725  {
726  numberOfResults = options.limit;
727  }
728 
729  if (limit_used)
730  {
731  if (numberOfResults <= *limit_used)
732  return "";
733  else
734  numberOfResults -= *limit_used;
735  }
736 
737  std::string maxClause = "";
738  std::string minClause = "";
739 
740  if (options.maxLedger)
741  {
742  maxClause = boost::str(
743  boost::format("AND AccountTransactions.LedgerSeq <= '%u'") %
744  options.maxLedger);
745  }
746 
747  if (options.minLedger)
748  {
749  minClause = boost::str(
750  boost::format("AND AccountTransactions.LedgerSeq >= '%u'") %
751  options.minLedger);
752  }
753 
754  std::string sql;
755 
756  if (count)
757  sql = boost::str(
758  boost::format("SELECT %s FROM AccountTransactions "
759  "WHERE Account = '%s' %s %s LIMIT %u, %u;") %
760  selection % app.accountIDCache().toBase58(options.account) %
761  maxClause % minClause %
762  beast::lexicalCastThrow<std::string>(options.offset) %
763  beast::lexicalCastThrow<std::string>(numberOfResults));
764  else
765  sql = boost::str(
766  boost::format(
767  "SELECT %s FROM "
768  "AccountTransactions INNER JOIN Transactions "
769  "ON Transactions.TransID = AccountTransactions.TransID "
770  "WHERE Account = '%s' %s %s "
771  "ORDER BY AccountTransactions.LedgerSeq %s, "
772  "AccountTransactions.TxnSeq %s, AccountTransactions.TransID %s "
773  "LIMIT %u, %u;") %
774  selection % app.accountIDCache().toBase58(options.account) %
775  maxClause % minClause % (descending ? "DESC" : "ASC") %
776  (descending ? "DESC" : "ASC") % (descending ? "DESC" : "ASC") %
777  beast::lexicalCastThrow<std::string>(options.offset) %
778  beast::lexicalCastThrow<std::string>(numberOfResults));
779  JLOG(j.trace()) << "txSQL query: " << sql;
780  return sql;
781 }
782 
808  soci::session& session,
809  Application& app,
810  LedgerMaster& ledgerMaster,
811  RelationalDBInterface::AccountTxOptions const& options,
812  std::optional<int> const& limit_used,
813  bool descending,
814  beast::Journal j)
815 {
817 
819  app,
820  "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
821  options,
822  limit_used,
823  descending,
824  false,
825  false,
826  j);
827  if (sql == "")
828  return {ret, 0};
829 
830  int total = 0;
831  {
832  // SOCI requires boost::optional (not std::optional) as parameters.
833  boost::optional<std::uint64_t> ledgerSeq;
834  boost::optional<std::string> status;
835  soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
836  soci::indicator rti, tmi;
837  Blob rawTxn, txnMeta;
838 
839  soci::statement st =
840  (session.prepare << sql,
841  soci::into(ledgerSeq),
842  soci::into(status),
843  soci::into(sociTxnBlob, rti),
844  soci::into(sociTxnMetaBlob, tmi));
845 
846  st.execute();
847  while (st.fetch())
848  {
849  if (soci::i_ok == rti)
850  convert(sociTxnBlob, rawTxn);
851  else
852  rawTxn.clear();
853 
854  if (soci::i_ok == tmi)
855  convert(sociTxnMetaBlob, txnMeta);
856  else
857  txnMeta.clear();
858 
859  auto txn =
860  Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
861 
862  if (txnMeta.empty())
863  { // Work around a bug that could leave the metadata missing
864  auto const seq =
865  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
866 
867  JLOG(j.warn())
868  << "Recovering ledger " << seq << ", txn " << txn->getID();
869 
870  if (auto l = ledgerMaster.getLedgerBySeq(seq))
871  pendSaveValidated(app, l, false, false);
872  }
873 
874  if (txn)
875  {
876  ret.emplace_back(
877  txn,
878  std::make_shared<TxMeta>(
879  txn->getID(), txn->getLedger(), txnMeta));
880  total++;
881  }
882  }
883 
884  if (!total && limit_used)
885  {
886  RelationalDBInterface::AccountTxOptions opt = options;
887  opt.offset = 0;
889  app, "COUNT(*)", opt, limit_used, descending, false, false, j);
890 
891  session << sql1, soci::into(total);
892 
893  total = -total;
894  }
895  }
896 
897  return {ret, total};
898 }
899 
902  soci::session& session,
903  Application& app,
904  LedgerMaster& ledgerMaster,
905  RelationalDBInterface::AccountTxOptions const& options,
906  std::optional<int> const& limit_used,
907  beast::Journal j)
908 {
910  session, app, ledgerMaster, options, limit_used, false, j);
911 }
912 
915  soci::session& session,
916  Application& app,
917  LedgerMaster& ledgerMaster,
918  RelationalDBInterface::AccountTxOptions const& options,
919  std::optional<int> const& limit_used,
920  beast::Journal j)
921 {
922  return getAccountTxs(
923  session, app, ledgerMaster, options, limit_used, true, j);
924 }
925 
951  soci::session& session,
952  Application& app,
953  RelationalDBInterface::AccountTxOptions const& options,
954  std::optional<int> const& limit_used,
955  bool descending,
956  beast::Journal j)
957 {
959 
961  app,
962  "AccountTransactions.LedgerSeq,Status,RawTxn,TxnMeta",
963  options,
964  limit_used,
965  descending,
966  true /*binary*/,
967  false,
968  j);
969  if (sql == "")
970  return {ret, 0};
971 
972  int total = 0;
973 
974  {
975  // SOCI requires boost::optional (not std::optional) as parameters.
976  boost::optional<std::uint64_t> ledgerSeq;
977  boost::optional<std::string> status;
978  soci::blob sociTxnBlob(session), sociTxnMetaBlob(session);
979  soci::indicator rti, tmi;
980 
981  soci::statement st =
982  (session.prepare << sql,
983  soci::into(ledgerSeq),
984  soci::into(status),
985  soci::into(sociTxnBlob, rti),
986  soci::into(sociTxnMetaBlob, tmi));
987 
988  st.execute();
989  while (st.fetch())
990  {
991  Blob rawTxn;
992  if (soci::i_ok == rti)
993  convert(sociTxnBlob, rawTxn);
994  Blob txnMeta;
995  if (soci::i_ok == tmi)
996  convert(sociTxnMetaBlob, txnMeta);
997 
998  auto const seq =
999  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0));
1000 
1001  ret.emplace_back(std::move(rawTxn), std::move(txnMeta), seq);
1002  total++;
1003  }
1004 
1005  if (!total && limit_used)
1006  {
1007  RelationalDBInterface::AccountTxOptions opt = options;
1008  opt.offset = 0;
1010  app, "COUNT(*)", opt, limit_used, descending, true, false, j);
1011 
1012  session << sql1, soci::into(total);
1013 
1014  total = -total;
1015  }
1016  }
1018  return {ret, total};
1019 }
1020 
1023  soci::session& session,
1024  Application& app,
1025  RelationalDBInterface::AccountTxOptions const& options,
1026  std::optional<int> const& limit_used,
1027  beast::Journal j)
1029  return getAccountTxsB(session, app, options, limit_used, false, j);
1030 }
1031 
1034  soci::session& session,
1035  Application& app,
1036  RelationalDBInterface::AccountTxOptions const& options,
1037  std::optional<int> const& limit_used,
1038  beast::Journal j)
1039 {
1040  return getAccountTxsB(session, app, options, limit_used, true, j);
1041 }
1042 
1067  soci::session& session,
1068  AccountIDCache const& idCache,
1069  std::function<void(std::uint32_t)> const& onUnsavedLedger,
1070  std::function<
1071  void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1072  onTransaction,
1073  RelationalDBInterface::AccountTxPageOptions const& options,
1074  int limit_used,
1075  std::uint32_t page_length,
1076  bool forward)
1077 {
1078  int total = 0;
1079 
1080  bool lookingForMarker = options.marker.has_value();
1081 
1082  std::uint32_t numberOfResults;
1083 
1084  if (options.limit == 0 || options.limit == UINT32_MAX ||
1085  (options.limit > page_length && !options.bAdmin))
1086  numberOfResults = page_length;
1087  else
1088  numberOfResults = options.limit;
1089 
1090  if (numberOfResults < limit_used)
1091  return {options.marker, -1};
1092  numberOfResults -= limit_used;
1093 
1094  // As an account can have many thousands of transactions, there is a limit
1095  // placed on the amount of transactions returned. If the limit is reached
1096  // before the result set has been exhausted (we always query for one more
1097  // than the limit), then we return an opaque marker that can be supplied in
1098  // a subsequent query.
1099  std::uint32_t queryLimit = numberOfResults + 1;
1100  std::uint32_t findLedger = 0, findSeq = 0;
1101 
1102  if (lookingForMarker)
1103  {
1104  findLedger = options.marker->ledgerSeq;
1105  findSeq = options.marker->txnSeq;
1106  }
1107 
1109  if (limit_used > 0)
1110  newmarker = options.marker;
1111 
1112  static std::string const prefix(
1113  R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1114  Status,RawTxn,TxnMeta
1115  FROM AccountTransactions INNER JOIN Transactions
1116  ON Transactions.TransID = AccountTransactions.TransID
1117  AND AccountTransactions.Account = '%s' WHERE
1118  )");
1119 
1120  std::string sql;
1121 
1122  // SQL's BETWEEN uses a closed interval ([a,b])
1123 
1124  const char* const order = forward ? "ASC" : "DESC";
1125 
1126  if (findLedger == 0)
1127  {
1128  sql = boost::str(
1129  boost::format(
1130  prefix + (R"(AccountTransactions.LedgerSeq BETWEEN '%u' AND '%u'
1131  ORDER BY AccountTransactions.LedgerSeq %s,
1132  AccountTransactions.TxnSeq %s
1133  LIMIT %u;)")) %
1134  idCache.toBase58(options.account) % options.minLedger %
1135  options.maxLedger % order % order % queryLimit);
1136  }
1137  else
1138  {
1139  const char* const compare = forward ? ">=" : "<=";
1140  const std::uint32_t minLedger =
1141  forward ? findLedger + 1 : options.minLedger;
1142  const std::uint32_t maxLedger =
1143  forward ? options.maxLedger : findLedger - 1;
1144 
1145  auto b58acct = idCache.toBase58(options.account);
1146  sql = boost::str(
1147  boost::format((
1148  R"(SELECT AccountTransactions.LedgerSeq,AccountTransactions.TxnSeq,
1149  Status,RawTxn,TxnMeta
1150  FROM AccountTransactions, Transactions WHERE
1151  (AccountTransactions.TransID = Transactions.TransID AND
1152  AccountTransactions.Account = '%s' AND
1153  AccountTransactions.LedgerSeq BETWEEN '%u' AND '%u')
1154  OR
1155  (AccountTransactions.TransID = Transactions.TransID AND
1156  AccountTransactions.Account = '%s' AND
1157  AccountTransactions.LedgerSeq = '%u' AND
1158  AccountTransactions.TxnSeq %s '%u')
1159  ORDER BY AccountTransactions.LedgerSeq %s,
1160  AccountTransactions.TxnSeq %s
1161  LIMIT %u;
1162  )")) %
1163  b58acct % minLedger % maxLedger % b58acct % findLedger % compare %
1164  findSeq % order % order % queryLimit);
1165  }
1166 
1167  {
1168  Blob rawData;
1169  Blob rawMeta;
1170 
1171  // SOCI requires boost::optional (not std::optional) as parameters.
1172  boost::optional<std::uint64_t> ledgerSeq;
1173  boost::optional<std::uint32_t> txnSeq;
1174  boost::optional<std::string> status;
1175  soci::blob txnData(session);
1176  soci::blob txnMeta(session);
1177  soci::indicator dataPresent, metaPresent;
1178 
1179  soci::statement st =
1180  (session.prepare << sql,
1181  soci::into(ledgerSeq),
1182  soci::into(txnSeq),
1183  soci::into(status),
1184  soci::into(txnData, dataPresent),
1185  soci::into(txnMeta, metaPresent));
1186 
1187  st.execute();
1188 
1189  while (st.fetch())
1190  {
1191  if (lookingForMarker)
1192  {
1193  if (findLedger == ledgerSeq.value_or(0) &&
1194  findSeq == txnSeq.value_or(0))
1195  {
1196  lookingForMarker = false;
1197  }
1198  else
1199  continue;
1200  }
1201  else if (numberOfResults == 0)
1202  {
1203  newmarker = {
1204  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1205  txnSeq.value_or(0)};
1206  break;
1207  }
1208 
1209  if (dataPresent == soci::i_ok)
1210  convert(txnData, rawData);
1211  else
1212  rawData.clear();
1213 
1214  if (metaPresent == soci::i_ok)
1215  convert(txnMeta, rawMeta);
1216  else
1217  rawMeta.clear();
1218 
1219  // Work around a bug that could leave the metadata missing
1220  if (rawMeta.size() == 0)
1221  onUnsavedLedger(ledgerSeq.value_or(0));
1222 
1223  // `rawData` and `rawMeta` will be used after they are moved.
1224  // That's OK.
1225  onTransaction(
1226  rangeCheckedCast<std::uint32_t>(ledgerSeq.value_or(0)),
1227  *status,
1228  std::move(rawData),
1229  std::move(rawMeta));
1230  // Note some callbacks will move the data, some will not. Clear
1231  // them so code doesn't depend on if the data was actually moved
1232  // or not. The code will be more efficient if `rawData` and
1233  // `rawMeta` don't have to allocate in `convert`, so don't
1234  // refactor my moving these variables into loop scope.
1235  rawData.clear();
1236  rawMeta.clear();
1237 
1238  --numberOfResults;
1239  total++;
1240  }
1241  }
1242 
1243  return {newmarker, total};
1244 }
1245 
1248  soci::session& session,
1249  AccountIDCache const& idCache,
1250  std::function<void(std::uint32_t)> const& onUnsavedLedger,
1251  std::function<
1252  void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1253  onTransaction,
1255  int limit_used,
1256  std::uint32_t page_length)
1257 {
1258  return accountTxPage(
1259  session,
1260  idCache,
1261  onUnsavedLedger,
1262  onTransaction,
1263  options,
1264  limit_used,
1265  page_length,
1266  true);
1267 }
1268 
1271  soci::session& session,
1272  AccountIDCache const& idCache,
1273  std::function<void(std::uint32_t)> const& onUnsavedLedger,
1274  std::function<
1275  void(std::uint32_t, std::string const&, Blob&&, Blob&&)> const&
1276  onTransaction,
1278  int limit_used,
1279  std::uint32_t page_length)
1280 {
1281  return accountTxPage(
1282  session,
1283  idCache,
1284  onUnsavedLedger,
1285  onTransaction,
1286  options,
1287  limit_used,
1288  page_length,
1289  false);
1290 }
1291 
1294  soci::session& session,
1295  Application& app,
1296  uint256 const& id,
1297  std::optional<ClosedInterval<uint32_t>> const& range,
1298  error_code_i& ec)
1299 {
1300  std::string sql =
1301  "SELECT LedgerSeq,Status,RawTxn,TxnMeta "
1302  "FROM Transactions WHERE TransID='";
1303 
1304  sql.append(to_string(id));
1305  sql.append("';");
1306 
1307  // SOCI requires boost::optional (not std::optional) as parameters.
1308  boost::optional<std::uint64_t> ledgerSeq;
1309  boost::optional<std::string> status;
1310  Blob rawTxn, rawMeta;
1311  {
1312  soci::blob sociRawTxnBlob(session), sociRawMetaBlob(session);
1313  soci::indicator txn, meta;
1314 
1315  session << sql, soci::into(ledgerSeq), soci::into(status),
1316  soci::into(sociRawTxnBlob, txn), soci::into(sociRawMetaBlob, meta);
1317 
1318  auto const got_data = session.got_data();
1319 
1320  if ((!got_data || txn != soci::i_ok || meta != soci::i_ok) && !range)
1321  return TxSearched::unknown;
1322 
1323  if (!got_data)
1324  {
1325  uint64_t count = 0;
1326  soci::indicator rti;
1327 
1328  session
1329  << "SELECT COUNT(DISTINCT LedgerSeq) FROM Transactions WHERE "
1330  "LedgerSeq BETWEEN "
1331  << range->first() << " AND " << range->last() << ";",
1332  soci::into(count, rti);
1333 
1334  if (!session.got_data() || rti != soci::i_ok)
1335  return TxSearched::some;
1336 
1337  return count == (range->last() - range->first() + 1)
1338  ? TxSearched::all
1339  : TxSearched::some;
1340  }
1341 
1342  convert(sociRawTxnBlob, rawTxn);
1343  convert(sociRawMetaBlob, rawMeta);
1344  }
1345 
1346  try
1347  {
1348  auto txn =
1349  Transaction::transactionFromSQL(ledgerSeq, status, rawTxn, app);
1351  if (!ledgerSeq)
1352  return std::pair{std::move(txn), nullptr};
1353 
1354  std::uint32_t inLedger =
1355  rangeCheckedCast<std::uint32_t>(ledgerSeq.value());
1356 
1357  auto txMeta = std::make_shared<TxMeta>(id, inLedger, rawMeta);
1358 
1359  return std::pair{std::move(txn), std::move(txMeta)};
1360  }
1361  catch (std::exception& e)
1362  {
1363  JLOG(app.journal("Ledger").warn())
1364  << "Unable to deserialize transaction from raw SQL value. Error: "
1365  << e.what();
1366 
1367  ec = rpcDB_DESERIALIZATION;
1368  }
1369 
1370  return TxSearched::unknown;
1371 }
1372 
1373 bool
1374 dbHasSpace(soci::session& session, Config const& config, beast::Journal j)
1375 {
1376  boost::filesystem::space_info space =
1377  boost::filesystem::space(config.legacy("database_path"));
1378 
1379  if (space.available < megabytes(512))
1380  {
1381  JLOG(j.fatal()) << "Remaining free disk space is less than 512MB";
1382  return false;
1383  }
1384 
1385  if (config.useTxTables())
1386  {
1387  DatabaseCon::Setup dbSetup = setup_DatabaseCon(config);
1388  boost::filesystem::path dbPath = dbSetup.dataDir / TxDBName;
1389  boost::system::error_code ec;
1391  boost::filesystem::file_size(dbPath, ec);
1392  if (ec)
1393  {
1394  JLOG(j.error())
1395  << "Error checking transaction db file size: " << ec.message();
1396  dbSize.reset();
1397  }
1398 
1399  static auto const pageSize = [&] {
1400  std::uint32_t ps;
1401  session << "PRAGMA page_size;", soci::into(ps);
1402  return ps;
1403  }();
1404  static auto const maxPages = [&] {
1405  std::uint32_t mp;
1406  session << "PRAGMA max_page_count;", soci::into(mp);
1407  return mp;
1408  }();
1409  std::uint32_t pageCount;
1410  session << "PRAGMA page_count;", soci::into(pageCount);
1411  std::uint32_t freePages = maxPages - pageCount;
1412  std::uint64_t freeSpace =
1413  safe_cast<std::uint64_t>(freePages) * pageSize;
1414  JLOG(j.info())
1415  << "Transaction DB pathname: " << dbPath.string()
1416  << "; file size: " << dbSize.value_or(-1) << " bytes"
1417  << "; SQLite page size: " << pageSize << " bytes"
1418  << "; Free pages: " << freePages << "; Free space: " << freeSpace
1419  << " bytes; "
1420  << "Note that this does not take into account available disk "
1421  "space.";
1422 
1423  if (freeSpace < megabytes(512))
1424  {
1425  JLOG(j.fatal())
1426  << "Free SQLite space for transaction db is less than "
1427  "512MB. To fix this, rippled must be executed with the "
1428  "vacuum parameter before restarting. "
1429  "Note that this activity can take multiple days, "
1430  "depending on database size.";
1431  return false;
1432  }
1433  }
1434 
1435  return true;
1436 }
1437 
1438 } // 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:454
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:90
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:614
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:508
ripple::SHAMap::getHash
SHAMapHash getHash() const
Definition: SHAMap.cpp:843
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:896
std::exception
STL class.
ripple::base_uint::isNonZero
bool isNonZero() const
Definition: base_uint.h:530
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:802
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:1017
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:162
ripple::setup_DatabaseCon
DatabaseCon::Setup setup_DatabaseCon(Config const &c, std::optional< beast::Journal > j=std::nullopt)
Definition: DatabaseCon.cpp:106
ripple::DatabaseCon::Setup::startUp
Config::StartUpType startUp
Definition: DatabaseCon.h:88
std::vector
STL class.
std::string::length
T length(T... args)
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:1246
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:497
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:485
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:473
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:384
ripple::uint256
base_uint< 256 > uint256
Definition: base_uint.h:543
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:909
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:972
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:547
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:945
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:1028
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:1269
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:538
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:1223
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:41
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:691
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:1350
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:1061
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:465
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