Merge branch 'develop' into FN-36-credential_pins_pseudo_account

This commit is contained in:
Vito Tumas
2026-08-13 10:25:12 +02:00
committed by GitHub
203 changed files with 7124 additions and 1932 deletions

View File

@@ -1,6 +1,6 @@
#pragma once
#include <boost/filesystem.hpp>
#include <filesystem>
namespace xrpl {
@@ -13,6 +13,6 @@ namespace xrpl {
* @throws runtime_error
*/
void
extractTarLz4(boost::filesystem::path const& src, boost::filesystem::path const& dst);
extractTarLz4(std::filesystem::path const& src, std::filesystem::path const& dst);
} // namespace xrpl

View File

@@ -3,6 +3,7 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <algorithm>
#include <cstdint>
#include <cstring>
#include <memory>
@@ -156,6 +157,19 @@ public:
}
/** @} */
/**
* Set every byte in the buffer to the given value.
*
* The size is unchanged, and this is a no-op on an empty buffer.
*
* @param value the byte to write to every position.
*/
void
fill(std::uint8_t value) noexcept
{
std::fill_n(p_.get(), size_, value);
}
/**
* Reset the buffer.
* All memory is deallocated. The resulting size is 0.
@@ -226,10 +240,4 @@ operator==(Buffer const& lhs, Buffer const& rhs) noexcept
return std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0;
}
inline bool
operator!=(Buffer const& lhs, Buffer const& rhs) noexcept
{
return !(lhs == rhs);
}
} // namespace xrpl

View File

@@ -1,24 +1,79 @@
#pragma once
#include <boost/filesystem.hpp>
#include <boost/system/error_code.hpp>
#include <cstddef>
#include <filesystem>
#include <optional>
#include <string>
#include <system_error>
namespace xrpl {
std::string
getFileContents(
boost::system::error_code& ec,
boost::filesystem::path const& sourcePath,
std::error_code& ec,
std::filesystem::path const& sourcePath,
std::optional<std::size_t> maxSize = std::nullopt);
void
writeFileContents(
boost::system::error_code& ec,
boost::filesystem::path const& destPath,
std::error_code& ec,
std::filesystem::path const& destPath,
std::string const& contents);
/**
* Generate a unique, non-existing path under @p base whose filename starts with
* @p prefix and ends with a random hex suffix.
*
* Attempts up to @p maxAttempts paths. Throws `std::runtime_error` if a unique
* path cannot be found or if the filesystem returns an error while checking for
* existence.
*/
std::filesystem::path
uniqueRandomPath(
std::filesystem::path const& base,
std::string const& prefix = "",
std::size_t maxAttempts = 100);
/**
* RAII temporary directory.
*
* The directory and all its contents are deleted when
* the instance of `TempDir` is destroyed.
*/
class TempDir
{
std::filesystem::path path_;
public:
#if !GENERATING_DOCS
TempDir(TempDir const&) = delete;
TempDir&
operator=(TempDir const&) = delete;
#endif
/**
* Construct a temporary directory.
*/
TempDir();
/**
* Destroy a temporary directory.
*/
~TempDir();
/**
* Get the native path for the temporary directory.
*/
[[nodiscard]] std::string
path() const;
/**
* Get the native path for a file.
*
* The file does not need to exist.
*/
[[nodiscard]] std::string
file(std::string const& name) const;
};
} // namespace xrpl

View File

@@ -96,9 +96,6 @@ public:
SharedIntrusive&
operator=(SharedIntrusive const& rhs);
bool
operator!=(std::nullptr_t) const;
bool
operator==(std::nullptr_t) const;

View File

@@ -111,13 +111,6 @@ SharedIntrusive<T>::operator=(SharedIntrusive<TT>&& rhs)
return *this;
}
template <class T>
bool
SharedIntrusive<T>::operator!=(std::nullptr_t) const
{
return this->get() != nullptr;
}
template <class T>
bool
SharedIntrusive<T>::operator==(std::nullptr_t) const

View File

@@ -3,8 +3,8 @@
#include <xrpl/beast/utility/Journal.h>
#include <boost/beast/core/string.hpp>
#include <boost/filesystem.hpp>
#include <filesystem>
#include <fstream>
#include <map>
#include <memory>
@@ -84,7 +84,7 @@ private:
* @return `true` if the file was opened.
*/
bool
open(boost::filesystem::path const& path);
open(std::filesystem::path const& path);
/**
* Close and re-open the system file associated with the log
@@ -133,7 +133,7 @@ private:
private:
std::unique_ptr<std::ofstream> stream_;
boost::filesystem::path path_;
std::filesystem::path path_;
};
std::mutex mutable mutex_;
@@ -152,7 +152,7 @@ public:
virtual ~Logs() = default;
bool
open(boost::filesystem::path const& pathToLogFile);
open(std::filesystem::path const& pathToLogFile);
beast::Journal::Sink&
get(std::string const& name);

View File

@@ -304,7 +304,7 @@ concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::u
* on-ledger are non-negative. This is due to implementation details of
* several operations which use unsigned arithmetic internally. This is
* sufficient to represent all valid XRP values (where the absolute value
* can not exceed INITIAL_XRP: 10^17), and MPT values (where the absolute
* can not exceed kInitialXRP: 10^17), and MPT values (where the absolute
* value can not exceed maxMPTokenAmount: 2^63-1).
*
* ---- Mantissa Range Switching ----
@@ -449,12 +449,6 @@ public:
x.exponent_ == y.exponent_;
}
friend constexpr bool
operator!=(Number const& x, Number const& y) noexcept
{
return !(x == y);
}
friend constexpr bool
operator<(Number const& l, Number const& r) noexcept
{

View File

@@ -85,12 +85,6 @@ public:
}
};
inline bool
operator!=(SHAMapHash const& x, SHAMapHash const& y)
{
return !(x == y);
}
template <>
inline std::size_t
extract(SHAMapHash const& key)

View File

@@ -208,12 +208,6 @@ operator==(Slice const& lhs, Slice const& rhs) noexcept
return std::memcmp(lhs.data(), rhs.data(), lhs.size()) == 0;
}
inline bool
operator!=(Slice const& lhs, Slice const& rhs) noexcept
{
return !(lhs == rhs);
}
inline bool
operator<(Slice const& lhs, Slice const& rhs) noexcept
{

View File

@@ -125,9 +125,31 @@ struct ParsedUrl
bool
parseUrl(ParsedUrl& pUrl, std::string const& strUrl);
/**
* Remove leading and trailing ASCII whitespace.
*
* Whitespace is the fixed set " \t\n\v\f\r"; the current locale is not
* consulted, so the result depends only on the input.
*
* @param str The string to trim.
* @return @p str without leading or trailing whitespace.
*/
std::string
trimWhitespace(std::string str);
/**
* Fold ASCII upper case letters to lower case.
*
* Only 'A' through 'Z' are remapped; every other byte is left alone and the
* current locale is not consulted, so the result depends only on the input.
*
* @param str The string to fold.
* @return @p str with each ASCII upper case letter replaced by its lower case
* equivalent.
*/
std::string
toLower(std::string str);
std::optional<std::uint64_t>
toUInt64(std::string const& s);

View File

@@ -116,12 +116,6 @@ public:
{
return lhs.map == rhs.map && lhs.ait == rhs.ait && lhs.mit == rhs.mit;
}
friend bool
operator!=(Iterator const& lhs, Iterator const& rhs)
{
return !(lhs == rhs);
}
};
struct ConstIterator
@@ -189,12 +183,6 @@ public:
{
return lhs.map == rhs.map && lhs.ait == rhs.ait && lhs.mit == rhs.mit;
}
friend bool
operator!=(ConstIterator const& lhs, ConstIterator const& rhs)
{
return !(lhs == rhs);
}
};
private:

View File

@@ -1038,25 +1038,6 @@ public:
Compare,
OtherAllocator> const& other) const;
template <
bool OtherIsMulti,
bool OtherIsMap,
class OtherT,
class OtherDuration,
class OtherAllocator>
bool
operator!=(AgedOrderedContainer<
OtherIsMulti,
OtherIsMap,
Key,
OtherT,
OtherDuration,
Compare,
OtherAllocator> const& other) const
{
return !(this->operator==(other));
}
template <
bool OtherIsMulti,
bool OtherIsMap,

View File

@@ -1340,28 +1340,6 @@ public:
OtherAllocator> const& other) const
requires MaybeMulti;
template <
bool OtherIsMulti,
bool OtherIsMap,
class OtherKey,
class OtherT,
class OtherDuration,
class OtherHash,
class OtherAllocator>
bool
operator!=(AgedUnorderedContainer<
OtherIsMulti,
OtherIsMap,
OtherKey,
OtherT,
OtherDuration,
OtherHash,
KeyEqual,
OtherAllocator> const& other) const
{
return !(this->operator==(other));
}
private:
bool
wouldExceed(size_type additional) const

View File

@@ -82,13 +82,6 @@ public:
return node_ == other.node_;
}
template <typename M>
bool
operator!=(ListIterator<M> const& other) const noexcept
{
return !((*this) == other);
}
reference
operator*() const noexcept
{

View File

@@ -110,12 +110,6 @@ public:
operator==(Endpoint const& lhs, Endpoint const& rhs);
friend bool
operator<(Endpoint const& lhs, Endpoint const& rhs);
friend bool
operator!=(Endpoint const& lhs, Endpoint const& rhs)
{
return !(lhs == rhs);
}
friend bool
operator>(Endpoint const& lhs, Endpoint const& rhs)
{

View File

@@ -229,12 +229,6 @@ public:
return other.it_ == it_ && other.end_ == end_ && other.value_.size() == value_.size();
}
bool
operator!=(ListIterator const& other) const
{
return !(*this == other);
}
reference
operator*() const
{

View File

@@ -8,7 +8,6 @@
#include <xrpl/beast/unit_test/runner.h>
#include <xrpl/beast/unit_test/suite_info.h>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <algorithm>
@@ -188,7 +187,7 @@ Reporter<Unused>::fmtdur(clock_type::duration const& d)
using namespace std::chrono;
auto const ms = duration_cast<milliseconds>(d);
if (ms < seconds{1})
return boost::lexical_cast<std::string>(ms.count()) + "ms";
return std::to_string(ms.count()) + "ms";
std::stringstream ss;
ss << std::fixed << std::setprecision(1) << (ms.count() / 1000.) << "s";
return ss.str();

View File

@@ -6,11 +6,10 @@
#include <xrpl/beast/unit_test/runner.h>
#include <boost/filesystem.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/throw_exception.hpp>
#include <exception>
#include <filesystem>
#include <memory>
#include <ostream>
#include <sstream>
@@ -27,10 +26,10 @@ makeReason(String const& reason, char const* file, int line)
std::string s(reason);
if (!s.empty())
s.append(": ");
namespace fs = boost::filesystem;
namespace fs = std::filesystem;
s.append(fs::path{file}.filename().string());
s.append("(");
s.append(boost::lexical_cast<std::string>(line));
s.append(std::to_string(line));
s.append(")");
return s;
}

View File

@@ -1,71 +0,0 @@
#pragma once
#include <boost/filesystem.hpp>
#include <string>
namespace beast {
/**
* RAII temporary directory.
*
* The directory and all its contents are deleted when
* the instance of `temp_dir` is destroyed.
*/
class TempDir
{
boost::filesystem::path path_;
public:
#if !GENERATING_DOCS
TempDir(TempDir const&) = delete;
TempDir&
operator=(TempDir const&) = delete;
#endif
/**
* Construct a temporary directory.
*/
TempDir()
{
auto const dir = boost::filesystem::temp_directory_path();
do
{
path_ = dir / boost::filesystem::unique_path();
} while (boost::filesystem::exists(path_));
boost::filesystem::create_directory(path_);
}
/**
* Destroy a temporary directory.
*/
~TempDir()
{
// use non-throwing calls in the destructor
boost::system::error_code ec;
boost::filesystem::remove_all(path_, ec);
// TODO: warn/notify if ec set ?
}
/**
* Get the native path for the temporary directory
*/
[[nodiscard]] std::string
path() const
{
return path_.string();
}
/**
* Get the native path for the a file.
*
* The file does not need to exist.
*/
[[nodiscard]] std::string
file(std::string const& name) const
{
return (path_ / name).string();
}
};
} // namespace beast

View File

@@ -92,10 +92,4 @@ operator==(Condition const& lhs, Condition const& rhs)
lhs.fingerprint == rhs.fingerprint;
}
inline bool
operator!=(Condition const& lhs, Condition const& rhs)
{
return !(lhs == rhs);
}
} // namespace xrpl::cryptoconditions

View File

@@ -93,12 +93,6 @@ operator==(Fulfillment const& lhs, Fulfillment const& rhs)
lhs.fingerprint() == rhs.fingerprint();
}
inline bool
operator!=(Fulfillment const& lhs, Fulfillment const& rhs)
{
return !(lhs == rhs);
}
/**
* Determine whether the given fulfillment and condition match
*/

View File

@@ -4,10 +4,9 @@
#include <xrpl/core/Job.h>
#include <xrpl/json/json_value.h>
#include <boost/filesystem.hpp>
#include <chrono>
#include <cstdint>
#include <filesystem>
#include <functional>
#include <memory>
#include <string>
@@ -44,7 +43,7 @@ public:
*/
struct Setup
{
boost::filesystem::path perfLog;
std::filesystem::path perfLog;
// log_interval is in milliseconds to support faster testing.
milliseconds logInterval{seconds(1)};
};
@@ -149,7 +148,7 @@ public:
};
PerfLog::Setup
setupPerfLog(Section const& section, boost::filesystem::path const& configDir);
setupPerfLog(Section const& section, std::filesystem::path const& configDir);
std::unique_ptr<PerfLog>
makePerfLog(

View File

@@ -4,6 +4,7 @@
#include <xrpl/json/json_forwards.h>
#include <cstring>
#include <iterator>
#include <limits>
#include <map>
#include <string>
@@ -72,36 +73,18 @@ operator==(StaticString x, StaticString y)
return strcmp(x.cStr(), y.cStr()) == 0;
}
inline bool
operator!=(StaticString x, StaticString y)
{
return !(x == y);
}
inline bool
operator==(std::string const& x, StaticString y)
{
return strcmp(x.c_str(), y.cStr()) == 0;
}
inline bool
operator!=(std::string const& x, StaticString y)
{
return !(x == y);
}
inline bool
operator==(StaticString x, std::string const& y)
{
return y == x;
}
inline bool
operator!=(StaticString x, std::string const& y)
{
return !(y == x);
}
/**
* @brief Represents a <a HREF="http://www.json.org">JSON</a> value.
*
@@ -489,12 +472,6 @@ toJson(xrpl::Number const& number)
bool
operator==(Value const&, Value const&);
inline bool
operator!=(Value const& x, Value const& y)
{
return !(x == y);
}
bool
operator<(Value const&, Value const&);
@@ -548,6 +525,7 @@ public:
class ValueIteratorBase
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using size_t = unsigned int;
using difference_type = int;
using SelfType = ValueIteratorBase;
@@ -562,12 +540,6 @@ public:
return isEqual(other);
}
bool
operator!=(SelfType const& other) const
{
return !isEqual(other);
}
/**
* Return either the index or the member name of the referenced value as a
* Value.

View File

@@ -49,12 +49,6 @@ public:
bool
operator==(const_iterator const& other) const;
bool
operator!=(const_iterator const& other) const
{
return !(*this == other);
}
reference
operator*() const;

View File

@@ -59,12 +59,6 @@ private:
return lhs.txId_ == rhs.txId_;
}
friend bool
operator!=(Key const& lhs, Key const& rhs)
{
return !(lhs == rhs);
}
[[nodiscard]] uint256 const&
getAccount() const
{

View File

@@ -59,12 +59,6 @@ public:
bool
operator==(ConstIterator const& other) const;
bool
operator!=(ConstIterator const& other) const
{
return !(*this == other);
}
reference
operator*() const;

View File

@@ -35,6 +35,11 @@ enum class SkipEntry : bool { No = false, Yes };
//
//------------------------------------------------------------------------------
/**
* Whether an expiration check should be inclusive or exclusive.
*/
enum class ExpiryComparison { Inclusive, Exclusive };
/**
* Determines whether the given expiration time has passed.
*
@@ -54,11 +59,16 @@ enum class SkipEntry : bool { No = false, Yes };
*
* @param view The ledger whose parent time is used as the clock.
* @param exp The optional expiration time we want to check.
* @param comparison Whether the boundary is inclusive (`now >= exp`, the
* default) or exclusive (`now > exp`).
*
* @return `true` if `exp` is in the past; `false` otherwise.
*/
[[nodiscard]] bool
hasExpired(ReadView const& view, std::optional<std::uint32_t> const& exp);
hasExpired(
ReadView const& view,
std::optional<std::uint32_t> const& exp,
ExpiryComparison comparison = ExpiryComparison::Inclusive);
// Note, depth parameter is used to limit the recursion depth
[[nodiscard]] bool

View File

@@ -85,9 +85,6 @@ public:
bool
operator==(Iterator const& other) const;
bool
operator!=(Iterator const& other) const;
// Can throw
reference
operator*() const;

View File

@@ -64,13 +64,6 @@ ReadViewFwdRange<ValueType>::Iterator::operator==(Iterator const& other) const
return impl_ == other.impl_;
}
template <class ValueType>
bool
ReadViewFwdRange<ValueType>::Iterator::operator!=(Iterator const& other) const
{
return !(*this == other);
}
template <class ValueType>
auto
ReadViewFwdRange<ValueType>::Iterator::operator*() const -> reference

View File

@@ -226,7 +226,7 @@ getAMMOfferStartWithTakerGets(
auto getAmounts = [&pool, &tfee](Number const& nTakerGetsProposed) {
// Round downward to minimize the offer and to maximize the quality.
// This has the most impact when takerGets is XRP.
// This has the most impact when takerGets is integral.
auto const takerGets =
toAmount<TOut>(getAsset(pool.out), nTakerGetsProposed, Number::RoundingMode::Downward);
return TAmounts<TIn, TOut>{swapAssetOut(pool, takerGets, tfee), takerGets};
@@ -294,7 +294,7 @@ getAMMOfferStartWithTakerPays(
auto getAmounts = [&pool, &tfee](Number const& nTakerPaysProposed) {
// Round downward to minimize the offer and to maximize the quality.
// This has the most impact when takerPays is XRP.
// This has the most impact when takerPays is integral.
auto const takerPays =
toAmount<TIn>(getAsset(pool.in), nTakerPaysProposed, Number::RoundingMode::Downward);
return TAmounts<TIn, TOut>{takerPays, swapAssetIn(pool, takerPays, tfee)};
@@ -313,11 +313,11 @@ getAMMOfferStartWithTakerPays(
* is equal to LOB quality (in this case AMM offer quality is
* better than LOB quality) or AMM offer is equal to LOB quality
* (in this case SPQ is better than LOB quality).
* Pre-amendment code calculates takerPays first. If takerGets is XRP,
* it is rounded down, which results in worse offer quality than
* LOB quality, and the offer might fail to generate.
* Post-amendment code calculates the XRP offer side first. The result
* is rounded down, which makes the offer quality better.
* Pre-amendment code calculates takerPays first. If takerGets is the
* economically coarser integral side, it is rounded down, which results in
* worse offer quality than LOB quality, and the offer might fail to generate.
* Post-amendment code calculates the economically coarser integral offer side
* first. The result is rounded down, which makes the offer quality better.
* It might not be possible to match either SPQ or AMM offer to LOB
* quality. This generally happens at higher fees.
* @param pool AMM pool balances
@@ -396,10 +396,18 @@ changeSpotPriceQuality(
return std::nullopt;
}
// Generate the offer starting with XRP side. Return seated offer amounts
// if the offer can be generated, otherwise nullopt.
auto amounts = [&]() {
if (isXRP(getAsset(pool.out)))
bool const inIntegral = getAsset(pool.in).integral();
bool const outIntegral = getAsset(pool.out).integral();
// Preserve historical behavior for fractional pairs and XRP/IOU-style
// one-integral-side pairs. For two integral assets, pick the side whose
// minimum unit is economically coarser at this quality.
//
// Quality::rate() is input units per output unit, so one output unit is
// coarser when it costs at least one input unit. Ties use takerGets,
// matching the historical XRP-output behavior.
if (outIntegral && (!inIntegral || Number(quality.rate()) >= 1))
return getAMMOfferStartWithTakerGets(pool, quality, tfee);
return getAMMOfferStartWithTakerPays(pool, quality, tfee);
}();

View File

@@ -7,6 +7,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/STArray.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <xrpl/protocol/STTx.h>
@@ -58,7 +59,7 @@ deletePseudoAccountCredentials(
// Amendment and parameters checks for sfCredentialIDs field
NotTEC
checkFields(STTx const& tx, beast::Journal j);
checkFields(STTx const& tx, Rules const& rules, beast::Journal j);
// Accessing the ledger to check if provided credentials are valid. Do not use
// in doApply (only in preclaim) since it does not remove expired credentials.

View File

@@ -261,6 +261,14 @@ checkCreateMPT(
xrpl::MPTIssue const& mptIssue,
xrpl::AccountID const& holder,
SLE::ref sponsorSle,
std::uint32_t flags,
beast::Journal j);
TER
checkCreateMPT(
xrpl::ApplyView& view,
xrpl::MPTIssue const& mptIssue,
xrpl::AccountID const& holder,
beast::Journal j);
//------------------------------------------------------------------------------

View File

@@ -6,10 +6,13 @@
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STLedgerEntry.h>
#include <cstdint>
#include <optional>
namespace xrpl {
class STTx;
/**
* From the perspective of a vault, return the number of shares to give
* depositor when they offer a fixed amount of assets. Note, since shares are
@@ -123,4 +126,82 @@ isSoleShareholder(ReadView const& view, AccountID const& account, SLE::const_ref
[[nodiscard]] VaultVersion
getVaultVersion(SLE::const_ref vault);
/**
* Resolves the VaultKind of a vault SLE. Returns VaultKind::ClosedEnded when
* sfVaultKind is present and equal to that value; anything else (including an
* absent field or an unrecognised value) is treated as VaultKind::OpenEnded.
*
* @param vault The vault SLE.
*/
[[nodiscard]] VaultKind
getVaultKind(SLE::const_ref vault);
/**
* Reads sfVaultKind from a transaction. An absent field resolves to
* VaultKind::OpenEnded (matching the on-ledger default); any unrecognised
* value is also treated as VaultKind::OpenEnded, mirroring the SLE overload.
* Callers that need to reject out-of-range values (e.g. preflight) should
* gate on isValidVaultKind() first.
*
* @param tx The transaction.
*/
[[nodiscard]] VaultKind
getVaultKind(STTx const& tx);
/**
* Returns true iff sfVaultKind is either absent from @p tx or is present and
* equal to a recognised VaultKind enumerator. Intended for use in preflight
* to reject malformed transactions before decoding with getVaultKind().
*
* @param tx The transaction.
*/
[[nodiscard]] bool
isValidVaultKind(STTx const& tx);
/**
* Returns true iff the (SubscriptionDate, RedemptionDate) gap of a
* closed-ended vault satisfies
* kMinInvestmentPeriod <= (red - sub) < kMaxInvestmentPeriod. The arithmetic
* is performed in std::int64_t so that @p sub near UINT32_MAX does not
* overflow. Shared by VaultCreate::preflight and the ValidVault invariant.
*
* @param sub The value of sfSubscriptionDate.
* @param red The value of sfRedemptionDate.
*/
[[nodiscard]] bool
isValidClosedEndedGap(std::uint32_t sub, std::uint32_t red);
/**
* Returns the current lifecycle phase of a vault. Open-ended
* vaults are always NoPhase. For closed-ended vaults the phase is derived
* from the parent ledger close time and the vault's immutable
* SubscriptionDate and RedemptionDate.
*
* @param view The ledger view whose parent close time is used as the clock.
* @param vault The vault SLE.
*/
[[nodiscard]] VaultPhase
getVaultPhase(ReadView const& view, SLE::const_ref vault);
/**
* Raw-fields overload of getVaultPhase. Derives the phase from an already
* decomposed vault snapshot: an absent or non-ClosedEnded @p vaultKind
* resolves to VaultPhase::NoPhase; otherwise the phase is computed from
* @p subscriptionDate and @p redemptionDate against the view's parent
* close time using the same boundary semantics as the SLE overload
* (Subscription is inclusive of now == SubscriptionDate; Investment starts
* strictly after).
*
* @param view The ledger view whose parent close time is used as the clock.
* @param vaultKind The value of sfVaultKind, or nullopt if absent.
* @param subscriptionDate The value of sfSubscriptionDate, or nullopt if absent.
* @param redemptionDate The value of sfRedemptionDate, or nullopt if absent.
*/
[[nodiscard]] VaultPhase
getVaultPhase(
ReadView const& view,
std::optional<std::uint8_t> vaultKind,
std::optional<std::uint32_t> subscriptionDate,
std::optional<std::uint32_t> redemptionDate);
} // namespace xrpl

View File

@@ -47,7 +47,7 @@ ammLPTIssue(Asset const& asset1, Asset const& asset2, AccountID const& ammAccoun
/**
* Validate the amount.
* If validZero is false and amount is beast::zero then invalid amount.
* If validZero is false and amount is beast::kZero then invalid amount.
* Return error code if invalid amount.
* If pair then validate amount's issue matches one of the pair's issue.
*/

View File

@@ -154,7 +154,7 @@ T
toAmount(Asset const& asset, Number const& n, Number::RoundingMode mode = Number::getround())
{
SaveNumberRoundMode const rm(Number::getround());
if (isXRP(asset))
if (asset.integral())
Number::setround(mode);
if constexpr (std::is_same_v<IOUAmount, T>)

View File

@@ -9,6 +9,7 @@
#include <mpt_protocol.h>
#include <secp256k1_mpt.h>
#include <chrono>
#include <cstddef>
#include <cstdint>
@@ -327,6 +328,36 @@ enum class VaultVersion : uint8_t {
CashBasis,
};
/**
* Vault kind. Distinguishes closed-ended vaults from the default open-ended
* kind. Persisted as sfVaultKind (UINT8); absent means OpenEnded.
*/
enum class VaultKind : std::uint8_t {
OpenEnded = 0,
ClosedEnded = 1,
};
/**
* Lifecycle phase of a vault. Open-ended vaults are always NoPhase; the other
* three values are the phases of a closed-ended vault.
*/
enum class VaultPhase : std::uint8_t {
NoPhase = 0,
Subscription,
Investment,
Redemption,
};
/**
* Bounds on the length of a closed-ended vault's Investment phase
* (RedemptionDate - SubscriptionDate). At vault creation the gap must satisfy
* kMinInvestmentPeriod <= gap < kMaxInvestmentPeriod.
*/
constexpr std::uint32_t kMinInvestmentPeriod =
std::chrono::seconds{std::chrono::minutes{1}}.count();
// This is 946708560 seconds which 30 x 365.2425 days (the average length of a Gregorian year).
constexpr std::uint32_t kMaxInvestmentPeriod = std::chrono::seconds{std::chrono::years{30}}.count();
/**
* Maximum recursion depth for vault shares being put as an asset inside
* another vault; counted from 0

View File

@@ -75,13 +75,6 @@ operator==(TAmounts<In, Out> const& lhs, TAmounts<In, Out> const& rhs) noexcept
return lhs.in == rhs.in && lhs.out == rhs.out;
}
template <class In, class Out>
bool
operator!=(TAmounts<In, Out> const& lhs, TAmounts<In, Out> const& rhs) noexcept
{
return !(lhs == rhs);
}
//------------------------------------------------------------------------------
// XRPL specific constant used for parsing qualities and other things
@@ -271,12 +264,6 @@ public:
return lhs.value_ == rhs.value_;
}
friend bool
operator!=(Quality const& lhs, Quality const& rhs) noexcept
{
return !(lhs == rhs);
}
friend std::ostream&
operator<<(std::ostream& os, Quality const& quality)
{

View File

@@ -60,6 +60,15 @@ public:
std::optional<Number>
outFromAvgQ(Quality const& quality);
/**
* Return whether `out` produces at least the requested
* average quality.
* @param quality requested average quality (quality limit)
* @param out output amount to test
*/
[[nodiscard]] bool
satisfiesAvgQ(Quality const& quality, Number const& out) const;
/**
* Return true if the quality function is constant
*/

View File

@@ -98,9 +98,6 @@ public:
*/
bool
operator==(Rules const&) const;
bool
operator!=(Rules const& other) const;
};
std::optional<Rules> const&

View File

@@ -642,12 +642,6 @@ operator==(STAmount const& lhs, STAmount const& rhs);
bool
operator<(STAmount const& lhs, STAmount const& rhs);
inline bool
operator!=(STAmount const& lhs, STAmount const& rhs)
{
return !(lhs == rhs);
}
inline bool
operator>(STAmount const& lhs, STAmount const& rhs)
{

View File

@@ -133,9 +133,6 @@ public:
bool
operator==(STArray const& s) const;
bool
operator!=(STArray const& s) const;
iterator
erase(iterator pos);
@@ -283,12 +280,6 @@ STArray::operator==(STArray const& s) const
return v_ == s.v_;
}
inline bool
STArray::operator!=(STArray const& s) const
{
return v_ != s.v_;
}
inline STArray::iterator
STArray::erase(iterator pos)
{

View File

@@ -140,8 +140,6 @@ public:
bool
operator==(STBase const& t) const;
bool
operator!=(STBase const& t) const;
template <class D>
D&

View File

@@ -93,12 +93,6 @@ operator==(STCurrency const& lhs, STCurrency const& rhs)
return lhs.currency() == rhs.currency();
}
inline bool
operator!=(STCurrency const& lhs, STCurrency const& rhs)
{
return !operator==(lhs, rhs);
}
inline bool
operator<(STCurrency const& lhs, STCurrency const& rhs)
{

View File

@@ -432,8 +432,6 @@ public:
bool
operator==(STObject const& o) const;
bool
operator!=(STObject const& o) const;
class FieldErr;
@@ -667,36 +665,6 @@ public:
return !lhs.engaged() || *lhs == *rhs;
}
friend bool
operator!=(OptionalProxy const& lhs, std::nullopt_t) noexcept
{
return !(lhs == std::nullopt);
}
friend bool
operator!=(std::nullopt_t, OptionalProxy const& rhs) noexcept
{
return !(rhs == std::nullopt);
}
friend bool
operator!=(OptionalProxy const& lhs, optional_type const& rhs) noexcept
{
return !(lhs == rhs);
}
friend bool
operator!=(optional_type const& lhs, OptionalProxy const& rhs) noexcept
{
return !(lhs == rhs);
}
friend bool
operator!=(OptionalProxy const& lhs, OptionalProxy const& rhs) noexcept
{
return !(lhs == rhs);
}
// Emulate std::optional::value_or
[[nodiscard]] value_type
valueOr(value_type val) const;
@@ -1202,12 +1170,6 @@ STObject::setFieldH160(SField const& field, BaseUInt<160, Tag> const& v)
}
}
inline bool
STObject::operator!=(STObject const& o) const
{
return !(*this == o);
}
template <typename T, typename V>
V
STObject::getFieldByValue(SField const& field) const

View File

@@ -115,9 +115,6 @@ public:
bool
operator==(STPathElement const& t) const;
bool
operator!=(STPathElement const& t) const;
private:
static std::size_t
getHash(STPathElement const& element);
@@ -432,12 +429,6 @@ STPathElement::operator==(STPathElement const& t) const
accountID_ == t.accountID_ && assetID_ == t.assetID_ && issuerID_ == t.issuerID_;
}
inline bool
STPathElement::operator!=(STPathElement const& t) const
{
return !operator==(t);
}
// ------------ STPath ------------
inline STPath::STPath(std::vector<STPathElement> p) : path_(std::move(p))

View File

@@ -123,12 +123,6 @@ public:
return (lhs.value() == rhs.value());
}
friend constexpr bool
operator!=(SeqProxy lhs, SeqProxy rhs)
{
return !(lhs == rhs);
}
friend constexpr bool
operator<(SeqProxy lhs, SeqProxy rhs)
{

View File

@@ -265,20 +265,10 @@ public:
return v == data_;
}
bool
operator!=(Blob const& v) const
{
return v != data_;
}
bool
operator==(Serializer const& v) const
{
return v.data_ == data_;
}
bool
operator!=(Serializer const& v) const
{
return v.data_ != data_;
}
static int
decodeLengthLength(int b1);

View File

@@ -425,8 +425,7 @@ inline constexpr FlagValue tfDepositSubTx =
ASF_FLAG(asfDefaultRipple, 8) \
ASF_FLAG(asfDepositAuth, 9) \
ASF_FLAG(asfAuthorizedNFTokenMinter, 10) \
/* 11 is reserved for Hooks amendment */ \
/* ASF_FLAG(asfTshCollect, 11) */ \
/* 11 is unused */ \
ASF_FLAG(asfDisallowIncomingNFTokenOffer, 12) \
ASF_FLAG(asfDisallowIncomingCheck, 13) \
ASF_FLAG(asfDisallowIncomingPayChan, 14) \

View File

@@ -258,13 +258,6 @@ public:
return value_ == other;
}
template <Compatible<ValueUnit> Other>
constexpr bool
operator!=(ValueUnit<unit_type, Other> const& other) const
{
return !operator==(other);
}
constexpr bool
operator<(ValueUnit const& other) const
{

View File

@@ -152,10 +152,4 @@ operator==(STVar const& lhs, STVar const& rhs)
return lhs.get().isEquivalent(rhs.get());
}
inline bool
operator!=(STVar const& lhs, STVar const& rhs)
{
return !(lhs == rhs);
}
} // namespace xrpl::detail

View File

@@ -506,6 +506,9 @@ LEDGER_ENTRY(ltVAULT, 0x0084, Vault, vault, ({
{sfWithdrawalPolicy, SoeRequired},
{sfScale, SoeDefault},
{sfLEVersion, SoeDefault},
{sfVaultKind, SoeDefault},
{sfSubscriptionDate, SoeOptional},
{sfRedemptionDate, SoeOptional},
// no SharesTotal ever (use MPTIssuance.sfOutstandingAmount)
// no PermissionedDomainID ever (use MPTIssuance.sfDomainID)
}))

View File

@@ -23,9 +23,11 @@ TYPED_SFIELD(sfLEVersion, UINT8, 6)
// 8-bit integers (uncommon)
TYPED_SFIELD(sfTickSize, UINT8, 16)
TYPED_SFIELD(sfUNLModifyDisabling, UINT8, 17)
TYPED_SFIELD(sfHookResult, UINT8, 18)
// 18 unused
TYPED_SFIELD(sfWasLockingChainSend, UINT8, 19)
TYPED_SFIELD(sfWithdrawalPolicy, UINT8, 20)
TYPED_SFIELD(sfContractResult, UINT8, 21)
TYPED_SFIELD(sfVaultKind, UINT8, 22)
// 16-bit integers (common)
TYPED_SFIELD(sfLedgerEntryType, UINT16, 1, SField::kSmdNever)
@@ -37,10 +39,7 @@ TYPED_SFIELD(sfDiscountedFee, UINT16, 6)
// 16-bit integers (uncommon)
TYPED_SFIELD(sfVersion, UINT16, 16)
TYPED_SFIELD(sfHookStateChangeCount, UINT16, 17)
TYPED_SFIELD(sfHookEmitCount, UINT16, 18)
TYPED_SFIELD(sfHookExecutionIndex, UINT16, 19)
TYPED_SFIELD(sfHookApiVersion, UINT16, 20)
// 17 to 20 unused
TYPED_SFIELD(sfLedgerFixType, UINT16, 21)
TYPED_SFIELD(sfManagementFeeRate, UINT16, 22) // 1/10 basis points (bips)
@@ -91,9 +90,7 @@ TYPED_SFIELD(sfTicketSequence, UINT32, 41)
TYPED_SFIELD(sfNFTokenTaxon, UINT32, 42)
TYPED_SFIELD(sfMintedNFTokens, UINT32, 43)
TYPED_SFIELD(sfBurnedNFTokens, UINT32, 44)
TYPED_SFIELD(sfHookStateCount, UINT32, 45)
TYPED_SFIELD(sfEmitGeneration, UINT32, 46)
// 47 reserved for Hooks
// 45 to 47 unused
TYPED_SFIELD(sfVoteWeight, UINT32, 48)
TYPED_SFIELD(sfFirstNFTokenSequence, UINT32, 50)
TYPED_SFIELD(sfOracleDocumentID, UINT32, 51)
@@ -120,6 +117,8 @@ TYPED_SFIELD(sfSponsoringOwnerCount, UINT32, 71)
TYPED_SFIELD(sfSponsoringAccountCount, UINT32, 72)
TYPED_SFIELD(sfRemainingOwnerCount, UINT32, 73)
TYPED_SFIELD(sfSponsorFlags, UINT32, 74)
TYPED_SFIELD(sfSubscriptionDate, UINT32, 75)
TYPED_SFIELD(sfRedemptionDate, UINT32, 76)
// 64-bit integers (common)
TYPED_SFIELD(sfIndexNext, UINT64, 1)
@@ -137,9 +136,7 @@ TYPED_SFIELD(sfNFTokenOfferNode, UINT64, 12)
TYPED_SFIELD(sfEmitBurden, UINT64, 13)
// 64-bit integers (uncommon)
TYPED_SFIELD(sfHookOn, UINT64, 16)
TYPED_SFIELD(sfHookInstructionCount, UINT64, 17)
TYPED_SFIELD(sfHookReturnCode, UINT64, 18)
// 16 to 18 unused
TYPED_SFIELD(sfReferenceCount, UINT64, 19)
TYPED_SFIELD(sfXChainClaimID, UINT64, 20)
TYPED_SFIELD(sfXChainAccountCreateCount, UINT64, 21)
@@ -203,10 +200,7 @@ TYPED_SFIELD(sfPreviousPageMin, UINT256, 26)
TYPED_SFIELD(sfNextPageMin, UINT256, 27)
TYPED_SFIELD(sfNFTokenBuyOffer, UINT256, 28)
TYPED_SFIELD(sfNFTokenSellOffer, UINT256, 29)
TYPED_SFIELD(sfHookStateKey, UINT256, 30)
TYPED_SFIELD(sfHookHash, UINT256, 31)
TYPED_SFIELD(sfHookNamespace, UINT256, 32)
TYPED_SFIELD(sfHookSetTxnID, UINT256, 33)
// 30 to 33 unused
TYPED_SFIELD(sfDomainID, UINT256, 34)
TYPED_SFIELD(sfVaultID, UINT256, 35,
SField::kSmdPseudoAccount | SField::kSmdDefault)
@@ -237,7 +231,7 @@ TYPED_SFIELD(sfTotalValueOutstanding, NUMBER, 15, SField::kSmdNeedsAsset
TYPED_SFIELD(sfPeriodicPayment, NUMBER, 16)
TYPED_SFIELD(sfManagementFeeOutstanding, NUMBER, 17, SField::kSmdNeedsAsset | SField::kSmdDefault)
// int32
// 32-bit signed (common)
TYPED_SFIELD(sfLoanScale, INT32, 1)
TYPED_SFIELD(sfRemainingOwnerCountDelta, INT32, 2)
@@ -261,15 +255,13 @@ TYPED_SFIELD(sfMinimumOffer, AMOUNT, 16)
TYPED_SFIELD(sfRippleEscrow, AMOUNT, 17)
TYPED_SFIELD(sfDeliveredAmount, AMOUNT, 18)
TYPED_SFIELD(sfNFTokenBrokerFee, AMOUNT, 19)
// Reserve 20 & 21 for Hooks.
// 20 to 21 unused
// currency amount (fees)
TYPED_SFIELD(sfBaseFeeDrops, AMOUNT, 22)
TYPED_SFIELD(sfReserveBaseDrops, AMOUNT, 23)
TYPED_SFIELD(sfReserveIncrementDrops, AMOUNT, 24)
// currency amount (AMM)
// currency amount (more)
TYPED_SFIELD(sfLPTokenOut, AMOUNT, 25)
TYPED_SFIELD(sfLPTokenIn, AMOUNT, 26)
TYPED_SFIELD(sfEPrice, AMOUNT, 27)
@@ -304,10 +296,7 @@ TYPED_SFIELD(sfMasterSignature, VL, 18, SField::kSmdDefault, SFi
TYPED_SFIELD(sfUNLModifyValidator, VL, 19)
TYPED_SFIELD(sfValidatorToDisable, VL, 20)
TYPED_SFIELD(sfValidatorToReEnable, VL, 21)
TYPED_SFIELD(sfHookStateData, VL, 22)
TYPED_SFIELD(sfHookReturnString, VL, 23)
TYPED_SFIELD(sfHookParameterName, VL, 24)
TYPED_SFIELD(sfHookParameterValue, VL, 25)
// 22 to 25 unused
TYPED_SFIELD(sfDIDDocument, VL, 26)
TYPED_SFIELD(sfData, VL, 27)
TYPED_SFIELD(sfAssetClass, VL, 28)
@@ -345,7 +334,7 @@ TYPED_SFIELD(sfHolder, ACCOUNT, 11)
TYPED_SFIELD(sfDelegate, ACCOUNT, 12)
// account (uncommon)
TYPED_SFIELD(sfHookAccount, ACCOUNT, 16)
// 16 unused
TYPED_SFIELD(sfOtherChainSource, ACCOUNT, 18)
TYPED_SFIELD(sfOtherChainDestination, ACCOUNT, 19)
TYPED_SFIELD(sfAttestationSignerAccount, ACCOUNT, 20)
@@ -398,7 +387,7 @@ UNTYPED_SFIELD(sfMemo, OBJECT, 10)
UNTYPED_SFIELD(sfSignerEntry, OBJECT, 11)
UNTYPED_SFIELD(sfNFToken, OBJECT, 12)
UNTYPED_SFIELD(sfEmitDetails, OBJECT, 13)
UNTYPED_SFIELD(sfHook, OBJECT, 14)
// 14 unused
UNTYPED_SFIELD(sfPermission, OBJECT, 15)
// inner object (uncommon)
@@ -406,11 +395,7 @@ UNTYPED_SFIELD(sfSigner, OBJECT, 16)
// 17 unused
UNTYPED_SFIELD(sfMajority, OBJECT, 18)
UNTYPED_SFIELD(sfDisabledValidator, OBJECT, 19)
UNTYPED_SFIELD(sfEmittedTxn, OBJECT, 20)
UNTYPED_SFIELD(sfHookExecution, OBJECT, 21)
UNTYPED_SFIELD(sfHookDefinition, OBJECT, 22)
UNTYPED_SFIELD(sfHookParameter, OBJECT, 23)
UNTYPED_SFIELD(sfHookGrant, OBJECT, 24)
// 20 to 24 unused
UNTYPED_SFIELD(sfVoteEntry, OBJECT, 25)
UNTYPED_SFIELD(sfAuctionSlot, OBJECT, 26)
UNTYPED_SFIELD(sfAuthAccount, OBJECT, 27)
@@ -438,16 +423,14 @@ UNTYPED_SFIELD(sfSufficient, ARRAY, 7)
UNTYPED_SFIELD(sfAffectedNodes, ARRAY, 8)
UNTYPED_SFIELD(sfMemos, ARRAY, 9)
UNTYPED_SFIELD(sfNFTokens, ARRAY, 10)
UNTYPED_SFIELD(sfHooks, ARRAY, 11)
// 11 unused
UNTYPED_SFIELD(sfVoteSlots, ARRAY, 12)
UNTYPED_SFIELD(sfAdditionalBooks, ARRAY, 13)
// array of objects (uncommon)
UNTYPED_SFIELD(sfMajorities, ARRAY, 16)
UNTYPED_SFIELD(sfDisabledValidators, ARRAY, 17)
UNTYPED_SFIELD(sfHookExecutions, ARRAY, 18)
UNTYPED_SFIELD(sfHookParameters, ARRAY, 19)
UNTYPED_SFIELD(sfHookGrants, ARRAY, 20)
// 18 to 20 unused
UNTYPED_SFIELD(sfXChainClaimAttestations, ARRAY, 21)
UNTYPED_SFIELD(sfXChainCreateAccountAttestations, ARRAY, 22)
// 23 unused

View File

@@ -862,6 +862,9 @@ TRANSACTION(ttVAULT_CREATE, 65, VaultCreate,
{sfWithdrawalPolicy, SoeOptional},
{sfData, SoeOptional},
{sfScale, SoeOptional},
{sfVaultKind, SoeOptional},
{sfSubscriptionDate, SoeOptional},
{sfRedemptionDate, SoeOptional},
}))
/** This transaction updates a single asset vault. */

View File

@@ -311,6 +311,78 @@ public:
{
return this->sle_->isFieldPresent(sfLEVersion);
}
/**
* @brief Get sfVaultKind (SoeDefault)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT8::type::value_type>
getVaultKind() const
{
if (hasVaultKind())
return this->sle_->at(sfVaultKind);
return std::nullopt;
}
/**
* @brief Check if sfVaultKind is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasVaultKind() const
{
return this->sle_->isFieldPresent(sfVaultKind);
}
/**
* @brief Get sfSubscriptionDate (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT32::type::value_type>
getSubscriptionDate() const
{
if (hasSubscriptionDate())
return this->sle_->at(sfSubscriptionDate);
return std::nullopt;
}
/**
* @brief Check if sfSubscriptionDate is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasSubscriptionDate() const
{
return this->sle_->isFieldPresent(sfSubscriptionDate);
}
/**
* @brief Get sfRedemptionDate (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT32::type::value_type>
getRedemptionDate() const
{
if (hasRedemptionDate())
return this->sle_->at(sfRedemptionDate);
return std::nullopt;
}
/**
* @brief Check if sfRedemptionDate is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasRedemptionDate() const
{
return this->sle_->isFieldPresent(sfRedemptionDate);
}
};
/**
@@ -543,6 +615,39 @@ public:
return *this;
}
/**
* @brief Set sfVaultKind (SoeDefault)
* @return Reference to this builder for method chaining.
*/
VaultBuilder&
setVaultKind(std::decay_t<typename SF_UINT8::type::value_type> const& value)
{
object_[sfVaultKind] = value;
return *this;
}
/**
* @brief Set sfSubscriptionDate (SoeOptional)
* @return Reference to this builder for method chaining.
*/
VaultBuilder&
setSubscriptionDate(std::decay_t<typename SF_UINT32::type::value_type> const& value)
{
object_[sfSubscriptionDate] = value;
return *this;
}
/**
* @brief Set sfRedemptionDate (SoeOptional)
* @return Reference to this builder for method chaining.
*/
VaultBuilder&
setRedemptionDate(std::decay_t<typename SF_UINT32::type::value_type> const& value)
{
object_[sfRedemptionDate] = value;
return *this;
}
/**
* @brief Build and return the completed Vault wrapper.
* @param index The ledger entry index.

View File

@@ -214,6 +214,84 @@ public:
{
return this->tx_->isFieldPresent(sfScale);
}
/**
* @brief Get sfVaultKind (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT8::type::value_type>
getVaultKind() const
{
if (hasVaultKind())
{
return this->tx_->at(sfVaultKind);
}
return std::nullopt;
}
/**
* @brief Check if sfVaultKind is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasVaultKind() const
{
return this->tx_->isFieldPresent(sfVaultKind);
}
/**
* @brief Get sfSubscriptionDate (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT32::type::value_type>
getSubscriptionDate() const
{
if (hasSubscriptionDate())
{
return this->tx_->at(sfSubscriptionDate);
}
return std::nullopt;
}
/**
* @brief Check if sfSubscriptionDate is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasSubscriptionDate() const
{
return this->tx_->isFieldPresent(sfSubscriptionDate);
}
/**
* @brief Get sfRedemptionDate (SoeOptional)
* @return The field value, or std::nullopt if not present.
*/
[[nodiscard]]
protocol_autogen::Optional<SF_UINT32::type::value_type>
getRedemptionDate() const
{
if (hasRedemptionDate())
{
return this->tx_->at(sfRedemptionDate);
}
return std::nullopt;
}
/**
* @brief Check if sfRedemptionDate is present.
* @return True if the field is present, false otherwise.
*/
[[nodiscard]]
bool
hasRedemptionDate() const
{
return this->tx_->isFieldPresent(sfRedemptionDate);
}
};
/**
@@ -338,6 +416,39 @@ public:
return *this;
}
/**
* @brief Set sfVaultKind (SoeOptional)
* @return Reference to this builder for method chaining.
*/
VaultCreateBuilder&
setVaultKind(std::decay_t<typename SF_UINT8::type::value_type> const& value)
{
object_[sfVaultKind] = value;
return *this;
}
/**
* @brief Set sfSubscriptionDate (SoeOptional)
* @return Reference to this builder for method chaining.
*/
VaultCreateBuilder&
setSubscriptionDate(std::decay_t<typename SF_UINT32::type::value_type> const& value)
{
object_[sfSubscriptionDate] = value;
return *this;
}
/**
* @brief Set sfRedemptionDate (SoeOptional)
* @return Reference to this builder for method chaining.
*/
VaultCreateBuilder&
setRedemptionDate(std::decay_t<typename SF_UINT32::type::value_type> const& value)
{
object_[sfRedemptionDate] = value;
return *this;
}
/**
* @brief Build and return the VaultCreate wrapper.
* @param publicKey The public key for signing.

View File

@@ -6,13 +6,12 @@
#include <xrpl/core/StartUpType.h>
#include <xrpl/rdb/SociDB.h>
#include <boost/filesystem/path.hpp>
#include <soci/statement.h>
#include <array>
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <functional>
#include <memory>
#include <mutex>
@@ -80,7 +79,7 @@ public:
StartUpType startUp = StartUpType::Normal;
bool standAlone = false;
boost::filesystem::path dataDir;
std::filesystem::path dataDir;
// Indicates whether or not to return the `globalPragma`
// from commonPragma()
bool useGlobalPragma = false;
@@ -143,7 +142,7 @@ public:
template <std::size_t N, std::size_t M>
DatabaseCon(
boost::filesystem::path const& dataDir,
std::filesystem::path const& dataDir,
std::string const& dbName,
std::array<std::string, N> const& pragma,
std::array<char const*, M> const& initSQL,
@@ -155,7 +154,7 @@ public:
// Use this constructor to setup checkpointing
template <std::size_t N, std::size_t M>
DatabaseCon(
boost::filesystem::path const& dataDir,
std::filesystem::path const& dataDir,
std::string const& dbName,
std::array<std::string, N> const& pragma,
std::array<char const*, M> const& initSQL,
@@ -190,7 +189,7 @@ private:
template <std::size_t N, std::size_t M>
DatabaseCon(
boost::filesystem::path const& pPath,
std::filesystem::path const& pPath,
std::vector<std::string> const* commonPragma,
std::array<std::string, N> const& pragma,
std::array<char const*, M> const& initSQL,

View File

@@ -14,7 +14,6 @@
#include <xrpl/protocol/TxMeta.h>
#include <xrpl/protocol/TxSearched.h>
#include <boost/filesystem.hpp>
#include <boost/variant.hpp>
#include <concepts>

View File

@@ -306,12 +306,6 @@ operator==(Manifest const& lhs, Manifest const& rhs)
lhs.serialized == rhs.serialized;
}
inline bool
operator!=(Manifest const& lhs, Manifest const& rhs)
{
return !(lhs == rhs);
}
struct ValidatorToken
{
std::string manifest;

View File

@@ -4,8 +4,6 @@
#include <xrpl/rdb/DatabaseCon.h>
#include <xrpl/rdb/SociDB.h>
#include <boost/filesystem.hpp>
#include <string>
namespace xrpl {

View File

@@ -789,12 +789,6 @@ operator==(SHAMap::ConstIterator const& x, SHAMap::ConstIterator const& y)
return x.item_ == y.item_;
}
inline bool
operator!=(SHAMap::ConstIterator const& x, SHAMap::ConstIterator const& y)
{
return !(x == y);
}
inline SHAMap::ConstIterator
SHAMap::begin() const
{

View File

@@ -3,6 +3,7 @@
#include <xrpl/basics/CountedObject.h>
#include <xrpl/basics/base_uint.h>
#include <compare>
#include <cstddef>
#include <optional>
#include <ostream>
@@ -65,45 +66,32 @@ public:
static SHAMapNodeID
createID(int depth, uint256 const& key);
// FIXME-C++20: use spaceship and operator synthesis
/**
* Comparison operators
*
* <, >, <= and >= are synthesized from the spaceship. It is written out
* rather than defaulted because the ordering is by depth first, and the
* members are not declared in that order.
*/
bool
operator<(SHAMapNodeID const& n) const
std::strong_ordering
operator<=>(SHAMapNodeID const& n) const
{
return std::tie(depth_, id_) < std::tie(n.depth_, n.id_);
}
bool
operator>(SHAMapNodeID const& n) const
{
return n < *this;
}
bool
operator<=(SHAMapNodeID const& n) const
{
return !(n < *this);
}
bool
operator>=(SHAMapNodeID const& n) const
{
return !(*this < n);
return std::tie(depth_, id_) <=> std::tie(n.depth_, n.id_);
}
/**
* Equality, which the spaceship above does not provide.
*
* Only a *defaulted* operator<=> implicitly declares a defaulted
* operator==; the one above is user-provided, so == has to be written.
* It cannot be defaulted either, because a defaulted == would also compare
* the CountedObject base, which is not equality comparable.
*/
bool
operator==(SHAMapNodeID const& n) const
{
return (depth_ == n.depth_) && (id_ == n.id_);
}
bool
operator!=(SHAMapNodeID const& n) const
{
return !(*this == n);
}
};
inline std::string

View File

@@ -69,7 +69,8 @@ private:
IssuerChanges const& changes,
STTx const& tx,
beast::Journal const& j,
bool enforce);
bool enforce,
bool fixOverrideFreeze);
static bool
validateFrozenState(
@@ -78,7 +79,8 @@ private:
STTx const& tx,
beast::Journal const& j,
bool enforce,
bool globalFreeze);
bool globalFreeze,
bool fixOverrideFreeze);
};
} // namespace xrpl

View File

@@ -198,7 +198,7 @@ public:
/**
* @brief Invariant: An account XRP balance must be in XRP and take a value
* between 0 and INITIAL_XRP drops, inclusive.
* between 0 and kInitialXRP drops, inclusive.
*
* We iterate all account roots modified by the transaction and ensure that
* their XRP balances are reasonable.
@@ -290,7 +290,7 @@ public:
/**
* @brief Invariant: an escrow entry must take a value between 0 and
* INITIAL_XRP drops exclusive.
* kInitialXRP drops exclusive.
*/
class NoZeroEscrow
{

View File

@@ -16,6 +16,8 @@ namespace xrpl {
* @brief Invariants: Loans are internally consistent
*
* 1. If `Loan.PaymentRemaining = 0` then `Loan.PrincipalOutstanding = 0`
* 2. A newly-created Loan against a closed-ended vault must satisfy
* `StartDate + PaymentInterval * PaymentRemaining < Vault.RedemptionDate`.
*
*/
class ValidLoan

View File

@@ -38,7 +38,17 @@ namespace xrpl {
* - vault set must not alter the vault assets or shares balance
* - no vault transaction can change loss unrealized (it's updated by loan
* transactions)
* - a created closed-ended vault must satisfy
* MIN_INVESTMENT_PERIOD <= RedemptionDate - SubscriptionDate <
* MAX_INVESTMENT_PERIOD
* - vault deposit may only succeed when the vault phase is NoPhase or
* Subscription
* - vault withdrawal may not succeed when the vault phase is Investment
* - closed-ended loan origination (ttLOAN_SET) may only succeed when the
* vault phase is Investment
*
* Immutability of VaultKind, SubscriptionDate and RedemptionDate is enforced
* by NoModifiedUnmodifiableFields (see InvariantCheck.cpp).
*/
class ValidVault
{
@@ -55,6 +65,9 @@ class ValidVault
Number assetsAvailable = 0;
Number assetsMaximum = 0;
Number lossUnrealized = 0;
std::optional<std::uint8_t> vaultKind;
std::optional<std::uint32_t> subscriptionDate;
std::optional<std::uint32_t> redemptionDate;
Vault static make(SLE const&);
};
@@ -153,6 +166,17 @@ private:
[[nodiscard]] static bool
isVaultEmpty(Vault const& vault);
/**
* @brief Invariant check for @c ttLOAN_SET.
*
* For a closed-ended vault, a loan may only be originated while the vault is in the Investment
* phase (strictly past @c SubscriptionDate and before @c RedemptionDate). Open-ended vaults (@c
* NoPhase) are unaffected. The complementary maturity bound (final payment strictly precedes @c
* RedemptionDate) is enforced by @c ValidLoan.
*/
[[nodiscard]] bool
finalizeLoanSet(ReadView const& view, beast::Journal const& j) const;
public:
// Compute the coarsest scale required to represent all numbers
[[nodiscard]] static std::int32_t

View File

@@ -274,19 +274,6 @@ public:
return lhs.equal(rhs);
}
/**
* Return true if lhs != rhs.
*
* @param lhs Step to compare.
* @param rhs Step to compare.
* @return true if lhs != rhs.
*/
friend bool
operator!=(Step const& lhs, Step const& rhs)
{
return !(lhs == rhs);
}
/**
* Streaming operator for a Step.
*/

View File

@@ -1,6 +1,7 @@
#pragma once
#include <xrpl/basics/Log.h>
#include <xrpl/basics/Number.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/Zero.h>
@@ -373,7 +374,7 @@ qualityUpperBound(ReadView const& v, Strand const& strand)
* increases quality of AMM steps, increasing the strand's composite
* quality as the result.
*/
template <typename TOutAmt>
template <StepAmount TOutAmt>
inline TOutAmt
limitOut(
ReadView const& v,
@@ -411,21 +412,29 @@ limitOut(
auto const out = qf->outFromAvgQ(limitQuality);
if (!out)
return remainingOut;
if constexpr (std::is_same_v<TOutAmt, XRPAmount>)
if constexpr (std::is_same_v<TOutAmt, XRPAmount> || std::is_same_v<TOutAmt, MPTAmount>)
{
return XRPAmount{*out};
auto const roundedOut = TOutAmt{*out};
// Integral outputs that round above the continuous target can
// realize worse average quality than the requested limit. Keep the
// default rounded value when it still satisfies the limit, since it
// is the largest matching offer; otherwise round down.
if (v.rules().enabled(featureMPTokensV2) && roundedOut > *out &&
!qf->satisfiesAvgQ(limitQuality, roundedOut))
{
NumberRoundModeGuard const g(Number::RoundingMode::Downward);
return TOutAmt{*out};
}
return roundedOut;
}
else if constexpr (std::is_same_v<TOutAmt, IOUAmount>)
{
return IOUAmount{*out};
}
else if constexpr (std::is_same_v<TOutAmt, MPTAmount>)
{
return MPTAmount{*out};
}
else
{
return STAmount{remainingOut.asset(), out->mantissa(), out->exponent()};
static constexpr bool kAlwaysFalse = !std::is_same_v<TOutAmt, TOutAmt>;
static_assert(kAlwaysFalse, "Unhandled StepAmount type");
}
}();
// A tiny difference could be due to the round off

View File

@@ -118,6 +118,7 @@ public:
Sandbox& view,
SLE const& ammSle,
AccountID const account,
std::optional<AccountID> const& clawbackIssuer,
AccountID const& ammAccount,
STAmount const& amountBalance,
STAmount const& amount2Balance,
@@ -138,6 +139,11 @@ public:
* @param view
* @param ammSle AMM ledger entry
* @param ammAccount AMM account
* @param clawbackIssuer when set (AMMClawback path), the issuer performing
* the clawback. A recreated MPToken is only auto-authorized when the
* asset's issuer matches this account, so a clawback cannot grant
* authorization on behalf of a different (paired-asset) issuer.
* @param account LP account
* @param amountBalance current LP asset1 balance
* @param amountWithdraw asset1 withdraw amount
* @param amount2Withdraw asset2 withdraw amount
@@ -153,6 +159,7 @@ public:
Sandbox& view,
SLE const& ammSle,
AccountID const& ammAccount,
std::optional<AccountID> const& clawbackIssuer,
AccountID const& account,
STAmount const& amountBalance,
STAmount const& amountWithdraw,