rippled
PeerFinder.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2021 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/rdb/PeerFinder.h>
21 
22 namespace ripple {
23 
24 void
26  soci::session& session,
27  BasicConfig const& config,
29 {
30  DBConfig m_sociConfig(config, "peerfinder");
31  m_sociConfig.open(session);
32 
33  JLOG(j.info()) << "Opening database at '" << m_sociConfig.connectionString()
34  << "'";
35 
36  soci::transaction tr(session);
37  session << "PRAGMA encoding=\"UTF-8\";";
38 
39  session << "CREATE TABLE IF NOT EXISTS SchemaVersion ( "
40  " name TEXT PRIMARY KEY, "
41  " version INTEGER"
42  ");";
43 
44  session << "CREATE TABLE IF NOT EXISTS PeerFinder_BootstrapCache ( "
45  " id INTEGER PRIMARY KEY AUTOINCREMENT, "
46  " address TEXT UNIQUE NOT NULL, "
47  " valence INTEGER"
48  ");";
49 
50  session << "CREATE INDEX IF NOT EXISTS "
51  " PeerFinder_BootstrapCache_Index ON "
52  "PeerFinder_BootstrapCache "
53  " ( "
54  " address "
55  " ); ";
56 
57  tr.commit();
58 }
59 
60 void
62  soci::session& session,
63  int currentSchemaVersion,
65 {
66  soci::transaction tr(session);
67  // get version
68  int version(0);
69  {
70  // SOCI requires a boost::optional (not std::optional) parameter.
71  boost::optional<int> vO;
72  session << "SELECT "
73  " version "
74  "FROM SchemaVersion WHERE "
75  " name = 'PeerFinder';",
76  soci::into(vO);
77 
78  version = vO.value_or(0);
79 
80  JLOG(j.info()) << "Opened version " << version << " database";
81  }
82 
83  {
84  if (version < currentSchemaVersion)
85  {
86  JLOG(j.info()) << "Updating database to version "
87  << currentSchemaVersion;
88  }
89  else if (version > currentSchemaVersion)
90  {
91  Throw<std::runtime_error>(
92  "The PeerFinder database version is higher than expected");
93  }
94  }
95 
96  if (version < 4)
97  {
98  //
99  // Remove the "uptime" column from the bootstrap table
100  //
101 
102  session << "CREATE TABLE IF NOT EXISTS "
103  "PeerFinder_BootstrapCache_Next ( "
104  " id INTEGER PRIMARY KEY AUTOINCREMENT, "
105  " address TEXT UNIQUE NOT NULL, "
106  " valence INTEGER"
107  ");";
108 
109  session << "CREATE INDEX IF NOT EXISTS "
110  " PeerFinder_BootstrapCache_Next_Index ON "
111  " PeerFinder_BootstrapCache_Next "
112  " ( address ); ";
113 
114  std::size_t count;
115  session << "SELECT COUNT(*) FROM PeerFinder_BootstrapCache;",
116  soci::into(count);
117 
119 
120  {
121  list.reserve(count);
122  std::string s;
123  int valence;
124  soci::statement st =
125  (session.prepare << "SELECT "
126  " address, "
127  " valence "
128  "FROM PeerFinder_BootstrapCache;",
129  soci::into(s),
130  soci::into(valence));
131 
132  st.execute();
133  while (st.fetch())
134  {
137  if (!is_unspecified(entry.endpoint))
138  {
139  entry.valence = valence;
140  list.push_back(entry);
141  }
142  else
143  {
144  JLOG(j.error()) << "Bad address string '" << s
145  << "' in Bootcache table";
146  }
147  }
148  }
149 
150  if (!list.empty())
151  {
153  std::vector<int> valence;
154  s.reserve(list.size());
155  valence.reserve(list.size());
156 
157  for (auto iter(list.cbegin()); iter != list.cend(); ++iter)
158  {
159  s.emplace_back(to_string(iter->endpoint));
160  valence.emplace_back(iter->valence);
161  }
162 
163  session << "INSERT INTO PeerFinder_BootstrapCache_Next ( "
164  " address, "
165  " valence "
166  ") VALUES ( "
167  " :s, :valence"
168  ");",
169  soci::use(s), soci::use(valence);
170  }
171 
172  session << "DROP TABLE IF EXISTS PeerFinder_BootstrapCache;";
173 
174  session << "DROP INDEX IF EXISTS PeerFinder_BootstrapCache_Index;";
175 
176  session << "ALTER TABLE PeerFinder_BootstrapCache_Next "
177  " RENAME TO PeerFinder_BootstrapCache;";
178 
179  session << "CREATE INDEX IF NOT EXISTS "
180  " PeerFinder_BootstrapCache_Index ON "
181  "PeerFinder_BootstrapCache "
182  " ( "
183  " address "
184  " ); ";
185  }
186 
187  if (version < 3)
188  {
189  //
190  // Remove legacy endpoints from the schema
191  //
192 
193  session << "DROP TABLE IF EXISTS LegacyEndpoints;";
194 
195  session << "DROP TABLE IF EXISTS PeerFinderLegacyEndpoints;";
196 
197  session << "DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints;";
198 
199  session << "DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints_Index;";
200  }
201 
202  {
203  int const v(currentSchemaVersion);
204  session << "INSERT OR REPLACE INTO SchemaVersion ("
205  " name "
206  " ,version "
207  ") VALUES ( "
208  " 'PeerFinder', :version "
209  ");",
210  soci::use(v);
211  }
212 
213  tr.commit();
214 }
215 
216 void
218  soci::session& session,
219  std::function<void(std::string const&, int)> const& func)
220 {
221  std::string s;
222  int valence;
223  soci::statement st =
224  (session.prepare << "SELECT "
225  " address, "
226  " valence "
227  "FROM PeerFinder_BootstrapCache;",
228  soci::into(s),
229  soci::into(valence));
230 
231  st.execute();
232  while (st.fetch())
233  {
234  func(s, valence);
235  }
236 }
237 
238 void
240  soci::session& session,
242 {
243  soci::transaction tr(session);
244  session << "DELETE FROM PeerFinder_BootstrapCache;";
245 
246  if (!v.empty())
247  {
249  std::vector<int> valence;
250  s.reserve(v.size());
251  valence.reserve(v.size());
252 
253  for (auto const& e : v)
254  {
255  s.emplace_back(to_string(e.endpoint));
256  valence.emplace_back(e.valence);
257  }
258 
259  session << "INSERT INTO PeerFinder_BootstrapCache ( "
260  " address, "
261  " valence "
262  ") VALUES ( "
263  " :s, :valence "
264  ");",
265  soci::use(s), soci::use(valence);
266  }
267 
268  tr.commit();
269 }
270 
271 } // namespace ripple
std::string
STL class.
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 a session with the peer finder database.
Definition: PeerFinder.cpp:25
std::vector::reserve
T reserve(T... args)
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 Updates the peer finder database to a new version.
Definition: PeerFinder.cpp:61
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::function
std::vector::push_back
T push_back(T... args)
ripple::readPeerFinderDB
void readPeerFinderDB(soci::session &session, std::function< void(std::string const &, int)> const &func)
readPeerFinderDB Reads all entries from the peer finder database and invokes the given callback for e...
Definition: PeerFinder.cpp:217
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
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
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::vector::cbegin
T cbegin(T... args)
beast::IP::Endpoint::from_string
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:49
ripple::savePeerFinderDB
void savePeerFinderDB(soci::session &session, std::vector< PeerFinder::Store::Entry > const &v)
savePeerFinderDB Saves a new entry to the peer finder database.
Definition: PeerFinder.cpp:239
std::vector::empty
T empty(T... args)
std::size_t
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
std::vector::cend
T cend(T... args)
ripple::PeerFinder::Store::Entry
Definition: Store.h:40
ripple::PeerFinder::Store::Entry::endpoint
beast::IP::Endpoint endpoint
Definition: Store.h:44
ripple::BasicConfig
Holds unparsed configuration information.
Definition: BasicConfig.h:215