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