rippled
Loading...
Searching...
No Matches
Wallet.cpp
1#include <xrpl/rdb/DBInit.h>
2#include <xrpl/server/Wallet.h>
3
4#include <boost/format.hpp>
5
6namespace xrpl {
7
10{
11 // wallet database
14}
15
18{
19 // wallet database
21 setup, dbname.data(), std::array<std::string, 0>(), WalletDBInit, j);
22}
23
24void
26 soci::session& session,
27 std::string const& dbTable,
28 ManifestCache& mCache,
30{
31 // Load manifests stored in database
32 std::string const sql = "SELECT RawData FROM " + dbTable + ";";
33 soci::blob sociRawData(session);
34 soci::statement st = (session.prepare << sql, soci::into(sociRawData));
35 st.execute();
36 while (st.fetch())
37 {
38 std::string serialized;
39 convert(sociRawData, serialized);
40 if (auto mo = deserializeManifest(serialized))
41 {
42 if (!mo->verify())
43 {
44 JLOG(j.warn()) << "Unverifiable manifest in db";
45 continue;
46 }
47
48 mCache.applyManifest(std::move(*mo));
49 }
50 else
51 {
52 JLOG(j.warn()) << "Malformed manifest in database";
53 }
54 }
55}
56
57static void
58saveManifest(soci::session& session, std::string const& dbTable, std::string const& serialized)
59{
60 // soci does not support bulk insertion of blob data
61 // Do not reuse blob because manifest ecdsa signatures vary in length
62 // but blob write length is expected to be >= the last write
63 soci::blob rawData(session);
64 convert(serialized, rawData);
65 session << "INSERT INTO " << dbTable << " (RawData) VALUES (:rawData);", soci::use(rawData);
66}
67
68void
70 soci::session& session,
71 std::string const& dbTable,
72 std::function<bool(PublicKey const&)> const& isTrusted,
75{
76 soci::transaction tr(session);
77 session << "DELETE FROM " << dbTable;
78 for (auto const& v : map)
79 {
80 // Save all revocation manifests,
81 // but only save trusted non-revocation manifests.
82 if (!v.second.revoked() && !isTrusted(v.second.masterKey))
83 {
84 JLOG(j.info()) << "Untrusted manifest in cache not saved to db";
85 continue;
86 }
87
88 saveManifest(session, dbTable, v.second.serialized);
89 }
90 tr.commit();
91}
92
93void
94addValidatorManifest(soci::session& session, std::string const& serialized)
95{
96 soci::transaction tr(session);
97 saveManifest(session, "ValidatorManifests", serialized);
98 tr.commit();
99}
100
101void
102clearNodeIdentity(soci::session& session)
103{
104 session << "DELETE FROM NodeIdentity;";
105}
106
108getNodeIdentity(soci::session& session)
109{
110 {
111 // SOCI requires boost::optional (not std::optional) as the parameter.
112 boost::optional<std::string> pubKO, priKO;
113 soci::statement st =
114 (session.prepare << "SELECT PublicKey, PrivateKey FROM NodeIdentity;",
115 soci::into(pubKO),
116 soci::into(priKO));
117 st.execute();
118 while (st.fetch())
119 {
120 auto const sk = parseBase58<SecretKey>(TokenType::NodePrivate, priKO.value_or(""));
121 auto const pk = parseBase58<PublicKey>(TokenType::NodePublic, pubKO.value_or(""));
122
123 // Only use if the public and secret keys are a pair
124 if (sk && pk && (*pk == derivePublicKey(KeyType::secp256k1, *sk)))
125 return {*pk, *sk};
126 }
127 }
128
129 // If a valid identity wasn't found, we randomly generate a new one:
130 auto [newpublicKey, newsecretKey] = randomKeyPair(KeyType::secp256k1);
131
132 session << str(
133 boost::format(
134 "INSERT INTO NodeIdentity (PublicKey,PrivateKey) "
135 "VALUES ('%s','%s');") %
136 toBase58(TokenType::NodePublic, newpublicKey) %
137 toBase58(TokenType::NodePrivate, newsecretKey));
138
139 return {newpublicKey, newsecretKey};
140}
141
143getPeerReservationTable(soci::session& session, beast::Journal j)
144{
146 // These values must be boost::optionals (not std) because SOCI expects
147 // boost::optionals.
148 boost::optional<std::string> valPubKey, valDesc;
149 // We should really abstract the table and column names into constants,
150 // but no one else does. Because it is too tedious? It would be easy if we
151 // had a jOOQ for C++.
152 soci::statement st =
153 (session.prepare << "SELECT PublicKey, Description FROM PeerReservations;",
154 soci::into(valPubKey),
155 soci::into(valDesc));
156 st.execute();
157 while (st.fetch())
158 {
159 if (!valPubKey || !valDesc)
160 {
161 // This represents a `NULL` in a `NOT NULL` column. It should be
162 // unreachable.
163 continue;
164 }
165 auto const optNodeId = parseBase58<PublicKey>(TokenType::NodePublic, *valPubKey);
166 if (!optNodeId)
167 {
168 JLOG(j.warn()) << "load: not a public key: " << valPubKey;
169 continue;
170 }
171 table.insert(PeerReservation{*optNodeId, *valDesc});
172 }
173
174 return table;
175}
176
177void
179 soci::session& session,
180 PublicKey const& nodeId,
181 std::string const& description)
182{
183 auto const sNodeId = toBase58(TokenType::NodePublic, nodeId);
184 session << "INSERT INTO PeerReservations (PublicKey, Description) "
185 "VALUES (:nodeId, :desc) "
186 "ON CONFLICT (PublicKey) DO UPDATE SET "
187 "Description=excluded.Description",
188 soci::use(sNodeId), soci::use(description);
189}
190
191void
192deletePeerReservation(soci::session& session, PublicKey const& nodeId)
193{
194 auto const sNodeId = toBase58(TokenType::NodePublic, nodeId);
195 session << "DELETE FROM PeerReservations WHERE PublicKey = :nodeId", soci::use(sNodeId);
196}
197
198bool
199createFeatureVotes(soci::session& session)
200{
201 soci::transaction tr(session);
202 std::string const sql =
203 "SELECT count(*) FROM sqlite_master "
204 "WHERE type='table' AND name='FeatureVotes'";
205 // SOCI requires boost::optional (not std::optional) as the parameter.
206 boost::optional<int> featureVotesCount;
207 session << sql, soci::into(featureVotesCount);
208 bool const exists = static_cast<bool>(*featureVotesCount);
209
210 // Create FeatureVotes table in WalletDB if it doesn't exist
211 if (!exists)
212 {
213 session << "CREATE TABLE FeatureVotes ( "
214 "AmendmentHash CHARACTER(64) NOT NULL, "
215 "AmendmentName TEXT, "
216 "Veto INTEGER NOT NULL );";
217 tr.commit();
218 }
219 return exists;
220}
221
222void
224 soci::session& session,
225 std::function<void(
226 boost::optional<std::string> amendment_hash,
227 boost::optional<std::string> amendment_name,
228 boost::optional<AmendmentVote> vote)> const& callback)
229{
230 // lambda that converts the internally stored int to an AmendmentVote.
231 auto intToVote = [](boost::optional<int> const& dbVote) -> boost::optional<AmendmentVote> {
232 return safe_cast<AmendmentVote>(dbVote.value_or(1));
233 };
234
235 soci::transaction const tr(session);
236 std::string const sql =
237 "SELECT AmendmentHash, AmendmentName, Veto FROM "
238 "( SELECT AmendmentHash, AmendmentName, Veto, RANK() OVER "
239 "( PARTITION BY AmendmentHash ORDER BY ROWID DESC ) "
240 "as rnk FROM FeatureVotes ) WHERE rnk = 1";
241 // SOCI requires boost::optional (not std::optional) as parameters.
242 boost::optional<std::string> amendment_hash;
243 boost::optional<std::string> amendment_name;
244 boost::optional<int> vote_to_veto;
245 soci::statement st =
246 (session.prepare << sql,
247 soci::into(amendment_hash),
248 soci::into(amendment_name),
249 soci::into(vote_to_veto));
250 st.execute();
251 while (st.fetch())
252 {
253 callback(amendment_hash, amendment_name, intToVote(vote_to_veto));
254 }
255}
256
257void
259 soci::session& session,
260 uint256 const& amendment,
261 std::string const& name,
262 AmendmentVote vote)
263{
264 soci::transaction tr(session);
265 std::string sql =
266 "INSERT INTO FeatureVotes (AmendmentHash, AmendmentName, Veto) VALUES "
267 "('";
268 sql += to_string(amendment);
269 sql += "', '" + name;
270 sql += "', '" + std::to_string(safe_cast<int>(vote)) + "');";
271 session << sql;
272 tr.commit();
273}
274
275} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:40
Stream info() const
Definition Journal.h:307
Stream warn() const
Definition Journal.h:313
Remembers manifests with the highest sequence number.
Definition Manifest.h:235
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
A public key.
Definition PublicKey.h:42
T data(T... args)
T insert(T... args)
T is_same_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
void getManifests(soci::session &session, std::string const &dbTable, ManifestCache &mCache, beast::Journal j)
getManifests Loads a manifest from the wallet database and stores it in the cache.
Definition Wallet.cpp:25
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
PublicKey derivePublicKey(KeyType type, SecretKey const &sk)
Derive the public key from a secret key.
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 the database.
Definition Wallet.cpp:69
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:602
static void saveManifest(soci::session &session, std::string const &dbTable, std::string const &serialized)
Definition Wallet.cpp:58
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:92
void deletePeerReservation(soci::session &session, PublicKey const &nodeId)
deletePeerReservation Deletes an entry from the peer reservation table.
Definition Wallet.cpp:192
std::pair< PublicKey, SecretKey > getNodeIdentity(soci::session &session)
Returns a stable public and private key for this node.
Definition Wallet.cpp:108
void insertPeerReservation(soci::session &session, PublicKey const &nodeId, std::string const &description)
insertPeerReservation Adds an entry to the peer reservation table.
Definition Wallet.cpp:178
std::unordered_set< PeerReservation, beast::uhash<>, KeyEqual > getPeerReservationTable(soci::session &session, beast::Journal j)
getPeerReservationTable Returns the peer reservation table.
Definition Wallet.cpp:143
constexpr auto WalletDBName
Definition DBInit.h:85
void addValidatorManifest(soci::session &session, std::string const &serialized)
addValidatorManifest Saves the manifest of a validator to the database.
Definition Wallet.cpp:94
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
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 Reads all amendments from the FeatureVotes table.
Definition Wallet.cpp:223
std::unique_ptr< DatabaseCon > makeWalletDB(DatabaseCon::Setup const &setup, beast::Journal j)
makeWalletDB Opens the wallet database and returns it.
Definition Wallet.cpp:9
bool createFeatureVotes(soci::session &session)
createFeatureVotes Creates the FeatureVote table if it does not exist.
Definition Wallet.cpp:199
AmendmentVote
Definition Wallet.h:126
void clearNodeIdentity(soci::session &session)
Delete any saved public/private key associated with this node.
Definition Wallet.cpp:102
constexpr std::array< char const *, 6 > WalletDBInit
Definition DBInit.h:87
std::unique_ptr< DatabaseCon > makeTestWalletDB(DatabaseCon::Setup const &setup, std::string const &dbname, beast::Journal j)
makeTestWalletDB Opens a test wallet database with an arbitrary name.
Definition Wallet.cpp:17
void voteAmendment(soci::session &session, uint256 const &amendment, std::string const &name, AmendmentVote vote)
voteAmendment Set the veto value for a particular amendment.
Definition Wallet.cpp:258
void convert(soci::blob &from, std::vector< std::uint8_t > &to)
Definition SociDB.cpp:130
T to_string(T... args)