rippled
RelationalDBInterface_global.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/TransactionMaster.h>
24 #include <ripple/app/misc/Manifest.h>
25 #include <ripple/app/rdb/RelationalDBInterface_global.h>
26 #include <ripple/basics/BasicConfig.h>
27 #include <ripple/basics/StringUtilities.h>
28 #include <ripple/core/DatabaseCon.h>
29 #include <ripple/core/SociDB.h>
30 #include <ripple/json/to_string.h>
31 #include <boost/algorithm/string.hpp>
32 #include <boost/range/adaptor/transformed.hpp>
33 #include <soci/sqlite3/soci-sqlite3.h>
34 
35 namespace ripple {
36 
37 /* Wallet DB */
38 
41 {
42  // wallet database
43  return std::make_unique<DatabaseCon>(
45 }
46 
48 makeTestWalletDB(DatabaseCon::Setup const& setup, std::string const& dbname)
49 {
50  // wallet database
51  return std::make_unique<DatabaseCon>(
52  setup, dbname.data(), std::array<char const*, 0>(), WalletDBInit);
53 }
54 
55 void
57  soci::session& session,
58  std::string const& dbTable,
59  ManifestCache& mCache,
61 {
62  // Load manifests stored in database
63  std::string const sql = "SELECT RawData FROM " + dbTable + ";";
64  soci::blob sociRawData(session);
65  soci::statement st = (session.prepare << sql, soci::into(sociRawData));
66  st.execute();
67  while (st.fetch())
68  {
69  std::string serialized;
70  convert(sociRawData, serialized);
71  if (auto mo = deserializeManifest(serialized))
72  {
73  if (!mo->verify())
74  {
75  JLOG(j.warn()) << "Unverifiable manifest in db";
76  continue;
77  }
78 
79  mCache.applyManifest(std::move(*mo));
80  }
81  else
82  {
83  JLOG(j.warn()) << "Malformed manifest in database";
84  }
85  }
86 }
87 
88 static void
90  soci::session& session,
91  std::string const& dbTable,
92  std::string const& serialized)
93 {
94  // soci does not support bulk insertion of blob data
95  // Do not reuse blob because manifest ecdsa signatures vary in length
96  // but blob write length is expected to be >= the last write
97  soci::blob rawData(session);
98  convert(serialized, rawData);
99  session << "INSERT INTO " << dbTable << " (RawData) VALUES (:rawData);",
100  soci::use(rawData);
101 }
102 
103 void
105  soci::session& session,
106  std::string const& dbTable,
107  std::function<bool(PublicKey const&)> const& isTrusted,
109  beast::Journal j)
110 {
111  soci::transaction tr(session);
112  session << "DELETE FROM " << dbTable;
113  for (auto const& v : map)
114  {
115  // Save all revocation manifests,
116  // but only save trusted non-revocation manifests.
117  if (!v.second.revoked() && !isTrusted(v.second.masterKey))
118  {
119  JLOG(j.info()) << "Untrusted manifest in cache not saved to db";
120  continue;
121  }
122 
123  saveManifest(session, dbTable, v.second.serialized);
124  }
125  tr.commit();
126 }
127 
128 void
129 addValidatorManifest(soci::session& session, std::string const& serialized)
130 {
131  soci::transaction tr(session);
132  saveManifest(session, "ValidatorManifests", serialized);
133  tr.commit();
134 }
135 
137 getNodeIdentity(soci::session& session)
138 {
139  {
140  // SOCI requires boost::optional (not std::optional) as the parameter.
141  boost::optional<std::string> pubKO, priKO;
142  soci::statement st =
143  (session.prepare
144  << "SELECT PublicKey, PrivateKey FROM NodeIdentity;",
145  soci::into(pubKO),
146  soci::into(priKO));
147  st.execute();
148  while (st.fetch())
149  {
150  auto const sk = parseBase58<SecretKey>(
151  TokenType::NodePrivate, priKO.value_or(""));
152  auto const pk = parseBase58<PublicKey>(
153  TokenType::NodePublic, pubKO.value_or(""));
154 
155  // Only use if the public and secret keys are a pair
156  if (sk && pk && (*pk == derivePublicKey(KeyType::secp256k1, *sk)))
157  return {*pk, *sk};
158  }
159  }
160 
161  // If a valid identity wasn't found, we randomly generate a new one:
162  auto [newpublicKey, newsecretKey] = randomKeyPair(KeyType::secp256k1);
163 
164  session << str(
165  boost::format("INSERT INTO NodeIdentity (PublicKey,PrivateKey) "
166  "VALUES ('%s','%s');") %
167  toBase58(TokenType::NodePublic, newpublicKey) %
168  toBase58(TokenType::NodePrivate, newsecretKey));
169 
170  return {newpublicKey, newsecretKey};
171 }
172 
174 getPeerReservationTable(soci::session& session, beast::Journal j)
175 {
177  // These values must be boost::optionals (not std) because SOCI expects
178  // boost::optionals.
179  boost::optional<std::string> valPubKey, valDesc;
180  // We should really abstract the table and column names into constants,
181  // but no one else does. Because it is too tedious? It would be easy if we
182  // had a jOOQ for C++.
183  soci::statement st =
184  (session.prepare
185  << "SELECT PublicKey, Description FROM PeerReservations;",
186  soci::into(valPubKey),
187  soci::into(valDesc));
188  st.execute();
189  while (st.fetch())
190  {
191  if (!valPubKey || !valDesc)
192  {
193  // This represents a `NULL` in a `NOT NULL` column. It should be
194  // unreachable.
195  continue;
196  }
197  auto const optNodeId =
198  parseBase58<PublicKey>(TokenType::NodePublic, *valPubKey);
199  if (!optNodeId)
200  {
201  JLOG(j.warn()) << "load: not a public key: " << valPubKey;
202  continue;
203  }
204  table.insert(PeerReservation{*optNodeId, *valDesc});
205  }
206 
207  return table;
208 }
209 
210 void
212  soci::session& session,
213  PublicKey const& nodeId,
214  std::string const& description)
215 {
216  session << "INSERT INTO PeerReservations (PublicKey, Description) "
217  "VALUES (:nodeId, :desc) "
218  "ON CONFLICT (PublicKey) DO UPDATE SET "
219  "Description=excluded.Description",
220  soci::use(toBase58(TokenType::NodePublic, nodeId)),
221  soci::use(description);
222 }
223 
224 void
225 deletePeerReservation(soci::session& session, PublicKey const& nodeId)
226 {
227  session << "DELETE FROM PeerReservations WHERE PublicKey = :nodeId",
228  soci::use(toBase58(TokenType::NodePublic, nodeId));
229 }
230 
231 bool
232 createFeatureVotes(soci::session& session)
233 {
234  soci::transaction tr(session);
235  std::string sql =
236  "SELECT count(*) FROM sqlite_master "
237  "WHERE type='table' AND name='FeatureVotes'";
238  // SOCI requires boost::optional (not std::optional) as the parameter.
239  boost::optional<int> featureVotesCount;
240  session << sql, soci::into(featureVotesCount);
241  bool exists = static_cast<bool>(*featureVotesCount);
242 
243  // Create FeatureVotes table in WalletDB if it doesn't exist
244  if (!exists)
245  {
246  session << "CREATE TABLE FeatureVotes ( "
247  "AmendmentHash CHARACTER(64) NOT NULL, "
248  "AmendmentName TEXT, "
249  "Veto INTEGER NOT NULL );";
250  tr.commit();
251  }
252  return exists;
253 }
254 
255 void
257  soci::session& session,
258  std::function<void(
259  boost::optional<std::string> amendment_hash,
260  boost::optional<std::string> amendment_name,
261  boost::optional<AmendmentVote> vote)> const& callback)
262 {
263  // lambda that converts the internally stored int to an AmendmentVote.
264  auto intToVote = [](boost::optional<int> const& dbVote)
265  -> boost::optional<AmendmentVote> {
266  return safe_cast<AmendmentVote>(dbVote.value_or(1));
267  };
268 
269  soci::transaction tr(session);
270  std::string sql =
271  "SELECT AmendmentHash, AmendmentName, Veto FROM FeatureVotes";
272  // SOCI requires boost::optional (not std::optional) as parameters.
273  boost::optional<std::string> amendment_hash;
274  boost::optional<std::string> amendment_name;
275  boost::optional<int> vote_to_veto;
276  soci::statement st =
277  (session.prepare << sql,
278  soci::into(amendment_hash),
279  soci::into(amendment_name),
280  soci::into(vote_to_veto));
281  st.execute();
282  while (st.fetch())
283  {
284  callback(amendment_hash, amendment_name, intToVote(vote_to_veto));
285  }
286 }
287 
288 void
290  soci::session& session,
291  uint256 const& amendment,
292  std::string const& name,
293  AmendmentVote vote)
294 {
295  soci::transaction tr(session);
296  std::string sql =
297  "INSERT INTO FeatureVotes (AmendmentHash, AmendmentName, Veto) VALUES "
298  "('";
299  sql += to_string(amendment);
300  sql += "', '" + name;
301  sql += "', '" + std::to_string(safe_cast<int>(vote)) + "');";
302  session << sql;
303  tr.commit();
304 }
305 
306 /* State DB */
307 
308 void
310  soci::session& session,
311  BasicConfig const& config,
312  std::string const& dbName)
313 {
314  open(session, config, dbName);
315 
316  session << "PRAGMA synchronous=FULL;";
317 
318  session << "CREATE TABLE IF NOT EXISTS DbState ("
319  " Key INTEGER PRIMARY KEY,"
320  " WritableDb TEXT,"
321  " ArchiveDb TEXT,"
322  " LastRotatedLedger INTEGER"
323  ");";
324 
325  session << "CREATE TABLE IF NOT EXISTS CanDelete ("
326  " Key INTEGER PRIMARY KEY,"
327  " CanDeleteSeq INTEGER"
328  ");";
329 
330  std::int64_t count = 0;
331  {
332  // SOCI requires boost::optional (not std::optional) as the parameter.
333  boost::optional<std::int64_t> countO;
334  session << "SELECT COUNT(Key) FROM DbState WHERE Key = 1;",
335  soci::into(countO);
336  if (!countO)
337  Throw<std::runtime_error>(
338  "Failed to fetch Key Count from DbState.");
339  count = *countO;
340  }
341 
342  if (!count)
343  {
344  session << "INSERT INTO DbState VALUES (1, '', '', 0);";
345  }
346 
347  {
348  // SOCI requires boost::optional (not std::optional) as the parameter.
349  boost::optional<std::int64_t> countO;
350  session << "SELECT COUNT(Key) FROM CanDelete WHERE Key = 1;",
351  soci::into(countO);
352  if (!countO)
353  Throw<std::runtime_error>(
354  "Failed to fetch Key Count from CanDelete.");
355  count = *countO;
356  }
357 
358  if (!count)
359  {
360  session << "INSERT INTO CanDelete VALUES (1, 0);";
361  }
362 }
363 
365 getCanDelete(soci::session& session)
366 {
367  LedgerIndex seq;
368  session << "SELECT CanDeleteSeq FROM CanDelete WHERE Key = 1;",
369  soci::into(seq);
370  ;
371  return seq;
372 }
373 
375 setCanDelete(soci::session& session, LedgerIndex canDelete)
376 {
377  session << "UPDATE CanDelete SET CanDeleteSeq = :canDelete WHERE Key = 1;",
378  soci::use(canDelete);
379  return canDelete;
380 }
381 
382 SavedState
383 getSavedState(soci::session& session)
384 {
385  SavedState state;
386  session << "SELECT WritableDb, ArchiveDb, LastRotatedLedger"
387  " FROM DbState WHERE Key = 1;",
388  soci::into(state.writableDb), soci::into(state.archiveDb),
389  soci::into(state.lastRotated);
390 
391  return state;
392 }
393 
394 void
395 setSavedState(soci::session& session, SavedState const& state)
396 {
397  session << "UPDATE DbState"
398  " SET WritableDb = :writableDb,"
399  " ArchiveDb = :archiveDb,"
400  " LastRotatedLedger = :lastRotated"
401  " WHERE Key = 1;",
402  soci::use(state.writableDb), soci::use(state.archiveDb),
403  soci::use(state.lastRotated);
404 }
405 
406 void
407 setLastRotated(soci::session& session, LedgerIndex seq)
408 {
409  session << "UPDATE DbState SET LastRotatedLedger = :seq"
410  " WHERE Key = 1;",
411  soci::use(seq);
412 }
413 
414 /* DatabaseBody DB */
415 
418  DatabaseCon::Setup const& setup,
419  boost::filesystem::path const& path)
420 {
421  // SOCI requires boost::optional (not std::optional) as the parameter.
422  boost::optional<std::string> pathFromDb;
423  boost::optional<std::uint64_t> size;
424 
425  auto conn = std::make_unique<DatabaseCon>(
426  setup, "Download", DownloaderDBPragma, DatabaseBodyDBInit);
427 
428  auto& session = *conn->checkoutDb();
429 
430  session << "SELECT Path FROM Download WHERE Part=0;",
431  soci::into(pathFromDb);
432 
433  // Try to reuse preexisting
434  // database.
435  if (pathFromDb)
436  {
437  // Can't resuse - database was
438  // from a different file download.
439  if (pathFromDb != path.string())
440  {
441  session << "DROP TABLE Download;";
442  }
443 
444  // Continuing a file download.
445  else
446  {
447  session << "SELECT SUM(LENGTH(Data)) FROM Download;",
448  soci::into(size);
449  }
450  }
451 
452  return {std::move(conn), (size ? *size : std::optional<std::uint64_t>())};
453 }
454 
457  soci::session& session,
458  std::string const& data,
459  std::string const& path,
460  std::uint64_t fileSize,
461  std::uint64_t part,
462  std::uint16_t maxRowSizePad)
463 {
464  std::uint64_t rowSize = 0;
465  soci::indicator rti;
466 
467  std::uint64_t remainingInRow = 0;
468 
469  auto be =
470  dynamic_cast<soci::sqlite3_session_backend*>(session.get_backend());
471  BOOST_ASSERT(be);
472 
473  // This limits how large we can make the blob
474  // in each row. Also subtract a pad value to
475  // account for the other values in the row.
476  auto const blobMaxSize =
477  sqlite_api::sqlite3_limit(be->conn_, SQLITE_LIMIT_LENGTH, -1) -
478  maxRowSizePad;
479 
480  std::string newpath;
481 
482  auto rowInit = [&] {
483  session << "INSERT INTO Download VALUES (:path, zeroblob(0), 0, :part)",
484  soci::use(newpath), soci::use(part);
485 
486  remainingInRow = blobMaxSize;
487  rowSize = 0;
488  };
489 
490  session << "SELECT Path,Size,Part FROM Download ORDER BY Part DESC "
491  "LIMIT 1",
492  soci::into(newpath), soci::into(rowSize), soci::into(part, rti);
493 
494  if (!session.got_data())
495  {
496  newpath = path;
497  rowInit();
498  }
499  else
500  remainingInRow = blobMaxSize - rowSize;
501 
502  auto insert = [&session, &rowSize, &part, &fs = fileSize](
503  auto const& data) {
504  std::uint64_t updatedSize = rowSize + data.size();
505 
506  session << "UPDATE Download SET Data = CAST(Data || :data AS blob), "
507  "Size = :size WHERE Part = :part;",
508  soci::use(data), soci::use(updatedSize), soci::use(part);
509 
510  fs += data.size();
511  };
512 
513  size_t currentBase = 0;
514 
515  while (currentBase + remainingInRow < data.size())
516  {
517  if (remainingInRow)
518  {
519  insert(data.substr(currentBase, remainingInRow));
520  currentBase += remainingInRow;
521  }
522 
523  ++part;
524  rowInit();
525  }
526 
527  insert(data.substr(currentBase));
528 
529  return part;
530 }
531 
532 void
533 databaseBodyFinish(soci::session& session, std::ofstream& fout)
534 {
535  soci::rowset<std::string> rs =
536  (session.prepare << "SELECT Data FROM Download ORDER BY PART ASC;");
537 
538  // iteration through the resultset:
539  for (auto it = rs.begin(); it != rs.end(); ++it)
540  fout.write(it->data(), it->size());
541 }
542 
543 /* Vacuum DB */
544 
545 bool
547 {
548  boost::filesystem::path dbPath = setup.dataDir / TxDBName;
549 
550  uintmax_t const dbSize = file_size(dbPath);
551  assert(dbSize != static_cast<uintmax_t>(-1));
552 
553  if (auto available = space(dbPath.parent_path()).available;
554  available < dbSize)
555  {
556  std::cerr << "The database filesystem must have at least as "
557  "much free space as the size of "
558  << dbPath.string() << ", which is " << dbSize
559  << " bytes. Only " << available << " bytes are available.\n";
560  return false;
561  }
562 
563  auto txnDB =
564  std::make_unique<DatabaseCon>(setup, TxDBName, TxDBPragma, TxDBInit);
565  auto& session = txnDB->getSession();
566  std::uint32_t pageSize;
567 
568  // Only the most trivial databases will fit in memory on typical
569  // (recommended) software. Force temp files to be written to disk
570  // regardless of the config settings.
571  session << boost::format(CommonDBPragmaTemp) % "file";
572  session << "PRAGMA page_size;", soci::into(pageSize);
573 
574  std::cout << "VACUUM beginning. page_size: " << pageSize << std::endl;
575 
576  session << "VACUUM;";
577  assert(setup.globalPragma);
578  for (auto const& p : *setup.globalPragma)
579  session << p;
580  session << "PRAGMA page_size;", soci::into(pageSize);
581 
582  std::cout << "VACUUM finished. page_size: " << pageSize << std::endl;
583 
584  return true;
585 }
586 
587 /* PeerFinder DB */
588 
589 void
591  soci::session& session,
592  BasicConfig const& config,
593  beast::Journal j)
594 {
595  DBConfig m_sociConfig(config, "peerfinder");
596  m_sociConfig.open(session);
597 
598  JLOG(j.info()) << "Opening database at '" << m_sociConfig.connectionString()
599  << "'";
600 
601  soci::transaction tr(session);
602  session << "PRAGMA encoding=\"UTF-8\";";
603 
604  session << "CREATE TABLE IF NOT EXISTS SchemaVersion ( "
605  " name TEXT PRIMARY KEY, "
606  " version INTEGER"
607  ");";
608 
609  session << "CREATE TABLE IF NOT EXISTS PeerFinder_BootstrapCache ( "
610  " id INTEGER PRIMARY KEY AUTOINCREMENT, "
611  " address TEXT UNIQUE NOT NULL, "
612  " valence INTEGER"
613  ");";
614 
615  session << "CREATE INDEX IF NOT EXISTS "
616  " PeerFinder_BootstrapCache_Index ON "
617  "PeerFinder_BootstrapCache "
618  " ( "
619  " address "
620  " ); ";
621 
622  tr.commit();
623 }
624 
625 void
627  soci::session& session,
628  int currentSchemaVersion,
629  beast::Journal j)
630 {
631  soci::transaction tr(session);
632  // get version
633  int version(0);
634  {
635  // SOCI requires a boost::optional (not std::optional) parameter.
636  boost::optional<int> vO;
637  session << "SELECT "
638  " version "
639  "FROM SchemaVersion WHERE "
640  " name = 'PeerFinder';",
641  soci::into(vO);
642 
643  version = vO.value_or(0);
644 
645  JLOG(j.info()) << "Opened version " << version << " database";
646  }
647 
648  {
649  if (version < currentSchemaVersion)
650  {
651  JLOG(j.info()) << "Updating database to version "
652  << currentSchemaVersion;
653  }
654  else if (version > currentSchemaVersion)
655  {
656  Throw<std::runtime_error>(
657  "The PeerFinder database version is higher than expected");
658  }
659  }
660 
661  if (version < 4)
662  {
663  //
664  // Remove the "uptime" column from the bootstrap table
665  //
666 
667  session << "CREATE TABLE IF NOT EXISTS "
668  "PeerFinder_BootstrapCache_Next ( "
669  " id INTEGER PRIMARY KEY AUTOINCREMENT, "
670  " address TEXT UNIQUE NOT NULL, "
671  " valence INTEGER"
672  ");";
673 
674  session << "CREATE INDEX IF NOT EXISTS "
675  " PeerFinder_BootstrapCache_Next_Index ON "
676  " PeerFinder_BootstrapCache_Next "
677  " ( address ); ";
678 
679  std::size_t count;
680  session << "SELECT COUNT(*) FROM PeerFinder_BootstrapCache;",
681  soci::into(count);
682 
684 
685  {
686  list.reserve(count);
687  std::string s;
688  int valence;
689  soci::statement st =
690  (session.prepare << "SELECT "
691  " address, "
692  " valence "
693  "FROM PeerFinder_BootstrapCache;",
694  soci::into(s),
695  soci::into(valence));
696 
697  st.execute();
698  while (st.fetch())
699  {
702  if (!is_unspecified(entry.endpoint))
703  {
704  entry.valence = valence;
705  list.push_back(entry);
706  }
707  else
708  {
709  JLOG(j.error()) << "Bad address string '" << s
710  << "' in Bootcache table";
711  }
712  }
713  }
714 
715  if (!list.empty())
716  {
718  std::vector<int> valence;
719  s.reserve(list.size());
720  valence.reserve(list.size());
721 
722  for (auto iter(list.cbegin()); iter != list.cend(); ++iter)
723  {
724  s.emplace_back(to_string(iter->endpoint));
725  valence.emplace_back(iter->valence);
726  }
727 
728  session << "INSERT INTO PeerFinder_BootstrapCache_Next ( "
729  " address, "
730  " valence "
731  ") VALUES ( "
732  " :s, :valence"
733  ");",
734  soci::use(s), soci::use(valence);
735  }
736 
737  session << "DROP TABLE IF EXISTS PeerFinder_BootstrapCache;";
738 
739  session << "DROP INDEX IF EXISTS PeerFinder_BootstrapCache_Index;";
740 
741  session << "ALTER TABLE PeerFinder_BootstrapCache_Next "
742  " RENAME TO PeerFinder_BootstrapCache;";
743 
744  session << "CREATE INDEX IF NOT EXISTS "
745  " PeerFinder_BootstrapCache_Index ON "
746  "PeerFinder_BootstrapCache "
747  " ( "
748  " address "
749  " ); ";
750  }
751 
752  if (version < 3)
753  {
754  //
755  // Remove legacy endpoints from the schema
756  //
757 
758  session << "DROP TABLE IF EXISTS LegacyEndpoints;";
759 
760  session << "DROP TABLE IF EXISTS PeerFinderLegacyEndpoints;";
761 
762  session << "DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints;";
763 
764  session << "DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints_Index;";
765  }
766 
767  {
768  int const v(currentSchemaVersion);
769  session << "INSERT OR REPLACE INTO SchemaVersion ("
770  " name "
771  " ,version "
772  ") VALUES ( "
773  " 'PeerFinder', :version "
774  ");",
775  soci::use(v);
776  }
777 
778  tr.commit();
779 }
780 
781 void
783  soci::session& session,
784  std::function<void(std::string const&, int)> const& func)
785 {
786  std::string s;
787  int valence;
788  soci::statement st =
789  (session.prepare << "SELECT "
790  " address, "
791  " valence "
792  "FROM PeerFinder_BootstrapCache;",
793  soci::into(s),
794  soci::into(valence));
795 
796  st.execute();
797  while (st.fetch())
798  {
799  func(s, valence);
800  }
801 }
802 
803 void
805  soci::session& session,
807 {
808  soci::transaction tr(session);
809  session << "DELETE FROM PeerFinder_BootstrapCache;";
810 
811  if (!v.empty())
812  {
814  std::vector<int> valence;
815  s.reserve(v.size());
816  valence.reserve(v.size());
817 
818  for (auto const& e : v)
819  {
820  s.emplace_back(to_string(e.endpoint));
821  valence.emplace_back(e.valence);
822  }
823 
824  session << "INSERT INTO PeerFinder_BootstrapCache ( "
825  " address, "
826  " valence "
827  ") VALUES ( "
828  " :s, :valence "
829  ");",
830  soci::use(s), soci::use(valence);
831  }
832 
833  tr.commit();
834 }
835 
836 } // namespace ripple
ripple::getNodeIdentity
std::pair< PublicKey, SecretKey > getNodeIdentity(Application &app)
The cryptographic credentials identifying this server instance.
Definition: NodeIdentity.cpp:32
ripple::setCanDelete
LedgerIndex setCanDelete(soci::session &session, LedgerIndex canDelete)
setCanDelete Updates ledger sequence which can be deleted.
Definition: RelationalDBInterface_global.cpp:375
ripple::WalletDBName
constexpr auto WalletDBName
Definition: DBInit.h:187
ripple::DatabaseCon::Setup::globalPragma
static std::unique_ptr< std::vector< std::string > const > globalPragma
Definition: DatabaseCon.h:104
ripple::LedgerIndex
std::uint32_t LedgerIndex
A ledger index.
Definition: Protocol.h:57
std::string
STL class.
ripple::DatabaseCon::Setup
Definition: DatabaseCon.h:84
ripple::DBConfig::connectionString
std::string connectionString() const
Definition: SociDB.cpp:86
ripple::initPeerFinderDB
void initPeerFinderDB(soci::session &session, BasicConfig const &config, beast::Journal j)
initPeerFinderDB Opens session with peer finder database.
Definition: RelationalDBInterface_global.cpp:590
std::unordered_set
STL class.
std::pair
std::vector::reserve
T reserve(T... args)
ripple::convert
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition: SociDB.cpp:154
ripple::setSavedState
void setSavedState(soci::session &session, SavedState const &state)
setSavedState Saves given state.
Definition: RelationalDBInterface_global.cpp:395
ripple::createFeatureVotes
bool createFeatureVotes(soci::session &session)
createFeatureVotes Creates FeatureVote table if it is not exists.
Definition: RelationalDBInterface_global.cpp:232
ripple::DBConfig::open
void open(soci::session &s) const
Definition: SociDB.cpp:92
std::vector
STL class.
std::vector::size
T size(T... args)
ripple::updatePeerFinderDB
void updatePeerFinderDB(soci::session &session, int currentSchemaVersion, beast::Journal j)
updatePeerFinderDB Update peer finder DB to new version.
Definition: RelationalDBInterface_global.cpp:626
ripple::SavedState::writableDb
std::string writableDb
Definition: RelationalDBInterface_global.h:171
ripple::toBase58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:29
beast::Journal::warn
Stream warn() const
Definition: Journal.h:327
ripple::addValidatorManifest
void addValidatorManifest(soci::session &session, std::string const &serialized)
addValidatorManifest Saves manifest of validator to database.
Definition: RelationalDBInterface_global.cpp:129
ripple::DBConfig
DBConfig is used when a client wants to delay opening a soci::session after parsing the config parame...
Definition: SociDB.h:57
std::cerr
ripple::DatabaseCon::Setup::dataDir
boost::filesystem::path dataDir
Definition: DatabaseCon.h:91
std::function
ripple::makeTestWalletDB
std::unique_ptr< DatabaseCon > makeTestWalletDB(DatabaseCon::Setup const &setup, std::string const &dbname)
makeTestWalletDB Opens test wallet DB with arbitrary name.
Definition: RelationalDBInterface_global.cpp:48
std::ofstream::write
T write(T... args)
std::vector::push_back
T push_back(T... args)
std::cout
ripple::DownloaderDBPragma
static constexpr std::array< char const *, 2 > DownloaderDBPragma
Definition: DBInit.h:225
ripple::TxDBName
constexpr auto TxDBName
Definition: DBInit.h:73
ripple::base_uint
Integers of any length that is a multiple of 32-bits.
Definition: base_uint.h:75
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::derivePublicKey
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
Definition: SecretKey.cpp:313
std::ofstream
STL class.
ripple::readPeerFinderDB
void readPeerFinderDB(soci::session &session, std::function< void(std::string const &, int)> const &func)
readPeerFinderDB Read all entries from peer finder DB and call given callback for each entry.
Definition: RelationalDBInterface_global.cpp:782
ripple::getManifests
void getManifests(soci::session &session, std::string const &dbTable, ManifestCache &mCache, beast::Journal j)
getManifests Loads manifest from wallet DB and stores it in the cache.
Definition: RelationalDBInterface_global.cpp:56
ripple::insertPeerReservation
void insertPeerReservation(soci::session &session, PublicKey const &nodeId, std::string const &description)
insertPeerReservation Adds entry to peer reservation table.
Definition: RelationalDBInterface_global.cpp:211
ripple::deletePeerReservation
void deletePeerReservation(soci::session &session, PublicKey const &nodeId)
deletePeerReservation Deletes entry from peer reservation table.
Definition: RelationalDBInterface_global.cpp:225
ripple::readAmendments
void readAmendments(soci::session &session, std::function< void(boost::optional< std::string > amendment_hash, boost::optional< std::string > amendment_name, boost::optional< AmendmentVote > vote)> const &callback)
readAmendments Read all amendments from FeatureVotes table.
Definition: RelationalDBInterface_global.cpp:256
std::to_string
T to_string(T... args)
std::array
STL class.
ripple::PeerFinder::Store::Entry::valence
int valence
Definition: Store.h:45
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
ripple::initStateDB
void initStateDB(soci::session &session, BasicConfig const &config, std::string const &dbName)
initStateDB Opens DB session with State DB.
Definition: RelationalDBInterface_global.cpp:309
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
std::int64_t
ripple::CommonDBPragmaTemp
constexpr char const * CommonDBPragmaTemp
Definition: DBInit.h:34
ripple::PeerReservation
Definition: PeerReservationTable.h:43
ripple::getSavedState
SavedState getSavedState(soci::session &session)
getSavedState Returns saved state.
Definition: RelationalDBInterface_global.cpp:383
ripple::databaseBodyDoPut
std::uint64_t databaseBodyDoPut(soci::session &session, std::string const &data, std::string const &path, std::uint64_t fileSize, std::uint64_t part, std::uint16_t maxRowSizePad)
databaseBodyDoPut Saves new fragment of downloaded file.
Definition: RelationalDBInterface_global.cpp:456
ripple::KeyType::secp256k1
@ secp256k1
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
ripple::getPeerReservationTable
std::unordered_set< PeerReservation, beast::uhash<>, KeyEqual > getPeerReservationTable(soci::session &session, beast::Journal j)
getPeerReservationTable Returns peer reservation table.
Definition: RelationalDBInterface_global.cpp:174
ripple::ManifestCache
Remembers manifests with the highest sequence number.
Definition: Manifest.h:223
ripple::setLastRotated
void setLastRotated(soci::session &session, LedgerIndex seq)
setLastRotated Updates last rotated ledger sequence.
Definition: RelationalDBInterface_global.cpp:407
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
std::endl
T endl(T... args)
std::vector::cbegin
T cbegin(T... args)
std::unordered_set::insert
T insert(T... args)
ripple::SavedState::archiveDb
std::string archiveDb
Definition: RelationalDBInterface_global.h:172
beast::IP::Endpoint::from_string
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:46
ripple::getCanDelete
LedgerIndex getCanDelete(soci::session &session)
getCanDelete Returns ledger sequence which can be deleted.
Definition: RelationalDBInterface_global.cpp:365
ripple::voteAmendment
void voteAmendment(soci::session &session, uint256 const &amendment, std::string const &name, AmendmentVote vote)
voteAmendment Set veto value for particular amendment.
Definition: RelationalDBInterface_global.cpp:289
ripple::makeWalletDB
std::unique_ptr< DatabaseCon > makeWalletDB(DatabaseCon::Setup const &setup)
makeWalletDB Opens wallet DB and returns it.
Definition: RelationalDBInterface_global.cpp:40
ripple::saveManifest
static void saveManifest(soci::session &session, std::string const &dbTable, std::string const &serialized)
Definition: RelationalDBInterface_global.cpp:89
ripple::SavedState::lastRotated
LedgerIndex lastRotated
Definition: RelationalDBInterface_global.h:173
ripple::savePeerFinderDB
void savePeerFinderDB(soci::session &session, std::vector< PeerFinder::Store::Entry > const &v)
savePeerFinderDB Save new entry to peer finder DB.
Definition: RelationalDBInterface_global.cpp:804
ripple::TxDBPragma
constexpr std::array TxDBPragma
Definition: DBInit.h:76
std::vector::empty
T empty(T... args)
ripple::AmendmentVote
AmendmentVote
Definition: RelationalDBInterface_global.h:137
ripple::TokenType::NodePublic
@ NodePublic
ripple::openDatabaseBodyDb
std::pair< std::unique_ptr< DatabaseCon >, std::optional< std::uint64_t > > openDatabaseBodyDb(DatabaseCon::Setup const &setup, boost::filesystem::path const &path)
openDatabaseBodyDb Opens file download DB and returns its descriptor.
Definition: RelationalDBInterface_global.cpp:417
std::optional
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:38
ripple::databaseBodyFinish
void databaseBodyFinish(soci::session &session, std::ofstream &fout)
databaseBodyFinish Finishes download process and writes file to disk.
Definition: RelationalDBInterface_global.cpp:533
std::vector::cend
T cend(T... args)
ripple::DatabaseBodyDBInit
static constexpr std::array< char const *, 3 > DatabaseBodyDBInit
Definition: DBInit.h:238
ripple::doVacuumDB
bool doVacuumDB(DatabaseCon::Setup const &setup)
doVacuumDB Creates, initialises DB, and performs its cleanup.
Definition: RelationalDBInterface_global.cpp:546
ripple::KeyEqual
Definition: PeerReservationTable.h:70
ripple::TxDBInit
constexpr std::array< char const *, 8 > TxDBInit
Definition: DBInit.h:84
ripple::PeerFinder::Store::Entry
Definition: Store.h:40
ripple::WalletDBInit
constexpr std::array< char const *, 6 > WalletDBInit
Definition: DBInit.h:189
std::unique_ptr
STL class.
ripple::ManifestCache::applyManifest
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition: app/misc/impl/Manifest.cpp:356
std::unordered_map
STL class.
ripple::deserializeManifest
std::optional< Manifest > deserializeManifest(Slice s)
Constructs Manifest from serialized string.
Definition: app/misc/impl/Manifest.cpp:50
ripple::SavedState
Definition: RelationalDBInterface_global.h:169
ripple::saveManifests
void saveManifests(soci::session &session, std::string const &dbTable, std::function< bool(PublicKey const &)> const &isTrusted, hash_map< PublicKey, Manifest > const &map, beast::Journal j)
saveManifests Saves all given manifests to database.
Definition: RelationalDBInterface_global.cpp:104
std::string::data
T data(T... args)
ripple::PeerFinder::Store::Entry::endpoint
beast::IP::Endpoint endpoint
Definition: Store.h:44
ripple::BasicConfig
Holds unparsed configuration information.
Definition: BasicConfig.h:215
ripple::TokenType::NodePrivate
@ NodePrivate
ripple::PublisherStatus::available
@ available
ripple::open
void open(soci::session &s, BasicConfig const &config, std::string const &dbName)
Open a soci session.
Definition: SociDB.cpp:98