Files
rippled/include/xrpl/protocol/AccountID.h
Denis Angell 88794a1ea9 docs: add Doxygen comments across xrpl and xrpld
Bulk documentation pass covering 702 C++ source files in src/libxrpl, src/xrpld, and
include/xrpl. Adds class, function, parameter, and invariant docs per
docs/DOCUMENTATION_STANDARDS.md.

Squashed from the original three-part series (part 1 / part 2 / part 3) to avoid
merge-conflict noise when rebasing the work onto current develop.
2026-05-14 10:20:15 +02:00

251 lines
8.7 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** @file
* Defines the AccountID type, serialization helpers, sentinel constants,
* and the optional base58 encoding cache for XRP Ledger account identities.
*/
#pragma once
#include <xrpl/protocol/tokens.h>
// VFALCO Uncomment when the header issues are resolved
// #include <xrpl/protocol/PublicKey.h>
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/json/json_value.h>
#include <xrpl/protocol/json_get_or_throw.h>
#include <cstddef>
#include <optional>
#include <string>
namespace xrpl {
namespace detail {
/** Phantom tag type that makes AccountID a distinct strong type.
*
* Passed as the second template argument to `BaseUInt<160, Tag>` so that
* a 160-bit account hash cannot be silently used where a raw hash or node ID
* is expected, and vice versa. The class has no data members or behaviour.
*/
class AccountIDTag
{
public:
explicit AccountIDTag() = default;
};
} // namespace detail
/** A 160-bit identifier that uniquely addresses an XRP Ledger account.
*
* Stored as five `uint32_t` values in big-endian byte order — a layout
* that is part of the binary serialization protocol and cannot be changed.
* Derived from a public key via SHA-256 + RIPEMD-160 (`calcAccountID()`).
*
* The phantom tag `detail::AccountIDTag` makes this a distinct C++ type,
* preventing accidental mixing with other 160-bit quantities at compile time.
*
* @see calcAccountID(), toBase58(), parseBase58<AccountID>()
*/
using AccountID = BaseUInt<160, detail::AccountIDTag>;
/** Encode an AccountID as a Base58Check string.
*
* Prepends `TokenType::AccountID` (value 0) before encoding. When the
* global cache has been initialised via `initAccountIdCache()`, the result
* is served from the cache to avoid repeated SHA-256 checksum computation.
*
* @param v The account identifier to encode.
* @return The Base58Check-encoded string (always 2534 printable characters).
* @see initAccountIdCache(), parseBase58<AccountID>()
*/
std::string
toBase58(AccountID const& v);
/** Decode a Base58Check string into an AccountID.
*
* Validates the `TokenType::AccountID` prefix and requires the decoded
* payload to be exactly 20 bytes. Input that fails either check returns
* `std::nullopt` rather than throwing, because external input is frequently
* untrusted.
*
* @param s The Base58Check-encoded account string to parse.
* @return The decoded AccountID, or `std::nullopt` on any parse failure.
* @see toBase58()
*/
template <>
std::optional<AccountID>
parseBase58(std::string const& s);
/** Compute the AccountID for a public key using SHA-256 + RIPEMD-160.
*
* Applies `RipeshaHasher` to the raw public-key bytes (no version byte).
* The double-hash matches Bitcoin's derivation: SHA-256 prevents
* length-extension attacks, and RIPEMD-160 is considered safe at 160 bits.
* XRPL adopted the scheme to avoid any claim of weaker security relative
* to Bitcoin.
*
* @note Declaration lives in `PublicKey.h`; the implementation is in
* `AccountID.cpp`.
*/
// VFALCO In PublicKey.h for now
// AccountID
// calcAccountID (PublicKey const& pk);
/** Return the canonical XRP issuer sentinel: the all-zero AccountID.
*
* Used as the issuer field in XRP `STAmount` values. Code that needs to
* test whether an amount is native XRP should prefer checking the native
* flag or the currency directly rather than comparing the issuer against
* this value — see the deprecated `isXRP(AccountID)` overload.
*
* @return A function-local static `AccountID` equal to `beast::kZERO`.
* Returned by `const&` to avoid copies; lifetime is the process lifetime.
*/
AccountID const&
xrpAccount();
/** Return the "no account" sentinel: `AccountID(1)`.
*
* Used as a placeholder in offer and trust-line fields that have no
* meaningful account value (e.g., an uninitialized or absent counterparty).
* Distinct from `xrpAccount()` (all zeros) so the two sentinels cannot
* be confused.
*
* @return A function-local static `AccountID` with value 1.
* Returned by `const&` to avoid copies; lifetime is the process lifetime.
*/
AccountID const&
noAccount();
/** Parse a hex or Base58Check string into an AccountID.
*
* Tries hex first (`parseHex`), then falls back to Base58Check. Used
* in legacy configuration parsing where the encoding is not guaranteed.
*
* @param issuer Output: receives the parsed AccountID on success.
* @param s The hex (40 chars) or Base58Check string to parse.
* @return `true` if parsing succeeded and `issuer` was written.
* @deprecated Prefer `parseBase58<AccountID>()` for user-facing input.
*/
// DEPRECATED
bool
toIssuer(AccountID&, std::string const&);
/** Test whether an AccountID equals the XRP issuer sentinel (all zeros).
*
* @param c The account identifier to test.
* @return `true` if `c` equals `beast::kZERO` (i.e., equals `xrpAccount()`).
* @deprecated Check the currency field or the native/integral flag instead;
* relying on the zero-account-as-issuer convention is a leaky abstraction.
*/
// DEPRECATED Should be checking the currency or native flag
inline bool
isXRP(AccountID const& c)
{
return c == beast::kZERO;
}
/** Convert an AccountID to its Base58Check string representation.
*
* @param account The account identifier to convert.
* @return The Base58Check-encoded string.
* @deprecated Use `toBase58()` directly.
*/
// DEPRECATED
inline std::string
to_string(AccountID const& account)
{
return toBase58(account);
}
/** Write the Base58Check encoding of an AccountID to an output stream.
*
* @param os The stream to write to.
* @param x The account identifier to encode.
* @return `os`, to allow chaining.
* @deprecated Prefer explicit `toBase58()` calls; stream output silently
* invokes Base58 encoding and can be surprising in logging contexts.
*/
// DEPRECATED
inline std::ostream&
operator<<(std::ostream& os, AccountID const& x)
{
os << to_string(x);
return os;
}
/** Initialize the global AccountID → Base58Check encoding cache.
*
* Base58Check encoding requires a SHA-256 checksum on every call, which is
* expensive at transaction-processing throughput. The cache uses a
* direct-mapped open-addressing table with 64 spinlocks packed into a single
* `atomic<uint64_t>` (via `PackedSpinlock`) to allow concurrent access with
* minimal memory overhead. The index hash is `hardened_hash<>` (DoS-
* resistant seeded hash) to prevent crafted workloads from degrading lookups.
*
* The cache is strictly optional: if never initialised, `toBase58()` falls
* through to `encodeBase58Token` on every call.
*
* @param count The number of cache slots to allocate. Pass 0 to leave the
* cache disabled (no-op if already disabled).
* @note This function initialises the cache at most once. Subsequent calls
* with any `count` value are silently ignored.
*/
void
initAccountIdCache(std::size_t count);
} // namespace xrpl
//------------------------------------------------------------------------------
namespace json {
/** Extract and parse an AccountID from a JSON object field.
*
* Reads `field` from `v` as a string, then decodes it as a Base58Check
* account address. Throws `JsonTypeMismatchError` if the field is absent,
* not a string, or not a valid AccountID encoding — the same error type
* raised for any other JSON type mismatch, enabling uniform error handling
* in RPC and transaction-parsing code.
*
* @param v The JSON object to read from.
* @param field The SField identifying the key to look up.
* @return The decoded AccountID.
* @throws JsonTypeMismatchError if the field is missing, not a string, or
* cannot be decoded as a valid Base58Check AccountID.
*/
template <>
inline xrpl::AccountID
getOrThrow(json::Value const& v, xrpl::SField const& field)
{
using namespace xrpl;
std::string const b58 = getOrThrow<std::string>(v, field);
if (auto const r = parseBase58<AccountID>(b58))
return *r;
Throw<JsonTypeMismatchError>(field.getJsonName(), "AccountID");
}
} // namespace json
//------------------------------------------------------------------------------
namespace std {
/** `std::hash` specialization for AccountID, delegating to `hardened_hash<>`.
*
* Maintains compatibility with standard-library unordered containers that
* key on `AccountID`. The underlying hasher uses a random seed (DoS-
* resistant), so hash values differ across process restarts.
*
* @deprecated Prefer `beast::uhash` or XRPL's hardened unordered containers
* (`UnorderedMap`, `UnorderedSet`) for new code.
*/
// DEPRECATED
// VFALCO Use beast::uhash or a hardened container
template <>
struct hash<xrpl::AccountID> : xrpl::AccountID::hasher
{
hash() = default;
};
} // namespace std