Compare commits

...
Author SHA1 Message Date
Nik Bougalis da2b5d5eaf Remove beast::typeName
Replace Beast's demangling wrapper (originally by @HowardHinnant)
with calls to `boost::core::type_name`, eliminating the low-level
dependency and manual memory management from the codebase.
2026-10-05 19:42:50 -07:00
Nik Bougalis 4de4902200 Rework and clean up the safe_cast framework:
The SafeToCast concept transposed its signedness clause: it was written in
<Dest, Src> order but it declared <Src, Dest>. This introduced what can be
best described as a polarity bug. As a result:

* Signed-to-wider-unsigned casts were wrongly deemed safe.
* Unsigned-to-wider-signed casts were wrongly deemed unsafe.

The root cause was drift caused by the safety condition being repeated in
the concept and again as a static_assert in safeCast. The checking is now
done only in the concept and is expressed in terms of range coverage, and
not via a sizeof/signedness proxy. This change also improves the handling
of bool (which previously compiled despite truncating) and eliminates the
platform-dependent accept/reject behavior for same-size types.

Additional fixes:

* The pointer form of safeDowncast now performs the same static_cast
  in all builds. The dynamic_cast check is now entirely contained in
  the XRPL_ASSERT.
* Extended integer types wider than intmax_t (e.g. __int128) are now
  excluded from SafeToCast instead of silently misevaluating through
  wrapped bounds; they remain expressible via unsafeCast.

Cleanups:

* Remove the single-parameter enum overload of safeCast: it had an
  explicitly-specified template argument binding to Src, where all
  sibling overload bound to Dest, silently yielding the underlying
  type from expressions that read as casts *to* an enum.
* Add checkedCast for conversions guarded by runtime bounds checks
  where safety varies per instantiation.
* Constrain safeDowncast to polymorphic sources and genuine public
  unambiguous downcasts, rejecting upcasts and unrelated types.
* Route enum conversions through std::to_underlying; clarify the
  unsafeCast/checkedCast documentation split.
2026-10-05 19:42:49 -07:00
Nik Bougalis 2ea1f09dcb Modernize beast::Zero for C++20
- Replace the twelve comparison operators with two
  `constexpr`-capable replacements: `==` and `<=>`
  and allow the compiler to synthesize the rest.
- Constrain `==` and `<=>` using concepts and mark
  them as conditionally noexcept).
- Remove the detail::zero_helper indirection which
  did not do what its comment claimed.
2026-10-05 19:30:38 -07:00
Nik Bougalis 68b4b894de Make ApplyFlags a scoped enumeration:
Convert ApplyFlags to a scoped enum, drop the now-redundant `Tap`
prefix from its enumerators and replace the hand-written bitwise
operators by opting in to enum_bitops.

No functional change.
2026-10-05 19:30:38 -07:00
Nik Bougalis defd83e5a6 Make STPathElement::Type a scoped enumeration:
`STPathElement` stored its type as an `unsigned int`, returned it
as a `std::uint32_t`, while the flags themselves were an unscoped
`enum` (i.e. an `int`). The type field has always been serialized
as a single byte.

This commit turns `STPathElement::Type` into a scoped `enum` with
a fixed sized that matches the serialized width, and opts it into
the bitwise operators from `enum_bitops.h`:

- Store the type as `Type`, and use `Type` for the constructor
  parameter and the return type of `getNodeType()`.
- Keep the existing spellings such as `STPathElement::TypeAccount`
  valid through `using enum`.
- Replace raw mask tests in the serializer, JSON output, strand
  construction and pathfinder with the existing predicates.
- Validate the type byte once when deserializing, before any field
  is read, and restructure the loop around that.
- Make `operator==` a hidden friend.
- Mark the trivial accessors `noexcept`.

No functional changes are intended. The one observable difference
is the rejection error generated for a malformed path element: if
the currency and MPT bits are both set and the input is truncated
within the account field, the invalid bit combination is detected
first; previously the short read would be detected. Such elements
are rejected either way.
2026-10-05 19:30:38 -07:00
Nik Bougalis 452e31a05f Introduce opt-in bitwise operators for scoped enumerations:
Scoped enumerations do not support bitwise operators, so using an
`enum class` as a set of flags requires extensive casting at call
sites or a hand-written set of operators for each type.

Add `enum_bitops.h`, which provides `&`, `|`, `^`, `~` along with
the compound assignment forms for any scoped enumeration that has
an unsigned underlying type and is opted in:

    enum class Flags : std::uint8_t { a = 1, b = 2 };

    // Opt into bitwise operations
    template <>
    struct enum_bitops::OptIn<Flags> : std::true_type {};

All synthesized operators are constexpr and noexcept, and preserve
the enumeration type.
2026-10-05 19:30:37 -07:00
Mayukha Vadari 1798262d7a refactor: Use LedgerHashesEntry everywhere (#8369) 2026-10-05 18:15:02 +00:00
Mayukha Vadari cd633b9ac9 refactor: Use EscrowEntry everywhere (#8354) 2026-10-05 17:51:18 +00:00
Ayaz Salikhov 5c5f7d315a chore: Update nix flake file (#8479) 2026-10-05 16:58:41 +00:00
Mayukha Vadari 0f7493ce50 refactor: Use FeeSettingsEntry everywhere (#8370) 2026-10-05 16:56:41 +00:00
Harshit Gupta 40f61f828a fix: Add string type validation for channel_id and signature (#7582) 2026-10-05 16:55:14 +00:00
Mayukha Vadari 108277f4b7 test: Migrate three beast suites from beast::unit_test to gtest (#7993) 2026-10-05 15:28:05 +00:00
103 changed files with 1346 additions and 1072 deletions

No files matched your search

+5
View File
@@ -30,6 +30,11 @@ Version 3.5.0 is not yet released.
- `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive a message with `type` `mptTransaction` for each validated transaction whose metadata affects a subscribed issuance; the message has the same fields as the `transactions` stream. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671)) - `subscribe`, `unsubscribe`: Added an optional `mpt_issuances` request field, an array of MPT issuance IDs (hex strings). Subscribers receive a message with `type` `mptTransaction` for each validated transaction whose metadata affects a subscribed issuance; the message has the same fields as the `transactions` stream. MPT issuance subscriptions count toward the per-connection subscription limit. An empty array, a non-array value, or an invalid ID returns `invalidParams`. ([#5671](https://github.com/XRPLF/rippled/pull/5671))
### Bugfixes in 3.5.0
- `channel_authorize`: The `channel_id` field now returns an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
- `channel_verify`: The `channel_id` and `signature` fields now return an `invalidParams` error if the value is not a string. [#7582](https://github.com/XRPLF/rippled/pull/7582)
## XRP Ledger server version 3.4.0 ## XRP Ledger server version 3.4.0
Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta releases. Version 3.4.0 is not yet released. These changes are available in the 3.4.0 beta releases.
Generated
+6 -6
View File
@@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1781173989, "lastModified": 1791130267,
"narHash": "sha256-fnzKKPvS+oieI/pTzotA5tkoM47EB1NpaBcgk4R97hE=", "narHash": "sha256-1sjwcQMcgAbmiip/VivBSiK8p2bTkQGOvCuO7vnwfx4=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "8c91a71d13451abc40eb9dae8910f972f979852f", "rev": "9013764fcc0ea99fa16cf7aa7decf8a5c3889dd2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@@ -47,11 +47,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1784611586, "lastModified": 1791189933,
"narHash": "sha256-OfqgY+0hp/zseZB7uyH0U8kIDPS4scZZCyAurEplvG0=", "narHash": "sha256-Y8eN7ki0Urx4Ojf4w1xSpWg8uk/3lJqK+E0Oth77rH0=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "14f58845249f3552a89b07772626b8d3c632fa86", "rev": "e60029353d0c48d216bc4b065168ccd4079c166f",
"type": "github" "type": "github"
}, },
"original": { "original": {
+2 -2
View File
@@ -1,6 +1,6 @@
#pragma once #pragma once
#include <xrpl/beast/type_name.h> #include <boost/core/type_name.hpp>
#include <atomic> #include <atomic>
#include <string> #include <string>
@@ -112,7 +112,7 @@ private:
static auto& static auto&
getCounter() noexcept getCounter() noexcept
{ {
static CountedObjects::Counter kC{beast::typeName<Object>()}; static CountedObjects::Counter kC{boost::core::type_name<Object>()};
return kC; return kC;
} }
+3 -2
View File
@@ -3,11 +3,11 @@
#pragma once #pragma once
#include <xrpl/basics/ByteUtilities.h> #include <xrpl/basics/ByteUtilities.h>
#include <xrpl/beast/type_name.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <boost/align.hpp> #include <boost/align.hpp>
#include <boost/container/static_vector.hpp> #include <boost/container/static_vector.hpp>
#include <boost/core/type_name.hpp>
#include <boost/predef.h> #include <boost/predef.h>
#include <algorithm> #include <algorithm>
@@ -16,6 +16,7 @@
#include <cstring> #include <cstring>
#include <mutex> #include <mutex>
#include <stdexcept> #include <stdexcept>
#include <typeinfo>
#include <vector> #include <vector>
#if BOOST_OS_LINUX #if BOOST_OS_LINUX
@@ -335,7 +336,7 @@ public:
}) != cfg.end()) }) != cfg.end())
{ {
throw std::runtime_error( throw std::runtime_error(
"SlabAllocatorSet<" + beast::typeName<Type>() + ">: duplicate slab size"); "SlabAllocatorSet<" + boost::core::type_name<Type>() + ">: duplicate slab size");
} }
for (auto const& c : cfg) for (auto const& c : cfg)
+3 -2
View File
@@ -1,7 +1,8 @@
#pragma once #pragma once
#include <xrpl/basics/sanitizers.h> #include <xrpl/basics/sanitizers.h>
#include <xrpl/beast/type_name.h>
#include <boost/core/type_name.hpp>
#include <exception> #include <exception>
#include <string> #include <string>
@@ -55,7 +56,7 @@ Throw(Args&&... args)
std::is_convertible_v<E*, std::exception*>, "Exception must derive from std::exception."); std::is_convertible_v<E*, std::exception*>, "Exception must derive from std::exception.");
E e(std::forward<Args>(args)...); E e(std::forward<Args>(args)...);
logThrow(std::string("Throwing exception of type " + beast::typeName<E>() + ": ") + e.what()); logThrow("Throwing exception of type " + boost::core::type_name<E>() + ": " + e.what());
throw std::move(e); throw std::move(e);
} }
+200
View File
@@ -0,0 +1,200 @@
#pragma once
#include <concepts>
#include <type_traits>
#include <utility>
namespace xrpl {
/**
* Opt-in bitwise operators for scoped enumerations.
*
* Provides `&`, `|`, `^`, `~` and the corresponding compound assignment forms
* for any scoped enumeration with an unsigned underlying type that opts in by
* specializing @ref OptIn:
*
* @code
* namespace xrpl {
*
* enum class MyFlags : std::uint32_t { a = 1, b = 2, c = 4 };
*
* template <>
* struct enum_bitops::OptIn<MyFlags> : std::true_type {};
*
* } // namespace xrpl
* @endcode
*
* The operators are constexpr and noexcept, and return the enumeration type.
*
* @par Where the specialization may be declared
* In namespace xrpl, or at global scope with full qualification, and after
* the enumeration is defined but before the operators are first used. This
* cannot be done in a nested namespace or at class scope; for enumerations
* nested in a class this means after the class definition.
*
* @par Where the operators are found
* The operators are declared in namespace xrpl, so argument-dependent lookup
* will find them only for enumerations declared in xrpl or nested in a class
* declared directly in xrpl. Enumerations in a nested namespace will only be
* found from code inside xrpl, and only if no enclosing scope declares an
* operator of the same name; elsewhere they require using-declarations.
*/
namespace enum_bitops {
/**
* Types that may be opted in to the bitwise operators.
*
* Satisfied by a scoped enumeration whose underlying type is an unsigned
* integer type.
*
* @tparam T The type to test.
*/
template <typename T>
concept Eligible = std::is_scoped_enum_v<T> && std::unsigned_integral<std::underlying_type_t<T>>;
/**
* Opt-in switch for the bitwise operators.
*
* The primary template derives from std::false_type. Specialize it to derive
* from std::true_type to enable the operators for an @ref Eligible enumeration.
*
* @tparam T The scoped enumeration to opt in.
*/
template <Eligible T>
struct OptIn : std::false_type
{
};
/**
* Enumerations for which the bitwise operators are enabled.
*
* Satisfied when @p T satisfies @ref Eligible and @ref OptIn has been
* specialized for it to derive from std::true_type.
*
* @tparam T The type to test.
*/
template <typename T>
concept Candidate = Eligible<T> && OptIn<T>::value;
} // namespace enum_bitops
// These are declared in xrpl, not in enum_bitops, so that argument-dependent
// lookup finds them for enumerations whose associated namespace is xrpl.
/**
* @name Bitwise operators for opted-in scoped enumerations
*
* Each operator applies the corresponding built-in operator to the
* underlying values and converts the result back to the enumeration type.
* Both operands must have the same enumeration type; there is no implicit
* conversion to or from the underlying type.
*/
/** @{ */
/**
* Bitwise AND.
*
* @param lhs The left operand.
* @param rhs The right operand.
* @return The bits set in both @p lhs and @p rhs.
*/
template <enum_bitops::Candidate T>
constexpr T
operator&(T lhs, T rhs) noexcept
{
return static_cast<T>(std::to_underlying(lhs) & std::to_underlying(rhs));
}
/**
* Bitwise OR.
*
* @param lhs The left operand.
* @param rhs The right operand.
* @return The bits set in @p lhs, in @p rhs, or in both.
*/
template <enum_bitops::Candidate T>
constexpr T
operator|(T lhs, T rhs) noexcept
{
return static_cast<T>(std::to_underlying(lhs) | std::to_underlying(rhs));
}
/**
* Bitwise exclusive OR.
*
* @param lhs The left operand.
* @param rhs The right operand.
* @return The bits set in exactly one of @p lhs and @p rhs.
*/
template <enum_bitops::Candidate T>
constexpr T
operator^(T lhs, T rhs) noexcept
{
return static_cast<T>(std::to_underlying(lhs) ^ std::to_underlying(rhs));
}
/**
* Bitwise complement.
*
* The result has every bit of the underlying type that is clear in
* @p val, including bits that no enumerator names. It is intended for
* clearing flags, as in `flags & ~flag`.
*
* @param val The operand.
* @return The complement of @p val.
*/
template <enum_bitops::Candidate T>
constexpr T
operator~(T val) noexcept
{
return static_cast<T>(~std::to_underlying(val));
}
/**
* Bitwise AND assignment.
*
* @param lhs The value to modify.
* @param rhs The right operand.
* @return A reference to @p lhs.
*/
template <enum_bitops::Candidate T>
constexpr T&
operator&=(T& lhs, T rhs) noexcept
{
lhs = lhs & rhs;
return lhs;
}
/**
* Bitwise OR assignment.
*
* @param lhs The value to modify.
* @param rhs The right operand.
* @return A reference to @p lhs.
*/
template <enum_bitops::Candidate T>
constexpr T&
operator|=(T& lhs, T rhs) noexcept
{
lhs = lhs | rhs;
return lhs;
}
/**
* Bitwise exclusive OR assignment.
*
* @param lhs The value to modify.
* @param rhs The right operand.
* @return A reference to @p lhs.
*/
template <enum_bitops::Candidate T>
constexpr T&
operator^=(T& lhs, T rhs) noexcept
{
lhs = lhs ^ rhs;
return lhs;
}
/** @} */
} // namespace xrpl
+152 -47
View File
@@ -2,107 +2,212 @@
#include <xrpl/beast/utility/instrumentation.h> // IWYU pragma: keep #include <xrpl/beast/utility/instrumentation.h> // IWYU pragma: keep
#include <concepts>
#include <cstdint>
#include <limits>
#include <memory>
#include <type_traits> #include <type_traits>
#include <utility>
namespace xrpl { namespace xrpl {
// safe_cast adds compile-time checks to a static_cast to ensure that /** Every value of @p Src can be represented by @p Dest.
// the destination can hold all values of the source. This is particularly
// handy when the source or destination is an enumeration type.
template <class Src, class Dest> Given two integral types, the cast is safe when the destination can
concept SafeToCast = (std::is_integral_v<Src> && std::is_integral_v<Dest>) && hold every possible value of the source.
(std::is_signed_v<Src> || std::is_unsigned_v<Dest>) &&
(std::is_signed_v<Src> != std::is_signed_v<Dest> ? sizeof(Dest) > sizeof(Src)
: sizeof(Dest) >= sizeof(Src));
template <class Dest, class Src> Comparing the bounds requires care: we use @c std::cmp_less_equal and
@c std::cmp_greater_equal; the plain relational operators would apply
arithmetic conversions, resulting in incorrect results when comparing
across signedness.
Because @c std::cmp_* requires standard signed or unsigned integer
arguments, which excludes character types and bool, we first widen
all type bounds to the maximum-width integer type while preserving
signedness.
@note Extended integer types, like __int128 on gcc, cannot be safely
widened to a standard integer type, so the concept will reject
them.
*/
template <typename Src, typename Dest>
concept SafeToCast = std::is_integral_v<Src> && std::is_integral_v<Dest> && []() consteval {
using WideSrc = std::conditional_t<std::is_signed_v<Src>, std::intmax_t, std::uintmax_t>;
using WideDest = std::conditional_t<std::is_signed_v<Dest>, std::intmax_t, std::uintmax_t>;
// Note: this guard must be an evaluated branch, and not a
// static_assert. The lambda body is outside the immediate
// context, so a substitution-time failure here would be a
// hard error rather than leaving the concept unsatisfied.
if constexpr (sizeof(Src) > sizeof(WideSrc) || sizeof(Dest) > sizeof(WideDest))
{
return false;
}
else
{
return std::cmp_less_equal(
static_cast<WideDest>(std::numeric_limits<Dest>::min()),
static_cast<WideSrc>(std::numeric_limits<Src>::min())) &&
std::cmp_greater_equal(
static_cast<WideDest>(std::numeric_limits<Dest>::max()),
static_cast<WideSrc>(std::numeric_limits<Src>::max()));
}
}();
/** Compile-time-checked static_cast that rejects non-value preserving casts.
@note There is deliberately no enum-to-enum overload, and no overload
returning the underlying type of an enum. For the latter, use
@c std::to_underlying.
*/
/** @{ */
template <typename Dest, typename Src>
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
constexpr Dest constexpr Dest
safeCast(Src s) noexcept safeCast(Src s) noexcept
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
{ {
static_assert( static_assert(
std::is_signed_v<Dest> || std::is_unsigned_v<Src>, "Cannot cast signed to unsigned"); SafeToCast<Src, Dest>, "This cast is not value-preserving. Please use unsafeCast instead.");
constexpr unsigned kNotSame = std::is_signed_v<Dest> != std::is_signed_v<Src>;
static_assert(
sizeof(Dest) >= sizeof(Src) + kNotSame,
"Destination is too small to hold all values of source");
return static_cast<Dest>(s); return static_cast<Dest>(s);
} }
template <class Dest, class Src> template <typename Dest, typename Src>
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
constexpr Dest constexpr Dest
safeCast(Src s) noexcept safeCast(Src s) noexcept
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
{ {
return static_cast<Dest>(safeCast<std::underlying_type_t<Dest>>(s)); return static_cast<Dest>(safeCast<std::underlying_type_t<Dest>>(s));
} }
template <class Dest, class Src> template <typename Dest, typename Src>
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
constexpr Dest constexpr Dest
safeCast(Src s) noexcept safeCast(Src s) noexcept
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
{ {
return safeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s)); return safeCast<Dest>(std::to_underlying(s));
} }
/** @} */
// unsafe_cast explicitly flags a static_cast as not necessarily able to hold /** Integral-to-integral cast that is known to be narrowing or sign-erasing.
// all values of the source. It includes a compile-time check so that if
// underlying types become safe, it can be converted to a safe_cast.
template <class Dest, class Src> This explicitly flags a conversion that can lose information for some
values of the source type, where the call site accepts that loss (or
truncation is the intended behavior).
The compile-time check ensures the cast remains "unsafe": if the types
involved later change such that the conversion becomes inherently
value-preserving, the static assertion fires with instructions to
migrate the call site to @ref safeCast.
If the conversion's safety depends on a runtime precondition rather
than on the types, or varies across instantiations of generic code,
use @ref checkedCast instead.
*/
/** @{ */
template <typename Dest, typename Src>
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
constexpr Dest constexpr Dest
unsafeCast(Src s) noexcept unsafeCast(Src s) noexcept
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
{ {
static_assert( static_assert(
!SafeToCast<Src, Dest>, !SafeToCast<Src, Dest>, "This cast is value-preserving. Please use safeCast instead.");
"Only unsafe if casting signed to unsigned or "
"destination is too small");
return static_cast<Dest>(s); return static_cast<Dest>(s);
} }
template <class Dest, class Src> template <typename Dest, typename Src>
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
constexpr Dest constexpr Dest
unsafeCast(Src s) noexcept unsafeCast(Src s) noexcept
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
{ {
return static_cast<Dest>(unsafeCast<std::underlying_type_t<Dest>>(s)); return static_cast<Dest>(unsafeCast<std::underlying_type_t<Dest>>(s));
} }
template <class Dest, class Src> template <typename Dest, typename Src>
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
constexpr Dest constexpr Dest
unsafeCast(Src s) noexcept unsafeCast(Src s) noexcept
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
{ {
return unsafeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s)); return unsafeCast<Dest>(std::to_underlying(s));
}
/** @} */
/** Integral-to-integral cast when the caller has performed a bounds check.
This documents that a runtime precondition or external invariant, which
is not necessarily visible to the compiler, guarantees that the requested
conversion is value-preserving for the values that can actually occur.
This is primarily meant for generic code, where the same expression may
be value-preserving for one instantiation but not for another, making
both @ref safeCast and @ref unsafeCast unusable.
Unlike @ref safeCast and @ref unsafeCast, this imposes no static check
on the type relationship: the caller's claim is about runtime values,
not about types.
*/
/** @{ */
template <typename Dest, typename Src>
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
constexpr Dest
checkedCast(Src s) noexcept
{
return static_cast<Dest>(s);
} }
template <typename Dest, typename Src>
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
constexpr Dest
checkedCast(Src s) noexcept
{
return static_cast<Dest>(checkedCast<std::underlying_type_t<Dest>>(s));
}
template <typename Dest, typename Src>
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
constexpr Dest
checkedCast(Src s) noexcept
{
return checkedCast<Dest>(std::to_underlying(s));
}
/** @} */
/** Downcast within a class hierarchy, verified in debug builds.
Performs a static_cast down a hierarchy, but in debug builds verifies
via dynamic_cast that the object's dynamic type actually permits the
downcast. Both build modes execute the same conversion; debug builds
merely add the check.
The pointer form passes null through unchanged, as dynamic_cast does.
@note The check requires @p Src to be polymorphic; in release builds
an invalid downcast is undefined behavior on use, exactly as
with a bare static_cast.
*/
/** @{ */
template <class Dest, class Src> template <class Dest, class Src>
requires std::is_pointer_v<Dest> requires(
std::is_pointer_v<Dest> && std::is_polymorphic_v<Src> &&
std::derived_from<std::remove_pointer_t<Dest>, Src> &&
(std::is_const_v<std::remove_pointer_t<Dest>> || !std::is_const_v<Src>) &&
(std::is_volatile_v<std::remove_pointer_t<Dest>> || !std::is_volatile_v<Src>))
inline Dest inline Dest
safeDowncast(Src* s) noexcept safeDowncast(Src* s) noexcept
{ {
#ifdef NDEBUG XRPL_ASSERT(
s == nullptr || dynamic_cast<Dest>(s) != nullptr, "xrpl::safeDowncast : valid downcast");
return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
#else
auto* result = dynamic_cast<Dest>(s);
XRPL_ASSERT(result != nullptr, "xrpl::safeDowncast : pointer downcast is valid");
return result;
#endif
} }
template <class Dest, class Src> template <class Dest, class Src>
requires std::is_lvalue_reference_v<Dest> requires(
std::is_lvalue_reference_v<Dest> && std::is_polymorphic_v<Src> &&
std::derived_from<std::remove_reference_t<Dest>, Src>)
inline Dest inline Dest
safeDowncast(Src& s) noexcept safeDowncast(Src& s) noexcept
{ {
#ifndef NDEBUG return *safeDowncast<std::add_pointer_t<std::remove_reference_t<Dest>>>(std::addressof(s));
XRPL_ASSERT(
dynamic_cast<std::add_pointer_t<std::remove_reference_t<Dest>>>(&s) != nullptr,
"xrpl::safeDowncast : reference downcast is valid");
#endif
return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
} }
/** @} */
} // namespace xrpl } // namespace xrpl
-47
View File
@@ -1,47 +0,0 @@
#pragma once
#include <cstdlib>
#include <string>
#include <type_traits>
#include <typeinfo>
#ifndef _MSC_VER
#include <cxxabi.h>
#endif
namespace beast {
template <typename T>
std::string
typeName()
{
using TR = std::remove_reference_t<T>;
std::string name = typeid(TR).name();
#ifndef _MSC_VER
if (auto s = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, nullptr))
{
name = s;
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
std::free(s);
}
#endif
if (std::is_const_v<TR>)
name += " const";
if (std::is_volatile_v<TR>)
name += " volatile";
if (std::is_lvalue_reference_v<T>)
{
name += "&";
}
else if (std::is_rvalue_reference_v<T>)
{
name += "&&";
}
return name;
}
} // namespace beast
+36 -109
View File
@@ -2,26 +2,24 @@
#pragma once #pragma once
#include <compare>
#include <concepts>
namespace beast { namespace beast {
/** /**
* Zero allows classes to offer efficient comparisons to zero. * Zero allows classes to offer efficient comparisons to zero.
* *
* Zero is a struct to allow classes to efficiently compare with zero without
* requiring an rvalue construction.
*
* It's often the case that we have classes which combine a number and a unit. * It's often the case that we have classes which combine a number and a unit.
* In such cases, comparisons like t > 0 or t != 0 make sense, but comparisons * In such cases, comparisons like t > 0 or t != 0 make sense, but comparisons
* like t > 1 or t != 1 do not. * like t > 1 or t != 1 do not. Comparing against kZero expresses exactly that,
* without constructing a T.
* *
* The class Zero allows such comparisons to be easily made. * A type T participates if either `t.signum()` or an unqualified `signum(t)`
* * found by argument-dependent lookup returns an integer that is negative,
* The comparing class T either needs to have a method called signum() which * zero, or positive according to the sign of t. Both `t == kZero` and
* returns a positive number, 0, or a negative; or there needs to be a signum * `kZero == t` work, as do all six relational operators in either order.
* function which resolves in the namespace which takes an instance of T and
* returns a positive, zero or negative number.
*/ */
struct Zero struct Zero
{ {
explicit Zero() = default; explicit Zero() = default;
@@ -30,115 +28,44 @@ struct Zero
inline constexpr Zero kZero{}; inline constexpr Zero kZero{};
/** /**
* Default implementation of signum calls the method on the class. * Default implementation of signum: call the member function.
*/ */
template <typename T> template <class T>
auto requires requires(T const& t) {
signum(T const& t) { t.signum() } -> std::integral;
}
[[nodiscard]] constexpr auto
signum(T const& t) noexcept(noexcept(t.signum()))
{ {
return t.signum(); return t.signum();
} }
namespace detail::zero_helper { namespace detail {
// For argument dependent lookup to function properly, calls to signum must /**
// be made from a namespace that does not include overloads of the function.. * A type with a usable signum: either the member-based default above, or a
* `signum(t)` overload in T's own namespace, found by ADL. A user overload
* that is a better match than the template wins, as usual.
*/
template <class T> template <class T>
auto concept HasSignum = requires(T const& t) {
callSignum(T const& t) { signum(t) } -> std::integral;
};
} // namespace detail
template <detail::HasSignum T>
[[nodiscard]] constexpr bool
operator==(T const& t, Zero) noexcept(noexcept(signum(t)))
{ {
return signum(t); return signum(t) == 0;
} }
} // namespace detail::zero_helper template <detail::HasSignum T>
[[nodiscard]] constexpr std::strong_ordering
// Handle operators where T is on the left side using signum. operator<=>(T const& t, Zero) noexcept(noexcept(signum(t)))
template <typename T>
bool
operator==(T const& t, Zero)
{ {
return detail::zero_helper::callSignum(t) == 0; return signum(t) <=> 0;
}
template <typename T>
bool
operator!=(T const& t, Zero)
{
return detail::zero_helper::callSignum(t) != 0;
}
template <typename T>
bool
operator<(T const& t, Zero)
{
return detail::zero_helper::callSignum(t) < 0;
}
template <typename T>
bool
operator>(T const& t, Zero)
{
return detail::zero_helper::callSignum(t) > 0;
}
template <typename T>
bool
operator>=(T const& t, Zero)
{
return detail::zero_helper::callSignum(t) >= 0;
}
template <typename T>
bool
operator<=(T const& t, Zero)
{
return detail::zero_helper::callSignum(t) <= 0;
}
// Handle operators where T is on the right side by
// reversing the operation, so that T is on the left side.
template <typename T>
bool
operator==(Zero, T const& t)
{
return t == kZero;
}
template <typename T>
bool
operator!=(Zero, T const& t)
{
return t != kZero;
}
template <typename T>
bool
operator<(Zero, T const& t)
{
return t > kZero;
}
template <typename T>
bool
operator>(Zero, T const& t)
{
return t < kZero;
}
template <typename T>
bool
operator>=(Zero, T const& t)
{
return t <= kZero;
}
template <typename T>
bool
operator<=(Zero, T const& t)
{
return t >= kZero;
} }
} // namespace beast } // namespace beast
+12 -53
View File
@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <xrpl/basics/base_uint.h> #include <xrpl/basics/base_uint.h>
#include <xrpl/basics/safe_cast.h> #include <xrpl/basics/enum_bitops.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/OwnerCounts.h> #include <xrpl/ledger/OwnerCounts.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
@@ -22,80 +22,39 @@
namespace xrpl { namespace xrpl {
// Bitwise flag enum with existing operator overloads enum class ApplyFlags : std::uint32_t {
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class) None = 0x00,
enum ApplyFlags : std::uint32_t {
TapNone = 0x00,
// This is a local transaction with the // This is a local transaction with the
// fail_hard flag set. // fail_hard flag set.
TapFailHard = 0x10, FailHard = 0x10,
// This is not the transaction's last pass // This is not the transaction's last pass
// Transaction can be retried, soft failures allowed // Transaction can be retried, soft failures allowed
TapRetry = 0x20, Retry = 0x20,
// Transaction came from a privileged source // Transaction came from a privileged source
TapUnlimited = 0x400, Unlimited = 0x400,
// Transaction is executing as part of a batch // Transaction is executing as part of a batch
TapBatch = 0x800, Batch = 0x800,
// Transaction shouldn't be applied // Transaction shouldn't be applied
// Signatures shouldn't be checked // Signatures shouldn't be checked
TapDryRun = 0x1000, DryRun = 0x1000,
// Transaction is being preflighted as the payload of a // Transaction is being preflighted as the payload of a
// TransactionProposalCreate. Its signatures are collected on-ledger // TransactionProposalCreate. Its signatures are collected on-ledger
// afterward, so signature-presence checks (e.g. Batch signer matching) // afterward, so signature-presence checks (e.g. Batch signer matching)
// are skipped at proposal-creation time (On-Chain Cosigner spec // are skipped at proposal-creation time (On-Chain Cosigner spec
// §5.3.1.2). // §5.3.1.2).
TapProposal = 0x2000 Proposal = 0x2000
}; };
constexpr ApplyFlags template <>
operator|(ApplyFlags const& lhs, ApplyFlags const& rhs) struct enum_bitops::OptIn<ApplyFlags> : std::true_type
{ {
return safeCast<ApplyFlags>( };
safeCast<std::underlying_type_t<ApplyFlags>>(lhs) |
safeCast<std::underlying_type_t<ApplyFlags>>(rhs));
}
static_assert((TapFailHard | TapRetry) == safeCast<ApplyFlags>(0x30u), "ApplyFlags operator |");
static_assert((TapRetry | TapFailHard) == safeCast<ApplyFlags>(0x30u), "ApplyFlags operator |");
constexpr ApplyFlags
operator&(ApplyFlags const& lhs, ApplyFlags const& rhs)
{
return safeCast<ApplyFlags>(
safeCast<std::underlying_type_t<ApplyFlags>>(lhs) &
safeCast<std::underlying_type_t<ApplyFlags>>(rhs));
}
static_assert((TapFailHard & TapRetry) == TapNone, "ApplyFlags operator &");
static_assert((TapRetry & TapFailHard) == TapNone, "ApplyFlags operator &");
constexpr ApplyFlags
operator~(ApplyFlags const& flags)
{
return safeCast<ApplyFlags>(~safeCast<std::underlying_type_t<ApplyFlags>>(flags));
}
static_assert(~TapRetry == safeCast<ApplyFlags>(0xFFFFFFDFu), "ApplyFlags operator ~");
inline ApplyFlags
operator|=(ApplyFlags& lhs, ApplyFlags const& rhs)
{
lhs = lhs | rhs;
return lhs;
}
inline ApplyFlags
operator&=(ApplyFlags& lhs, ApplyFlags const& rhs)
{
lhs = lhs & rhs;
return lhs;
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -1,11 +1,17 @@
#pragma once #pragma once
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/SLEBase.h> #include <xrpl/ledger/entries/SLEBase.h>
#include <xrpl/protocol/Indexes.h> #include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h> #include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STVector256.h>
#include <cstddef>
#include <optional>
namespace xrpl { namespace xrpl {
@@ -25,6 +31,31 @@ public:
: Base(keylet::skip(), view, j) : Base(keylet::skip(), view, j)
{ {
} }
/**
* Looks up a hash `diff` slots back from the most recent entry in the
* sfHashes vector (diff == 0 is the most recent entry).
*
* Callers decide which skip list entry to read and how to translate a
* target ledger sequence into `diff`; this only does the bounds check
* and vector indexing shared by both the recent (stride 1) and distant
* (stride 256) skip lists.
*
* @param diff how many slots back from the most recent hash to look up;
* 0 is the most recent hash.
* @return the hash at that slot, or std::nullopt if the entry does not
* exist or `diff` is out of range.
*/
[[nodiscard]] std::optional<UInt256>
hashAt(std::size_t diff) const
{
if (!this->exists())
return std::nullopt;
STVector256 const vec = (*this)->getFieldV256(sfHashes);
if (vec.size() > diff)
return vec[vec.size() - diff - 1];
return std::nullopt;
}
}; };
using LedgerHashesEntryR = LedgerHashesEntry<ReadView>; using LedgerHashesEntryR = LedgerHashesEntry<ReadView>;
+2 -2
View File
@@ -1,10 +1,10 @@
#pragma once #pragma once
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#include <xrpl/beast/type_name.h>
#include <xrpl/protocol/SOTemplate.h> #include <xrpl/protocol/SOTemplate.h>
#include <boost/container/flat_map.hpp> #include <boost/container/flat_map.hpp>
#include <boost/core/type_name.hpp>
#include <algorithm> #include <algorithm>
#include <cstddef> #include <cstddef>
@@ -84,7 +84,7 @@ public:
* Derived classes will load the object with all the known formats. * Derived classes will load the object with all the known formats.
*/ */
private: private:
KnownFormats() : name_(beast::typeName<Derived>()) KnownFormats() : name_(boost::core::type_name<Derived>())
{ {
} }
+56 -51
View File
@@ -2,6 +2,7 @@
#include <xrpl/basics/CountedObject.h> #include <xrpl/basics/CountedObject.h>
#include <xrpl/basics/UnorderedContainers.h> #include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/enum_bitops.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/json/json_value.h> #include <xrpl/json/json_value.h>
#include <xrpl/protocol/AccountID.h> #include <xrpl/protocol/AccountID.h>
@@ -15,6 +16,7 @@
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <type_traits>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -22,18 +24,8 @@ namespace xrpl {
class STPathElement final : public CountedObject<STPathElement> class STPathElement final : public CountedObject<STPathElement>
{ {
unsigned int type_;
AccountID accountID_;
PathAsset assetID_;
AccountID issuerID_;
bool isOffer_;
std::size_t hashValue_;
public: public:
// Bitwise values (typeCurrency | typeMPT) enum class Type : std::uint8_t {
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
enum Type {
TypeNone = 0x00, TypeNone = 0x00,
TypeAccount = 0x01, // Rippling through an account (vs taking an offer). TypeAccount = 0x01, // Rippling through an account (vs taking an offer).
TypeCurrency = 0x10, // Currency follows. TypeCurrency = 0x10, // Currency follows.
@@ -45,6 +37,8 @@ public:
// Combination of all types. // Combination of all types.
}; };
using enum Type;
STPathElement(); STPathElement();
STPathElement(STPathElement const&) = default; STPathElement(STPathElement const&) = default;
STPathElement& STPathElement&
@@ -62,42 +56,42 @@ public:
bool forceAsset = false); bool forceAsset = false);
STPathElement( STPathElement(
unsigned int uType, Type type,
AccountID const& account, AccountID const& account,
PathAsset const& asset, PathAsset const& asset,
AccountID const& issuer); AccountID const& issuer);
[[nodiscard]] std::uint32_t [[nodiscard]] Type
getNodeType() const; getNodeType() const noexcept;
[[nodiscard]] bool [[nodiscard]] bool
isOffer() const; isOffer() const noexcept;
[[nodiscard]] bool [[nodiscard]] bool
isAccount() const; isAccount() const noexcept;
[[nodiscard]] bool [[nodiscard]] bool
hasIssuer() const; hasIssuer() const noexcept;
[[nodiscard]] bool [[nodiscard]] bool
hasCurrency() const; hasCurrency() const noexcept;
[[nodiscard]] bool [[nodiscard]] bool
hasMPT() const; hasMPT() const noexcept;
[[nodiscard]] bool [[nodiscard]] bool
hasAsset() const; hasAsset() const noexcept;
[[nodiscard]] bool [[nodiscard]] bool
isNone() const; isNone() const noexcept;
// Nodes are either an account ID or a offer prefix. Offer prefixs denote a // Nodes are either an account ID or a offer prefix. Offer prefixs denote a
// class of offers. // class of offers.
[[nodiscard]] AccountID const& [[nodiscard]] AccountID const&
getAccountID() const; getAccountID() const noexcept;
[[nodiscard]] PathAsset const& [[nodiscard]] PathAsset const&
getPathAsset() const; getPathAsset() const noexcept;
[[nodiscard]] Currency const& [[nodiscard]] Currency const&
getCurrency() const; getCurrency() const;
@@ -106,17 +100,35 @@ public:
getMPTID() const; getMPTID() const;
[[nodiscard]] AccountID const& [[nodiscard]] AccountID const&
getIssuerID() const; getIssuerID() const noexcept;
[[nodiscard]] bool [[nodiscard]] bool
isType(Type const& pe) const; isType(Type pe) const noexcept;
bool friend bool
operator==(STPathElement const& t) const; operator==(STPathElement const& lhs, STPathElement const& rhs) noexcept
{
return lhs.isType(TypeAccount) == rhs.isType(TypeAccount) &&
lhs.hashValue_ == rhs.hashValue_ && lhs.accountID_ == rhs.accountID_ &&
lhs.assetID_ == rhs.assetID_ && lhs.issuerID_ == rhs.issuerID_;
}
private: private:
static std::size_t static std::size_t
getHash(STPathElement const& element); getHash(STPathElement const& element);
Type type_;
AccountID accountID_;
PathAsset assetID_;
AccountID issuerID_;
bool isOffer_;
std::size_t hashValue_;
};
template <>
struct enum_bitops::OptIn<STPathElement::Type> : std::true_type
{
}; };
template <class Hasher> template <class Hasher>
@@ -124,7 +136,7 @@ void
hash_append(Hasher& h, STPathElement const& e) noexcept hash_append(Hasher& h, STPathElement const& e) noexcept
{ {
using beast::hash_append; using beast::hash_append;
hash_append(h, (e.getNodeType() & STPathElement::TypeAccount) != 0u); hash_append(h, e.isType(STPathElement::TypeAccount));
hash_append(h, e.getAccountID()); hash_append(h, e.getAccountID());
hash_append(h, e.getPathAsset()); hash_append(h, e.getPathAsset());
hash_append(h, e.getIssuerID()); hash_append(h, e.getIssuerID());
@@ -404,11 +416,11 @@ inline STPathElement::STPathElement(
} }
inline STPathElement::STPathElement( inline STPathElement::STPathElement(
unsigned int uType, Type type,
AccountID const& account, AccountID const& account,
PathAsset const& asset, PathAsset const& asset,
AccountID const& issuer) AccountID const& issuer)
: type_(uType) : type_(type)
, accountID_(account) , accountID_(account)
, assetID_(asset) , assetID_(asset)
, issuerID_(issuer) , issuerID_(issuer)
@@ -423,56 +435,56 @@ inline STPathElement::STPathElement(
hashValue_ = getHash(*this); hashValue_ = getHash(*this);
} }
inline std::uint32_t inline STPathElement::Type
STPathElement::getNodeType() const STPathElement::getNodeType() const noexcept
{ {
return type_; return type_;
} }
inline bool inline bool
STPathElement::isOffer() const STPathElement::isOffer() const noexcept
{ {
return isOffer_; return isOffer_;
} }
inline bool inline bool
STPathElement::isAccount() const STPathElement::isAccount() const noexcept
{ {
return !isOffer(); return !isOffer();
} }
inline bool inline bool
STPathElement::isType(Type const& pe) const STPathElement::isType(Type pe) const noexcept
{ {
return (type_ & pe) != 0u; return (type_ & pe) != STPathElement::TypeNone;
} }
inline bool inline bool
STPathElement::hasIssuer() const STPathElement::hasIssuer() const noexcept
{ {
return isType(STPathElement::TypeIssuer); return isType(STPathElement::TypeIssuer);
} }
inline bool inline bool
STPathElement::hasCurrency() const STPathElement::hasCurrency() const noexcept
{ {
return isType(STPathElement::TypeCurrency); return isType(STPathElement::TypeCurrency);
} }
inline bool inline bool
STPathElement::hasMPT() const STPathElement::hasMPT() const noexcept
{ {
return isType(STPathElement::TypeMpt); return isType(STPathElement::TypeMpt);
} }
inline bool inline bool
STPathElement::hasAsset() const STPathElement::hasAsset() const noexcept
{ {
return isType(STPathElement::TypeAsset); return isType(STPathElement::TypeAsset);
} }
inline bool inline bool
STPathElement::isNone() const STPathElement::isNone() const noexcept
{ {
return getNodeType() == STPathElement::TypeNone; return getNodeType() == STPathElement::TypeNone;
} }
@@ -480,13 +492,13 @@ STPathElement::isNone() const
// Nodes are either an account ID or a offer prefix. Offer prefixs denote a // Nodes are either an account ID or a offer prefix. Offer prefixs denote a
// class of offers. // class of offers.
inline AccountID const& inline AccountID const&
STPathElement::getAccountID() const STPathElement::getAccountID() const noexcept
{ {
return accountID_; return accountID_;
} }
inline PathAsset const& inline PathAsset const&
STPathElement::getPathAsset() const STPathElement::getPathAsset() const noexcept
{ {
return assetID_; return assetID_;
} }
@@ -504,18 +516,11 @@ STPathElement::getMPTID() const
} }
inline AccountID const& inline AccountID const&
STPathElement::getIssuerID() const STPathElement::getIssuerID() const noexcept
{ {
return issuerID_; return issuerID_;
} }
inline bool
STPathElement::operator==(STPathElement const& t) const
{
return (type_ & TypeAccount) == (t.type_ & TypeAccount) && hashValue_ == t.hashValue_ &&
accountID_ == t.accountID_ && assetID_ == t.assetID_ && issuerID_ == t.issuerID_;
}
// ------------ STPath ------------ // ------------ STPath ------------
inline STPath::STPath(std::vector<STPathElement> p) : path_(std::move(p)) inline STPath::STPath(std::vector<STPathElement> p) : path_(std::move(p))
+2 -1
View File
@@ -51,7 +51,8 @@ public:
beast::Journal journal = beast::Journal{beast::Journal::getNullSink()}) beast::Journal journal = beast::Journal{beast::Journal::getNullSink()})
: ApplyContext(registry, base, std::nullopt, tx, preclaimResult, baseFee, flags, journal) : ApplyContext(registry, base, std::nullopt, tx, preclaimResult, baseFee, flags, journal)
{ {
XRPL_ASSERT((flags & TapBatch) == 0, "Batch apply flag should not be set"); XRPL_ASSERT(
(flags & ApplyFlags::Batch) == ApplyFlags::None, "Batch apply flag should not be set");
} }
std::reference_wrapper<ServiceRegistry> registry; std::reference_wrapper<ServiceRegistry> registry;
+11 -8
View File
@@ -59,10 +59,11 @@ public:
, parentBatchId(parentBatchId) , parentBatchId(parentBatchId)
, j(j) , j(j)
{ {
XRPL_ASSERT((flags & TapBatch) == TapBatch, "Batch apply flag should be set"); XRPL_ASSERT(
(flags & ApplyFlags::Batch) == ApplyFlags::Batch, "Batch apply flag should be set");
XRPL_ASSERT_IF( XRPL_ASSERT_IF(
(flags & TapProposal) != TapNone, (flags & ApplyFlags::Proposal) != ApplyFlags::None,
(flags & TapDryRun) != TapNone, (flags & ApplyFlags::DryRun) != ApplyFlags::None,
"xrpl::PreflightContext : proposal preflight implies dry run"); "xrpl::PreflightContext : proposal preflight implies dry run");
} }
@@ -74,10 +75,11 @@ public:
beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: registry(registry), tx(tx), rules(std::move(rules)), flags(flags), j(j) : registry(registry), tx(tx), rules(std::move(rules)), flags(flags), j(j)
{ {
XRPL_ASSERT((flags & TapBatch) == 0, "Batch apply flag should not be set"); XRPL_ASSERT(
(flags & ApplyFlags::Batch) == ApplyFlags::None, "Batch apply flag should not be set");
XRPL_ASSERT_IF( XRPL_ASSERT_IF(
(flags & TapProposal) != TapNone, (flags & ApplyFlags::Proposal) != ApplyFlags::None,
(flags & TapDryRun) != TapNone, (flags & ApplyFlags::DryRun) != ApplyFlags::None,
"xrpl::PreflightContext : proposal preflight implies dry run"); "xrpl::PreflightContext : proposal preflight implies dry run");
} }
@@ -116,7 +118,7 @@ public:
, j(j) , j(j)
{ {
XRPL_ASSERT( XRPL_ASSERT(
parentBatchId.has_value() == ((flags & TapBatch) == TapBatch), parentBatchId.has_value() == ((flags & ApplyFlags::Batch) == ApplyFlags::Batch),
"Parent Batch ID should be set if batch apply flag is set"); "Parent Batch ID should be set if batch apply flag is set");
} }
@@ -129,7 +131,8 @@ public:
beast::Journal j = beast::Journal{beast::Journal::getNullSink()}) beast::Journal j = beast::Journal{beast::Journal::getNullSink()})
: PreclaimContext(registry, view, preflightResult, tx, flags, std::nullopt, j) : PreclaimContext(registry, view, preflightResult, tx, flags, std::nullopt, j)
{ {
XRPL_ASSERT((flags & TapBatch) == 0, "Batch apply flag should not be set"); XRPL_ASSERT(
(flags & ApplyFlags::Batch) == ApplyFlags::None, "Batch apply flag should not be set");
} }
PreclaimContext& PreclaimContext&
+1 -1
View File
@@ -41,7 +41,7 @@ struct ApplyResult
inline bool inline bool
isTecClaimHardFail(TER ter, ApplyFlags flags) isTecClaimHardFail(TER ter, ApplyFlags flags)
{ {
return isTecClaim(ter) && ((flags & TapRetry) == 0u); return isTecClaim(ter) && ((flags & ApplyFlags::Retry) == ApplyFlags::None);
} }
/** /**
+73 -73
View File
@@ -2,144 +2,144 @@ Detected OS: macos (Darwin arm64)
Core build tools: Core build tools:
✅ cmake ✅ cmake
cmake version 4.1.2 cmake version 4.4.3
/nix/store/gvabsb4yqb5xsqzqph54rijnn4zpihnp-cmake-4.1.2/bin/cmake /nix/store/q85csxf4s4shx89zif097h1ql4ax1rrz-cmake-4.4.3/bin/cmake
✅ conan ✅ conan
Conan version 2.28.1 Conan version 2.32.0
/nix/store/9jiyxmkpwmn6dcqs0765s83riw3l5ail-conan-2.28.1/bin/conan /nix/store/921jqsgbilixmr3xchj95si0jl8pi13z-conan-2.32.0/bin/conan
✅ git ✅ git
git version 2.54.0 git version 2.55.0
/nix/store/a14yxcqvv9x2l9mllgpirzhvz93pgprg-git-2.54.0/bin/git /nix/store/gw7c7m0dwca5lg4152x9lpmxpj171bzw-git-2.55.0/bin/git
✅ python3 ✅ python3
Python 3.13.13 Python 3.14.7
/nix/store/ygxqin6ydzjfawywqpp5pal8wv6sf5bh-python3-3.13.13/bin/python3.13 /nix/store/0kcws5blwbdyxqxjd1w8hjipz61xny3k-python3-3.14.7/bin/python3.14
Development tooling: Development tooling:
✅ ccache ✅ ccache
ccache version 4.13.6 ccache version 4.13.6
/nix/store/57davyvs6p6dkrl3svzwg1ph18wsy4cz-ccache-4.13.6/bin/ccache /nix/store/ydr5nlzxp1djb5256y0zzqa87vz55gsk-ccache-4.13.6/bin/ccache
✅ clang ✅ clang
clang version 22.1.7 clang version 22.1.8
/nix/store/192glrb2cldvziyf3378mzjqbzx3ih4g-clang-wrapper-22.1.7/bin/clang /nix/store/dakcxgwz4ixkk6ps50b7vn3dvblyzsnf-clang-wrapper-22.1.8/bin/clang
✅ clang-22 ✅ clang-22
clang version 22.1.7 clang version 22.1.8
/nix/store/rbap7zqq7mw00fyqa02p5rj7gqjp4w5i-clang-22/bin/clang-22 /nix/store/w826sqb98nnym6kzackg829664iqdlxj-clang-22/bin/clang-22
✅ clang++ ✅ clang++
clang version 22.1.7 clang version 22.1.8
/nix/store/192glrb2cldvziyf3378mzjqbzx3ih4g-clang-wrapper-22.1.7/bin/clang++ /nix/store/dakcxgwz4ixkk6ps50b7vn3dvblyzsnf-clang-wrapper-22.1.8/bin/clang++
✅ clang++-22 ✅ clang++-22
clang version 22.1.7 clang version 22.1.8
/nix/store/v9haf787f7bcz0mq1sad4bpyx21pj6li-clang++-22/bin/clang++-22 /nix/store/wnwyw3yfqrhpxij65bl3pa1x65q2zg3m-clang++-22/bin/clang++-22
✅ ClangBuildAnalyzer ✅ ClangBuildAnalyzer
ClangBuildAnalyzer 1.6.0 ClangBuildAnalyzer 1.6.0
/nix/store/4l50ds9fa2mkvh7wg8qzrlbmjs12sb8l-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer /nix/store/c7jjnw29ra78jdlzjww2m374izhy05n8-clangbuildanalyzer-1.6.0/bin/ClangBuildAnalyzer
✅ curl ✅ curl
curl 8.20.0 (aarch64-apple-darwin25.3.0) libcurl/8.20.0 OpenSSL/3.6.2 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.69.0 mit-krb5/1.22.1 curl 8.22.0 (aarch64-apple-darwin25.6.0) libcurl/8.22.0 OpenSSL/3.5.8 zlib/1.3.2 libssh2/1.11.1 nghttp2/1.70.0 mit-krb5/1.22.2
/nix/store/kclq0czaxvsgh4ym9ld7b6iwy50l1snk-curl-8.20.0-bin/bin/curl /nix/store/pq1h17abqy6q5y6k5dn9qj0fwb89flba-curl-8.22.0-bin/bin/curl
✅ file ✅ file
file-5.47 file-5.48
/nix/store/dax63li7wwcbqxxkkgzc4g2rx7d4w86x-file-5.47/bin/file /nix/store/y44vpziwbzfm8020dzlqqbybyyy7lb6g-file-5.48/bin/file
✅ less ✅ less
less 692 (PCRE2 regular expressions) less 710 (PCRE2 regular expressions)
/nix/store/lvr16y75r1pdxpdv0aph5ak2yd0hkvqm-less-692/bin/less /nix/store/3yn3dx5fwg5i0inqqzwnxq7f6lwhpjqa-less-710/bin/less
✅ make ✅ make
GNU Make 4.4.1 GNU Make 4.4.1
/nix/store/8wwiw8pwyhrkzyq28hqzxfl4z84lks81-gnumake-4.4.1/bin/make /nix/store/8l4wgxmhdxfvc9g18y76bnxl1ghgcp7n-gnumake-4.4.1/bin/make
✅ netstat ✅ netstat
present present
/nix/store/qsd1kzqb0ahrk433vmyl245gp623j19s-network_cmds-730.80.3/bin/netstat /nix/store/57fqvgdav8lrmzndkwm7qrgksl01yj23-network_cmds-741.100.2/bin/netstat
✅ ninja ✅ ninja
1.13.2 1.13.2
/nix/store/bqykhrblarkj4fl0hz2mf8ngwfv6x6bz-ninja-1.13.2/bin/ninja /nix/store/infm4vlx71q83bqz0k559w1gn4b0rq4i-ninja-1.13.2/bin/ninja
✅ perl ✅ perl
v5.42.0 v5.42.3
/nix/store/js13ri9fvm0ajk1fpd3acigys2a9whdv-perl-5.42.0/bin/perl /nix/store/7rvr6qjfzk2ybzn1imjw6c6qq1n1a9cr-perl-5.42.3/bin/perl
✅ pkg-config ✅ pkg-config
0.29.2 0.29.2
/nix/store/lzrwr375jqhhbca116kja96xf1md83l8-pkg-config-wrapper-0.29.2/bin/pkg-config /nix/store/nhgylvj98klqggy54h7gbc3b2ia4a00y-pkg-config-wrapper-0.29.2/bin/pkg-config
✅ vim ✅ vim
VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00) VIM - Vi IMproved 9.2 (2026 Feb 14, compiled Jan 01 1980 00:00:00)
/nix/store/6vbkykg92w603c0sw3mkk7p7mfaawbns-vim-9.2.0389/bin/vim /nix/store/akaa9kqm3b8rlkv61kvsqr2l2j70rvxb-vim-9.2.1001/bin/vim
✅ zip ✅ zip
Zip 3.0 Zip 3.0
/nix/store/z6ph729vcakbvz3wh8ln1wk6mi06w487-zip-3.0/bin/zip /nix/store/dvawr36npnad4xa6dxi2ss0fw44aa82r-zip-3.0/bin/zip
✅ clang-apply-replacements ✅ clang-apply-replacements
clang-apply-replacements version 22.1.7 clang-apply-replacements version 22.1.8
/nix/store/vzyyjf3cm1hbj9wcr2qcb66x6j98zpy7-clang-tools-22.1.7/bin/clang-apply-replacements /nix/store/5bij4zn161lagwyndmrr21vmxjg054nv-clang-tools-22.1.8/bin/clang-apply-replacements
✅ clang-apply-replacements-22 ✅ clang-apply-replacements-22
clang-apply-replacements version 22.1.7 clang-apply-replacements version 22.1.8
/nix/store/m3ii69rca4077lf4wlk7m3jcag1fs577-clang-apply-replacements-22/bin/clang-apply-replacements-22 /nix/store/w4bz034k4l0w719rrmbwnqcgyjbswy81-clang-apply-replacements-22/bin/clang-apply-replacements-22
✅ clang-format ✅ clang-format
clang-format version 22.1.7 clang-format version 22.1.8
/nix/store/vzyyjf3cm1hbj9wcr2qcb66x6j98zpy7-clang-tools-22.1.7/bin/clang-format /nix/store/5bij4zn161lagwyndmrr21vmxjg054nv-clang-tools-22.1.8/bin/clang-format
✅ clang-format-22 ✅ clang-format-22
clang-format version 22.1.7 clang-format version 22.1.8
/nix/store/4fawqy6ngqcsqd2ygyyzm93q0xy3f5gs-clang-format-22/bin/clang-format-22 /nix/store/w7z346l0r8y36b6lc5i7jzj3w0581l2y-clang-format-22/bin/clang-format-22
✅ clang-tidy ✅ clang-tidy
LLVM version 22.1.7 LLVM version 22.1.8
/nix/store/vzyyjf3cm1hbj9wcr2qcb66x6j98zpy7-clang-tools-22.1.7/bin/clang-tidy /nix/store/5bij4zn161lagwyndmrr21vmxjg054nv-clang-tools-22.1.8/bin/clang-tidy
✅ clang-tidy-22 ✅ clang-tidy-22
LLVM version 22.1.7 LLVM version 22.1.8
/nix/store/jqw4280saixaxxihwdba9ldm2fsm6dr3-clang-tidy-22/bin/clang-tidy-22 /nix/store/0lv25qd3ddgjm3ndn70q61jfr6krlkl7-clang-tidy-22/bin/clang-tidy-22
✅ dot ✅ dot
dot - graphviz version 12.2.1 (0) dot - graphviz version 15.1.1 (0)
/nix/store/ijb4fbnqa6wzlpqnhb6q9knqpf7qqn5z-graphviz-12.2.1/bin/dot /nix/store/mc99a6bpbk2waym2cnw6ifmxli4ndb4x-graphviz-15.1.1/bin/dot
✅ doxygen ✅ doxygen
1.16.1 1.17.0
/nix/store/kbryjdpq9jizjb0ws0nzbf2h2ymbdiwm-doxygen-1.16.1/bin/doxygen /nix/store/kz43yaj0wg6fx6cbrcmi2442z1ramy0c-doxygen-1.17.0/bin/doxygen
✅ gcovr ✅ gcovr
gcovr 8.4 gcovr 8.4
/nix/store/wn8jiyh9p0bybs96s4163qp3k8vfmczx-python3.13-gcovr-8.4/bin/gcovr /nix/store/czj1vxsizrbba280gg22cys40qxkqjgr-python3.14-gcovr-8.4/bin/gcovr
✅ gh ✅ gh
gh version 2.94.0 (nixpkgs) gh version 2.102.0 (2026-09-30)
/nix/store/fhnpw0hs0gjms1ha6ap02jq7rx13gkbp-gh-2.94.0/bin/gh /nix/store/s8bahl6zssvry93ihivfmk1l6c58byrr-gh-2.102.0/bin/gh
✅ git-cliff ✅ git-cliff
git-cliff 2.13.1 git-cliff 2.14.2
/nix/store/cy0wwhgxa7yvrz97zydbq6sqmixc90fq-git-cliff-2.13.1/bin/git-cliff /nix/store/k4m5yk0qb7hfslwsq1zjajz1d94j12bj-git-cliff-2.14.2/bin/git-cliff
✅ git-lfs ✅ git-lfs
git-lfs/3.7.1 (3.7.1; darwin arm64; go 1.26.3) git-lfs/3.8.0 (3.8.0; darwin arm64; go 1.26.8)
/nix/store/k9r7zjfjplqa4d5s71cqvf2iv73jd9mc-git-lfs-3.7.1/bin/git-lfs /nix/store/wzixjr3yb40a13m2q654hm3bdjn6sal3-git-lfs-3.8.0/bin/git-lfs
✅ gpg ✅ gpg
gpg (GnuPG) 2.4.9 gpg (GnuPG) 2.4.9
/nix/store/cgh6iwzz5jgx9z5whka4vgj210i6npc6-gnupg-2.4.9/bin/gpg /nix/store/0ldfwnwx385i5kh7cyvxx4mkvgjhs5rh-gnupg-2.4.9/bin/gpg
✅ pre-commit ✅ pre-commit
pre-commit 4.5.1 pre-commit 4.6.2
/nix/store/z3cca68620w0w10f090szgzdnmh1waf2-pre-commit-4.5.1/bin/pre-commit /nix/store/ivh54xypg9qvd3ha9lis0i8p4nkf8n7a-pre-commit-4.6.2/bin/pre-commit
✅ run-clang-tidy ✅ run-clang-tidy
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers] usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/4x28x911z2f9y7adqlh3qspp4a16dig7-run-clang-tidy/bin/run-clang-tidy /nix/store/3xss1mm3mh1hzcmg182na6ki1p5rnxf1-run-clang-tidy/bin/run-clang-tidy
✅ run-clang-tidy-22 ✅ run-clang-tidy-22
usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers] usage: run-clang-tidy [-h] [-allow-enabling-alpha-checkers]
/nix/store/x8iymrh76sk5q91ryg5pa7i32s6gfh34-run-clang-tidy-22/bin/run-clang-tidy-22 /nix/store/w68r9z07hcq4fwbfyq3yvc7qxm8aqfbl-run-clang-tidy-22/bin/run-clang-tidy-22
Rust toolchain: Rust toolchain:
✅ cargo ✅ cargo
cargo 1.97.1 (c980f4866 2026-06-30) cargo 1.97.1 (c980f4866 2026-06-30)
/nix/store/bnfk1sl4s9angb0vj1cj9a5y5zvqinwy-rust-minimal-1.97.1/bin/cargo /nix/store/gklji8yq8yrx1k039c10kwz60vqf2dxj-rust-minimal-1.97.1/bin/cargo
✅ cargo-audit ✅ cargo-audit
cargo-audit-audit 0.22.1 cargo-audit-audit 0.22.2
/nix/store/snwkga2f5gyf404h7mmp9wriwxb8v65f-cargo-audit-0.22.1/bin/cargo-audit /nix/store/7jgrwj557l91940aj0ag4i924ima1cqn-cargo-audit-0.22.2/bin/cargo-audit
✅ cargo-llvm-cov ✅ cargo-llvm-cov
cargo-llvm-cov 0.8.5 cargo-llvm-cov 0.9.0
/nix/store/fpiqdh91gwyxalqp409ynm0s0g086w7w-cargo-llvm-cov-0.8.5/bin/cargo-llvm-cov /nix/store/5q1h285z8zzkw2qxig9a0b1avcsk1cf0-cargo-llvm-cov-0.9.0/bin/cargo-llvm-cov
✅ cargo-nextest ✅ cargo-nextest
cargo-nextest 0.9.137 cargo-nextest 0.9.146
/nix/store/ylz7m947mhkgsp6i7611id3s3gcd58nq-cargo-nextest-0.9.137/bin/cargo-nextest /nix/store/69v3hx3k597hcxd2zy7yad7fg0aw5yxd-cargo-nextest-0.9.146/bin/cargo-nextest
✅ clippy-driver ✅ clippy-driver
clippy 0.1.97 (8bab26f4f6 2026-07-14) clippy 0.1.97 (8bab26f4f6 2026-07-14)
/nix/store/bnfk1sl4s9angb0vj1cj9a5y5zvqinwy-rust-minimal-1.97.1/bin/clippy-driver /nix/store/gklji8yq8yrx1k039c10kwz60vqf2dxj-rust-minimal-1.97.1/bin/clippy-driver
✅ rust-analyzer ✅ rust-analyzer
rust-analyzer 1.97.1 (8bab26f4 2026-07-14) rust-analyzer 1.97.1 (8bab26f4 2026-07-14)
/nix/store/j6apc5pmd0giy15da9p650r8zklslmvi-rust-analyzer-preview-1.97.1-aarch64-apple-darwin/bin/rust-analyzer /nix/store/30rbyk8gx7v53fxqhs4pp0fvxfjycspr-rust-analyzer-preview-1.97.1-aarch64-apple-darwin/bin/rust-analyzer
✅ rust-nightly ✅ rust-nightly
rustc 1.99.0-nightly (87e5904f5 2026-07-20) rustc 1.101.0-nightly (282215592 2026-10-04)
/nix/store/fqpjz4l0nsnji8b2pz57mnj0akbp6hcl-rust-nightly/bin/rust-nightly /nix/store/a9552rf3pylcnkijc1z0hf1lcnv50djq-rust-nightly/bin/rust-nightly
✅ rustc ✅ rustc
rustc 1.97.1 (8bab26f4f 2026-07-14) rustc 1.97.1 (8bab26f4f 2026-07-14)
/nix/store/bnfk1sl4s9angb0vj1cj9a5y5zvqinwy-rust-minimal-1.97.1/bin/rustc /nix/store/gklji8yq8yrx1k039c10kwz60vqf2dxj-rust-minimal-1.97.1/bin/rustc
✅ rustfmt ✅ rustfmt
rustfmt 1.9.0-stable (8bab26f4f6 2026-07-14) rustfmt 1.9.0-stable (8bab26f4f6 2026-07-14)
/nix/store/5ymwgr9jqjz7zzbmj0j5vqbwcd3kp0vm-rustfmt-preview-1.97.1-aarch64-apple-darwin/bin/rustfmt /nix/store/0jmdipyn8266j9kqx2xxm2qkxlrlrjfc-rustfmt-preview-1.97.1-aarch64-apple-darwin/bin/rustfmt
Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set). Skipping git-over-HTTPS check (CHECK_TOOLS_SKIP_CLONE is set).
+2 -1
View File
@@ -21,7 +21,8 @@ let
) )
); );
toolchain = if pkgs.stdenv.isLinux then linux.toolchain else (darwin.toolchain ++ [ darwinEnv ]); toolchain =
if pkgs.stdenv.hostPlatform.isLinux then linux.toolchain else (darwin.toolchain ++ [ darwinEnv ]);
in in
{ {
default = pkgs.buildEnv { default = pkgs.buildEnv {
+7 -6
View File
@@ -20,15 +20,16 @@ let
# Custom-glibc stdenvs, matching the CI environment. darwin has no custom # Custom-glibc stdenvs, matching the CI environment. darwin has no custom
# glibc, so there they fall back to the plain nixpkgs stdenvs. # glibc, so there they fall back to the plain nixpkgs stdenvs.
customGccStdenv = if pkgs.stdenv.isLinux then linux.gccStdenv else plainGccStdenv; customGccStdenv = if pkgs.stdenv.hostPlatform.isLinux then linux.gccStdenv else plainGccStdenv;
customClangStdenv = if pkgs.stdenv.isLinux then linux.clangStdenv else plainClangStdenv; customClangStdenv =
if pkgs.stdenv.hostPlatform.isLinux then linux.clangStdenv else plainClangStdenv;
# gcov matching each gcc shell, so `-Dcoverage=ON` builds work in the shell. # gcov matching each gcc shell, so `-Dcoverage=ON` builds work in the shell.
plainGcov = mkGcov { plainGcov = mkGcov {
name = "plain"; name = "plain";
cc = gccPackage.cc; cc = gccPackage.cc;
}; };
customGccGcov = if pkgs.stdenv.isLinux then linux.gcov else plainGcov; customGccGcov = if pkgs.stdenv.hostPlatform.isLinux then linux.gcov else plainGcov;
# Whole directory: init.sh locates the profiles relative to itself. # Whole directory: init.sh locates the profiles relative to itself.
conanDir = ../conan; conanDir = ../conan;
@@ -51,7 +52,7 @@ let
# Not sdkEnv: a shell's stdenv already sets that up. Prepended so the stub # Not sdkEnv: a shell's stdenv already sets that up. Prepended so the stub
# beats the nixpkgs libresolv this shell's tooling drags in. # beats the nixpkgs libresolv this shell's tooling drags in.
darwinLibresolvHook = pkgs.lib.optionalString pkgs.stdenv.isDarwin ( darwinLibresolvHook = pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isDarwin (
pkgs.lib.concatLines ( pkgs.lib.concatLines (
pkgs.lib.mapAttrsToList ( pkgs.lib.mapAttrsToList (
name: value: ''export ${name}="${value} ''${${name}:-}"'' name: value: ''export ${name}="${value} ''${${name}:-}"''
@@ -126,7 +127,7 @@ let
in in
rec { rec {
# macOS: Nix Clang. Linux: Nix GCC. # macOS: Nix Clang. Linux: Nix GCC.
default = if pkgs.stdenv.isDarwin then clang else gcc; default = if pkgs.stdenv.hostPlatform.isDarwin then clang else gcc;
# gcc/clang use the custom-glibc toolchain, matching CI. On darwin there is no # gcc/clang use the custom-glibc toolchain, matching CI. On darwin there is no
# custom glibc, so they fall back to the plain nixpkgs toolchain. # custom glibc, so they fall back to the plain nixpkgs toolchain.
@@ -171,7 +172,7 @@ rec {
# The *-plain shells (stock nixpkgs toolchain) exist only on Linux: on darwin # The *-plain shells (stock nixpkgs toolchain) exist only on Linux: on darwin
# gcc/clang are already plain, so these would be redundant and are omitted, which # gcc/clang are already plain, so these would be redundant and are omitted, which
# makes `nix develop .#gcc-plain` fail there rather than silently aliasing gcc. # makes `nix develop .#gcc-plain` fail there rather than silently aliasing gcc.
// pkgs.lib.optionalAttrs pkgs.stdenv.isLinux { // pkgs.lib.optionalAttrs pkgs.stdenv.hostPlatform.isLinux {
gcc-plain = makeShell { gcc-plain = makeShell {
shellName = "gcc-plain"; shellName = "gcc-plain";
stdenv = plainGccStdenv; stdenv = plainGccStdenv;
+2 -1
View File
@@ -11,6 +11,7 @@
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/LedgerTiming.h> #include <xrpl/ledger/LedgerTiming.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/FeeSettingsEntry.h>
#include <xrpl/nodestore/NodeObject.h> #include <xrpl/nodestore/NodeObject.h>
#include <xrpl/protocol/Feature.h> #include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Fees.h> #include <xrpl/protocol/Fees.h>
@@ -560,7 +561,7 @@ Ledger::setup()
try try
{ {
if (auto const sle = read(keylet::feeSettings())) if (auto const sle = FeeSettingsEntryR(*this))
{ {
bool oldFees = false; bool oldFees = false;
bool newFees = false; bool newFees = false;
+8 -10
View File
@@ -9,6 +9,7 @@
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/LedgerHashesEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h> #include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h> #include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h> #include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -361,17 +362,16 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal)
if (int const diff = ledger.seq() - seq; diff <= 256) if (int const diff = ledger.seq() - seq; diff <= 256)
{ {
// Within 256... // Within 256...
auto const hashIndex = ledger.read(keylet::skip()); LedgerHashesEntryR const hashIndex(ledger, journal);
if (hashIndex) if (hashIndex)
{ {
XRPL_ASSERT( XRPL_ASSERT(
hashIndex->getFieldU32(sfLastLedgerSequence) == (ledger.seq() - 1), hashIndex->getFieldU32(sfLastLedgerSequence) == (ledger.seq() - 1),
"xrpl::hashOfSeq : matching ledger sequence"); "xrpl::hashOfSeq : matching ledger sequence");
STVector256 vec = hashIndex->getFieldV256(sfHashes); if (auto const hash = hashIndex.hashAt(diff - 1))
if (vec.size() >= diff) return hash;
return vec[vec.size() - diff];
JLOG(journal.warn()) << "Ledger " << ledger.seq() << " missing hash for " << seq << " (" JLOG(journal.warn()) << "Ledger " << ledger.seq() << " missing hash for " << seq << " ("
<< vec.size() << "," << diff << ")"; << hashIndex->getFieldV256(sfHashes).size() << "," << diff << ")";
} }
else else
{ {
@@ -387,16 +387,14 @@ hashOfSeq(ReadView const& ledger, LedgerIndex seq, beast::Journal journal)
} }
// in skiplist // in skiplist
auto const hashIndex = ledger.read(keylet::skip(seq)); LedgerHashesEntryR const hashIndex(keylet::skip(seq), ledger, journal);
if (hashIndex) if (hashIndex)
{ {
auto const lastSeq = hashIndex->getFieldU32(sfLastLedgerSequence); auto const lastSeq = hashIndex->getFieldU32(sfLastLedgerSequence);
XRPL_ASSERT(lastSeq >= seq, "xrpl::hashOfSeq : minimum last ledger"); XRPL_ASSERT(lastSeq >= seq, "xrpl::hashOfSeq : minimum last ledger");
XRPL_ASSERT((lastSeq & 0xff) == 0, "xrpl::hashOfSeq : valid last ledger"); XRPL_ASSERT((lastSeq & 0xff) == 0, "xrpl::hashOfSeq : valid last ledger");
auto const diff = (lastSeq - seq) >> 8; if (auto const hash = hashIndex.hashAt((lastSeq - seq) >> 8))
STVector256 vec = hashIndex->getFieldV256(sfHashes); return hash;
if (vec.size() > diff)
return vec[vec.size() - diff - 1];
} }
JLOG(journal.warn()) << "Can't get seq " << seq << " from " << ledger.seq() << " error"; JLOG(journal.warn()) << "Can't get seq " << seq << " from " << ledger.seq() << " error";
return std::nullopt; return std::nullopt;
@@ -317,8 +317,8 @@ public:
} }
else else
{ {
status = static_cast<Status>( status = checkedCast<Status>(
static_cast<int>(Status::CustomCode) + unsafeCast<int>(getStatus.code())); safeCast<int>(Status::CustomCode) + safeCast<int>(getStatus.code()));
JLOG(journal.error()) << getStatus.ToString(); JLOG(journal.error()) << getStatus.ToString();
} }
+75 -47
View File
@@ -5,6 +5,7 @@
#include <xrpl/basics/UnorderedContainers.h> #include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/base_uint.h> #include <xrpl/basics/base_uint.h>
#include <xrpl/basics/contract.h> #include <xrpl/basics/contract.h>
#include <xrpl/basics/safe_cast.h>
#include <xrpl/beast/hash/uhash.h> #include <xrpl/beast/hash/uhash.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/json/json_value.h> #include <xrpl/json/json_value.h>
@@ -17,9 +18,13 @@
#include <xrpl/protocol/jss.h> #include <xrpl/protocol/jss.h>
#include <algorithm> #include <algorithm>
#include <concepts>
#include <cstddef> #include <cstddef>
#include <cstdint>
#include <memory> #include <memory>
#include <optional>
#include <stdexcept> #include <stdexcept>
#include <type_traits>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -36,10 +41,10 @@ STPathElement::getHash(STPathElement const& element)
// important. We don't even really need to fully hash the whole // important. We don't even really need to fully hash the whole
// base_uint here, as a few bytes would do for our use. // base_uint here, as a few bytes would do for our use.
// //
// The note above is only true because the result of this function reaches // The note above is only true because the result of this function is only
// nothing but STPathElement::operator==, where it is a fast-reject // used by the STPathElement equality operator as a fast-reject prefilter,
// prefilter ahead of the field comparisons that decide the answer. Do not // ahead of the field comparisons that then decide the answer. Do not use
// use it to key a container. // it to key a container.
for (auto const x : element.getAccountID()) for (auto const x : element.getAccountID())
hashAccount += (hashAccount * 257) ^ x; hashAccount += (hashAccount * 257) ^ x;
@@ -106,12 +111,38 @@ STPathSet::operator=(STPathSet const& other)
STPathSet::STPathSet(SerialIter& sit, SField const& name) : STBase(name) STPathSet::STPathSet(SerialIter& sit, SField const& name) : STBase(name)
{ {
std::vector<STPathElement> path; using enum STPathElement::Type;
for (;;)
{
int const iType = sit.get8();
if (iType == STPathElement::TypeNone || iType == STPathElement::TypeBoundary) auto parsePathElementType = [](std::underlying_type_t<STPathElement::Type> byte) noexcept
-> std::optional<STPathElement::Type> {
if (byte == std::to_underlying(TypeBoundary))
return TypeBoundary;
constexpr auto knownBits = static_cast<std::underlying_type_t<STPathElement::Type>>(
std::to_underlying(TypeAccount) | std::to_underlying(TypeCurrency) |
std::to_underlying(TypeIssuer) | std::to_underlying(TypeMpt));
if ((byte & ~knownBits) != 0)
return std::nullopt;
return static_cast<STPathElement::Type>(byte);
};
std::vector<STPathElement> path;
std::optional<STPathElement::Type> type;
do
{
type = parsePathElementType(sit.get8());
if (!type)
{
JLOG(debugLog().error()) << "Bad path element in pathset";
Throw<std::runtime_error>("bad path element");
}
if (type == TypeNone || type == TypeBoundary)
{ {
if (path.empty()) if (path.empty())
{ {
@@ -122,28 +153,11 @@ STPathSet::STPathSet(SerialIter& sit, SField const& name) : STBase(name)
// Move rather than converting the vector to an STPath by copy. // Move rather than converting the vector to an STPath by copy.
value_.emplace_back(std::move(path)); value_.emplace_back(std::move(path));
path.clear(); path.clear();
if (iType == STPathElement::TypeNone)
return;
}
else if ((iType & ~STPathElement::TypeAll) != 0)
{
JLOG(debugLog().error()) << "Bad path element " << iType << " in pathset";
Throw<std::runtime_error>("bad path element");
} }
else else
{ {
auto const hasAccount = (iType & STPathElement::TypeAccount) != 0u; bool const hasCurrency = ((*type & TypeCurrency) == TypeCurrency);
auto const hasCurrency = (iType & STPathElement::TypeCurrency) != 0u; bool const hasMPT = ((*type & TypeMpt) == TypeMpt);
auto const hasIssuer = (iType & STPathElement::TypeIssuer) != 0u;
auto const hasMPT = (iType & STPathElement::TypeMpt) != 0u;
AccountID account;
PathAsset asset;
AccountID issuer;
if (hasAccount)
account = sit.get160();
if (hasCurrency && hasMPT) if (hasCurrency && hasMPT)
{ {
@@ -151,18 +165,26 @@ STPathSet::STPathSet(SerialIter& sit, SField const& name) : STBase(name)
Throw<std::runtime_error>("bad path element: MPT and Currency"); Throw<std::runtime_error>("bad path element: MPT and Currency");
} }
AccountID account;
AccountID issuer;
if ((*type & TypeAccount) == TypeAccount)
account = sit.get160();
PathAsset asset;
if (hasCurrency) if (hasCurrency)
asset = Currency::fromRaw(sit.get160()); asset = Currency::fromRaw(sit.get160());
if (hasMPT) if (hasMPT)
asset = sit.get192(); asset = sit.get192();
if (hasIssuer) if ((*type & TypeIssuer) == TypeIssuer)
issuer = sit.get160(); issuer = sit.get160();
path.emplace_back(account, asset, issuer, hasCurrency || hasMPT); path.emplace_back(account, asset, issuer, hasCurrency || hasMPT);
} }
} } while (type != TypeNone);
} }
STBase* STBase*
@@ -216,24 +238,22 @@ STPath::getJson(JsonOptions) const
for (auto const& it : path_) for (auto const& it : path_)
{ {
json::Value elem(json::ValueType::Object); json::Value elem(json::ValueType::Object);
auto const iType = it.getNodeType();
elem[jss::type] = iType; elem[jss::type] = safeCast<std::uint32_t>(it.getNodeType());
if ((iType & STPathElement::TypeAccount) != 0u) if (it.isType(STPathElement::TypeAccount))
elem[jss::account] = to_string(it.getAccountID()); elem[jss::account] = to_string(it.getAccountID());
XRPL_ASSERT( XRPL_ASSERT(
((iType & STPathElement::TypeCurrency) == 0u) || !(it.hasCurrency() && it.hasMPT()),
((iType & STPathElement::TypeMpt) == 0u),
"xrpl::STPath::getJson : not type Currency and MPT"); "xrpl::STPath::getJson : not type Currency and MPT");
if ((iType & STPathElement::TypeCurrency) != 0u) if (it.hasCurrency())
elem[jss::currency] = to_string(it.getCurrency()); elem[jss::currency] = to_string(it.getCurrency());
if ((iType & STPathElement::TypeMpt) != 0u) if (it.hasMPT())
elem[jss::mpt_issuance_id] = to_string(it.getMPTID()); elem[jss::mpt_issuance_id] = to_string(it.getMPTID());
if ((iType & STPathElement::TypeIssuer) != 0u) if (it.hasIssuer())
elem[jss::issuer] = to_string(it.getIssuerID()); elem[jss::issuer] = to_string(it.getIssuerID());
ret.append(elem); ret.append(elem);
@@ -265,34 +285,42 @@ STPathSet::add(Serializer& s) const
XRPL_ASSERT(getFName().fieldType == STI_PATHSET, "xrpl::STPathSet::add : valid field type"); XRPL_ASSERT(getFName().fieldType == STI_PATHSET, "xrpl::STPathSet::add : valid field type");
bool first = true; bool first = true;
// Workaround, since `Serializer` does not accept strongly-typed enums
// yet. When support is added, the static_assert will trigger, and the
// lambda can be removed entirely.
auto const toByte = [](std::same_as<STPathElement::Type> auto t) noexcept {
static_assert(
!requires(Serializer& ser) { ser.add8(t); },
"Serializer::add8 now accepts STPathElement::Type directly; remove toByte.");
return std::to_underlying(t);
};
for (auto const& spPath : value_) for (auto const& spPath : value_)
{ {
if (!first) if (!first)
s.add8(STPathElement::TypeBoundary); s.add8(toByte(STPathElement::TypeBoundary));
for (auto const& speElement : spPath) for (auto const& speElement : spPath)
{ {
int const iType = speElement.getNodeType(); s.add8(toByte(speElement.getNodeType()));
s.add8(iType); if (speElement.isType(STPathElement::TypeAccount))
if ((iType & STPathElement::TypeAccount) != 0u)
s.addBitString(speElement.getAccountID()); s.addBitString(speElement.getAccountID());
if ((iType & STPathElement::TypeMpt) != 0u) if (speElement.hasMPT())
s.addBitString(speElement.getMPTID()); s.addBitString(speElement.getMPTID());
if ((iType & STPathElement::TypeCurrency) != 0u) if (speElement.hasCurrency())
s.addBitString(speElement.getCurrency()); s.addBitString(speElement.getCurrency());
if ((iType & STPathElement::TypeIssuer) != 0u) if (speElement.hasIssuer())
s.addBitString(speElement.getIssuerID()); s.addBitString(speElement.getIssuerID());
} }
first = false; first = false;
} }
s.add8(STPathElement::TypeNone); s.add8(toByte(STPathElement::TypeNone));
} }
} // namespace xrpl } // namespace xrpl
+4 -3
View File
@@ -38,7 +38,7 @@ ApplyContext::ApplyContext(
, parentBatchId_(parentBatchId) , parentBatchId_(parentBatchId)
{ {
XRPL_ASSERT( XRPL_ASSERT(
parentBatchId.has_value() == ((flags_ & TapBatch) == TapBatch), parentBatchId.has_value() == ((flags_ & ApplyFlags::Batch) == ApplyFlags::Batch),
"Parent Batch ID should be set if batch apply flag is set"); "Parent Batch ID should be set if batch apply flag is set");
view_.emplace(&base_, flags_); view_.emplace(&base_, flags_);
} }
@@ -53,13 +53,14 @@ std::optional<TxMeta>
ApplyContext::apply(TER ter) ApplyContext::apply(TER ter)
{ {
// NOLINTNEXTLINE(bugprone-unchecked-optional-access) view_ emplaced in constructor // NOLINTNEXTLINE(bugprone-unchecked-optional-access) view_ emplaced in constructor
return view_->apply(base_, tx, ter, parentBatchId_, (flags_ & TapDryRun) != 0u, journal); return view_->apply(
base_, tx, ter, parentBatchId_, (flags_ & ApplyFlags::DryRun) != ApplyFlags::None, journal);
} }
void void
ApplyContext::addOrderBook(Book const& book) ApplyContext::addOrderBook(Book const& book)
{ {
if ((flags_ & TapDryRun) == TapNone) if ((flags_ & ApplyFlags::DryRun) == ApplyFlags::None)
registry.get().getOrderBookDB().addOrderBook(book); registry.get().getOrderBookDB().addOrderBook(book);
} }
+9 -7
View File
@@ -134,7 +134,7 @@ preflightCheckSigningKey(STObject const& sigObject, beast::Journal j)
std::optional<NotTEC> std::optional<NotTEC>
preflightCheckSimulateKeys(ApplyFlags flags, STObject const& sigObject, beast::Journal j) preflightCheckSimulateKeys(ApplyFlags flags, STObject const& sigObject, beast::Journal j)
{ {
if ((flags & TapDryRun) != 0u) // simulation if ((flags & ApplyFlags::DryRun) != ApplyFlags::None) // simulation
{ {
std::optional<Slice> const signature = sigObject[~sfTxnSignature]; std::optional<Slice> const signature = sigObject[~sfTxnSignature];
if (signature && !signature->empty()) if (signature && !signature->empty())
@@ -510,7 +510,8 @@ Transactor::minimumFee(
Fees const& fees, Fees const& fees,
ApplyFlags flags) ApplyFlags flags)
{ {
return scaleFeeLoad(baseFee, registry.getFeeTrack(), fees, (flags & TapUnlimited) != 0u); return scaleFeeLoad(
baseFee, registry.getFeeTrack(), fees, (flags & ApplyFlags::Unlimited) != ApplyFlags::None);
} }
TER TER
@@ -521,7 +522,7 @@ Transactor::checkFee(PreclaimContext const& ctx, XRPAmount baseFee)
auto const feePaid = ctx.tx[sfFee].xrp(); auto const feePaid = ctx.tx[sfFee].xrp();
if ((ctx.flags & TapBatch) != 0u) if ((ctx.flags & ApplyFlags::Batch) != ApplyFlags::None)
{ {
if (feePaid == beast::kZero) if (feePaid == beast::kZero)
return tesSUCCESS; return tesSUCCESS;
@@ -951,7 +952,8 @@ Transactor::checkSign(
return tesSUCCESS; return tesSUCCESS;
} }
if (((flags & TapDryRun) != 0u) && pkSigner.empty() && !sigObject.isFieldPresent(sfSigners)) if (((flags & ApplyFlags::DryRun) != ApplyFlags::None) && pkSigner.empty() &&
!sigObject.isFieldPresent(sfSigners))
{ {
// simulate: skip signature validation when neither SigningPubKey nor // simulate: skip signature validation when neither SigningPubKey nor
// Signers are provided // Signers are provided
@@ -1122,7 +1124,7 @@ Transactor::checkMultiSign(
} }
XRPL_ASSERT( XRPL_ASSERT(
(flags & TapDryRun) || !spk.empty(), (flags & ApplyFlags::DryRun) != ApplyFlags::None || !spk.empty(),
"xrpl::Transactor::checkMultiSign : non-empty signer or " "xrpl::Transactor::checkMultiSign : non-empty signer or "
"simulation"); "simulation");
AccountID const signingAcctIDFromPubKey = AccountID const signingAcctIDFromPubKey =
@@ -1604,7 +1606,7 @@ Transactor::operator()()
if (ctx_.size() > kOversizeMetaDataCap) if (ctx_.size() > kOversizeMetaDataCap)
result = tecOVERSIZE; result = tecOVERSIZE;
if (isTecClaim(result) && ((view().flags() & TapFailHard) != 0u)) if (isTecClaim(result) && ((view().flags() & ApplyFlags::FailHard) != ApplyFlags::None))
{ {
// If the TapFailHard flag is set, a tec result // If the TapFailHard flag is set, a tec result
// must not do anything // must not do anything
@@ -1684,7 +1686,7 @@ Transactor::operator()()
// Once we call apply, we will no longer be able to look at view() // Once we call apply, we will no longer be able to look at view()
metadata = ctx_.apply(result); metadata = ctx_.apply(result);
if ((ctx_.flags() & TapDryRun) != 0u) if ((ctx_.flags() & ApplyFlags::DryRun) != ApplyFlags::None)
return logger(result, false, std::move(metadata)); return logger(result, false, std::move(metadata));
return logger(result, canApply, std::move(metadata)); return logger(result, canApply, std::move(metadata));
+2 -2
View File
@@ -215,7 +215,7 @@ applyBatchTransactions(
auto applyOneTransaction = [&registry, &j, &parentBatchId, &batchView](STTx const& tx) { auto applyOneTransaction = [&registry, &j, &parentBatchId, &batchView](STTx const& tx) {
OpenView perTxBatchView(kBatchView, batchView); OpenView perTxBatchView(kBatchView, batchView);
auto const ret = apply(registry, perTxBatchView, parentBatchId, tx, TapBatch, j); auto const ret = apply(registry, perTxBatchView, parentBatchId, tx, ApplyFlags::Batch, j);
XRPL_ASSERT( XRPL_ASSERT(
ret.applied == (isTesSuccess(ret.ter) || isTecClaim(ret.ter)), ret.applied == (isTesSuccess(ret.ter) || isTecClaim(ret.ter)),
"Inner transaction should not be applied"); "Inner transaction should not be applied");
@@ -274,7 +274,7 @@ applyTransaction(
{ {
// Returns false if the transaction has need not be retried. // Returns false if the transaction has need not be retried.
if (retryAssured) if (retryAssured)
flags = flags | TapRetry; flags = flags | ApplyFlags::Retry;
JLOG(j.debug()) << "TXN " << txn.getTransactionID() << (retryAssured ? "/retry" : "/final"); JLOG(j.debug()) << "TXN " << txn.getTransactionID() << (retryAssured ? "/retry" : "/final");
+4 -2
View File
@@ -346,7 +346,8 @@ preflight(
// builds; re-check the same invariant here so a release build can't // builds; re-check the same invariant here so a release build can't
// silently skip a proposed transaction's signature-presence checks // silently skip a proposed transaction's signature-presence checks
// outside of a dry run. // outside of a dry run.
if ((flags & TapProposal) != TapNone && (flags & TapDryRun) == TapNone) if ((flags & ApplyFlags::Proposal) != ApplyFlags::None &&
(flags & ApplyFlags::DryRun) == ApplyFlags::None)
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
JLOG(j.fatal()) << "apply (preflight): TapProposal set without TapDryRun."; JLOG(j.fatal()) << "apply (preflight): TapProposal set without TapDryRun.";
@@ -377,7 +378,8 @@ preflight(
PreflightContext const pfCtx(registry, tx, parentBatchId, rules, flags, j); PreflightContext const pfCtx(registry, tx, parentBatchId, rules, flags, j);
// See the comment in the other preflight() overload above. // See the comment in the other preflight() overload above.
if ((flags & TapProposal) != TapNone && (flags & TapDryRun) == TapNone) if ((flags & ApplyFlags::Proposal) != ApplyFlags::None &&
(flags & ApplyFlags::DryRun) == ApplyFlags::None)
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
JLOG(j.fatal()) << "apply (preflight): TapProposal set without TapDryRun."; JLOG(j.fatal()) << "apply (preflight): TapProposal set without TapDryRun.";
+1 -1
View File
@@ -985,7 +985,7 @@ std::optional<std::variant<Quality, AMMOffer<TIn, TOut>>>
BookStep<TIn, TOut, TDerived>::tip(ReadView const& view) const BookStep<TIn, TOut, TDerived>::tip(ReadView const& view) const
{ {
// This can be simplified (and sped up) if directories are never empty. // This can be simplified (and sped up) if directories are never empty.
Sandbox sb(&view, TapNone); Sandbox sb(&view, ApplyFlags::None);
BookTip bt(sb, book_); BookTip bt(sb, book_);
auto const lobQuality = bt.step(j_) ? std::optional<Quality>(bt.quality()) : std::nullopt; auto const lobQuality = bt.step(j_) ? std::optional<Quality>(bt.quality()) : std::nullopt;
// Multi-path offer generates an offer with the quality // Multi-path offer generates an offer with the quality
+13 -27
View File
@@ -57,10 +57,8 @@ checkNear(IOUAmount const& expected, IOUAmount const& actual)
static bool static bool
isXRPAccount(STPathElement const& pe) isXRPAccount(STPathElement const& pe)
{ {
if (pe.getNodeType() != STPathElement::TypeAccount) return pe.getNodeType() == STPathElement::TypeAccount && isXRP(pe.getAccountID());
return false; }
return isXRP(pe.getAccountID());
};
static std::pair<TER, std::unique_ptr<Step>> static std::pair<TER, std::unique_ptr<Step>>
toStep( toStep(
@@ -71,11 +69,8 @@ toStep(
{ {
auto& j = ctx.j; auto& j = ctx.j;
if (ctx.isFirst && e1->isAccount() && if (ctx.isFirst && e1->isAccount() && e1->hasCurrency() && e1->getPathAsset().isXRP())
((e1->getNodeType() & STPathElement::TypeCurrency) != 0u) && e1->getPathAsset().isXRP())
{
return makeXrpEndpointStep(ctx, e1->getAccountID()); return makeXrpEndpointStep(ctx, e1->getAccountID());
}
if (ctx.isLast && isXRPAccount(*e1) && e2->isAccount()) if (ctx.isLast && isXRPAccount(*e1) && e2->isAccount())
return makeXrpEndpointStep(ctx, e2->getAccountID()); return makeXrpEndpointStep(ctx, e2->getAccountID());
@@ -117,15 +112,9 @@ toStep(
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
XRPL_ASSERT( XRPL_ASSERT(e2->hasAsset() || e2->hasIssuer(), "xrpl::toStep : currency or issuer");
(e2->getNodeType() & STPathElement::TypeAsset) || PathAsset const outAsset = e2->hasAsset() ? e2->getPathAsset() : curAsset;
(e2->getNodeType() & STPathElement::TypeIssuer), auto const outIssuer = e2->hasIssuer() ? e2->getIssuerID() : curAsset.getIssuer();
"xrpl::toStep : currency or issuer");
PathAsset const outAsset =
((e2->getNodeType() & STPathElement::TypeAsset) != 0u) ? e2->getPathAsset() : curAsset;
auto const outIssuer = ((e2->getNodeType() & STPathElement::TypeIssuer) != 0u)
? e2->getIssuerID()
: curAsset.getIssuer();
if (isXRP(curAsset) && outAsset.isXRP()) if (isXRP(curAsset) && outAsset.isXRP())
{ {
@@ -197,16 +186,15 @@ toStrand(
for (std::size_t i = 0; i < path.size(); ++i) for (std::size_t i = 0; i < path.size(); ++i)
{ {
auto const& pe = path[i]; auto const& pe = path[i];
auto const t = pe.getNodeType();
if (((t & ~STPathElement::TypeAll) != 0u) || (t == 0u)) if ((pe.getNodeType() & ~STPathElement::TypeAll) != STPathElement::TypeNone || pe.isNone())
return {temBAD_PATH, Strand{}}; return {temBAD_PATH, Strand{}};
bool const hasAccount = (t & STPathElement::TypeAccount) != 0u; bool const hasAccount = pe.isType(STPathElement::TypeAccount);
bool const hasIssuer = (t & STPathElement::TypeIssuer) != 0u; bool const hasIssuer = pe.hasIssuer();
bool const hasCurrency = (t & STPathElement::TypeCurrency) != 0u; bool const hasCurrency = pe.hasCurrency();
bool const hasMPT = (t & STPathElement::TypeMpt) != 0u; bool const hasMPT = pe.hasMPT();
bool const hasAsset = (t & STPathElement::TypeAsset) != 0u; bool const hasAsset = pe.hasAsset();
if (hasAccount && (hasIssuer || hasCurrency)) if (hasAccount && (hasIssuer || hasCurrency))
return {temBAD_PATH, Strand{}}; return {temBAD_PATH, Strand{}};
@@ -250,9 +238,7 @@ toStrand(
}(); }();
// Currency or MPT // Currency or MPT
auto hasAsset = [](STPathElement const pe) { auto hasAsset = [](STPathElement const& pe) { return pe.hasAsset(); };
return pe.getNodeType() & STPathElement::TypeAsset;
};
std::vector<STPathElement> normPath; std::vector<STPathElement> normPath;
// reserve enough for the path, the implied source, destination, // reserve enough for the path, the implied source, destination,
@@ -187,7 +187,8 @@ AccountSet::preclaim(PreclaimContext const& ctx)
if (!dirIsEmpty(ctx.view, keylet::ownerDir(id))) if (!dirIsEmpty(ctx.view, keylet::ownerDir(id)))
{ {
JLOG(ctx.j.trace()) << "Retry: Owner directory not empty."; JLOG(ctx.j.trace()) << "Retry: Owner directory not empty.";
return ((ctx.flags & TapRetry) != 0u) ? TER{terOWNERS} : TER{tecOWNERS}; return ((ctx.flags & ApplyFlags::Retry) != ApplyFlags::None) ? TER{terOWNERS}
: TER{tecOWNERS};
} }
} }
@@ -295,7 +295,8 @@ OfferCreate::checkAcceptAsset(
JLOG(j.debug()) << "delay: can't receive IOUs from non-existent issuer: " JLOG(j.debug()) << "delay: can't receive IOUs from non-existent issuer: "
<< to_string(asset.getIssuer()); << to_string(asset.getIssuer());
return ((flags & TapRetry) != 0u) ? TER{terNO_ACCOUNT} : TER{tecNO_ISSUER}; return ((flags & ApplyFlags::Retry) != ApplyFlags::None) ? TER{terNO_ACCOUNT}
: TER{tecNO_ISSUER};
} }
// An account cannot create a trustline to itself, so no line can exist // An account cannot create a trustline to itself, so no line can exist
@@ -318,7 +319,8 @@ OfferCreate::checkAcceptAsset(
{ {
JLOG(j.debug()) << "delay: can't receive IOUs from issuer with " JLOG(j.debug()) << "delay: can't receive IOUs from issuer with "
"DisallowIncomingTrustline set"; "DisallowIncomingTrustline set";
return ((flags & TapRetry) != 0u) ? TER{terNO_LINE} : TER{tecNO_LINE}; return ((flags & ApplyFlags::Retry) != ApplyFlags::None) ? TER{terNO_LINE}
: TER{tecNO_LINE};
} }
} }
@@ -326,7 +328,8 @@ OfferCreate::checkAcceptAsset(
{ {
if (!trustLine) if (!trustLine)
{ {
return ((flags & TapRetry) != 0u) ? TER{terNO_LINE} : TER{tecNO_LINE}; return ((flags & ApplyFlags::Retry) != ApplyFlags::None) ? TER{terNO_LINE}
: TER{tecNO_LINE};
} }
// Entries have a canonical representation, determined by a // Entries have a canonical representation, determined by a
@@ -342,7 +345,8 @@ OfferCreate::checkAcceptAsset(
JLOG(j.debug()) << "delay: can't receive IOUs from " JLOG(j.debug()) << "delay: can't receive IOUs from "
"issuer without auth."; "issuer without auth.";
return ((flags & TapRetry) != 0u) ? TER{terNO_AUTH} : TER{tecNO_AUTH}; return ((flags & ApplyFlags::Retry) != ApplyFlags::None) ? TER{terNO_AUTH}
: TER{tecNO_AUTH};
} }
} }
@@ -3,6 +3,7 @@
#include <xrpl/basics/Log.h> #include <xrpl/basics/Log.h>
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h> #include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/EscrowEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h> #include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/EscrowHelpers.h> #include <xrpl/ledger/helpers/EscrowHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h> #include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -94,13 +95,12 @@ EscrowCancel::preclaim(PreclaimContext const& ctx)
if (ctx.view.rules().enabled(featureTokenEscrow)) if (ctx.view.rules().enabled(featureTokenEscrow))
{ {
auto const seqProxy = SeqProxy::rawSequence(ctx.tx[sfOfferSequence]); auto const seqProxy = SeqProxy::rawSequence(ctx.tx[sfOfferSequence]);
auto const k = keylet::escrow(ctx.tx[sfOwner], seqProxy); EscrowEntryR const escrow(ctx.tx[sfOwner], seqProxy, ctx.view);
auto const slep = ctx.view.read(k); if (!escrow)
if (!slep)
return tecNO_TARGET; return tecNO_TARGET;
AccountID const account = (*slep)[sfAccount]; AccountID const account = (*escrow)[sfAccount];
STAmount const amount = (*slep)[sfAmount]; STAmount const amount = (*escrow)[sfAmount];
if (!isXRP(amount)) if (!isXRP(amount))
{ {
@@ -120,9 +120,8 @@ TER
EscrowCancel::doApply() EscrowCancel::doApply()
{ {
auto const seqProxy = SeqProxy::rawSequence(ctx_.tx[sfOfferSequence]); auto const seqProxy = SeqProxy::rawSequence(ctx_.tx[sfOfferSequence]);
auto const k = keylet::escrow(ctx_.tx[sfOwner], seqProxy); EscrowEntryW escrow(ctx_.tx[sfOwner], seqProxy, ctx_.view(), j_);
auto const slep = ctx_.view().peek(k); if (!escrow)
if (!slep)
{ {
if (ctx_.view().rules().enabled(featureTokenEscrow)) if (ctx_.view().rules().enabled(featureTokenEscrow))
return tecINTERNAL; // LCOV_EXCL_LINE return tecINTERNAL; // LCOV_EXCL_LINE
@@ -133,19 +132,19 @@ EscrowCancel::doApply()
auto const now = ctx_.view().header().parentCloseTime; auto const now = ctx_.view().header().parentCloseTime;
// No cancel time specified: can't execute at all. // No cancel time specified: can't execute at all.
if (!(*slep)[~sfCancelAfter]) if (!(*escrow)[~sfCancelAfter])
return tecNO_PERMISSION; return tecNO_PERMISSION;
// Too soon: can't execute before the cancel time. // Too soon: can't execute before the cancel time.
if (!after(now, (*slep)[sfCancelAfter])) if (!after(now, (*escrow)[sfCancelAfter]))
return tecNO_PERMISSION; return tecNO_PERMISSION;
AccountID const account = (*slep)[sfAccount]; AccountID const account = (*escrow)[sfAccount];
// Remove escrow from owner directory // Remove escrow from owner directory
{ {
auto const page = (*slep)[sfOwnerNode]; auto const page = (*escrow)[sfOwnerNode];
if (!ctx_.view().dirRemove(keylet::ownerDir(account), page, k.key, true)) if (!ctx_.view().dirRemove(keylet::ownerDir(account), page, escrow.key(), true))
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete Escrow from owner."; JLOG(j_.fatal()) << "Unable to delete Escrow from owner.";
@@ -155,9 +154,10 @@ EscrowCancel::doApply()
} }
// Remove escrow from recipient's owner directory, if present. // Remove escrow from recipient's owner directory, if present.
if (auto const optPage = (*slep)[~sfDestinationNode]; optPage) if (auto const optPage = (*escrow)[~sfDestinationNode]; optPage)
{ {
if (!ctx_.view().dirRemove(keylet::ownerDir((*slep)[sfDestination]), *optPage, k.key, true)) if (!ctx_.view().dirRemove(
keylet::ownerDir((*escrow)[sfDestination]), *optPage, escrow.key(), true))
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete Escrow from recipient."; JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
@@ -167,13 +167,13 @@ EscrowCancel::doApply()
} }
auto const sle = ctx_.view().peek(keylet::account(account)); auto const sle = ctx_.view().peek(keylet::account(account));
STAmount const amount = slep->getFieldAmount(sfAmount); STAmount const amount = escrow->getFieldAmount(sfAmount);
// The return can re-create a holding the owner deleted while the escrow // The return can re-create a holding the owner deleted while the escrow
// was pending; the removed escrow must not be counted against its reserve. // was pending; the removed escrow must not be counted against its reserve.
bool const recycleReserve = ctx_.view().rules().enabled(fixCleanup3_4_0); bool const recycleReserve = ctx_.view().rules().enabled(fixCleanup3_4_0);
if (recycleReserve) if (recycleReserve)
decreaseOwnerCountForObject(ctx_.view(), sle, slep, 1, ctx_.journal); decreaseOwnerCountForObject(ctx_.view(), sle, escrow.mutableRawSle(), 1, ctx_.journal);
// Transfer amount back to the owner // Transfer amount back to the owner
if (isXRP(amount)) if (isXRP(amount))
@@ -192,7 +192,7 @@ EscrowCancel::doApply()
return escrowUnlockApplyHelper<T>( return escrowUnlockApplyHelper<T>(
ctx_.getApplyViewContext(), ctx_.getApplyViewContext(),
kParityRate, kParityRate,
ctx_.view().rules().enabled(fixCleanup3_2_0) ? sle : slep, ctx_.view().rules().enabled(fixCleanup3_2_0) ? sle : escrow.mutableRawSle(),
preFeeBalance_, preFeeBalance_,
amount, amount,
issuer, issuer,
@@ -206,9 +206,9 @@ EscrowCancel::doApply()
return ret; // LCOV_EXCL_LINE return ret; // LCOV_EXCL_LINE
// Remove escrow from issuers owner directory, if present. // Remove escrow from issuers owner directory, if present.
if (auto const optPage = (*slep)[~sfIssuerNode]; optPage) if (auto const optPage = (*escrow)[~sfIssuerNode]; optPage)
{ {
if (!ctx_.view().dirRemove(keylet::ownerDir(issuer), *optPage, k.key, true)) if (!ctx_.view().dirRemove(keylet::ownerDir(issuer), *optPage, escrow.key(), true))
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete Escrow from recipient."; JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
@@ -219,10 +219,10 @@ EscrowCancel::doApply()
} }
if (!recycleReserve) if (!recycleReserve)
decreaseOwnerCountForObject(ctx_.view(), sle, slep, 1, ctx_.journal); decreaseOwnerCountForObject(ctx_.view(), sle, escrow.mutableRawSle(), 1, ctx_.journal);
// Remove escrow from ledger // Remove escrow from ledger
ctx_.view().erase(slep); escrow.erase();
return tesSUCCESS; return tesSUCCESS;
} }
@@ -7,6 +7,7 @@
#include <xrpl/core/ServiceRegistry.h> #include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h> #include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/EscrowEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h> #include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h> #include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h> #include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -481,30 +482,31 @@ EscrowCreate::doApply()
// Create escrow in ledger. Note that we use the value from the // Create escrow in ledger. Note that we use the value from the
// sequence or ticket. For more explanation see comments in SeqProxy.h. // sequence or ticket. For more explanation see comments in SeqProxy.h.
Keylet const escrowKeylet = keylet::escrow(accountID_, ctx_.tx.getSeqProxy()); EscrowEntryW escrow(accountID_, ctx_.tx.getSeqProxy(), ctx_.view(), j_);
auto const slep = std::make_shared<SLE>(escrowKeylet); Keylet const escrowKeylet = escrow.keylet();
(*slep)[sfAmount] = amount; escrow.newSLE();
(*slep)[sfAccount] = accountID_; (*escrow)[sfAmount] = amount;
(*slep)[~sfCondition] = ctx_.tx[~sfCondition]; (*escrow)[sfAccount] = accountID_;
(*slep)[~sfSourceTag] = ctx_.tx[~sfSourceTag]; (*escrow)[~sfCondition] = ctx_.tx[~sfCondition];
(*slep)[sfDestination] = ctx_.tx[sfDestination]; (*escrow)[~sfSourceTag] = ctx_.tx[~sfSourceTag];
(*slep)[~sfCancelAfter] = ctx_.tx[~sfCancelAfter]; (*escrow)[sfDestination] = ctx_.tx[sfDestination];
(*slep)[~sfFinishAfter] = ctx_.tx[~sfFinishAfter]; (*escrow)[~sfCancelAfter] = ctx_.tx[~sfCancelAfter];
(*slep)[~sfDestinationTag] = ctx_.tx[~sfDestinationTag]; (*escrow)[~sfFinishAfter] = ctx_.tx[~sfFinishAfter];
(*escrow)[~sfDestinationTag] = ctx_.tx[~sfDestinationTag];
if (ctx_.view().rules().enabled(fixIncludeKeyletFields)) if (ctx_.view().rules().enabled(fixIncludeKeyletFields))
{ {
(*slep)[sfSequence] = ctx_.tx.getSeqProxy().value(); (*escrow)[sfSequence] = ctx_.tx.getSeqProxy().value();
} }
if (ctx_.view().rules().enabled(featureTokenEscrow) && !isXRP(amount)) if (ctx_.view().rules().enabled(featureTokenEscrow) && !isXRP(amount))
{ {
auto const xferRate = transferRate(ctx_.view(), amount); auto const xferRate = transferRate(ctx_.view(), amount);
if (xferRate != kParityRate) if (xferRate != kParityRate)
(*slep)[sfTransferRate] = xferRate.value; (*escrow)[sfTransferRate] = xferRate.value;
} }
ctx_.view().insert(slep); escrow.insert();
// Add escrow to sender's owner directory // Add escrow to sender's owner directory
{ {
@@ -512,7 +514,7 @@ EscrowCreate::doApply()
keylet::ownerDir(accountID_), escrowKeylet, describeOwnerDir(accountID_)); keylet::ownerDir(accountID_), escrowKeylet, describeOwnerDir(accountID_));
if (!page) if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE return tecDIR_FULL; // LCOV_EXCL_LINE
(*slep)[sfOwnerNode] = *page; (*escrow)[sfOwnerNode] = *page;
} }
// If it's not a self-send, add escrow to recipient's owner directory. // If it's not a self-send, add escrow to recipient's owner directory.
@@ -523,7 +525,7 @@ EscrowCreate::doApply()
ctx_.view().dirInsert(keylet::ownerDir(dest), escrowKeylet, describeOwnerDir(dest)); ctx_.view().dirInsert(keylet::ownerDir(dest), escrowKeylet, describeOwnerDir(dest));
if (!page) if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE return tecDIR_FULL; // LCOV_EXCL_LINE
(*slep)[sfDestinationNode] = *page; (*escrow)[sfDestinationNode] = *page;
} }
// IOU escrow objects are added to the issuer's owner directory to help // IOU escrow objects are added to the issuer's owner directory to help
@@ -536,7 +538,7 @@ EscrowCreate::doApply()
ctx_.view().dirInsert(keylet::ownerDir(issuer), escrowKeylet, describeOwnerDir(issuer)); ctx_.view().dirInsert(keylet::ownerDir(issuer), escrowKeylet, describeOwnerDir(issuer));
if (!page) if (!page)
return tecDIR_FULL; // LCOV_EXCL_LINE return tecDIR_FULL; // LCOV_EXCL_LINE
(*slep)[sfIssuerNode] = *page; (*escrow)[sfIssuerNode] = *page;
} }
// Deduct owner's balance // Deduct owner's balance
@@ -559,7 +561,7 @@ EscrowCreate::doApply()
// increment owner count // increment owner count
increaseOwnerCount(ctx_.getApplyViewContext(), sle, 1, ctx_.journal); increaseOwnerCount(ctx_.getApplyViewContext(), sle, 1, ctx_.journal);
addSponsorToLedgerEntry(ctx_.getApplyViewContext(), slep); addSponsorToLedgerEntry(ctx_.getApplyViewContext(), escrow.mutableRawSle());
ctx_.view().update(sle); ctx_.view().update(sle);
return tesSUCCESS; return tesSUCCESS;
} }
@@ -9,6 +9,7 @@
#include <xrpl/ledger/ApplyView.h> #include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h> #include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h> #include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/EscrowEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h> #include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h> #include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/EscrowHelpers.h> #include <xrpl/ledger/helpers/EscrowHelpers.h>
@@ -211,13 +212,12 @@ EscrowFinish::preclaim(PreclaimContext const& ctx)
if (ctx.view.rules().enabled(featureTokenEscrow)) if (ctx.view.rules().enabled(featureTokenEscrow))
{ {
auto const seqProxy = SeqProxy::rawSequence(ctx.tx[sfOfferSequence]); auto const seqProxy = SeqProxy::rawSequence(ctx.tx[sfOfferSequence]);
auto const k = keylet::escrow(ctx.tx[sfOwner], seqProxy); EscrowEntryR const escrow(ctx.tx[sfOwner], seqProxy, ctx.view);
auto const slep = ctx.view.read(k); if (!escrow)
if (!slep)
return tecNO_TARGET; return tecNO_TARGET;
AccountID const dest = (*slep)[sfDestination]; AccountID const dest = (*escrow)[sfDestination];
STAmount const amount = (*slep)[sfAmount]; STAmount const amount = (*escrow)[sfAmount];
if (!isXRP(amount)) if (!isXRP(amount))
{ {
@@ -237,9 +237,8 @@ TER
EscrowFinish::doApply() EscrowFinish::doApply()
{ {
auto const seqProxy = SeqProxy::rawSequence(ctx_.tx[sfOfferSequence]); auto const seqProxy = SeqProxy::rawSequence(ctx_.tx[sfOfferSequence]);
auto const k = keylet::escrow(ctx_.tx[sfOwner], seqProxy); EscrowEntryW escrow(ctx_.tx[sfOwner], seqProxy, ctx_.view(), j_);
auto const slep = ctx_.view().peek(k); if (!escrow)
if (!slep)
{ {
if (ctx_.view().rules().enabled(featureTokenEscrow)) if (ctx_.view().rules().enabled(featureTokenEscrow))
return tecINTERNAL; // LCOV_EXCL_LINE return tecINTERNAL; // LCOV_EXCL_LINE
@@ -252,11 +251,11 @@ EscrowFinish::doApply()
auto const now = ctx_.view().header().parentCloseTime; auto const now = ctx_.view().header().parentCloseTime;
// Too soon: can't execute before the finish time // Too soon: can't execute before the finish time
if ((*slep)[~sfFinishAfter] && !after(now, (*slep)[sfFinishAfter])) if ((*escrow)[~sfFinishAfter] && !after(now, (*escrow)[sfFinishAfter]))
return tecNO_PERMISSION; return tecNO_PERMISSION;
// Too late: can't execute after the cancel time // Too late: can't execute after the cancel time
if ((*slep)[~sfCancelAfter] && after(now, (*slep)[sfCancelAfter])) if ((*escrow)[~sfCancelAfter] && after(now, (*escrow)[sfCancelAfter]))
return tecNO_PERMISSION; return tecNO_PERMISSION;
// Check cryptocondition fulfillment // Check cryptocondition fulfillment
@@ -296,7 +295,7 @@ EscrowFinish::doApply()
return tecCRYPTOCONDITION_ERROR; return tecCRYPTOCONDITION_ERROR;
// Check against condition in the ledger entry: // Check against condition in the ledger entry:
auto const cond = (*slep)[~sfCondition]; auto const cond = (*escrow)[~sfCondition];
// If a condition wasn't specified during creation, // If a condition wasn't specified during creation,
// one shouldn't be included now. // one shouldn't be included now.
@@ -313,7 +312,7 @@ EscrowFinish::doApply()
} }
// NOTE: Escrow payments cannot be used to fund accounts. // NOTE: Escrow payments cannot be used to fund accounts.
AccountID const destID = (*slep)[sfDestination]; AccountID const destID = (*escrow)[sfDestination];
auto const sled = ctx_.view().peek(keylet::account(destID)); auto const sled = ctx_.view().peek(keylet::account(destID));
if (!sled) if (!sled)
return tecNO_DST; return tecNO_DST;
@@ -323,12 +322,12 @@ EscrowFinish::doApply()
!isTesSuccess(err)) !isTesSuccess(err))
return err; return err;
AccountID const account = (*slep)[sfAccount]; AccountID const account = (*escrow)[sfAccount];
// Remove escrow from owner directory // Remove escrow from owner directory
{ {
auto const page = (*slep)[sfOwnerNode]; auto const page = (*escrow)[sfOwnerNode];
if (!ctx_.view().dirRemove(keylet::ownerDir(account), page, k.key, true)) if (!ctx_.view().dirRemove(keylet::ownerDir(account), page, escrow.key(), true))
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete Escrow from owner."; JLOG(j_.fatal()) << "Unable to delete Escrow from owner.";
@@ -338,9 +337,9 @@ EscrowFinish::doApply()
} }
// Remove escrow from recipient's owner directory, if present. // Remove escrow from recipient's owner directory, if present.
if (auto const optPage = (*slep)[~sfDestinationNode]) if (auto const optPage = (*escrow)[~sfDestinationNode])
{ {
if (!ctx_.view().dirRemove(keylet::ownerDir(destID), *optPage, k.key, true)) if (!ctx_.view().dirRemove(keylet::ownerDir(destID), *optPage, escrow.key(), true))
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete Escrow from recipient."; JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
@@ -355,9 +354,9 @@ EscrowFinish::doApply()
bool const recycleReserve = bool const recycleReserve =
ctx_.view().rules().enabled(featureSponsor) || ctx_.view().rules().enabled(fixCleanup3_4_0); ctx_.view().rules().enabled(featureSponsor) || ctx_.view().rules().enabled(fixCleanup3_4_0);
if (recycleReserve) if (recycleReserve)
decreaseOwnerCountForObject(ctx_.view(), account, slep, 1, ctx_.journal); decreaseOwnerCountForObject(ctx_.view(), account, escrow.mutableRawSle(), 1, ctx_.journal);
STAmount const amount = slep->getFieldAmount(sfAmount); STAmount const amount = escrow->getFieldAmount(sfAmount);
// Transfer amount to destination // Transfer amount to destination
if (isXRP(amount)) if (isXRP(amount))
{ {
@@ -368,8 +367,8 @@ EscrowFinish::doApply()
if (!ctx_.view().rules().enabled(featureTokenEscrow)) if (!ctx_.view().rules().enabled(featureTokenEscrow))
return temDISABLED; // LCOV_EXCL_LINE return temDISABLED; // LCOV_EXCL_LINE
Rate lockedRate = slep->isFieldPresent(sfTransferRate) Rate lockedRate = escrow->isFieldPresent(sfTransferRate)
? xrpl::Rate(slep->getFieldU32(sfTransferRate)) ? xrpl::Rate(escrow->getFieldU32(sfTransferRate))
: kParityRate; : kParityRate;
auto const issuer = amount.getIssuer(); auto const issuer = amount.getIssuer();
bool const createAsset = destID == accountID_; bool const createAsset = destID == accountID_;
@@ -392,9 +391,9 @@ EscrowFinish::doApply()
return ret; return ret;
// Remove escrow from issuers owner directory, if present. // Remove escrow from issuers owner directory, if present.
if (auto const optPage = (*slep)[~sfIssuerNode]; optPage) if (auto const optPage = (*escrow)[~sfIssuerNode]; optPage)
{ {
if (!ctx_.view().dirRemove(keylet::ownerDir(issuer), *optPage, k.key, true)) if (!ctx_.view().dirRemove(keylet::ownerDir(issuer), *optPage, escrow.key(), true))
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
JLOG(j_.fatal()) << "Unable to delete Escrow from recipient."; JLOG(j_.fatal()) << "Unable to delete Escrow from recipient.";
@@ -407,10 +406,10 @@ EscrowFinish::doApply()
ctx_.view().update(sled); ctx_.view().update(sled);
if (!recycleReserve) if (!recycleReserve)
decreaseOwnerCountForObject(ctx_.view(), account, slep, 1, ctx_.journal); decreaseOwnerCountForObject(ctx_.view(), account, escrow.mutableRawSle(), 1, ctx_.journal);
// Remove escrow from ledger // Remove escrow from ledger
ctx_.view().erase(slep); escrow.erase();
return tesSUCCESS; return tesSUCCESS;
} }
@@ -91,7 +91,8 @@ LoanSet::preflight(PreflightContext const& ctx)
// A proposed LoanSet is stored unsigned; its CounterpartySignature is // A proposed LoanSet is stored unsigned; its CounterpartySignature is
// collected on-ledger afterward, so its absence here is expected, not an // collected on-ledger afterward, so its absence here is expected, not an
// error (On-Chain Cosigner spec §5.3.1.2). // error (On-Chain Cosigner spec §5.3.1.2).
if (!tx.isFlag(tfInnerBatchTxn) && !counterPartySig && (ctx.flags & TapProposal) == 0) if (!tx.isFlag(tfInnerBatchTxn) && !counterPartySig &&
(ctx.flags & ApplyFlags::Proposal) == ApplyFlags::None)
{ {
JLOG(ctx.j.warn()) << "LoanSet transaction must have a CounterpartySignature."; JLOG(ctx.j.warn()) << "LoanSet transaction must have a CounterpartySignature.";
return temBAD_SIGNER; return temBAD_SIGNER;
@@ -54,8 +54,8 @@ TransactionProposalCreate::preflight(PreflightContext const& ctx)
try try
{ {
STTx const stx{STObject{proposedTx}}; STTx const stx{STObject{proposedTx}};
auto const inner = auto const inner = xrpl::preflight(
xrpl::preflight(ctx.registry, ctx.rules, stx, TapDryRun | TapProposal, ctx.j); ctx.registry, ctx.rules, stx, ApplyFlags::DryRun | ApplyFlags::Proposal, ctx.j);
if (!isTesSuccess(inner.ter)) if (!isTesSuccess(inner.ter))
{ {
JLOG(ctx.j.debug()) << "TransactionProposalCreate: proposed txn " JLOG(ctx.j.debug()) << "TransactionProposalCreate: proposed txn "
@@ -205,7 +205,7 @@ SponsorshipTransfer::preflight(PreflightContext const& ctx)
// is collected on-ledger afterward, so its absence here is expected, not // is collected on-ledger afterward, so its absence here is expected, not
// an error (On-Chain Cosigner spec §5.3.1.2). // an error (On-Chain Cosigner spec §5.3.1.2).
if (isAccountReserveSponsorship && !ctx.tx.isFieldPresent(sfSponsorSignature) && if (isAccountReserveSponsorship && !ctx.tx.isFieldPresent(sfSponsorSignature) &&
(ctx.flags & TapProposal) == 0) (ctx.flags & ApplyFlags::Proposal) == ApplyFlags::None)
{ {
JLOG(ctx.j.debug()) << "preflight: account sponsorship requires sfSponsorSignature"; JLOG(ctx.j.debug()) << "preflight: account sponsorship requires sfSponsorSignature";
return temMALFORMED; return temMALFORMED;
+3 -2
View File
@@ -359,7 +359,8 @@ Batch::preflight(PreflightContext const& ctx)
// TapBatch — PreflightContext with a parentBatchId requires it. // TapBatch — PreflightContext with a parentBatchId requires it.
// LoanSet already short-circuits on tfInnerBatchTxn; it is also in // LoanSet already short-circuits on tfInnerBatchTxn; it is also in
// kDisabledTxTypes, so it never reaches this call. // kDisabledTxTypes, so it never reaches this call.
ApplyFlags const innerFlags = TapBatch | (ctx.flags & (TapProposal | TapDryRun)); ApplyFlags const innerFlags =
ApplyFlags::Batch | (ctx.flags & (ApplyFlags::Proposal | ApplyFlags::DryRun));
if (auto const preflightResult = if (auto const preflightResult =
xrpl::preflight(ctx.registry, ctx.rules, parentBatchId, stx, innerFlags, ctx.j); xrpl::preflight(ctx.registry, ctx.rules, parentBatchId, stx, innerFlags, ctx.j);
!isTesSuccess(preflightResult.ter)) !isTesSuccess(preflightResult.ter))
@@ -431,7 +432,7 @@ Batch::preflightSigValidated(PreflightContext const& ctx)
// A proposed Batch is stored unsigned; its BatchSigners are collected // A proposed Batch is stored unsigned; its BatchSigners are collected
// on-ledger afterward, so the signer-presence match belongs to submission // on-ledger afterward, so the signer-presence match belongs to submission
// time, not proposal creation (On-Chain Cosigner spec §5.3.1.2). // time, not proposal creation (On-Chain Cosigner spec §5.3.1.2).
if ((ctx.flags & TapProposal) != 0) if ((ctx.flags & ApplyFlags::Proposal) != ApplyFlags::None)
return tesSUCCESS; return tesSUCCESS;
auto const parentBatchId = ctx.tx.getTransactionID(); auto const parentBatchId = ctx.tx.getTransactionID();
+6 -7
View File
@@ -8,6 +8,7 @@
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h> #include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/AmendmentTable.h> #include <xrpl/ledger/AmendmentTable.h>
#include <xrpl/ledger/entries/FeeSettingsEntry.h>
#include <xrpl/protocol/Feature.h> #include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h> #include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Protocol.h> #include <xrpl/protocol/Protocol.h>
@@ -260,16 +261,14 @@ Change::applyAmendment()
TER TER
Change::applyFee() Change::applyFee()
{ {
auto const k = keylet::feeSettings(); FeeSettingsEntryW feeObject(view());
SLE::pointer feeObject = view().peek(k);
if (!feeObject) if (!feeObject)
{ {
feeObject = std::make_shared<SLE>(k); feeObject.newSLE();
view().insert(feeObject); feeObject.insert();
} }
auto set = [](SLE::pointer& feeObject, STTx const& tx, auto const& field) { auto set = [](FeeSettingsEntryW& feeObject, STTx const& tx, auto const& field) {
feeObject->at(field) = tx[field]; feeObject->at(field) = tx[field];
}; };
if (view().rules().enabled(featureXRPFees)) if (view().rules().enabled(featureXRPFees))
@@ -291,7 +290,7 @@ Change::applyFee()
set(feeObject, ctx_.tx, sfReserveIncrement); set(feeObject, ctx_.tx, sfReserveIncrement);
} }
view().update(feeObject); feeObject.update();
JLOG(j_.warn()) << "Fees have been changed"; JLOG(j_.warn()) << "Fees have been changed";
return tesSUCCESS; return tesSUCCESS;
+2 -2
View File
@@ -1890,7 +1890,7 @@ private:
auto const flowResult = [&] { auto const flowResult = [&] {
STAmount const deliver(eth(51'000'000)); STAmount const deliver(eth(51'000'000));
STAmount smax(btc(61'000'000)); STAmount smax(btc(61'000'000));
PaymentSandbox sb(env.current().get(), TapNone); PaymentSandbox sb(env.current().get(), ApplyFlags::None);
STPathSet paths; STPathSet paths;
auto ipe = [](MPTTester const& iss) { auto ipe = [](MPTTester const& iss) {
return STPathElement( return STPathElement(
@@ -1928,7 +1928,7 @@ private:
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
if (flowResult.removableOffers.empty()) if (flowResult.removableOffers.empty())
return false; return false;
Sandbox sb(&view, TapNone); Sandbox sb(&view, ApplyFlags::None);
for (auto const& o : flowResult.removableOffers) for (auto const& o : flowResult.removableOffers)
{ {
if (auto ok = sb.peek(keylet::offer(o))) if (auto ok = sb.peek(keylet::offer(o)))
+2 -2
View File
@@ -2049,7 +2049,7 @@ private:
auto const flowResult = [&] { auto const flowResult = [&] {
STAmount const deliver(USD(51)); STAmount const deliver(USD(51));
STAmount smax(BTC(61)); STAmount smax(BTC(61));
PaymentSandbox sb(env.current().get(), TapNone); PaymentSandbox sb(env.current().get(), ApplyFlags::None);
STPathSet paths; STPathSet paths;
auto ipe = [](Issue const& iss) { auto ipe = [](Issue const& iss) {
return STPathElement( return STPathElement(
@@ -2087,7 +2087,7 @@ private:
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
if (flowResult.removableOffers.empty()) if (flowResult.removableOffers.empty())
return false; return false;
Sandbox sb(&view, TapNone); Sandbox sb(&view, ApplyFlags::None);
for (auto const& o : flowResult.removableOffers) for (auto const& o : flowResult.removableOffers)
{ {
if (auto ok = sb.peek(keylet::offer(o))) if (auto ok = sb.peek(keylet::offer(o)))
+2 -2
View File
@@ -4158,7 +4158,7 @@ private:
auto jtx = env.jt(tx, Seq(1), Fee(10)); auto jtx = env.jt(tx, Seq(1), Fee(10));
env.app().config().features.erase(featureMPTokensV2); env.app().config().features.erase(featureMPTokensV2);
PreflightContext const ctx( PreflightContext const ctx(
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal); env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
auto pf = AMMBid::checkExtraFeatures(ctx); auto pf = AMMBid::checkExtraFeatures(ctx);
BEAST_EXPECT(pf == false); BEAST_EXPECT(pf == false);
env.app().config().features.insert(featureMPTokensV2); env.app().config().features.insert(featureMPTokensV2);
@@ -4170,7 +4170,7 @@ private:
jtx.jv["Asset2"].removeMember("mpt_issuance_id"); jtx.jv["Asset2"].removeMember("mpt_issuance_id");
jtx.stx = env.ust(jtx); jtx.stx = env.ust(jtx);
PreflightContext const ctx( PreflightContext const ctx(
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal); env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
auto pf = AMMBid::preflight(ctx); auto pf = AMMBid::preflight(ctx);
BEAST_EXPECT(pf == temBAD_AMM_TOKENS); BEAST_EXPECT(pf == temBAD_AMM_TOKENS);
} }
+3 -3
View File
@@ -3263,7 +3263,7 @@ private:
auto jtx = env.jt(tx, Seq(1), Fee(baseFee)); auto jtx = env.jt(tx, Seq(1), Fee(baseFee));
env.app().config().features.erase(featureAMM); env.app().config().features.erase(featureAMM);
PreflightContext const pfCtx( PreflightContext const pfCtx(
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal); env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
auto pf = Transactor::invokePreflight<AMMBid>(pfCtx); auto pf = Transactor::invokePreflight<AMMBid>(pfCtx);
BEAST_EXPECT(pf == temDISABLED); BEAST_EXPECT(pf == temDISABLED);
env.app().config().features.insert(featureAMM); env.app().config().features.insert(featureAMM);
@@ -3274,7 +3274,7 @@ private:
jtx.jv["TxnSignature"] = "deadbeef"; jtx.jv["TxnSignature"] = "deadbeef";
jtx.stx = env.ust(jtx); jtx.stx = env.ust(jtx);
PreflightContext const pfCtx( PreflightContext const pfCtx(
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal); env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
auto pf = Transactor::invokePreflight<AMMBid>(pfCtx); auto pf = Transactor::invokePreflight<AMMBid>(pfCtx);
BEAST_EXPECT(!isTesSuccess(pf)); BEAST_EXPECT(!isTesSuccess(pf));
} }
@@ -3285,7 +3285,7 @@ private:
jtx.jv["Asset2"].removeMember("issuer"); jtx.jv["Asset2"].removeMember("issuer");
jtx.stx = env.ust(jtx); jtx.stx = env.ust(jtx);
PreflightContext const pfCtx( PreflightContext const pfCtx(
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal); env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
auto pf = Transactor::invokePreflight<AMMBid>(pfCtx); auto pf = Transactor::invokePreflight<AMMBid>(pfCtx);
BEAST_EXPECT(pf == temBAD_AMM_TOKENS); BEAST_EXPECT(pf == temBAD_AMM_TOKENS);
} }
+1 -1
View File
@@ -594,7 +594,7 @@ public:
stx->at(sfSigningPubKey) = makeSlice(std::string("badkey")); stx->at(sfSigningPubKey) = makeSlice(std::string("badkey"));
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result = xrpl::apply(env.app(), view, *stx, TapNone, j); auto const result = xrpl::apply(env.app(), view, *stx, ApplyFlags::None, j);
BEAST_EXPECT(result.ter == temBAD_SIGNATURE); BEAST_EXPECT(result.ter == temBAD_SIGNATURE);
BEAST_EXPECT(!result.applied); BEAST_EXPECT(!result.applied);
return result.applied; return result.applied;
+11 -6
View File
@@ -436,7 +436,7 @@ class Batch_test : public beast::unit_test::Suite
{ {
auto jtx = env.jt(pay(alice, bob, XRP(1)), Txflags(tfInnerBatchTxn)); auto jtx = env.jt(pay(alice, bob, XRP(1)), Txflags(tfInnerBatchTxn));
PreflightContext const pfCtx( PreflightContext const pfCtx(
env.app(), *jtx.stx, env.current()->rules(), TapNone, env.journal); env.app(), *jtx.stx, env.current()->rules(), ApplyFlags::None, env.journal);
auto const pf = Transactor::invokePreflight<Payment>(pfCtx); auto const pf = Transactor::invokePreflight<Payment>(pfCtx);
BEAST_EXPECT(pf == temINVALID_INNER_BATCH); BEAST_EXPECT(pf == temINVALID_INNER_BATCH);
} }
@@ -451,7 +451,7 @@ class Batch_test : public beast::unit_test::Suite
disabledEnv.app(), disabledEnv.app(),
*jtx.stx, *jtx.stx,
disabledEnv.current()->rules(), disabledEnv.current()->rules(),
TapNone, ApplyFlags::None,
disabledEnv.journal); disabledEnv.journal);
auto const pf = Transactor::invokePreflight<Payment>(pfCtx); auto const pf = Transactor::invokePreflight<Payment>(pfCtx);
BEAST_EXPECT(pf == temINVALID_FLAG); BEAST_EXPECT(pf == temINVALID_FLAG);
@@ -462,7 +462,12 @@ class Batch_test : public beast::unit_test::Suite
{ {
auto jtx = env.jt(pay(alice, bob, XRP(1))); auto jtx = env.jt(pay(alice, bob, XRP(1)));
PreflightContext const pfCtx( PreflightContext const pfCtx(
env.app(), *jtx.stx, UInt256{1}, env.current()->rules(), TapBatch, env.journal); env.app(),
*jtx.stx,
UInt256{1},
env.current()->rules(),
ApplyFlags::Batch,
env.journal);
auto const pf = Transactor::invokePreflight<Payment>(pfCtx); auto const pf = Transactor::invokePreflight<Payment>(pfCtx);
BEAST_EXPECT(pf == temINVALID_INNER_BATCH); BEAST_EXPECT(pf == temINVALID_INNER_BATCH);
} }
@@ -1590,7 +1595,7 @@ class Batch_test : public beast::unit_test::Suite
batch::Sig(std::vector<Reg>(kMaxBatchSigners + 1, bob))); batch::Sig(std::vector<Reg>(kMaxBatchSigners + 1, bob)));
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result = xrpl::apply(env.app(), view, *jt.stx, TapNone, j); auto const result = xrpl::apply(env.app(), view, *jt.stx, ApplyFlags::None, j);
BEAST_EXPECT(!result.applied && result.ter == temARRAY_TOO_LARGE); BEAST_EXPECT(!result.applied && result.ter == temARRAY_TOO_LARGE);
return result.applied; return result.applied;
}); });
@@ -4391,7 +4396,7 @@ class Batch_test : public beast::unit_test::Suite
BEAST_EXPECT(!passesLocalChecks(stx, reason)); BEAST_EXPECT(!passesLocalChecks(stx, reason));
BEAST_EXPECT(reason == "Cannot submit pseudo transactions."); BEAST_EXPECT(reason == "Cannot submit pseudo transactions.");
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result = xrpl::apply(env.app(), view, stx, TapNone, j); auto const result = xrpl::apply(env.app(), view, stx, ApplyFlags::None, j);
BEAST_EXPECT(!result.applied && result.ter == temINVALID_FLAG); BEAST_EXPECT(!result.applied && result.ter == temINVALID_FLAG);
return result.applied; return result.applied;
}); });
@@ -5637,7 +5642,7 @@ class Batch_test : public beast::unit_test::Suite
obj.setFieldU32(sfFlags, tfInnerBatchTxn); obj.setFieldU32(sfFlags, tfInnerBatchTxn);
}); });
auto const result = xrpl::apply(env.app(), view, stx, TapNone, j); auto const result = xrpl::apply(env.app(), view, stx, ApplyFlags::None, j);
// Must NOT be applied — signature was never checked // Must NOT be applied — signature was never checked
BEAST_EXPECT(!result.applied); BEAST_EXPECT(!result.applied);
return false; return false;
+2 -1
View File
@@ -1745,7 +1745,8 @@ class ConfidentialTransfer_test : public ConfidentialTransferTestBase
(*sle)[sfConfidentialBalanceVersion] = wrappedFrom; (*sle)[sfConfidentialBalanceVersion] = wrappedFrom;
view.rawReplace(sle); view.rawReplace(sle);
auto const result = xrpl::apply(env.app(), view, *jt.stx, TapNone, env.journal); auto const result =
xrpl::apply(env.app(), view, *jt.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(result.ter == tesSUCCESS); BEAST_EXPECT(result.ter == tesSUCCESS);
return result.applied; return result.applied;
})); }));
+2 -3
View File
@@ -901,8 +901,7 @@ struct Credentials_test : public beast::unit_test::Suite
{ {
testcase("deleteSLE fail, bad SLE."); testcase("deleteSLE fail, bad SLE.");
auto view = auto view = std::make_shared<ApplyViewImpl>(env.current().get(), ApplyFlags::None);
std::make_shared<ApplyViewImpl>(env.current().get(), ApplyFlags::TapNone);
auto ter = xrpl::credentials::deleteSLE(*view, {}, env.journal); auto ter = xrpl::credentials::deleteSLE(*view, {}, env.journal);
BEAST_EXPECT(ter == tecNO_ENTRY); BEAST_EXPECT(ter == tecNO_ENTRY);
} }
@@ -1125,7 +1124,7 @@ struct Credentials_test : public beast::unit_test::Suite
// Create an ApplyViewImpl on top of the current closed ledger // Create an ApplyViewImpl on top of the current closed ledger
// and corrupt it by erasing the issuer's account SLE // and corrupt it by erasing the issuer's account SLE
auto const open = env.current(); auto const open = env.current();
ApplyViewImpl av(&*open, TapNone); ApplyViewImpl av(&*open, ApplyFlags::None);
// Erase the issuer's account to simulate ledger corruption // Erase the issuer's account to simulate ledger corruption
auto sleIssuer = av.peek(keylet::account(issuer.id())); auto sleIssuer = av.peek(keylet::account(issuer.id()));
+2 -2
View File
@@ -2795,7 +2795,7 @@ struct EscrowToken_test : public beast::unit_test::Suite
auto const seq1 = env.seq(alice); auto const seq1 = env.seq(alice);
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
Sandbox sb(&view, TapNone); Sandbox sb(&view, ApplyFlags::None);
auto sleNew = auto sleNew =
std::make_shared<SLE>(keylet::escrow(alice, SeqProxy::rawSequence(seq1))); std::make_shared<SLE>(keylet::escrow(alice, SeqProxy::rawSequence(seq1)));
MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}}; MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}};
@@ -3023,7 +3023,7 @@ struct EscrowToken_test : public beast::unit_test::Suite
auto const seq1 = env.seq(alice); auto const seq1 = env.seq(alice);
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
Sandbox sb(&view, TapNone); Sandbox sb(&view, ApplyFlags::None);
auto sleNew = auto sleNew =
std::make_shared<SLE>(keylet::escrow(alice, SeqProxy::rawSequence(seq1))); std::make_shared<SLE>(keylet::escrow(alice, SeqProxy::rawSequence(seq1)));
MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}}; MPTIssue const mpt{MPTIssue{makeMptID(1, AccountID(0x4985601))}};
+6 -6
View File
@@ -1302,8 +1302,8 @@ struct Escrow_test : public beast::unit_test::Suite
escrow::kFinishTime(env.now() + 1s), escrow::kFinishTime(env.now() + 1s),
Seq(1), Seq(1),
Fee(baseFee)); Fee(baseFee));
auto const pf = auto const pf = preflight(
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal); env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter)); BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee)); BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
@@ -1312,8 +1312,8 @@ struct Escrow_test : public beast::unit_test::Suite
{ {
auto const jtx = env.jt(escrow::cancel("bob", "alice", 3), Seq(1), Fee(baseFee)); auto const jtx = env.jt(escrow::cancel("bob", "alice", 3), Seq(1), Fee(baseFee));
auto const pf = auto const pf = preflight(
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal); env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter)); BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee)); BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
@@ -1322,8 +1322,8 @@ struct Escrow_test : public beast::unit_test::Suite
{ {
auto const jtx = env.jt(escrow::finish("bob", "alice", 3), Seq(1), Fee(baseFee)); auto const jtx = env.jt(escrow::finish("bob", "alice", 3), Seq(1), Fee(baseFee));
auto const pf = auto const pf = preflight(
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal); env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter)); BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee)); BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
+1 -1
View File
@@ -134,7 +134,7 @@ createInvalidFeeTx(
bool bool
applyFeeAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx) applyFeeAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx)
{ {
auto const res = apply(env.app(), view, tx, ApplyFlags::TapNone, env.journal); auto const res = apply(env.app(), view, tx, ApplyFlags::None, env.journal);
return isTesSuccess(res.ter); return isTesSuccess(res.ter);
} }
+2 -2
View File
@@ -333,7 +333,7 @@ struct FlowMPT_test : public beast::unit_test::Suite
auto const flowResult = [&] { auto const flowResult = [&] {
STAmount const deliver(usd(5'100)); STAmount const deliver(usd(5'100));
STAmount smax(btc(61)); STAmount smax(btc(61));
PaymentSandbox sb(env.current().get(), TapNone); PaymentSandbox sb(env.current().get(), ApplyFlags::None);
STPathSet paths; STPathSet paths;
auto ipe = [](Asset const& asset) { auto ipe = [](Asset const& asset) {
return STPathElement( return STPathElement(
@@ -371,7 +371,7 @@ struct FlowMPT_test : public beast::unit_test::Suite
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
if (flowResult.removableOffers.empty()) if (flowResult.removableOffers.empty())
return false; return false;
Sandbox sb(&view, TapNone); Sandbox sb(&view, ApplyFlags::None);
for (auto const& o : flowResult.removableOffers) for (auto const& o : flowResult.removableOffers)
{ {
if (auto ok = sb.peek(keylet::offer(o))) if (auto ok = sb.peek(keylet::offer(o)))
+2 -2
View File
@@ -476,7 +476,7 @@ struct Flow_test : public beast::unit_test::Suite
auto const flowResult = [&] { auto const flowResult = [&] {
STAmount const deliver(usd(51)); STAmount const deliver(usd(51));
STAmount smax(btc(61)); STAmount smax(btc(61));
PaymentSandbox sb(env.current().get(), TapNone); PaymentSandbox sb(env.current().get(), ApplyFlags::None);
STPathSet paths; STPathSet paths;
auto ipe = [](Issue const& iss) { auto ipe = [](Issue const& iss) {
return STPathElement( return STPathElement(
@@ -514,7 +514,7 @@ struct Flow_test : public beast::unit_test::Suite
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
if (flowResult.removableOffers.empty()) if (flowResult.removableOffers.empty())
return false; return false;
Sandbox sb(&view, TapNone); Sandbox sb(&view, ApplyFlags::None);
for (auto const& o : flowResult.removableOffers) for (auto const& o : flowResult.removableOffers)
{ {
if (auto ok = sb.peek(keylet::offer(o))) if (auto ok = sb.peek(keylet::offer(o)))
+1 -1
View File
@@ -59,7 +59,7 @@ public:
if (stx) if (stx)
{ {
OpenView accum(&*res); OpenView accum(&*res);
applyTransaction(env.app(), accum, *stx, false, TapNone, env.journal); applyTransaction(env.app(), accum, *stx, false, ApplyFlags::None, env.journal);
accum.apply(*res); accum.apply(*res);
} }
res->updateSkipList(); res->updateSkipList();
+2 -2
View File
@@ -90,7 +90,7 @@ struct LedgerReplay_test : public beast::unit_test::Suite
auto const lastClosedParent = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash); auto const lastClosedParent = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash);
auto const replayed = buildLedger( auto const replayed = buildLedger(
LedgerReplay(lastClosedParent, lastClosed), TapNone, env.app(), env.journal); LedgerReplay(lastClosedParent, lastClosed), ApplyFlags::None, env.app(), env.journal);
BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash); BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash);
} }
@@ -122,7 +122,7 @@ struct LedgerReplay_test : public beast::unit_test::Suite
auto const lastClosedParent = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash); auto const lastClosedParent = ledgerMaster.getLedgerByHash(lastClosed->header().parentHash);
auto const replayed = buildLedger( auto const replayed = buildLedger(
LedgerReplay(lastClosedParent, lastClosed), TapNone, env.app(), env.journal); LedgerReplay(lastClosedParent, lastClosed), ApplyFlags::None, env.app(), env.journal);
BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash); BEAST_EXPECT(replayed->header().hash == lastClosed->header().hash);
} }
+1 -1
View File
@@ -4059,7 +4059,7 @@ class MPToken_test : public beast::unit_test::Suite
TER expectedTer, TER expectedTer,
std::optional<std::uint64_t> expectedOutstanding, std::optional<std::uint64_t> expectedOutstanding,
std::string const& label) { std::string const& label) {
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
auto const ter = auto const ter =
accountSendMulti(av, issuer.id(), asset, receivers, env.app().getJournal("View")); accountSendMulti(av, issuer.id(), asset, receivers, env.app().getJournal("View"));
BEAST_EXPECTS(ter == expectedTer, label); BEAST_EXPECTS(ter == expectedTer, label);
+14 -2
View File
@@ -776,7 +776,13 @@ class NFTokenBurn_test : public beast::unit_test::Suite
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
// Verify that the last page is present and contains one NFT. // Verify that the last page is present and contains one NFT.
auto lastNFTokenPage = ac.view().peek(keylet::nftokenPageMax(alice)); auto lastNFTokenPage = ac.view().peek(keylet::nftokenPageMax(alice));
@@ -808,7 +814,13 @@ class NFTokenBurn_test : public beast::unit_test::Suite
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
// Verify that the middle page is present. // Verify that the middle page is present.
auto lastNFTokenPage = ac.view().peek(keylet::nftokenPageMax(alice)); auto lastNFTokenPage = ac.view().peek(keylet::nftokenPageMax(alice));
+24
View File
@@ -1404,6 +1404,30 @@ struct PayChan_test : public beast::unit_test::Suite
rv = env.rpc("channel_authorize", "alice", chan1StrBad, "1000"); rv = env.rpc("channel_authorize", "alice", chan1StrBad, "1000");
BEAST_EXPECT(rv[jss::error] == "channelMalformed"); BEAST_EXPECT(rv[jss::error] == "channelMalformed");
} }
{
// channel_id is not a string.
json::Value args{json::ValueType::Object};
args[jss::amount] = "2000";
args[jss::channel_id] = 2000;
args[jss::key_type] = "secp256k1";
args[jss::passphrase] = "passphrase_can_be_anything";
auto const ra =
env.rpc("json", "channel_authorize", args.toStyledString())[jss::result];
BEAST_EXPECT(ra[jss::error] == "invalidParams");
}
{
// channel_id is not a string.
json::Value args{json::ValueType::Object};
args[jss::public_key] = chan1PkStr;
args[jss::channel_id] = 2000;
args[jss::amount] = "1000";
args[jss::signature] = sig;
auto const rv =
env.rpc("json", "channel_verify", args.toStyledString())[jss::result];
BEAST_EXPECT(rv[jss::error] == "invalidParams");
}
{ {
// give an ill formed base 58 public key // give an ill formed base 58 public key
auto illFormedPk = chan1PkStr.substr(0, chan1PkStr.size() - 1); auto illFormedPk = chan1PkStr.substr(0, chan1PkStr.size() - 1);
+1 -1
View File
@@ -572,7 +572,7 @@ struct PayStrandMPT_test : public beast::unit_test::Suite
inputs.defaultPathsAllowed = true; inputs.defaultPathsAllowed = true;
try try
{ {
PaymentSandbox sb{env.current().get(), TapNone}; PaymentSandbox sb{env.current().get(), ApplyFlags::None};
{ {
auto const r = ::xrpl::path::RippleCalc::rippleCalculate( auto const r = ::xrpl::path::RippleCalc::rippleCalculate(
sb, sb,
+3 -2
View File
@@ -768,7 +768,8 @@ struct PayStrand_test : public beast::unit_test::Suite
env, env,
usd, usd,
std::nullopt, std::nullopt,
STPath({STPathElement(0, xrpAccount(), xrpCurrency(), xrpAccount())}), STPath({STPathElement(
STPathElement::Type::TypeNone, xrpAccount(), xrpCurrency(), xrpAccount())}),
temBAD_PATH); temBAD_PATH);
// The same account can't appear more than once on a path // The same account can't appear more than once on a path
@@ -1076,7 +1077,7 @@ struct PayStrand_test : public beast::unit_test::Suite
inputs.defaultPathsAllowed = true; inputs.defaultPathsAllowed = true;
try try
{ {
PaymentSandbox sb{env.current().get(), TapNone}; PaymentSandbox sb{env.current().get(), ApplyFlags::None};
{ {
auto const r = ::xrpl::path::RippleCalc::rippleCalculate( auto const r = ::xrpl::path::RippleCalc::rippleCalculate(
sb, sb,
+1 -1
View File
@@ -82,7 +82,7 @@ struct PseudoTx_test : public beast::unit_test::Suite
BEAST_EXPECT(!passesLocalChecks(stx, reason)); BEAST_EXPECT(!passesLocalChecks(stx, reason));
BEAST_EXPECT(reason == "Cannot submit pseudo transactions."); BEAST_EXPECT(reason == "Cannot submit pseudo transactions.");
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result = xrpl::apply(env.app(), view, stx, TapNone, j); auto const result = xrpl::apply(env.app(), view, stx, ApplyFlags::None, j);
BEAST_EXPECT(!result.applied && result.ter == temINVALID); BEAST_EXPECT(!result.applied && result.ter == temINVALID);
return result.applied; return result.applied;
}); });
+4 -2
View File
@@ -103,7 +103,8 @@ struct Regression_test : public beast::unit_test::Suite
auto const jt = env.jt(pay(env.master, "alice", aliceAmount)); auto const jt = env.jt(pay(env.master, "alice", aliceAmount));
OpenView accum(&*next); OpenView accum(&*next);
auto const result = xrpl::apply(env.app(), accum, *jt.stx, TapNone, env.journal); auto const result =
xrpl::apply(env.app(), accum, *jt.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(isTesSuccess(result.ter)); BEAST_EXPECT(isTesSuccess(result.ter));
BEAST_EXPECT(result.applied); BEAST_EXPECT(result.applied);
@@ -126,7 +127,8 @@ struct Regression_test : public beast::unit_test::Suite
OpenView accum(&*next); OpenView accum(&*next);
auto const result = xrpl::apply(env.app(), accum, *jt.stx, TapNone, env.journal); auto const result =
xrpl::apply(env.app(), accum, *jt.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(result.ter == tecINSUFF_FEE); BEAST_EXPECT(result.ter == tecINSUFF_FEE);
BEAST_EXPECT(result.applied); BEAST_EXPECT(result.applied);
+10 -8
View File
@@ -915,8 +915,8 @@ public:
sponsor::SponseeAcc(alice), sponsor::SponseeAcc(alice),
Seq(1), Seq(1),
Fee(baseFee)); Fee(baseFee));
auto const pf = auto const pf = preflight(
preflight(env.app(), env.current()->rules(), *jt.stx, TapNone, env.journal); env.app(), env.current()->rules(), *jt.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter)); BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee)); BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
@@ -931,8 +931,8 @@ public:
sponsor::SponseeAcc(alice), sponsor::SponseeAcc(alice),
Seq(1), Seq(1),
Fee(baseFee)); Fee(baseFee));
auto const pf = auto const pf = preflight(
preflight(env.app(), env.current()->rules(), *jt.stx, TapNone, env.journal); env.app(), env.current()->rules(), *jt.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter)); BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee)); BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
@@ -946,8 +946,8 @@ public:
sponsor::SponseeAcc(alice), sponsor::SponseeAcc(alice),
Seq(1), Seq(1),
Fee(baseFee)); Fee(baseFee));
auto const pf = auto const pf = preflight(
preflight(env.app(), env.current()->rules(), *jt.stx, TapNone, env.journal); env.app(), env.current()->rules(), *jt.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter)); BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(baseFee)); BEAST_EXPECT(pf.consequences.fee() == drops(baseFee));
@@ -2242,7 +2242,8 @@ public:
Seq(env.seq(alice)), Seq(env.seq(alice)),
sponsor::As(carol, spfSponsorFee)); sponsor::As(carol, spfSponsorFee));
auto const result = xrpl::apply(env.app(), overlay, *jt.stx, TapNone, env.journal); auto const result =
xrpl::apply(env.app(), overlay, *jt.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(result.ter == tecINSUFF_FEE); BEAST_EXPECT(result.ter == tecINSUFF_FEE);
BEAST_EXPECT(result.applied); BEAST_EXPECT(result.applied);
@@ -2295,7 +2296,8 @@ public:
Fee(fixFee), Fee(fixFee),
sponsor::As(sponsor, spfSponsorFee)); sponsor::As(sponsor, spfSponsorFee));
auto const pf = preflight(env.app(), overlay.rules(), *jt.stx, TapNone, env.journal); auto const pf =
preflight(env.app(), overlay.rules(), *jt.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter)); BEAST_EXPECT(isTesSuccess(pf.ter));
auto const pc = preclaim(pf, env.app(), overlay); auto const pc = preclaim(pf, env.app(), overlay);
BEAST_EXPECT(isTesSuccess(pc.ter)); BEAST_EXPECT(isTesSuccess(pc.ter));
+1 -1
View File
@@ -252,7 +252,7 @@ class TheoreticalQuality_test : public beast::unit_test::Suite
std::shared_ptr<ReadView const> closed, std::shared_ptr<ReadView const> closed,
std::optional<Quality> const& expectedQ = {}) std::optional<Quality> const& expectedQ = {})
{ {
PaymentSandbox const sb(closed.get(), TapNone); PaymentSandbox const sb(closed.get(), ApplyFlags::None);
AMMContext ammContext(rcp.srcAccount, false); AMMContext ammContext(rcp.srcAccount, false);
auto const sendMaxIssue = [&rcp]() -> std::optional<Asset> { auto const sendMaxIssue = [&rcp]() -> std::optional<Asset> {
+10 -9
View File
@@ -989,7 +989,8 @@ public:
Env::ParsedResult parsed; Env::ParsedResult parsed;
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const result = xrpl::apply(env.app(), view, *jt.stx, TapNone, env.journal); auto const result =
xrpl::apply(env.app(), view, *jt.stx, ApplyFlags::None, env.journal);
parsed.ter = result.ter; parsed.ter = result.ter;
return result.applied; return result.applied;
}); });
@@ -2424,8 +2425,8 @@ public:
env.memoize("carol"); env.memoize("carol");
{ {
auto const jtx = env.jt(offerCancel(alice, 3), Seq(5), Fee(10)); auto const jtx = env.jt(offerCancel(alice, 3), Seq(5), Fee(10));
auto const pf = auto const pf = preflight(
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal); env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter)); BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(10)); BEAST_EXPECT(pf.consequences.fee() == drops(10));
@@ -2436,8 +2437,8 @@ public:
auto usd = alice["USD"]; auto usd = alice["USD"];
auto const jtx = env.jt(trust("carol", usd(50000000)), Seq(1), Fee(10)); auto const jtx = env.jt(trust("carol", usd(50000000)), Seq(1), Fee(10));
auto const pf = auto const pf = preflight(
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal); env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter)); BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(10)); BEAST_EXPECT(pf.consequences.fee() == drops(10));
@@ -2446,8 +2447,8 @@ public:
{ {
auto const jtx = env.jt(ticket::create(alice, 1), Seq(1), Fee(10)); auto const jtx = env.jt(ticket::create(alice, 1), Seq(1), Fee(10));
auto const pf = auto const pf = preflight(
preflight(env.app(), env.current()->rules(), *jtx.stx, TapNone, env.journal); env.app(), env.current()->rules(), *jtx.stx, ApplyFlags::None, env.journal);
BEAST_EXPECT(isTesSuccess(pf.ter)); BEAST_EXPECT(isTesSuccess(pf.ter));
BEAST_EXPECT(!pf.consequences.isBlocker()); BEAST_EXPECT(!pf.consequences.isBlocker());
BEAST_EXPECT(pf.consequences.fee() == drops(10)); BEAST_EXPECT(pf.consequences.fee() == drops(10));
@@ -4002,7 +4003,7 @@ public:
// be callable via RPC.) // be callable via RPC.)
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const tx = env.jt(noop(alice), Seq(aliceSeq), Fee(openLedgerCost(env))); auto const tx = env.jt(noop(alice), Seq(aliceSeq), Fee(openLedgerCost(env)));
auto const result = xrpl::apply(env.app(), view, *tx.stx, TapUnlimited, j); auto const result = xrpl::apply(env.app(), view, *tx.stx, ApplyFlags::Unlimited, j);
BEAST_EXPECT(isTesSuccess(result.ter) && result.applied); BEAST_EXPECT(isTesSuccess(result.ter) && result.applied);
return result.applied; return result.applied;
}); });
@@ -4070,7 +4071,7 @@ public:
// be callable via RPC.) // be callable via RPC.)
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
auto const tx = env.jt(noop(alice), ticket::Use(tktSeq0 + 1), Fee(openLedgerCost(env))); auto const tx = env.jt(noop(alice), ticket::Use(tktSeq0 + 1), Fee(openLedgerCost(env)));
auto const result = xrpl::apply(env.app(), view, *tx.stx, TapUnlimited, j); auto const result = xrpl::apply(env.app(), view, *tx.stx, ApplyFlags::Unlimited, j);
BEAST_EXPECT(isTesSuccess(result.ter) && result.applied); BEAST_EXPECT(isTesSuccess(result.ter) && result.applied);
return result.applied; return result.applied;
}); });
+2 -1
View File
@@ -122,7 +122,8 @@ InvariantsBase::doInvariantCheck(
OpenView ov{*env.current()}; OpenView ov{*env.current()};
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
// Invariants normally run in the Transaction's "apply" (operator()) context, and can always // Invariants normally run in the Transaction's "apply" (operator()) context, and can always
// access global Rules. // access global Rules.
@@ -811,7 +811,13 @@ class InvariantsMisc_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto sleLoan = ac.view().peek(loanKeylet); auto sleLoan = ac.view().peek(loanKeylet);
@@ -866,7 +872,13 @@ class InvariantsMisc_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto sleLoan = ac.view().peek(loanKeylet); auto sleLoan = ac.view().peek(loanKeylet);
@@ -979,7 +991,13 @@ class InvariantsMisc_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto sleLoan = ac.view().peek(loanKeylet); auto sleLoan = ac.view().peek(loanKeylet);
@@ -1417,7 +1435,7 @@ class InvariantsMisc_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto sle = ac.view().peek(vaultKeylet); auto sle = ac.view().peek(vaultKeylet);
@@ -1484,7 +1502,7 @@ class InvariantsMisc_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
// visitEntry only runs for entries the transaction touched, so // visitEntry only runs for entries the transaction touched, so
@@ -1541,7 +1559,8 @@ class InvariantsMisc_test : public InvariantsBase
STTx const tx{ttACCOUNT_SET, [](STObject&) {}}; STTx const tx{ttACCOUNT_SET, [](STObject&) {}};
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
FailingTxInvariantCheck failing; FailingTxInvariantCheck failing;
@@ -581,7 +581,7 @@ class InvariantsPseudoAccount_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto sleBroker = ac.view().peek(brokerKeylet); auto sleBroker = ac.view().peek(brokerKeylet);
@@ -633,7 +633,7 @@ class InvariantsPseudoAccount_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto sleBroker = ac.view().peek(brokerKeylet); auto sleBroker = ac.view().peek(brokerKeylet);
@@ -681,7 +681,7 @@ class InvariantsPseudoAccount_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto sleBroker = ac.view().peek(brokerKeylet); auto sleBroker = ac.view().peek(brokerKeylet);
@@ -1088,7 +1088,13 @@ class InvariantsVault_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto sleLoan = ac.view().peek(loanKeylet); auto sleLoan = ac.view().peek(loanKeylet);
@@ -1140,7 +1146,7 @@ class InvariantsVault_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto sleLoan = ac.view().peek(loanKeylet); auto sleLoan = ac.view().peek(loanKeylet);
@@ -1302,7 +1308,13 @@ class InvariantsVault_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto sleLoan = ac.view().peek(loanKeylet); auto sleLoan = ac.view().peek(loanKeylet);
@@ -1357,7 +1369,13 @@ class InvariantsVault_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(),
ov,
tx,
tesSUCCESS,
env.current()->fees().base,
ApplyFlags::None,
jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
auto sleLoan = ac.view().peek(loanKeylet); auto sleLoan = ac.view().peek(loanKeylet);
@@ -1457,7 +1475,7 @@ class InvariantsVault_test : public InvariantsBase
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{ ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
CurrentTransactionRulesGuard const rulesGuard(ov.rules()); CurrentTransactionRulesGuard const rulesGuard(ov.rules());
{ {
+3 -2
View File
@@ -1249,7 +1249,8 @@ class LoanBroker_test : public beast::unit_test::Suite
OpenView ov{*env.current()}; OpenView ov{*env.current()};
test::StreamSink sink{beast::Severity::Warning}; test::StreamSink sink{beast::Severity::Warning};
beast::Journal const jlog{sink}; beast::Journal const jlog{sink};
ApplyContext ac{env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, TapNone, jlog}; ApplyContext ac{
env.app(), ov, tx, tesSUCCESS, env.current()->fees().base, ApplyFlags::None, jlog};
if (auto sleBroker = ac.view().peek(keylet::loanBroker(brokerKeylet.key))) if (auto sleBroker = ac.view().peek(keylet::loanBroker(brokerKeylet.key)))
{ {
@@ -1262,7 +1263,7 @@ class LoanBroker_test : public beast::unit_test::Suite
// Invoke preclaim against the mutated (ApplyView) view; triggers // Invoke preclaim against the mutated (ApplyView) view; triggers
// nullptr deref // nullptr deref
PreclaimContext const pctx{env.app(), ac.view(), tesSUCCESS, tx, TapNone, jlog}; PreclaimContext const pctx{env.app(), ac.view(), tesSUCCESS, tx, ApplyFlags::None, jlog};
(void)LoanBrokerCoverDeposit::preclaim(pctx); (void)LoanBrokerCoverDeposit::preclaim(pctx);
} }
+1 -1
View File
@@ -108,7 +108,7 @@ private:
auto const peek = [keylet, &env, this](std::function<bool(SLE&, SLE&)> fn) -> bool { auto const peek = [keylet, &env, this](std::function<bool(SLE&, SLE&)> fn) -> bool {
return env.app().getOpenLedger().modify( return env.app().getOpenLedger().modify(
[&](OpenView& view, beast::Journal j) -> bool { [&](OpenView& view, beast::Journal j) -> bool {
Sandbox sb(&view, TapNone); Sandbox sb(&view, ApplyFlags::None);
auto vault = sb.peek(keylet::vault(keylet.key)); auto vault = sb.peek(keylet::vault(keylet.key));
if (!BEAST_EXPECT(vault)) if (!BEAST_EXPECT(vault))
return false; return false;
+1 -1
View File
@@ -300,7 +300,7 @@ private:
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) {
for (auto const field : encryptedBalanceFields) for (auto const field : encryptedBalanceFields)
{ {
Sandbox sb(&view, TapNone); Sandbox sb(&view, ApplyFlags::None);
auto const token = sb.peek(tokenKeylet); auto const token = sb.peek(tokenKeylet);
if (!BEAST_EXPECT(token)) if (!BEAST_EXPECT(token))
return false; return false;
-90
View File
@@ -1,90 +0,0 @@
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/beast/utility/Journal.h>
#include <string>
namespace beast {
class Journal_test : public unit_test::Suite
{
public:
class TestSink : public Journal::Sink
{
private:
int count_{0};
public:
TestSink() : Sink(Severity::Warning, false)
{
}
[[nodiscard]] int
count() const
{
return count_;
}
void
reset()
{
count_ = 0;
}
void
write(Severity level, std::string const&) override
{
if (level >= threshold())
++count_;
}
void
writeAlways(Severity level, std::string const&) override
{
++count_;
}
};
void
run() override
{
TestSink sink;
sink.threshold(Severity::Info);
Journal const j(sink);
j.trace() << " ";
BEAST_EXPECT(sink.count() == 0);
j.debug() << " ";
BEAST_EXPECT(sink.count() == 0);
j.info() << " ";
BEAST_EXPECT(sink.count() == 1);
j.warn() << " ";
BEAST_EXPECT(sink.count() == 2);
j.error() << " ";
BEAST_EXPECT(sink.count() == 3);
j.fatal() << " ";
BEAST_EXPECT(sink.count() == 4);
sink.reset();
sink.threshold(Severity::Debug);
j.trace() << " ";
BEAST_EXPECT(sink.count() == 0);
j.debug() << " ";
BEAST_EXPECT(sink.count() == 1);
j.info() << " ";
BEAST_EXPECT(sink.count() == 2);
j.warn() << " ";
BEAST_EXPECT(sink.count() == 3);
j.error() << " ";
BEAST_EXPECT(sink.count() == 4);
j.fatal() << " ";
BEAST_EXPECT(sink.count() == 5);
}
};
BEAST_DEFINE_TESTSUITE(Journal, beast, beast);
} // namespace beast
@@ -1,19 +0,0 @@
#include <xrpl/beast/clock/basic_seconds_clock.h>
#include <xrpl/beast/unit_test/suite.h>
namespace beast {
class BasicSecondsClock_test : public unit_test::Suite
{
public:
void
run() override
{
BasicSecondsClock::now();
pass();
}
};
BEAST_DEFINE_TESTSUITE(BasicSecondsClock, beast, beast);
} // namespace beast
-196
View File
@@ -1,196 +0,0 @@
#include <xrpl/beast/hash/xxhasher.h>
#include <xrpl/beast/unit_test/suite.h>
#include <cstdint>
namespace beast {
class XXHasher_test : public unit_test::Suite
{
public:
void
testWithoutSeed()
{
testcase("Without seed");
Xxhasher hasher{};
std::string objectToHash{"Hello, xxHash!"};
hasher(objectToHash.data(), objectToHash.size());
BEAST_EXPECT(static_cast<Xxhasher::result_type>(hasher) == 16042857369214894119ULL);
}
void
testWithSeed()
{
testcase("With seed");
Xxhasher hasher{static_cast<std::uint32_t>(102)};
std::string objectToHash{"Hello, xxHash!"};
hasher(objectToHash.data(), objectToHash.size());
BEAST_EXPECT(static_cast<Xxhasher::result_type>(hasher) == 14440132435660934800ULL);
}
void
testWithTwoSeeds()
{
testcase("With two seeds");
Xxhasher hasher{static_cast<std::uint32_t>(102), static_cast<std::uint32_t>(103)};
std::string objectToHash{"Hello, xxHash!"};
hasher(objectToHash.data(), objectToHash.size());
BEAST_EXPECT(static_cast<Xxhasher::result_type>(hasher) == 14440132435660934800ULL);
}
void
testBigObjectWithMultipleSmallUpdatesWithoutSeed()
{
testcase("Big object with multiple small updates without seed");
Xxhasher hasher{};
std::string objectToHash{"Hello, xxHash!"};
for (int i = 0; i < 100; i++)
{
hasher(objectToHash.data(), objectToHash.size());
}
BEAST_EXPECT(static_cast<Xxhasher::result_type>(hasher) == 15296278154063476002ULL);
}
void
testBigObjectWithMultipleSmallUpdatesWithSeed()
{
testcase("Big object with multiple small updates with seed");
Xxhasher hasher{static_cast<std::uint32_t>(103)};
std::string objectToHash{"Hello, xxHash!"};
for (int i = 0; i < 100; i++)
{
hasher(objectToHash.data(), objectToHash.size());
}
BEAST_EXPECT(static_cast<Xxhasher::result_type>(hasher) == 17285302196561698791ULL);
}
void
testBigObjectWithSmallAndBigUpdatesWithoutSeed()
{
testcase("Big object with small and big updates without seed");
Xxhasher hasher{};
std::string objectToHash{"Hello, xxHash!"};
std::string bigObject;
for (int i = 0; i < 20; i++)
{
bigObject += "Hello, xxHash!";
}
hasher(objectToHash.data(), objectToHash.size());
hasher(bigObject.data(), bigObject.size());
hasher(objectToHash.data(), objectToHash.size());
BEAST_EXPECT(static_cast<Xxhasher::result_type>(hasher) == 1865045178324729219ULL);
}
void
testBigObjectWithSmallAndBigUpdatesWithSeed()
{
testcase("Big object with small and big updates with seed");
Xxhasher hasher{static_cast<std::uint32_t>(103)};
std::string objectToHash{"Hello, xxHash!"};
std::string bigObject;
for (int i = 0; i < 20; i++)
{
bigObject += "Hello, xxHash!";
}
hasher(objectToHash.data(), objectToHash.size());
hasher(bigObject.data(), bigObject.size());
hasher(objectToHash.data(), objectToHash.size());
BEAST_EXPECT(static_cast<Xxhasher::result_type>(hasher) == 16189862915636005281ULL);
}
void
testBigObjectWithOneUpdateWithoutSeed()
{
testcase("Big object with one update without seed");
Xxhasher hasher{};
std::string objectToHash;
for (int i = 0; i < 100; i++)
{
objectToHash += "Hello, xxHash!";
}
hasher(objectToHash.data(), objectToHash.size());
BEAST_EXPECT(static_cast<Xxhasher::result_type>(hasher) == 15296278154063476002ULL);
}
void
testBigObjectWithOneUpdateWithSeed()
{
testcase("Big object with one update with seed");
Xxhasher hasher{static_cast<std::uint32_t>(103)};
std::string objectToHash;
for (int i = 0; i < 100; i++)
{
objectToHash += "Hello, xxHash!";
}
hasher(objectToHash.data(), objectToHash.size());
BEAST_EXPECT(static_cast<Xxhasher::result_type>(hasher) == 17285302196561698791ULL);
}
void
testOperatorResultTypeDoesNotChangeInternalState()
{
testcase("Operator result type doesn't change the internal state");
{
Xxhasher hasher;
std::string object{"Hello xxhash"};
hasher(object.data(), object.size());
auto xxhashResult1 = static_cast<Xxhasher::result_type>(hasher);
auto xxhashResult2 = static_cast<Xxhasher::result_type>(hasher);
BEAST_EXPECT(xxhashResult1 == xxhashResult2);
}
{
Xxhasher hasher;
std::string object;
for (int i = 0; i < 100; i++)
{
object += "Hello, xxHash!";
}
hasher(object.data(), object.size());
auto xxhashResult1 = hasher.operator Xxhasher::result_type();
auto xxhashResult2 = hasher.operator Xxhasher::result_type();
BEAST_EXPECT(xxhashResult1 == xxhashResult2);
}
}
void
run() override
{
testWithoutSeed();
testWithSeed();
testWithTwoSeeds();
testBigObjectWithMultipleSmallUpdatesWithoutSeed();
testBigObjectWithMultipleSmallUpdatesWithSeed();
testBigObjectWithSmallAndBigUpdatesWithoutSeed();
testBigObjectWithSmallAndBigUpdatesWithSeed();
testBigObjectWithOneUpdateWithoutSeed();
testBigObjectWithOneUpdateWithSeed();
testOperatorResultTypeDoesNotChangeInternalState();
}
};
BEAST_DEFINE_TESTSUITE(XXHasher, beast_core, beast);
} // namespace beast
+1 -1
View File
@@ -1902,7 +1902,7 @@ negUnlSizeTest(
bool bool
applyAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass) applyAndTestResult(jtx::Env& env, OpenView& view, STTx const& tx, bool pass)
{ {
auto const res = apply(env.app(), view, tx, ApplyFlags::TapNone, env.journal); auto const res = apply(env.app(), view, tx, ApplyFlags::None, env.journal);
if (pass) if (pass)
{ {
return isTesSuccess(res.ter); return isTesSuccess(res.ter);
+1 -1
View File
@@ -32,7 +32,7 @@ bumpLastPage(
{ {
std::expected<void, Error> res{}; std::expected<void, Error> res{};
env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) -> bool { env.app().getOpenLedger().modify([&](OpenView& view, beast::Journal j) -> bool {
Sandbox sb(&view, TapNone); Sandbox sb(&view, ApplyFlags::None);
// Find the root page // Find the root page
auto sleRoot = sb.peek(directory); auto sleRoot = sb.peek(directory);
+3 -3
View File
@@ -313,7 +313,7 @@ struct Directory_test : public beast::unit_test::Suite
// All the offers have been cancelled, so the book // All the offers have been cancelled, so the book
// should have no entries and be empty: // should have no entries and be empty:
{ {
Sandbox const sb(env.closed().get(), TapNone); Sandbox const sb(env.closed().get(), ApplyFlags::None);
UInt256 const bookBase = getBookBase({xrpIssue(), usd, std::nullopt}); UInt256 const bookBase = getBookBase({xrpIssue(), usd, std::nullopt});
BEAST_EXPECT(dirIsEmpty(sb, keylet::page(bookBase))); BEAST_EXPECT(dirIsEmpty(sb, keylet::page(bookBase)));
@@ -352,7 +352,7 @@ struct Directory_test : public beast::unit_test::Suite
{ {
// Create a chain of three pages: // Create a chain of three pages:
Sandbox sb(env.closed().get(), TapNone); Sandbox sb(env.closed().get(), ApplyFlags::None);
makePages(sb, kBase, 3); makePages(sb, kBase, 3);
// Insert an item in the middle page: // Insert an item in the middle page:
@@ -376,7 +376,7 @@ struct Directory_test : public beast::unit_test::Suite
{ {
// Create a chain of four pages: // Create a chain of four pages:
Sandbox sb(env.closed().get(), TapNone); Sandbox sb(env.closed().get(), ApplyFlags::None);
makePages(sb, kBase, 4); makePages(sb, kBase, 4);
// Now add items on pages 1 and 2: // Now add items on pages 1 and 2:
+11 -11
View File
@@ -131,7 +131,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
STAmount const toDebit(usdGw1(20)); STAmount const toDebit(usdGw1(20));
{ {
// accountSend, no deferredCredits // accountSend, no deferredCredits
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
auto const iss = usdGw1; auto const iss = usdGw1;
auto const startingAmount = auto const startingAmount =
@@ -156,7 +156,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{ {
// directSendNoFee, no deferredCredits // directSendNoFee, no deferredCredits
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
auto const iss = usdGw1; auto const iss = usdGw1;
auto const startingAmount = auto const startingAmount =
@@ -177,7 +177,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{ {
// accountSend, w/ deferredCredits // accountSend, w/ deferredCredits
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
PaymentSandbox pv(&av); PaymentSandbox pv(&av);
auto const iss = usdGw1; auto const iss = usdGw1;
@@ -205,7 +205,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{ {
// directSendNoFee, w/ deferredCredits // directSendNoFee, w/ deferredCredits
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
PaymentSandbox pv(&av); PaymentSandbox pv(&av);
auto const iss = usdGw1; auto const iss = usdGw1;
@@ -221,7 +221,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{ {
// redeemIOU, w/ deferredCredits // redeemIOU, w/ deferredCredits
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
PaymentSandbox pv(&av); PaymentSandbox pv(&av);
auto const iss = usdGw1; auto const iss = usdGw1;
@@ -237,7 +237,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{ {
// issueIOU, w/ deferredCredits // issueIOU, w/ deferredCredits
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
PaymentSandbox pv(&av); PaymentSandbox pv(&av);
auto const iss = usdGw1; auto const iss = usdGw1;
@@ -253,7 +253,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
{ {
// accountSend, w/ deferredCredits and stacked views // accountSend, w/ deferredCredits and stacked views
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
PaymentSandbox pv(&av); PaymentSandbox pv(&av);
auto const iss = usdGw1; auto const iss = usdGw1;
@@ -319,7 +319,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
STAmount const hugeAmt( STAmount const hugeAmt(
issue, STAmount::kMaxValue, STAmount::kMaxOffset - 1, false, STAmount::Unchecked{}); issue, STAmount::kMaxValue, STAmount::kMaxOffset - 1, false, STAmount::Unchecked{});
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
PaymentSandbox pv(&av); PaymentSandbox pv(&av);
pv.creditHookIOU(gw, alice, hugeAmt, -tinyAmt); pv.creditHookIOU(gw, alice, hugeAmt, -tinyAmt);
BEAST_EXPECT(pv.balanceHookIOU(alice, gw, hugeAmt) == tinyAmt); BEAST_EXPECT(pv.balanceHookIOU(alice, gw, hugeAmt) == tinyAmt);
@@ -347,7 +347,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
env.fund(reserve(env, 1), alice); env.fund(reserve(env, 1), alice);
env.close(); env.close();
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
PaymentSandbox sb(&av); PaymentSandbox sb(&av);
{ {
// Send alice an amount and spend it. The deferredCredits will cause // Send alice an amount and spend it. The deferredCredits will cause
@@ -380,7 +380,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
auto const usd = gw["USD"]; auto const usd = gw["USD"];
Account const alice("alice"); Account const alice("alice");
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
PaymentSandbox sb(&av); PaymentSandbox sb(&av);
// The currency we pass for the last argument mimics the currency that // The currency we pass for the last argument mimics the currency that
@@ -412,7 +412,7 @@ class PaymentSandbox_test : public beast::unit_test::Suite
env.fund(XRP(10000), alice, sponsor); env.fund(XRP(10000), alice, sponsor);
env.close(); env.close();
ApplyViewImpl av(&*env.current(), TapNone); ApplyViewImpl av(&*env.current(), ApplyFlags::None);
PaymentSandbox sb(&av); PaymentSandbox sb(&av);
// Test basic owner count hook without sponsor // Test basic owner count hook without sponsor
+9 -9
View File
@@ -189,7 +189,7 @@ class View_test : public beast::unit_test::Suite
Env env(*this); Env env(*this);
wipe(env.app().getOpenLedger()); wipe(env.app().getOpenLedger());
auto const open = env.current(); auto const open = env.current();
ApplyViewImpl v(&*open, TapNone); ApplyViewImpl v(&*open, ApplyFlags::None);
succ(v, 0, std::nullopt); succ(v, 0, std::nullopt);
v.insert(sle(1)); v.insert(sle(1));
BEAST_EXPECT(v.exists(k(1))); BEAST_EXPECT(v.exists(k(1)));
@@ -222,7 +222,7 @@ class View_test : public beast::unit_test::Suite
Env env(*this); Env env(*this);
wipe(env.app().getOpenLedger()); wipe(env.app().getOpenLedger());
auto const open = env.current(); auto const open = env.current();
ApplyViewImpl v0(&*open, TapNone); ApplyViewImpl v0(&*open, ApplyFlags::None);
v0.insert(sle(1)); v0.insert(sle(1));
v0.insert(sle(2)); v0.insert(sle(2));
v0.insert(sle(4)); v0.insert(sle(4));
@@ -288,7 +288,7 @@ class View_test : public beast::unit_test::Suite
Env env(*this); Env env(*this);
wipe(env.app().getOpenLedger()); wipe(env.app().getOpenLedger());
auto const open = env.current(); auto const open = env.current();
ApplyViewImpl v0(&*open, TapNone); ApplyViewImpl v0(&*open, ApplyFlags::None);
v0.rawInsert(sle(1, 1)); v0.rawInsert(sle(1, 1));
v0.rawInsert(sle(2, 2)); v0.rawInsert(sle(2, 2));
v0.rawInsert(sle(4, 4)); v0.rawInsert(sle(4, 4));
@@ -368,22 +368,22 @@ class View_test : public beast::unit_test::Suite
BEAST_EXPECT(v1.seq() == v0.seq()); BEAST_EXPECT(v1.seq() == v0.seq());
BEAST_EXPECT(v1.parentCloseTime() == v1.parentCloseTime()); BEAST_EXPECT(v1.parentCloseTime() == v1.parentCloseTime());
ApplyViewImpl v2(&v1, TapRetry); ApplyViewImpl v2(&v1, ApplyFlags::Retry);
BEAST_EXPECT(v2.parentCloseTime() == v1.parentCloseTime()); BEAST_EXPECT(v2.parentCloseTime() == v1.parentCloseTime());
BEAST_EXPECT(v2.seq() == v1.seq()); BEAST_EXPECT(v2.seq() == v1.seq());
BEAST_EXPECT(v2.flags() == TapRetry); BEAST_EXPECT(v2.flags() == ApplyFlags::Retry);
Sandbox const v3(&v2); Sandbox const v3(&v2);
BEAST_EXPECT(v3.seq() == v2.seq()); BEAST_EXPECT(v3.seq() == v2.seq());
BEAST_EXPECT(v3.parentCloseTime() == v2.parentCloseTime()); BEAST_EXPECT(v3.parentCloseTime() == v2.parentCloseTime());
BEAST_EXPECT(v3.flags() == TapRetry); BEAST_EXPECT(v3.flags() == ApplyFlags::Retry);
} }
{ {
ApplyViewImpl v1(&v0, TapRetry); ApplyViewImpl v1(&v0, ApplyFlags::Retry);
PaymentSandbox v2(&v1); PaymentSandbox v2(&v1);
BEAST_EXPECT(v2.seq() == v0.seq()); BEAST_EXPECT(v2.seq() == v0.seq());
BEAST_EXPECT(v2.parentCloseTime() == v0.parentCloseTime()); BEAST_EXPECT(v2.parentCloseTime() == v0.parentCloseTime());
BEAST_EXPECT(v2.flags() == TapRetry); BEAST_EXPECT(v2.flags() == ApplyFlags::Retry);
PaymentSandbox const v3(&v2); PaymentSandbox const v3(&v2);
BEAST_EXPECT(v3.seq() == v2.seq()); BEAST_EXPECT(v3.seq() == v2.seq());
BEAST_EXPECT(v3.parentCloseTime() == v2.parentCloseTime()); BEAST_EXPECT(v3.parentCloseTime() == v2.parentCloseTime());
@@ -1028,7 +1028,7 @@ class View_test : public beast::unit_test::Suite
wipe(*ledger); wipe(*ledger);
ledger->rawInsert(sle(1)); ledger->rawInsert(sle(1));
ReadView const& v0 = *ledger; ReadView const& v0 = *ledger;
ApplyViewImpl v1(&v0, TapNone); ApplyViewImpl v1(&v0, ApplyFlags::None);
{ {
Sandbox v2(&v1); Sandbox v2(&v1);
v2.erase(v2.peek(k(1))); v2.erase(v2.peek(k(1)));
+103
View File
@@ -0,0 +1,103 @@
#include <xrpl/beast/utility/Journal.h>
#include <gtest/gtest.h>
#include <cstddef>
#include <string>
namespace beast {
namespace {
// Counts the messages that actually reach the sink, so the tests can assert on
// which severities the journal let through.
class CountingSink : public Journal::Sink
{
std::size_t count_{0};
public:
CountingSink() : Sink(Severity::Warning, false)
{
}
[[nodiscard]] std::size_t
count() const
{
return count_;
}
void
write(Severity level, std::string const&) override
{
if (level >= threshold())
++count_;
}
void
writeAlways(Severity, std::string const&) override
{
++count_;
}
};
} // namespace
TEST(Journal, info_threshold)
{
CountingSink sink;
sink.threshold(Severity::Info);
Journal const j(sink);
j.trace() << " ";
EXPECT_EQ(sink.count(), 0uz);
j.debug() << " ";
EXPECT_EQ(sink.count(), 0uz);
j.info() << " ";
EXPECT_EQ(sink.count(), 1uz);
j.warn() << " ";
EXPECT_EQ(sink.count(), 2uz);
j.error() << " ";
EXPECT_EQ(sink.count(), 3uz);
j.fatal() << " ";
EXPECT_EQ(sink.count(), 4uz);
}
TEST(Journal, debug_threshold)
{
CountingSink sink;
sink.threshold(Severity::Debug);
Journal const j(sink);
j.trace() << " ";
EXPECT_EQ(sink.count(), 0uz);
j.debug() << " ";
EXPECT_EQ(sink.count(), 1uz);
j.info() << " ";
EXPECT_EQ(sink.count(), 2uz);
j.warn() << " ";
EXPECT_EQ(sink.count(), 3uz);
j.error() << " ";
EXPECT_EQ(sink.count(), 4uz);
j.fatal() << " ";
EXPECT_EQ(sink.count(), 5uz);
}
// A Journal holds a reference to its sink rather than a copy of the threshold,
// so lowering the threshold has to take effect on a Journal that already exists.
// The two tests above each build the Journal after setting the threshold, so
// neither of them would notice if that stopped working.
TEST(Journal, threshold_change_applies_to_an_existing_journal)
{
CountingSink sink;
sink.threshold(Severity::Info);
Journal const j(sink);
j.debug() << " ";
EXPECT_EQ(sink.count(), 0uz);
sink.threshold(Severity::Debug);
j.debug() << " ";
EXPECT_EQ(sink.count(), 1uz);
}
} // namespace beast
@@ -0,0 +1,14 @@
#include <xrpl/beast/clock/basic_seconds_clock.h>
#include <gtest/gtest.h>
namespace beast {
// The clock keeps a lazily started background thread; this only asserts that
// asking it for the time does not throw or crash.
TEST(BasicSecondsClock, now)
{
EXPECT_NO_THROW({ BasicSecondsClock::now(); });
}
} // namespace beast
+147
View File
@@ -0,0 +1,147 @@
#include <xrpl/beast/hash/xxhasher.h>
#include <gtest/gtest.h>
#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
namespace beast {
namespace {
constexpr std::string_view kInput{"Hello, xxHash!"};
constexpr std::uint32_t kSeed{102};
constexpr std::uint32_t kOtherSeed{103};
// The multiple-update and one-update cases hash the same kRepeatCount copies of
// kInput, so their expected digests must agree.
constexpr std::size_t kRepeatCount{100};
constexpr std::size_t kBigObjectRepeat{20};
// Returns text repeated the given number of times.
//
// Used by the cases that hash a large object in one update, so that their
// expected digest can be compared against the cases that feed the same bytes
// in as many small updates.
std::string
repeat(std::string_view text, std::size_t times)
{
std::string out;
out.reserve(text.size() * times);
for (std::size_t i = 0; i < times; ++i)
out += text;
return out;
}
} // namespace
TEST(XXHasher, without_seed)
{
Xxhasher hasher{};
hasher(kInput.data(), kInput.size());
EXPECT_EQ(static_cast<Xxhasher::result_type>(hasher), 16042857369214894119ULL);
}
TEST(XXHasher, with_seed)
{
Xxhasher hasher{kSeed};
hasher(kInput.data(), kInput.size());
EXPECT_EQ(static_cast<Xxhasher::result_type>(hasher), 14440132435660934800ULL);
}
TEST(XXHasher, with_two_seeds)
{
Xxhasher hasher{kSeed, kOtherSeed};
hasher(kInput.data(), kInput.size());
// The second seed is ignored, so this matches the single-seed result.
EXPECT_EQ(static_cast<Xxhasher::result_type>(hasher), 14440132435660934800ULL);
}
// Feeds the bytes in as kRepeatCount small updates, never materializing the full object.
// big_object_with_one_update_without_seed below hashes the same bytes in a single
// update and must agree, which is what exercises xxHash's internal buffering.
TEST(XXHasher, big_object_with_multiple_small_updates_without_seed)
{
Xxhasher hasher{};
for (std::size_t i = 0; i < kRepeatCount; ++i)
hasher(kInput.data(), kInput.size());
EXPECT_EQ(static_cast<Xxhasher::result_type>(hasher), 15296278154063476002ULL);
}
TEST(XXHasher, big_object_with_multiple_small_updates_with_seed)
{
Xxhasher hasher{kOtherSeed};
for (std::size_t i = 0; i < kRepeatCount; ++i)
hasher(kInput.data(), kInput.size());
EXPECT_EQ(static_cast<Xxhasher::result_type>(hasher), 17285302196561698791ULL);
}
TEST(XXHasher, big_object_with_small_and_big_updates_without_seed)
{
Xxhasher hasher{};
std::string const bigObject = repeat(kInput, kBigObjectRepeat);
hasher(kInput.data(), kInput.size());
hasher(bigObject.data(), bigObject.size());
hasher(kInput.data(), kInput.size());
EXPECT_EQ(static_cast<Xxhasher::result_type>(hasher), 1865045178324729219ULL);
}
TEST(XXHasher, big_object_with_small_and_big_updates_with_seed)
{
Xxhasher hasher{kOtherSeed};
std::string const bigObject = repeat(kInput, kBigObjectRepeat);
hasher(kInput.data(), kInput.size());
hasher(bigObject.data(), bigObject.size());
hasher(kInput.data(), kInput.size());
EXPECT_EQ(static_cast<Xxhasher::result_type>(hasher), 16189862915636005281ULL);
}
TEST(XXHasher, big_object_with_one_update_without_seed)
{
Xxhasher hasher{};
std::string const object = repeat(kInput, kRepeatCount);
hasher(object.data(), object.size());
// Hashing the whole object at once must match hashing it in kRepeatCount pieces.
EXPECT_EQ(static_cast<Xxhasher::result_type>(hasher), 15296278154063476002ULL);
}
TEST(XXHasher, big_object_with_one_update_with_seed)
{
Xxhasher hasher{kOtherSeed};
std::string const object = repeat(kInput, kRepeatCount);
hasher(object.data(), object.size());
EXPECT_EQ(static_cast<Xxhasher::result_type>(hasher), 17285302196561698791ULL);
}
TEST(XXHasher, operator_result_type_does_not_change_internal_state)
{
{
Xxhasher hasher;
std::string const object{"Hello xxhash"};
hasher(object.data(), object.size());
EXPECT_EQ(
static_cast<Xxhasher::result_type>(hasher), static_cast<Xxhasher::result_type>(hasher));
}
{
Xxhasher hasher;
std::string const object = repeat(kInput, kRepeatCount);
hasher(object.data(), object.size());
EXPECT_EQ(hasher.operator Xxhasher::result_type(), hasher.operator Xxhasher::result_type());
}
}
} // namespace beast
+4 -2
View File
@@ -107,7 +107,8 @@ TxTest::getRules() const
[[nodiscard]] TxResult [[nodiscard]] TxResult
TxTest::submit(std::shared_ptr<STTx const> stx) TxTest::submit(std::shared_ptr<STTx const> stx)
{ {
auto result = apply(registry_, *openLedger_, *stx, TapNone, registry_.getJournal("apply")); auto result =
apply(registry_, *openLedger_, *stx, ApplyFlags::None, registry_.getJournal("apply"));
// Track successfully applied transactions for canonical reordering on close // Track successfully applied transactions for canonical reordering on close
// We make a copy since the TransactionBase doesn't own the STTx // We make a copy since the TransactionBase doesn't own the STTx
@@ -198,7 +199,8 @@ TxTest::close()
OpenView accum(&*newLedger); OpenView accum(&*newLedger);
for (auto const& [key, tx] : txSet) for (auto const& [key, tx] : txSet)
{ {
auto result = apply(registry_, accum, *tx, TapNone, registry_.getJournal("apply")); auto result =
apply(registry_, accum, *tx, ApplyFlags::None, registry_.getJournal("apply"));
if (!result.applied) if (!result.applied)
{ {
throw std::runtime_error("TxTest::close: failed to apply transaction"); throw std::runtime_error("TxTest::close: failed to apply transaction");
+1 -1
View File
@@ -32,7 +32,7 @@ public:
Account const bob{"bob"}; Account const bob{"bob"};
Account const carol{"carol"}; Account const carol{"carol"};
EntryTestEnv() : av_(&fundAndClose(), TapNone) EntryTestEnv() : av_(&fundAndClose(), ApplyFlags::None)
{ {
} }
+7 -7
View File
@@ -204,7 +204,7 @@ TEST_F(SLEBaseTests, adopt_sle)
TEST_F(SLEBaseTests, writable_accessors) TEST_F(SLEBaseTests, writable_accessors)
{ {
ApplyViewImpl av(&env_.getClosedLedger(), TapNone); ApplyViewImpl av(&env_.getClosedLedger(), ApplyFlags::None);
beast::Journal const j{beast::Journal::getNullSink()}; beast::Journal const j{beast::Journal::getNullSink()};
AccountRootEntryW account(alice_.id(), av, j); AccountRootEntryW account(alice_.id(), av, j);
@@ -239,7 +239,7 @@ TEST_F(SLEBaseTests, writable_accessors)
TEST_F(SLEBaseTests, apply_view_context_ctor) TEST_F(SLEBaseTests, apply_view_context_ctor)
{ {
ApplyViewImpl av(&env_.getClosedLedger(), TapNone); ApplyViewImpl av(&env_.getClosedLedger(), ApplyFlags::None);
beast::Journal const j{beast::Journal::getNullSink()}; beast::Journal const j{beast::Journal::getNullSink()};
transactions::AccountSetBuilder builder{alice_.id()}; transactions::AccountSetBuilder builder{alice_.id()};
@@ -264,7 +264,7 @@ TEST_F(SLEBaseTests, apply_view_context_ctor)
TEST_F(SLEBaseTests, writable_lifecycle) TEST_F(SLEBaseTests, writable_lifecycle)
{ {
// A view we never apply, so nothing here reaches the ledger. // A view we never apply, so nothing here reaches the ledger.
ApplyViewImpl av(&env_.getClosedLedger(), TapNone); ApplyViewImpl av(&env_.getClosedLedger(), ApplyFlags::None);
// Entry that does not exist yet: newSLE() -> insert(). // Entry that does not exist yet: newSLE() -> insert().
{ {
@@ -289,7 +289,7 @@ TEST_F(SLEBaseTests, writable_lifecycle)
// Erase but not Cache, so it shows the difference: building the entry // Erase but not Cache, so it shows the difference: building the entry
// only peeks, and the write is invisible to the view until update(). // only peeks, and the write is invisible to the view until update().
{ {
ApplyViewImpl fresh(&env_.getClosedLedger(), TapNone); ApplyViewImpl fresh(&env_.getClosedLedger(), ApplyFlags::None);
AccountRootEntryW account(alice_.id(), fresh); AccountRootEntryW account(alice_.id(), fresh);
EXPECT_TRUE(account.exists()); EXPECT_TRUE(account.exists());
@@ -321,7 +321,7 @@ TEST_F(SLEBaseTests, writable_lifecycle)
TEST_F(SLEBaseTests, conversion) TEST_F(SLEBaseTests, conversion)
{ {
ApplyViewImpl av(&env_.getClosedLedger(), TapNone); ApplyViewImpl av(&env_.getClosedLedger(), ApplyFlags::None);
AccountRootEntryW const writable(alice_.id(), av); AccountRootEntryW const writable(alice_.id(), av);
EXPECT_TRUE(writable.exists()); EXPECT_TRUE(writable.exists());
@@ -346,7 +346,7 @@ TEST_F(SLEBaseTests, resolve_entry_peeks)
AccountRootEntryR const overLedger(alice_.id(), ledger); AccountRootEntryR const overLedger(alice_.id(), ledger);
EXPECT_TRUE(overLedger.exists()); EXPECT_TRUE(overLedger.exists());
ApplyViewImpl av(&ledger, TapNone); ApplyViewImpl av(&ledger, ApplyFlags::None);
// ReadView const& binds an ApplyViewImpl just as happily, and there the // ReadView const& binds an ApplyViewImpl just as happily, and there the
// dynamic_cast succeeds, so this one resolves through ApplyView::peek(). // dynamic_cast succeeds, so this one resolves through ApplyView::peek().
@@ -393,7 +393,7 @@ TEST_F(SLEBaseTests, throws_on_missing_entry)
TEST_F(SLEBaseTests, throws_on_missing_writable_entry) TEST_F(SLEBaseTests, throws_on_missing_writable_entry)
{ {
// A view we never apply, so nothing here reaches the ledger. // A view we never apply, so nothing here reaches the ledger.
ApplyViewImpl av(&env_.getClosedLedger(), TapNone); ApplyViewImpl av(&env_.getClosedLedger(), ApplyFlags::None);
// bob is unfunded, so this resolves to nothing and every operation that // bob is unfunded, so this resolves to nothing and every operation that
// needs an SLE has to throw instead of dereferencing null. These are the // needs an SLE has to throw instead of dereferencing null. These are the
+2 -2
View File
@@ -655,7 +655,7 @@ RCLConsensus::Adaptor::doAccept(
localTxs_.getTxSet(), localTxs_.getTxSet(),
anyDisputes, anyDisputes,
retriableTxs, retriableTxs,
TapNone, ApplyFlags::None,
"consensus", "consensus",
[&](OpenView& view, beast::Journal j) { [&](OpenView& view, beast::Journal j) {
// Stuff the ledger with transactions from the queue. // Stuff the ledger with transactions from the queue.
@@ -760,7 +760,7 @@ RCLConsensus::Adaptor::buildLCL(
XRPL_ASSERT( XRPL_ASSERT(
replayData->parent()->header().hash == previousLedger.id(), replayData->parent()->header().hash == previousLedger.id(),
"xrpl::RCLConsensus::Adaptor::buildLCL : parent hash match"); "xrpl::RCLConsensus::Adaptor::buildLCL : parent hash match");
return buildLedger(*replayData, TapNone, app_, j_); return buildLedger(*replayData, ApplyFlags::None, app_, j_);
} }
return buildLedger( return buildLedger(
previousLedger.ledger, previousLedger.ledger,
+2 -2
View File
@@ -14,7 +14,7 @@
#include <xrpl/core/Job.h> #include <xrpl/core/Job.h>
#include <xrpl/core/JobQueue.h> #include <xrpl/core/JobQueue.h>
#include <xrpl/core/PerfLog.h> #include <xrpl/core/PerfLog.h>
#include <xrpl/protocol/Indexes.h> #include <xrpl/ledger/entries/LedgerHashesEntry.h>
#include <xrpl/protocol/PublicKey.h> #include <xrpl/protocol/PublicKey.h>
#include <xrpl/protocol/RippleLedgerHash.h> #include <xrpl/protocol/RippleLedgerHash.h>
#include <xrpl/protocol/SField.h> #include <xrpl/protocol/SField.h>
@@ -36,7 +36,7 @@ RCLValidatedLedger::RCLValidatedLedger(
beast::Journal j) beast::Journal j)
: ledgerID_{ledger->header().hash}, ledgerSeq_{ledger->seq()}, j_{j} : ledgerID_{ledger->header().hash}, ledgerSeq_{ledger->seq()}, j_{j}
{ {
auto const hashIndex = ledger->read(keylet::skip()); LedgerHashesEntryR const hashIndex(*ledger, j_);
if (hashIndex) if (hashIndex)
{ {
XRPL_ASSERT( XRPL_ASSERT(
+3 -2
View File
@@ -12,6 +12,7 @@
#include <xrpl/ledger/CanonicalTXSet.h> #include <xrpl/ledger/CanonicalTXSet.h>
#include <xrpl/ledger/Ledger.h> #include <xrpl/ledger/Ledger.h>
#include <xrpl/ledger/OpenView.h> #include <xrpl/ledger/OpenView.h>
#include <xrpl/ledger/entries/FeeSettingsEntry.h>
#include <xrpl/nodestore/NodeObject.h> #include <xrpl/nodestore/NodeObject.h>
#include <xrpl/protocol/Indexes.h> // IWYU pragma: keep #include <xrpl/protocol/Indexes.h> // IWYU pragma: keep
#include <xrpl/protocol/LedgerHeader.h> #include <xrpl/protocol/LedgerHeader.h>
@@ -74,7 +75,7 @@ buildLedgerImpl(
// Accept ledger // Accept ledger
XRPL_ASSERT( XRPL_ASSERT(
built->header().seq < kXrpLedgerEarliestFees || built->read(keylet::feeSettings()), built->header().seq < kXrpLedgerEarliestFees || FeeSettingsEntryR(*built),
"xrpl::buildLedgerImpl : valid ledger fees"); "xrpl::buildLedgerImpl : valid ledger fees");
built->setAccepted(closeTime, closeResolution, closeTimeCorrect); built->setAccepted(closeTime, closeResolution, closeTimeCorrect);
@@ -125,7 +126,7 @@ applyTransactions(
continue; continue;
} }
switch (applyTransaction(app, view, *it->second, certainRetry, TapNone, j)) switch (applyTransaction(app, view, *it->second, certainRetry, ApplyFlags::None, j))
{ {
case ApplyTransactionResult::Success: case ApplyTransactionResult::Success:
it = txns.erase(it); it = txns.erase(it);
@@ -19,6 +19,7 @@
#include <xrpl/core/Job.h> #include <xrpl/core/Job.h>
#include <xrpl/core/JobQueue.h> #include <xrpl/core/JobQueue.h>
#include <xrpl/json/json_value.h> #include <xrpl/json/json_value.h>
#include <xrpl/ledger/entries/FeeSettingsEntry.h>
#include <xrpl/nodestore/Database.h> #include <xrpl/nodestore/Database.h>
#include <xrpl/nodestore/NodeObject.h> #include <xrpl/nodestore/NodeObject.h>
#include <xrpl/protocol/HashPrefix.h> #include <xrpl/protocol/HashPrefix.h>
@@ -110,7 +111,7 @@ InboundLedger::init(ScopedLockType& collectionLock)
JLOG(journal_.debug()) << "Acquiring ledger we already have in " JLOG(journal_.debug()) << "Acquiring ledger we already have in "
<< " local store. " << hash_; << " local store. " << hash_;
XRPL_ASSERT( XRPL_ASSERT(
ledger_->header().seq < kXrpLedgerEarliestFees || ledger_->read(keylet::feeSettings()), ledger_->header().seq < kXrpLedgerEarliestFees || FeeSettingsEntryR(*ledger_),
"xrpl::InboundLedger::init : valid ledger fees"); "xrpl::InboundLedger::init : valid ledger fees");
ledger_->setImmutable(); ledger_->setImmutable();
@@ -331,7 +332,7 @@ InboundLedger::tryDB(node_store::Database& srcDB)
JLOG(journal_.debug()) << "Had everything locally"; JLOG(journal_.debug()) << "Had everything locally";
complete_ = true; complete_ = true;
XRPL_ASSERT( XRPL_ASSERT(
ledger_->header().seq < kXrpLedgerEarliestFees || ledger_->read(keylet::feeSettings()), ledger_->header().seq < kXrpLedgerEarliestFees || FeeSettingsEntryR(*ledger_),
"xrpl::InboundLedger::tryDB : valid ledger fees"); "xrpl::InboundLedger::tryDB : valid ledger fees");
ledger_->setImmutable(); ledger_->setImmutable();
} }
@@ -430,7 +431,7 @@ InboundLedger::done()
if (complete_ && !failed_ && ledger_) if (complete_ && !failed_ && ledger_)
{ {
XRPL_ASSERT( XRPL_ASSERT(
ledger_->header().seq < kXrpLedgerEarliestFees || ledger_->read(keylet::feeSettings()), ledger_->header().seq < kXrpLedgerEarliestFees || FeeSettingsEntryR(*ledger_),
"xrpl::InboundLedger::done : valid ledger fees"); "xrpl::InboundLedger::done : valid ledger fees");
ledger_->setImmutable(); ledger_->setImmutable();
switch (reason_) switch (reason_)
@@ -205,7 +205,7 @@ LedgerDeltaAcquire::tryBuild(std::shared_ptr<Ledger const> const& parent)
"xrpl::LedgerDeltaAcquire::tryBuild : parent hash match"); "xrpl::LedgerDeltaAcquire::tryBuild : parent hash match");
// build ledger // build ledger
LedgerReplay const replayData(parent, replayTemp_, std::move(orderedTxns_)); LedgerReplay const replayData(parent, replayTemp_, std::move(orderedTxns_));
fullLedger_ = buildLedger(replayData, TapNone, app_, journal_); fullLedger_ = buildLedger(replayData, ApplyFlags::None, app_, journal_);
if (fullLedger_ && fullLedger_->header().hash == hash_) if (fullLedger_ && fullLedger_->header().hash == hash_)
{ {
JLOG(journal_.info()) << "Built " << hash_; JLOG(journal_.info()) << "Built " << hash_;
@@ -8,6 +8,7 @@
#include <xrpl/core/JobQueue.h> #include <xrpl/core/JobQueue.h>
#include <xrpl/core/ServiceRegistry.h> #include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/PendingSaves.h> #include <xrpl/ledger/PendingSaves.h>
#include <xrpl/ledger/entries/FeeSettingsEntry.h>
#include <xrpl/protocol/Indexes.h> // IWYU pragma: keep #include <xrpl/protocol/Indexes.h> // IWYU pragma: keep
#include <xrpl/protocol/Rules.h> #include <xrpl/protocol/Rules.h>
#include <xrpl/protocol/SystemParameters.h> // IWYU pragma: keep #include <xrpl/protocol/SystemParameters.h> // IWYU pragma: keep
@@ -122,7 +123,7 @@ finishLoadByIndexOrHash(std::shared_ptr<Ledger> const& ledger, beast::Journal j)
return; return;
XRPL_ASSERT( XRPL_ASSERT(
ledger->header().seq < kXrpLedgerEarliestFees || ledger->read(keylet::feeSettings()), ledger->header().seq < kXrpLedgerEarliestFees || FeeSettingsEntryR(*ledger),
"xrpl::finishLoadByIndexOrHash : valid ledger fees"); "xrpl::finishLoadByIndexOrHash : valid ledger fees");
ledger->setImmutable(); ledger->setImmutable();
+1 -1
View File
@@ -178,7 +178,7 @@ OpenLedger::applyOne(
beast::Journal j) -> Result beast::Journal j) -> Result
{ {
if (retry) if (retry)
flags = flags | TapRetry; flags = flags | ApplyFlags::Retry;
// If it's in anybody's proposed set, try to keep it in the ledger // If it's in anybody's proposed set, try to keep it in the ledger
auto const result = xrpl::apply(app, view, *tx, flags, j); auto const result = xrpl::apply(app, view, *tx, flags, j);
if (result.applied || result.ter == terQUEUED) if (result.applied || result.ter == terQUEUED)
@@ -13,6 +13,7 @@
#include <xrpl/basics/base_uint.h> #include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/Job.h> #include <xrpl/core/Job.h>
#include <xrpl/ledger/entries/LedgerHashesEntry.h>
#include <xrpl/protocol/Indexes.h> #include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h> #include <xrpl/protocol/SField.h>
#include <xrpl/shamap/SHAMapItem.h> #include <xrpl/shamap/SHAMapItem.h>
@@ -183,7 +184,7 @@ SkipListAcquire::getData() const
void void
SkipListAcquire::retrieveSkipList(std::shared_ptr<Ledger const> const& ledger, ScopedLockType& sl) SkipListAcquire::retrieveSkipList(std::shared_ptr<Ledger const> const& ledger, ScopedLockType& sl)
{ {
if (auto const hashIndex = ledger->read(keylet::skip()); if (LedgerHashesEntryR const hashIndex(*ledger, journal_);
hashIndex && hashIndex->isFieldPresent(sfHashes)) hashIndex && hashIndex->isFieldPresent(sfHashes))
{ {
auto const& slist = hashIndex->getFieldV256(sfHashes).value(); auto const& slist = hashIndex->getFieldV256(sfHashes).value();
+4 -4
View File
@@ -72,6 +72,7 @@
#include <xrpl/ledger/Ledger.h> #include <xrpl/ledger/Ledger.h>
#include <xrpl/ledger/OpenView.h> #include <xrpl/ledger/OpenView.h>
#include <xrpl/ledger/PendingSaves.h> #include <xrpl/ledger/PendingSaves.h>
#include <xrpl/ledger/entries/FeeSettingsEntry.h>
#include <xrpl/nodestore/Database.h> #include <xrpl/nodestore/Database.h>
#include <xrpl/nodestore/DummyScheduler.h> #include <xrpl/nodestore/DummyScheduler.h>
#include <xrpl/nodestore/Manager.h> #include <xrpl/nodestore/Manager.h>
@@ -1700,7 +1701,7 @@ ApplicationImp::startGenesisLedger()
auto const next = std::make_shared<Ledger>(*genesis, getTimeKeeper().closeTime()); auto const next = std::make_shared<Ledger>(*genesis, getTimeKeeper().closeTime());
next->updateSkipList(); next->updateSkipList();
XRPL_ASSERT( XRPL_ASSERT(
next->header().seq < kXrpLedgerEarliestFees || next->read(keylet::feeSettings()), next->header().seq < kXrpLedgerEarliestFees || FeeSettingsEntryR(*next),
"xrpl::ApplicationImp::startGenesisLedger : valid ledger fees"); "xrpl::ApplicationImp::startGenesisLedger : valid ledger fees");
next->setImmutable(); next->setImmutable();
openLedger_.emplace(next, cachedSLEs_, logs_->journal("OpenLedger")); openLedger_.emplace(next, cachedSLEs_, logs_->journal("OpenLedger"));
@@ -1722,7 +1723,7 @@ ApplicationImp::getLastFullLedger()
return ledger; return ledger;
XRPL_ASSERT( XRPL_ASSERT(
ledger->header().seq < kXrpLedgerEarliestFees || ledger->read(keylet::feeSettings()), ledger->header().seq < kXrpLedgerEarliestFees || FeeSettingsEntryR(*ledger),
"xrpl::ApplicationImp::getLastFullLedger : valid ledger fees"); "xrpl::ApplicationImp::getLastFullLedger : valid ledger fees");
ledger->setImmutable(); ledger->setImmutable();
@@ -1873,8 +1874,7 @@ ApplicationImp::loadLedgerFromFile(std::string const& name)
loadLedger->stateMap().flushDirty(NodeObjectType::AccountNode); loadLedger->stateMap().flushDirty(NodeObjectType::AccountNode);
XRPL_ASSERT( XRPL_ASSERT(
loadLedger->header().seq < kXrpLedgerEarliestFees || loadLedger->header().seq < kXrpLedgerEarliestFees || FeeSettingsEntryR(*loadLedger),
loadLedger->read(keylet::feeSettings()),
"xrpl::ApplicationImp::loadLedgerFromFile : valid ledger fees"); "xrpl::ApplicationImp::loadLedgerFromFile : valid ledger fees");
loadLedger->setAccepted(closeTime, closeTimeResolution, !closeTimeEstimated); loadLedger->setAccepted(closeTime, closeTimeResolution, !closeTimeEstimated);
+12 -17
View File
@@ -226,27 +226,22 @@ FeeVoteImpl::doVoting(
auto doVote = [](std::shared_ptr<STValidation> const& val, auto doVote = [](std::shared_ptr<STValidation> const& val,
detail::VotableValue& value, detail::VotableValue& value,
auto const& valueField) { auto const& valueField) {
if (auto const field = val->at(~valueField)) using XRPType = XRPAmount::value_type;
if (auto const field = val->at(~valueField); field && std::in_range<XRPType>(*field))
{ {
using XRPType = XRPAmount::value_type; if (auto const amount = XRPAmount{checkedCast<XRPType>(*field)};
auto const vote = *field; isLegalAmountSigned(amount))
if (vote <= std::numeric_limits<XRPType>::max() &&
isLegalAmountSigned(XRPAmount{unsafeCast<XRPType>(vote)}))
{ {
value.addVote(XRPAmount{unsafeCast<XRPType>(vote)}); value.addVote(amount);
} return;
else
{
// Invalid amounts will be treated as if they're
// not provided. Don't throw because this value is
// provided by an external entity.
value.noVote();
} }
} }
else
{ // Invalid or missing amounts are treated as if they're not
value.noVote(); // provided. Don't throw because this value is provided by an
} // external entity.
value.noVote();
}; };
for (auto const& val : set) for (auto const& val : set)
+2 -2
View File
@@ -8,7 +8,7 @@
#include <xrpl/beast/utility/Journal.h> #include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/instrumentation.h> #include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/Ledger.h> #include <xrpl/ledger/Ledger.h>
#include <xrpl/protocol/Indexes.h> #include <xrpl/ledger/entries/LedgerHashesEntry.h>
#include <xrpl/protocol/Protocol.h> #include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/PublicKey.h> #include <xrpl/protocol/PublicKey.h>
#include <xrpl/protocol/SField.h> #include <xrpl/protocol/SField.h>
@@ -170,7 +170,7 @@ NegativeUNLVote::buildScoreTable(
validations.setSeqToKeep(seq - 1, seq + kFlagLedgerInterval); validations.setSeqToKeep(seq - 1, seq + kFlagLedgerInterval);
// Find FLAG_LEDGER_INTERVAL (i.e. 256) previous ledger hashes // Find FLAG_LEDGER_INTERVAL (i.e. 256) previous ledger hashes
auto const hashIndex = prevLedger->read(keylet::skip()); LedgerHashesEntryR const hashIndex(*prevLedger, j_);
if (!hashIndex || !hashIndex->isFieldPresent(sfHashes)) if (!hashIndex || !hashIndex->isFieldPresent(sfHashes))
{ {
JLOG(j_.debug()) << "N-UNL: ledger " << seq << " no history."; JLOG(j_.debug()) << "N-UNL: ledger " << seq << " no history.";
+4 -4
View File
@@ -1706,12 +1706,12 @@ NetworkOPsImp::apply(std::unique_lock<std::mutex>& batchLock)
for (TransactionStatus& e : transactions) for (TransactionStatus& e : transactions)
{ {
// we check before adding to the batch // we check before adding to the batch
ApplyFlags flags = TapNone; ApplyFlags flags = ApplyFlags::None;
if (e.admin) if (e.admin)
flags |= TapUnlimited; flags |= ApplyFlags::Unlimited;
if (e.failType == FailHard::Yes) if (e.failType == FailHard::Yes)
flags |= TapFailHard; flags |= ApplyFlags::FailHard;
auto const result = registry_.get().getTxQ().apply( auto const result = registry_.get().getTxQ().apply(
registry_.get().getApp(), view, e.transaction->getSTransaction(), flags, j); registry_.get().getApp(), view, e.transaction->getSTransaction(), flags, j);
@@ -2207,7 +2207,7 @@ NetworkOPsImp::switchLastClosedLedger(std::shared_ptr<Ledger const> const& newLC
OrderedTxs({}), OrderedTxs({}),
false, false,
retries, retries,
TapNone, ApplyFlags::None,
"jump", "jump",
[&](OpenView& view, beast::Journal j) { [&](OpenView& view, beast::Journal j) {
// Stuff the ledger with transactions from the queue. // Stuff the ledger with transactions from the queue.
+11 -9
View File
@@ -333,8 +333,9 @@ TxQ::MaybeTx::apply(Application& app, OpenView& view, beast::Journal j)
if (pfResult->rules != view.rules() || pfResult->flags != flags) if (pfResult->rules != view.rules() || pfResult->flags != flags)
{ {
JLOG(j.debug()) << "Queued transaction " << txID JLOG(j.debug()) << "Queued transaction " << txID
<< " rules or flags have changed. Flags from " << pfResult->flags << " to " << " rules or flags have changed. Flags from "
<< flags; << std::to_underlying(pfResult->flags) << " to "
<< std::to_underlying(flags);
pfResult.emplace(preflight(app, view.rules(), pfResult->tx, flags, pfResult->j)); pfResult.emplace(preflight(app, view.rules(), pfResult->tx, flags, pfResult->j));
} }
@@ -425,7 +426,7 @@ TxQ::canBeHeld(
// queue yet, but should be added in the future. // queue yet, but should be added in the future.
// TapFailHard transactions are never held // TapFailHard transactions are never held
if (tx.isFieldPresent(sfPreviousTxnID) || tx.isFieldPresent(sfAccountTxnID) || if (tx.isFieldPresent(sfPreviousTxnID) || tx.isFieldPresent(sfAccountTxnID) ||
((flags & TapFailHard) != 0u)) ((flags & ApplyFlags::FailHard) != ApplyFlags::None))
return telCAN_NOT_QUEUE; return telCAN_NOT_QUEUE;
// Disallow delegated transactions from being queued. // Disallow delegated transactions from being queued.
@@ -777,7 +778,7 @@ TxQ::apply(
if (auto directApplied = tryDirectApply(app, view, tx, flags, j)) if (auto directApplied = tryDirectApply(app, view, tx, flags, j))
return *directApplied; return *directApplied;
if ((flags & TapDryRun) != 0u) if ((flags & ApplyFlags::DryRun) != ApplyFlags::None)
return {telCAN_NOT_QUEUE, false}; return {telCAN_NOT_QUEUE, false};
// If we get past tryDirectApply() without returning then we expect // If we get past tryDirectApply() without returning then we expect
@@ -1345,7 +1346,7 @@ TxQ::apply(
// will not be checked again, so the cost should be minimal. // will not be checked again, so the cost should be minimal.
// Don't allow soft failures, which can lead to retries // Don't allow soft failures, which can lead to retries
flags &= ~TapRetry; flags &= ~ApplyFlags::Retry;
auto& candidate = accountIter->second.add({tx, transactionID, feeLevelPaid, flags, pfResult}); auto& candidate = accountIter->second.add({tx, transactionID, feeLevelPaid, flags, pfResult});
@@ -1354,8 +1355,7 @@ TxQ::apply(
JLOG(j_.debug()) << "Added transaction " << candidate.txID << " with result " JLOG(j_.debug()) << "Added transaction " << candidate.txID << " with result "
<< transToken(pfResult.ter) << " from " << transToken(pfResult.ter) << " from "
<< (accountIsInQueue ? "existing" : "new") << " account " << candidate.account << (accountIsInQueue ? "existing" : "new") << " account " << candidate.account
<< " to queue." << " to queue. Flags: " << std::to_underlying(flags);
<< " Flags: " << flags;
return {terQUEUED, false}; return {terQUEUED, false};
} }
@@ -1473,7 +1473,8 @@ TxQ::accept(Application& app, OpenView& view)
candidateIter++; candidateIter++;
continue; continue;
} }
auto const requiredFeeLevel = getRequiredFeeLevel(view, TapNone, metricsSnapshot, lock); auto const requiredFeeLevel =
getRequiredFeeLevel(view, ApplyFlags::None, metricsSnapshot, lock);
auto const feeLevelPaid = candidateIter->feeLevel; auto const feeLevelPaid = candidateIter->feeLevel;
JLOG(j_.trace()) << "Queued transaction " << candidateIter->txID << " from account " JLOG(j_.trace()) << "Queued transaction " << candidateIter->txID << " from account "
<< candidateIter->account << " has fee level of " << feeLevelPaid << candidateIter->account << " has fee level of " << feeLevelPaid
@@ -1515,7 +1516,8 @@ TxQ::accept(Application& app, OpenView& view)
{ {
JLOG(j_.debug()) << "Queued transaction " << candidateIter->txID << " failed with " JLOG(j_.debug()) << "Queued transaction " << candidateIter->txID << " failed with "
<< transToken(txnResult) << ". Leave in queue." << transToken(txnResult) << ". Leave in queue."
<< " Applied: " << didApply << ". Flags: " << candidateIter->flags; << " Applied: " << didApply
<< ". Flags: " << std::to_underlying(candidateIter->flags);
if (account.retryPenalty && candidateIter->retriesRemaining > 2) if (account.retryPenalty && candidateIter->retriesRemaining > 2)
{ {
candidateIter->retriesRemaining = 1; candidateIter->retriesRemaining = 1;
+2 -2
View File
@@ -633,7 +633,7 @@ PathRequest::findPaths(
path::RippleCalc::Input rcInput; path::RippleCalc::Input rcInput;
if (convertAll_) if (convertAll_)
rcInput.partialPaymentAllowed = true; rcInput.partialPaymentAllowed = true;
auto sandbox = std::make_unique<PaymentSandbox>(&*cache->getLedger(), TapNone); auto sandbox = std::make_unique<PaymentSandbox>(&*cache->getLedger(), ApplyFlags::None);
auto rc = path::RippleCalc::rippleCalculate( auto rc = path::RippleCalc::rippleCalculate(
*sandbox, *sandbox,
saMaxAmount, // --> Amount to send is unlimited saMaxAmount, // --> Amount to send is unlimited
@@ -654,7 +654,7 @@ PathRequest::findPaths(
JLOG(journal_.debug()) << iIdentifier_ << " Trying with an extra path element"; JLOG(journal_.debug()) << iIdentifier_ << " Trying with an extra path element";
ps.pushBack(fullLiquidityPath); ps.pushBack(fullLiquidityPath);
sandbox = std::make_unique<PaymentSandbox>(&*cache->getLedger(), TapNone); sandbox = std::make_unique<PaymentSandbox>(&*cache->getLedger(), ApplyFlags::None);
rc = path::RippleCalc::rippleCalculate( rc = path::RippleCalc::rippleCalculate(
*sandbox, *sandbox,
saMaxAmount, // --> Amount to send is unlimited saMaxAmount, // --> Amount to send is unlimited
+3 -3
View File
@@ -392,7 +392,7 @@ Pathfinder::getPathLiquidity(
path::RippleCalc::Input rcInput; path::RippleCalc::Input rcInput;
rcInput.defaultPathsAllowed = false; rcInput.defaultPathsAllowed = false;
PaymentSandbox sandbox(&*ledger_, TapNone); PaymentSandbox sandbox(&*ledger_, ApplyFlags::None);
try try
{ {
@@ -455,7 +455,7 @@ Pathfinder::computePathRanks(int maxPaths, std::function<bool(void)> const& cont
// Must subtract liquidity in default path from remaining amount. // Must subtract liquidity in default path from remaining amount.
try try
{ {
PaymentSandbox sandbox(&*ledger_, TapNone); PaymentSandbox sandbox(&*ledger_, ApplyFlags::None);
path::RippleCalc::Input rcInput; path::RippleCalc::Input rcInput;
rcInput.partialPaymentAllowed = true; rcInput.partialPaymentAllowed = true;
@@ -948,7 +948,7 @@ Pathfinder::isNoRippleOut(STPath const& currentPath)
// Last link must be an account. // Last link must be an account.
STPathElement const& endElement = currentPath.back(); STPathElement const& endElement = currentPath.back();
if ((endElement.getNodeType() & STPathElement::TypeAccount) == 0u) if (!endElement.isType(STPathElement::TypeAccount))
return false; return false;
// If there's only one item in the path, return true if that item specifies // If there's only one item in the path, return true if that item specifies
Loaded 100 of 103 files, more files were not shown because too many files have changed in this diff. Show more