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