Merge branch 'dev' into remarks

This commit is contained in:
Denis Angell
2024-05-23 08:23:54 +02:00
committed by GitHub
23 changed files with 910 additions and 250 deletions

View File

@@ -986,6 +986,7 @@ if (tests)
src/test/rpc/AccountLinesRPC_test.cpp
src/test/rpc/AccountObjects_test.cpp
src/test/rpc/AccountOffers_test.cpp
src/test/rpc/AccountNamespace_test.cpp
src/test/rpc/AccountSet_test.cpp
src/test/rpc/AccountTx_test.cpp
src/test/rpc/AmendmentBlocked_test.cpp

View File

@@ -52,6 +52,9 @@ Loop: ripple.overlay ripple.rpc
Loop: test.app test.jtx
test.app > test.jtx
Loop: test.app test.rpc
test.rpc == test.app
Loop: test.jtx test.toplevel
test.toplevel > test.jtx

View File

@@ -90,7 +90,6 @@ test.app > ripple.overlay
test.app > ripple.protocol
test.app > ripple.resource
test.app > ripple.rpc
test.app > test.rpc
test.app > test.toplevel
test.app > test.unit_test
test.basics > ripple.basics

View File

@@ -5,11 +5,11 @@
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
// __/ | https://github.com/Neargye/magic_enum
// |___/ version 0.9.3
// |___/ version 0.9.5
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2023 Daniil Goncharov <neargye@gmail.com>.
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -34,7 +34,7 @@
#define MAGIC_ENUM_VERSION_MAJOR 0
#define MAGIC_ENUM_VERSION_MINOR 9
#define MAGIC_ENUM_VERSION_PATCH 3
#define MAGIC_ENUM_VERSION_PATCH 5
#include <array>
#include <cstddef>
@@ -60,7 +60,7 @@
#if defined(MAGIC_ENUM_NO_ASSERT)
# define MAGIC_ENUM_ASSERT(...) static_cast<void>(0)
#else
#elif !defined(MAGIC_ENUM_ASSERT)
# include <cassert>
# define MAGIC_ENUM_ASSERT(...) assert((__VA_ARGS__))
#endif
@@ -69,9 +69,11 @@
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunknown-warning-option"
# pragma clang diagnostic ignored "-Wenum-constexpr-conversion"
# pragma clang diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for char_type = char (common on Linux).
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
# pragma GCC diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for char_type = char (common on Linux).
#elif defined(_MSC_VER)
# pragma warning(push)
# pragma warning(disable : 26495) // Variable 'static_str<N>::chars_' is uninitialized.
@@ -164,14 +166,11 @@ namespace customize {
// If need another range for specific enum type, add specialization enum_range for necessary enum type.
template <typename E>
struct enum_range {
static_assert(std::is_enum_v<E>, "magic_enum::customize::enum_range requires enum type.");
static constexpr int min = MAGIC_ENUM_RANGE_MIN;
static constexpr int max = MAGIC_ENUM_RANGE_MAX;
static_assert(max > min, "magic_enum::customize::enum_range requires max > min.");
};
static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN.");
static_assert((MAGIC_ENUM_RANGE_MAX - MAGIC_ENUM_RANGE_MIN) < (std::numeric_limits<std::uint16_t>::max)(), "MAGIC_ENUM_RANGE must be less than UINT16_MAX.");
namespace detail {
@@ -216,9 +215,9 @@ namespace detail {
template <typename T>
struct supported
#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT)
: std::true_type {};
: std::true_type {};
#else
: std::false_type {};
: std::false_type {};
#endif
template <auto V, typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>, int> = 0>
@@ -423,10 +422,20 @@ constexpr auto n() noexcept {
constexpr auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E);
constexpr auto name = name_ptr ? str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
#elif defined(__clang__)
auto name = str_view{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36};
str_view name;
if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
static_assert(always_false_v<E>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
return str_view{};
} else {
name.size_ = sizeof(__PRETTY_FUNCTION__) - 36;
name.str_ = __PRETTY_FUNCTION__ + 34;
}
#elif defined(__GNUC__)
auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
if (name.str_[name.size_ - 1] == ']') {
if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
static_assert(always_false_v<E>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
return str_view{};
} else if (name.str_[name.size_ - 1] == ']') {
name.size_ -= 50;
name.str_ += 49;
} else {
@@ -489,7 +498,14 @@ constexpr auto n() noexcept {
constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
auto name = name_ptr ? str_view{name_ptr, std::char_traits<char>::length(name_ptr)} : str_view{};
#elif defined(__clang__)
auto name = str_view{__PRETTY_FUNCTION__ + 34, sizeof(__PRETTY_FUNCTION__) - 36};
str_view name;
if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
static_assert(always_false_v<decltype(V)>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
return str_view{};
} else {
name.size_ = sizeof(__PRETTY_FUNCTION__) - 36;
name.str_ = __PRETTY_FUNCTION__ + 34;
}
if (name.size_ > 22 && name.str_[0] == '(' && name.str_[1] == 'a' && name.str_[10] == ' ' && name.str_[22] == ':') {
name.size_ -= 23;
name.str_ += 23;
@@ -499,7 +515,10 @@ constexpr auto n() noexcept {
}
#elif defined(__GNUC__)
auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1};
if (name.str_[name.size_ - 1] == ']') {
if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
static_assert(always_false_v<decltype(V)>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
return str_view{};
} else if (name.str_[name.size_ - 1] == ']') {
name.size_ -= 55;
name.str_ += 54;
} else {
@@ -698,7 +717,7 @@ constexpr void valid_count(bool* valid, std::size_t& count) noexcept {
} \
}
MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_V);
MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_V)
if constexpr ((I + 256) < Size) {
valid_count<E, S, Size, Min, I + 256>(valid, count);
@@ -750,7 +769,6 @@ constexpr auto values() noexcept {
constexpr auto max = reflected_max<E, S>();
constexpr auto range_size = max - min + 1;
static_assert(range_size > 0, "magic_enum::enum_range requires valid size.");
static_assert(range_size < (std::numeric_limits<std::uint16_t>::max)(), "magic_enum::enum_range requires valid size.");
return values<E, S, range_size, min>();
}
@@ -807,7 +825,8 @@ inline constexpr auto max_v = (count_v<E, S> > 0) ? static_cast<U>(values_v<E, S
template <typename E, enum_subtype S, std::size_t... I>
constexpr auto names(std::index_sequence<I...>) noexcept {
return std::array<string_view, sizeof...(I)>{{enum_name_v<E, values_v<E, S>[I]>...}};
constexpr auto names = std::array<string_view, sizeof...(I)>{{enum_name_v<E, values_v<E, S>[I]>...}};
return names;
}
template <typename E, enum_subtype S>
@@ -818,7 +837,8 @@ using names_t = decltype((names_v<D, S>));
template <typename E, enum_subtype S, std::size_t... I>
constexpr auto entries(std::index_sequence<I...>) noexcept {
return std::array<std::pair<E, string_view>, sizeof...(I)>{{{values_v<E, S>[I], enum_name_v<E, values_v<E, S>[I]>}...}};
constexpr auto entries = std::array<std::pair<E, string_view>, sizeof...(I)>{{{values_v<E, S>[I], enum_name_v<E, values_v<E, S>[I]>}...}};
return entries;
}
template <typename E, enum_subtype S>
@@ -845,17 +865,16 @@ constexpr bool is_sparse() noexcept {
template <typename E, enum_subtype S = subtype_v<E>>
inline constexpr bool is_sparse_v = is_sparse<E, S>();
template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
constexpr U values_ors() noexcept {
static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype.");
template <typename E, enum_subtype S>
struct is_reflected
#if defined(MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM)
: std::true_type {};
#else
: std::bool_constant<std::is_enum_v<E> && (count_v<E, S> != 0)> {};
#endif
auto ors = U{0};
for (std::size_t i = 0; i < count_v<E, S>; ++i) {
ors |= static_cast<U>(values_v<E, S>[i]);
}
return ors;
}
template <typename E, enum_subtype S>
inline constexpr bool is_reflected_v = is_reflected<std::decay_t<E>, S>{};
template <bool, typename R>
struct enable_if_enum {};
@@ -1156,6 +1175,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
using D = std::decay_t<E>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
if constexpr (detail::is_sparse_v<D, S>) {
return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::values_v<D, S>[index];
@@ -1170,6 +1190,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
template <typename E, std::size_t I, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
using D = std::decay_t<E>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
static_assert(I < detail::count_v<D, S>, "magic_enum::enum_value out of range.");
return enum_value<D, S>(I);
@@ -1178,7 +1199,10 @@ template <typename E, std::size_t I, detail::enum_subtype S = detail::subtype_v<
// Returns std::array with enum values, sorted by enum value.
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t<E, detail::values_t<E, S>> {
return detail::values_v<std::decay_t<E>, S>;
using D = std::decay_t<E>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
return detail::values_v<D, S>;
}
// Returns integer value from enum value.
@@ -1199,11 +1223,9 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
return {}; // Empty enum.
} else if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
#if defined(MAGIC_ENUM_ENABLE_HASH)
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::index>(
[](std::size_t i) { return optional<std::size_t>{i}; },
@@ -1231,14 +1253,17 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
template <detail::enum_subtype S, typename E>
[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
using D = std::decay_t<E>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
return enum_index<D, S>(value);
}
// Obtains index in enum values from static storage enum variable.
template <auto V, detail::enum_subtype S = detail::subtype_v<std::decay_t<decltype(V)>>>
[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t<decltype(V), std::size_t> {
constexpr auto index = enum_index<std::decay_t<decltype(V)>, S>(V);
[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t<decltype(V), std::size_t> {\
using D = std::decay_t<decltype(V)>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
constexpr auto index = enum_index<D, S>(V);
static_assert(index, "magic_enum::enum_index enum value does not have a index.");
return *index;
@@ -1259,6 +1284,7 @@ template <auto V>
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t<E, string_view> {
using D = std::decay_t<E>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
if (const auto i = enum_index<D, S>(value)) {
return detail::names_v<D, S>[*i];
@@ -1271,6 +1297,7 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
template <detail::enum_subtype S, typename E>
[[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_t<E, string_view> {
using D = std::decay_t<E>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
return enum_name<D, S>(value);
}
@@ -1278,13 +1305,19 @@ template <detail::enum_subtype S, typename E>
// Returns std::array with names, sorted by enum value.
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t<E, detail::names_t<E, S>> {
return detail::names_v<std::decay_t<E>, S>;
using D = std::decay_t<E>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
return detail::names_v<D, S>;
}
// Returns std::array with pairs (value, name), sorted by enum value.
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t<E, detail::entries_t<E, S>> {
return detail::entries_v<std::decay_t<E>, S>;
using D = std::decay_t<E>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
return detail::entries_v<D, S>;
}
// Allows you to write magic_enum::enum_cast<foo>("bar", magic_enum::case_insensitive);
@@ -1295,31 +1328,27 @@ inline constexpr auto case_insensitive = detail::case_insensitive<>{};
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
using D = std::decay_t<E>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
return {}; // Empty enum.
} else {
if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
if constexpr (detail::is_sparse_v<D, S> || (S == detail::enum_subtype::flags)) {
#if defined(MAGIC_ENUM_ENABLE_HASH)
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
[](D v) { return optional<D>{v}; },
static_cast<D>(value),
detail::default_result_type_lambda<optional<D>>);
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
[](D v) { return optional<D>{v}; },
static_cast<D>(value),
detail::default_result_type_lambda<optional<D>>);
#else
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (value == static_cast<underlying_type_t<D>>(enum_value<D, S>(i))) {
return static_cast<D>(value);
}
}
return {}; // Invalid value or out of range.
#endif
} else {
if (value >= detail::min_v<D, S> && value <= detail::max_v<D, S>) {
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (value == static_cast<underlying_type_t<D>>(enum_value<D, S>(i))) {
return static_cast<D>(value);
}
return {}; // Invalid value or out of range.
}
return {}; // Invalid value or out of range.
#endif
} else {
if (value >= detail::min_v<D, S> && value <= detail::max_v<D, S>) {
return static_cast<D>(value);
}
return {}; // Invalid value or out of range.
}
}
@@ -1328,26 +1357,23 @@ template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename BinaryPredicate = std::equal_to<>>
[[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
using D = std::decay_t<E>;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
return {}; // Empty enum.
#if defined(MAGIC_ENUM_ENABLE_HASH)
} else if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
return detail::constexpr_switch<&detail::names_v<D, S>, detail::case_call_t::index>(
[](std::size_t i) { return optional<D>{detail::values_v<D, S>[i]}; },
value,
detail::default_result_type_lambda<optional<D>>,
[&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); });
#endif
} else {
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (detail::cmp_equal(value, detail::names_v<D, S>[i], p)) {
return enum_value<D, S>(i);
}
}
return {}; // Invalid value or out of range.
if constexpr (detail::is_default_predicate<BinaryPredicate>()) {
return detail::constexpr_switch<&detail::names_v<D, S>, detail::case_call_t::index>(
[](std::size_t i) { return optional<D>{detail::values_v<D, S>[i]}; },
value,
detail::default_result_type_lambda<optional<D>>,
[&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); });
}
#endif
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (detail::cmp_equal(value, detail::names_v<D, S>[i], p)) {
return enum_value<D, S>(i);
}
}
return {}; // Invalid value or out of range.
}
// Checks whether enum contains value with such value.

View File

@@ -55,80 +55,98 @@ namespace ripple {
// wrapped lines
// clang-format off
// Universal Transaction flags:
constexpr std::uint32_t tfFullyCanonicalSig = 0x80000000;
enum UniversalFlags : uint32_t {
tfFullyCanonicalSig = 0x80000000,
};
constexpr std::uint32_t tfUniversal = tfFullyCanonicalSig;
constexpr std::uint32_t tfUniversalMask = ~tfUniversal;
// AccountSet flags:
constexpr std::uint32_t tfRequireDestTag = 0x00010000;
constexpr std::uint32_t tfOptionalDestTag = 0x00020000;
constexpr std::uint32_t tfRequireAuth = 0x00040000;
constexpr std::uint32_t tfOptionalAuth = 0x00080000;
constexpr std::uint32_t tfDisallowXRP = 0x00100000;
constexpr std::uint32_t tfAllowXRP = 0x00200000;
enum AccountSetFlags : uint32_t {
tfRequireDestTag = 0x00010000,
tfOptionalDestTag = 0x00020000,
tfRequireAuth = 0x00040000,
tfOptionalAuth = 0x00080000,
tfDisallowXRP = 0x00100000,
tfAllowXRP = 0x00200000,
};
constexpr std::uint32_t tfAccountSetMask =
~(tfUniversal | tfRequireDestTag | tfOptionalDestTag | tfRequireAuth |
tfOptionalAuth | tfDisallowXRP | tfAllowXRP);
// AccountSet SetFlag/ClearFlag values
constexpr std::uint32_t asfRequireDest = 1;
constexpr std::uint32_t asfRequireAuth = 2;
constexpr std::uint32_t asfDisallowXRP = 3;
constexpr std::uint32_t asfDisableMaster = 4;
constexpr std::uint32_t asfAccountTxnID = 5;
constexpr std::uint32_t asfNoFreeze = 6;
constexpr std::uint32_t asfGlobalFreeze = 7;
constexpr std::uint32_t asfDefaultRipple = 8;
constexpr std::uint32_t asfDepositAuth = 9;
constexpr std::uint32_t asfAuthorizedNFTokenMinter = 10;
constexpr std::uint32_t asfTshCollect = 11;
constexpr std::uint32_t asfDisallowIncomingNFTokenOffer = 12;
constexpr std::uint32_t asfDisallowIncomingCheck = 13;
constexpr std::uint32_t asfDisallowIncomingPayChan = 14;
constexpr std::uint32_t asfDisallowIncomingTrustline = 15;
constexpr std::uint32_t asfDisallowIncomingRemit = 16;
enum AccountFlags : uint32_t {
asfRequireDest = 1,
asfRequireAuth = 2,
asfDisallowXRP = 3,
asfDisableMaster = 4,
asfAccountTxnID = 5,
asfNoFreeze = 6,
asfGlobalFreeze = 7,
asfDefaultRipple = 8,
asfDepositAuth = 9,
asfAuthorizedNFTokenMinter = 10,
asfTshCollect = 11,
asfDisallowIncomingNFTokenOffer = 12,
asfDisallowIncomingCheck = 13,
asfDisallowIncomingPayChan = 14,
asfDisallowIncomingTrustline = 15,
asfDisallowIncomingRemit = 16,
};
// OfferCreate flags:
constexpr std::uint32_t tfPassive = 0x00010000;
constexpr std::uint32_t tfImmediateOrCancel = 0x00020000;
constexpr std::uint32_t tfFillOrKill = 0x00040000;
constexpr std::uint32_t tfSell = 0x00080000;
enum OfferCreateFlags : uint32_t {
tfPassive = 0x00010000,
tfImmediateOrCancel = 0x00020000,
tfFillOrKill = 0x00040000,
tfSell = 0x00080000,
};
constexpr std::uint32_t tfOfferCreateMask =
~(tfUniversal | tfPassive | tfImmediateOrCancel | tfFillOrKill | tfSell);
// Payment flags:
constexpr std::uint32_t tfNoRippleDirect = 0x00010000;
constexpr std::uint32_t tfPartialPayment = 0x00020000;
constexpr std::uint32_t tfLimitQuality = 0x00040000;
enum PaymentFlags : uint32_t {
tfNoRippleDirect = 0x00010000,
tfPartialPayment = 0x00020000,
tfLimitQuality = 0x00040000,
};
constexpr std::uint32_t tfPaymentMask =
~(tfUniversal | tfPartialPayment | tfLimitQuality | tfNoRippleDirect);
// TrustSet flags:
constexpr std::uint32_t tfSetfAuth = 0x00010000;
constexpr std::uint32_t tfSetNoRipple = 0x00020000;
constexpr std::uint32_t tfClearNoRipple = 0x00040000;
constexpr std::uint32_t tfSetFreeze = 0x00100000;
constexpr std::uint32_t tfClearFreeze = 0x00200000;
enum TrustSetFlags : uint32_t {
tfSetfAuth = 0x00010000,
tfSetNoRipple = 0x00020000,
tfClearNoRipple = 0x00040000,
tfSetFreeze = 0x00100000,
tfClearFreeze = 0x00200000,
};
constexpr std::uint32_t tfTrustSetMask =
~(tfUniversal | tfSetfAuth | tfSetNoRipple | tfClearNoRipple | tfSetFreeze |
tfClearFreeze);
// EnableAmendment flags:
constexpr std::uint32_t tfGotMajority = 0x00010000;
constexpr std::uint32_t tfLostMajority = 0x00020000;
constexpr std::uint32_t tfTestSuite = 0x80000000;
enum EnableAmendmentFlags : std::uint32_t {
tfGotMajority = 0x00010000,
tfLostMajority = 0x00020000,
tfTestSuite = 0x80000000,
};
// PaymentChannelClaim flags:
constexpr std::uint32_t tfRenew = 0x00010000;
constexpr std::uint32_t tfClose = 0x00020000;
enum PaymentChannelClaimFlags : uint32_t {
tfRenew = 0x00010000,
tfClose = 0x00020000,
};
constexpr std::uint32_t tfPayChanClaimMask = ~(tfUniversal | tfRenew | tfClose);
// NFTokenMint flags:
constexpr std::uint32_t const tfBurnable = 0x00000001;
constexpr std::uint32_t const tfOnlyXRP = 0x00000002;
constexpr std::uint32_t const tfTrustLine = 0x00000004;
constexpr std::uint32_t const tfTransferable = 0x00000008;
constexpr std::uint32_t const tfStrongTSH = 0x00008000;
enum NFTokenMintFlags : uint32_t {
tfBurnable = 0x00000001,
tfOnlyXRP = 0x00000002,
tfTrustLine = 0x00000004,
tfTransferable = 0x00000008,
tfStrongTSH = 0x00008000,
};
constexpr std::uint32_t const tfNFTokenMintOldMask =
~(tfUniversal | tfBurnable | tfOnlyXRP | tfTrustLine | tfTransferable | tfStrongTSH);
@@ -151,7 +169,9 @@ constexpr std::uint32_t const tfNFTokenMintMask =
~(tfUniversal | tfBurnable | tfOnlyXRP | tfTransferable | tfStrongTSH);
// NFTokenCreateOffer flags:
constexpr std::uint32_t const tfSellNFToken = 0x00000001;
enum NFTokenCreateOfferFlags : uint32_t {
tfSellNFToken = 0x00000001,
};
constexpr std::uint32_t const tfNFTokenCreateOfferMask =
~(tfUniversal | tfSellNFToken);
@@ -166,7 +186,9 @@ constexpr std::uint32_t const tfURITokenMintMask = ~(tfUniversal | tfBurnable);
constexpr std::uint32_t const tfURITokenNonMintMask = ~tfUniversal;
// ClaimReward flags:
constexpr std::uint32_t const tfOptOut = 0x00000001;
enum ClaimRewardFlags : uint32_t {
tfOptOut = 0x00000001,
};
// Remarks flags:
constexpr std::uint32_t const tfImmutable = 1;

View File

@@ -108,6 +108,7 @@ constexpr static ErrorInfo unorderedErrorInfos[]{
{rpcSTREAM_MALFORMED, "malformedStream", "Stream malformed.", 400},
{rpcTOO_BUSY, "tooBusy", "The server is too busy to help you now.", 503},
{rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found.", 404},
{rpcNAMESPACE_NOT_FOUND, "namespaceNotFound", "Namespace not found.", 404},
{rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method.", 405}};
// clang-format on

View File

@@ -162,6 +162,7 @@ JSS(account_data); // out: AccountInfo
JSS(account_flags); // out: AccountInfo
JSS(account_hash); // out: LedgerToJson
JSS(account_id); // out: WalletPropose
JSS(account_namespace); // out: AccountNamespace
JSS(account_nfts); // out: AccountNFTs
JSS(account_objects); // out: AccountObjects
JSS(account_root); // in: LedgerEntry
@@ -354,6 +355,7 @@ JSS(id); // websocket.
JSS(ident); // in: AccountCurrencies, AccountInfo,
// OwnerInfo
JSS(ignore_default); // in: AccountLines
JSS(import_vlseq); // in: LedgerEntry
JSS(inLedger); // out: tx/Transaction
JSS(in_queue);
JSS(inbound); // out: PeerImp
@@ -666,50 +668,53 @@ JSS(trusted); // out: UnlList
JSS(trusted_validator_keys); // out: ValidatorList
JSS(tx); // out: STTx, AccountTx*
JSS(txroot);
JSS(tx_blob); // in/out: Submit,
// in: TransactionSign, AccountTx*
JSS(tx_hash); // in: TransactionEntry
JSS(tx_json); // in/out: TransactionSign
// out: TransactionEntry
JSS(tx_signing_hash); // out: TransactionSign
JSS(tx_unsigned); // out: TransactionSign
JSS(txn_count); // out: NetworkOPs
JSS(txr_tx_cnt); // out: protocol message tx's count
JSS(txr_tx_sz); // out: protocol message tx's size
JSS(txr_have_txs_cnt); // out: protocol message have tx count
JSS(txr_have_txs_sz); // out: protocol message have tx size
JSS(txr_get_ledger_cnt); // out: protocol message get ledger count
JSS(txr_get_ledger_sz); // out: protocol message get ledger size
JSS(txr_ledger_data_cnt); // out: protocol message ledger data count
JSS(txr_ledger_data_sz); // out: protocol message ledger data size
JSS(txr_transactions_cnt); // out: protocol message get object count
JSS(txr_transactions_sz); // out: protocol message get object size
JSS(txr_selected_cnt); // out: selected peers count
JSS(txr_suppressed_cnt); // out: suppressed peers count
JSS(txr_not_enabled_cnt); // out: peers with tx reduce-relay disabled count
JSS(txr_missing_tx_freq); // out: missing tx frequency average
JSS(txs); // out: TxHistory
JSS(type); // in: AccountObjects
// out: NetworkOPs RPC server_definitions
// OverlayImpl, Logic
JSS(TRANSACTION_RESULTS); // out: RPC server_definitions
JSS(TRANSACTION_TYPES); // out: RPC server_definitions
JSS(TYPES); // out: RPC server_definitions
JSS(type_hex); // out: STPathSet
JSS(unl); // out: UnlList
JSS(unlimited); // out: Connection.h
JSS(uptime); // out: GetCounts
JSS(uri); // out: ValidatorSites
JSS(uri_token); // in: LedgerEntry
JSS(url); // in/out: Subscribe, Unsubscribe
JSS(url_password); // in: Subscribe
JSS(url_username); // in: Subscribe
JSS(urlgravatar); //
JSS(username); // in: Subscribe
JSS(validated); // out: NetworkOPs, RPCHelpers, AccountTx*
// Tx
JSS(validator_list_expires); // out: NetworkOps, ValidatorList
JSS(validator_list); // out: NetworkOps, ValidatorList
JSS(tx_blob); // in/out: Submit,
// in: TransactionSign, AccountTx*
JSS(tx_hash); // in: TransactionEntry
JSS(tx_json); // in/out: TransactionSign
// out: TransactionEntry
JSS(tx_signing_hash); // out: TransactionSign
JSS(tx_unsigned); // out: TransactionSign
JSS(txn_count); // out: NetworkOPs
JSS(txr_tx_cnt); // out: protocol message tx's count
JSS(txr_tx_sz); // out: protocol message tx's size
JSS(txr_have_txs_cnt); // out: protocol message have tx count
JSS(txr_have_txs_sz); // out: protocol message have tx size
JSS(txr_get_ledger_cnt); // out: protocol message get ledger count
JSS(txr_get_ledger_sz); // out: protocol message get ledger size
JSS(txr_ledger_data_cnt); // out: protocol message ledger data count
JSS(txr_ledger_data_sz); // out: protocol message ledger data size
JSS(txr_transactions_cnt); // out: protocol message get object count
JSS(txr_transactions_sz); // out: protocol message get object size
JSS(txr_selected_cnt); // out: selected peers count
JSS(txr_suppressed_cnt); // out: suppressed peers count
JSS(txr_not_enabled_cnt); // out: peers with tx reduce-relay disabled count
JSS(txr_missing_tx_freq); // out: missing tx frequency average
JSS(txs); // out: TxHistory
JSS(type); // in: AccountObjects
// out: NetworkOPs RPC server_definitions
// OverlayImpl, Logic
JSS(TRANSACTION_RESULTS); // out: RPC server_definitions
JSS(TRANSACTION_TYPES); // out: RPC server_definitions
JSS(TYPES); // out: RPC server_definitions
JSS(TRANSACTION_FLAGS); // out: RPC server_definitions
JSS(TRANSACTION_FLAGS_INDICES); // out: RPC server_definitions
JSS(type_hex); // out: STPathSet
JSS(unl); // out: UnlList
JSS(unlimited); // out: Connection.h
JSS(unl_report); // in: LedgerEntry
JSS(uptime); // out: GetCounts
JSS(uri); // out: ValidatorSites
JSS(uri_token); // in: LedgerEntry
JSS(url); // in/out: Subscribe, Unsubscribe
JSS(url_password); // in: Subscribe
JSS(url_username); // in: Subscribe
JSS(urlgravatar); //
JSS(username); // in: Subscribe
JSS(validated); // out: NetworkOPs, RPCHelpers, AccountTx*
// Tx
JSS(validator_list_expires); // out: NetworkOps, ValidatorList
JSS(validator_list); // out: NetworkOps, ValidatorList
JSS(validators);
JSS(validated_hash); // out: NetworkOPs
JSS(validated_ledger); // out: NetworkOPs

View File

@@ -78,7 +78,7 @@ doAccountInfo(RPC::JsonContext& context)
return jvAccepted;
static constexpr std::
array<std::pair<std::string_view, LedgerSpecificFlags>, 9>
array<std::pair<std::string_view, LedgerSpecificFlags>, 10>
lsFlags{
{{"defaultRipple", lsfDefaultRipple},
{"depositAuth", lsfDepositAuth},
@@ -88,6 +88,7 @@ doAccountInfo(RPC::JsonContext& context)
{"noFreeze", lsfNoFreeze},
{"passwordSpent", lsfPasswordSpent},
{"requireAuthorization", lsfRequireAuth},
{"tshCollect", lsfTshCollect},
{"requireDestinationTag", lsfRequireDestTag}}};
static constexpr std::

View File

@@ -42,7 +42,6 @@ namespace ripple {
namespace_id: <namespace hex>
ledger_hash: <string> // optional
ledger_index: <string | unsigned integer> // optional
type: <string> // optional, defaults to all account objects types
limit: <integer> // optional
marker: <opaque> // optional, resume previous query
}

View File

@@ -24,6 +24,7 @@
#include <ripple/net/RPCErr.h>
#include <ripple/protocol/ErrorCodes.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/PublicKey.h>
#include <ripple/protocol/jss.h>
#include <ripple/rpc/Context.h>
#include <ripple/rpc/GRPCHandlers.h>
@@ -231,6 +232,41 @@ doLedgerEntry(RPC::JsonContext& context)
uNodeIndex = keylet::emittedTxn(uNodeIndex).key;
}
}
else if (context.params.isMember(jss::import_vlseq))
{
expectedType = ltIMPORT_VLSEQ;
if (!context.params[jss::import_vlseq].isObject())
{
if (!uNodeIndex.parseHex(
context.params[jss::import_vlseq].asString()))
{
uNodeIndex = beast::zero;
jvResult[jss::error] = "malformedRequest";
}
}
else if (
!context.params[jss::import_vlseq].isMember(jss::public_key) ||
!context.params[jss::import_vlseq][jss::public_key].isString())
{
jvResult[jss::error] = "malformedRequest";
}
else
{
auto const pkHex = strUnHex(
context.params[jss::import_vlseq][jss::public_key].asString());
auto const pkSlice = makeSlice(*pkHex);
if (!publicKeyType(pkSlice))
{
uNodeIndex = beast::zero;
jvResult[jss::error] = "malformedRequest";
}
else
{
auto const pk = PublicKey(pkSlice);
uNodeIndex = keylet::import_vlseq(pk).key;
}
}
}
else if (context.params.isMember(jss::offer))
{
expectedType = ltOFFER;
@@ -277,11 +313,32 @@ doLedgerEntry(RPC::JsonContext& context)
{
expectedType = ltURI_TOKEN;
if (!uNodeIndex.parseHex(context.params[jss::uri_token].asString()))
if (!context.params[jss::uri_token].isObject())
{
if (!uNodeIndex.parseHex(context.params[jss::uri_token].asString()))
{
uNodeIndex = beast::zero;
jvResult[jss::error] = "malformedRequest";
}
}
else if (
!context.params[jss::uri_token].isMember(jss::account) ||
!context.params[jss::uri_token].isMember(jss::uri))
{
uNodeIndex = beast::zero;
jvResult[jss::error] = "malformedRequest";
}
else
{
auto const id = parseBase58<AccountID>(
context.params[jss::uri_token][jss::account].asString());
auto const strUri =
context.params[jss::uri_token][jss::uri].asString();
Blob raw = Blob(strUri.begin(), strUri.end());
if (!id)
jvResult[jss::error] = "malformedAddress";
else
uNodeIndex = keylet::uritoken(*id, raw).key;
}
}
else if (context.params.isMember(jss::ripple_state))
{

View File

@@ -17,6 +17,8 @@
*/
//==============================================================================
#define MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM
#include <ripple/app/main/Application.h>
#include <ripple/app/misc/AmendmentTable.h>
#include <ripple/app/misc/NetworkOPs.h>
@@ -26,6 +28,7 @@
#include <ripple/net/RPCErr.h>
#include <ripple/protocol/LedgerFormats.h>
#include <ripple/protocol/SField.h>
#include <ripple/protocol/TxFlags.h>
#include <ripple/protocol/digest.h>
#include <ripple/protocol/jss.h>
#include <ripple/rpc/impl/TransactionSign.h>
@@ -41,6 +44,21 @@
static constexpr int max = 20000; \
};
#define MAGIC_ENUM_16(x) \
template <> \
struct magic_enum::customize::enum_range<x> \
{ \
static constexpr int min = -128; \
static constexpr int max = 127; \
};
#define MAGIC_ENUM_FLAG(x) \
template <> \
struct magic_enum::customize::enum_range<x> \
{ \
static constexpr bool is_flags = true; \
};
MAGIC_ENUM(ripple::SerializedTypeID);
MAGIC_ENUM(ripple::LedgerEntryType);
MAGIC_ENUM(ripple::TELcodes);
@@ -49,22 +67,45 @@ MAGIC_ENUM(ripple::TEFcodes);
MAGIC_ENUM(ripple::TERcodes);
MAGIC_ENUM(ripple::TEScodes);
MAGIC_ENUM(ripple::TECcodes);
MAGIC_ENUM_16(ripple::TxType);
MAGIC_ENUM_FLAG(ripple::UniversalFlags);
MAGIC_ENUM_FLAG(ripple::AccountSetFlags);
MAGIC_ENUM_FLAG(ripple::OfferCreateFlags);
MAGIC_ENUM_FLAG(ripple::PaymentFlags);
MAGIC_ENUM_FLAG(ripple::TrustSetFlags);
MAGIC_ENUM_FLAG(ripple::EnableAmendmentFlags);
MAGIC_ENUM_FLAG(ripple::PaymentChannelClaimFlags);
MAGIC_ENUM_FLAG(ripple::NFTokenMintFlags);
MAGIC_ENUM_FLAG(ripple::NFTokenCreateOfferFlags);
MAGIC_ENUM_FLAG(ripple::ClaimRewardFlags);
MAGIC_ENUM_16(ripple::AccountFlags);
namespace ripple {
class Definitions
{
private:
Json::Value
generate()
{
// RH TODO: probably a better way to do this?
#define STR(x) \
([&] { \
std::ostringstream ss; \
return ss << (x), ss.str(); \
}())
template <typename EnumType>
void
addFlagsToJson(Json::Value& json, std::string const& key)
{
for (auto const& entry : magic_enum::enum_entries<EnumType>())
{
const auto name = entry.second;
json[jss::TRANSACTION_FLAGS][key][STR(name)] =
static_cast<uint32_t>(entry.first);
}
}
Json::Value
generate()
{
Json::Value ret{Json::objectValue};
ret[jss::TYPES] = Json::objectValue;
@@ -368,6 +409,39 @@ private:
ret[jss::TRANSACTION_TYPES][type_name] = type_value;
}
// Transaction Flags:
ret[jss::TRANSACTION_FLAGS] = Json::objectValue;
addFlagsToJson<UniversalFlags>(ret, "Universal");
addFlagsToJson<AccountSetFlags>(ret, "AccountSet");
addFlagsToJson<OfferCreateFlags>(ret, "OfferCreate");
addFlagsToJson<PaymentFlags>(ret, "Payment");
addFlagsToJson<TrustSetFlags>(ret, "TrustSet");
addFlagsToJson<EnableAmendmentFlags>(ret, "EnableAmendment");
addFlagsToJson<PaymentChannelClaimFlags>(ret, "PaymentChannelClaim");
addFlagsToJson<NFTokenMintFlags>(ret, "NFTokenMint");
addFlagsToJson<NFTokenCreateOfferFlags>(ret, "NFTokenCreateOffer");
addFlagsToJson<ClaimRewardFlags>(ret, "ClaimReward");
struct FlagData
{
std::string name;
std::uint32_t value;
};
std::array<FlagData, 1> uriTokenMintFlags{{{"tfBurnable", tfBurnable}}};
for (auto const& entry : uriTokenMintFlags)
{
ret[jss::TRANSACTION_FLAGS]["URITokenMint"][entry.name] =
static_cast<uint32_t>(entry.value);
}
// Transaction Indicies Flags:
ret[jss::TRANSACTION_FLAGS_INDICES] = Json::objectValue;
for (auto const& entry : magic_enum::enum_entries<AccountFlags>())
{
const auto name = entry.second;
ret[jss::TRANSACTION_FLAGS_INDICES]["AccountSet"][STR(name)] =
static_cast<uint32_t>(entry.first);
}
ret[jss::native_currency_code] = systemCurrencyCode();
// generate hash

View File

@@ -1067,7 +1067,7 @@ chooseLedgerEntryType(Json::Value const& params)
std::pair<RPC::Status, LedgerEntryType> result{RPC::Status::OK, ltANY};
if (params.isMember(jss::type))
{
static constexpr std::array<std::pair<char const*, LedgerEntryType>, 19>
static constexpr std::array<std::pair<char const*, LedgerEntryType>, 22>
types{
{{jss::account, ltACCOUNT_ROOT},
{jss::amendments, ltAMENDMENTS},
@@ -1075,11 +1075,13 @@ chooseLedgerEntryType(Json::Value const& params)
{jss::deposit_preauth, ltDEPOSIT_PREAUTH},
{jss::directory, ltDIR_NODE},
{jss::escrow, ltESCROW},
{jss::emitted_txn, ltEMITTED_TXN},
{jss::hook, ltHOOK},
{jss::hook_definition, ltHOOK_DEFINITION},
{jss::hook_state, ltHOOK_STATE},
{jss::fee, ltFEE_SETTINGS},
{jss::hashes, ltLEDGER_HASHES},
{jss::import_vlseq, ltIMPORT_VLSEQ},
{jss::offer, ltOFFER},
{jss::payment_channel, ltPAYCHAN},
{jss::uri_token, ltURI_TOKEN},
@@ -1087,7 +1089,8 @@ chooseLedgerEntryType(Json::Value const& params)
{jss::state, ltRIPPLE_STATE},
{jss::ticket, ltTICKET},
{jss::nft_offer, ltNFTOKEN_OFFER},
{jss::nft_page, ltNFTOKEN_PAGE}}};
{jss::nft_page, ltNFTOKEN_PAGE},
{jss::unl_report, ltUNL_REPORT}}};
auto const& p = params[jss::type];
if (!p.isString())

View File

@@ -84,28 +84,6 @@ class Import_test : public beast::unit_test::suite
return 0;
}
STTx
createUNLReportTx(
LedgerIndex seq,
PublicKey const& importKey,
PublicKey const& valKey)
{
auto fill = [&](auto& obj) {
obj.setFieldU32(sfLedgerSequence, seq);
obj.set(([&]() {
auto inner = std::make_unique<STObject>(sfActiveValidator);
inner->setFieldVL(sfPublicKey, valKey);
return inner;
})());
obj.set(([&]() {
auto inner = std::make_unique<STObject>(sfImportVLKey);
inner->setFieldVL(sfPublicKey, importKey);
return inner;
})());
};
return STTx(ttUNL_REPORT, fill);
}
bool
hasUNLReport(jtx::Env const& env)
{
@@ -5320,7 +5298,7 @@ class Import_test : public beast::unit_test::suite
// insert a ttUNL_REPORT pseudo into the open ledger
env.app().openLedger().modify(
[&](OpenView& view, beast::Journal j) -> bool {
STTx tx = createUNLReportTx(
STTx tx = unl::createUNLReportTx(
env.current()->seq() + 1, ivlKeys[0], vlKeys[0]);
uint256 txID = tx.getTransactionID();
auto s = std::make_shared<ripple::Serializer>();

View File

@@ -3598,28 +3598,6 @@ struct XahauGenesis_test : public beast::unit_test::suite
return slep != nullptr;
}
STTx
createUNLReportTx(
LedgerIndex seq,
PublicKey const& importKey,
PublicKey const& valKey)
{
auto fill = [&](auto& obj) {
obj.setFieldU32(sfLedgerSequence, seq);
obj.set(([&]() {
auto inner = std::make_unique<STObject>(sfActiveValidator);
inner->setFieldVL(sfPublicKey, valKey);
return inner;
})());
obj.set(([&]() {
auto inner = std::make_unique<STObject>(sfImportVLKey);
inner->setFieldVL(sfPublicKey, importKey);
return inner;
})());
};
return STTx(ttUNL_REPORT, fill);
}
void
activateUNLReport(
jtx::Env& env,
@@ -3631,7 +3609,7 @@ struct XahauGenesis_test : public beast::unit_test::suite
{
env.app().openLedger().modify(
[&](OpenView& view, beast::Journal j) -> bool {
STTx tx = createUNLReportTx(
STTx tx = unl::createUNLReportTx(
env.current()->seq() + 1, ivlKeys[0], vlKey);
uint256 txID = tx.getTransactionID();
auto s = std::make_shared<ripple::Serializer>();

View File

@@ -90,6 +90,28 @@ createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey)
return STTx(ttUNL_MODIFY, fill);
}
STTx
createUNLReportTx(
LedgerIndex seq,
PublicKey const& importKey,
PublicKey const& valKey)
{
auto fill = [&](auto& obj) {
obj.setFieldU32(sfLedgerSequence, seq);
obj.set(([&]() {
auto inner = std::make_unique<STObject>(sfActiveValidator);
inner->setFieldVL(sfPublicKey, valKey);
return inner;
})());
obj.set(([&]() {
auto inner = std::make_unique<STObject>(sfImportVLKey);
inner->setFieldVL(sfPublicKey, importKey);
return inner;
})());
};
return STTx(ttUNL_REPORT, fill);
}
} // namespace unl
} // namespace test
} // namespace ripple

View File

@@ -78,6 +78,20 @@ countTx(std::shared_ptr<SHAMap> const& txSet);
STTx
createTx(bool disabling, LedgerIndex seq, PublicKey const& txKey);
/**
* Create ttUNL_REPORT Tx
*
* @param seq current ledger seq
* @param importKey the public key of the import network
* @param txKey the public key of the validator
* @return the ttUNL_REPORT Tx
*/
STTx
createUNLReportTx(
LedgerIndex seq,
PublicKey const& importKey,
PublicKey const& valKey);
} // namespace unl
} // namespace test

View File

@@ -516,7 +516,7 @@ public:
};
static constexpr std::
array<std::pair<std::string_view, std::uint32_t>, 7>
array<std::pair<std::string_view, std::uint32_t>, 8>
asFlags{
{{"defaultRipple", asfDefaultRipple},
{"depositAuth", asfDepositAuth},
@@ -524,6 +524,7 @@ public:
{"globalFreeze", asfGlobalFreeze},
{"noFreeze", asfNoFreeze},
{"requireAuthorization", asfRequireAuth},
{"tshCollect", asfTshCollect},
{"requireDestinationTag", asfRequireDest}}};
for (auto& asf : asFlags)

View File

@@ -0,0 +1,250 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2024 XRPL-Labs
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/protocol/Feature.h>
#include <ripple/protocol/jss.h>
#include <test/jtx.h>
namespace ripple {
namespace test {
class AccountNamespace_test : public beast::unit_test::suite
{
public:
void
testErrors(FeatureBitset features)
{
testcase("error cases");
using namespace jtx;
Env env(*this);
Account const alice{"alice"};
Account const bob{"bob"};
Account const carol{"carol"};
env.fund(XRP(1000), alice, bob);
env.close();
auto const ns = uint256::fromVoid(
(std::array<uint8_t, 32>{
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU,
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU,
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU,
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU})
.data());
{
// account_namespace with no account.
auto const info = env.rpc("json", "account_namespace", "{ }");
BEAST_EXPECT(
info[jss::result][jss::error_message] ==
"Missing field 'account'.");
}
{
// account_namespace missing filed namespace_id.
Json::Value params;
params[jss::account] = alice.human();
auto const info =
env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
info[jss::result][jss::error_message] ==
"Missing field 'namespace_id'.");
}
{
// account_namespace with a malformed account string.
Json::Value params;
params[jss::account] =
"n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
params[jss::namespace_id] = "";
auto const info =
env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
info[jss::result][jss::error_message] == "Disallowed seed.");
}
{
// account_namespace with an invalid namespace_id.
Json::Value params;
params[jss::account] = alice.human();
params[jss::namespace_id] = "DEADBEEF";
auto const info =
env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
info[jss::result][jss::error_message] == "Invalid parameters.");
}
{
// account_namespace with an account that's not in the ledger.
Json::Value params;
params[jss::account] = carol.human();
params[jss::namespace_id] = to_string(ns);
auto const info =
env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
info[jss::result][jss::error_message] == "Account not found.");
}
{
// account_namespace with a namespace that doesnt exist.
Json::Value params;
params[jss::account] = alice.human();
params[jss::namespace_id] = to_string(ns);
auto const info =
env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
info[jss::result][jss::error_message] ==
"Namespace not found.");
}
// test errors on marker
{
auto const key = uint256::fromVoid(
(std::array<uint8_t, 32>{
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U,
0x00U, 0x00U, 0x00U, 0x00U, 'k', 'e', 'y', 0x00U})
.data());
auto const ns = uint256::fromVoid(
(std::array<uint8_t, 32>{
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU,
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU,
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU,
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU})
.data());
auto const nons = uint256::fromVoid(
(std::array<uint8_t, 32>{
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU,
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU,
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU,
0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFEU, 0xCAU, 0xFFU})
.data());
// Lambda to create a hook.
auto setHook = [](test::jtx::Account const& account) {
std::string const createCodeHex =
"0061736D01000000011B0460027F7F017F60047F7F7F7F017E60037F7F"
"7E01"
"7E60017F017E02270303656E76025F67000003656E760973746174655F"
"7365"
"74000103656E76066163636570740002030201030503010002062B077F"
"0141"
"9088040B7F004180080B7F00418A080B7F004180080B7F00419088040B"
"7F00"
"41000B7F0041010B07080104686F6F6B00030AE7800001E3800002017F"
"017E"
"230041106B220124002001200036020C41012200200010001A20014180"
"0828"
"0000360208200141046A410022002F0088083B01002001200028008408"
"3602"
"004100200020014106200141086A4104100110022102200141106A2400"
"2002"
"0B0B1001004180080B096B65790076616C7565";
std::string ns_str =
"CAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECAFECA"
"FECA"
"FE";
Json::Value jv =
ripple::test::jtx::hook(account, {{hso(createCodeHex)}}, 0);
jv[jss::Hooks][0U][jss::Hook][jss::HookNamespace] = ns_str;
return jv;
};
env(setHook(bob), fee(XRP(1)), ter(tesSUCCESS));
env.close();
env(pay(alice, bob, XRP(1)), fee(XRP(1)), ter(tesSUCCESS));
env.close();
Json::Value params;
params[jss::account] = bob.human();
params[jss::namespace_id] = to_string(ns);
params[jss::limit] = 1;
auto resp = env.rpc("json", "account_namespace", to_string(params));
auto resume_marker = resp[jss::result][jss::marker];
std::string mark = to_string(resume_marker);
params[jss::marker] = 10;
resp = env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker', not string.");
params[jss::marker] = "This is a string with no comma";
resp = env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
params[jss::marker] = "This string has a comma, but is not hex";
resp = env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
params[jss::marker] = std::string(&mark[1U], 64);
resp = env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
params[jss::marker] = std::string(&mark[1U], 65);
resp = env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
params[jss::marker] = std::string(&mark[1U], 65) + "not hex";
resp = env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
params[jss::marker] = std::string(&mark[1U], 128);
resp = env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'marker'.");
}
// test error on limit -ve
{
Account const bob{"bob"};
Json::Value params;
params[jss::account] = bob.human();
params[jss::namespace_id] = to_string(ns);
params[jss::limit] = -1;
auto resp = env.rpc("json", "account_namespace", to_string(params));
BEAST_EXPECT(
resp[jss::result][jss::error_message] ==
"Invalid field 'limit', not unsigned integer.");
}
}
void
run() override
{
using namespace test::jtx;
FeatureBitset const all{supported_amendments()};
testErrors(all);
}
};
BEAST_DEFINE_TESTSUITE(AccountNamespace, rpc, ripple);
} // namespace test
} // namespace ripple

View File

@@ -34,19 +34,19 @@ namespace test {
static char const* bobs_account_objects[] = {
R"json({
"Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
"BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000",
"BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
"BookNode" : "0",
"Flags" : 65536,
"LedgerEntryType" : "Offer",
"OwnerNode" : "0",
"Sequence" : 6,
"Sequence" : 4,
"TakerGets" : {
"currency" : "USD",
"issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
"issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
"value" : "1"
},
"TakerPays" : "100000000",
"index" : "29665262716C19830E26AEEC0916E476FC7D8EF195FF3B4F06829E64F82A3B3E"
"index" : "A984D036A0E562433A8377CA57D1A1E056E58C0D04818F8DFD3A1AA3F217DD82"
})json",
R"json({
"Balance" : {
@@ -94,19 +94,19 @@ static char const* bobs_account_objects[] = {
})json",
R"json({
"Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
"BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
"BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000",
"BookNode" : "0",
"Flags" : 65536,
"LedgerEntryType" : "Offer",
"OwnerNode" : "0",
"Sequence" : 7,
"Sequence" : 3,
"TakerGets" : {
"currency" : "USD",
"issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
"issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
"value" : "1"
},
"TakerPays" : "100000000",
"index" : "F03ABE26CB8C5F4AFB31A86590BD25C64C5756FCE5CE9704C27AFE291A4A29A1"
"index" : "E11029302EE744401427793A4F37BCB18F698D55C96851BEC5ABBD6242CF03D7"
})json"};
class AccountObjects_test : public beast::unit_test::suite
@@ -328,9 +328,7 @@ public:
aobj.removeMember("PreviousTxnID");
aobj.removeMember("PreviousTxnLgrSeq");
BEAST_EXPECT(aobj == bobj[i]);
params[jss::marker] = resp[jss::result][jss::marker];
}
}
@@ -734,7 +732,7 @@ public:
auto const& ticket = resp[jss::result][jss::account_objects][0u];
BEAST_EXPECT(ticket[sfAccount.jsonName] == gw.human());
BEAST_EXPECT(ticket[sfLedgerEntryType.jsonName] == jss::Ticket);
BEAST_EXPECT(ticket[sfTicketSequence.jsonName].asUInt() == 13);
BEAST_EXPECT(ticket[sfTicketSequence.jsonName].asUInt() == 10);
}
{
// Create a uri token.
@@ -856,7 +854,7 @@ public:
run() override
{
using namespace jtx;
FeatureBitset const all{supported_amendments() - featureXahauGenesis};
FeatureBitset const all{supported_amendments()};
testErrors(all);
testUnsteppedThenStepped(all);
testUnsteppedThenSteppedWithNFTs(all);

View File

@@ -119,23 +119,23 @@ public:
BEAST_EXPECT(jroOuter[0u][jss::quality] == "100000000");
BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::currency] == "USD");
BEAST_EXPECT(
jroOuter[0u][jss::taker_gets][jss::issuer] == gw.human());
BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::value] == "2");
BEAST_EXPECT(jroOuter[0u][jss::taker_pays] == "200000000");
jroOuter[0u][jss::taker_gets][jss::issuer] == bob.human());
BEAST_EXPECT(jroOuter[0u][jss::taker_gets][jss::value] == "1");
BEAST_EXPECT(jroOuter[0u][jss::taker_pays] == "100000000");
BEAST_EXPECT(jroOuter[1u][jss::quality] == "100000000");
BEAST_EXPECT(jroOuter[1u][jss::quality] == "5000000");
BEAST_EXPECT(jroOuter[1u][jss::taker_gets][jss::currency] == "USD");
BEAST_EXPECT(
jroOuter[1u][jss::taker_gets][jss::issuer] == bob.human());
BEAST_EXPECT(jroOuter[1u][jss::taker_gets][jss::value] == "1");
BEAST_EXPECT(jroOuter[1u][jss::taker_pays] == "100000000");
jroOuter[1u][jss::taker_gets][jss::issuer] == gw.human());
BEAST_EXPECT(jroOuter[1u][jss::taker_gets][jss::value] == "6");
BEAST_EXPECT(jroOuter[1u][jss::taker_pays] == "30000000");
BEAST_EXPECT(jroOuter[2u][jss::quality] == "5000000");
BEAST_EXPECT(jroOuter[2u][jss::quality] == "100000000");
BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::currency] == "USD");
BEAST_EXPECT(
jroOuter[2u][jss::taker_gets][jss::issuer] == gw.human());
BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::value] == "6");
BEAST_EXPECT(jroOuter[2u][jss::taker_pays] == "30000000");
BEAST_EXPECT(jroOuter[2u][jss::taker_gets][jss::value] == "2");
BEAST_EXPECT(jroOuter[2u][jss::taker_pays] == "200000000");
}
{
@@ -327,7 +327,7 @@ public:
run() override
{
using namespace jtx;
FeatureBitset const all{supported_amendments() - featureXahauGenesis};
FeatureBitset const all{supported_amendments()};
testSequential(all, true);
testSequential(all, false);
testBadInput(all);

View File

@@ -17,8 +17,11 @@
*/
//==============================================================================
#include <ripple/app/misc/HashRouter.h>
#include <ripple/basics/StringUtilities.h>
#include <ripple/protocol/digest.h>
#include <ripple/protocol/jss.h>
#include <test/app/Import_json.h>
#include <test/jtx.h>
namespace ripple {
@@ -308,11 +311,16 @@ public:
// Put a bunch of different LedgerEntryTypes into a ledger
using namespace test::jtx;
using namespace std::chrono;
Env env{*this, envconfig(validator, "")};
std::vector<std::string> const keys = {
"ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC"
"1"};
Env env{*this, network::makeNetworkVLConfig(21337, keys)};
Account const alice{"alice"};
Account const gw{"gateway"};
auto const USD = gw["USD"];
env.fund(XRP(100000), gw);
env.fund(XRP(100000), gw, alice);
auto makeRequest = [&env](Json::StaticString const& type) {
Json::Value jvParams;
@@ -335,6 +343,10 @@ public:
jss::ticket,
jss::escrow,
jss::payment_channel,
jss::hook,
jss::hook_definition,
jss::hook_state,
jss::uri_token,
jss::deposit_preauth})
{
auto const jrr = makeRequest(type);
@@ -399,6 +411,12 @@ public:
env.close();
}
{
std::string const uri(maxTokenURILength, '?');
env(uritoken::mint(Account{"bob2"}, uri));
env.close();
}
{
Json::Value jv;
jv[jss::TransactionType] = jss::PaymentChannelCreate;
@@ -414,6 +432,63 @@ public:
env(jv);
}
{
auto const master = Account("masterpassphrase");
env(noop(master), fee(10'000'000'000), ter(tesSUCCESS));
env.close();
env(import::import(
alice, import::loadXpop(test::ImportTCAccountSet::w_seed)),
fee(10 * 10),
ter(tesSUCCESS));
env.close();
}
{
// ADD UNL REPORT
std::vector<std::string> const _ivlKeys = {
"ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1"
"CDC1",
"ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1"
"CDC2",
};
std::vector<PublicKey> ivlKeys;
for (auto const& strPk : _ivlKeys)
{
auto pkHex = strUnHex(strPk);
ivlKeys.emplace_back(makeSlice(*pkHex));
}
std::vector<std::string> const _vlKeys = {
"ED8E43A943A174190BA2FAE91F44AC6E2D1D8202EFDCC2EA3DBB39814576D6"
"90F7",
"ED45D1840EE724BE327ABE9146503D5848EFD5F38B6D5FEDE71E80ACCE5E6E"
"738B"};
std::vector<PublicKey> vlKeys;
for (auto const& strPk : _vlKeys)
{
auto pkHex = strUnHex(strPk);
vlKeys.emplace_back(makeSlice(*pkHex));
}
// insert a ttUNL_REPORT pseudo into the open ledger
env.app().openLedger().modify(
[&](OpenView& view, beast::Journal j) -> bool {
STTx tx = test::unl::createUNLReportTx(
env.current()->seq() + 1, ivlKeys[0], vlKeys[0]);
uint256 txID = tx.getTransactionID();
auto s = std::make_shared<ripple::Serializer>();
tx.add(*s);
env.app().getHashRouter().setFlags(txID, SF_PRIVATE2);
view.rawTxInsert(txID, std::move(s), nullptr);
return true;
});
// close the ledger
env.close();
}
env(check::create("bob6", "bob7", XRP(100)));
// bob9 DepositPreauths bob4 and bob8.
@@ -425,18 +500,26 @@ public:
{ // jvParams[jss::type] = "account";
auto const jrr = makeRequest(jss::account);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 12));
BEAST_EXPECT(checkArraySize(jrr[jss::state], 13));
for (auto const& j : jrr[jss::state])
BEAST_EXPECT(j["LedgerEntryType"] == jss::AccountRoot);
}
{ // jvParams[jss::type] = "amendments";
auto const jrr = makeRequest(jss::amendments);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
BEAST_EXPECT(checkArraySize(jrr[jss::state], 0));
for (auto const& j : jrr[jss::state])
BEAST_EXPECT(j["LedgerEntryType"] == jss::Amendments);
}
{ // jvParams[jss::type] = "unl_report";
auto const jrr = makeRequest(jss::unl_report);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
for (auto const& j : jrr[jss::state])
BEAST_EXPECT(j["LedgerEntryType"] == jss::UNLReport);
}
{ // jvParams[jss::type] = "check";
auto const jrr = makeRequest(jss::check);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
@@ -465,6 +548,13 @@ public:
BEAST_EXPECT(j["LedgerEntryType"] == jss::LedgerHashes);
}
{ // jvParams[jss::type] = "import_vlseq";
auto const jrr = makeRequest(jss::import_vlseq);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
for (auto const& j : jrr[jss::state])
BEAST_EXPECT(j["LedgerEntryType"] == jss::ImportVLSequence);
}
{ // jvParams[jss::type] = "offer";
auto const jrr = makeRequest(jss::offer);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
@@ -521,6 +611,13 @@ public:
BEAST_EXPECT(j["LedgerEntryType"] == jss::HookState);
}
{ // jvParams[jss::type] = "uri_token";
auto const jrr = makeRequest(jss::uri_token);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));
for (auto const& j : jrr[jss::state])
BEAST_EXPECT(j["LedgerEntryType"] == jss::URIToken);
}
{ // jvParams[jss::type] = "payment_channel";
auto const jrr = makeRequest(jss::payment_channel);
BEAST_EXPECT(checkArraySize(jrr[jss::state], 1));

View File

@@ -1707,6 +1707,39 @@ public:
BEAST_EXPECT(jrr[jss::node][sfURI.jsonName] == strHex(uri));
BEAST_EXPECT(jrr[jss::node][sfFlags.jsonName] == lsfBurnable);
}
{
// Request the uritoken using its account and uri.
Json::Value jvParams;
jvParams[jss::uri_token] = Json::objectValue;
jvParams[jss::uri_token][jss::account] = alice.human();
jvParams[jss::uri_token][jss::uri] = uri;
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::node][sfOwner.jsonName] == alice.human());
BEAST_EXPECT(jrr[jss::node][sfURI.jsonName] == strHex(uri));
BEAST_EXPECT(jrr[jss::node][sfFlags.jsonName] == lsfBurnable);
}
{
// Malformed uritoken object. Missing account member.
Json::Value jvParams;
jvParams[jss::uri_token] = Json::objectValue;
jvParams[jss::uri_token][jss::uri] = uri;
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "malformedRequest", "");
}
{
// Malformed uritoken object. Missing seq member.
Json::Value jvParams;
jvParams[jss::uri_token] = Json::objectValue;
jvParams[jss::uri_token][jss::account] = env.master.human();
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "malformedRequest", "");
}
{
// Request an index that is not a uritoken.
Json::Value jvParams;
@@ -1718,6 +1751,93 @@ public:
}
}
void
testLedgerEntryImportVLSeq()
{
testcase("ledger_entry Request ImportVLSeq");
using namespace test::jtx;
std::vector<std::string> const keys = {
"ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1CDC"
"1"};
Env env{*this, network::makeNetworkVLConfig(21337, keys)};
Account const alice{"alice"};
env.fund(XRP(10000), alice);
env.close();
auto const master = Account("masterpassphrase");
env(noop(master), fee(10'000'000'000), ter(tesSUCCESS));
env.close();
env(import::import(
alice, import::loadXpop(test::ImportTCAccountSet::w_seed)),
fee(10 * 10),
ter(tesSUCCESS));
env.close();
std::string const ledgerHash{to_string(env.closed()->info().hash)};
auto const pk = PublicKey(makeSlice(*strUnHex(keys[0u])));
uint256 const importvlIndex{keylet::import_vlseq(pk).key};
{
// Request the import vl using its index.
Json::Value jvParams;
jvParams[jss::import_vlseq] = to_string(importvlIndex);
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::node][sfPublicKey.jsonName] == keys[0u]);
}
{
// Request the import vl using its public key.
Json::Value jvParams;
jvParams[jss::import_vlseq] = Json::objectValue;
jvParams[jss::import_vlseq][jss::public_key] = keys[0u];
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::node][sfPublicKey.jsonName] == keys[0u]);
}
{
// Malformed import vl object. Missing public key.
Json::Value jvParams;
jvParams[jss::import_vlseq] = Json::objectValue;
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "malformedRequest", "");
}
{
// Malformed import vl object. Bad public key.
Json::Value jvParams;
jvParams[jss::import_vlseq] = Json::objectValue;
jvParams[jss::import_vlseq][jss::public_key] = 1;
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "malformedRequest", "");
}
{
// Malformed import vl object. Bad public key.
Json::Value jvParams;
jvParams[jss::import_vlseq] = Json::objectValue;
jvParams[jss::import_vlseq][jss::public_key] = "DEADBEEF";
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "malformedRequest", "");
}
{
// Request an index that is not a uritoken.
Json::Value jvParams;
jvParams[jss::import_vlseq] = ledgerHash;
jvParams[jss::ledger_hash] = ledgerHash;
Json::Value const jrr = env.rpc(
"json", "ledger_entry", to_string(jvParams))[jss::result];
checkErrorValue(jrr, "entryNotFound", "");
}
}
void
testLedgerEntryUnknownOption()
{
@@ -2242,6 +2362,7 @@ public:
testLedgerEntryRippleState();
testLedgerEntryTicket();
testLedgerEntryURIToken();
testLedgerEntryImportVLSeq();
testLedgerEntryUnknownOption();
testLookupLedger();
testNoQueue();

View File

@@ -57,12 +57,16 @@ public:
{
Env env(*this);
auto const result = env.rpc("server_definitions");
std::cout << "RESULT: " << result << "\n";
BEAST_EXPECT(!result[jss::result].isMember(jss::error));
BEAST_EXPECT(result[jss::result].isMember(jss::FIELDS));
BEAST_EXPECT(result[jss::result].isMember(jss::LEDGER_ENTRY_TYPES));
BEAST_EXPECT(
result[jss::result].isMember(jss::TRANSACTION_RESULTS));
BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_TYPES));
BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_FLAGS));
BEAST_EXPECT(
result[jss::result].isMember(jss::TRANSACTION_FLAGS_INDICES));
BEAST_EXPECT(result[jss::result].isMember(jss::TYPES));
BEAST_EXPECT(result[jss::result].isMember(jss::hash));
BEAST_EXPECT(result[jss::result][jss::status] == "success");
@@ -70,7 +74,7 @@ public:
}
void
testDefitionsHash(FeatureBitset features)
testDefinitionsHash(FeatureBitset features)
{
testcase("Definitions Hash");
@@ -92,6 +96,9 @@ public:
BEAST_EXPECT(
!result[jss::result].isMember(jss::TRANSACTION_RESULTS));
BEAST_EXPECT(!result[jss::result].isMember(jss::TRANSACTION_TYPES));
BEAST_EXPECT(!result[jss::result].isMember(jss::TRANSACTION_FLAGS));
BEAST_EXPECT(
!result[jss::result].isMember(jss::TRANSACTION_FLAGS_INDICES));
BEAST_EXPECT(!result[jss::result].isMember(jss::TYPES));
BEAST_EXPECT(result[jss::result].isMember(jss::hash));
}
@@ -113,6 +120,9 @@ public:
BEAST_EXPECT(
result[jss::result].isMember(jss::TRANSACTION_RESULTS));
BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_TYPES));
BEAST_EXPECT(result[jss::result].isMember(jss::TRANSACTION_FLAGS));
BEAST_EXPECT(
result[jss::result].isMember(jss::TRANSACTION_FLAGS_INDICES));
BEAST_EXPECT(result[jss::result].isMember(jss::TYPES));
BEAST_EXPECT(result[jss::result].isMember(jss::hash));
}
@@ -330,7 +340,7 @@ public:
testServerDefinitions(FeatureBitset features)
{
testDefinitions(features);
testDefitionsHash(features);
testDefinitionsHash(features);
}
void