mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-04 20:05:51 +00:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0eaaa1fb31 | ||
|
|
1846f629a5 | ||
|
|
83af5af3c6 | ||
|
|
418a0ddbf2 | ||
|
|
6cfbfda014 | ||
|
|
91648f98ad | ||
|
|
71e1637c5f | ||
|
|
59cd2ce5aa | ||
|
|
d783edd57a | ||
|
|
1ce8a58167 | ||
|
|
92e5c4792b | ||
|
|
d7f36733bc |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,7 @@
|
||||
*clio*.log
|
||||
build*/
|
||||
.build
|
||||
.cache
|
||||
.vscode
|
||||
.python-version
|
||||
CMakeUserPresets.json
|
||||
|
||||
@@ -5,21 +5,27 @@
|
||||
find_package (Git REQUIRED)
|
||||
|
||||
set (GIT_COMMAND rev-parse --short HEAD)
|
||||
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND} OUTPUT_VARIABLE REV OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE REV OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
set (GIT_COMMAND branch --show-current)
|
||||
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND} OUTPUT_VARIABLE BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
|
||||
if (BRANCH STREQUAL "")
|
||||
set (BRANCH "dev")
|
||||
endif ()
|
||||
|
||||
if (NOT (BRANCH MATCHES master OR BRANCH MATCHES release/*)) # for develop and any other branch name YYYYMMDDHMS-<branch>-<git-ref>
|
||||
if (NOT (BRANCH MATCHES master OR BRANCH MATCHES release/*)) # for develop and any other branch name YYYYMMDDHMS-<branch>-<git-rev>
|
||||
execute_process (COMMAND date +%Y%m%d%H%M%S OUTPUT_VARIABLE DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set (VERSION "${DATE}-${BRANCH}-${REV}")
|
||||
else ()
|
||||
set (GIT_COMMAND describe --tags)
|
||||
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND} OUTPUT_VARIABLE TAG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
execute_process (COMMAND ${GIT_EXECUTABLE} ${GIT_COMMAND}
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE TAG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
set (VERSION "${TAG_VERSION}-${REV}")
|
||||
endif ()
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@ project(clio)
|
||||
# ========================================================================== #
|
||||
# Options #
|
||||
# ========================================================================== #
|
||||
option (verbose "Verbose build" FALSE)
|
||||
option (verbose "Verbose build" FALSE)
|
||||
option (tests "Build tests" FALSE)
|
||||
option (docs "Generate doxygen docs" FALSE)
|
||||
option (coverage "Build test coverage report" FALSE)
|
||||
option (packaging "Create distribution packages" FALSE)
|
||||
# ========================================================================== #
|
||||
set (san "" CACHE STRING "Add sanitizer instrumentation")
|
||||
set (CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
|
||||
set_property (CACHE san PROPERTY STRINGS ";undefined;memory;address;thread")
|
||||
# ========================================================================== #
|
||||
|
||||
@@ -135,7 +136,11 @@ target_sources (clio PRIVATE
|
||||
|
||||
# Clio server
|
||||
add_executable (clio_server src/main/Main.cpp)
|
||||
target_link_libraries (clio_server PUBLIC clio)
|
||||
target_link_libraries (clio_server PRIVATE clio)
|
||||
target_link_options(clio_server
|
||||
PRIVATE
|
||||
$<$<AND:$<NOT:$<BOOL:${APPLE}>>,$<NOT:$<BOOL:${san}>>>:-static-libstdc++ -static-libgcc>
|
||||
)
|
||||
|
||||
# Unittesting
|
||||
if (tests)
|
||||
@@ -158,6 +163,7 @@ if (tests)
|
||||
unittests/etl/ExtractorTests.cpp
|
||||
unittests/etl/TransformerTests.cpp
|
||||
unittests/etl/CacheLoaderTests.cpp
|
||||
unittests/etl/AmendmentBlockHandlerTests.cpp
|
||||
# RPC
|
||||
unittests/rpc/ErrorTests.cpp
|
||||
unittests/rpc/BaseTests.cpp
|
||||
@@ -219,7 +225,7 @@ if (tests)
|
||||
# See https://github.com/google/googletest/issues/3475
|
||||
gtest_discover_tests (clio_tests DISCOVERY_TIMEOUT 10)
|
||||
|
||||
# Fix for dwarf5 bug on ci
|
||||
# Fix for dwarf5 bug on ci
|
||||
target_compile_options (clio PUBLIC -gdwarf-4)
|
||||
|
||||
target_compile_definitions (${TEST_TARGET} PUBLIC UNITTEST_BUILD)
|
||||
|
||||
@@ -24,7 +24,7 @@ class Clio(ConanFile):
|
||||
'fmt/10.0.0',
|
||||
'grpc/1.50.1',
|
||||
'openssl/1.1.1u',
|
||||
'xrpl/1.12.0-b2',
|
||||
'xrpl/1.12.0',
|
||||
]
|
||||
|
||||
default_options = {
|
||||
|
||||
@@ -16,21 +16,12 @@
|
||||
//
|
||||
// Advanced options. USE AT OWN RISK:
|
||||
// ---
|
||||
"max_connections_per_host": 1, // Defaults to 2
|
||||
"core_connections_per_host": 1, // Defaults to 2
|
||||
"max_concurrent_requests_threshold": 55000 // Defaults to ((max_read + max_write) / core_connections_per_host)
|
||||
"core_connections_per_host": 1 // Defaults to 1
|
||||
//
|
||||
// Below options will use defaults from cassandra driver if left unspecified.
|
||||
// See https://docs.datastax.com/en/developer/cpp-driver/2.0/api/struct.CassCluster/ for details.
|
||||
// See https://docs.datastax.com/en/developer/cpp-driver/2.17/api/struct.CassCluster/ for details.
|
||||
//
|
||||
// "queue_size_event": 1,
|
||||
// "queue_size_io": 2,
|
||||
// "write_bytes_high_water_mark": 3,
|
||||
// "write_bytes_low_water_mark": 4,
|
||||
// "pending_requests_high_water_mark": 5,
|
||||
// "pending_requests_low_water_mark": 6,
|
||||
// "max_requests_per_flush": 7,
|
||||
// "max_concurrent_creation": 8
|
||||
// "queue_size_io": 2
|
||||
//
|
||||
// ---
|
||||
}
|
||||
|
||||
@@ -93,14 +93,15 @@ synchronous(FnType&& func)
|
||||
if constexpr (!std::is_same<R, void>::value)
|
||||
{
|
||||
R res;
|
||||
boost::asio::spawn(ctx, [&func, &res](auto yield) { res = func(yield); });
|
||||
boost::asio::spawn(
|
||||
ctx, [_ = boost::asio::make_work_guard(ctx), &func, &res](auto yield) { res = func(yield); });
|
||||
|
||||
ctx.run();
|
||||
return res;
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::asio::spawn(ctx, [&func](auto yield) { func(yield); });
|
||||
boost::asio::spawn(ctx, [_ = boost::asio::make_work_guard(ctx), &func](auto yield) { func(yield); });
|
||||
ctx.run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ LedgerCache::getSuccessor(ripple::uint256 const& key, uint32_t seq) const
|
||||
{
|
||||
if (!full_)
|
||||
return {};
|
||||
std::shared_lock{mtx_};
|
||||
std::shared_lock lck{mtx_};
|
||||
successorReqCounter_++;
|
||||
if (seq != latestSeq_)
|
||||
return {};
|
||||
|
||||
@@ -116,22 +116,10 @@ SettingsProvider::parseSettings() const
|
||||
config_.valueOr<uint32_t>("max_write_requests_outstanding", settings.maxWriteRequestsOutstanding);
|
||||
settings.maxReadRequestsOutstanding =
|
||||
config_.valueOr<uint32_t>("max_read_requests_outstanding", settings.maxReadRequestsOutstanding);
|
||||
settings.maxConnectionsPerHost =
|
||||
config_.valueOr<uint32_t>("max_connections_per_host", settings.maxConnectionsPerHost);
|
||||
settings.coreConnectionsPerHost =
|
||||
config_.valueOr<uint32_t>("core_connections_per_host", settings.coreConnectionsPerHost);
|
||||
settings.maxConcurrentRequestsThreshold = config_.valueOr<uint32_t>(
|
||||
"max_concurrent_requests_threshold",
|
||||
(settings.maxReadRequestsOutstanding + settings.maxWriteRequestsOutstanding) / settings.coreConnectionsPerHost);
|
||||
|
||||
settings.queueSizeIO = config_.maybeValue<uint32_t>("queue_size_io");
|
||||
settings.queueSizeEvent = config_.maybeValue<uint32_t>("queue_size_event");
|
||||
settings.writeBytesHighWatermark = config_.maybeValue<uint32_t>("write_bytes_high_water_mark");
|
||||
settings.writeBytesLowWatermark = config_.maybeValue<uint32_t>("write_bytes_low_water_mark");
|
||||
settings.pendingRequestsHighWatermark = config_.maybeValue<uint32_t>("pending_requests_high_water_mark");
|
||||
settings.pendingRequestsLowWatermark = config_.maybeValue<uint32_t>("pending_requests_low_water_mark");
|
||||
settings.maxRequestsPerFlush = config_.maybeValue<uint32_t>("max_requests_per_flush");
|
||||
settings.maxConcurrentCreation = config_.maybeValue<uint32_t>("max_concurrent_creation");
|
||||
|
||||
auto const connectTimeoutSecond = config_.maybeValue<uint32_t>("connect_timeout");
|
||||
if (connectTimeoutSecond)
|
||||
|
||||
@@ -64,19 +64,6 @@ Cluster::Cluster(Settings const& settings) : ManagedObject{cass_cluster_new(), c
|
||||
cass_cluster_set_connect_timeout(*this, settings.connectionTimeout.count());
|
||||
cass_cluster_set_request_timeout(*this, settings.requestTimeout.count());
|
||||
|
||||
if (auto const rc =
|
||||
cass_cluster_set_max_concurrent_requests_threshold(*this, settings.maxConcurrentRequestsThreshold);
|
||||
rc != CASS_OK)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
fmt::format("Could not set max concurrent requests per host threshold: {}", cass_error_desc(rc)));
|
||||
}
|
||||
|
||||
if (auto const rc = cass_cluster_set_max_connections_per_host(*this, settings.maxConnectionsPerHost); rc != CASS_OK)
|
||||
{
|
||||
throw std::runtime_error(fmt::format("Could not set max connections per host: {}", cass_error_desc(rc)));
|
||||
}
|
||||
|
||||
if (auto const rc = cass_cluster_set_core_connections_per_host(*this, settings.coreConnectionsPerHost);
|
||||
rc != CASS_OK)
|
||||
{
|
||||
@@ -90,71 +77,13 @@ Cluster::Cluster(Settings const& settings) : ManagedObject{cass_cluster_new(), c
|
||||
throw std::runtime_error(fmt::format("Could not set queue size for IO per host: {}", cass_error_desc(rc)));
|
||||
}
|
||||
|
||||
auto apply = []<typename ValueType, typename Fn>(
|
||||
std::optional<ValueType> const& maybeValue, Fn&& fn) requires std::is_object_v<Fn>
|
||||
{
|
||||
if (maybeValue)
|
||||
std::invoke(fn, maybeValue.value());
|
||||
};
|
||||
|
||||
apply(settings.queueSizeEvent, [this](auto value) {
|
||||
if (auto const rc = cass_cluster_set_queue_size_event(*this, value); rc != CASS_OK)
|
||||
throw std::runtime_error(
|
||||
fmt::format("Could not set queue size for events per host: {}", cass_error_desc(rc)));
|
||||
});
|
||||
|
||||
apply(settings.writeBytesHighWatermark, [this](auto value) {
|
||||
if (auto const rc = cass_cluster_set_write_bytes_high_water_mark(*this, value); rc != CASS_OK)
|
||||
throw std::runtime_error(fmt::format("Could not set write bytes high water_mark: {}", cass_error_desc(rc)));
|
||||
});
|
||||
|
||||
apply(settings.writeBytesLowWatermark, [this](auto value) {
|
||||
if (auto const rc = cass_cluster_set_write_bytes_low_water_mark(*this, value); rc != CASS_OK)
|
||||
throw std::runtime_error(fmt::format("Could not set write bytes low water mark: {}", cass_error_desc(rc)));
|
||||
});
|
||||
|
||||
apply(settings.pendingRequestsHighWatermark, [this](auto value) {
|
||||
if (auto const rc = cass_cluster_set_pending_requests_high_water_mark(*this, value); rc != CASS_OK)
|
||||
throw std::runtime_error(
|
||||
fmt::format("Could not set pending requests high water mark: {}", cass_error_desc(rc)));
|
||||
});
|
||||
|
||||
apply(settings.pendingRequestsLowWatermark, [this](auto value) {
|
||||
if (auto const rc = cass_cluster_set_pending_requests_low_water_mark(*this, value); rc != CASS_OK)
|
||||
throw std::runtime_error(
|
||||
fmt::format("Could not set pending requests low water mark: {}", cass_error_desc(rc)));
|
||||
});
|
||||
|
||||
apply(settings.maxRequestsPerFlush, [this](auto value) {
|
||||
if (auto const rc = cass_cluster_set_max_requests_per_flush(*this, value); rc != CASS_OK)
|
||||
throw std::runtime_error(fmt::format("Could not set max requests per flush: {}", cass_error_desc(rc)));
|
||||
});
|
||||
|
||||
apply(settings.maxConcurrentCreation, [this](auto value) {
|
||||
if (auto const rc = cass_cluster_set_max_concurrent_creation(*this, value); rc != CASS_OK)
|
||||
throw std::runtime_error(fmt::format("Could not set max concurrent creation: {}", cass_error_desc(rc)));
|
||||
});
|
||||
|
||||
setupConnection(settings);
|
||||
setupCertificate(settings);
|
||||
setupCredentials(settings);
|
||||
|
||||
auto valueOrDefault = []<typename T>(std::optional<T> const& maybeValue) -> std::string {
|
||||
return maybeValue ? to_string(*maybeValue) : "default";
|
||||
};
|
||||
|
||||
LOG(log_.info()) << "Threads: " << settings.threads;
|
||||
LOG(log_.info()) << "Max concurrent requests per host: " << settings.maxConcurrentRequestsThreshold;
|
||||
LOG(log_.info()) << "Max connections per host: " << settings.maxConnectionsPerHost;
|
||||
LOG(log_.info()) << "Core connections per host: " << settings.coreConnectionsPerHost;
|
||||
LOG(log_.info()) << "IO queue size: " << queueSize;
|
||||
LOG(log_.info()) << "Event queue size: " << valueOrDefault(settings.queueSizeEvent);
|
||||
LOG(log_.info()) << "Write bytes high watermark: " << valueOrDefault(settings.writeBytesHighWatermark);
|
||||
LOG(log_.info()) << "Write bytes low watermark: " << valueOrDefault(settings.writeBytesLowWatermark);
|
||||
LOG(log_.info()) << "Pending requests high watermark: " << valueOrDefault(settings.pendingRequestsHighWatermark);
|
||||
LOG(log_.info()) << "Pending requests low watermark: " << valueOrDefault(settings.pendingRequestsLowWatermark);
|
||||
LOG(log_.info()) << "Max requests per flush: " << valueOrDefault(settings.maxRequestsPerFlush);
|
||||
LOG(log_.info()) << "Max concurrent creation: " << valueOrDefault(settings.maxConcurrentCreation);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -73,45 +73,17 @@ struct Settings
|
||||
uint32_t threads = std::thread::hardware_concurrency();
|
||||
|
||||
/** @brief The maximum number of outstanding write requests at any given moment */
|
||||
uint32_t maxWriteRequestsOutstanding = 10'000;
|
||||
uint32_t maxWriteRequestsOutstanding = 10'000u;
|
||||
|
||||
/** @brief The maximum number of outstanding read requests at any given moment */
|
||||
uint32_t maxReadRequestsOutstanding = 100'000;
|
||||
|
||||
/** @brief The maximum number of connections per host */
|
||||
uint32_t maxConnectionsPerHost = 2u;
|
||||
uint32_t maxReadRequestsOutstanding = 100'000u;
|
||||
|
||||
/** @brief The number of connection per host to always have active */
|
||||
uint32_t coreConnectionsPerHost = 2u;
|
||||
|
||||
/** @brief The maximum concurrent requests per connection; new connections will be created when reached */
|
||||
uint32_t maxConcurrentRequestsThreshold =
|
||||
(maxWriteRequestsOutstanding + maxReadRequestsOutstanding) / coreConnectionsPerHost;
|
||||
|
||||
/** @brief Size of the event queue */
|
||||
std::optional<uint32_t> queueSizeEvent;
|
||||
uint32_t coreConnectionsPerHost = 1u;
|
||||
|
||||
/** @brief Size of the IO queue */
|
||||
std::optional<uint32_t> queueSizeIO;
|
||||
|
||||
/** @brief High watermark for bytes written */
|
||||
std::optional<uint32_t> writeBytesHighWatermark;
|
||||
|
||||
/** @brief Low watermark for bytes written */
|
||||
std::optional<uint32_t> writeBytesLowWatermark;
|
||||
|
||||
/** @brief High watermark for pending requests */
|
||||
std::optional<uint32_t> pendingRequestsHighWatermark;
|
||||
|
||||
/** @brief Low watermark for pending requests */
|
||||
std::optional<uint32_t> pendingRequestsLowWatermark;
|
||||
|
||||
/** @brief Maximum number of requests per flush */
|
||||
std::optional<uint32_t> maxRequestsPerFlush;
|
||||
|
||||
/** @brief Maximum number of connections that will be created concurrently */
|
||||
std::optional<uint32_t> maxConcurrentCreation;
|
||||
|
||||
/** @brief SSL certificate */
|
||||
std::optional<std::string> certificate; // ssl context
|
||||
|
||||
|
||||
@@ -235,21 +235,15 @@ public:
|
||||
while (true)
|
||||
{
|
||||
numReadRequestsOutstanding_ += numStatements;
|
||||
// TODO: see if we can avoid using shared_ptr for self here
|
||||
|
||||
auto init = [this, &statements, &future]<typename Self>(Self& self) {
|
||||
future.emplace(handle_.get().asyncExecute(
|
||||
statements, [sself = std::make_shared<Self>(std::move(self))](auto&& res) mutable {
|
||||
// Note: explicit work below needed on linux/gcc11
|
||||
auto executor = boost::asio::get_associated_executor(*sself);
|
||||
boost::asio::post(
|
||||
executor,
|
||||
[sself = std::move(sself),
|
||||
res = std::move(res),
|
||||
_ = boost::asio::make_work_guard(executor)]() mutable {
|
||||
sself->complete(std::move(res));
|
||||
sself.reset();
|
||||
});
|
||||
}));
|
||||
auto sself = std::make_shared<Self>(std::move(self));
|
||||
|
||||
future.emplace(handle_.get().asyncExecute(statements, [sself](auto&& res) mutable {
|
||||
boost::asio::post(
|
||||
boost::asio::get_associated_executor(*sself),
|
||||
[sself, res = std::move(res)]() mutable { sself->complete(std::move(res)); });
|
||||
}));
|
||||
};
|
||||
|
||||
auto res = boost::asio::async_compose<CompletionTokenType, void(ResultOrErrorType)>(
|
||||
@@ -287,25 +281,21 @@ public:
|
||||
while (true)
|
||||
{
|
||||
++numReadRequestsOutstanding_;
|
||||
// TODO: see if we can avoid using shared_ptr for self here
|
||||
auto init = [this, &statement, &future]<typename Self>(Self& self) {
|
||||
future.emplace(handle_.get().asyncExecute(
|
||||
statement, [sself = std::make_shared<Self>(std::move(self))](auto&&) mutable {
|
||||
// Note: explicit work below needed on linux/gcc11
|
||||
auto executor = boost::asio::get_associated_executor(*sself);
|
||||
boost::asio::post(
|
||||
executor, [sself = std::move(sself), _ = boost::asio::make_work_guard(executor)]() mutable {
|
||||
sself->complete();
|
||||
sself.reset();
|
||||
});
|
||||
}));
|
||||
auto sself = std::make_shared<Self>(std::move(self));
|
||||
|
||||
future.emplace(handle_.get().asyncExecute(statement, [sself](auto&& res) mutable {
|
||||
boost::asio::post(
|
||||
boost::asio::get_associated_executor(*sself),
|
||||
[sself, res = std::move(res)]() mutable { sself->complete(std::move(res)); });
|
||||
}));
|
||||
};
|
||||
|
||||
boost::asio::async_compose<CompletionTokenType, void()>(
|
||||
auto res = boost::asio::async_compose<CompletionTokenType, void(ResultOrErrorType)>(
|
||||
init, token, boost::asio::get_associated_executor(token));
|
||||
--numReadRequestsOutstanding_;
|
||||
|
||||
if (auto res = future->get(); res)
|
||||
if (res)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
@@ -339,22 +329,15 @@ public:
|
||||
futures.reserve(numOutstanding);
|
||||
|
||||
auto init = [this, &statements, &futures, &hadError, &numOutstanding]<typename Self>(Self& self) {
|
||||
auto sself = std::make_shared<Self>(std::move(self)); // TODO: see if we can avoid this
|
||||
auto executionHandler = [&hadError, &numOutstanding, sself = std::move(sself)](auto const& res) mutable {
|
||||
auto sself = std::make_shared<Self>(std::move(self));
|
||||
auto executionHandler = [&hadError, &numOutstanding, sself](auto const& res) mutable {
|
||||
if (not res)
|
||||
hadError = true;
|
||||
|
||||
// when all async operations complete unblock the result
|
||||
if (--numOutstanding == 0)
|
||||
{
|
||||
// Note: explicit work below needed on linux/gcc11
|
||||
auto executor = boost::asio::get_associated_executor(*sself);
|
||||
boost::asio::post(
|
||||
executor, [sself = std::move(sself), _ = boost::asio::make_work_guard(executor)]() mutable {
|
||||
sself->complete();
|
||||
sself.reset();
|
||||
});
|
||||
}
|
||||
boost::asio::get_associated_executor(*sself), [sself]() mutable { sself->complete(); });
|
||||
};
|
||||
|
||||
std::transform(
|
||||
|
||||
@@ -73,7 +73,10 @@ void
|
||||
invokeHelper(CassFuture* ptr, void* cbPtr)
|
||||
{
|
||||
// Note: can't use Future{ptr}.get() because double free will occur :/
|
||||
// Note2: we are moving/copying it locally as a workaround for an issue we are seeing from asio recently.
|
||||
// stackoverflow.com/questions/77004137/boost-asio-async-compose-gets-stuck-under-load
|
||||
auto* cb = static_cast<FutureWithCallback::FnType*>(cbPtr);
|
||||
auto local = std::make_unique<FutureWithCallback::FnType>(std::move(*cb));
|
||||
if (auto const rc = cass_future_error_code(ptr); rc)
|
||||
{
|
||||
auto const errMsg = [&ptr](std::string const& label) {
|
||||
@@ -82,11 +85,11 @@ invokeHelper(CassFuture* ptr, void* cbPtr)
|
||||
cass_future_error_message(ptr, &message, &len);
|
||||
return label + ": " + std::string{message, len};
|
||||
}("invokeHelper");
|
||||
(*cb)(Error{CassandraError{errMsg, rc}});
|
||||
(*local)(Error{CassandraError{errMsg, rc}});
|
||||
}
|
||||
else
|
||||
{
|
||||
(*cb)(Result{cass_future_get_result(ptr)});
|
||||
(*local)(Result{cass_future_get_result(ptr)});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,8 @@ ETLService::runETLPipeline(uint32_t startSequence, uint32_t numExtractors)
|
||||
extractors.push_back(std::make_unique<ExtractorType>(
|
||||
pipe, networkValidatedLedgers_, ledgerFetcher_, startSequence + i, finishSequence_, state_));
|
||||
|
||||
auto transformer = TransformerType{pipe, backend_, ledgerLoader_, ledgerPublisher_, startSequence, state_};
|
||||
auto transformer =
|
||||
TransformerType{pipe, backend_, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, startSequence, state_};
|
||||
transformer.waitTillFinished(); // suspend current thread until exit condition is met
|
||||
pipe.cleanup(); // TODO: this should probably happen automatically using destructor
|
||||
|
||||
@@ -110,12 +111,8 @@ ETLService::monitor()
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
setAmendmentBlocked();
|
||||
|
||||
log_.fatal()
|
||||
<< "Failed to load initial ledger, Exiting monitor loop: " << e.what()
|
||||
<< " Possible cause: The ETL node is not compatible with the version of the rippled lib Clio is using.";
|
||||
return;
|
||||
LOG(log_.fatal()) << "Failed to load initial ledger: " << e.what();
|
||||
return amendmentBlockHandler_.onAmendmentBlock();
|
||||
}
|
||||
|
||||
if (ledger)
|
||||
@@ -259,6 +256,7 @@ ETLService::ETLService(
|
||||
, ledgerFetcher_(backend, balancer)
|
||||
, ledgerLoader_(backend, balancer, ledgerFetcher_, state_)
|
||||
, ledgerPublisher_(ioc, backend, subscriptions, state_)
|
||||
, amendmentBlockHandler_(ioc, state_)
|
||||
{
|
||||
startSequence_ = config.maybeValue<uint32_t>("start_sequence");
|
||||
finishSequence_ = config.maybeValue<uint32_t>("finish_sequence");
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <etl/LoadBalancer.h>
|
||||
#include <etl/Source.h>
|
||||
#include <etl/SystemState.h>
|
||||
#include <etl/impl/AmendmentBlock.h>
|
||||
#include <etl/impl/CacheLoader.h>
|
||||
#include <etl/impl/ExtractionDataPipe.h>
|
||||
#include <etl/impl/Extractor.h>
|
||||
@@ -35,6 +36,7 @@
|
||||
#include <util/log/Logger.h>
|
||||
|
||||
#include <ripple/proto/org/xrpl/rpc/v1/xrp_ledger.grpc.pb.h>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <grpcpp/grpcpp.h>
|
||||
|
||||
#include <memory>
|
||||
@@ -76,7 +78,9 @@ class ETLService
|
||||
using ExtractorType = etl::detail::Extractor<DataPipeType, NetworkValidatedLedgersType, LedgerFetcherType>;
|
||||
using LedgerLoaderType = etl::detail::LedgerLoader<LoadBalancerType, LedgerFetcherType>;
|
||||
using LedgerPublisherType = etl::detail::LedgerPublisher<SubscriptionManagerType>;
|
||||
using TransformerType = etl::detail::Transformer<DataPipeType, LedgerLoaderType, LedgerPublisherType>;
|
||||
using AmendmentBlockHandlerType = etl::detail::AmendmentBlockHandler<>;
|
||||
using TransformerType =
|
||||
etl::detail::Transformer<DataPipeType, LedgerLoaderType, LedgerPublisherType, AmendmentBlockHandlerType>;
|
||||
|
||||
util::Logger log_{"ETL"};
|
||||
|
||||
@@ -91,6 +95,7 @@ class ETLService
|
||||
LedgerFetcherType ledgerFetcher_;
|
||||
LedgerLoaderType ledgerLoader_;
|
||||
LedgerPublisherType ledgerPublisher_;
|
||||
AmendmentBlockHandlerType amendmentBlockHandler_;
|
||||
|
||||
SystemState state_;
|
||||
|
||||
@@ -267,14 +272,5 @@ private:
|
||||
*/
|
||||
void
|
||||
doWork();
|
||||
|
||||
/**
|
||||
* @brief Sets amendment blocked flag.
|
||||
*/
|
||||
void
|
||||
setAmendmentBlocked()
|
||||
{
|
||||
state_.isAmendmentBlocked = true;
|
||||
}
|
||||
};
|
||||
} // namespace etl
|
||||
|
||||
@@ -36,10 +36,18 @@ struct SystemState
|
||||
*/
|
||||
bool isReadOnly = false;
|
||||
|
||||
std::atomic_bool isWriting = false; /**< @brief Whether the process is writing to the database. */
|
||||
std::atomic_bool isStopping = false; /**< @brief Whether the software is stopping. */
|
||||
std::atomic_bool writeConflict = false; /**< @brief Whether a write conflict was detected. */
|
||||
std::atomic_bool isAmendmentBlocked = false; /**< @brief Whether we detected an amendment block. */
|
||||
std::atomic_bool isWriting = false; /**< @brief Whether the process is writing to the database. */
|
||||
std::atomic_bool isStopping = false; /**< @brief Whether the software is stopping. */
|
||||
std::atomic_bool writeConflict = false; /**< @brief Whether a write conflict was detected. */
|
||||
|
||||
/**
|
||||
* @brief Whether clio detected an amendment block.
|
||||
*
|
||||
* Being amendment blocked means that Clio was compiled with libxrpl that does not yet support some field that
|
||||
* arrived from rippled and therefore can't extract the ledger diff. When this happens, Clio can't proceed with ETL
|
||||
* and should log this error and only handle RPC requests.
|
||||
*/
|
||||
std::atomic_bool isAmendmentBlocked = false;
|
||||
};
|
||||
|
||||
} // namespace etl
|
||||
|
||||
96
src/etl/impl/AmendmentBlock.h
Normal file
96
src/etl/impl/AmendmentBlock.h
Normal file
@@ -0,0 +1,96 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2023, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <etl/SystemState.h>
|
||||
#include <util/log/Logger.h>
|
||||
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
|
||||
namespace etl::detail {
|
||||
|
||||
struct AmendmentBlockAction
|
||||
{
|
||||
void
|
||||
operator()()
|
||||
{
|
||||
static util::Logger log{"ETL"};
|
||||
LOG(log.fatal())
|
||||
<< "Can't process new ledgers: The current ETL source is not compatible with the version of the "
|
||||
"libxrpl Clio is currently using. Please upgrade Clio to a newer version.";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ActionCallableType = AmendmentBlockAction>
|
||||
class AmendmentBlockHandler
|
||||
{
|
||||
std::reference_wrapper<boost::asio::io_context> ctx_;
|
||||
std::reference_wrapper<SystemState> state_;
|
||||
boost::asio::steady_timer timer_;
|
||||
std::chrono::milliseconds interval_;
|
||||
|
||||
ActionCallableType action_;
|
||||
|
||||
public:
|
||||
template <typename DurationType = std::chrono::seconds>
|
||||
AmendmentBlockHandler(
|
||||
boost::asio::io_context& ioc,
|
||||
SystemState& state,
|
||||
DurationType interval = DurationType{1},
|
||||
ActionCallableType&& action = ActionCallableType())
|
||||
: ctx_{std::ref(ioc)}
|
||||
, state_{std::ref(state)}
|
||||
, timer_{ioc}
|
||||
, interval_{std::chrono::duration_cast<std::chrono::milliseconds>(interval)}
|
||||
, action_{std::move(action)}
|
||||
{
|
||||
}
|
||||
|
||||
~AmendmentBlockHandler()
|
||||
{
|
||||
boost::asio::post(ctx_.get(), [this]() { timer_.cancel(); });
|
||||
}
|
||||
|
||||
void
|
||||
onAmendmentBlock()
|
||||
{
|
||||
state_.get().isAmendmentBlocked = true;
|
||||
startReportingTimer();
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
startReportingTimer()
|
||||
{
|
||||
action_();
|
||||
|
||||
timer_.expires_after(interval_);
|
||||
timer_.async_wait([this](auto ec) {
|
||||
if (!ec)
|
||||
boost::asio::post(ctx_.get(), [this] { startReportingTimer(); });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace etl::detail
|
||||
@@ -68,6 +68,7 @@ class CacheLoader
|
||||
|
||||
std::vector<ClioPeer> clioPeers_;
|
||||
|
||||
std::thread thread_;
|
||||
std::atomic_bool stopping_ = false;
|
||||
|
||||
public:
|
||||
@@ -115,6 +116,8 @@ public:
|
||||
~CacheLoader()
|
||||
{
|
||||
stop();
|
||||
if (thread_.joinable())
|
||||
thread_.join();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -367,7 +370,7 @@ private:
|
||||
LOG(log_.info()) << "Loading cache. num cursors = " << cursors.size() - 1;
|
||||
LOG(log_.trace()) << "cursors = " << cursorStr.str();
|
||||
|
||||
boost::asio::post(ioContext_.get(), [this, seq, cursors = std::move(cursors)]() {
|
||||
thread_ = std::thread{[this, seq, cursors = std::move(cursors)]() {
|
||||
auto startTime = std::chrono::system_clock::now();
|
||||
auto markers = std::make_shared<std::atomic_int>(0);
|
||||
auto numRemaining = std::make_shared<std::atomic_int>(cursors.size() - 1);
|
||||
@@ -425,7 +428,7 @@ private:
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <data/BackendInterface.h>
|
||||
#include <etl/SystemState.h>
|
||||
#include <etl/impl/AmendmentBlock.h>
|
||||
#include <etl/impl/LedgerLoader.h>
|
||||
#include <util/LedgerUtils.h>
|
||||
#include <util/Profiler.h>
|
||||
@@ -47,7 +48,11 @@ namespace etl::detail {
|
||||
/**
|
||||
* @brief Transformer thread that prepares new ledger out of raw data from GRPC.
|
||||
*/
|
||||
template <typename DataPipeType, typename LedgerLoaderType, typename LedgerPublisherType>
|
||||
template <
|
||||
typename DataPipeType,
|
||||
typename LedgerLoaderType,
|
||||
typename LedgerPublisherType,
|
||||
typename AmendmentBlockHandlerType>
|
||||
class Transformer
|
||||
{
|
||||
using GetLedgerResponseType = typename LedgerLoaderType::GetLedgerResponseType;
|
||||
@@ -59,6 +64,8 @@ class Transformer
|
||||
std::shared_ptr<BackendInterface> backend_;
|
||||
std::reference_wrapper<LedgerLoaderType> loader_;
|
||||
std::reference_wrapper<LedgerPublisherType> publisher_;
|
||||
std::reference_wrapper<AmendmentBlockHandlerType> amendmentBlockHandler_;
|
||||
|
||||
uint32_t startSequence_;
|
||||
std::reference_wrapper<SystemState> state_; // shared state for ETL
|
||||
|
||||
@@ -76,12 +83,14 @@ public:
|
||||
std::shared_ptr<BackendInterface> backend,
|
||||
LedgerLoaderType& loader,
|
||||
LedgerPublisherType& publisher,
|
||||
AmendmentBlockHandlerType& amendmentBlockHandler,
|
||||
uint32_t startSequence,
|
||||
SystemState& state)
|
||||
: pipe_(std::ref(pipe))
|
||||
: pipe_{std::ref(pipe)}
|
||||
, backend_{backend}
|
||||
, loader_(std::ref(loader))
|
||||
, publisher_(std::ref(publisher))
|
||||
, loader_{std::ref(loader)}
|
||||
, publisher_{std::ref(publisher)}
|
||||
, amendmentBlockHandler_{std::ref(amendmentBlockHandler)}
|
||||
, startSequence_{startSequence}
|
||||
, state_{std::ref(state)}
|
||||
{
|
||||
@@ -185,11 +194,9 @@ private:
|
||||
}
|
||||
catch (std::runtime_error const& e)
|
||||
{
|
||||
setAmendmentBlocked();
|
||||
LOG(log_.fatal()) << "Failed to build next ledger: " << e.what();
|
||||
|
||||
log_.fatal()
|
||||
<< "Failed to build next ledger: " << e.what()
|
||||
<< " Possible cause: The ETL node is not compatible with the version of the rippled lib Clio is using.";
|
||||
amendmentBlockHandler_.get().onAmendmentBlock();
|
||||
return {ripple::LedgerHeader{}, false};
|
||||
}
|
||||
|
||||
@@ -238,7 +245,7 @@ private:
|
||||
LOG(log_.debug()) << "object neighbors not included. using cache";
|
||||
|
||||
if (!backend_->cache().isFull() || backend_->cache().latestLedgerSequence() != lgrInfo.seq - 1)
|
||||
throw std::runtime_error("Cache is not full, but object neighbors were not included");
|
||||
throw std::logic_error("Cache is not full, but object neighbors were not included");
|
||||
|
||||
auto const blob = obj.mutable_data();
|
||||
auto checkBookBase = false;
|
||||
@@ -288,7 +295,7 @@ private:
|
||||
{
|
||||
LOG(log_.debug()) << "object neighbors not included. using cache";
|
||||
if (!backend_->cache().isFull() || backend_->cache().latestLedgerSequence() != lgrInfo.seq)
|
||||
throw std::runtime_error("Cache is not full, but object neighbors were not included");
|
||||
throw std::logic_error("Cache is not full, but object neighbors were not included");
|
||||
|
||||
for (auto const& obj : cacheUpdates)
|
||||
{
|
||||
@@ -423,19 +430,6 @@ private:
|
||||
{
|
||||
state_.get().writeConflict = conflict;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the amendment blocked flag.
|
||||
*
|
||||
* Being amendment blocked means that Clio was compiled with libxrpl that does not yet support some field that
|
||||
* arrived from rippled and therefore can't extract the ledger diff. When this happens, Clio can't proceed with ETL
|
||||
* and should log this error and only handle RPC requests.
|
||||
*/
|
||||
void
|
||||
setAmendmentBlocked()
|
||||
{
|
||||
state_.get().isAmendmentBlocked = true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace etl::detail
|
||||
|
||||
@@ -19,10 +19,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <util/JsonUtils.h>
|
||||
|
||||
#include <ripple/protocol/jss.h>
|
||||
|
||||
/** @brief Helper macro for borrowing from ripple::jss static (J)son (S)trings. */
|
||||
#define JS(x) ripple::jss::x.c_str()
|
||||
|
||||
/** @brief Access the lower case copy of a static (J)son (S)tring. */
|
||||
#define JSL(x) util::toLower(JS(x))
|
||||
|
||||
/** @brief Provides access to (SF)ield name (S)trings. */
|
||||
#define SFS(x) ripple::x.jsonName.c_str()
|
||||
|
||||
@@ -141,6 +141,7 @@ accountFromStringStrict(std::string const& account)
|
||||
else
|
||||
return {};
|
||||
}
|
||||
|
||||
std::pair<std::shared_ptr<ripple::STTx const>, std::shared_ptr<ripple::STObject const>>
|
||||
deserializeTxPlusMeta(data::TransactionAndMetadata const& blobs)
|
||||
{
|
||||
@@ -654,8 +655,10 @@ traverseOwnedNodes(
|
||||
}
|
||||
auto end = std::chrono::system_clock::now();
|
||||
|
||||
LOG(gLog.debug()) << "Time loading owned directories: "
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << " milliseconds";
|
||||
LOG(gLog.debug()) << fmt::format(
|
||||
"Time loading owned directories: {} milliseconds, entries size: {}",
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(),
|
||||
keys.size());
|
||||
|
||||
auto [objects, timeDiff] = util::timed([&]() { return backend.fetchLedgerObjects(keys, sequence, yield); });
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
#include <rpc/common/Concepts.h>
|
||||
#include <rpc/common/Specs.h>
|
||||
#include <rpc/common/Types.h>
|
||||
#include <util/JsonUtils.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace rpc::modifiers {
|
||||
|
||||
@@ -68,4 +71,32 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Convert input string to lower case.
|
||||
*
|
||||
* Note: the conversion is only performed if the input value is a string.
|
||||
*/
|
||||
struct ToLower final
|
||||
{
|
||||
/**
|
||||
* @brief Update the input string to lower case.
|
||||
*
|
||||
* @param value The JSON value representing the outer object
|
||||
* @param key The key used to retrieve the modified value from the outer object
|
||||
* @return Possibly an error
|
||||
*/
|
||||
[[nodiscard]] MaybeError
|
||||
modify(boost::json::value& value, std::string_view key) const
|
||||
{
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
return {}; // ignore. field does not exist, let 'required' fail instead
|
||||
|
||||
if (not value.as_object().at(key.data()).is_string())
|
||||
return {}; // ignore for non-string types
|
||||
|
||||
value.as_object()[key.data()] = util::toLower(value.as_object().at(key.data()).as_string().c_str());
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rpc::modifiers
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
namespace rpc {
|
||||
|
||||
// found here : https://xrpl.org/ledger_entry.html#:~:text=valid%20fields%20are%3A-,index,-account_root
|
||||
std::unordered_map<std::string, ripple::LedgerEntryType> const AccountObjectsHandler::TYPESMAP{
|
||||
{"state", ripple::ltRIPPLE_STATE},
|
||||
{"ticket", ripple::ltTICKET},
|
||||
|
||||
@@ -18,10 +18,50 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <rpc/handlers/AccountTx.h>
|
||||
#include <util/JsonUtils.h>
|
||||
#include <util/Profiler.h>
|
||||
|
||||
namespace rpc {
|
||||
|
||||
// found here : https://xrpl.org/transaction-types.html
|
||||
// TODO [https://github.com/XRPLF/clio/issues/856]: add AMMBid, AMMCreate, AMMDelete, AMMDeposit, AMMVote, AMMWithdraw
|
||||
std::unordered_map<std::string, ripple::TxType> const AccountTxHandler::TYPESMAP{
|
||||
{JSL(AccountSet), ripple::ttACCOUNT_SET},
|
||||
{JSL(AccountDelete), ripple::ttACCOUNT_DELETE},
|
||||
{JSL(CheckCancel), ripple::ttCHECK_CANCEL},
|
||||
{JSL(CheckCash), ripple::ttCHECK_CASH},
|
||||
{JSL(CheckCreate), ripple::ttCHECK_CREATE},
|
||||
{JSL(Clawback), ripple::ttCLAWBACK},
|
||||
{JSL(DepositPreauth), ripple::ttDEPOSIT_PREAUTH},
|
||||
{JSL(EscrowCancel), ripple::ttESCROW_CANCEL},
|
||||
{JSL(EscrowCreate), ripple::ttESCROW_CREATE},
|
||||
{JSL(EscrowFinish), ripple::ttESCROW_FINISH},
|
||||
{JSL(NFTokenAcceptOffer), ripple::ttNFTOKEN_ACCEPT_OFFER},
|
||||
{JSL(NFTokenBurn), ripple::ttNFTOKEN_BURN},
|
||||
{JSL(NFTokenCancelOffer), ripple::ttNFTOKEN_CANCEL_OFFER},
|
||||
{JSL(NFTokenCreateOffer), ripple::ttNFTOKEN_CREATE_OFFER},
|
||||
{JSL(NFTokenMint), ripple::ttNFTOKEN_MINT},
|
||||
{JSL(OfferCancel), ripple::ttOFFER_CANCEL},
|
||||
{JSL(OfferCreate), ripple::ttOFFER_CREATE},
|
||||
{JSL(Payment), ripple::ttPAYMENT},
|
||||
{JSL(PaymentChannelClaim), ripple::ttPAYCHAN_CLAIM},
|
||||
{JSL(PaymentChannelCreate), ripple::ttCHECK_CREATE},
|
||||
{JSL(PaymentChannelFund), ripple::ttPAYCHAN_FUND},
|
||||
{JSL(SetRegularKey), ripple::ttREGULAR_KEY_SET},
|
||||
{JSL(SignerListSet), ripple::ttSIGNER_LIST_SET},
|
||||
{JSL(TicketCreate), ripple::ttTICKET_CREATE},
|
||||
{JSL(TrustSet), ripple::ttTRUST_SET},
|
||||
};
|
||||
|
||||
// TODO: should be std::views::keys when clang supports it
|
||||
std::unordered_set<std::string> const AccountTxHandler::TYPES_KEYS = [] {
|
||||
std::unordered_set<std::string> keys;
|
||||
std::transform(TYPESMAP.begin(), TYPESMAP.end(), std::inserter(keys, keys.begin()), [](auto const& pair) {
|
||||
return pair.first;
|
||||
});
|
||||
return keys;
|
||||
}();
|
||||
|
||||
// TODO: this is currently very similar to nft_history but its own copy for time
|
||||
// being. we should aim to reuse common logic in some way in the future.
|
||||
AccountTxHandler::Result
|
||||
@@ -116,6 +156,18 @@ AccountTxHandler::process(AccountTxHandler::Input input, Context const& ctx) con
|
||||
auto [txn, meta] = toExpandedJson(txnPlusMeta, NFTokenjson::ENABLE);
|
||||
obj[JS(meta)] = std::move(meta);
|
||||
obj[JS(tx)] = std::move(txn);
|
||||
|
||||
if (obj[JS(tx)].as_object().contains(JS(TransactionType)))
|
||||
{
|
||||
auto const objTransactionType = obj[JS(tx)].as_object()[JS(TransactionType)];
|
||||
auto const strType = util::toLower(objTransactionType.as_string().c_str());
|
||||
|
||||
// if transactionType does not match
|
||||
if (input.transactionType.has_value() && AccountTxHandler::TYPESMAP.contains(strType) &&
|
||||
AccountTxHandler::TYPESMAP.at(strType) != input.transactionType.value())
|
||||
continue;
|
||||
}
|
||||
|
||||
obj[JS(tx)].as_object()[JS(ledger_index)] = txnPlusMeta.ledgerSequence;
|
||||
obj[JS(tx)].as_object()[JS(date)] = txnPlusMeta.date;
|
||||
}
|
||||
@@ -208,6 +260,12 @@ tag_invoke(boost::json::value_to_tag<AccountTxHandler::Input>, boost::json::valu
|
||||
jsonObject.at(JS(marker)).as_object().at(JS(ledger)).as_int64(),
|
||||
jsonObject.at(JS(marker)).as_object().at(JS(seq)).as_int64()};
|
||||
|
||||
if (jsonObject.contains("tx_type"))
|
||||
{
|
||||
auto objTransactionType = jsonObject.at("tx_type");
|
||||
input.transactionType = AccountTxHandler::TYPESMAP.at(objTransactionType.as_string().c_str());
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@ class AccountTxHandler
|
||||
util::Logger log_{"RPC"};
|
||||
std::shared_ptr<BackendInterface> sharedPtrBackend_;
|
||||
|
||||
static std::unordered_map<std::string, ripple::TxType> const TYPESMAP;
|
||||
static const std::unordered_set<std::string> TYPES_KEYS;
|
||||
|
||||
public:
|
||||
// no max limit
|
||||
static auto constexpr LIMIT_MIN = 1;
|
||||
@@ -77,6 +80,7 @@ public:
|
||||
bool forward = false;
|
||||
std::optional<uint32_t> limit;
|
||||
std::optional<Marker> marker;
|
||||
std::optional<ripple::TxType> transactionType;
|
||||
};
|
||||
|
||||
using Result = HandlerReturnType<Output>;
|
||||
@@ -109,6 +113,12 @@ public:
|
||||
{JS(ledger), validation::Required{}, validation::Type<uint32_t>{}},
|
||||
{JS(seq), validation::Required{}, validation::Type<uint32_t>{}},
|
||||
}},
|
||||
{
|
||||
"tx_type",
|
||||
validation::Type<std::string>{},
|
||||
modifiers::ToLower{},
|
||||
validation::OneOf<std::string>(TYPES_KEYS.cbegin(), TYPES_KEYS.cend()),
|
||||
},
|
||||
};
|
||||
|
||||
return rpcSpec;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <rpc/common/Validators.h>
|
||||
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/protocol/BuildInfo.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <fmt/core.h>
|
||||
@@ -87,6 +88,7 @@ public:
|
||||
std::chrono::time_point<std::chrono::system_clock> time = std::chrono::system_clock::now();
|
||||
std::chrono::seconds uptime = {};
|
||||
std::string clioVersion = Build::getClioVersionString();
|
||||
std::string xrplVersion = ripple::BuildInfo::getVersionString();
|
||||
std::optional<boost::json::object> rippledInfo = std::nullopt;
|
||||
ValidatedLedgerSection validatedLedger = {};
|
||||
CacheSection cache = {};
|
||||
@@ -194,6 +196,7 @@ private:
|
||||
{JS(time), to_string(std::chrono::floor<std::chrono::microseconds>(info.time))},
|
||||
{JS(uptime), info.uptime.count()},
|
||||
{"clio_version", info.clioVersion},
|
||||
{"libxrpl_version", info.xrplVersion},
|
||||
{JS(validated_ledger), value_from(info.validatedLedger)},
|
||||
{"cache", value_from(info.cache)},
|
||||
};
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include <data/BackendInterface.h>
|
||||
#include <rpc/RPCHelpers.h>
|
||||
#include <rpc/common/MetaProcessors.h>
|
||||
#include <rpc/common/Types.h>
|
||||
#include <rpc/common/Validators.h>
|
||||
|
||||
@@ -95,7 +96,11 @@ public:
|
||||
return Error{Status{RippledError::rpcINVALID_PARAMS, "snapshotNotBool"}};
|
||||
|
||||
if (book.as_object().contains("taker"))
|
||||
if (auto const err = validation::AccountValidator.verify(book.as_object(), "taker"); !err)
|
||||
if (auto const err = meta::WithCustomError(
|
||||
validation::AccountValidator,
|
||||
Status{RippledError::rpcBAD_ISSUER, "Issuer account malformed."})
|
||||
.verify(book.as_object(), "taker");
|
||||
!err)
|
||||
return err;
|
||||
|
||||
auto const parsedBook = parseBook(book.as_object());
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include <boost/json.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
@@ -28,6 +30,13 @@
|
||||
*/
|
||||
namespace util {
|
||||
|
||||
inline std::string
|
||||
toLower(std::string str)
|
||||
{
|
||||
std::transform(std::begin(str), std::end(str), std::begin(str), [](unsigned char c) { return std::tolower(c); });
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Removes any detected secret information from a response JSON object.
|
||||
*
|
||||
|
||||
@@ -66,12 +66,12 @@ public:
|
||||
* @brief Send via shared_ptr of string, that enables SubscriptionManager to publish to clients.
|
||||
*
|
||||
* @param msg The message to send
|
||||
* @throws Not supported unless implemented in child classes. Will always throw std::runtime_error.
|
||||
* @throws Not supported unless implemented in child classes. Will always throw std::logic_error.
|
||||
*/
|
||||
virtual void
|
||||
send(std::shared_ptr<std::string> msg)
|
||||
{
|
||||
throw std::runtime_error("web server can not send the shared payload");
|
||||
throw std::logic_error("web server can not send the shared payload");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,20 +53,11 @@ TEST_F(SettingsProviderTest, Defaults)
|
||||
EXPECT_EQ(settings.requestTimeout, std::chrono::milliseconds{0});
|
||||
EXPECT_EQ(settings.maxWriteRequestsOutstanding, 10'000);
|
||||
EXPECT_EQ(settings.maxReadRequestsOutstanding, 100'000);
|
||||
EXPECT_EQ(settings.maxConnectionsPerHost, 2);
|
||||
EXPECT_EQ(settings.coreConnectionsPerHost, 2);
|
||||
EXPECT_EQ(settings.maxConcurrentRequestsThreshold, (100'000 + 10'000) / 2);
|
||||
EXPECT_EQ(settings.coreConnectionsPerHost, 1);
|
||||
EXPECT_EQ(settings.certificate, std::nullopt);
|
||||
EXPECT_EQ(settings.username, std::nullopt);
|
||||
EXPECT_EQ(settings.password, std::nullopt);
|
||||
EXPECT_EQ(settings.queueSizeIO, std::nullopt);
|
||||
EXPECT_EQ(settings.queueSizeEvent, std::nullopt);
|
||||
EXPECT_EQ(settings.writeBytesHighWatermark, std::nullopt);
|
||||
EXPECT_EQ(settings.writeBytesLowWatermark, std::nullopt);
|
||||
EXPECT_EQ(settings.pendingRequestsHighWatermark, std::nullopt);
|
||||
EXPECT_EQ(settings.pendingRequestsLowWatermark, std::nullopt);
|
||||
EXPECT_EQ(settings.maxRequestsPerFlush, std::nullopt);
|
||||
EXPECT_EQ(settings.maxConcurrentCreation, std::nullopt);
|
||||
|
||||
auto const* cp = std::get_if<Settings::ContactPoints>(&settings.connectionInfo);
|
||||
ASSERT_TRUE(cp != nullptr);
|
||||
@@ -103,69 +94,16 @@ TEST_F(SettingsProviderTest, SimpleConfig)
|
||||
EXPECT_EQ(provider.getTablePrefix(), "prefix");
|
||||
}
|
||||
|
||||
TEST_F(SettingsProviderTest, DriverOptionCalculation)
|
||||
{
|
||||
Config cfg{json::parse(R"({
|
||||
"contact_points": "123.123.123.123",
|
||||
"max_write_requests_outstanding": 100,
|
||||
"max_read_requests_outstanding": 200
|
||||
})")};
|
||||
SettingsProvider provider{cfg};
|
||||
|
||||
auto const settings = provider.getSettings();
|
||||
EXPECT_EQ(settings.maxReadRequestsOutstanding, 200);
|
||||
EXPECT_EQ(settings.maxWriteRequestsOutstanding, 100);
|
||||
|
||||
EXPECT_EQ(settings.maxConnectionsPerHost, 2);
|
||||
EXPECT_EQ(settings.coreConnectionsPerHost, 2);
|
||||
EXPECT_EQ(settings.maxConcurrentRequestsThreshold, 150); // calculated from above
|
||||
}
|
||||
|
||||
TEST_F(SettingsProviderTest, DriverOptionSecifiedMaxConcurrentRequestsThreshold)
|
||||
{
|
||||
Config cfg{json::parse(R"({
|
||||
"contact_points": "123.123.123.123",
|
||||
"max_write_requests_outstanding": 100,
|
||||
"max_read_requests_outstanding": 200,
|
||||
"max_connections_per_host": 5,
|
||||
"core_connections_per_host": 4,
|
||||
"max_concurrent_requests_threshold": 1234
|
||||
})")};
|
||||
SettingsProvider provider{cfg};
|
||||
|
||||
auto const settings = provider.getSettings();
|
||||
EXPECT_EQ(settings.maxReadRequestsOutstanding, 200);
|
||||
EXPECT_EQ(settings.maxWriteRequestsOutstanding, 100);
|
||||
|
||||
EXPECT_EQ(settings.maxConnectionsPerHost, 5);
|
||||
EXPECT_EQ(settings.coreConnectionsPerHost, 4);
|
||||
EXPECT_EQ(settings.maxConcurrentRequestsThreshold, 1234);
|
||||
}
|
||||
|
||||
TEST_F(SettingsProviderTest, DriverOptionalOptionsSpecified)
|
||||
{
|
||||
Config cfg{json::parse(R"({
|
||||
"contact_points": "123.123.123.123",
|
||||
"queue_size_event": 1,
|
||||
"queue_size_io": 2,
|
||||
"write_bytes_high_water_mark": 3,
|
||||
"write_bytes_low_water_mark": 4,
|
||||
"pending_requests_high_water_mark": 5,
|
||||
"pending_requests_low_water_mark": 6,
|
||||
"max_requests_per_flush": 7,
|
||||
"max_concurrent_creation": 8
|
||||
"queue_size_io": 2
|
||||
})")};
|
||||
SettingsProvider provider{cfg};
|
||||
|
||||
auto const settings = provider.getSettings();
|
||||
EXPECT_EQ(settings.queueSizeEvent, 1);
|
||||
EXPECT_EQ(settings.queueSizeIO, 2);
|
||||
EXPECT_EQ(settings.writeBytesHighWatermark, 3);
|
||||
EXPECT_EQ(settings.writeBytesLowWatermark, 4);
|
||||
EXPECT_EQ(settings.pendingRequestsHighWatermark, 5);
|
||||
EXPECT_EQ(settings.pendingRequestsLowWatermark, 6);
|
||||
EXPECT_EQ(settings.maxRequestsPerFlush, 7);
|
||||
EXPECT_EQ(settings.maxConcurrentCreation, 8);
|
||||
}
|
||||
|
||||
TEST_F(SettingsProviderTest, SecureBundleConfig)
|
||||
|
||||
50
unittests/etl/AmendmentBlockHandlerTests.cpp
Normal file
50
unittests/etl/AmendmentBlockHandlerTests.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2023, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and 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 <util/FakeAmendmentBlockAction.h>
|
||||
#include <util/Fixtures.h>
|
||||
|
||||
#include <etl/impl/AmendmentBlock.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace testing;
|
||||
using namespace etl;
|
||||
|
||||
class AmendmentBlockHandlerTest : public NoLoggerFixture
|
||||
{
|
||||
protected:
|
||||
using AmendmentBlockHandlerType = detail::AmendmentBlockHandler<FakeAmendmentBlockAction>;
|
||||
|
||||
boost::asio::io_context ioc_;
|
||||
};
|
||||
|
||||
TEST_F(AmendmentBlockHandlerTest, CallToOnAmendmentBlockSetsStateAndRepeatedlyCallsAction)
|
||||
{
|
||||
std::size_t callCount = 0;
|
||||
SystemState state;
|
||||
AmendmentBlockHandlerType handler{ioc_, state, std::chrono::nanoseconds{1}, {std::ref(callCount)}};
|
||||
|
||||
EXPECT_FALSE(state.isAmendmentBlocked);
|
||||
handler.onAmendmentBlock();
|
||||
EXPECT_TRUE(state.isAmendmentBlocked);
|
||||
|
||||
ioc_.run_for(std::chrono::milliseconds{1});
|
||||
EXPECT_TRUE(callCount >= 10);
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <etl/impl/Transformer.h>
|
||||
#include <util/FakeFetchResponse.h>
|
||||
#include <util/Fixtures.h>
|
||||
#include <util/MockAmendmentBlockHandler.h>
|
||||
#include <util/MockExtractionDataPipe.h>
|
||||
#include <util/MockLedgerLoader.h>
|
||||
#include <util/MockLedgerPublisher.h>
|
||||
@@ -47,11 +48,14 @@ protected:
|
||||
using ExtractionDataPipeType = MockExtractionDataPipe;
|
||||
using LedgerLoaderType = MockLedgerLoader;
|
||||
using LedgerPublisherType = MockLedgerPublisher;
|
||||
using TransformerType = etl::detail::Transformer<ExtractionDataPipeType, LedgerLoaderType, LedgerPublisherType>;
|
||||
using AmendmentBlockHandlerType = MockAmendmentBlockHandler;
|
||||
using TransformerType = etl::detail::
|
||||
Transformer<ExtractionDataPipeType, LedgerLoaderType, LedgerPublisherType, AmendmentBlockHandlerType>;
|
||||
|
||||
ExtractionDataPipeType dataPipe_;
|
||||
LedgerLoaderType ledgerLoader_;
|
||||
LedgerPublisherType ledgerPublisher_;
|
||||
AmendmentBlockHandlerType amendmentBlockHandler_;
|
||||
SystemState state_;
|
||||
|
||||
std::unique_ptr<TransformerType> transformer_;
|
||||
@@ -82,8 +86,8 @@ TEST_F(ETLTransformerTest, StopsOnWriteConflict)
|
||||
EXPECT_CALL(dataPipe_, popNext).Times(0);
|
||||
EXPECT_CALL(ledgerPublisher_, publish(_)).Times(0);
|
||||
|
||||
transformer_ =
|
||||
std::make_unique<TransformerType>(dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, 0, state_);
|
||||
transformer_ = std::make_unique<TransformerType>(
|
||||
dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_);
|
||||
|
||||
transformer_->waitTillFinished(); // explicitly joins the thread
|
||||
}
|
||||
@@ -114,8 +118,8 @@ TEST_F(ETLTransformerTest, StopsOnEmptyFetchResponse)
|
||||
EXPECT_CALL(*rawBackendPtr, doFinishWrites).Times(AtLeast(1));
|
||||
EXPECT_CALL(ledgerPublisher_, publish(_)).Times(AtLeast(1));
|
||||
|
||||
transformer_ =
|
||||
std::make_unique<TransformerType>(dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, 0, state_);
|
||||
transformer_ = std::make_unique<TransformerType>(
|
||||
dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_);
|
||||
|
||||
// after 10ms we start spitting out empty responses which means the extractor is finishing up
|
||||
// this is normally combined with stopping the entire thing by setting the isStopping flag.
|
||||
@@ -147,6 +151,8 @@ TEST_F(ETLTransformerTest, DoesNotPublishIfCanNotBuildNextLedger)
|
||||
// should not call publish
|
||||
EXPECT_CALL(ledgerPublisher_, publish(_)).Times(0);
|
||||
|
||||
transformer_ =
|
||||
std::make_unique<TransformerType>(dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, 0, state_);
|
||||
transformer_ = std::make_unique<TransformerType>(
|
||||
dataPipe_, mockBackendPtr, ledgerLoader_, ledgerPublisher_, amendmentBlockHandler_, 0, state_);
|
||||
}
|
||||
|
||||
// TODO: implement tests for amendment block. requires more refactoring
|
||||
|
||||
@@ -568,3 +568,25 @@ TEST_F(RPCBaseTest, ClampingModifier)
|
||||
ASSERT_TRUE(spec.process(passingInput3));
|
||||
ASSERT_EQ(passingInput3.at("amount").as_uint64(), 20u); // clamped
|
||||
}
|
||||
|
||||
TEST_F(RPCBaseTest, ToLowerModifier)
|
||||
{
|
||||
auto spec = RpcSpec{
|
||||
{"str", ToLower{}},
|
||||
};
|
||||
|
||||
auto passingInput = json::parse(R"({ "str": "TesT" })");
|
||||
ASSERT_TRUE(spec.process(passingInput));
|
||||
ASSERT_EQ(passingInput.at("str").as_string(), "test");
|
||||
|
||||
auto passingInput2 = json::parse(R"({ "str2": "TesT" })");
|
||||
ASSERT_TRUE(spec.process(passingInput2)); // no str no problem
|
||||
|
||||
auto passingInput3 = json::parse(R"({ "str": "already lower case" })");
|
||||
ASSERT_TRUE(spec.process(passingInput3));
|
||||
ASSERT_EQ(passingInput3.at("str").as_string(), "already lower case");
|
||||
|
||||
auto passingInput4 = json::parse(R"({ "str": "" })");
|
||||
ASSERT_TRUE(spec.process(passingInput4)); // empty str no problem
|
||||
ASSERT_EQ(passingInput4.at("str").as_string(), "");
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
using namespace rpc;
|
||||
using namespace testing;
|
||||
namespace json = boost::json;
|
||||
|
||||
constexpr static auto CLIENT_IP = "127.0.0.1";
|
||||
|
||||
@@ -54,7 +55,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfClioOnly)
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "test";
|
||||
auto const params = boost::json::parse("{}");
|
||||
auto const params = json::parse("{}");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(true));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -74,7 +75,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfProxied)
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "submit";
|
||||
auto const params = boost::json::parse("{}");
|
||||
auto const params = json::parse("{}");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -94,7 +95,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfCurrentLedgerSpecified)
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "anymethod";
|
||||
auto const params = boost::json::parse(R"({"ledger_index": "current"})");
|
||||
auto const params = json::parse(R"({"ledger_index": "current"})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -114,7 +115,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfClosedLedgerSpecified)
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "anymethod";
|
||||
auto const params = boost::json::parse(R"({"ledger_index": "closed"})");
|
||||
auto const params = json::parse(R"({"ledger_index": "closed"})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -134,7 +135,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfAccountInfoWithQueueSpe
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "account_info";
|
||||
auto const params = boost::json::parse(R"({"queue": true})");
|
||||
auto const params = json::parse(R"({"queue": true})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -154,7 +155,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfLedgerWithQueueSpecifie
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "ledger";
|
||||
auto const params = boost::json::parse(R"({"queue": true})");
|
||||
auto const params = json::parse(R"({"queue": true})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -174,7 +175,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfLedgerWithFullSpecified
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "ledger";
|
||||
auto const params = boost::json::parse(R"({"full": true})");
|
||||
auto const params = json::parse(R"({"full": true})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -194,7 +195,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfLedgerWithAccountsSpeci
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "ledger";
|
||||
auto const params = boost::json::parse(R"({"accounts": true})");
|
||||
auto const params = json::parse(R"({"accounts": true})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -214,7 +215,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfAccountInfoQueueIsFals
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "account_info";
|
||||
auto const params = boost::json::parse(R"({"queue": false})");
|
||||
auto const params = json::parse(R"({"queue": false})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -234,7 +235,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfLedgerQueueIsFalse)
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "ledger";
|
||||
auto const params = boost::json::parse(R"({"queue": false})");
|
||||
auto const params = json::parse(R"({"queue": false})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -254,7 +255,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfLedgerFullIsFalse)
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "ledger";
|
||||
auto const params = boost::json::parse(R"({"full": false})");
|
||||
auto const params = json::parse(R"({"full": false})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -274,7 +275,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfLedgerAccountsIsFalse)
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "ledger";
|
||||
auto const params = boost::json::parse(R"({"accounts": false})");
|
||||
auto const params = json::parse(R"({"accounts": false})");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -293,7 +294,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsTrueIfAPIVersionIsV1)
|
||||
{
|
||||
auto const apiVersion = 1u;
|
||||
auto const method = "api_version_check";
|
||||
auto const params = boost::json::parse("{}");
|
||||
auto const params = json::parse("{}");
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = mockBackendPtr->fetchLedgerRange();
|
||||
@@ -310,7 +311,7 @@ TEST_F(RPCForwardingProxyTest, ShouldForwardReturnsFalseIfAPIVersionIsV2)
|
||||
auto const rawHandlerProviderPtr = static_cast<MockHandlerProvider*>(handlerProvider.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "api_version_check";
|
||||
auto const params = boost::json::parse("{}");
|
||||
auto const params = json::parse("{}");
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, isClioOnly(_)).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawHandlerProviderPtr, isClioOnly(method)).Times(1);
|
||||
@@ -329,7 +330,7 @@ TEST_F(RPCForwardingProxyTest, ShouldNeverForwardSubscribe)
|
||||
{
|
||||
auto const apiVersion = 1u;
|
||||
auto const method = "subscribe";
|
||||
auto const params = boost::json::parse("{}");
|
||||
auto const params = json::parse("{}");
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = mockBackendPtr->fetchLedgerRange();
|
||||
@@ -345,7 +346,7 @@ TEST_F(RPCForwardingProxyTest, ShouldNeverForwardUnsubscribe)
|
||||
{
|
||||
auto const apiVersion = 1u;
|
||||
auto const method = "unsubscribe";
|
||||
auto const params = boost::json::parse("{}");
|
||||
auto const params = json::parse("{}");
|
||||
|
||||
runSpawn([&](auto yield) {
|
||||
auto const range = mockBackendPtr->fetchLedgerRange();
|
||||
@@ -363,10 +364,10 @@ TEST_F(RPCForwardingProxyTest, ForwardCallsBalancerWithCorrectParams)
|
||||
auto const rawBalancerPtr = static_cast<MockLoadBalancer*>(loadBalancer.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "submit";
|
||||
auto const params = boost::json::parse(R"({"test": true})");
|
||||
auto const forwarded = boost::json::parse(R"({"test": true, "command": "submit"})");
|
||||
auto const params = json::parse(R"({"test": true})");
|
||||
auto const forwarded = json::parse(R"({"test": true, "command": "submit"})");
|
||||
|
||||
ON_CALL(*rawBalancerPtr, forwardToRippled).WillByDefault(Return(std::make_optional<boost::json::object>()));
|
||||
ON_CALL(*rawBalancerPtr, forwardToRippled).WillByDefault(Return(std::make_optional<json::object>()));
|
||||
EXPECT_CALL(*rawBalancerPtr, forwardToRippled(forwarded.as_object(), CLIENT_IP, _)).Times(1);
|
||||
|
||||
ON_CALL(*rawHandlerProviderPtr, contains).WillByDefault(Return(true));
|
||||
@@ -382,7 +383,7 @@ TEST_F(RPCForwardingProxyTest, ForwardCallsBalancerWithCorrectParams)
|
||||
|
||||
auto const res = proxy.forward(ctx);
|
||||
|
||||
auto const data = std::get_if<boost::json::object>(&res);
|
||||
auto const data = std::get_if<json::object>(&res);
|
||||
EXPECT_TRUE(data != nullptr);
|
||||
});
|
||||
}
|
||||
@@ -393,8 +394,8 @@ TEST_F(RPCForwardingProxyTest, ForwardingFailYieldsErrorStatus)
|
||||
auto const rawBalancerPtr = static_cast<MockLoadBalancer*>(loadBalancer.get());
|
||||
auto const apiVersion = 2u;
|
||||
auto const method = "submit";
|
||||
auto const params = boost::json::parse(R"({"test": true})");
|
||||
auto const forwarded = boost::json::parse(R"({"test": true, "command": "submit"})");
|
||||
auto const params = json::parse(R"({"test": true})");
|
||||
auto const forwarded = json::parse(R"({"test": true, "command": "submit"})");
|
||||
|
||||
ON_CALL(*rawBalancerPtr, forwardToRippled).WillByDefault(Return(std::nullopt));
|
||||
EXPECT_CALL(*rawBalancerPtr, forwardToRippled(forwarded.as_object(), CLIENT_IP, _)).Times(1);
|
||||
|
||||
@@ -52,7 +52,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, AccountNotExist)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional<Blob>{}));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}"
|
||||
}})",
|
||||
@@ -76,7 +76,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaIntSequence)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}"
|
||||
}})",
|
||||
@@ -101,7 +101,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaStringSequence)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(12, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":"{}"
|
||||
@@ -128,7 +128,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, LedgerNonExistViaHash)
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
|
||||
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_hash":"{}"
|
||||
@@ -197,7 +197,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, DefaultParameter)
|
||||
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}"
|
||||
}})",
|
||||
@@ -235,7 +235,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, RequestViaLegderHash)
|
||||
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_hash":"{}"
|
||||
@@ -276,7 +276,7 @@ TEST_F(RPCAccountCurrenciesHandlerTest, RequestViaLegderSeq)
|
||||
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":{}
|
||||
|
||||
@@ -125,7 +125,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaIntSequence)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"ledger_index": 30
|
||||
@@ -150,7 +150,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaStringSequence)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::nullopt));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"ledger_index": "30"
|
||||
@@ -176,7 +176,7 @@ TEST_F(RPCAccountInfoHandlerTest, LedgerNonExistViaHash)
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
|
||||
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"ledger_hash": "{}"
|
||||
@@ -205,7 +205,7 @@ TEST_F(RPCAccountInfoHandlerTest, AccountNotExist)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional<Blob>{}));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}"
|
||||
}})",
|
||||
@@ -233,7 +233,7 @@ TEST_F(RPCAccountInfoHandlerTest, AccountInvalid)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(CreateFeeSettingBlob(1, 2, 3, 4, 0)));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}"
|
||||
}})",
|
||||
@@ -269,7 +269,7 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsInvalid)
|
||||
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(4);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"signer_lists": true
|
||||
@@ -370,7 +370,7 @@ TEST_F(RPCAccountInfoHandlerTest, SignerListsTrue)
|
||||
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(4);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"signer_lists": true
|
||||
@@ -443,7 +443,7 @@ TEST_F(RPCAccountInfoHandlerTest, Flags)
|
||||
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}"
|
||||
}})",
|
||||
@@ -474,7 +474,7 @@ TEST_F(RPCAccountInfoHandlerTest, IdentAndSignerListsFalse)
|
||||
.WillByDefault(Return(CreateAmendmentsObject({}).getSerializer().peekData()));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"ident": "{}"
|
||||
}})",
|
||||
@@ -551,7 +551,7 @@ TEST_F(RPCAccountInfoHandlerTest, DisallowIncoming)
|
||||
.WillByDefault(Return(CreateAmendmentsObject({rpc::Amendments::DisallowIncoming}).getSerializer().peekData()));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}"
|
||||
}})",
|
||||
@@ -624,7 +624,7 @@ TEST_F(RPCAccountInfoHandlerTest, Clawback)
|
||||
.WillByDefault(Return(CreateAmendmentsObject({rpc::Amendments::Clawback}).getSerializer().peekData()));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(3);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}"
|
||||
}})",
|
||||
|
||||
@@ -171,7 +171,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaHash)
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
|
||||
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_hash":"{}"
|
||||
@@ -198,7 +198,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaStringIndex)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":"{}"
|
||||
@@ -225,7 +225,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LedgerNotFoundViaIntIndex)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":{}
|
||||
@@ -254,7 +254,7 @@ TEST_F(RPCAccountNFTsHandlerTest, AccountNotFound)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional<Blob>{}));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}"
|
||||
}})",
|
||||
@@ -316,7 +316,7 @@ TEST_F(RPCAccountNFTsHandlerTest, NormalPath)
|
||||
.WillByDefault(Return(pageObject.getSerializer().peekData()));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}"
|
||||
}})",
|
||||
@@ -351,7 +351,7 @@ TEST_F(RPCAccountNFTsHandlerTest, Limit)
|
||||
.WillByDefault(Return(pageObject.getSerializer().peekData()));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1 + limit);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit":{}
|
||||
@@ -387,7 +387,7 @@ TEST_F(RPCAccountNFTsHandlerTest, Marker)
|
||||
.WillByDefault(Return(pageObject.getSerializer().peekData()));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"marker":"{}"
|
||||
@@ -450,7 +450,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LimitLessThanMin)
|
||||
.WillByDefault(Return(pageObject.getSerializer().peekData()));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit":{}
|
||||
@@ -513,7 +513,7 @@ TEST_F(RPCAccountNFTsHandlerTest, LimitMoreThanMax)
|
||||
.WillByDefault(Return(pageObject.getSerializer().peekData()));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit":{}
|
||||
|
||||
@@ -176,7 +176,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaIntSequence)
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _))
|
||||
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":30
|
||||
@@ -201,7 +201,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaStringSequence)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(std::nullopt));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":"30"
|
||||
@@ -227,7 +227,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LedgerNonExistViaHash)
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
|
||||
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_hash":"{}"
|
||||
@@ -256,7 +256,7 @@ TEST_F(RPCAccountObjectsHandlerTest, AccountNotExist)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional<Blob>{}));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}"
|
||||
}})",
|
||||
@@ -334,7 +334,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DefaultParameterNoNFTFound)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}"
|
||||
}})",
|
||||
@@ -385,7 +385,7 @@ TEST_F(RPCAccountObjectsHandlerTest, Limit)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit":{}
|
||||
@@ -434,7 +434,7 @@ TEST_F(RPCAccountObjectsHandlerTest, Marker)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"marker":"{},{}"
|
||||
@@ -496,7 +496,7 @@ TEST_F(RPCAccountObjectsHandlerTest, MultipleDirNoNFT)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit":{}
|
||||
@@ -555,7 +555,7 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilter)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"type":"offer"
|
||||
@@ -611,7 +611,7 @@ TEST_F(RPCAccountObjectsHandlerTest, TypeFilterReturnEmpty)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"type": "check"
|
||||
@@ -674,7 +674,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilter)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"deletion_blockers_only": true
|
||||
@@ -725,7 +725,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterWithTypeFilter)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"deletion_blockers_only": true,
|
||||
@@ -793,7 +793,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterEmptyResult)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"deletion_blockers_only": true
|
||||
@@ -858,7 +858,7 @@ TEST_F(RPCAccountObjectsHandlerTest, DeletionBlockersOnlyFilterWithIncompatibleT
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"deletion_blockers_only": true,
|
||||
@@ -978,7 +978,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMixOtherObjects)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}"
|
||||
}})",
|
||||
@@ -1022,7 +1022,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitReturnMarker)
|
||||
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(11);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit":{}
|
||||
@@ -1075,7 +1075,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTReachLimitNoMarker)
|
||||
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(12);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit":{}
|
||||
@@ -1157,7 +1157,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarker)
|
||||
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(13);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"marker":"{},{}"
|
||||
@@ -1218,7 +1218,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNoMoreNFT)
|
||||
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"marker":"{},{}"
|
||||
@@ -1250,7 +1250,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNotInRange)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountKk, MAXSEQ, _)).WillByDefault(Return(Blob{'f', 'a', 'k', 'e'}));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"marker" : "{},{}"
|
||||
@@ -1287,7 +1287,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTMarkerNotExist)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObject(accountNftMax, MAXSEQ, _)).WillByDefault(Return(std::nullopt));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"marker" : "{},{}"
|
||||
@@ -1367,7 +1367,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTLimitAdjust)
|
||||
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(13);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"marker":"{},{}",
|
||||
@@ -1469,7 +1469,7 @@ TEST_F(RPCAccountObjectsHandlerTest, FilterNFT)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"type": "nft_page"
|
||||
@@ -1517,7 +1517,7 @@ TEST_F(RPCAccountObjectsHandlerTest, NFTZeroMarkerNotAffectOtherMarker)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit":{},
|
||||
@@ -1602,7 +1602,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LimitLessThanMin)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit": {}
|
||||
@@ -1683,7 +1683,7 @@ TEST_F(RPCAccountObjectsHandlerTest, LimitMoreThanMax)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit": {}
|
||||
|
||||
@@ -164,7 +164,7 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaHash)
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
|
||||
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_hash":"{}"
|
||||
@@ -191,7 +191,7 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaStringIndex)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":"{}"
|
||||
@@ -218,7 +218,7 @@ TEST_F(RPCAccountOffersHandlerTest, LedgerNotFoundViaIntIndex)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":{}
|
||||
@@ -247,7 +247,7 @@ TEST_F(RPCAccountOffersHandlerTest, AccountNotFound)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObject).WillByDefault(Return(std::optional<Blob>{}));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}"
|
||||
}})",
|
||||
@@ -324,7 +324,7 @@ TEST_F(RPCAccountOffersHandlerTest, DefaultParams)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}"
|
||||
}})",
|
||||
@@ -374,7 +374,7 @@ TEST_F(RPCAccountOffersHandlerTest, Limit)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit":10
|
||||
@@ -429,7 +429,7 @@ TEST_F(RPCAccountOffersHandlerTest, Marker)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"marker":"{},{}"
|
||||
@@ -467,7 +467,7 @@ TEST_F(RPCAccountOffersHandlerTest, MarkerNotExists)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObject(hintIndex, ledgerSeq, _)).WillByDefault(Return(std::nullopt));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObject).Times(2);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"marker":"{},{}"
|
||||
@@ -524,7 +524,7 @@ TEST_F(RPCAccountOffersHandlerTest, LimitLessThanMin)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit":{}
|
||||
@@ -578,7 +578,7 @@ TEST_F(RPCAccountOffersHandlerTest, LimitMoreThanMax)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"limit":{}
|
||||
|
||||
@@ -309,9 +309,9 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardTrue)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"account": "{}",
|
||||
"ledger_index_min": {},
|
||||
"ledger_index_max": {},
|
||||
"forward": true
|
||||
@@ -324,7 +324,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardTrue)
|
||||
EXPECT_EQ(output->at("account").as_string(), ACCOUNT);
|
||||
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ + 1);
|
||||
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ - 1);
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
|
||||
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
|
||||
EXPECT_FALSE(output->as_object().contains("limit"));
|
||||
});
|
||||
@@ -350,9 +350,9 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardFalse)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"account": "{}",
|
||||
"ledger_index_min": {},
|
||||
"ledger_index_max": {},
|
||||
"forward": false
|
||||
@@ -365,7 +365,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexSpecificForwardFalse)
|
||||
EXPECT_EQ(output->at("account").as_string(), ACCOUNT);
|
||||
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ + 1);
|
||||
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ - 1);
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
|
||||
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
|
||||
EXPECT_FALSE(output->as_object().contains("limit"));
|
||||
});
|
||||
@@ -391,9 +391,9 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardTrue)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"account": "{}",
|
||||
"ledger_index_min": {},
|
||||
"ledger_index_max": {},
|
||||
"forward": true
|
||||
@@ -406,7 +406,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardTrue)
|
||||
EXPECT_EQ(output->at("account").as_string(), ACCOUNT);
|
||||
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ);
|
||||
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ);
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
|
||||
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
|
||||
EXPECT_FALSE(output->as_object().contains("limit"));
|
||||
});
|
||||
@@ -432,9 +432,9 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardFalse)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"account": "{}",
|
||||
"ledger_index_min": {},
|
||||
"ledger_index_max": {},
|
||||
"forward": false
|
||||
@@ -447,7 +447,7 @@ TEST_F(RPCAccountTxHandlerTest, IndexNotSpecificForwardFalse)
|
||||
EXPECT_EQ(output->at("account").as_string(), ACCOUNT);
|
||||
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ);
|
||||
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ);
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
|
||||
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
|
||||
EXPECT_FALSE(output->as_object().contains("limit"));
|
||||
});
|
||||
@@ -473,9 +473,9 @@ TEST_F(RPCAccountTxHandlerTest, BinaryTrue)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"account": "{}",
|
||||
"ledger_index_min": {},
|
||||
"ledger_index_max": {},
|
||||
"binary": true
|
||||
@@ -488,7 +488,7 @@ TEST_F(RPCAccountTxHandlerTest, BinaryTrue)
|
||||
EXPECT_EQ(output->at("account").as_string(), ACCOUNT);
|
||||
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ);
|
||||
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ);
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
|
||||
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
|
||||
EXPECT_EQ(
|
||||
output->at("transactions").as_array()[0].as_object().at("meta").as_string(),
|
||||
@@ -522,9 +522,9 @@ TEST_F(RPCAccountTxHandlerTest, LimitAndMarker)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"account": "{}",
|
||||
"ledger_index_min": {},
|
||||
"ledger_index_max": {},
|
||||
"limit": 2,
|
||||
@@ -540,7 +540,7 @@ TEST_F(RPCAccountTxHandlerTest, LimitAndMarker)
|
||||
EXPECT_EQ(output->at("ledger_index_min").as_uint64(), MINSEQ);
|
||||
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ);
|
||||
EXPECT_EQ(output->at("limit").as_uint64(), 2);
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
|
||||
EXPECT_EQ(output->at("transactions").as_array().size(), 2);
|
||||
});
|
||||
}
|
||||
@@ -570,10 +570,10 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerIndex)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":{}
|
||||
"account": "{}",
|
||||
"ledger_index": {}
|
||||
}})",
|
||||
ACCOUNT,
|
||||
MAXSEQ - 1));
|
||||
@@ -599,10 +599,10 @@ TEST_F(RPCAccountTxHandlerTest, SpecificNonexistLedgerIntIndex)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":{}
|
||||
"account": "{}",
|
||||
"ledger_index": {}
|
||||
}})",
|
||||
ACCOUNT,
|
||||
MAXSEQ - 1));
|
||||
@@ -625,10 +625,10 @@ TEST_F(RPCAccountTxHandlerTest, SpecificNonexistLedgerStringIndex)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":"{}"
|
||||
"account": "{}",
|
||||
"ledger_index": "{}"
|
||||
}})",
|
||||
ACCOUNT,
|
||||
MAXSEQ - 1));
|
||||
@@ -665,10 +665,10 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerHash)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_hash":"{}"
|
||||
"account": "{}",
|
||||
"ledger_hash": "{}"
|
||||
}})",
|
||||
ACCOUNT,
|
||||
LEDGERHASH));
|
||||
@@ -708,10 +708,10 @@ TEST_F(RPCAccountTxHandlerTest, SpecificLedgerIndexValidated)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"ledger_index":"validated"
|
||||
"account": "{}",
|
||||
"ledger_index": "validated"
|
||||
}})",
|
||||
ACCOUNT));
|
||||
auto const output = handler.process(input, Context{yield});
|
||||
@@ -745,9 +745,9 @@ TEST_F(RPCAccountTxHandlerTest, TxLessThanMinSeq)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"account": "{}",
|
||||
"ledger_index_min": {},
|
||||
"ledger_index_max": {},
|
||||
"forward": false
|
||||
@@ -786,9 +786,9 @@ TEST_F(RPCAccountTxHandlerTest, TxLargerThanMaxSeq)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account":"{}",
|
||||
"account": "{}",
|
||||
"ledger_index_min": {},
|
||||
"ledger_index_max": {},
|
||||
"forward": false
|
||||
@@ -803,7 +803,7 @@ TEST_F(RPCAccountTxHandlerTest, TxLargerThanMaxSeq)
|
||||
EXPECT_EQ(output->at("ledger_index_max").as_uint64(), MAXSEQ - 2);
|
||||
EXPECT_EQ(output->at("transactions").as_array().size(), 1);
|
||||
EXPECT_FALSE(output->as_object().contains("limit"));
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger":12,"seq":34})"));
|
||||
EXPECT_EQ(output->at("marker").as_object(), json::parse(R"({"ledger": 12, "seq": 34})"));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -909,8 +909,8 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs)
|
||||
"date": 2
|
||||
},
|
||||
"validated": true
|
||||
},
|
||||
{
|
||||
},
|
||||
{
|
||||
"meta":
|
||||
{
|
||||
"AffectedNodes":
|
||||
@@ -1015,7 +1015,7 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"ledger_index_min": {},
|
||||
@@ -1028,6 +1028,312 @@ TEST_F(RPCAccountTxHandlerTest, NFTTxs)
|
||||
-1));
|
||||
auto const output = handler.process(input, Context{yield});
|
||||
ASSERT_TRUE(output);
|
||||
EXPECT_EQ(*output, boost::json::parse(OUT));
|
||||
EXPECT_EQ(*output, json::parse(OUT));
|
||||
});
|
||||
}
|
||||
|
||||
struct AccountTxTransactionBundle
|
||||
{
|
||||
std::string testName;
|
||||
std::string testJson;
|
||||
std::string result;
|
||||
};
|
||||
|
||||
// parameterized test cases for parameters check
|
||||
struct AccountTxTransactionTypeTest : public RPCAccountTxHandlerTest,
|
||||
public WithParamInterface<AccountTxTransactionBundle>
|
||||
{
|
||||
struct NameGenerator
|
||||
{
|
||||
template <class ParamType>
|
||||
std::string
|
||||
operator()(const testing::TestParamInfo<ParamType>& info) const
|
||||
{
|
||||
auto bundle = static_cast<AccountTxTransactionBundle>(info.param);
|
||||
return bundle.testName;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
static auto
|
||||
generateTransactionTypeTestValues()
|
||||
{
|
||||
return std::vector<AccountTxTransactionBundle>{
|
||||
AccountTxTransactionBundle{
|
||||
"AccountSet",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "AccountSet"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"AccountDelete",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "AccountDelete"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"CheckCancel",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "CheckCancel"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"CheckCash",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "CheckCash"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"CheckCreate",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "CheckCreate"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"Clawback",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "Clawback"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"DepositPreauth",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "DepositPreauth"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"EscrowCancel",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "EscrowCancel"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"EscrowCreate",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "EscrowCreate"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"EscrowFinish",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "EscrowFinish"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"NFTokenAcceptOffer",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "NFTokenAcceptOffer"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"NFTokenBurn",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "NFTokenBurn"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"NFTokenCancelOffer",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "NFTokenCancelOffer"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"NFTokenCreateOffer",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "NFTokenCreateOffer"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"NFTokenMint",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "NFTokenMint"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"OfferCancel",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "OfferCancel"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"OfferCreate",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "OfferCreate"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"Payment",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "Payment"
|
||||
})",
|
||||
R"([
|
||||
{
|
||||
"meta": {
|
||||
"AffectedNodes": [
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Balance": "22"
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ModifiedNode": {
|
||||
"FinalFields": {
|
||||
"Account": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"Balance": "23"
|
||||
},
|
||||
"LedgerEntryType": "AccountRoot"
|
||||
}
|
||||
}],
|
||||
"TransactionIndex": 0,
|
||||
"TransactionResult": "tesSUCCESS",
|
||||
"delivered_amount": "unavailable"
|
||||
},
|
||||
"tx": {
|
||||
"Account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"Amount": "1",
|
||||
"Destination": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
|
||||
"Fee": "1",
|
||||
"Sequence": 32,
|
||||
"SigningPubKey": "74657374",
|
||||
"TransactionType": "Payment",
|
||||
"hash": "51D2AAA6B8E4E16EF22F6424854283D8391B56875858A711B8CE4D5B9A422CC2",
|
||||
"ledger_index": 30,
|
||||
"date": 1
|
||||
},
|
||||
"validated": true
|
||||
}
|
||||
])"},
|
||||
AccountTxTransactionBundle{
|
||||
"PaymentChannelClaim",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "PaymentChannelClaim"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"PaymentChannelCreate",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "PaymentChannelCreate"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"PaymentChannelFund",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "PaymentChannelFund"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"SetRegularKey",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "SetRegularKey"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"SignerListSet",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "SignerListSet"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"TicketCreate",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "TicketCreate"
|
||||
})",
|
||||
"[]"},
|
||||
AccountTxTransactionBundle{
|
||||
"TrustSet",
|
||||
R"({
|
||||
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
|
||||
"ledger_index": "validated",
|
||||
"tx_type": "TrustSet"
|
||||
})",
|
||||
"[]"},
|
||||
};
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
RPCAccountTxTransactionTypeTest,
|
||||
AccountTxTransactionTypeTest,
|
||||
ValuesIn(generateTransactionTypeTestValues()),
|
||||
AccountTxTransactionTypeTest::NameGenerator{});
|
||||
|
||||
TEST_P(AccountTxTransactionTypeTest, SpecificTransactionType)
|
||||
{
|
||||
mockBackendPtr->updateRange(MINSEQ); // min
|
||||
mockBackendPtr->updateRange(MAXSEQ); // max
|
||||
MockBackend* rawBackendPtr = static_cast<MockBackend*>(mockBackendPtr.get());
|
||||
|
||||
auto const transactions = genTransactions(MAXSEQ, MAXSEQ - 1);
|
||||
auto const transCursor = TransactionsAndCursor{transactions, TransactionsCursor{12, 34}};
|
||||
ON_CALL(*rawBackendPtr, fetchAccountTransactions).WillByDefault(Return(transCursor));
|
||||
EXPECT_CALL(
|
||||
*rawBackendPtr, fetchAccountTransactions(_, _, false, Optional(Eq(TransactionsCursor{MAXSEQ, INT32_MAX})), _))
|
||||
.Times(1);
|
||||
|
||||
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, MAXSEQ);
|
||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1);
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(ledgerinfo));
|
||||
|
||||
auto const testBundle = GetParam();
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{AccountTxHandler{mockBackendPtr}};
|
||||
auto const req = json::parse(testBundle.testJson);
|
||||
auto const output = handler.process(req, Context{yield});
|
||||
EXPECT_TRUE(output);
|
||||
|
||||
auto const transactions = output->at("transactions").as_array();
|
||||
auto const jsonObject = json::parse(testBundle.result);
|
||||
EXPECT_EQ(jsonObject, transactions);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaIntSequence)
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _))
|
||||
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(R"({"ledger_index":30})");
|
||||
auto const static input = json::parse(R"({"ledger_index":30})");
|
||||
auto const handler = AnyHandler{BookChangesHandler{mockBackendPtr}};
|
||||
runSpawn([&](auto yield) {
|
||||
auto const output = handler.process(input, Context{yield});
|
||||
@@ -127,7 +127,7 @@ TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaStringSequence)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(MAXSEQ, _)).WillByDefault(Return(std::nullopt));
|
||||
|
||||
auto const static input = boost::json::parse(R"({"ledger_index":"30"})");
|
||||
auto const static input = json::parse(R"({"ledger_index":"30"})");
|
||||
auto const handler = AnyHandler{BookChangesHandler{mockBackendPtr}};
|
||||
runSpawn([&](auto yield) {
|
||||
auto const output = handler.process(input, Context{yield});
|
||||
@@ -148,7 +148,7 @@ TEST_F(RPCBookChangesHandlerTest, LedgerNonExistViaHash)
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
|
||||
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"ledger_hash":"{}"
|
||||
}})",
|
||||
|
||||
@@ -1107,7 +1107,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaIntSequence)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"ledger_index": 30,
|
||||
"taker_gets":
|
||||
@@ -1140,7 +1140,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaSequence)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(30, _)).WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"ledger_index": "30",
|
||||
"taker_gets":
|
||||
@@ -1174,7 +1174,7 @@ TEST_F(RPCBookOffersHandlerTest, LedgerNonExistViaHash)
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _))
|
||||
.WillByDefault(Return(std::optional<ripple::LedgerInfo>{}));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"ledger_hash": "{}",
|
||||
"taker_gets":
|
||||
@@ -1248,7 +1248,7 @@ TEST_F(RPCBookOffersHandlerTest, Limit)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"taker_gets":
|
||||
{{
|
||||
@@ -1319,7 +1319,7 @@ TEST_F(RPCBookOffersHandlerTest, LimitMoreThanMax)
|
||||
ON_CALL(*rawBackendPtr, doFetchLedgerObjects).WillByDefault(Return(bbs));
|
||||
EXPECT_CALL(*rawBackendPtr, doFetchLedgerObjects).Times(1);
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"taker_gets":
|
||||
{{
|
||||
|
||||
@@ -268,7 +268,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardTrue)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index_min": {},
|
||||
@@ -309,7 +309,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexSpecificForwardFalse)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index_min": {},
|
||||
@@ -346,7 +346,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexNotSpecificForwardTrue)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index_min": {},
|
||||
@@ -387,7 +387,7 @@ TEST_F(RPCNFTHistoryHandlerTest, IndexNotSpecificForwardFalse)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index_min": {},
|
||||
@@ -428,7 +428,7 @@ TEST_F(RPCNFTHistoryHandlerTest, BinaryTrue)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index_min": {},
|
||||
@@ -477,7 +477,7 @@ TEST_F(RPCNFTHistoryHandlerTest, LimitAndMarker)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index_min": {},
|
||||
@@ -525,7 +525,7 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificLedgerIndex)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index":{}
|
||||
@@ -554,7 +554,7 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificNonexistLedgerIntIndex)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index":{}
|
||||
@@ -580,7 +580,7 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificNonexistLedgerStringIndex)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index":"{}"
|
||||
@@ -620,7 +620,7 @@ TEST_F(RPCNFTHistoryHandlerTest, SpecificLedgerHash)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_hash":"{}"
|
||||
@@ -658,7 +658,7 @@ TEST_F(RPCNFTHistoryHandlerTest, TxLessThanMinSeq)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index_min": {},
|
||||
@@ -699,7 +699,7 @@ TEST_F(RPCNFTHistoryHandlerTest, TxLargerThanMaxSeq)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index_min": {},
|
||||
@@ -740,7 +740,7 @@ TEST_F(RPCNFTHistoryHandlerTest, LimitMoreThanMax)
|
||||
|
||||
runSpawn([&, this](auto yield) {
|
||||
auto const handler = AnyHandler{NFTHistoryHandler{mockBackendPtr}};
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"nft_id":"{}",
|
||||
"ledger_index_min": {},
|
||||
|
||||
@@ -174,7 +174,7 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaHash)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerByHash(ripple::uint256{LEDGERHASH}, _)).WillByDefault(Return(std::nullopt));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"role": "gateway",
|
||||
@@ -202,7 +202,7 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaIntIndex)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::nullopt));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"role": "gateway",
|
||||
@@ -230,7 +230,7 @@ TEST_F(RPCNoRippleCheckTest, LedgerNotExistViaStringIndex)
|
||||
// return empty ledgerinfo
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence(seq, _)).WillByDefault(Return(std::nullopt));
|
||||
|
||||
auto const static input = boost::json::parse(fmt::format(
|
||||
auto const static input = json::parse(fmt::format(
|
||||
R"({{
|
||||
"account": "{}",
|
||||
"role": "gateway",
|
||||
|
||||
@@ -71,6 +71,7 @@ protected:
|
||||
EXPECT_STREQ(info.at("complete_ledgers").as_string().c_str(), "10-30");
|
||||
EXPECT_TRUE(info.contains("load_factor"));
|
||||
EXPECT_TRUE(info.contains("clio_version"));
|
||||
EXPECT_TRUE(info.contains("libxrpl_version"));
|
||||
EXPECT_TRUE(info.contains("validated_ledger"));
|
||||
EXPECT_TRUE(info.contains("time"));
|
||||
EXPECT_TRUE(info.contains("uptime"));
|
||||
@@ -284,7 +285,7 @@ TEST_F(RPCServerInfoHandlerTest, AdminSectionPresentWhenAdminFlagIsSet)
|
||||
mockBackendPtr->updateRange(10); // min
|
||||
mockBackendPtr->updateRange(30); // max
|
||||
|
||||
auto const empty = boost::json::object{};
|
||||
auto const empty = json::object{};
|
||||
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo));
|
||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1);
|
||||
@@ -336,7 +337,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesPresent)
|
||||
mockBackendPtr->updateRange(10); // min
|
||||
mockBackendPtr->updateRange(30); // max
|
||||
|
||||
auto const empty = boost::json::object{};
|
||||
auto const empty = json::object{};
|
||||
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo));
|
||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1);
|
||||
@@ -351,7 +352,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesPresent)
|
||||
ON_CALL(*rawETLServicePtr, isAmendmentBlocked).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawETLServicePtr, isAmendmentBlocked).Times(1);
|
||||
|
||||
auto const rippledObj = boost::json::parse(R"({
|
||||
auto const rippledObj = json::parse(R"({
|
||||
"result": {
|
||||
"info": {
|
||||
"build_version": "1234",
|
||||
@@ -399,7 +400,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesMissingNoExceptionThrown)
|
||||
mockBackendPtr->updateRange(10); // min
|
||||
mockBackendPtr->updateRange(30); // max
|
||||
|
||||
auto const empty = boost::json::object{};
|
||||
auto const empty = json::object{};
|
||||
auto const ledgerinfo = CreateLedgerInfo(LEDGERHASH, 30, 3); // 3 seconds old
|
||||
ON_CALL(*rawBackendPtr, fetchLedgerBySequence).WillByDefault(Return(ledgerinfo));
|
||||
EXPECT_CALL(*rawBackendPtr, fetchLedgerBySequence).Times(1);
|
||||
@@ -414,7 +415,7 @@ TEST_F(RPCServerInfoHandlerTest, RippledForwardedValuesMissingNoExceptionThrown)
|
||||
ON_CALL(*rawETLServicePtr, isAmendmentBlocked).WillByDefault(Return(false));
|
||||
EXPECT_CALL(*rawETLServicePtr, isAmendmentBlocked).Times(1);
|
||||
|
||||
auto const rippledObj = boost::json::parse(R"({
|
||||
auto const rippledObj = json::parse(R"({
|
||||
"result": {
|
||||
"info": {}
|
||||
}
|
||||
|
||||
@@ -504,8 +504,8 @@ generateTestValuesForParametersTest()
|
||||
}
|
||||
]
|
||||
})",
|
||||
"invalidParams",
|
||||
"takerNotString"},
|
||||
"badIssuer",
|
||||
"Issuer account malformed."},
|
||||
SubscribeParamTestCaseBundle{
|
||||
"BooksItemInvalidTaker",
|
||||
R"({
|
||||
@@ -523,8 +523,8 @@ generateTestValuesForParametersTest()
|
||||
}
|
||||
]
|
||||
})",
|
||||
"actMalformed",
|
||||
"takerMalformed"},
|
||||
"badIssuer",
|
||||
"Issuer account malformed."},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
33
unittests/util/FakeAmendmentBlockAction.h
Normal file
33
unittests/util/FakeAmendmentBlockAction.h
Normal file
@@ -0,0 +1,33 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2023, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
struct FakeAmendmentBlockAction
|
||||
{
|
||||
std::reference_wrapper<std::size_t> callCount;
|
||||
|
||||
void
|
||||
operator()()
|
||||
{
|
||||
++(callCount.get());
|
||||
}
|
||||
};
|
||||
@@ -160,10 +160,6 @@ private:
|
||||
*/
|
||||
struct SyncAsioContextTest : virtual public NoLoggerFixture
|
||||
{
|
||||
SyncAsioContextTest()
|
||||
{
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void
|
||||
runSpawn(F&& f)
|
||||
|
||||
27
unittests/util/MockAmendmentBlockHandler.h
Normal file
27
unittests/util/MockAmendmentBlockHandler.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2023, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
struct MockAmendmentBlockHandler
|
||||
{
|
||||
MOCK_METHOD(void, onAmendmentBlock, (), ());
|
||||
};
|
||||
Reference in New Issue
Block a user