mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-05 03:35:51 +00:00
Compare commits
2 Commits
a1q123456/
...
ci/use-new
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eb6d9c1cb6 | ||
|
|
7ed62f0ea3 |
2
.github/actions/dependencies/action.yml
vendored
2
.github/actions/dependencies/action.yml
vendored
@@ -43,7 +43,7 @@ runs:
|
||||
cd ${build_dir}
|
||||
conan install \
|
||||
--output-folder . \
|
||||
--build '*' \
|
||||
--build missing \
|
||||
--options:host "&:tests=True" \
|
||||
--options:host "&:xrpld=True" \
|
||||
--settings:all build_type=${{ inputs.configuration }} \
|
||||
|
||||
2
.github/workflows/clang-format.yml
vendored
2
.github/workflows/clang-format.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
check:
|
||||
if: ${{ github.event_name == 'push' || github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'DraftRunCI') }}
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: [self-hosted, Linux, X64, devbox]
|
||||
container: ghcr.io/xrplf/ci/tools-rippled-clang-format
|
||||
steps:
|
||||
# For jobs running in containers, $GITHUB_WORKSPACE and ${{ github.workspace }} might not be the
|
||||
|
||||
2
.github/workflows/macos.yml
vendored
2
.github/workflows/macos.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
- Ninja
|
||||
configuration:
|
||||
- Release
|
||||
runs-on: [self-hosted, macOS, mac-runner-m1]
|
||||
runs-on: [self-hosted, macOS, devbox]
|
||||
env:
|
||||
# The `build` action requires these variables.
|
||||
build_dir: .build
|
||||
|
||||
12
.github/workflows/nix.yml
vendored
12
.github/workflows/nix.yml
vendored
@@ -74,7 +74,7 @@ jobs:
|
||||
compiler_version: 16
|
||||
distro: debian
|
||||
codename: bookworm
|
||||
runs-on: [self-hosted, heavy]
|
||||
runs-on: [self-hosted, Linux, X64, devbox]
|
||||
container: ghcr.io/xrplf/ci/${{ matrix.distro }}-${{ matrix.codename }}:${{ matrix.compiler }}-${{ matrix.compiler_version }}
|
||||
env:
|
||||
build_dir: .build
|
||||
@@ -133,7 +133,7 @@ jobs:
|
||||
-
|
||||
- "-Dunity=ON"
|
||||
needs: dependencies
|
||||
runs-on: [self-hosted, heavy]
|
||||
runs-on: [self-hosted, Linux, X64, devbox]
|
||||
container: ghcr.io/xrplf/ci/${{ matrix.distro }}-${{ matrix.codename }}:${{ matrix.compiler }}-${{ matrix.compiler_version }}
|
||||
env:
|
||||
build_dir: .build
|
||||
@@ -194,7 +194,7 @@ jobs:
|
||||
- "-DUNIT_TEST_REFERENCE_FEE=200"
|
||||
- "-DUNIT_TEST_REFERENCE_FEE=1000"
|
||||
needs: dependencies
|
||||
runs-on: [self-hosted, heavy]
|
||||
runs-on: [self-hosted, Linux, X64, devbox]
|
||||
container: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12
|
||||
env:
|
||||
build_dir: .build
|
||||
@@ -242,7 +242,7 @@ jobs:
|
||||
configuration:
|
||||
- Debug
|
||||
needs: dependencies
|
||||
runs-on: [self-hosted, heavy]
|
||||
runs-on: [self-hosted, Linux, X64, devbox]
|
||||
container: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12
|
||||
env:
|
||||
build_dir: .build
|
||||
@@ -309,7 +309,7 @@ jobs:
|
||||
|
||||
conan:
|
||||
needs: dependencies
|
||||
runs-on: [self-hosted, heavy]
|
||||
runs-on: [self-hosted, Linux, X64, devbox]
|
||||
container:
|
||||
image: ghcr.io/xrplf/ci/ubuntu-jammy:gcc-12
|
||||
env:
|
||||
@@ -358,7 +358,7 @@ jobs:
|
||||
|
||||
instrumentation-build:
|
||||
needs: dependencies
|
||||
runs-on: [self-hosted, heavy]
|
||||
runs-on: [self-hosted, Linux, X64, devbox]
|
||||
container: ghcr.io/xrplf/ci/debian-bookworm:clang-16
|
||||
env:
|
||||
build_dir: .build
|
||||
|
||||
2
.github/workflows/windows.yml
vendored
2
.github/workflows/windows.yml
vendored
@@ -40,7 +40,7 @@ jobs:
|
||||
matrix:
|
||||
version:
|
||||
- generator: Visual Studio 17 2022
|
||||
runs-on: windows-2022
|
||||
runs-on: [self-hosted, Windows, devbox]
|
||||
configuration:
|
||||
- type: Release
|
||||
tests: true
|
||||
|
||||
57
BUILD.md
57
BUILD.md
@@ -370,13 +370,18 @@ and can be helpful for detecting `#include` omissions.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
### Conan
|
||||
|
||||
After any updates or changes to dependencies, you may need to do the following:
|
||||
|
||||
1. Remove your build directory.
|
||||
2. Remove the Conan cache: `conan remove "*" -c`
|
||||
3. Re-run [conan install](#build-and-test).
|
||||
2. Remove the Conan cache:
|
||||
```
|
||||
rm -rf ~/.conan/data
|
||||
```
|
||||
4. Re-run [conan install](#build-and-test).
|
||||
|
||||
|
||||
### 'protobuf/port_def.inc' file not found
|
||||
|
||||
@@ -394,6 +399,54 @@ For example, if you want to build Debug:
|
||||
1. For conan install, pass `--settings build_type=Debug`
|
||||
2. For cmake, pass `-DCMAKE_BUILD_TYPE=Debug`
|
||||
|
||||
|
||||
### no std::result_of
|
||||
|
||||
If your compiler version is recent enough to have removed `std::result_of` as
|
||||
part of C++20, e.g. Apple Clang 15.0, then you might need to add a preprocessor
|
||||
definition to your build.
|
||||
|
||||
```
|
||||
conan profile update 'options.boost:extra_b2_flags="define=BOOST_ASIO_HAS_STD_INVOKE_RESULT"' default
|
||||
conan profile update 'env.CFLAGS="-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"' default
|
||||
conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"' default
|
||||
conan profile update 'conf.tools.build:cflags+=["-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"]' default
|
||||
conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_HAS_STD_INVOKE_RESULT"]' default
|
||||
```
|
||||
|
||||
|
||||
### call to 'async_teardown' is ambiguous
|
||||
|
||||
If you are compiling with an early version of Clang 16, then you might hit
|
||||
a [regression][6] when compiling C++20 that manifests as an [error in a Boost
|
||||
header][7]. You can workaround it by adding this preprocessor definition:
|
||||
|
||||
```
|
||||
conan profile update 'env.CXXFLAGS="-DBOOST_ASIO_DISABLE_CONCEPTS"' default
|
||||
conan profile update 'conf.tools.build:cxxflags+=["-DBOOST_ASIO_DISABLE_CONCEPTS"]' default
|
||||
```
|
||||
|
||||
|
||||
### recompile with -fPIC
|
||||
|
||||
If you get a linker error suggesting that you recompile Boost with
|
||||
position-independent code, such as:
|
||||
|
||||
```
|
||||
/usr/bin/ld.gold: error: /home/username/.conan/data/boost/1.77.0/_/_/package/.../lib/libboost_container.a(alloc_lib.o):
|
||||
requires unsupported dynamic reloc 11; recompile with -fPIC
|
||||
```
|
||||
|
||||
Conan most likely downloaded a bad binary distribution of the dependency.
|
||||
This seems to be a [bug][1] in Conan just for Boost 1.77.0 compiled with GCC
|
||||
for Linux. The solution is to build the dependency locally by passing
|
||||
`--build boost` when calling `conan install`.
|
||||
|
||||
```
|
||||
conan install --build boost ...
|
||||
```
|
||||
|
||||
|
||||
## Add a Dependency
|
||||
|
||||
If you want to experiment with a new package, follow these steps:
|
||||
|
||||
@@ -90,15 +90,28 @@ if (MSVC)
|
||||
-errorreport:none
|
||||
-machine:X64)
|
||||
else ()
|
||||
# HACK : because these need to come first, before any warning demotion
|
||||
string (APPEND CMAKE_CXX_FLAGS " -Wall -Wdeprecated")
|
||||
if (wextra)
|
||||
string (APPEND CMAKE_CXX_FLAGS " -Wextra -Wno-unused-parameter")
|
||||
endif ()
|
||||
# not MSVC
|
||||
target_compile_options (common
|
||||
INTERFACE
|
||||
-Wall
|
||||
-Wdeprecated
|
||||
$<$<BOOL:${wextra}>:-Wextra -Wno-unused-parameter>
|
||||
$<$<BOOL:${werr}>:-Werror>
|
||||
-fstack-protector
|
||||
$<$<COMPILE_LANGUAGE:CXX>:
|
||||
-frtti
|
||||
-Wnon-virtual-dtor
|
||||
>
|
||||
-Wno-sign-compare
|
||||
-Wno-unused-but-set-variable
|
||||
-Wno-char-subscripts
|
||||
-Wno-format
|
||||
-Wno-unused-local-typedefs
|
||||
-fstack-protector
|
||||
$<$<BOOL:${is_gcc}>:
|
||||
-Wno-unused-but-set-variable
|
||||
-Wno-deprecated
|
||||
>
|
||||
$<$<NOT:$<CONFIG:Debug>>:-fno-strict-aliasing>
|
||||
# tweak gcc optimization for debug
|
||||
$<$<AND:$<BOOL:${is_gcc}>,$<CONFIG:Debug>>:-O0>
|
||||
|
||||
@@ -26,6 +26,9 @@ tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
|
||||
{% if compiler == "apple-clang" and compiler_version >= 17 %}
|
||||
tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
|
||||
{% endif %}
|
||||
{% if compiler == "clang" and compiler_version == 16 %}
|
||||
tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS']
|
||||
{% endif %}
|
||||
{% if compiler == "gcc" and compiler_version < 13 %}
|
||||
tools.build:cxxflags=['-Wno-restrict']
|
||||
{% endif %}
|
||||
|
||||
@@ -104,7 +104,7 @@ class Xrpl(ConanFile):
|
||||
def requirements(self):
|
||||
# Conan 2 requires transitive headers to be specified
|
||||
transitive_headers_opt = {'transitive_headers': True} if conan_version.split('.')[0] == '2' else {}
|
||||
self.requires('boost/1.86.0', force=True, **transitive_headers_opt)
|
||||
self.requires('boost/1.83.0', force=True, **transitive_headers_opt)
|
||||
self.requires('date/3.0.4', **transitive_headers_opt)
|
||||
self.requires('lz4/1.10.0', force=True)
|
||||
self.requires('protobuf/3.21.12', force=True)
|
||||
|
||||
3
external/ed25519-donna/CMakeLists.txt
vendored
3
external/ed25519-donna/CMakeLists.txt
vendored
@@ -17,9 +17,6 @@ add_library(ed25519 STATIC
|
||||
)
|
||||
add_library(ed25519::ed25519 ALIAS ed25519)
|
||||
target_link_libraries(ed25519 PUBLIC OpenSSL::SSL)
|
||||
if(NOT MSVC)
|
||||
target_compile_options(ed25519 PRIVATE -Wno-implicit-fallthrough)
|
||||
endif()
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
|
||||
4
external/soci/conanfile.py
vendored
4
external/soci/conanfile.py
vendored
@@ -70,7 +70,7 @@ class SociConan(ConanFile):
|
||||
if self.options.with_postgresql:
|
||||
self.requires("libpq/15.5")
|
||||
if self.options.with_boost:
|
||||
self.requires("boost/1.86.0")
|
||||
self.requires("boost/1.83.0")
|
||||
|
||||
@property
|
||||
def _minimum_compilers_version(self):
|
||||
@@ -154,7 +154,7 @@ class SociConan(ConanFile):
|
||||
self.cpp_info.components["soci_core"].set_property("cmake_target_name", "SOCI::soci_core{}".format(target_suffix))
|
||||
self.cpp_info.components["soci_core"].libs = ["{}soci_core{}".format(lib_prefix, lib_suffix)]
|
||||
if self.options.with_boost:
|
||||
self.cpp_info.components["soci_core"].requires.append("boost::headers")
|
||||
self.cpp_info.components["soci_core"].requires.append("boost::boost")
|
||||
|
||||
# soci_empty
|
||||
if self.options.empty:
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include <boost/beast/core/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
@@ -37,28 +37,6 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
constexpr bool IsStatelessLambdaV = std::is_empty_v<T> && std::is_constructible_v<T>;
|
||||
|
||||
template<class Lambda, int=(Lambda{}(), 0)>
|
||||
constexpr std::true_type IsConstexpr(Lambda);
|
||||
constexpr std::false_type IsConstexpr(...);
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsConstexprInvocableV = IsStatelessLambdaV<T> && decltype(IsConstexpr(T{})){};
|
||||
|
||||
template <typename Lambda, bool ConstInvocable = IsConstexprInvocableV<Lambda>>
|
||||
constexpr bool ShouldTakeConstReferenceV = false;
|
||||
|
||||
template <typename Lambda>
|
||||
constexpr bool ShouldTakeConstReferenceV<Lambda, true> = Lambda{}();
|
||||
|
||||
template <typename Lambda>
|
||||
constexpr bool ShouldTakeConstReferenceV<Lambda, false> = true;
|
||||
|
||||
}
|
||||
|
||||
/** Map/cache combination.
|
||||
This class implements a cache and a map. The cache keeps objects alive
|
||||
in the map. The map allows multiple code paths that reference objects
|
||||
@@ -140,15 +118,6 @@ public:
|
||||
del(key_type const& key, bool valid);
|
||||
|
||||
public:
|
||||
|
||||
// We take a const reference if R (the replaceCallback) is a stateless
|
||||
// lambda and can be evaluated at compile time, and it's evaluated to true,
|
||||
// because there's no chance to update the parameter.
|
||||
template <class R>
|
||||
using SharedPointerTypeReference = std::conditional_t<
|
||||
detail::ShouldTakeConstReferenceV<R>,
|
||||
SharedPointerType const&,
|
||||
SharedPointerType&>;
|
||||
/** Replace aliased objects with originals.
|
||||
|
||||
Due to concurrency it is possible for two separate objects with
|
||||
@@ -158,7 +127,7 @@ public:
|
||||
|
||||
@param key The key corresponding to the object
|
||||
@param data A shared pointer to the data corresponding to the object.
|
||||
@param replaceCallback Function that decides if cache should be replaced
|
||||
@param replace Function that decides if cache should be replaced
|
||||
|
||||
@return `true` If the key already existed.
|
||||
*/
|
||||
@@ -166,7 +135,7 @@ public:
|
||||
bool
|
||||
canonicalize(
|
||||
key_type const& key,
|
||||
SharedPointerTypeReference<R> data,
|
||||
SharedPointerType& data,
|
||||
R&& replaceCallback);
|
||||
|
||||
bool
|
||||
|
||||
@@ -415,7 +415,7 @@ TaggedCache<
|
||||
Mutex>::
|
||||
canonicalize(
|
||||
key_type const& key,
|
||||
SharedPointerTypeReference<R> data,
|
||||
SharedPointerType& data,
|
||||
R&& replaceCallback)
|
||||
{
|
||||
// Return canonical value, store if needed, refresh in cache
|
||||
@@ -457,7 +457,7 @@ TaggedCache<
|
||||
{
|
||||
entry.ptr = data;
|
||||
}
|
||||
else if constexpr (std::assignable_from<decltype(data), decltype(entry.ptr.getStrong())>)
|
||||
else
|
||||
{
|
||||
data = entry.ptr.getStrong();
|
||||
}
|
||||
@@ -473,7 +473,7 @@ TaggedCache<
|
||||
{
|
||||
entry.ptr = data;
|
||||
}
|
||||
else if constexpr (std::assignable_from<decltype(data), decltype(entry.ptr.getStrong())>)
|
||||
else
|
||||
{
|
||||
entry.ptr.convertToStrong();
|
||||
data = cachedData;
|
||||
@@ -513,7 +513,7 @@ TaggedCache<
|
||||
SharedPointerType const& data)
|
||||
{
|
||||
return canonicalize(
|
||||
key, data, []() { return true; });
|
||||
key, const_cast<SharedPointerType&>(data), []() { return true; });
|
||||
}
|
||||
|
||||
template <
|
||||
|
||||
@@ -3257,6 +3257,7 @@ operator==(aged_unordered_container<
|
||||
{
|
||||
if (size() != other.size())
|
||||
return false;
|
||||
using EqRng = std::pair<const_iterator, const_iterator>;
|
||||
for (auto iter(cbegin()), last(cend()); iter != last;)
|
||||
{
|
||||
auto const& k(extract(*iter));
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
// If you add an amendment here, then do not forget to increment `numFeatures`
|
||||
// in include/xrpl/protocol/Feature.h.
|
||||
|
||||
XRPL_FIX (MPTDeliveredAmount, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (AMMClawbackRounding, Supported::no, VoteBehavior::DefaultNo)
|
||||
XRPL_FEATURE(TokenEscrow, Supported::yes, VoteBehavior::DefaultNo)
|
||||
XRPL_FIX (EnforceNFTokenTrustlineV2, Supported::yes, VoteBehavior::DefaultNo)
|
||||
|
||||
@@ -509,7 +509,6 @@ TRANSACTION(ttVAULT_WITHDRAW, 69, VaultWithdraw, Delegation::delegatable, ({
|
||||
{sfVaultID, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported},
|
||||
{sfDestination, soeOPTIONAL},
|
||||
{sfDestinationTag, soeOPTIONAL},
|
||||
}))
|
||||
|
||||
/** This transaction claws back tokens from a vault. */
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <fstream>
|
||||
#include <ios>
|
||||
#include <iterator>
|
||||
#include <optional>
|
||||
@@ -56,7 +55,7 @@ getFileContents(
|
||||
return {};
|
||||
}
|
||||
|
||||
std::ifstream fileStream(fullPath.string(), std::ios::in);
|
||||
ifstream fileStream(fullPath, std::ios::in);
|
||||
|
||||
if (!fileStream)
|
||||
{
|
||||
@@ -86,8 +85,7 @@ writeFileContents(
|
||||
using namespace boost::filesystem;
|
||||
using namespace boost::system::errc;
|
||||
|
||||
std::ofstream fileStream(
|
||||
destPath.string(), std::ios::out | std::ios::trunc);
|
||||
ofstream fileStream(destPath, std::ios::out | std::ios::trunc);
|
||||
|
||||
if (!fileStream)
|
||||
{
|
||||
|
||||
@@ -107,9 +107,8 @@ sliceToHex(Slice const& slice)
|
||||
}
|
||||
for (int i = 0; i < slice.size(); ++i)
|
||||
{
|
||||
constexpr char hex[] = "0123456789ABCDEF";
|
||||
s += hex[((slice[i] & 0xf0) >> 4)];
|
||||
s += hex[((slice[i] & 0x0f) >> 0)];
|
||||
s += "0123456789ABCDEF"[((slice[i] & 0xf0) >> 4)];
|
||||
s += "0123456789ABCDEF"[((slice[i] & 0x0f) >> 0)];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -671,12 +671,12 @@ isMemoOkay(STObject const& st, std::string& reason)
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz");
|
||||
|
||||
for (unsigned char c : symbols)
|
||||
for (char c : symbols)
|
||||
a[c] = 1;
|
||||
return a;
|
||||
}();
|
||||
|
||||
for (unsigned char c : *optData)
|
||||
for (auto c : *optData)
|
||||
{
|
||||
if (!allowedSymbols[c])
|
||||
{
|
||||
|
||||
@@ -544,7 +544,7 @@ b58_to_b256_be(std::string_view input, std::span<std::uint8_t> out)
|
||||
XRPL_ASSERT(
|
||||
num_b_58_10_coeffs <= b_58_10_coeff.size(),
|
||||
"ripple::b58_fast::detail::b58_to_b256_be : maximum coeff");
|
||||
for (unsigned char c : input.substr(0, partial_coeff_len))
|
||||
for (auto c : input.substr(0, partial_coeff_len))
|
||||
{
|
||||
auto cur_val = ::ripple::alphabetReverse[c];
|
||||
if (cur_val < 0)
|
||||
@@ -558,7 +558,7 @@ b58_to_b256_be(std::string_view input, std::span<std::uint8_t> out)
|
||||
{
|
||||
for (int j = 0; j < num_full_coeffs; ++j)
|
||||
{
|
||||
unsigned char c = input[partial_coeff_len + j * 10 + i];
|
||||
auto c = input[partial_coeff_len + j * 10 + i];
|
||||
auto cur_val = ::ripple::alphabetReverse[c];
|
||||
if (cur_val < 0)
|
||||
{
|
||||
|
||||
@@ -229,6 +229,7 @@ class RCLValidations_test : public beast::unit_test::suite
|
||||
// support for a ledger hash which is already in the trie.
|
||||
|
||||
using Seq = RCLValidatedLedger::Seq;
|
||||
using ID = RCLValidatedLedger::ID;
|
||||
|
||||
// Max known ancestors for each ledger
|
||||
Seq const maxAncestors = 256;
|
||||
|
||||
@@ -234,28 +234,6 @@ class Vault_test : public beast::unit_test::suite
|
||||
env(tx, ter{tecNO_PERMISSION});
|
||||
}
|
||||
|
||||
{
|
||||
testcase(prefix + " fail to withdraw to zero destination");
|
||||
auto tx = vault.withdraw(
|
||||
{.depositor = depositor,
|
||||
.id = keylet.key,
|
||||
.amount = asset(1000)});
|
||||
tx[sfDestination] = "0";
|
||||
env(tx, ter(temMALFORMED));
|
||||
}
|
||||
|
||||
{
|
||||
testcase(
|
||||
prefix +
|
||||
" fail to withdraw with tag but without destination");
|
||||
auto tx = vault.withdraw(
|
||||
{.depositor = depositor,
|
||||
.id = keylet.key,
|
||||
.amount = asset(1000)});
|
||||
tx[sfDestinationTag] = "0";
|
||||
env(tx, ter(temMALFORMED));
|
||||
}
|
||||
|
||||
if (!asset.raw().native())
|
||||
{
|
||||
testcase(
|
||||
@@ -1357,7 +1335,6 @@ class Vault_test : public beast::unit_test::suite
|
||||
struct CaseArgs
|
||||
{
|
||||
bool enableClawback = true;
|
||||
bool requireAuth = true;
|
||||
};
|
||||
|
||||
auto testCase = [this](
|
||||
@@ -1379,20 +1356,16 @@ class Vault_test : public beast::unit_test::suite
|
||||
Vault vault{env};
|
||||
|
||||
MPTTester mptt{env, issuer, mptInitNoFund};
|
||||
auto const none = LedgerSpecificFlags(0);
|
||||
mptt.create(
|
||||
{.flags = tfMPTCanTransfer | tfMPTCanLock |
|
||||
(args.enableClawback ? tfMPTCanClawback : none) |
|
||||
(args.requireAuth ? tfMPTRequireAuth : none)});
|
||||
(args.enableClawback ? lsfMPTCanClawback
|
||||
: LedgerSpecificFlags(0)) |
|
||||
tfMPTRequireAuth});
|
||||
PrettyAsset asset = mptt.issuanceID();
|
||||
mptt.authorize({.account = owner});
|
||||
mptt.authorize({.account = issuer, .holder = owner});
|
||||
mptt.authorize({.account = depositor});
|
||||
if (args.requireAuth)
|
||||
{
|
||||
mptt.authorize({.account = issuer, .holder = owner});
|
||||
mptt.authorize({.account = issuer, .holder = depositor});
|
||||
}
|
||||
|
||||
mptt.authorize({.account = issuer, .holder = depositor});
|
||||
env(pay(issuer, depositor, asset(1000)));
|
||||
env.close();
|
||||
|
||||
@@ -1541,100 +1514,6 @@ class Vault_test : public beast::unit_test::suite
|
||||
}
|
||||
});
|
||||
|
||||
testCase(
|
||||
[this](
|
||||
Env& env,
|
||||
Account const& issuer,
|
||||
Account const& owner,
|
||||
Account const& depositor,
|
||||
PrettyAsset const& asset,
|
||||
Vault& vault,
|
||||
MPTTester& mptt) {
|
||||
testcase(
|
||||
"MPT 3rd party without MPToken cannot be withdrawal "
|
||||
"destination");
|
||||
|
||||
auto [tx, keylet] =
|
||||
vault.create({.owner = owner, .asset = asset});
|
||||
env(tx);
|
||||
env.close();
|
||||
|
||||
tx = vault.deposit(
|
||||
{.depositor = depositor,
|
||||
.id = keylet.key,
|
||||
.amount = asset(100)});
|
||||
env(tx);
|
||||
env.close();
|
||||
|
||||
{
|
||||
// Set destination to 3rd party without MPToken
|
||||
Account charlie{"charlie"};
|
||||
env.fund(XRP(1000), charlie);
|
||||
env.close();
|
||||
|
||||
tx = vault.withdraw(
|
||||
{.depositor = depositor,
|
||||
.id = keylet.key,
|
||||
.amount = asset(100)});
|
||||
tx[sfDestination] = charlie.human();
|
||||
env(tx, ter(tecNO_AUTH));
|
||||
}
|
||||
},
|
||||
{.requireAuth = false});
|
||||
|
||||
testCase(
|
||||
[this](
|
||||
Env& env,
|
||||
Account const& issuer,
|
||||
Account const& owner,
|
||||
Account const& depositor,
|
||||
PrettyAsset const& asset,
|
||||
Vault& vault,
|
||||
MPTTester& mptt) {
|
||||
testcase("MPT depositor without MPToken cannot withdraw");
|
||||
|
||||
auto [tx, keylet] =
|
||||
vault.create({.owner = owner, .asset = asset});
|
||||
env(tx);
|
||||
env.close();
|
||||
|
||||
tx = vault.deposit(
|
||||
{.depositor = depositor,
|
||||
.id = keylet.key,
|
||||
.amount = asset(1000)});
|
||||
env(tx);
|
||||
env.close();
|
||||
|
||||
{
|
||||
// Remove depositor's MPToken and withdraw will fail
|
||||
mptt.authorize(
|
||||
{.account = depositor, .flags = tfMPTUnauthorize});
|
||||
env.close();
|
||||
auto const mptoken =
|
||||
env.le(keylet::mptoken(mptt.issuanceID(), depositor));
|
||||
BEAST_EXPECT(mptoken == nullptr);
|
||||
|
||||
tx = vault.withdraw(
|
||||
{.depositor = depositor,
|
||||
.id = keylet.key,
|
||||
.amount = asset(100)});
|
||||
env(tx, ter(tecNO_AUTH));
|
||||
}
|
||||
|
||||
{
|
||||
// Restore depositor's MPToken and withdraw will succeed
|
||||
mptt.authorize({.account = depositor});
|
||||
env.close();
|
||||
|
||||
tx = vault.withdraw(
|
||||
{.depositor = depositor,
|
||||
.id = keylet.key,
|
||||
.amount = asset(100)});
|
||||
env(tx);
|
||||
}
|
||||
},
|
||||
{.requireAuth = false});
|
||||
|
||||
testCase([this](
|
||||
Env& env,
|
||||
Account const& issuer,
|
||||
@@ -1924,7 +1803,6 @@ class Vault_test : public beast::unit_test::suite
|
||||
|
||||
PrettyAsset const asset = issuer["IOU"];
|
||||
env.trust(asset(1000), owner);
|
||||
env.trust(asset(1000), charlie);
|
||||
env(pay(issuer, owner, asset(200)));
|
||||
env(rate(issuer, 1.25));
|
||||
env.close();
|
||||
@@ -2240,79 +2118,6 @@ class Vault_test : public beast::unit_test::suite
|
||||
env.close();
|
||||
});
|
||||
|
||||
testCase([&, this](
|
||||
Env& env,
|
||||
Account const& owner,
|
||||
Account const& issuer,
|
||||
Account const& charlie,
|
||||
auto,
|
||||
Vault& vault,
|
||||
PrettyAsset const& asset,
|
||||
auto&&...) {
|
||||
testcase("IOU no trust line to 3rd party");
|
||||
|
||||
auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
|
||||
env(tx);
|
||||
env.close();
|
||||
|
||||
env(vault.deposit(
|
||||
{.depositor = owner, .id = keylet.key, .amount = asset(100)}));
|
||||
env.close();
|
||||
|
||||
Account const erin{"erin"};
|
||||
env.fund(XRP(1000), erin);
|
||||
env.close();
|
||||
|
||||
// Withdraw to 3rd party without trust line
|
||||
auto const tx1 = [&](ripple::Keylet keylet) {
|
||||
auto tx = vault.withdraw(
|
||||
{.depositor = owner,
|
||||
.id = keylet.key,
|
||||
.amount = asset(10)});
|
||||
tx[sfDestination] = erin.human();
|
||||
return tx;
|
||||
}(keylet);
|
||||
env(tx1, ter{tecNO_LINE});
|
||||
});
|
||||
|
||||
testCase([&, this](
|
||||
Env& env,
|
||||
Account const& owner,
|
||||
Account const& issuer,
|
||||
Account const& charlie,
|
||||
auto,
|
||||
Vault& vault,
|
||||
PrettyAsset const& asset,
|
||||
auto&&...) {
|
||||
testcase("IOU no trust line to depositor");
|
||||
|
||||
auto [tx, keylet] = vault.create({.owner = owner, .asset = asset});
|
||||
env(tx);
|
||||
env.close();
|
||||
|
||||
// reset limit, so deposit of all funds will delete the trust line
|
||||
env.trust(asset(0), owner);
|
||||
env.close();
|
||||
|
||||
env(vault.deposit(
|
||||
{.depositor = owner, .id = keylet.key, .amount = asset(200)}));
|
||||
env.close();
|
||||
|
||||
auto trustline =
|
||||
env.le(keylet::line(owner, asset.raw().get<Issue>()));
|
||||
BEAST_EXPECT(trustline == nullptr);
|
||||
|
||||
// Withdraw without trust line, will succeed
|
||||
auto const tx1 = [&](ripple::Keylet keylet) {
|
||||
auto tx = vault.withdraw(
|
||||
{.depositor = owner,
|
||||
.id = keylet.key,
|
||||
.amount = asset(10)});
|
||||
return tx;
|
||||
}(keylet);
|
||||
env(tx1);
|
||||
});
|
||||
|
||||
testCase([&, this](
|
||||
Env& env,
|
||||
Account const& owner,
|
||||
|
||||
@@ -148,30 +148,6 @@ public:
|
||||
BEAST_EXPECT(c.getCacheSize() == 0);
|
||||
BEAST_EXPECT(c.getTrackSize() == 0);
|
||||
}
|
||||
{
|
||||
BEAST_EXPECT(!c.insert(5, "five"));
|
||||
BEAST_EXPECT(c.getCacheSize() == 1);
|
||||
BEAST_EXPECT(c.getTrackSize() == 1);
|
||||
|
||||
auto const p1 = c.fetch(5);
|
||||
BEAST_EXPECT(p1 != nullptr);
|
||||
BEAST_EXPECT(c.getCacheSize() == 1);
|
||||
BEAST_EXPECT(c.getTrackSize() == 1);
|
||||
|
||||
// Advance the clock a lot
|
||||
++clock;
|
||||
c.sweep();
|
||||
BEAST_EXPECT(c.getCacheSize() == 0);
|
||||
BEAST_EXPECT(c.getTrackSize() == 1);
|
||||
|
||||
auto p2 = std::make_shared<std::string>("five_2");
|
||||
BEAST_EXPECT(c.canonicalize_replace_cache(5, p2));
|
||||
BEAST_EXPECT(c.getCacheSize() == 1);
|
||||
BEAST_EXPECT(c.getTrackSize() == 1);
|
||||
// Make sure we get the original object
|
||||
BEAST_EXPECT(p1.get() != p2.get());
|
||||
BEAST_EXPECT(*p2 == "five_2");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -703,6 +703,10 @@ aged_associative_container_test_base::checkContentsRefRef(
|
||||
Values const& v)
|
||||
{
|
||||
using Cont = typename std::remove_reference<C>::type;
|
||||
using Traits = TestTraits<
|
||||
Cont::is_unordered::value,
|
||||
Cont::is_multi::value,
|
||||
Cont::is_map::value>;
|
||||
using size_type = typename Cont::size_type;
|
||||
|
||||
BEAST_EXPECT(c.size() == v.size());
|
||||
@@ -757,6 +761,10 @@ typename std::enable_if<!IsUnordered>::type
|
||||
aged_associative_container_test_base::testConstructEmpty()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
using Value = typename Traits::Value;
|
||||
using Key = typename Traits::Key;
|
||||
using T = typename Traits::T;
|
||||
using Clock = typename Traits::Clock;
|
||||
using Comp = typename Traits::Comp;
|
||||
using Alloc = typename Traits::Alloc;
|
||||
using MyComp = typename Traits::MyComp;
|
||||
@@ -794,6 +802,10 @@ typename std::enable_if<IsUnordered>::type
|
||||
aged_associative_container_test_base::testConstructEmpty()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
using Value = typename Traits::Value;
|
||||
using Key = typename Traits::Key;
|
||||
using T = typename Traits::T;
|
||||
using Clock = typename Traits::Clock;
|
||||
using Hash = typename Traits::Hash;
|
||||
using Equal = typename Traits::Equal;
|
||||
using Alloc = typename Traits::Alloc;
|
||||
@@ -858,6 +870,10 @@ typename std::enable_if<!IsUnordered>::type
|
||||
aged_associative_container_test_base::testConstructRange()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
using Value = typename Traits::Value;
|
||||
using Key = typename Traits::Key;
|
||||
using T = typename Traits::T;
|
||||
using Clock = typename Traits::Clock;
|
||||
using Comp = typename Traits::Comp;
|
||||
using Alloc = typename Traits::Alloc;
|
||||
using MyComp = typename Traits::MyComp;
|
||||
@@ -909,6 +925,10 @@ typename std::enable_if<IsUnordered>::type
|
||||
aged_associative_container_test_base::testConstructRange()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
using Value = typename Traits::Value;
|
||||
using Key = typename Traits::Key;
|
||||
using T = typename Traits::T;
|
||||
using Clock = typename Traits::Clock;
|
||||
using Hash = typename Traits::Hash;
|
||||
using Equal = typename Traits::Equal;
|
||||
using Alloc = typename Traits::Alloc;
|
||||
@@ -976,6 +996,14 @@ typename std::enable_if<!IsUnordered>::type
|
||||
aged_associative_container_test_base::testConstructInitList()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
using Value = typename Traits::Value;
|
||||
using Key = typename Traits::Key;
|
||||
using T = typename Traits::T;
|
||||
using Clock = typename Traits::Clock;
|
||||
using Comp = typename Traits::Comp;
|
||||
using Alloc = typename Traits::Alloc;
|
||||
using MyComp = typename Traits::MyComp;
|
||||
using MyAlloc = typename Traits::MyAlloc;
|
||||
typename Traits::ManualClock clock;
|
||||
|
||||
// testcase (Traits::name() + " init-list");
|
||||
@@ -992,6 +1020,16 @@ typename std::enable_if<IsUnordered>::type
|
||||
aged_associative_container_test_base::testConstructInitList()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
using Value = typename Traits::Value;
|
||||
using Key = typename Traits::Key;
|
||||
using T = typename Traits::T;
|
||||
using Clock = typename Traits::Clock;
|
||||
using Hash = typename Traits::Hash;
|
||||
using Equal = typename Traits::Equal;
|
||||
using Alloc = typename Traits::Alloc;
|
||||
using MyHash = typename Traits::MyHash;
|
||||
using MyEqual = typename Traits::MyEqual;
|
||||
using MyAlloc = typename Traits::MyAlloc;
|
||||
typename Traits::ManualClock clock;
|
||||
|
||||
// testcase (Traits::name() + " init-list");
|
||||
@@ -1012,6 +1050,7 @@ void
|
||||
aged_associative_container_test_base::testCopyMove()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
using Value = typename Traits::Value;
|
||||
using Alloc = typename Traits::Alloc;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v(Traits::values());
|
||||
@@ -1082,6 +1121,8 @@ void
|
||||
aged_associative_container_test_base::testIterator()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
using Value = typename Traits::Value;
|
||||
using Alloc = typename Traits::Alloc;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v(Traits::values());
|
||||
|
||||
@@ -1138,6 +1179,8 @@ typename std::enable_if<!IsUnordered>::type
|
||||
aged_associative_container_test_base::testReverseIterator()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
using Value = typename Traits::Value;
|
||||
using Alloc = typename Traits::Alloc;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v(Traits::values());
|
||||
|
||||
@@ -1147,6 +1190,7 @@ aged_associative_container_test_base::testReverseIterator()
|
||||
typename Traits::template Cont<> c{clock};
|
||||
|
||||
using iterator = decltype(c.begin());
|
||||
using const_iterator = decltype(c.cbegin());
|
||||
using reverse_iterator = decltype(c.rbegin());
|
||||
using const_reverse_iterator = decltype(c.crbegin());
|
||||
|
||||
@@ -1350,6 +1394,7 @@ void
|
||||
aged_associative_container_test_base::testChronological()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
using Value = typename Traits::Value;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v(Traits::values());
|
||||
|
||||
@@ -1715,6 +1760,7 @@ typename std::enable_if<!IsUnordered>::type
|
||||
aged_associative_container_test_base::testCompare()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
using Value = typename Traits::Value;
|
||||
typename Traits::ManualClock clock;
|
||||
auto const v(Traits::values());
|
||||
|
||||
@@ -1786,6 +1832,8 @@ template <bool IsUnordered, bool IsMulti, bool IsMap>
|
||||
void
|
||||
aged_associative_container_test_base::testMaybeUnorderedMultiMap()
|
||||
{
|
||||
using Traits = TestTraits<IsUnordered, IsMulti, IsMap>;
|
||||
|
||||
testConstructEmpty<IsUnordered, IsMulti, IsMap>();
|
||||
testConstructRange<IsUnordered, IsMulti, IsMap>();
|
||||
testConstructInitList<IsUnordered, IsMulti, IsMap>();
|
||||
|
||||
@@ -313,6 +313,7 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
testSupport()
|
||||
{
|
||||
using namespace csf;
|
||||
using Seq = Ledger::Seq;
|
||||
|
||||
LedgerTrie<Ledger> t;
|
||||
LedgerHistoryHelper h;
|
||||
@@ -595,6 +596,7 @@ class LedgerTrie_test : public beast::unit_test::suite
|
||||
testRootRelated()
|
||||
{
|
||||
using namespace csf;
|
||||
using Seq = Ledger::Seq;
|
||||
// Since the root is a special node that breaks the no-single child
|
||||
// invariant, do some tests that exercise it.
|
||||
|
||||
|
||||
@@ -805,6 +805,7 @@ class Validations_test : public beast::unit_test::suite
|
||||
Ledger ledgerACD = h["acd"];
|
||||
|
||||
using Seq = Ledger::Seq;
|
||||
using ID = Ledger::ID;
|
||||
|
||||
auto pref = [](Ledger ledger) {
|
||||
return std::make_pair(ledger.seq(), ledger.id());
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
#include <boost/beast/core/flat_buffer.hpp>
|
||||
#include <boost/beast/http.hpp>
|
||||
#include <boost/beast/ssl.hpp>
|
||||
#include <boost/beast/version.hpp>
|
||||
@@ -221,8 +220,9 @@ public:
|
||||
getList_ = [blob = blob, sig, manifest, version](int interval) {
|
||||
// Build the contents of a version 1 format UNL file
|
||||
std::stringstream l;
|
||||
l << "{\"blob\":\"" << blob << "\"" << ",\"signature\":\"" << sig
|
||||
<< "\"" << ",\"manifest\":\"" << manifest << "\""
|
||||
l << "{\"blob\":\"" << blob << "\""
|
||||
<< ",\"signature\":\"" << sig << "\""
|
||||
<< ",\"manifest\":\"" << manifest << "\""
|
||||
<< ",\"refresh_interval\": " << interval
|
||||
<< ",\"version\":" << version << '}';
|
||||
return l.str();
|
||||
@@ -257,14 +257,15 @@ public:
|
||||
std::stringstream l;
|
||||
for (auto const& info : blobInfo)
|
||||
{
|
||||
l << "{\"blob\":\"" << info.blob << "\"" << ",\"signature\":\""
|
||||
<< info.signature << "\"},";
|
||||
l << "{\"blob\":\"" << info.blob << "\""
|
||||
<< ",\"signature\":\"" << info.signature << "\"},";
|
||||
}
|
||||
std::string blobs = l.str();
|
||||
blobs.pop_back();
|
||||
l.str(std::string());
|
||||
l << "{\"blobs_v2\": [ " << blobs << "],\"manifest\":\"" << manifest
|
||||
<< "\"" << ",\"refresh_interval\": " << interval
|
||||
<< "\""
|
||||
<< ",\"refresh_interval\": " << interval
|
||||
<< ",\"version\":" << (version + 1) << '}';
|
||||
return l.str();
|
||||
};
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <test/jtx/WSClient.h>
|
||||
|
||||
#include <xrpl/beast/unit_test.h>
|
||||
#include <xrpl/beast/unit_test/suite.h>
|
||||
#include <xrpl/protocol/jss.h>
|
||||
|
||||
namespace ripple {
|
||||
@@ -330,95 +329,12 @@ class DeliveredAmount_test : public beast::unit_test::suite
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testMPTDeliveredAmountRPC(FeatureBitset features)
|
||||
{
|
||||
testcase("MPT DeliveredAmount");
|
||||
|
||||
using namespace jtx;
|
||||
Account const alice("alice");
|
||||
Account const carol("carol");
|
||||
Account const bob("bob");
|
||||
Env env{*this, features};
|
||||
|
||||
MPTTester mptAlice(
|
||||
env, alice, {.holders = {bob, carol}, .close = false});
|
||||
|
||||
mptAlice.create(
|
||||
{.transferFee = 25000,
|
||||
.ownerCount = 1,
|
||||
.holderCount = 0,
|
||||
.flags = tfMPTCanTransfer});
|
||||
auto const MPT = mptAlice["MPT"];
|
||||
|
||||
mptAlice.authorize({.account = bob});
|
||||
mptAlice.authorize({.account = carol});
|
||||
|
||||
// issuer to holder
|
||||
mptAlice.pay(alice, bob, 10000);
|
||||
|
||||
// holder to holder
|
||||
env(pay(bob, carol, mptAlice.mpt(1000)), txflags(tfPartialPayment));
|
||||
env.close();
|
||||
|
||||
// Get the hash for the most recent transaction.
|
||||
std::string txHash{
|
||||
env.tx()->getJson(JsonOptions::none)[jss::hash].asString()};
|
||||
Json::Value meta = env.rpc("tx", txHash)[jss::result][jss::meta];
|
||||
|
||||
if (features[fixMPTDeliveredAmount])
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
meta[sfDeliveredAmount.jsonName] ==
|
||||
STAmount{MPT(800)}.getJson(JsonOptions::none));
|
||||
BEAST_EXPECT(
|
||||
meta[jss::delivered_amount] ==
|
||||
STAmount{MPT(800)}.getJson(JsonOptions::none));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!meta.isMember(sfDeliveredAmount.jsonName));
|
||||
BEAST_EXPECT(
|
||||
meta[jss::delivered_amount] = Json::Value("unavailable"));
|
||||
}
|
||||
|
||||
env(pay(bob, carol, MPT(1000)),
|
||||
sendmax(MPT(1200)),
|
||||
txflags(tfPartialPayment));
|
||||
env.close();
|
||||
|
||||
txHash = env.tx()->getJson(JsonOptions::none)[jss::hash].asString();
|
||||
meta = env.rpc("tx", txHash)[jss::result][jss::meta];
|
||||
|
||||
if (features[fixMPTDeliveredAmount])
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
meta[sfDeliveredAmount.jsonName] ==
|
||||
STAmount{MPT(960)}.getJson(JsonOptions::none));
|
||||
BEAST_EXPECT(
|
||||
meta[jss::delivered_amount] ==
|
||||
STAmount{MPT(960)}.getJson(JsonOptions::none));
|
||||
}
|
||||
else
|
||||
{
|
||||
BEAST_EXPECT(!meta.isMember(sfDeliveredAmount.jsonName));
|
||||
BEAST_EXPECT(
|
||||
meta[jss::delivered_amount] = Json::Value("unavailable"));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
using namespace test::jtx;
|
||||
FeatureBitset const all{testable_amendments()};
|
||||
|
||||
testTxDeliveredAmountRPC();
|
||||
testAccountDeliveredAmountSubscribe();
|
||||
|
||||
testMPTDeliveredAmountRPC(all - fixMPTDeliveredAmount);
|
||||
testMPTDeliveredAmountRPC(all);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -681,7 +681,7 @@ class ServerStatus_test : public beast::unit_test::suite,
|
||||
resp["Upgrade"] == "websocket");
|
||||
BEAST_EXPECT(
|
||||
resp.find("Connection") != resp.end() &&
|
||||
resp["Connection"] == "Upgrade");
|
||||
resp["Connection"] == "upgrade");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -26,8 +26,6 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
namespace detail {
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
|
||||
@@ -315,14 +315,14 @@ escrowCreatePreclaimHelper<MPTIssue>(
|
||||
// authorized
|
||||
auto const& mptIssue = amount.get<MPTIssue>();
|
||||
if (auto const ter =
|
||||
requireAuth(ctx.view, mptIssue, account, AuthType::WeakAuth);
|
||||
requireAuth(ctx.view, mptIssue, account, MPTAuthType::WeakAuth);
|
||||
ter != tesSUCCESS)
|
||||
return ter;
|
||||
|
||||
// If the issuer has requireAuth set, check if the destination is
|
||||
// authorized
|
||||
if (auto const ter =
|
||||
requireAuth(ctx.view, mptIssue, dest, AuthType::WeakAuth);
|
||||
requireAuth(ctx.view, mptIssue, dest, MPTAuthType::WeakAuth);
|
||||
ter != tesSUCCESS)
|
||||
return ter;
|
||||
|
||||
@@ -746,7 +746,7 @@ escrowFinishPreclaimHelper<MPTIssue>(
|
||||
// authorized
|
||||
auto const& mptIssue = amount.get<MPTIssue>();
|
||||
if (auto const ter =
|
||||
requireAuth(ctx.view, mptIssue, dest, AuthType::WeakAuth);
|
||||
requireAuth(ctx.view, mptIssue, dest, MPTAuthType::WeakAuth);
|
||||
ter != tesSUCCESS)
|
||||
return ter;
|
||||
|
||||
@@ -1259,7 +1259,7 @@ escrowCancelPreclaimHelper<MPTIssue>(
|
||||
// authorized
|
||||
auto const& mptIssue = amount.get<MPTIssue>();
|
||||
if (auto const ter =
|
||||
requireAuth(ctx.view, mptIssue, account, AuthType::WeakAuth);
|
||||
requireAuth(ctx.view, mptIssue, account, MPTAuthType::WeakAuth);
|
||||
ter != tesSUCCESS)
|
||||
return ter;
|
||||
|
||||
|
||||
@@ -580,16 +580,7 @@ Payment::doApply()
|
||||
auto res = accountSend(
|
||||
pv, account_, dstAccountID, amountDeliver, ctx_.journal);
|
||||
if (res == tesSUCCESS)
|
||||
{
|
||||
pv.apply(ctx_.rawView());
|
||||
|
||||
// If the actual amount delivered is different from the original
|
||||
// amount due to partial payment or transfer fee, we need to update
|
||||
// DelieveredAmount using the actual delivered amount
|
||||
if (view().rules().enabled(fixMPTDeliveredAmount) &&
|
||||
amountDeliver != dstAmount)
|
||||
ctx_.deliver(amountDeliver);
|
||||
}
|
||||
else if (res == tecINSUFFICIENT_FUNDS || res == tecPATH_DRY)
|
||||
res = tecPATH_PARTIAL;
|
||||
|
||||
|
||||
@@ -52,19 +52,9 @@ VaultWithdraw::preflight(PreflightContext const& ctx)
|
||||
return temBAD_AMOUNT;
|
||||
|
||||
if (auto const destination = ctx.tx[~sfDestination];
|
||||
destination.has_value())
|
||||
destination && *destination == beast::zero)
|
||||
{
|
||||
if (*destination == beast::zero)
|
||||
{
|
||||
JLOG(ctx.j.debug())
|
||||
<< "VaultWithdraw: zero/empty destination account.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
}
|
||||
else if (ctx.tx.isFieldPresent(sfDestinationTag))
|
||||
{
|
||||
JLOG(ctx.j.debug()) << "VaultWithdraw: sfDestinationTag is set but "
|
||||
"sfDestination is not";
|
||||
JLOG(ctx.j.debug()) << "VaultWithdraw: zero/empty destination account.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
@@ -133,39 +123,33 @@ VaultWithdraw::preclaim(PreclaimContext const& ctx)
|
||||
|
||||
// Withdrawal to a 3rd party destination account is essentially a transfer,
|
||||
// via shares in the vault. Enforce all the usual asset transfer checks.
|
||||
AuthType authType = AuthType::Legacy;
|
||||
if (account != dstAcct)
|
||||
{
|
||||
auto const sleDst = ctx.view.read(keylet::account(dstAcct));
|
||||
if (sleDst == nullptr)
|
||||
return tecNO_DST;
|
||||
|
||||
if (sleDst->isFlag(lsfRequireDestTag) &&
|
||||
!ctx.tx.isFieldPresent(sfDestinationTag))
|
||||
if (sleDst->getFlags() & lsfRequireDestTag)
|
||||
return tecDST_TAG_NEEDED; // Cannot send without a tag
|
||||
|
||||
if (sleDst->isFlag(lsfDepositAuth))
|
||||
if (sleDst->getFlags() & lsfDepositAuth)
|
||||
{
|
||||
if (!ctx.view.exists(keylet::depositPreauth(dstAcct, account)))
|
||||
return tecNO_PERMISSION;
|
||||
}
|
||||
// The destination account must have consented to receive the asset by
|
||||
// creating a RippleState or MPToken
|
||||
authType = AuthType::StrongAuth;
|
||||
}
|
||||
|
||||
// Destination MPToken (for an MPT) or trust line (for an IOU) must exist
|
||||
// if not sending to Account.
|
||||
if (auto const ter = requireAuth(ctx.view, vaultAsset, dstAcct, authType);
|
||||
// Destination MPToken must exist (if asset is an MPT)
|
||||
if (auto const ter = requireAuth(ctx.view, vaultAsset, dstAcct);
|
||||
!isTesSuccess(ter))
|
||||
return ter;
|
||||
|
||||
// Cannot withdraw from a Vault an Asset frozen for the destination account
|
||||
if (auto const ret = checkFrozen(ctx.view, dstAcct, vaultAsset))
|
||||
return ret;
|
||||
if (isFrozen(ctx.view, dstAcct, vaultAsset))
|
||||
return vaultAsset.holds<Issue>() ? tecFROZEN : tecLOCKED;
|
||||
|
||||
if (auto const ret = checkFrozen(ctx.view, account, vaultShare))
|
||||
return ret;
|
||||
if (isFrozen(ctx.view, account, vaultShare))
|
||||
return tecLOCKED;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
@@ -175,29 +175,6 @@ isFrozen(
|
||||
asset.value());
|
||||
}
|
||||
|
||||
[[nodiscard]] inline TER
|
||||
checkFrozen(ReadView const& view, AccountID const& account, Issue const& issue)
|
||||
{
|
||||
return isFrozen(view, account, issue) ? (TER)tecFROZEN : (TER)tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline TER
|
||||
checkFrozen(
|
||||
ReadView const& view,
|
||||
AccountID const& account,
|
||||
MPTIssue const& mptIssue)
|
||||
{
|
||||
return isFrozen(view, account, mptIssue) ? (TER)tecLOCKED : (TER)tesSUCCESS;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline TER
|
||||
checkFrozen(ReadView const& view, AccountID const& account, Asset const& asset)
|
||||
{
|
||||
return std::visit(
|
||||
[&](auto const& issue) { return checkFrozen(view, account, issue); },
|
||||
asset.value());
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isAnyFrozen(
|
||||
ReadView const& view,
|
||||
@@ -748,40 +725,19 @@ transferXRP(
|
||||
STAmount const& amount,
|
||||
beast::Journal j);
|
||||
|
||||
/* Check if MPToken (for MPT) or trust line (for IOU) exists:
|
||||
* - StrongAuth - before checking if authorization is required
|
||||
* - WeakAuth
|
||||
* for MPT - after checking lsfMPTRequireAuth flag
|
||||
* for IOU - do not check if trust line exists
|
||||
* - Legacy
|
||||
* for MPT - before checking lsfMPTRequireAuth flag i.e. same as StrongAuth
|
||||
* for IOU - do not check if trust line exists i.e. same as WeakAuth
|
||||
/* Check if MPToken exists:
|
||||
* - StrongAuth - before checking lsfMPTRequireAuth is set
|
||||
* - WeakAuth - after checking if lsfMPTRequireAuth is set
|
||||
*/
|
||||
enum class AuthType { StrongAuth, WeakAuth, Legacy };
|
||||
enum class MPTAuthType : bool { StrongAuth = true, WeakAuth = false };
|
||||
|
||||
/** Check if the account lacks required authorization.
|
||||
*
|
||||
* Return tecNO_AUTH or tecNO_LINE if it does
|
||||
* and tesSUCCESS otherwise.
|
||||
*
|
||||
* If StrongAuth then return tecNO_LINE if the RippleState doesn't exist. Return
|
||||
* tecNO_AUTH if lsfRequireAuth is set on the issuer's AccountRoot, and the
|
||||
* RippleState does exist, and the RippleState is not authorized.
|
||||
*
|
||||
* If WeakAuth then return tecNO_AUTH if lsfRequireAuth is set, and the
|
||||
* RippleState exists, and is not authorized. Return tecNO_LINE if
|
||||
* lsfRequireAuth is set and the RippleState doesn't exist. Consequently, if
|
||||
* WeakAuth and lsfRequireAuth is *not* set, this function will return
|
||||
* tesSUCCESS even if RippleState does *not* exist.
|
||||
*
|
||||
* The default "Legacy" auth type is equivalent to WeakAuth.
|
||||
* Return tecNO_AUTH or tecNO_LINE if it does
|
||||
* and tesSUCCESS otherwise.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
requireAuth(
|
||||
ReadView const& view,
|
||||
Issue const& issue,
|
||||
AccountID const& account,
|
||||
AuthType authType = AuthType::Legacy);
|
||||
requireAuth(ReadView const& view, Issue const& issue, AccountID const& account);
|
||||
|
||||
/** Check if the account lacks required authorization.
|
||||
*
|
||||
@@ -795,33 +751,32 @@ requireAuth(
|
||||
* purely defensive, as we currently do not allow such vaults to be created.
|
||||
*
|
||||
* If StrongAuth then return tecNO_AUTH if MPToken doesn't exist or
|
||||
* lsfMPTRequireAuth is set and MPToken is not authorized.
|
||||
*
|
||||
* If WeakAuth then return tecNO_AUTH if lsfMPTRequireAuth is set and MPToken
|
||||
* doesn't exist or is not authorized (explicitly or via credentials, if
|
||||
* DomainID is set in MPTokenIssuance). Consequently, if WeakAuth and
|
||||
* lsfMPTRequireAuth is *not* set, this function will return true even if
|
||||
* MPToken does *not* exist.
|
||||
*
|
||||
* The default "Legacy" auth type is equivalent to StrongAuth.
|
||||
* lsfMPTRequireAuth is set and MPToken is not authorized. If WeakAuth then
|
||||
* return tecNO_AUTH if lsfMPTRequireAuth is set and MPToken doesn't exist or is
|
||||
* not authorized (explicitly or via credentials, if DomainID is set in
|
||||
* MPTokenIssuance). Consequently, if WeakAuth and lsfMPTRequireAuth is *not*
|
||||
* set, this function will return true even if MPToken does *not* exist.
|
||||
*/
|
||||
[[nodiscard]] TER
|
||||
requireAuth(
|
||||
ReadView const& view,
|
||||
MPTIssue const& mptIssue,
|
||||
AccountID const& account,
|
||||
AuthType authType = AuthType::Legacy,
|
||||
MPTAuthType authType = MPTAuthType::StrongAuth,
|
||||
int depth = 0);
|
||||
|
||||
[[nodiscard]] TER inline requireAuth(
|
||||
ReadView const& view,
|
||||
Asset const& asset,
|
||||
AccountID const& account,
|
||||
AuthType authType = AuthType::Legacy)
|
||||
MPTAuthType authType = MPTAuthType::StrongAuth)
|
||||
{
|
||||
return std::visit(
|
||||
[&]<ValidIssueType TIss>(TIss const& issue_) {
|
||||
return requireAuth(view, issue_, account, authType);
|
||||
if constexpr (std::is_same_v<TIss, Issue>)
|
||||
return requireAuth(view, issue_, account);
|
||||
else
|
||||
return requireAuth(view, issue_, account, authType);
|
||||
},
|
||||
asset.value());
|
||||
}
|
||||
|
||||
@@ -505,8 +505,8 @@ accountHolds(
|
||||
if (zeroIfUnauthorized == ahZERO_IF_UNAUTHORIZED &&
|
||||
view.rules().enabled(featureSingleAssetVault))
|
||||
{
|
||||
if (auto const err =
|
||||
requireAuth(view, mptIssue, account, AuthType::StrongAuth);
|
||||
if (auto const err = requireAuth(
|
||||
view, mptIssue, account, MPTAuthType::StrongAuth);
|
||||
!isTesSuccess(err))
|
||||
amount.clear(mptIssue);
|
||||
}
|
||||
@@ -2298,27 +2298,15 @@ transferXRP(
|
||||
}
|
||||
|
||||
TER
|
||||
requireAuth(
|
||||
ReadView const& view,
|
||||
Issue const& issue,
|
||||
AccountID const& account,
|
||||
AuthType authType)
|
||||
requireAuth(ReadView const& view, Issue const& issue, AccountID const& account)
|
||||
{
|
||||
if (isXRP(issue) || issue.account == account)
|
||||
return tesSUCCESS;
|
||||
|
||||
auto const trustLine =
|
||||
view.read(keylet::line(account, issue.account, issue.currency));
|
||||
// If account has no line, and this is a strong check, fail
|
||||
if (!trustLine && authType == AuthType::StrongAuth)
|
||||
return tecNO_LINE;
|
||||
|
||||
// If this is a weak or legacy check, or if the account has a line, fail if
|
||||
// auth is required and not set on the line
|
||||
if (auto const issuerAccount = view.read(keylet::account(issue.account));
|
||||
issuerAccount && (*issuerAccount)[sfFlags] & lsfRequireAuth)
|
||||
{
|
||||
if (trustLine)
|
||||
if (auto const trustLine =
|
||||
view.read(keylet::line(account, issue.account, issue.currency)))
|
||||
return ((*trustLine)[sfFlags] &
|
||||
((account > issue.account) ? lsfLowAuth : lsfHighAuth))
|
||||
? tesSUCCESS
|
||||
@@ -2334,7 +2322,7 @@ requireAuth(
|
||||
ReadView const& view,
|
||||
MPTIssue const& mptIssue,
|
||||
AccountID const& account,
|
||||
AuthType authType,
|
||||
MPTAuthType authType,
|
||||
int depth)
|
||||
{
|
||||
auto const mptID = keylet::mptIssuance(mptIssue.getMptID());
|
||||
@@ -2369,7 +2357,7 @@ requireAuth(
|
||||
if (auto const err = std::visit(
|
||||
[&]<ValidIssueType TIss>(TIss const& issue) {
|
||||
if constexpr (std::is_same_v<TIss, Issue>)
|
||||
return requireAuth(view, issue, account, authType);
|
||||
return requireAuth(view, issue, account);
|
||||
else
|
||||
return requireAuth(
|
||||
view, issue, account, authType, depth + 1);
|
||||
@@ -2384,8 +2372,7 @@ requireAuth(
|
||||
auto const sleToken = view.read(mptokenID);
|
||||
|
||||
// if account has no MPToken, fail
|
||||
if (!sleToken &&
|
||||
(authType == AuthType::StrongAuth || authType == AuthType::Legacy))
|
||||
if (!sleToken && authType == MPTAuthType::StrongAuth)
|
||||
return tecNO_AUTH;
|
||||
|
||||
// Note, this check is not amendment-gated because DomainID will be always
|
||||
|
||||
@@ -44,6 +44,7 @@ doLogLevel(RPC::JsonContext& context)
|
||||
Logs::toString(Logs::fromSeverity(context.app.logs().threshold()));
|
||||
std::vector<std::pair<std::string, std::string>> logTable(
|
||||
context.app.logs().partition_severities());
|
||||
using stringPair = std::map<std::string, std::string>::value_type;
|
||||
for (auto const& [k, v] : logTable)
|
||||
lev[k] = v;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user