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