diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index e328f8b0d..63bd190a9 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -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 diff --git a/Builds/levelization/results/loops.txt b/Builds/levelization/results/loops.txt index 917cd45b4..209e0e1fa 100644 --- a/Builds/levelization/results/loops.txt +++ b/Builds/levelization/results/loops.txt @@ -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 diff --git a/Builds/levelization/results/ordering.txt b/Builds/levelization/results/ordering.txt index ddb0f6083..12df1a86e 100644 --- a/Builds/levelization/results/ordering.txt +++ b/Builds/levelization/results/ordering.txt @@ -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 diff --git a/src/magic/magic_enum.h b/src/magic/magic_enum.h index 095183d63..78b1d17cf 100644 --- a/src/magic/magic_enum.h +++ b/src/magic/magic_enum.h @@ -5,11 +5,11 @@ // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum -// |___/ version 0.9.3 +// |___/ version 0.9.5 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT -// Copyright (c) 2019 - 2023 Daniil Goncharov . +// Copyright (c) 2019 - 2024 Daniil Goncharov . // // 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 #include @@ -60,7 +60,7 @@ #if defined(MAGIC_ENUM_NO_ASSERT) # define MAGIC_ENUM_ASSERT(...) static_cast(0) -#else +#elif !defined(MAGIC_ENUM_ASSERT) # include # 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('\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('\0')' for char_type = char (common on Linux). #elif defined(_MSC_VER) # pragma warning(push) # pragma warning(disable : 26495) // Variable 'static_str::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 struct enum_range { - static_assert(std::is_enum_v, "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::max)(), "MAGIC_ENUM_RANGE must be less than UINT16_MAX."); namespace detail { @@ -216,9 +215,9 @@ namespace detail { template 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 , std::enable_if_t, 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::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, "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, "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::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, "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, "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(valid, count); @@ -750,7 +769,6 @@ constexpr auto values() noexcept { constexpr auto max = reflected_max(); 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::max)(), "magic_enum::enum_range requires valid size."); return values(); } @@ -807,7 +825,8 @@ inline constexpr auto max_v = (count_v > 0) ? static_cast(values_v constexpr auto names(std::index_sequence) noexcept { - return std::array{{enum_name_v[I]>...}}; + constexpr auto names = std::array{{enum_name_v[I]>...}}; + return names; } template @@ -818,7 +837,8 @@ using names_t = decltype((names_v)); template constexpr auto entries(std::index_sequence) noexcept { - return std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; + constexpr auto entries = std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; + return entries; } template @@ -845,17 +865,16 @@ constexpr bool is_sparse() noexcept { template > inline constexpr bool is_sparse_v = is_sparse(); -template > -constexpr U values_ors() noexcept { - static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype."); +template +struct is_reflected +#if defined(MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM) + : std::true_type {}; +#else + : std::bool_constant && (count_v != 0)> {}; +#endif - auto ors = U{0}; - for (std::size_t i = 0; i < count_v; ++i) { - ors |= static_cast(values_v[i]); - } - - return ors; -} +template +inline constexpr bool is_reflected_v = is_reflected, S>{}; template struct enable_if_enum {}; @@ -1156,6 +1175,7 @@ template > template > [[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t> { using D = std::decay_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if constexpr (detail::is_sparse_v) { return MAGIC_ENUM_ASSERT(index < detail::count_v), detail::values_v[index]; @@ -1170,6 +1190,7 @@ template > template > [[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t> { using D = std::decay_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); static_assert(I < detail::count_v, "magic_enum::enum_value out of range."); return enum_value(I); @@ -1178,7 +1199,10 @@ template > [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t> { - return detail::values_v, S>; + using D = std::decay_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); + + return detail::values_v; } // Returns integer value from enum value. @@ -1199,11 +1223,9 @@ template > [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { using D = std::decay_t; using U = underlying_type_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); - if constexpr (detail::count_v == 0) { - static_cast(value); - return {}; // Empty enum. - } else if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { + if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { #if defined(MAGIC_ENUM_ENABLE_HASH) return detail::constexpr_switch<&detail::values_v, detail::case_call_t::index>( [](std::size_t i) { return optional{i}; }, @@ -1231,14 +1253,17 @@ template > template [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { using D = std::decay_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return enum_index(value); } // Obtains index in enum values from static storage enum variable. template >> -[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t { - constexpr auto index = enum_index, S>(V); +[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t {\ + using D = std::decay_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); + constexpr auto index = enum_index(V); static_assert(index, "magic_enum::enum_index enum value does not have a index."); return *index; @@ -1259,6 +1284,7 @@ template template > [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t { using D = std::decay_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if (const auto i = enum_index(value)) { return detail::names_v[*i]; @@ -1271,6 +1297,7 @@ template > template [[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_t { using D = std::decay_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return enum_name(value); } @@ -1278,13 +1305,19 @@ template // Returns std::array with names, sorted by enum value. template > [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t> { - return detail::names_v, S>; + using D = std::decay_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); + + return detail::names_v; } // Returns std::array with pairs (value, name), sorted by enum value. template > [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t> { - return detail::entries_v, S>; + using D = std::decay_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); + + return detail::entries_v; } // Allows you to write magic_enum::enum_cast("bar", magic_enum::case_insensitive); @@ -1295,31 +1328,27 @@ inline constexpr auto case_insensitive = detail::case_insensitive<>{}; template > [[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_t>> { using D = std::decay_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); - if constexpr (detail::count_v == 0) { - static_cast(value); - return {}; // Empty enum. - } else { - if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { + if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { #if defined(MAGIC_ENUM_ENABLE_HASH) - return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( - [](D v) { return optional{v}; }, - static_cast(value), - detail::default_result_type_lambda>); + return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( + [](D v) { return optional{v}; }, + static_cast(value), + detail::default_result_type_lambda>); #else - for (std::size_t i = 0; i < detail::count_v; ++i) { - if (value == static_cast>(enum_value(i))) { - return static_cast(value); - } - } - return {}; // Invalid value or out of range. -#endif - } else { - if (value >= detail::min_v && value <= detail::max_v) { + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (value == static_cast>(enum_value(i))) { return static_cast(value); } - return {}; // Invalid value or out of range. } + return {}; // Invalid value or out of range. +#endif + } else { + if (value >= detail::min_v && value <= detail::max_v) { + return static_cast(value); + } + return {}; // Invalid value or out of range. } } @@ -1328,26 +1357,23 @@ template > template , typename BinaryPredicate = std::equal_to<>> [[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t>, BinaryPredicate> { using D = std::decay_t; + static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); - if constexpr (detail::count_v == 0) { - static_cast(value); - return {}; // Empty enum. #if defined(MAGIC_ENUM_ENABLE_HASH) - } else if constexpr (detail::is_default_predicate()) { - return detail::constexpr_switch<&detail::names_v, detail::case_call_t::index>( - [](std::size_t i) { return optional{detail::values_v[i]}; }, - value, - detail::default_result_type_lambda>, - [&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; ++i) { - if (detail::cmp_equal(value, detail::names_v[i], p)) { - return enum_value(i); - } - } - return {}; // Invalid value or out of range. + if constexpr (detail::is_default_predicate()) { + return detail::constexpr_switch<&detail::names_v, detail::case_call_t::index>( + [](std::size_t i) { return optional{detail::values_v[i]}; }, + value, + detail::default_result_type_lambda>, + [&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; ++i) { + if (detail::cmp_equal(value, detail::names_v[i], p)) { + return enum_value(i); + } + } + return {}; // Invalid value or out of range. } // Checks whether enum contains value with such value. diff --git a/src/ripple/protocol/TxFlags.h b/src/ripple/protocol/TxFlags.h index 3f73c5e27..7b010794b 100644 --- a/src/ripple/protocol/TxFlags.h +++ b/src/ripple/protocol/TxFlags.h @@ -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; diff --git a/src/ripple/protocol/impl/ErrorCodes.cpp b/src/ripple/protocol/impl/ErrorCodes.cpp index a1844890c..bc31b21b8 100644 --- a/src/ripple/protocol/impl/ErrorCodes.cpp +++ b/src/ripple/protocol/impl/ErrorCodes.cpp @@ -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 diff --git a/src/ripple/protocol/jss.h b/src/ripple/protocol/jss.h index 659aa6232..dd39b40e5 100644 --- a/src/ripple/protocol/jss.h +++ b/src/ripple/protocol/jss.h @@ -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 diff --git a/src/ripple/rpc/handlers/AccountInfo.cpp b/src/ripple/rpc/handlers/AccountInfo.cpp index 524777e38..5b85fc257 100644 --- a/src/ripple/rpc/handlers/AccountInfo.cpp +++ b/src/ripple/rpc/handlers/AccountInfo.cpp @@ -78,7 +78,7 @@ doAccountInfo(RPC::JsonContext& context) return jvAccepted; static constexpr std:: - array, 9> + array, 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:: diff --git a/src/ripple/rpc/handlers/AccountNamespace.cpp b/src/ripple/rpc/handlers/AccountNamespace.cpp index 625fa15e9..c7c969867 100644 --- a/src/ripple/rpc/handlers/AccountNamespace.cpp +++ b/src/ripple/rpc/handlers/AccountNamespace.cpp @@ -42,7 +42,6 @@ namespace ripple { namespace_id: ledger_hash: // optional ledger_index: // optional - type: // optional, defaults to all account objects types limit: // optional marker: // optional, resume previous query } diff --git a/src/ripple/rpc/handlers/LedgerEntry.cpp b/src/ripple/rpc/handlers/LedgerEntry.cpp index a6e718e39..aa5ffb02a 100644 --- a/src/ripple/rpc/handlers/LedgerEntry.cpp +++ b/src/ripple/rpc/handlers/LedgerEntry.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -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( + 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)) { diff --git a/src/ripple/rpc/handlers/ServerDefinitions.cpp b/src/ripple/rpc/handlers/ServerDefinitions.cpp index a7954b99a..e0260fdcf 100644 --- a/src/ripple/rpc/handlers/ServerDefinitions.cpp +++ b/src/ripple/rpc/handlers/ServerDefinitions.cpp @@ -17,6 +17,8 @@ */ //============================================================================== +#define MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM + #include #include #include @@ -26,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +44,21 @@ static constexpr int max = 20000; \ }; +#define MAGIC_ENUM_16(x) \ + template <> \ + struct magic_enum::customize::enum_range \ + { \ + static constexpr int min = -128; \ + static constexpr int max = 127; \ + }; + +#define MAGIC_ENUM_FLAG(x) \ + template <> \ + struct magic_enum::customize::enum_range \ + { \ + 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 + void + addFlagsToJson(Json::Value& json, std::string const& key) + { + for (auto const& entry : magic_enum::enum_entries()) + { + const auto name = entry.second; + json[jss::TRANSACTION_FLAGS][key][STR(name)] = + static_cast(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(ret, "Universal"); + addFlagsToJson(ret, "AccountSet"); + addFlagsToJson(ret, "OfferCreate"); + addFlagsToJson(ret, "Payment"); + addFlagsToJson(ret, "TrustSet"); + addFlagsToJson(ret, "EnableAmendment"); + addFlagsToJson(ret, "PaymentChannelClaim"); + addFlagsToJson(ret, "NFTokenMint"); + addFlagsToJson(ret, "NFTokenCreateOffer"); + addFlagsToJson(ret, "ClaimReward"); + struct FlagData + { + std::string name; + std::uint32_t value; + }; + std::array uriTokenMintFlags{{{"tfBurnable", tfBurnable}}}; + for (auto const& entry : uriTokenMintFlags) + { + ret[jss::TRANSACTION_FLAGS]["URITokenMint"][entry.name] = + static_cast(entry.value); + } + + // Transaction Indicies Flags: + ret[jss::TRANSACTION_FLAGS_INDICES] = Json::objectValue; + for (auto const& entry : magic_enum::enum_entries()) + { + const auto name = entry.second; + ret[jss::TRANSACTION_FLAGS_INDICES]["AccountSet"][STR(name)] = + static_cast(entry.first); + } + ret[jss::native_currency_code] = systemCurrencyCode(); // generate hash diff --git a/src/ripple/rpc/impl/RPCHelpers.cpp b/src/ripple/rpc/impl/RPCHelpers.cpp index 8a3195571..26d279dbd 100644 --- a/src/ripple/rpc/impl/RPCHelpers.cpp +++ b/src/ripple/rpc/impl/RPCHelpers.cpp @@ -1067,7 +1067,7 @@ chooseLedgerEntryType(Json::Value const& params) std::pair result{RPC::Status::OK, ltANY}; if (params.isMember(jss::type)) { - static constexpr std::array, 19> + static constexpr std::array, 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()) diff --git a/src/test/app/Import_test.cpp b/src/test/app/Import_test.cpp index d85a0420b..c115bcc4d 100644 --- a/src/test/app/Import_test.cpp +++ b/src/test/app/Import_test.cpp @@ -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(sfActiveValidator); - inner->setFieldVL(sfPublicKey, valKey); - return inner; - })()); - obj.set(([&]() { - auto inner = std::make_unique(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(); diff --git a/src/test/app/XahauGenesis_test.cpp b/src/test/app/XahauGenesis_test.cpp index 23ec46a60..3c409a36a 100644 --- a/src/test/app/XahauGenesis_test.cpp +++ b/src/test/app/XahauGenesis_test.cpp @@ -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(sfActiveValidator); - inner->setFieldVL(sfPublicKey, valKey); - return inner; - })()); - obj.set(([&]() { - auto inner = std::make_unique(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(); diff --git a/src/test/jtx/impl/unl.cpp b/src/test/jtx/impl/unl.cpp index 41cbd50b0..54d628cff 100644 --- a/src/test/jtx/impl/unl.cpp +++ b/src/test/jtx/impl/unl.cpp @@ -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(sfActiveValidator); + inner->setFieldVL(sfPublicKey, valKey); + return inner; + })()); + obj.set(([&]() { + auto inner = std::make_unique(sfImportVLKey); + inner->setFieldVL(sfPublicKey, importKey); + return inner; + })()); + }; + return STTx(ttUNL_REPORT, fill); +} + } // namespace unl } // namespace test } // namespace ripple diff --git a/src/test/jtx/unl.h b/src/test/jtx/unl.h index 68a30cc6b..2e0bae354 100644 --- a/src/test/jtx/unl.h +++ b/src/test/jtx/unl.h @@ -78,6 +78,20 @@ countTx(std::shared_ptr 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 diff --git a/src/test/rpc/AccountInfo_test.cpp b/src/test/rpc/AccountInfo_test.cpp index 78aa9e646..5c9e32328 100644 --- a/src/test/rpc/AccountInfo_test.cpp +++ b/src/test/rpc/AccountInfo_test.cpp @@ -516,7 +516,7 @@ public: }; static constexpr std:: - array, 7> + array, 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) diff --git a/src/test/rpc/AccountNamespace_test.cpp b/src/test/rpc/AccountNamespace_test.cpp new file mode 100644 index 000000000..b63b52e68 --- /dev/null +++ b/src/test/rpc/AccountNamespace_test.cpp @@ -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 +#include +#include + +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{ + 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{ + 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{ + 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{ + 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 diff --git a/src/test/rpc/AccountObjects_test.cpp b/src/test/rpc/AccountObjects_test.cpp index 2714d2c35..8a784b884 100644 --- a/src/test/rpc/AccountObjects_test.cpp +++ b/src/test/rpc/AccountObjects_test.cpp @@ -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); diff --git a/src/test/rpc/AccountOffers_test.cpp b/src/test/rpc/AccountOffers_test.cpp index 58b908f73..79e0ddd72 100644 --- a/src/test/rpc/AccountOffers_test.cpp +++ b/src/test/rpc/AccountOffers_test.cpp @@ -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); diff --git a/src/test/rpc/LedgerData_test.cpp b/src/test/rpc/LedgerData_test.cpp index 5e354c881..1c5366891 100644 --- a/src/test/rpc/LedgerData_test.cpp +++ b/src/test/rpc/LedgerData_test.cpp @@ -17,8 +17,11 @@ */ //============================================================================== +#include #include +#include #include +#include #include 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 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 const _ivlKeys = { + "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1" + "CDC1", + "ED74D4036C6591A4BDF9C54CEFA39B996A5DCE5F86D11FDA1874481CE9D5A1" + "CDC2", + }; + + std::vector ivlKeys; + for (auto const& strPk : _ivlKeys) + { + auto pkHex = strUnHex(strPk); + ivlKeys.emplace_back(makeSlice(*pkHex)); + } + + std::vector const _vlKeys = { + "ED8E43A943A174190BA2FAE91F44AC6E2D1D8202EFDCC2EA3DBB39814576D6" + "90F7", + "ED45D1840EE724BE327ABE9146503D5848EFD5F38B6D5FEDE71E80ACCE5E6E" + "738B"}; + + std::vector 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(); + 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)); diff --git a/src/test/rpc/LedgerRPC_test.cpp b/src/test/rpc/LedgerRPC_test.cpp index 7eb4e4484..de141311b 100644 --- a/src/test/rpc/LedgerRPC_test.cpp +++ b/src/test/rpc/LedgerRPC_test.cpp @@ -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 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(); diff --git a/src/test/rpc/ServerDefinitions_test.cpp b/src/test/rpc/ServerDefinitions_test.cpp index 7727f3934..fd9de6613 100644 --- a/src/test/rpc/ServerDefinitions_test.cpp +++ b/src/test/rpc/ServerDefinitions_test.cpp @@ -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