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>
43 return std::make_unique<DatabaseCon>(
51 return std::make_unique<DatabaseCon>(
57 soci::session& session,
63 std::string const sql =
"SELECT RawData FROM " + dbTable +
";";
64 soci::blob sociRawData(session);
65 soci::statement st = (session.prepare << sql, soci::into(sociRawData));
70 convert(sociRawData, serialized);
75 JLOG(j.
warn()) <<
"Unverifiable manifest in db";
83 JLOG(j.
warn()) <<
"Malformed manifest in database";
90 soci::session& session,
97 soci::blob rawData(session);
99 session <<
"INSERT INTO " << dbTable <<
" (RawData) VALUES (:rawData);",
105 soci::session& session,
111 soci::transaction tr(session);
112 session <<
"DELETE FROM " << dbTable;
113 for (
auto const& v : map)
117 if (!v.second.revoked() && !isTrusted(v.second.masterKey))
119 JLOG(j.
info()) <<
"Untrusted manifest in cache not saved to db";
131 soci::transaction tr(session);
132 saveManifest(session,
"ValidatorManifests", serialized);
141 boost::optional<std::string> pubKO, priKO;
144 <<
"SELECT PublicKey, PrivateKey FROM NodeIdentity;",
150 auto const sk = parseBase58<SecretKey>(
152 auto const pk = parseBase58<PublicKey>(
165 boost::format(
"INSERT INTO NodeIdentity (PublicKey,PrivateKey) "
166 "VALUES ('%s','%s');") %
170 return {newpublicKey, newsecretKey};
179 boost::optional<std::string> valPubKey, valDesc;
185 <<
"SELECT PublicKey, Description FROM PeerReservations;",
186 soci::into(valPubKey),
187 soci::into(valDesc));
191 if (!valPubKey || !valDesc)
197 auto const optNodeId =
201 JLOG(j.
warn()) <<
"load: not a public key: " << valPubKey;
212 soci::session& session,
216 session <<
"INSERT INTO PeerReservations (PublicKey, Description) "
217 "VALUES (:nodeId, :desc) "
218 "ON CONFLICT (PublicKey) DO UPDATE SET "
219 "Description=excluded.Description",
221 soci::use(description);
227 session <<
"DELETE FROM PeerReservations WHERE PublicKey = :nodeId",
234 soci::transaction tr(session);
236 "SELECT count(*) FROM sqlite_master "
237 "WHERE type='table' AND name='FeatureVotes'";
239 boost::optional<int> featureVotesCount;
240 session << sql, soci::into(featureVotesCount);
241 bool exists =
static_cast<bool>(*featureVotesCount);
246 session <<
"CREATE TABLE FeatureVotes ( "
247 "AmendmentHash CHARACTER(64) NOT NULL, "
248 "AmendmentName TEXT, "
249 "Veto INTEGER NOT NULL );";
257 soci::session& session,
259 boost::optional<std::string> amendment_hash,
260 boost::optional<std::string> amendment_name,
261 boost::optional<int> vote_to_veto)>
const& callback)
263 soci::transaction tr(session);
265 "SELECT AmendmentHash, AmendmentName, Veto FROM FeatureVotes";
267 boost::optional<std::string> amendment_hash;
268 boost::optional<std::string> amendment_name;
269 boost::optional<int> vote_to_veto;
271 (session.prepare << sql,
272 soci::into(amendment_hash),
273 soci::into(amendment_name),
274 soci::into(vote_to_veto));
278 callback(amendment_hash, amendment_name, vote_to_veto);
284 soci::session& session,
289 soci::transaction tr(session);
291 "INSERT INTO FeatureVotes (AmendmentHash, AmendmentName, Veto) VALUES "
294 sql +=
"', '" + name;
304 soci::session& session,
308 open(session, config, dbName);
310 session <<
"PRAGMA synchronous=FULL;";
312 session <<
"CREATE TABLE IF NOT EXISTS DbState ("
313 " Key INTEGER PRIMARY KEY,"
316 " LastRotatedLedger INTEGER"
319 session <<
"CREATE TABLE IF NOT EXISTS CanDelete ("
320 " Key INTEGER PRIMARY KEY,"
321 " CanDeleteSeq INTEGER"
327 boost::optional<std::int64_t> countO;
328 session <<
"SELECT COUNT(Key) FROM DbState WHERE Key = 1;",
331 Throw<std::runtime_error>(
332 "Failed to fetch Key Count from DbState.");
338 session <<
"INSERT INTO DbState VALUES (1, '', '', 0);";
343 boost::optional<std::int64_t> countO;
344 session <<
"SELECT COUNT(Key) FROM CanDelete WHERE Key = 1;",
347 Throw<std::runtime_error>(
348 "Failed to fetch Key Count from CanDelete.");
354 session <<
"INSERT INTO CanDelete VALUES (1, 0);";
362 session <<
"SELECT CanDeleteSeq FROM CanDelete WHERE Key = 1;",
371 session <<
"UPDATE CanDelete SET CanDeleteSeq = :canDelete WHERE Key = 1;",
372 soci::use(canDelete);
380 session <<
"SELECT WritableDb, ArchiveDb, LastRotatedLedger"
381 " FROM DbState WHERE Key = 1;",
391 session <<
"UPDATE DbState"
392 " SET WritableDb = :writableDb,"
393 " ArchiveDb = :archiveDb,"
394 " LastRotatedLedger = :lastRotated"
403 session <<
"UPDATE DbState SET LastRotatedLedger = :seq"
413 boost::filesystem::path
const& path)
416 boost::optional<std::string> pathFromDb;
417 boost::optional<std::uint64_t> size;
419 auto conn = std::make_unique<DatabaseCon>(
422 auto& session = *conn->checkoutDb();
424 session <<
"SELECT Path FROM Download WHERE Part=0;",
425 soci::into(pathFromDb);
433 if (pathFromDb != path.string())
435 session <<
"DROP TABLE Download;";
441 session <<
"SELECT SUM(LENGTH(Data)) FROM Download;",
451 soci::session& session,
464 dynamic_cast<soci::sqlite3_session_backend*
>(session.get_backend());
470 auto const blobMaxSize =
471 sqlite_api::sqlite3_limit(be->conn_, SQLITE_LIMIT_LENGTH, -1) -
477 session <<
"INSERT INTO Download VALUES (:path, zeroblob(0), 0, :part)",
478 soci::use(newpath), soci::use(part);
480 remainingInRow = blobMaxSize;
484 session <<
"SELECT Path,Size,Part FROM Download ORDER BY Part DESC "
486 soci::into(newpath), soci::into(rowSize), soci::into(part, rti);
488 if (!session.got_data())
494 remainingInRow = blobMaxSize - rowSize;
496 auto insert = [&session, &rowSize, &part, &fs = fileSize](
500 session <<
"UPDATE Download SET Data = CAST(Data || :data AS blob), "
501 "Size = :size WHERE Part = :part;",
502 soci::use(data), soci::use(updatedSize), soci::use(part);
507 size_t currentBase = 0;
509 while (currentBase + remainingInRow < data.size())
513 insert(data.substr(currentBase, remainingInRow));
514 currentBase += remainingInRow;
521 insert(data.substr(currentBase));
529 soci::rowset<std::string> rs =
530 (session.prepare <<
"SELECT Data FROM Download ORDER BY PART ASC;");
533 for (
auto it = rs.begin(); it != rs.end(); ++it)
534 fout.
write(it->data(), it->size());
544 uintmax_t
const dbSize = file_size(dbPath);
545 assert(dbSize !=
static_cast<uintmax_t
>(-1));
547 if (
auto available = space(dbPath.parent_path()).available;
550 std::cerr <<
"The database filesystem must have at least as "
551 "much free space as the size of "
552 << dbPath.string() <<
", which is " << dbSize
553 <<
" bytes. Only " <<
available <<
" bytes are available.\n";
559 auto& session = txnDB->getSession();
566 session <<
"PRAGMA page_size;", soci::into(pageSize);
570 session <<
"VACUUM;";
574 session <<
"PRAGMA page_size;", soci::into(pageSize);
585 soci::session& session,
589 DBConfig m_sociConfig(config,
"peerfinder");
590 m_sociConfig.
open(session);
595 soci::transaction tr(session);
596 session <<
"PRAGMA encoding=\"UTF-8\";";
598 session <<
"CREATE TABLE IF NOT EXISTS SchemaVersion ( "
599 " name TEXT PRIMARY KEY, "
603 session <<
"CREATE TABLE IF NOT EXISTS PeerFinder_BootstrapCache ( "
604 " id INTEGER PRIMARY KEY AUTOINCREMENT, "
605 " address TEXT UNIQUE NOT NULL, "
609 session <<
"CREATE INDEX IF NOT EXISTS "
610 " PeerFinder_BootstrapCache_Index ON "
611 "PeerFinder_BootstrapCache "
621 soci::session& session,
622 int currentSchemaVersion,
625 soci::transaction tr(session);
630 boost::optional<int> vO;
633 "FROM SchemaVersion WHERE "
634 " name = 'PeerFinder';",
637 version = vO.value_or(0);
639 JLOG(j.
info()) <<
"Opened version " << version <<
" database";
643 if (version < currentSchemaVersion)
645 JLOG(j.
info()) <<
"Updating database to version "
646 << currentSchemaVersion;
648 else if (version > currentSchemaVersion)
650 Throw<std::runtime_error>(
651 "The PeerFinder database version is higher than expected");
661 session <<
"CREATE TABLE IF NOT EXISTS "
662 "PeerFinder_BootstrapCache_Next ( "
663 " id INTEGER PRIMARY KEY AUTOINCREMENT, "
664 " address TEXT UNIQUE NOT NULL, "
668 session <<
"CREATE INDEX IF NOT EXISTS "
669 " PeerFinder_BootstrapCache_Next_Index ON "
670 " PeerFinder_BootstrapCache_Next "
674 session <<
"SELECT COUNT(*) FROM PeerFinder_BootstrapCache;",
684 (session.prepare <<
"SELECT "
687 "FROM PeerFinder_BootstrapCache;",
689 soci::into(valence));
696 if (!is_unspecified(entry.
endpoint))
703 JLOG(j.
error()) <<
"Bad address string '" << s
704 <<
"' in Bootcache table";
716 for (
auto iter(list.
cbegin()); iter != list.
cend(); ++iter)
722 session <<
"INSERT INTO PeerFinder_BootstrapCache_Next ( "
728 soci::use(s), soci::use(valence);
731 session <<
"DROP TABLE IF EXISTS PeerFinder_BootstrapCache;";
733 session <<
"DROP INDEX IF EXISTS PeerFinder_BootstrapCache_Index;";
735 session <<
"ALTER TABLE PeerFinder_BootstrapCache_Next "
736 " RENAME TO PeerFinder_BootstrapCache;";
738 session <<
"CREATE INDEX IF NOT EXISTS "
739 " PeerFinder_BootstrapCache_Index ON "
740 "PeerFinder_BootstrapCache "
752 session <<
"DROP TABLE IF EXISTS LegacyEndpoints;";
754 session <<
"DROP TABLE IF EXISTS PeerFinderLegacyEndpoints;";
756 session <<
"DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints;";
758 session <<
"DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints_Index;";
762 int const v(currentSchemaVersion);
763 session <<
"INSERT OR REPLACE INTO SchemaVersion ("
767 " 'PeerFinder', :version "
777 soci::session& session,
783 (session.prepare <<
"SELECT "
786 "FROM PeerFinder_BootstrapCache;",
788 soci::into(valence));
799 soci::session& session,
802 soci::transaction tr(session);
803 session <<
"DELETE FROM PeerFinder_BootstrapCache;";
812 for (
auto const& e : v)
818 session <<
"INSERT INTO PeerFinder_BootstrapCache ( "
824 soci::use(s), soci::use(valence);
std::pair< PublicKey, SecretKey > getNodeIdentity(Application &app)
The cryptographic credentials identifying this server instance.
LedgerIndex setCanDelete(soci::session &session, LedgerIndex canDelete)
setCanDelete Updates ledger sequence which can be deleted.
constexpr auto WalletDBName
static std::unique_ptr< std::vector< std::string > const > globalPragma
std::uint32_t LedgerIndex
A ledger index.
std::string connectionString() const
void initPeerFinderDB(soci::session &session, BasicConfig const &config, beast::Journal j)
initPeerFinderDB Opens session with peer finder database.
void readAmendments(soci::session &session, std::function< void(boost::optional< std::string > amendment_hash, boost::optional< std::string > amendment_name, boost::optional< int > vote_to_veto)> const &callback)
readAmendments Read all amendments from FeatureVotes table.
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
void setSavedState(soci::session &session, SavedState const &state)
setSavedState Saves given state.
bool createFeatureVotes(soci::session &session)
createFeatureVotes Creates FeatureVote table if it is not exists.
void open(soci::session &s) const
void updatePeerFinderDB(soci::session &session, int currentSchemaVersion, beast::Journal j)
updatePeerFinderDB Update peer finder DB to new version.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
void addValidatorManifest(soci::session &session, std::string const &serialized)
addValidatorManifest Saves manifest of validator to database.
DBConfig is used when a client wants to delay opening a soci::session after parsing the config parame...
boost::filesystem::path dataDir
std::unique_ptr< DatabaseCon > makeTestWalletDB(DatabaseCon::Setup const &setup, std::string const &dbname)
makeTestWalletDB Opens test wallet DB with arbitrary name.
static constexpr std::array< char const *, 2 > DownloaderDBPragma
Integers of any length that is a multiple of 32-bits.
void voteAmendment(soci::session &session, uint256 const &amendment, std::string const &name, bool vote_to_veto)
voteAmendment Set veto value for particular amendment.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
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.
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.
void insertPeerReservation(soci::session &session, PublicKey const &nodeId, std::string const &description)
insertPeerReservation Adds entry to peer reservation table.
void deletePeerReservation(soci::session &session, PublicKey const &nodeId)
deletePeerReservation Deletes entry from peer reservation table.
void initStateDB(soci::session &session, BasicConfig const &config, std::string const &dbName)
initStateDB Opens DB session with State DB.
A generic endpoint for log messages.
constexpr char const * CommonDBPragmaTemp
SavedState getSavedState(soci::session &session)
getSavedState Returns saved state.
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.
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
std::unordered_set< PeerReservation, beast::uhash<>, KeyEqual > getPeerReservationTable(soci::session &session, beast::Journal j)
getPeerReservationTable Returns peer reservation table.
Remembers manifests with the highest sequence number.
void setLastRotated(soci::session &session, LedgerIndex seq)
setLastRotated Updates last rotated ledger sequence.
T emplace_back(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
static Endpoint from_string(std::string const &s)
LedgerIndex getCanDelete(soci::session &session)
getCanDelete Returns ledger sequence which can be deleted.
std::unique_ptr< DatabaseCon > makeWalletDB(DatabaseCon::Setup const &setup)
makeWalletDB Opens wallet DB and returns it.
static void saveManifest(soci::session &session, std::string const &dbTable, std::string const &serialized)
void savePeerFinderDB(soci::session &session, std::vector< PeerFinder::Store::Entry > const &v)
savePeerFinderDB Save new entry to peer finder DB.
constexpr std::array TxDBPragma
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.
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
void databaseBodyFinish(soci::session &session, std::ofstream &fout)
databaseBodyFinish Finishes download process and writes file to disk.
static constexpr std::array< char const *, 3 > DatabaseBodyDBInit
bool doVacuumDB(DatabaseCon::Setup const &setup)
doVacuumDB Creates, initialises DB, and performs its cleanup.
constexpr std::array< char const *, 8 > TxDBInit
constexpr std::array< char const *, 6 > WalletDBInit
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
std::optional< Manifest > deserializeManifest(Slice s)
Constructs Manifest from serialized string.
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.
beast::IP::Endpoint endpoint
Holds unparsed configuration information.
void open(soci::session &s, BasicConfig const &config, std::string const &dbName)
Open a soci session.