Compare commits

..

2 Commits

Author SHA1 Message Date
Jingchen
eb6d9c1cb6 Merge branch 'develop' into ci/use-new-macos-runners 2025-07-25 10:21:55 +01:00
JCW
7ed62f0ea3 Fix build error
Signed-off-by: JCW <a1q123456@users.noreply.github.com>

Use new ec2 macos runner

Signed-off-by: JCW <a1q123456@users.noreply.github.com>

Fix build error

Signed-off-by: JCW <a1q123456@users.noreply.github.com>

Revert unnecessary changes

Signed-off-by: JCW <a1q123456@users.noreply.github.com>

Update runners

Signed-off-by: JCW <a1q123456@users.noreply.github.com>

Revert unnecessary changes

Signed-off-by: JCW <a1q123456@users.noreply.github.com>

Switch to self hosted runner

Signed-off-by: JCW <a1q123456@users.noreply.github.com>
2025-07-24 14:13:29 +01:00
39 changed files with 212 additions and 516 deletions

View File

@@ -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 }} \

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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>

View File

@@ -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 %}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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:

View File

@@ -26,7 +26,6 @@
#include <boost/beast/core/string.hpp>
#include <boost/filesystem.hpp>
#include <fstream>
#include <map>
#include <memory>
#include <mutex>

View File

@@ -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

View File

@@ -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 <

View File

@@ -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));

View File

@@ -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)

View File

@@ -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. */

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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])
{

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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,

View File

@@ -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");
}
}
};

View File

@@ -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>();

View File

@@ -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.

View File

@@ -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());

View File

@@ -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();
};

View File

@@ -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);
}
};

View File

@@ -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

View File

@@ -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 {

View File

@@ -79,7 +79,7 @@
#include <chrono>
#include <condition_variable>
#include <cstring>
#include <fstream>
#include <iostream>
#include <limits>
#include <mutex>
#include <optional>

View File

@@ -39,7 +39,7 @@
#include <google/protobuf/stubs/common.h>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <utility>

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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());
}

View File

@@ -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

View File

@@ -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;