mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 08:46:46 +00:00
266 lines
9.1 KiB
C++
266 lines
9.1 KiB
C++
#pragma once
|
|
|
|
/** @file
|
|
* Defines `STAccount`, the serialized-type wrapper for 160-bit XRPL account
|
|
* identifiers used inside transactions and ledger objects.
|
|
*
|
|
* The internal storage is a plain `AccountID` (`base_uint<160>`) — no heap
|
|
* allocation — while the wire format deliberately preserves the
|
|
* variable-length (VL) blob encoding of the original `STBlob`-based
|
|
* implementation for byte-for-byte ledger compatibility.
|
|
*/
|
|
|
|
#include <xrpl/basics/CountedObject.h>
|
|
#include <xrpl/protocol/AccountID.h>
|
|
#include <xrpl/protocol/STBase.h>
|
|
|
|
#include <string>
|
|
|
|
namespace xrpl {
|
|
|
|
/** Serialized-type wrapper for a 160-bit XRPL account identifier.
|
|
*
|
|
* `STAccount` stores an `AccountID` value in a fixed-size `uint160` (no
|
|
* heap allocation) while serializing and deserializing using the
|
|
* VL-prefixed blob encoding of the legacy `STBlob` implementation, keeping
|
|
* the wire format byte-for-byte compatible with all existing ledger data.
|
|
*
|
|
* A `bool default_` flag tracks whether the field has ever been explicitly
|
|
* assigned. A default field serializes as a zero-length VL blob, which is
|
|
* distinct from a field explicitly set to the all-zeros pseudo-account
|
|
* (`noAccount()`). Any call to `setValue()` or `operator=` clears the flag,
|
|
* even when the assigned value is zero.
|
|
*
|
|
* Inherits `CountedObject<STAccount>` for lock-free diagnostic instance
|
|
* counting, and is `final` — no further derivation is expected.
|
|
*
|
|
* @see STBase, CountedObject
|
|
*/
|
|
class STAccount final : public STBase, public CountedObject<STAccount>
|
|
{
|
|
private:
|
|
// The original implementation kept the value in an STBlob.
|
|
// But an STAccount is always 160 bits, so we can store it with less
|
|
// overhead in an xrpl::uint160. However, so the serialized format of the
|
|
// STAccount stays unchanged, we serialize and deserialize like an STBlob.
|
|
AccountID value_;
|
|
bool default_;
|
|
|
|
public:
|
|
using value_type = AccountID;
|
|
|
|
/** Construct an anonymous, unset account field.
|
|
*
|
|
* Sets the stored value to zero and marks the field as default (unset).
|
|
* A default field serializes as a zero-length VL blob and returns an
|
|
* empty string from `getText()`.
|
|
*/
|
|
STAccount();
|
|
|
|
/** Construct a named but unset account field.
|
|
*
|
|
* Binds the field to `n` but leaves it in the default (unset) state.
|
|
* Typical use: pre-populating an `STObject` slot before the account
|
|
* address is known.
|
|
*
|
|
* @param n The `SField` descriptor identifying this field (e.g. `sfAccount`).
|
|
*/
|
|
STAccount(SField const& n);
|
|
|
|
/** Construct from a raw VL-blob byte buffer.
|
|
*
|
|
* An empty buffer is the canonical round-trip encoding of a default
|
|
* (unset) field and leaves the object in the default state. A non-empty
|
|
* buffer must be exactly 20 bytes; any other size throws.
|
|
*
|
|
* @param n The `SField` descriptor for this field.
|
|
* @param v Raw bytes from a VL-blob read. Must be empty or exactly 20 bytes.
|
|
* @throws std::runtime_error if `v` is non-empty and not exactly 20 bytes.
|
|
*/
|
|
STAccount(SField const& n, Buffer const& v);
|
|
|
|
/** Deserialize an account field from a wire-format byte stream.
|
|
*
|
|
* Extracts the next VL-prefixed blob from `sit` and delegates to the
|
|
* `Buffer` constructor for size validation and value assignment.
|
|
*
|
|
* @param sit Forward cursor over the serialized byte stream; advanced
|
|
* past the VL blob on return.
|
|
* @param name The `SField` descriptor for this field.
|
|
* @throws std::runtime_error if the extracted blob is not empty or 20 bytes.
|
|
*/
|
|
STAccount(SerialIter& sit, SField const& name);
|
|
|
|
/** Construct from a known `AccountID` value.
|
|
*
|
|
* Marks the field as non-default regardless of whether `v` is the
|
|
* zero account. This is the standard path when the account address
|
|
* is already available at construction time.
|
|
*
|
|
* @param n The `SField` descriptor for this field.
|
|
* @param v The 160-bit account identifier to store.
|
|
*/
|
|
STAccount(SField const& n, AccountID const& v);
|
|
|
|
/** Return the `SerializedTypeID` constant for this type (`STI_ACCOUNT`). */
|
|
[[nodiscard]] SerializedTypeID
|
|
getSType() const override;
|
|
|
|
/** Return the account address as a Base58Check string, or empty if unset.
|
|
*
|
|
* A default (unset) field returns `""` rather than the Base58 encoding
|
|
* of the all-zeros pseudo-account, preserving the distinction between an
|
|
* unset field and one explicitly set to `noAccount()`.
|
|
*
|
|
* @return Base58Check-encoded address, or `""` when `isDefault()` is true.
|
|
*/
|
|
[[nodiscard]] std::string
|
|
getText() const override;
|
|
|
|
/** Append this field to `s` using VL-blob wire encoding.
|
|
*
|
|
* A default (unset) field serializes as a zero-length VL blob (one
|
|
* `0x00` byte on the wire). A non-default field serializes as a 20-byte
|
|
* VL blob. This preserves byte-for-byte compatibility with the legacy
|
|
* `STBlob`-based encoding and distinguishes "unset" from "explicitly set
|
|
* to the zero account."
|
|
*
|
|
* @param s The `Serializer` to append to.
|
|
* @note Asserts (debug builds only) that the associated `SField` is a
|
|
* binary field of type `STI_ACCOUNT`.
|
|
*/
|
|
void
|
|
add(Serializer& s) const override;
|
|
|
|
/** Check semantic equivalence with another serialized field.
|
|
*
|
|
* Two `STAccount` objects are equivalent only when both their `default_`
|
|
* flags and their 160-bit values agree. The `SField` name is ignored —
|
|
* equivalence is purely about stored account state, not which field slot
|
|
* the object occupies.
|
|
*
|
|
* @param t The field to compare against.
|
|
* @return `true` if `t` is an `STAccount` with the same default flag and
|
|
* value; `false` if `t` is a different type or either attribute differs.
|
|
* @note Callers that need to compare only the address (ignoring default
|
|
* state) should use `operator==` on the `value()` accessors directly.
|
|
*/
|
|
[[nodiscard]] bool
|
|
isEquivalent(STBase const& t) const override;
|
|
|
|
/** Return `true` if this field has never been explicitly assigned.
|
|
*
|
|
* A default field serializes as a zero-length VL blob. Assigning any
|
|
* `AccountID` — including the zero account — clears the default flag.
|
|
*/
|
|
[[nodiscard]] bool
|
|
isDefault() const override;
|
|
|
|
/** Assign an `AccountID` value, clearing the default flag.
|
|
*
|
|
* @param value The account identifier to store.
|
|
* @return `*this`, to support chained assignments.
|
|
*/
|
|
STAccount&
|
|
operator=(AccountID const& value);
|
|
|
|
/** Return the stored 160-bit account identifier.
|
|
*
|
|
* Returns the underlying `AccountID` regardless of whether the field is
|
|
* in the default state. Callers that need to distinguish "unset" from
|
|
* a real zero account should check `isDefault()` first.
|
|
*/
|
|
[[nodiscard]] AccountID const&
|
|
value() const noexcept;
|
|
|
|
/** Store `v` and mark this field as explicitly set.
|
|
*
|
|
* Unconditionally clears the default flag, even when `v` is the zero
|
|
* account, so that `isDefault()` returns `false` after any call.
|
|
*
|
|
* @param v The 160-bit account identifier to store.
|
|
*/
|
|
void
|
|
setValue(AccountID const& v);
|
|
|
|
private:
|
|
/** Place a copy of this object into `buf` (if it fits within `n` bytes)
|
|
* or heap-allocate a copy via `STBase::emplace()`.
|
|
*
|
|
* Used by `detail::STVar` for the small-object optimization.
|
|
*/
|
|
STBase*
|
|
copy(std::size_t n, void* buf) const override;
|
|
|
|
/** Place a moved instance into `buf` (if it fits within `n` bytes)
|
|
* or heap-allocate via `STBase::emplace()`.
|
|
*
|
|
* Used by `detail::STVar` for the small-object optimization.
|
|
*/
|
|
STBase*
|
|
move(std::size_t n, void* buf) override;
|
|
|
|
friend class detail::STVar;
|
|
};
|
|
|
|
inline STAccount&
|
|
STAccount::operator=(AccountID const& value)
|
|
{
|
|
setValue(value);
|
|
return *this;
|
|
}
|
|
|
|
inline AccountID const&
|
|
STAccount::value() const noexcept
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
inline void
|
|
STAccount::setValue(AccountID const& v)
|
|
{
|
|
value_ = v;
|
|
default_ = false;
|
|
}
|
|
|
|
/** Return `true` if both `STAccount` objects hold the same 160-bit value.
|
|
*
|
|
* @note The default flag is not considered; use `isEquivalent()` when
|
|
* "set-ness" must also match.
|
|
*/
|
|
inline bool
|
|
operator==(STAccount const& lhs, STAccount const& rhs)
|
|
{
|
|
return lhs.value() == rhs.value();
|
|
}
|
|
|
|
/** Three-way-comparable less-than for two `STAccount` values. */
|
|
inline auto
|
|
operator<(STAccount const& lhs, STAccount const& rhs)
|
|
{
|
|
return lhs.value() < rhs.value();
|
|
}
|
|
|
|
/** Return `true` if the `STAccount` holds the same 160-bit value as `rhs`. */
|
|
inline bool
|
|
operator==(STAccount const& lhs, AccountID const& rhs)
|
|
{
|
|
return lhs.value() == rhs;
|
|
}
|
|
|
|
/** Less-than comparison between an `STAccount` and a raw `AccountID`. */
|
|
inline auto
|
|
operator<(STAccount const& lhs, AccountID const& rhs)
|
|
{
|
|
return lhs.value() < rhs;
|
|
}
|
|
|
|
/** Less-than comparison between a raw `AccountID` and an `STAccount`. */
|
|
inline auto
|
|
operator<(AccountID const& lhs, STAccount const& rhs)
|
|
{
|
|
return lhs < rhs.value();
|
|
}
|
|
|
|
} // namespace xrpl
|