Files
rippled/include/xrpl/server/Wallet.h
Pratik Mankawde e55f48caf8 test(server): cover every resolveNodeIdentity() decision branch
Lift the seed parsing and the stored-vs-mint choice into two libxrpl
helpers, parseNodeIdentitySeed() and selectNodeIdentity(), so xrpl_tests
can drive each branch without an xrpld Config. resolveNodeIdentity() now
marshals Config and the cmdline into them; behaviour is unchanged.

Also pin that storeNodeIdentity() appends (row count, not SQLite row
order), fix the test header that described getNodeIdentity()'s property
as the store's, and route NullTelemetry::getMeter() through noopMeter().

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-14 23:31:27 +01:00

247 lines
8.1 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/protocol/Seed.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);
/**
* The seed a configured [node_seed] or --nodeid names.
*
* The command-line value wins when both are set. A cmdline value is parsed
* with parseGenericSeed(rfc1751=false); a config value is parsed as Base58
* only. Empty inputs count as supplied-but-invalid and throw.
*
* @param cmdlineSeed The --nodeid value, or std::nullopt when not passed.
* @param configSeed The first line of [node_seed], or std::nullopt when the
* section is absent. An empty section is passed as "".
* @return The parsed seed, or std::nullopt when neither is set.
* @throws std::runtime_error if the value present is malformed.
*/
[[nodiscard]] std::optional<Seed>
parseNodeIdentitySeed(
std::optional<std::string> const& cmdlineSeed,
std::optional<std::string> const& configSeed);
/**
* Pick this node's keypair from a pre-parsed seed and a stored-key reader.
*
* A configured seed wins outright and the reader is not consulted. When
* newNodeId is set, mint a fresh pair and skip the reader too. Otherwise
* consult the reader; return its pair if it has one, else mint.
*
* Lifting the decision out of the Application layer lets libxrpl-level
* tests drive every branch without an xrpld Config.
*
* @param configuredSeed Seed from parseNodeIdentitySeed(), or std::nullopt.
* @param newNodeId True when --newnodeid was passed.
* @param readStored Callable that returns the wallet's stored pair, or
* std::nullopt when nothing is stored.
* @return This node's keypair.
*/
[[nodiscard]] std::pair<PublicKey, SecretKey>
selectNodeIdentity(
std::optional<Seed> const& configuredSeed,
bool newNodeId,
std::function<std::optional<std::pair<PublicKey, SecretKey>>()> const& readStored);
/**
* 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