Files
rippled/include/xrpl/server/Wallet.h
Pratik Mankawde bec9e1c8a9 fix(telemetry): resolve the node identity before the Application is built
resolveNodePublicKey() returned std::nullopt in three real cases: a first boot
with no wallet database, a standalone run (its wallet is a private temporary
database), and --newnodeid. Telemetry's resources are built during
ApplicationImp's member-init list and are immutable, so on those runs the node
reported an empty service.instance.id and no xrpl.node.id for the whole run,
while setup() minted a key moments later and patched only the tracer.

Replace it with resolveNodeIdentity(), which always returns a keypair: derived
from a configured seed, else read from an existing wallet database, else
minted. Main.cpp passes that pair to makeApplication(), ApplicationImp stores
it in nodeIdentity_ -- now declared before telemetry_ and no longer an optional,
because it is always set -- and builds the telemetry resource from it.

setup() calls getNodeIdentity(), which now persists rather than mints: it
stores the resolved pair when the wallet holds no identity, adopts the stored
one when it does, and clears first for --newnodeid. The write stays in setup()
because that is where the database exists; a standalone run has no persistent
wallet to write to, which is why the pair has to be decided before
construction rather than read back afterwards. Wallet gains storeNodeIdentity()
for that write, and getNodeIdentity(session) now uses it instead of repeating
the insert.

The three-argument makeApplication() mints a keypair, so jtx::Env and any other
test Application behave as a standalone run always did.

Also fold the three hand-rolled "meter from a NoopMeterProvider" copies into
telemetry::noopMeter(): the base-pointer call and the kMeterVersion argument are
both easy to get wrong alone, and the meter identity has to match the one the
histogram views select on.

The new gtest covers the wallet half: store-then-read, store not replacing an
existing identity, clear-then-store, and that the mint path persists. It adds
the tests.libxrpl > xrpl.rdb levelization edge, regenerated here.
2026-09-14 20:34:31 +01:00

206 lines
6.4 KiB
C++

#pragma once
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/hash/uhash.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/core/PeerReservationTable.h>
#include <xrpl/protocol/PublicKey.h>
#include <xrpl/protocol/SecretKey.h>
#include <xrpl/rdb/DatabaseCon.h>
#include <xrpl/server/Manifest.h>
// boost::optional (not std::optional) appears in the declarations below,
// because SOCI's into()/use() bindings only support boost::optional.
#include <boost/optional/optional.hpp>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <unordered_set>
#include <utility>
namespace xrpl {
/**
* @brief makeWalletDB Opens the wallet database and returns it.
* @param setup Path to the database and other opening parameters.
* @param j Journal.
* @return Unique pointer to the database descriptor.
*/
std::unique_ptr<DatabaseCon>
makeWalletDB(DatabaseCon::Setup const& setup, beast::Journal j);
/**
* @brief makeTestWalletDB Opens a test wallet database with an arbitrary name.
* @param setup Path to the database and other opening parameters.
* @param dbname Name of the database.
* @param j Journal.
* @return Unique pointer to the database descriptor.
*/
std::unique_ptr<DatabaseCon>
makeTestWalletDB(DatabaseCon::Setup const& setup, std::string const& dbname, beast::Journal j);
/**
* @brief getManifests Loads a manifest from the wallet database and stores it
* in the cache.
* @param session Session with the database.
* @param dbTable Name of the database table from which the manifest will be
* extracted.
* @param cache_ Cache for storing the manifest.
* @param j Journal.
*/
void
getManifests(
soci::session& session,
std::string const& dbTable,
ManifestCache& cache,
beast::Journal j);
/**
* @brief saveManifests Saves all given manifests to the database.
* @param session Session with the database.
* @param dbTable Name of the database table that will store the manifest.
* @param isTrusted Callback that returns true if the key is trusted.
* @param map Maps public keys to manifests.
* @param j Journal.
*/
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);
/**
* @brief addValidatorManifest Saves the manifest of a validator to the
* database.
* @param session Session with the database.
* @param serialized Manifest of the validator in raw format.
*/
void
addValidatorManifest(soci::session& session, std::string const& serialized);
/**
* Delete any saved public/private key associated with this node.
*/
void
clearNodeIdentity(soci::session& session);
/**
* Returns this node's stored keypair, if the database holds a valid one.
*
* Read-only: unlike getNodeIdentity(), never generates or persists a key. A row
* counts only when its public and secret keys are a pair.
*
* @param session Session with the database.
*
* @return The stored keypair, or std::nullopt.
*/
std::optional<std::pair<PublicKey, SecretKey>>
readNodeIdentity(soci::session& session);
/**
* Persist a keypair as this node's identity.
*
* Write-only counterpart of readNodeIdentity(). The caller must have found the
* table empty: this inserts a row without clearing, so storing twice leaves two
* and readNodeIdentity() then returns whichever the query yields first.
*
* Exists because xrpld resolves its identity before the Application, and so
* before any database, is built; setup() persists that keypair here.
*
* @param session Session with the database.
* @param keys The keypair to store.
*/
void
storeNodeIdentity(soci::session& session, std::pair<PublicKey, SecretKey> const& keys);
/**
* Returns a stable public and private key for this node.
*
* The node's public identity is defined by a secp256k1 keypair
* that is (normally) randomly generated. This function will
* return such a keypair, securely generating one if needed.
*
* @param session Session with the database.
*
* @return Pair of public and private secp256k1 keys.
*/
std::pair<PublicKey, SecretKey>
getNodeIdentity(soci::session& session);
/**
* @brief getPeerReservationTable Returns the peer reservation table.
* @param session Session with the database.
* @param j Journal.
* @return Peer reservation hash table.
*/
std::unordered_set<PeerReservation, beast::Uhash<>, KeyEqual>
getPeerReservationTable(soci::session& session, beast::Journal j);
/**
* @brief insertPeerReservation Adds an entry to the peer reservation table.
* @param session Session with the database.
* @param nodeId Public key of the node.
* @param description Description of the node.
*/
void
insertPeerReservation(
soci::session& session,
PublicKey const& nodeId,
std::string const& description);
/**
* @brief deletePeerReservation Deletes an entry from the peer reservation
* table.
* @param session Session with the database.
* @param nodeId Public key of the node to remove.
*/
void
deletePeerReservation(soci::session& session, PublicKey const& nodeId);
/**
* @brief createFeatureVotes Creates the FeatureVote table if it does not exist.
* @param session Session with the wallet database.
* @return true if the table already exists
*/
bool
createFeatureVotes(soci::session& session);
// For historical reasons the up-vote and down-vote integer representations
// are unintuitive.
enum class AmendmentVote : int { Obsolete = -1, Up = 0, Down = 1 };
/**
* @brief readAmendments Reads all amendments from the FeatureVotes table.
* @param session Session with the wallet database.
* @param callback Callback called for each amendment with its hash, name and
* optionally a flag denoting whether the amendment should be vetoed.
*/
void
readAmendments(
soci::session& session,
std::function<void(
boost::optional<std::string> amendmentHash,
boost::optional<std::string> amendmentName,
boost::optional<AmendmentVote> vote)> const& callback);
/**
* @brief voteAmendment Set the veto value for a particular amendment.
* @param session Session with the wallet database.
* @param amendment Hash of the amendment.
* @param name Name of the amendment.
* @param vote Whether to vote in favor of this amendment.
*/
void
voteAmendment(
soci::session& session,
uint256 const& amendment,
std::string const& name,
AmendmentVote vote);
} // namespace xrpl