Compare commits

..

11 Commits

Author SHA1 Message Date
Bart Thomee
3d6cc7dc91 Restore CI env vars 2025-10-20 12:11:03 -04:00
Bart Thomee
3711d40901 Restore CMAKE_UNITY_BUILD_BATCH_SIZE 2025-10-20 11:49:41 -04:00
Bart Thomee
26acbaed64 chore: Set CMake CI variable but reduce its effects 2025-10-20 11:47:59 -04:00
Bart
afb6e0e41b chore: Set fail fast to false, except for when the merge group is used (#5897)
This PR sets the fail-fast strategy option to false (it defaults to true), unless it is run by a merge group.

Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-17 16:17:02 +00:00
Bart
5523557226 chore: Clean up Conan variables in CI (#5903)
This change sanitizes inputs by setting them as environment variables, and adjusts the number of CPUs used for building. Namely, GitHub inputs should be sanitized, per recommendation by Semgrep, as using them directly poses a security risk. A recent change further overrode the global configuration by having builds use all cores, but as we have noticed an increased number of job cancelation this change updates it to use all cores less one.

Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-17 16:04:58 +00:00
Bart
b64707f53b chore: Add support for RHEL 8 (#5880)
Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-17 14:09:47 +00:00
Ayaz Salikhov
0b113f371f refactor: Update pre-commit workflow to latest version (#5902)
Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-17 13:40:10 +00:00
tequ
b4c894c1ba refactor: Autofill signature for Simulate RPC (#5852)
This change enables autofilling of signature-related fields in the Simulate RPC.

Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-16 21:18:53 +00:00
Mayukha Vadari
92281a4ede refactor: replace string JSONs with Json::Value (#5886)
There are some tests that write out JSONs as a string instead of using the Json::Value library, which are cleaned up by this change.

Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-16 16:02:25 +00:00
Bronek Kozicki
e80642fc12 fix: Fix regression in ConnectAttempt (#5900)
A regression was introduced in #5669 which would cause rippled to potentially dereference a disengaged std::optional when connecting to a peer. This would cause UB in release build and crash in debug.

Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-16 12:54:36 +00:00
Mayukha Vadari
640ce4988f refactor: replace boost::lexical_cast<std::string> with to_string (#5883)
This change replaces boost::lexical_cast<std::string> with to_string in some of the tests to make them more readable.

Co-authored-by: Bart Thomee <11445373+bthomee@users.noreply.github.com>
2025-10-16 12:46:21 +00:00
34 changed files with 659 additions and 1173 deletions

View File

@@ -28,6 +28,7 @@ runs:
BUILD_DIR: ${{ inputs.build_dir }}
BUILD_OPTION: ${{ inputs.force_build == 'true' && '*' || 'missing' }}
BUILD_TYPE: ${{ inputs.build_type }}
VERBOSITY: ${{ inputs.verbosity }}
run: |
echo 'Installing dependencies.'
mkdir -p '${{ env.BUILD_DIR }}'
@@ -38,7 +39,6 @@ runs:
--options:host='&:tests=True' \
--options:host='&:xrpld=True' \
--settings:all build_type='${{ env.BUILD_TYPE }}' \
--conf:all tools.build:verbosity='${{ inputs.verbosity }}' \
--conf:all tools.compilation:verbosity='${{ inputs.verbosity }}' \
--conf:all tools.build:jobs=$(nproc) \
--conf:all tools.build:verbosity='${{ env.VERBOSITY }}' \
--conf:all tools.compilation:verbosity='${{ env.VERBOSITY }}' \
..

View File

@@ -138,7 +138,6 @@ test.toplevel > test.csf
test.toplevel > xrpl.json
test.unit_test > xrpl.basics
tests.libxrpl > xrpl.basics
tests.libxrpl > xrpl.ledger
tests.libxrpl > xrpl.net
xrpl.json > xrpl.basics
xrpl.ledger > xrpl.basics

View File

@@ -73,47 +73,61 @@
"compiler_version": "20",
"image_sha": "6948666"
},
{
"distro_name": "rhel",
"distro_version": "8",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "10e69b4"
},
{
"distro_name": "rhel",
"distro_version": "8",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "10e69b4"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "12",
"image_sha": "6948666"
"image_sha": "10e69b4"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "13",
"image_sha": "6948666"
"image_sha": "10e69b4"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "6948666"
"image_sha": "10e69b4"
},
{
"distro_name": "rhel",
"distro_version": "9",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "6948666"
"image_sha": "10e69b4"
},
{
"distro_name": "rhel",
"distro_version": "10",
"compiler_name": "gcc",
"compiler_version": "14",
"image_sha": "6948666"
"image_sha": "10e69b4"
},
{
"distro_name": "rhel",
"distro_version": "10",
"compiler_name": "clang",
"compiler_version": "any",
"image_sha": "6948666"
"image_sha": "10e69b4"
},
{
"distro_name": "ubuntu",

View File

@@ -103,6 +103,7 @@ jobs:
if: ${{ needs.should-run.outputs.go == 'true' }}
uses: ./.github/workflows/reusable-build-test.yml
strategy:
fail-fast: false
matrix:
os: [linux, macos, windows]
with:

View File

@@ -65,6 +65,7 @@ jobs:
build-test:
uses: ./.github/workflows/reusable-build-test.yml
strategy:
fail-fast: ${{ github.event_name == 'merge_group' }}
matrix:
os: [linux, macos, windows]
with:

View File

@@ -9,7 +9,7 @@ on:
jobs:
# Call the workflow in the XRPLF/actions repo that runs the pre-commit hooks.
run-hooks:
uses: XRPLF/actions/.github/workflows/pre-commit.yml@af1b0f0d764cda2e5435f5ac97b240d4bd4d95d3
uses: XRPLF/actions/.github/workflows/pre-commit.yml@a8d7472b450eb53a1e5228f64552e5974457a21a
with:
runs_on: ubuntu-latest
container: '{ "image": "ghcr.io/xrplf/ci/tools-rippled-pre-commit:sha-a8c7be1" }'

View File

@@ -42,7 +42,7 @@ jobs:
- generate-matrix
uses: ./.github/workflows/reusable-build-test-config.yml
strategy:
fail-fast: false
fail-fast: ${{ github.event_name == 'merge_group' }}
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
max-parallel: 10
with:

View File

@@ -64,7 +64,9 @@ jobs:
conan_remote_name: ${{ inputs.conan_remote_name }}
conan_remote_url: ${{ inputs.conan_remote_url }}
- name: Log into Conan remote
run: conan remote login ${{ inputs.conan_remote_name }} "${{ secrets.conan_remote_username }}" --password "${{ secrets.conan_remote_password }}"
env:
CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }}
run: conan remote login ${{ env.CONAN_REMOTE_NAME }} "${{ secrets.conan_remote_username }}" --password "${{ secrets.conan_remote_password }}"
- name: Upload package
env:
CONAN_REMOTE_NAME: ${{ inputs.conan_remote_name }}

View File

@@ -181,11 +181,6 @@ if(xrpld)
xrpl.libxrpl
)
exclude_if_included(rippled)
# define a macro for tests that might need to
# be exluded or run differently in CI environment
if(is_ci)
target_compile_definitions(rippled PRIVATE RIPPLED_RUNNING_IN_CI)
endif ()
if(voidstar)
target_compile_options(rippled

View File

@@ -43,6 +43,7 @@ else ()
set (is_linux FALSE)
endif ()
# The CI environment variable is set by GitHub Actions.
if ("$ENV{CI}" STREQUAL "true" OR "$ENV{CONTINUOUS_INTEGRATION}" STREQUAL "true")
set (is_ci TRUE)
else ()

View File

@@ -3,4 +3,4 @@
core:non_interactive=True
core.download:parallel={{ os.cpu_count() }}
core.upload:parallel={{ os.cpu_count() }}
tools.build:jobs={{ (os.cpu_count() * 4/5) | int }}
tools.build:jobs={{ os.cpu_count() - 1 }}

View File

@@ -170,6 +170,9 @@ public:
bool
retrieve(key_type const& key, T& data);
mutex_type&
peekMutex();
std::vector<key_type>
getKeys() const;

View File

@@ -668,6 +668,29 @@ TaggedCache<
return true;
}
template <
class Key,
class T,
bool IsKeyCache,
class SharedWeakUnionPointer,
class SharedPointerType,
class Hash,
class KeyEqual,
class Mutex>
inline auto
TaggedCache<
Key,
T,
IsKeyCache,
SharedWeakUnionPointer,
SharedPointerType,
Hash,
KeyEqual,
Mutex>::peekMutex() -> mutex_type&
{
return m_mutex;
}
template <
class Key,
class T,

View File

@@ -1,138 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLE_APP_LEDGER_INDEX_MAP_H_INCLUDED
#define RIPPLE_APP_LEDGER_INDEX_MAP_H_INCLUDED
#include <algorithm>
#include <mutex>
#include <unordered_map>
namespace ripple {
template <class Key, class Mapped>
class LedgerIndexMap
{
public:
LedgerIndexMap() = default;
explicit LedgerIndexMap(std::size_t reserve_capacity)
{
data_.reserve(reserve_capacity);
}
LedgerIndexMap(LedgerIndexMap const&) = delete;
LedgerIndexMap&
operator=(LedgerIndexMap const&) = delete;
LedgerIndexMap(LedgerIndexMap&&) = delete;
LedgerIndexMap&
operator=(LedgerIndexMap&&) = delete;
Mapped&
operator[](Key const& k)
{
std::lock_guard lock(mutex_);
return data_[k];
}
Mapped&
operator[](Key&& k)
{
std::lock_guard lock(mutex_);
return data_[std::move(k)];
}
[[nodiscard]] Mapped*
get(Key const& k)
{
std::lock_guard lock(mutex_);
auto it = data_.find(k);
return it == data_.end() ? nullptr : &it->second;
}
[[nodiscard]] Mapped const*
get(Key const& k) const
{
std::lock_guard lock(mutex_);
auto it = data_.find(k);
return it == data_.end() ? nullptr : &it->second;
}
template <class... Args>
Mapped&
put(Key const& k, Args&&... args)
{
std::lock_guard lock(mutex_);
auto [it, inserted] = data_.try_emplace(k, std::forward<Args>(args)...);
if (!inserted)
it->second = Mapped(std::forward<Args>(args)...);
return it->second;
}
bool
contains(Key const& k) const
{
std::lock_guard lock(mutex_);
return data_.find(k) != data_.end();
}
std::size_t
size() const noexcept
{
std::lock_guard lock(mutex_);
return data_.size();
}
bool
empty() const noexcept
{
std::lock_guard lock(mutex_);
return data_.empty();
}
void
reserve(std::size_t n)
{
std::lock_guard lock(mutex_);
data_.reserve(n);
}
void
rehash(std::size_t n)
{
std::lock_guard lock(mutex_);
data_.rehash(n);
}
std::size_t
eraseBefore(Key const& cutoff)
{
std::lock_guard lock(mutex_);
auto const before = data_.size();
std::erase_if(data_, [&](auto const& kv) { return kv.first < cutoff; });
return before - data_.size();
}
private:
std::unordered_map<Key, Mapped> data_;
mutable std::mutex mutex_;
};
} // namespace ripple
#endif // RIPPLE_APP_LEDGER_INDEX_MAP_H_INCLUDED

View File

@@ -88,10 +88,8 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite
jvParams[jss::ledger_index] = "current";
jvParams[jss::binary] = false;
{
Json::Value jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams));
Json::Value jrr =
env.rpc("json", "ledger_data", to_string(jvParams));
// Iterate the state and print all NFTokenPages.
if (!jrr.isMember(jss::result) ||
@@ -413,10 +411,8 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite
jvParams[jss::ledger_index] = "current";
jvParams[jss::binary] = false;
{
Json::Value jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams));
Json::Value jrr =
env.rpc("json", "ledger_data", to_string(jvParams));
Json::Value& state = jrr[jss::result][jss::state];
@@ -460,10 +456,8 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite
jvParams[jss::ledger_index] = "current";
jvParams[jss::binary] = false;
{
Json::Value jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams));
Json::Value jrr =
env.rpc("json", "ledger_data", to_string(jvParams));
Json::Value& state = jrr[jss::result][jss::state];
@@ -1235,10 +1229,8 @@ class NFTokenBurnBaseUtil_test : public beast::unit_test::suite
jvParams[jss::ledger_index] = "current";
jvParams[jss::binary] = false;
{
Json::Value jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams));
Json::Value jrr =
env.rpc("json", "ledger_data", to_string(jvParams));
Json::Value& state = jrr[jss::result][jss::state];

View File

@@ -47,10 +47,8 @@ class NFTokenDir_test : public beast::unit_test::suite
jvParams[jss::ledger_index] = "current";
jvParams[jss::binary] = false;
{
Json::Value jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams));
Json::Value jrr =
env.rpc("json", "ledger_data", to_string(jvParams));
// Iterate the state and print all NFTokenPages.
if (!jrr.isMember(jss::result) ||

View File

@@ -592,10 +592,8 @@ private:
jvParams[field] = value;
jvParams[jss::binary] = false;
jvParams[jss::type] = jss::oracle;
Json::Value jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams));
Json::Value jrr =
env.rpc("json", "ledger_data", to_string(jvParams));
BEAST_EXPECT(jrr[jss::result][jss::state].size() == 2);
};
verifyLedgerData(jss::ledger_index, index);

View File

@@ -3081,16 +3081,23 @@ public:
env.fund(XRP(1000000), alice);
env.close();
auto const withQueue =
R"({ "account": ")" + alice.human() + R"(", "queue": true })";
auto const withoutQueue = R"({ "account": ")" + alice.human() + R"("})";
auto const prevLedgerWithQueue = R"({ "account": ")" + alice.human() +
R"(", "queue": true, "ledger_index": 3 })";
Json::Value withQueue;
withQueue[jss::account] = alice.human();
withQueue[jss::queue] = true;
Json::Value withoutQueue;
withoutQueue[jss::account] = alice.human();
Json::Value prevLedgerWithQueue;
prevLedgerWithQueue[jss::account] = alice.human();
prevLedgerWithQueue[jss::queue] = true;
prevLedgerWithQueue[jss::ledger_index] = 3;
BEAST_EXPECT(env.current()->info().seq > 3);
{
// account_info without the "queue" argument.
auto const info = env.rpc("json", "account_info", withoutQueue);
auto const info =
env.rpc("json", "account_info", to_string(withoutQueue));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));
@@ -3098,7 +3105,8 @@ public:
}
{
// account_info with the "queue" argument.
auto const info = env.rpc("json", "account_info", withQueue);
auto const info =
env.rpc("json", "account_info", to_string(withQueue));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));
@@ -3120,7 +3128,8 @@ public:
checkMetrics(*this, env, 0, 6, 4, 3);
{
auto const info = env.rpc("json", "account_info", withQueue);
auto const info =
env.rpc("json", "account_info", to_string(withQueue));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));
@@ -3149,7 +3158,8 @@ public:
checkMetrics(*this, env, 4, 6, 4, 3);
{
auto const info = env.rpc("json", "account_info", withQueue);
auto const info =
env.rpc("json", "account_info", to_string(withQueue));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));
@@ -3212,7 +3222,8 @@ public:
checkMetrics(*this, env, 1, 8, 5, 4);
{
auto const info = env.rpc("json", "account_info", withQueue);
auto const info =
env.rpc("json", "account_info", to_string(withQueue));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));
@@ -3276,7 +3287,8 @@ public:
checkMetrics(*this, env, 1, 8, 5, 4);
{
auto const info = env.rpc("json", "account_info", withQueue);
auto const info =
env.rpc("json", "account_info", to_string(withQueue));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));
@@ -3344,7 +3356,7 @@ public:
{
auto const info =
env.rpc("json", "account_info", prevLedgerWithQueue);
env.rpc("json", "account_info", to_string(prevLedgerWithQueue));
BEAST_EXPECT(
info.isMember(jss::result) &&
RPC::contains_error(info[jss::result]));
@@ -3356,7 +3368,8 @@ public:
checkMetrics(*this, env, 0, 10, 0, 5);
{
auto const info = env.rpc("json", "account_info", withQueue);
auto const info =
env.rpc("json", "account_info", to_string(withQueue));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));

View File

@@ -411,7 +411,7 @@ Env::sign_and_submit(JTx const& jt, Json::Value params)
if (params.isNull())
{
// Use the command line interface
auto const jv = boost::lexical_cast<std::string>(jt.jv);
auto const jv = to_string(jt.jv);
jr = rpc("submit", passphrase, jv);
}
else

View File

@@ -43,9 +43,7 @@ class AccountCurrencies_test : public beast::unit_test::suite
params[jss::account] = Account{"bob"}.human();
params[jss::ledger_hash] = 1;
auto const result = env.rpc(
"json",
"account_currencies",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "account_currencies", to_string(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_message] == "ledgerHashNotString");
}
@@ -107,9 +105,7 @@ class AccountCurrencies_test : public beast::unit_test::suite
params[jss::account] =
"llIIOO"; // these are invalid in bitcoin alphabet
auto const result = env.rpc(
"json",
"account_currencies",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "account_currencies", to_string(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "actMalformed");
BEAST_EXPECT(result[jss::error_message] == "Account malformed.");
}
@@ -119,9 +115,7 @@ class AccountCurrencies_test : public beast::unit_test::suite
Json::Value params;
params[jss::account] = "Bob";
auto const result = env.rpc(
"json",
"account_currencies",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "account_currencies", to_string(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "actMalformed");
BEAST_EXPECT(result[jss::error_message] == "Account malformed.");
}
@@ -130,9 +124,7 @@ class AccountCurrencies_test : public beast::unit_test::suite
Json::Value params;
params[jss::account] = Account{"bob"}.human();
auto const result = env.rpc(
"json",
"account_currencies",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "account_currencies", to_string(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "actNotFound");
BEAST_EXPECT(result[jss::error_message] == "Account not found.");
}
@@ -161,9 +153,7 @@ class AccountCurrencies_test : public beast::unit_test::suite
Json::Value params;
params[jss::account] = alice.human();
auto result = env.rpc(
"json",
"account_currencies",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "account_currencies", to_string(params))[jss::result];
auto arrayCheck =
[&result](
@@ -189,9 +179,7 @@ class AccountCurrencies_test : public beast::unit_test::suite
// send_currencies should be populated now
result = env.rpc(
"json",
"account_currencies",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "account_currencies", to_string(params))[jss::result];
BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrencies));
BEAST_EXPECT(arrayCheck(jss::send_currencies, gwCurrencies));
@@ -203,9 +191,7 @@ class AccountCurrencies_test : public beast::unit_test::suite
BEAST_EXPECT(
l[jss::freeze].asBool() == (l[jss::currency] == "USD"));
result = env.rpc(
"json",
"account_currencies",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "account_currencies", to_string(params))[jss::result];
BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrencies));
BEAST_EXPECT(arrayCheck(jss::send_currencies, gwCurrencies));
// clear the freeze
@@ -215,9 +201,7 @@ class AccountCurrencies_test : public beast::unit_test::suite
env(pay(gw, alice, gw["USA"](50)));
// USA should now be missing from receive_currencies
result = env.rpc(
"json",
"account_currencies",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "account_currencies", to_string(params))[jss::result];
decltype(gwCurrencies) gwCurrenciesNoUSA(
gwCurrencies.begin() + 1, gwCurrencies.end());
BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrenciesNoUSA));
@@ -228,9 +212,7 @@ class AccountCurrencies_test : public beast::unit_test::suite
env(trust(gw, alice["USA"](100)));
env(pay(alice, gw, alice["USA"](200)));
result = env.rpc(
"json",
"account_currencies",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "account_currencies", to_string(params))[jss::result];
BEAST_EXPECT(arrayCheck(jss::receive_currencies, gwCurrencies));
BEAST_EXPECT(arrayCheck(jss::send_currencies, gwCurrenciesNoUSA));
}

View File

@@ -58,10 +58,10 @@ public:
{
// account_info with an account that's not in the ledger.
Account const bogie{"bogie"};
auto const info = env.rpc(
"json",
"account_info",
R"({ "account": ")" + bogie.human() + R"("})");
Json::Value params;
params[jss::account] = bogie.human();
auto const info =
env.rpc("json", "account_info", to_string(params));
BEAST_EXPECT(
info[jss::result][jss::error_code] == rpcACT_NOT_FOUND);
BEAST_EXPECT(
@@ -128,16 +128,18 @@ public:
Account const alice{"alice"};
env.fund(XRP(1000), alice);
auto const withoutSigners =
std::string("{ ") + "\"account\": \"" + alice.human() + "\"}";
Json::Value withoutSigners;
withoutSigners[jss::account] = alice.human();
auto const withSigners = std::string("{ ") + "\"account\": \"" +
alice.human() + "\", " + "\"signer_lists\": true }";
Json::Value withSigners;
withSigners[jss::account] = alice.human();
withSigners[jss::signer_lists] = true;
// Alice has no SignerList yet.
{
// account_info without the "signer_lists" argument.
auto const info = env.rpc("json", "account_info", withoutSigners);
auto const info =
env.rpc("json", "account_info", to_string(withoutSigners));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));
@@ -146,7 +148,8 @@ public:
}
{
// account_info with the "signer_lists" argument.
auto const info = env.rpc("json", "account_info", withSigners);
auto const info =
env.rpc("json", "account_info", to_string(withSigners));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));
@@ -164,7 +167,8 @@ public:
env(smallSigners);
{
// account_info without the "signer_lists" argument.
auto const info = env.rpc("json", "account_info", withoutSigners);
auto const info =
env.rpc("json", "account_info", to_string(withoutSigners));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));
@@ -173,7 +177,8 @@ public:
}
{
// account_info with the "signer_lists" argument.
auto const info = env.rpc("json", "account_info", withSigners);
auto const info =
env.rpc("json", "account_info", to_string(withSigners));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));
@@ -216,7 +221,8 @@ public:
env(bigSigners);
{
// account_info with the "signer_lists" argument.
auto const info = env.rpc("json", "account_info", withSigners);
auto const info =
env.rpc("json", "account_info", to_string(withSigners));
BEAST_EXPECT(
info.isMember(jss::result) &&
info[jss::result].isMember(jss::account_data));
@@ -250,12 +256,14 @@ public:
Account const alice{"alice"};
env.fund(XRP(1000), alice);
auto const withoutSigners = std::string("{ ") +
"\"api_version\": 2, \"account\": \"" + alice.human() + "\"}";
Json::Value withoutSigners;
withoutSigners[jss::api_version] = 2;
withoutSigners[jss::account] = alice.human();
auto const withSigners = std::string("{ ") +
"\"api_version\": 2, \"account\": \"" + alice.human() + "\", " +
"\"signer_lists\": true }";
Json::Value withSigners;
withSigners[jss::api_version] = 2;
withSigners[jss::account] = alice.human();
withSigners[jss::signer_lists] = true;
auto const withSignersAsString = std::string("{ ") +
"\"api_version\": 2, \"account\": \"" + alice.human() + "\", " +
@@ -264,13 +272,15 @@ public:
// Alice has no SignerList yet.
{
// account_info without the "signer_lists" argument.
auto const info = env.rpc("json", "account_info", withoutSigners);
auto const info =
env.rpc("json", "account_info", to_string(withoutSigners));
BEAST_EXPECT(info.isMember(jss::result));
BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists));
}
{
// account_info with the "signer_lists" argument.
auto const info = env.rpc("json", "account_info", withSigners);
auto const info =
env.rpc("json", "account_info", to_string(withSigners));
BEAST_EXPECT(info.isMember(jss::result));
auto const& data = info[jss::result];
BEAST_EXPECT(data.isMember(jss::signer_lists));
@@ -286,13 +296,15 @@ public:
env(smallSigners);
{
// account_info without the "signer_lists" argument.
auto const info = env.rpc("json", "account_info", withoutSigners);
auto const info =
env.rpc("json", "account_info", to_string(withoutSigners));
BEAST_EXPECT(info.isMember(jss::result));
BEAST_EXPECT(!info[jss::result].isMember(jss::signer_lists));
}
{
// account_info with the "signer_lists" argument.
auto const info = env.rpc("json", "account_info", withSigners);
auto const info =
env.rpc("json", "account_info", to_string(withSigners));
BEAST_EXPECT(info.isMember(jss::result));
auto const& data = info[jss::result];
BEAST_EXPECT(data.isMember(jss::signer_lists));
@@ -340,7 +352,8 @@ public:
env(bigSigners);
{
// account_info with the "signer_lists" argument.
auto const info = env.rpc("json", "account_info", withSigners);
auto const info =
env.rpc("json", "account_info", to_string(withSigners));
BEAST_EXPECT(info.isMember(jss::result));
auto const& data = info[jss::result];
BEAST_EXPECT(data.isMember(jss::signer_lists));
@@ -567,10 +580,10 @@ public:
auto getAccountFlag = [&env](
std::string_view fName,
Account const& account) {
auto const info = env.rpc(
"json",
"account_info",
R"({"account" : ")" + account.human() + R"("})");
Json::Value params;
params[jss::account] = account.human();
auto const info =
env.rpc("json", "account_info", to_string(params));
std::optional<bool> res;
if (info[jss::result][jss::status] == "success" &&

File diff suppressed because it is too large Load Diff

View File

@@ -309,10 +309,8 @@ class Feature_test : public beast::unit_test::suite
params[jss::feature] =
"1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCD"
"EF";
auto const result = env.rpc(
"json",
"feature",
boost::lexical_cast<std::string>(params))[jss::result];
auto const result =
env.rpc("json", "feature", to_string(params))[jss::result];
BEAST_EXPECTS(
result[jss::error] == "badFeature", result.toStyledString());
BEAST_EXPECT(
@@ -326,10 +324,8 @@ class Feature_test : public beast::unit_test::suite
"A7";
// invalid param
params[jss::vetoed] = true;
auto const result = env.rpc(
"json",
"feature",
boost::lexical_cast<std::string>(params))[jss::result];
auto const result =
env.rpc("json", "feature", to_string(params))[jss::result];
BEAST_EXPECTS(
result[jss::error] == "noPermission",
result[jss::error].asString());
@@ -344,10 +340,8 @@ class Feature_test : public beast::unit_test::suite
"37";
Json::Value params;
params[jss::feature] = feature;
auto const result = env.rpc(
"json",
"feature",
boost::lexical_cast<std::string>(params))[jss::result];
auto const result =
env.rpc("json", "feature", to_string(params))[jss::result];
BEAST_EXPECT(result.isMember(feature));
auto const amendmentResult = result[feature];
BEAST_EXPECT(amendmentResult[jss::enabled].asBool() == false);

View File

@@ -63,9 +63,7 @@ public:
jvParams[jss::binary] = false;
{
auto const jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(
jrr[jss::ledger_current_index].isIntegral() &&
jrr[jss::ledger_current_index].asInt() > 0);
@@ -78,9 +76,7 @@ public:
{
jvParams[jss::limit] = max_limit + delta;
auto const jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(checkArraySize(
jrr[jss::state],
(delta > 0 && !asAdmin) ? max_limit : max_limit + delta));
@@ -109,10 +105,8 @@ public:
Json::Value jvParams;
jvParams[jss::ledger_index] = "current";
jvParams[jss::binary] = true;
auto const jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
auto const jrr =
env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(
jrr[jss::ledger_current_index].isIntegral() &&
jrr[jss::ledger_current_index].asInt() > 0);
@@ -137,9 +131,7 @@ public:
Json::Value jvParams;
jvParams[jss::limit] = "0"; // NOT an integer
auto const jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(
@@ -152,9 +144,7 @@ public:
Json::Value jvParams;
jvParams[jss::marker] = "NOT_A_MARKER";
auto const jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(
@@ -167,9 +157,7 @@ public:
Json::Value jvParams;
jvParams[jss::marker] = 1;
auto const jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(
@@ -182,9 +170,7 @@ public:
Json::Value jvParams;
jvParams[jss::ledger_index] = 10u;
auto const jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
BEAST_EXPECT(jrr[jss::status] == "error");
BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
@@ -213,27 +199,20 @@ public:
Json::Value jvParams;
jvParams[jss::ledger_index] = "current";
jvParams[jss::binary] = false;
auto jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
auto jrr =
env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
auto const total_count = jrr[jss::state].size();
// now make request with a limit and loop until we get all
jvParams[jss::limit] = 5;
jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(checkMarker(jrr));
auto running_total = jrr[jss::state].size();
while (jrr.isMember(jss::marker))
{
jvParams[jss::marker] = jrr[jss::marker];
jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
running_total += jrr[jss::state].size();
}
BEAST_EXPECT(running_total == total_count);
@@ -253,9 +232,7 @@ public:
Json::Value jvParams;
jvParams[jss::ledger_index] = "closed";
auto jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
if (BEAST_EXPECT(jrr.isMember(jss::ledger)))
BEAST_EXPECT(
jrr[jss::ledger][jss::ledger_hash] ==
@@ -267,9 +244,7 @@ public:
jvParams[jss::ledger_index] = "closed";
jvParams[jss::binary] = true;
auto jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
if (BEAST_EXPECT(jrr.isMember(jss::ledger)))
{
auto data =
@@ -288,9 +263,7 @@ public:
Json::Value jvParams;
jvParams[jss::binary] = true;
auto jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember(jss::ledger));
BEAST_EXPECT(!jrr[jss::ledger].isMember(jss::ledger_data));
}
@@ -319,9 +292,7 @@ public:
jvParams[jss::ledger_index] = "current";
jvParams[jss::type] = type;
return env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
};
// Assert that state is an empty array.
@@ -500,9 +471,7 @@ public:
jvParams[jss::ledger_index] = "current";
jvParams[jss::type] = "misspelling";
auto const jrr = env.rpc(
"json",
"ledger_data",
boost::lexical_cast<std::string>(jvParams))[jss::result];
"json", "ledger_data", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember("error"));
BEAST_EXPECT(jrr["error"] == "invalidParams");
BEAST_EXPECT(jrr["error_message"] == "Invalid field 'type'.");

View File

@@ -287,56 +287,39 @@ class LedgerRPC_test : public beast::unit_test::suite
// access via the legacy ledger field, keyword index values
Json::Value jvParams;
jvParams[jss::ledger] = "closed";
auto jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
auto jrr =
env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember(jss::ledger));
BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
jvParams[jss::ledger] = "validated";
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember(jss::ledger));
BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
jvParams[jss::ledger] = "current";
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember(jss::ledger));
BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
// ask for a bad ledger keyword
jvParams[jss::ledger] = "invalid";
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
// numeric index
jvParams[jss::ledger] = 4;
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember(jss::ledger));
BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "4");
// numeric index - out of range
jvParams[jss::ledger] = 20;
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
}
@@ -348,29 +331,21 @@ class LedgerRPC_test : public beast::unit_test::suite
// access via the ledger_hash field
Json::Value jvParams;
jvParams[jss::ledger_hash] = hash3;
auto jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
auto jrr =
env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember(jss::ledger));
BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "3");
// extra leading hex chars in hash are not allowed
jvParams[jss::ledger_hash] = "DEADBEEF" + hash3;
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
// request with non-string ledger_hash
jvParams[jss::ledger_hash] = 2;
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashNotString");
@@ -378,10 +353,7 @@ class LedgerRPC_test : public beast::unit_test::suite
jvParams[jss::ledger_hash] =
"2E81FC6EC0DD943197EGC7E3FBE9AE30"
"7F2775F2F7485BB37307984C3C0F2340";
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_message] == "ledgerHashMalformed");
@@ -389,10 +361,7 @@ class LedgerRPC_test : public beast::unit_test::suite
jvParams[jss::ledger_hash] =
"8C3EEDB3124D92E49E75D81A8826A2E6"
"5A75FD71FC3FD6F36FEB803C5F1D812D";
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
}
@@ -401,39 +370,28 @@ class LedgerRPC_test : public beast::unit_test::suite
// access via the ledger_index field, keyword index values
Json::Value jvParams;
jvParams[jss::ledger_index] = "closed";
auto jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
auto jrr =
env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember(jss::ledger));
BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
BEAST_EXPECT(jrr.isMember(jss::ledger_index));
jvParams[jss::ledger_index] = "validated";
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember(jss::ledger));
BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "5");
jvParams[jss::ledger_index] = "current";
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember(jss::ledger));
BEAST_EXPECT(jrr[jss::ledger][jss::ledger_index] == "6");
BEAST_EXPECT(jrr.isMember(jss::ledger_current_index));
// ask for a bad ledger keyword
jvParams[jss::ledger_index] = "invalid";
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "invalidParams");
BEAST_EXPECT(jrr[jss::error_message] == "ledgerIndexMalformed");
@@ -441,10 +399,8 @@ class LedgerRPC_test : public beast::unit_test::suite
for (auto i : {1, 2, 3, 4, 5, 6})
{
jvParams[jss::ledger_index] = i;
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr =
env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr.isMember(jss::ledger));
if (i < 6)
BEAST_EXPECT(jrr.isMember(jss::ledger_hash));
@@ -454,10 +410,7 @@ class LedgerRPC_test : public beast::unit_test::suite
// numeric index - out of range
jvParams[jss::ledger_index] = 7;
jrr = env.rpc(
"json",
"ledger",
boost::lexical_cast<std::string>(jvParams))[jss::result];
jrr = env.rpc("json", "ledger", to_string(jvParams))[jss::result];
BEAST_EXPECT(jrr[jss::error] == "lgrNotFound");
BEAST_EXPECT(jrr[jss::error_message] == "ledgerNotFound");
}

View File

@@ -59,9 +59,7 @@ class NoRippleCheck_test : public beast::unit_test::suite
Json::Value params;
params[jss::account] = alice.human();
auto const result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "noripple_check", to_string(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_message] == "Missing field 'role'.");
}
@@ -92,9 +90,7 @@ class NoRippleCheck_test : public beast::unit_test::suite
params[jss::account] = alice.human();
params[jss::role] = "not_a_role";
auto const result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "noripple_check", to_string(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_message] == "Invalid field 'role'.");
}
@@ -105,9 +101,7 @@ class NoRippleCheck_test : public beast::unit_test::suite
params[jss::role] = "user";
params[jss::limit] = -1;
auto const result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "noripple_check", to_string(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(
result[jss::error_message] ==
@@ -120,9 +114,7 @@ class NoRippleCheck_test : public beast::unit_test::suite
params[jss::role] = "user";
params[jss::ledger_hash] = 1;
auto const result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "noripple_check", to_string(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "invalidParams");
BEAST_EXPECT(result[jss::error_message] == "ledgerHashNotString");
}
@@ -133,9 +125,7 @@ class NoRippleCheck_test : public beast::unit_test::suite
params[jss::role] = "user";
params[jss::ledger] = "current";
auto const result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "noripple_check", to_string(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "actNotFound");
BEAST_EXPECT(result[jss::error_message] == "Account not found.");
}
@@ -147,9 +137,7 @@ class NoRippleCheck_test : public beast::unit_test::suite
params[jss::role] = "user";
params[jss::ledger] = "current";
auto const result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
"json", "noripple_check", to_string(params))[jss::result];
BEAST_EXPECT(result[jss::error] == "actMalformed");
BEAST_EXPECT(result[jss::error_message] == "Account malformed.");
}
@@ -184,10 +172,8 @@ class NoRippleCheck_test : public beast::unit_test::suite
params[jss::account] = alice.human();
params[jss::role] = (user ? "user" : "gateway");
params[jss::ledger] = "current";
auto result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
auto result =
env.rpc("json", "noripple_check", to_string(params))[jss::result];
auto const pa = result["problems"];
if (!BEAST_EXPECT(pa.isArray()))
@@ -221,10 +207,8 @@ class NoRippleCheck_test : public beast::unit_test::suite
// now make a second request asking for the relevant transactions this
// time.
params[jss::transactions] = true;
result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
result =
env.rpc("json", "noripple_check", to_string(params))[jss::result];
if (!BEAST_EXPECT(result[jss::transactions].isArray()))
return;
@@ -343,43 +327,33 @@ class NoRippleCheckLimits_test : public beast::unit_test::suite
params[jss::account] = alice.human();
params[jss::role] = "user";
params[jss::ledger] = "current";
auto result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
auto result =
env.rpc("json", "noripple_check", to_string(params))[jss::result];
BEAST_EXPECT(result["problems"].size() == 301);
// one below minimum
params[jss::limit] = 9;
result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
result =
env.rpc("json", "noripple_check", to_string(params))[jss::result];
BEAST_EXPECT(result["problems"].size() == (admin ? 10 : 11));
// at minimum
params[jss::limit] = 10;
result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
result =
env.rpc("json", "noripple_check", to_string(params))[jss::result];
BEAST_EXPECT(result["problems"].size() == 11);
// at max
params[jss::limit] = 400;
result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
result =
env.rpc("json", "noripple_check", to_string(params))[jss::result];
BEAST_EXPECT(result["problems"].size() == 401);
// at max+1
params[jss::limit] = 401;
result = env.rpc(
"json",
"noripple_check",
boost::lexical_cast<std::string>(params))[jss::result];
result =
env.rpc("json", "noripple_check", to_string(params))[jss::result];
BEAST_EXPECT(result["problems"].size() == (admin ? 402 : 401));
}

View File

@@ -258,15 +258,13 @@ class TransactionEntry_test : public beast::unit_test::suite
Account A2{"A2"};
env.fund(XRP(10000), A1);
auto fund_1_tx =
boost::lexical_cast<std::string>(env.tx()->getTransactionID());
auto fund_1_tx = to_string(env.tx()->getTransactionID());
BEAST_EXPECT(
fund_1_tx ==
"F4E9DF90D829A9E8B423FF68C34413E240D8D8BB0EFD080DF08114ED398E2506");
env.fund(XRP(10000), A2);
auto fund_2_tx =
boost::lexical_cast<std::string>(env.tx()->getTransactionID());
auto fund_2_tx = to_string(env.tx()->getTransactionID());
BEAST_EXPECT(
fund_2_tx ==
"6853CD8226A05068C951CB1F54889FF4E40C5B440DC1C5BA38F114C4E0B1E705");
@@ -308,15 +306,13 @@ class TransactionEntry_test : public beast::unit_test::suite
// the trust tx is actually a payment since the trust method
// refunds fees with a payment after TrustSet..so just ignore the type
// in the check below
auto trust_tx =
boost::lexical_cast<std::string>(env.tx()->getTransactionID());
auto trust_tx = to_string(env.tx()->getTransactionID());
BEAST_EXPECT(
trust_tx ==
"C992D97D88FF444A1AB0C06B27557EC54B7F7DA28254778E60238BEA88E0C101");
env(pay(A2, A1, A2["USD"](5)));
auto pay_tx =
boost::lexical_cast<std::string>(env.tx()->getTransactionID());
auto pay_tx = to_string(env.tx()->getTransactionID());
env.close();
BEAST_EXPECT(
pay_tx ==
@@ -362,8 +358,7 @@ class TransactionEntry_test : public beast::unit_test::suite
"2000-01-01T00:00:20Z");
env(offer(A2, XRP(100), A2["USD"](1)));
auto offer_tx =
boost::lexical_cast<std::string>(env.tx()->getTransactionID());
auto offer_tx = to_string(env.tx()->getTransactionID());
BEAST_EXPECT(
offer_tx ==
"5FCC1A27A7664F82A0CC4BE5766FBBB7C560D52B93AA7B550CD33B27AEC7EFFB");

View File

@@ -14,5 +14,3 @@ xrpl_add_test(crypto)
target_link_libraries(xrpl.test.crypto PRIVATE xrpl.imports.test)
xrpl_add_test(net)
target_link_libraries(xrpl.test.net PRIVATE xrpl.imports.test)
xrpl_add_test(ledger)
target_link_libraries(xrpl.test.ledger PRIVATE xrpl.imports.test)

View File

@@ -1,210 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <xrpl/ledger/LedgerIndexMap.h>
#include <doctest/doctest.h>
#include <cstdint>
#include <string>
#include <vector>
using namespace ripple;
TEST_SUITE_BEGIN("LedgerIndexMap");
using TestMap = LedgerIndexMap<int, std::string>;
TEST_CASE("Default empty")
{
TestMap m;
CHECK(m.size() == 0);
CHECK(m.empty());
CHECK(m.get(42) == nullptr);
CHECK_FALSE(m.contains(42));
}
TEST_CASE("Operator bracket inserts default")
{
TestMap m;
auto& v = m[10];
CHECK(m.size() == 1);
CHECK(m.contains(10));
CHECK(v.empty());
}
TEST_CASE("Operator bracket, rvalue key")
{
TestMap m;
int k = 7;
auto& v1 = m[std::move(k)];
v1 = "seven";
CHECK(m.size() == 1);
auto* got = m.get(7);
REQUIRE(got != nullptr);
CHECK(*got == "seven");
}
TEST_CASE("Insert through put")
{
TestMap m;
auto& v = m.put(20, "twenty");
CHECK(v == "twenty");
auto* got = m.get(20);
REQUIRE(got != nullptr);
CHECK(*got == "twenty");
CHECK(m.size() == 1);
}
TEST_CASE("Overwrite existing key with put")
{
TestMap m;
m.put(5, "five");
CHECK(m.size() == 1);
m.put(5, "FIVE");
CHECK(m.size() == 1);
auto* got = m.get(5);
REQUIRE(got != nullptr);
CHECK(*got == "FIVE");
}
TEST_CASE("Once found, one not found")
{
TestMap m;
m.put(1, "one");
CHECK(m.get(1) != nullptr);
CHECK(m.get(2) == nullptr);
}
TEST_CASE("Try eraseBefore - nothing to do")
{
TestMap m;
m.put(10, "a");
m.put(11, "b");
m.put(12, "c");
CHECK(m.eraseBefore(10) == 0);
CHECK(m.size() == 3);
CHECK(m.contains(10));
CHECK(m.contains(11));
CHECK(m.contains(12));
}
TEST_CASE("eraseBefore - removes several entries")
{
TestMap m;
m.put(10, "a");
m.put(11, "b");
m.put(12, "c");
m.put(13, "d");
CHECK(m.eraseBefore(12) == 2);
CHECK_FALSE(m.contains(10));
CHECK_FALSE(m.contains(11));
CHECK(m.contains(12));
CHECK(m.contains(13));
CHECK(m.size() == 2);
}
TEST_CASE("eraseBefore - removes all entries")
{
TestMap m;
m.put(1, "x");
m.put(2, "y");
CHECK(m.eraseBefore(1000) == 2);
CHECK(m.size() == 0);
CHECK(m.empty());
}
TEST_CASE("eraseBefore - same call, second time nothing to do")
{
TestMap m;
m.put(10, "a");
m.put(11, "b");
m.put(12, "c");
CHECK(m.eraseBefore(12) == 2);
CHECK(m.contains(12));
CHECK(m.eraseBefore(12) == 0);
CHECK(m.size() == 1);
}
TEST_CASE("eraseBefore - single entry removed")
{
TestMap m;
m.put(10, "v1");
m.put(10, "v2");
m.put(10, "v3");
CHECK(m.size() == 1);
CHECK(m.eraseBefore(11) == 1);
CHECK(m.size() == 0);
}
TEST_CASE("eraseBefore - outlier still removed in one call")
{
TestMap m;
m.put(10, "a");
m.put(12, "c");
m.put(11, "b"); // out-of-order insert
CHECK(m.eraseBefore(12) == 2); // removes 10 and 11
CHECK_FALSE(m.contains(10));
CHECK_FALSE(m.contains(11));
CHECK(m.contains(12));
CHECK(m.size() == 1);
}
TEST_CASE("eraseBefore - erase in two steps (one first, then some more)")
{
TestMap m;
for (int k : {10, 11, 12, 13})
m.put(k, std::to_string(k));
CHECK(m.eraseBefore(11) == 1);
CHECK_FALSE(m.contains(10));
CHECK(m.size() == 3);
CHECK(m.eraseBefore(13) == 2);
CHECK_FALSE(m.contains(11));
CHECK_FALSE(m.contains(12));
CHECK(m.contains(13));
CHECK(m.size() == 1);
}
TEST_CASE("rehash does not lose entries")
{
TestMap m;
for (int k = 0; k < 16; ++k)
m.put(k, "v" + std::to_string(k));
m.reserve(64);
m.rehash(32);
for (int k = 0; k < 16; ++k)
{
auto* v = m.get(k);
REQUIRE(v != nullptr);
CHECK(*v == "v" + std::to_string(k));
}
CHECK(m.eraseBefore(8) == 8);
for (int k = 0; k < 8; ++k)
CHECK_FALSE(m.contains(k));
for (int k = 8; k < 16; ++k)
CHECK(m.contains(k));
}
TEST_SUITE_END();

View File

@@ -1,2 +0,0 @@
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>

View File

@@ -27,6 +27,8 @@
namespace ripple {
// FIXME: Need to clean up ledgers by index at some point
LedgerHistory::LedgerHistory(
beast::insight::Collector::ptr const& collector,
Application& app)
@@ -45,7 +47,6 @@ LedgerHistory::LedgerHistory(
std::chrono::minutes{5},
stopwatch(),
app_.journal("TaggedCache"))
, mLedgersByIndex(512)
, j_(app.journal("LedgerHistory"))
{
}
@@ -62,6 +63,8 @@ LedgerHistory::insert(
ledger->stateMap().getHash().isNonZero(),
"ripple::LedgerHistory::insert : nonzero hash");
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
bool const alreadyHad = m_ledgers_by_hash.canonicalize_replace_cache(
ledger->info().hash, ledger);
if (validated)
@@ -73,18 +76,25 @@ LedgerHistory::insert(
LedgerHash
LedgerHistory::getLedgerHash(LedgerIndex index)
{
if (auto p = mLedgersByIndex.get(index))
return *p;
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
if (auto it = mLedgersByIndex.find(index); it != mLedgersByIndex.end())
return it->second;
return {};
}
std::shared_ptr<Ledger const>
LedgerHistory::getLedgerBySeq(LedgerIndex index)
{
if (auto p = mLedgersByIndex.get(index))
{
uint256 const hash = *p;
return getLedgerByHash(hash);
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
auto it = mLedgersByIndex.find(index);
if (it != mLedgersByIndex.end())
{
uint256 hash = it->second;
sl.unlock();
return getLedgerByHash(hash);
}
}
std::shared_ptr<Ledger const> ret = loadByIndex(index, app_);
@@ -98,6 +108,8 @@ LedgerHistory::getLedgerBySeq(LedgerIndex index)
{
// Add this ledger to the local tracking by index
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
XRPL_ASSERT(
ret->isImmutable(),
"ripple::LedgerHistory::getLedgerBySeq : immutable result ledger");
@@ -446,6 +458,8 @@ LedgerHistory::builtLedger(
XRPL_ASSERT(
!hash.isZero(), "ripple::LedgerHistory::builtLedger : nonzero hash");
std::unique_lock sl(m_consensus_validated.peekMutex());
auto entry = std::make_shared<cv_entry>();
m_consensus_validated.canonicalize_replace_client(index, entry);
@@ -486,6 +500,8 @@ LedgerHistory::validatedLedger(
!hash.isZero(),
"ripple::LedgerHistory::validatedLedger : nonzero hash");
std::unique_lock sl(m_consensus_validated.peekMutex());
auto entry = std::make_shared<cv_entry>();
m_consensus_validated.canonicalize_replace_client(index, entry);
@@ -519,13 +535,13 @@ LedgerHistory::validatedLedger(
bool
LedgerHistory::fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash)
{
if (auto cur = mLedgersByIndex.get(ledgerIndex))
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
auto it = mLedgersByIndex.find(ledgerIndex);
if ((it != mLedgersByIndex.end()) && (it->second != ledgerHash))
{
if (*cur != ledgerHash)
{
mLedgersByIndex.put(ledgerIndex, ledgerHash);
return false;
}
it->second = ledgerHash;
return false;
}
return true;
}
@@ -533,24 +549,12 @@ LedgerHistory::fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash)
void
LedgerHistory::clearLedgerCachePrior(LedgerIndex seq)
{
std::size_t hashesCleared = 0;
for (LedgerHash it : m_ledgers_by_hash.getKeys())
{
auto const ledger = getLedgerByHash(it);
if (!ledger || ledger->info().seq < seq)
{
m_ledgers_by_hash.del(it, false);
++hashesCleared;
}
}
JLOG(j_.debug()) << "LedgersByHash: cleared " << hashesCleared
<< " entries before seq " << seq << " (total now "
<< m_ledgers_by_hash.size() << ")";
std::size_t const indexesCleared = mLedgersByIndex.eraseBefore(seq);
JLOG(j_.debug()) << "LedgerIndexMap: cleared " << indexesCleared
<< " index entries before seq " << seq << " (total now "
<< mLedgersByIndex.size() << ")";
}
} // namespace ripple

View File

@@ -24,7 +24,6 @@
#include <xrpld/app/main/Application.h>
#include <xrpl/beast/insight/Collector.h>
#include <xrpl/ledger/LedgerIndexMap.h>
#include <xrpl/protocol/RippleLedgerHash.h>
#include <optional>
@@ -150,8 +149,7 @@ private:
ConsensusValidated m_consensus_validated;
// Maps ledger indexes to the corresponding hash.
ripple::LedgerIndexMap<LedgerIndex, LedgerHash>
mLedgersByIndex; // validated ledgers
std::map<LedgerIndex, LedgerHash> mLedgersByIndex; // validated ledgers
beast::Journal j_;
};

View File

@@ -600,8 +600,8 @@ ConnectAttempt::processResponse()
JLOG(journal_.info()) << "Cluster name: " << *member;
}
auto const result =
overlay_.peerFinder().activate(slot_, publicKey, !member->empty());
auto const result = overlay_.peerFinder().activate(
slot_, publicKey, member.has_value());
if (result != PeerFinder::Result::success)
{
std::stringstream ss;

View File

@@ -72,39 +72,23 @@ getAutofillSequence(Json::Value const& tx_json, RPC::JsonContext& context)
}
static std::optional<Json::Value>
autofillTx(Json::Value& tx_json, RPC::JsonContext& context)
autofillSignature(Json::Value& sigObject)
{
if (!tx_json.isMember(jss::Fee))
{
// autofill Fee
// Must happen after all the other autofills happen
// Error handling/messaging works better that way
auto feeOrError = RPC::getCurrentNetworkFee(
context.role,
context.app.config(),
context.app.getFeeTrack(),
context.app.getTxQ(),
context.app,
tx_json);
if (feeOrError.isMember(jss::error))
return feeOrError;
tx_json[jss::Fee] = feeOrError;
}
if (!tx_json.isMember(jss::SigningPubKey))
if (!sigObject.isMember(jss::SigningPubKey))
{
// autofill SigningPubKey
tx_json[jss::SigningPubKey] = "";
sigObject[jss::SigningPubKey] = "";
}
if (tx_json.isMember(jss::Signers))
if (sigObject.isMember(jss::Signers))
{
if (!tx_json[jss::Signers].isArray())
if (!sigObject[jss::Signers].isArray())
return RPC::invalid_field_error("tx.Signers");
// check multisigned signers
for (unsigned index = 0; index < tx_json[jss::Signers].size(); index++)
for (unsigned index = 0; index < sigObject[jss::Signers].size();
index++)
{
auto& signer = tx_json[jss::Signers][index];
auto& signer = sigObject[jss::Signers][index];
if (!signer.isObject() || !signer.isMember(jss::Signer) ||
!signer[jss::Signer].isObject())
return RPC::invalid_field_error(
@@ -129,16 +113,41 @@ autofillTx(Json::Value& tx_json, RPC::JsonContext& context)
}
}
if (!tx_json.isMember(jss::TxnSignature))
if (!sigObject.isMember(jss::TxnSignature))
{
// autofill TxnSignature
tx_json[jss::TxnSignature] = "";
sigObject[jss::TxnSignature] = "";
}
else if (tx_json[jss::TxnSignature] != "")
else if (sigObject[jss::TxnSignature] != "")
{
// Transaction must not be signed
return rpcError(rpcTX_SIGNED);
}
return std::nullopt;
}
static std::optional<Json::Value>
autofillTx(Json::Value& tx_json, RPC::JsonContext& context)
{
if (!tx_json.isMember(jss::Fee))
{
// autofill Fee
// Must happen after all the other autofills happen
// Error handling/messaging works better that way
auto feeOrError = RPC::getCurrentNetworkFee(
context.role,
context.app.config(),
context.app.getFeeTrack(),
context.app.getTxQ(),
context.app,
tx_json);
if (feeOrError.isMember(jss::error))
return feeOrError;
tx_json[jss::Fee] = feeOrError;
}
if (auto error = autofillSignature(tx_json))
return *error;
if (!tx_json.isMember(jss::Sequence))
{