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