mirror of
https://github.com/XRPLF/clio.git
synced 2025-12-06 17:27:58 +00:00
@@ -53,6 +53,7 @@
|
||||
namespace rpc::credentials {
|
||||
|
||||
bool
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage)
|
||||
checkExpired(ripple::SLE const& sleCred, ripple::LedgerHeader const& ledger)
|
||||
{
|
||||
if (sleCred.isFieldPresent(ripple::sfExpiration)) {
|
||||
@@ -64,6 +65,7 @@ checkExpired(ripple::SLE const& sleCred, ripple::LedgerHeader const& ledger)
|
||||
}
|
||||
|
||||
std::set<std::pair<ripple::AccountID, ripple::Slice>>
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage)
|
||||
createAuthCredentials(ripple::STArray const& in)
|
||||
{
|
||||
std::set<std::pair<ripple::AccountID, ripple::Slice>> out;
|
||||
@@ -74,6 +76,7 @@ createAuthCredentials(ripple::STArray const& in)
|
||||
}
|
||||
|
||||
ripple::STArray
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage)
|
||||
parseAuthorizeCredentials(boost::json::array const& jv)
|
||||
{
|
||||
ripple::STArray arr;
|
||||
@@ -108,6 +111,7 @@ parseAuthorizeCredentials(boost::json::array const& jv)
|
||||
}
|
||||
|
||||
std::expected<ripple::STArray, Status>
|
||||
// NOLINTNEXTLINE(misc-use-internal-linkage)
|
||||
fetchCredentialArray(
|
||||
std::optional<boost::json::array> const& credID,
|
||||
ripple::AccountID const& srcAcc,
|
||||
|
||||
@@ -55,7 +55,7 @@ getWarningInfo(WarningCode code)
|
||||
};
|
||||
|
||||
auto matchByCode = [code](auto const& info) { return info.code == code; };
|
||||
if (auto it = find_if(begin(infos), end(infos), matchByCode); it != end(infos))
|
||||
if (auto it = std::ranges::find_if(infos, matchByCode); it != end(infos))
|
||||
return *it;
|
||||
|
||||
throw(out_of_range("Invalid WarningCode"));
|
||||
@@ -75,32 +75,43 @@ ClioErrorInfo const&
|
||||
getErrorInfo(ClioError code)
|
||||
{
|
||||
constexpr static ClioErrorInfo infos[]{
|
||||
{ClioError::rpcMALFORMED_CURRENCY, "malformedCurrency", "Malformed currency."},
|
||||
{ClioError::rpcMALFORMED_REQUEST, "malformedRequest", "Malformed request."},
|
||||
{ClioError::rpcMALFORMED_OWNER, "malformedOwner", "Malformed owner."},
|
||||
{ClioError::rpcMALFORMED_ADDRESS, "malformedAddress", "Malformed address."},
|
||||
{ClioError::rpcINVALID_HOT_WALLET, "invalidHotWallet", "Invalid hot wallet."},
|
||||
{ClioError::rpcUNKNOWN_OPTION, "unknownOption", "Unknown option."},
|
||||
{ClioError::rpcFIELD_NOT_FOUND_TRANSACTION, "fieldNotFoundTransaction", "Missing field."},
|
||||
{ClioError::rpcMALFORMED_ORACLE_DOCUMENT_ID, "malformedDocumentID", "Malformed oracle_document_id."},
|
||||
{ClioError::rpcMALFORMED_AUTHORIZED_CREDENTIALS,
|
||||
"malformedAuthorizedCredentials",
|
||||
"Malformed authorized credentials."},
|
||||
{.code = ClioError::rpcMALFORMED_CURRENCY, .error = "malformedCurrency", .message = "Malformed currency."},
|
||||
{.code = ClioError::rpcMALFORMED_REQUEST, .error = "malformedRequest", .message = "Malformed request."},
|
||||
{.code = ClioError::rpcMALFORMED_OWNER, .error = "malformedOwner", .message = "Malformed owner."},
|
||||
{.code = ClioError::rpcMALFORMED_ADDRESS, .error = "malformedAddress", .message = "Malformed address."},
|
||||
{.code = ClioError::rpcINVALID_HOT_WALLET, .error = "invalidHotWallet", .message = "Invalid hot wallet."},
|
||||
{.code = ClioError::rpcUNKNOWN_OPTION, .error = "unknownOption", .message = "Unknown option."},
|
||||
{.code = ClioError::rpcFIELD_NOT_FOUND_TRANSACTION,
|
||||
.error = "fieldNotFoundTransaction",
|
||||
.message = "Missing field."},
|
||||
{.code = ClioError::rpcMALFORMED_ORACLE_DOCUMENT_ID,
|
||||
.error = "malformedDocumentID",
|
||||
.message = "Malformed oracle_document_id."},
|
||||
{.code = ClioError::rpcMALFORMED_AUTHORIZED_CREDENTIALS,
|
||||
.error = "malformedAuthorizedCredentials",
|
||||
.message = "Malformed authorized credentials."},
|
||||
// special system errors
|
||||
{ClioError::rpcINVALID_API_VERSION, JS(invalid_API_version), "Invalid API version."},
|
||||
{ClioError::rpcCOMMAND_IS_MISSING, JS(missingCommand), "Method is not specified or is not a string."},
|
||||
{ClioError::rpcCOMMAND_NOT_STRING, "commandNotString", "Method is not a string."},
|
||||
{ClioError::rpcCOMMAND_IS_EMPTY, "emptyCommand", "Method is an empty string."},
|
||||
{ClioError::rpcPARAMS_UNPARSEABLE, "paramsUnparseable", "Params must be an array holding exactly one object."},
|
||||
{.code = ClioError::rpcINVALID_API_VERSION, .error = JS(invalid_API_version), .message = "Invalid API version."
|
||||
},
|
||||
{.code = ClioError::rpcCOMMAND_IS_MISSING,
|
||||
.error = JS(missingCommand),
|
||||
.message = "Method is not specified or is not a string."},
|
||||
{.code = ClioError::rpcCOMMAND_NOT_STRING, .error = "commandNotString", .message = "Method is not a string."},
|
||||
{.code = ClioError::rpcCOMMAND_IS_EMPTY, .error = "emptyCommand", .message = "Method is an empty string."},
|
||||
{.code = ClioError::rpcPARAMS_UNPARSEABLE,
|
||||
.error = "paramsUnparseable",
|
||||
.message = "Params must be an array holding exactly one object."},
|
||||
// etl related errors
|
||||
{ClioError::etlCONNECTION_ERROR, "connectionError", "Couldn't connect to rippled."},
|
||||
{ClioError::etlREQUEST_ERROR, "requestError", "Error sending request to rippled."},
|
||||
{ClioError::etlREQUEST_TIMEOUT, "timeout", "Request to rippled timed out."},
|
||||
{ClioError::etlINVALID_RESPONSE, "invalidResponse", "Rippled returned an invalid response."}
|
||||
{.code = ClioError::etlCONNECTION_ERROR, .error = "connectionError", .message = "Couldn't connect to rippled."},
|
||||
{.code = ClioError::etlREQUEST_ERROR, .error = "requestError", .message = "Error sending request to rippled."},
|
||||
{.code = ClioError::etlREQUEST_TIMEOUT, .error = "timeout", .message = "Request to rippled timed out."},
|
||||
{.code = ClioError::etlINVALID_RESPONSE,
|
||||
.error = "invalidResponse",
|
||||
.message = "Rippled returned an invalid response."}
|
||||
};
|
||||
|
||||
auto matchByCode = [code](auto const& info) { return info.code == code; };
|
||||
if (auto it = find_if(begin(infos), end(infos), matchByCode); it != end(infos))
|
||||
if (auto it = std::ranges::find_if(infos, matchByCode); it != end(infos))
|
||||
return *it;
|
||||
|
||||
throw(out_of_range("Invalid error code"));
|
||||
|
||||
@@ -174,7 +174,13 @@ public:
|
||||
try {
|
||||
LOG(perfLog_.debug()) << ctx.tag() << " start executing rpc `" << ctx.method << '`';
|
||||
|
||||
auto const context = Context{ctx.yield, ctx.session, ctx.isAdmin, ctx.clientIp, ctx.apiVersion};
|
||||
auto const context = Context{
|
||||
.yield = ctx.yield,
|
||||
.session = ctx.session,
|
||||
.isAdmin = ctx.isAdmin,
|
||||
.clientIp = ctx.clientIp,
|
||||
.apiVersion = ctx.apiVersion
|
||||
};
|
||||
auto v = (*method).process(ctx.params, context);
|
||||
|
||||
LOG(perfLog_.debug()) << ctx.tag() << " finish executing rpc `" << ctx.method << '`';
|
||||
|
||||
@@ -113,7 +113,7 @@ parseAccountCursor(std::optional<std::string> jsonCursor)
|
||||
std::uint64_t startHint = 0;
|
||||
|
||||
if (!jsonCursor)
|
||||
return AccountCursor({cursorIndex, startHint});
|
||||
return AccountCursor({.index = cursorIndex, .hint = startHint});
|
||||
|
||||
// Cursor is composed of a comma separated index and start hint. The
|
||||
// former will be read as hex, and the latter using boost lexical cast.
|
||||
@@ -134,7 +134,7 @@ parseAccountCursor(std::optional<std::string> jsonCursor)
|
||||
return {};
|
||||
}
|
||||
|
||||
return AccountCursor({cursorIndex, startHint});
|
||||
return AccountCursor({.index = cursorIndex, .hint = startHint});
|
||||
}
|
||||
|
||||
std::optional<ripple::STAmount>
|
||||
@@ -220,8 +220,8 @@ deserializeTxPlusMeta(data::TransactionAndMetadata const& blobs)
|
||||
} catch (std::exception const& e) {
|
||||
std::stringstream txn;
|
||||
std::stringstream meta;
|
||||
std::copy(blobs.transaction.begin(), blobs.transaction.end(), std::ostream_iterator<unsigned char>(txn));
|
||||
std::copy(blobs.metadata.begin(), blobs.metadata.end(), std::ostream_iterator<unsigned char>(meta));
|
||||
std::ranges::copy(blobs.transaction, std::ostream_iterator<unsigned char>(txn));
|
||||
std::ranges::copy(blobs.metadata, std::ostream_iterator<unsigned char>(meta));
|
||||
LOG(gLog.error()) << "Failed to deserialize transaction. txn = " << txn.str() << " - meta = " << meta.str()
|
||||
<< " txn length = " << std::to_string(blobs.transaction.size())
|
||||
<< " meta length = " << std::to_string(blobs.metadata.size());
|
||||
@@ -609,7 +609,7 @@ traverseNFTObjects(
|
||||
|
||||
if (!page) {
|
||||
if (nextPage == beast::zero) { // no nft objects in lastNFTPage
|
||||
return AccountCursor{beast::zero, 0};
|
||||
return AccountCursor{.index = beast::zero, .hint = 0};
|
||||
}
|
||||
// marker is in the right range, but still invalid
|
||||
return Status{RippledError::rpcINVALID_PARAMS, "Invalid marker."};
|
||||
@@ -626,13 +626,13 @@ traverseNFTObjects(
|
||||
count++;
|
||||
|
||||
if (count == limit or nftPreviousPage == beast::zero)
|
||||
return AccountCursor{nftPreviousPage, count};
|
||||
return AccountCursor{.index = nftPreviousPage, .hint = count};
|
||||
|
||||
page = backend.fetchLedgerObject(nftPreviousPage, sequence, yield);
|
||||
pageSLE = ripple::SLE{ripple::SerialIter{page->data(), page->size()}, nftPreviousPage};
|
||||
}
|
||||
|
||||
return AccountCursor{beast::zero, 0};
|
||||
return AccountCursor{.index = beast::zero, .hint = 0};
|
||||
}
|
||||
|
||||
std::variant<Status, AccountCursor>
|
||||
@@ -671,7 +671,7 @@ traverseOwnedNodes(
|
||||
|
||||
// if limit reach , we return the next page and max as marker
|
||||
if (nftsCount >= limit)
|
||||
return AccountCursor{nextNFTPage, std::numeric_limits<uint32_t>::max()};
|
||||
return AccountCursor{.index = nextNFTPage, .hint = std::numeric_limits<uint32_t>::max()};
|
||||
|
||||
// adjust limit ,continue traversing owned nodes
|
||||
limit -= nftsCount;
|
||||
@@ -700,7 +700,7 @@ traverseOwnedNodes(
|
||||
std::function<void(ripple::SLE)> atOwnedNode
|
||||
)
|
||||
{
|
||||
auto cursor = AccountCursor({beast::zero, 0});
|
||||
auto cursor = AccountCursor({.index = beast::zero, .hint = 0});
|
||||
|
||||
auto const rootIndex = owner;
|
||||
auto currentIndex = rootIndex;
|
||||
@@ -728,7 +728,7 @@ traverseOwnedNodes(
|
||||
ripple::SLE const hintDirSle{hintDirIt, hintIndex.key};
|
||||
|
||||
if (auto const& indexes = hintDirSle.getFieldV256(ripple::sfIndexes);
|
||||
std::find(std::begin(indexes), std::end(indexes), hexMarker) == std::end(indexes)) {
|
||||
std::ranges::find(indexes, hexMarker) == std::end(indexes)) {
|
||||
// the index specified by marker is not in the page specified by marker
|
||||
return Status(ripple::rpcINVALID_PARAMS, "Invalid marker.");
|
||||
}
|
||||
@@ -758,7 +758,7 @@ traverseOwnedNodes(
|
||||
}
|
||||
|
||||
if (limit == 0) {
|
||||
cursor = AccountCursor({keys.back(), currentPage});
|
||||
cursor = AccountCursor({.index = keys.back(), .hint = currentPage});
|
||||
break;
|
||||
}
|
||||
// the next page
|
||||
@@ -787,7 +787,7 @@ traverseOwnedNodes(
|
||||
}
|
||||
|
||||
if (limit == 0) {
|
||||
cursor = AccountCursor({keys.back(), currentPage});
|
||||
cursor = AccountCursor({.index = keys.back(), .hint = currentPage});
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -819,7 +819,7 @@ traverseOwnedNodes(
|
||||
if (limit == 0)
|
||||
return cursor;
|
||||
|
||||
return AccountCursor({beast::zero, 0});
|
||||
return AccountCursor({.index = beast::zero, .hint = 0});
|
||||
}
|
||||
|
||||
std::shared_ptr<ripple::SLE const>
|
||||
|
||||
@@ -31,10 +31,10 @@ namespace rpc::meta {
|
||||
[[nodiscard]] MaybeError
|
||||
Section::verify(boost::json::value& value, std::string_view key) const
|
||||
{
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. field does not exist, let 'required' fail instead
|
||||
|
||||
auto& res = value.as_object().at(key.data());
|
||||
auto& res = value.as_object().at(key);
|
||||
|
||||
// if it is not a json object, let other validators fail
|
||||
if (!res.is_object())
|
||||
@@ -51,13 +51,13 @@ Section::verify(boost::json::value& value, std::string_view key) const
|
||||
[[nodiscard]] MaybeError
|
||||
ValidateArrayAt::verify(boost::json::value& value, std::string_view key) const
|
||||
{
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. field does not exist, let 'required' fail instead
|
||||
|
||||
if (not value.as_object().at(key.data()).is_array())
|
||||
if (not value.as_object().at(key).is_array())
|
||||
return Error{Status{RippledError::rpcINVALID_PARAMS}};
|
||||
|
||||
auto& arr = value.as_object().at(key.data()).as_array();
|
||||
auto& arr = value.as_object().at(key).as_array();
|
||||
if (idx_ >= arr.size())
|
||||
return Error{Status{RippledError::rpcINVALID_PARAMS}};
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <boost/json/value_to.hpp>
|
||||
#include <xrpl/protocol/ErrorCodes.h>
|
||||
|
||||
#include <concepts>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
@@ -65,12 +66,12 @@ public:
|
||||
{
|
||||
using boost::json::value_to;
|
||||
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. field does not exist, let 'required' fail instead
|
||||
|
||||
// clamp to min_ and max_
|
||||
auto const oldValue = value_to<Type>(value.as_object().at(key.data()));
|
||||
value.as_object()[key.data()] = std::clamp<Type>(oldValue, min_, max_);
|
||||
auto const oldValue = value_to<Type>(value.as_object().at(key));
|
||||
value.as_object()[key] = std::clamp<Type>(oldValue, min_, max_);
|
||||
|
||||
return {};
|
||||
}
|
||||
@@ -92,14 +93,13 @@ struct ToLower final {
|
||||
[[nodiscard]] static MaybeError
|
||||
modify(boost::json::value& value, std::string_view key)
|
||||
{
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. field does not exist, let 'required' fail instead
|
||||
|
||||
if (not value.as_object().at(key.data()).is_string())
|
||||
if (not value.as_object().at(key).is_string())
|
||||
return {}; // ignore for non-string types
|
||||
|
||||
value.as_object()[key.data()] =
|
||||
util::toLower(boost::json::value_to<std::string>(value.as_object().at(key.data())));
|
||||
value.as_object()[key] = util::toLower(boost::json::value_to<std::string>(value.as_object().at(key)));
|
||||
return {};
|
||||
}
|
||||
};
|
||||
@@ -131,7 +131,7 @@ struct ToNumber final {
|
||||
return Error{Status{RippledError::rpcINVALID_PARAMS}}; // maybe a float
|
||||
|
||||
try {
|
||||
value.as_object()[key.data()] = std::stoi(strInt);
|
||||
value.as_object()[key] = std::stoi(strInt);
|
||||
} catch (std::exception& e) {
|
||||
return Error{Status{RippledError::rpcINVALID_PARAMS}};
|
||||
}
|
||||
@@ -171,7 +171,7 @@ public:
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. field does not exist, let 'required' fail instead
|
||||
|
||||
return modifier_(value.as_object().at(key.data()), key);
|
||||
return modifier_(value.as_object().at(key), key);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -92,9 +92,9 @@ public:
|
||||
[[nodiscard]] MaybeError
|
||||
verify(boost::json::value const& value, std::string_view key) const
|
||||
{
|
||||
if (value.is_object() and value.as_object().contains(key.data())) {
|
||||
if (value.is_object() and value.as_object().contains(key)) {
|
||||
using boost::json::value_to;
|
||||
auto const res = value_to<T>(value.as_object().at(key.data()));
|
||||
auto const res = value_to<T>(value.as_object().at(key));
|
||||
if (value_ == res) {
|
||||
return Error{Status{
|
||||
RippledError::rpcNOT_SUPPORTED,
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
[[nodiscard]] static MaybeError
|
||||
verify(boost::json::value const& value, std::string_view key)
|
||||
{
|
||||
if (value.is_object() and value.as_object().contains(key.data()))
|
||||
if (value.is_object() and value.as_object().contains(key))
|
||||
return Error{Status{RippledError::rpcNOT_SUPPORTED, "Not supported field '" + std::string{key} + '\''}};
|
||||
|
||||
return {};
|
||||
@@ -150,10 +150,10 @@ struct Type final {
|
||||
[[nodiscard]] MaybeError
|
||||
verify(boost::json::value const& value, std::string_view key) const
|
||||
{
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. If field is supposed to exist, let 'required' fail instead
|
||||
|
||||
auto const& res = value.as_object().at(key.data());
|
||||
auto const& res = value.as_object().at(key);
|
||||
auto const convertible = (checkType<Types>(res) || ...);
|
||||
|
||||
if (not convertible)
|
||||
@@ -194,10 +194,10 @@ public:
|
||||
{
|
||||
using boost::json::value_to;
|
||||
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. field does not exist, let 'required' fail instead
|
||||
|
||||
auto const res = value_to<Type>(value.as_object().at(key.data()));
|
||||
auto const res = value_to<Type>(value.as_object().at(key));
|
||||
|
||||
// TODO: may want a way to make this code more generic (e.g. use a free
|
||||
// function that can be overridden for this comparison)
|
||||
@@ -237,10 +237,10 @@ public:
|
||||
{
|
||||
using boost::json::value_to;
|
||||
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. field does not exist, let 'required' fail instead
|
||||
|
||||
auto const res = value_to<Type>(value.as_object().at(key.data()));
|
||||
auto const res = value_to<Type>(value.as_object().at(key));
|
||||
|
||||
if (res < min_)
|
||||
return Error{Status{RippledError::rpcINVALID_PARAMS}};
|
||||
@@ -278,10 +278,10 @@ public:
|
||||
{
|
||||
using boost::json::value_to;
|
||||
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. field does not exist, let 'required' fail instead
|
||||
|
||||
auto const res = value_to<Type>(value.as_object().at(key.data()));
|
||||
auto const res = value_to<Type>(value.as_object().at(key));
|
||||
|
||||
if (res > max_)
|
||||
return Error{Status{RippledError::rpcINVALID_PARAMS}};
|
||||
@@ -346,10 +346,10 @@ public:
|
||||
{
|
||||
using boost::json::value_to;
|
||||
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. field does not exist, let 'required' fail instead
|
||||
|
||||
auto const res = value_to<Type>(value.as_object().at(key.data()));
|
||||
auto const res = value_to<Type>(value.as_object().at(key));
|
||||
if (res != original_)
|
||||
return Error{Status{RippledError::rpcINVALID_PARAMS}};
|
||||
|
||||
@@ -401,10 +401,10 @@ public:
|
||||
{
|
||||
using boost::json::value_to;
|
||||
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. field does not exist, let 'required' fail instead
|
||||
|
||||
auto const res = value_to<Type>(value.as_object().at(key.data()));
|
||||
auto const res = value_to<Type>(value.as_object().at(key));
|
||||
if (std::find(std::begin(options_), std::end(options_), res) == std::end(options_))
|
||||
return Error{Status{RippledError::rpcINVALID_PARAMS, fmt::format("Invalid field '{}'.", key)}};
|
||||
|
||||
@@ -588,10 +588,10 @@ struct Hex256ItemType final {
|
||||
[[nodiscard]] static MaybeError
|
||||
verify(boost::json::value const& value, std::string_view key)
|
||||
{
|
||||
if (not value.is_object() or not value.as_object().contains(key.data()))
|
||||
if (not value.is_object() or not value.as_object().contains(key))
|
||||
return {}; // ignore. If field is supposed to exist, let 'required' fail instead
|
||||
|
||||
auto const& res = value.as_object().at(key.data());
|
||||
auto const& res = value.as_object().at(key);
|
||||
|
||||
// loop through each item in the array and make sure it is uint256 hex string
|
||||
for (auto const& elem : res.as_array()) {
|
||||
|
||||
@@ -78,41 +78,41 @@ ProductionHandlerProvider::ProductionHandlerProvider(
|
||||
Counters const& counters
|
||||
)
|
||||
: handlerMap_{
|
||||
{"account_channels", {AccountChannelsHandler{backend}}},
|
||||
{"account_currencies", {AccountCurrenciesHandler{backend}}},
|
||||
{"account_info", {AccountInfoHandler{backend, amendmentCenter}}},
|
||||
{"account_lines", {AccountLinesHandler{backend}}},
|
||||
{"account_nfts", {AccountNFTsHandler{backend}}},
|
||||
{"account_objects", {AccountObjectsHandler{backend}}},
|
||||
{"account_offers", {AccountOffersHandler{backend}}},
|
||||
{"account_tx", {AccountTxHandler{backend}}},
|
||||
{"amm_info", {AMMInfoHandler{backend}}},
|
||||
{"book_changes", {BookChangesHandler{backend}}},
|
||||
{"book_offers", {BookOffersHandler{backend}}},
|
||||
{"deposit_authorized", {DepositAuthorizedHandler{backend}}},
|
||||
{"feature", {FeatureHandler{backend, amendmentCenter}}},
|
||||
{"gateway_balances", {GatewayBalancesHandler{backend}}},
|
||||
{"get_aggregate_price", {GetAggregatePriceHandler{backend}}},
|
||||
{"ledger", {LedgerHandler{backend}}},
|
||||
{"ledger_data", {LedgerDataHandler{backend}}},
|
||||
{"ledger_entry", {LedgerEntryHandler{backend}}},
|
||||
{"ledger_index", {LedgerIndexHandler{backend}, true}}, // clio only
|
||||
{"ledger_range", {LedgerRangeHandler{backend}}},
|
||||
{"mpt_holders", {MPTHoldersHandler{backend}, true}}, // clio only
|
||||
{"nfts_by_issuer", {NFTsByIssuerHandler{backend}, true}}, // clio only
|
||||
{"nft_history", {NFTHistoryHandler{backend}, true}}, // clio only
|
||||
{"nft_buy_offers", {NFTBuyOffersHandler{backend}}},
|
||||
{"nft_info", {NFTInfoHandler{backend}, true}}, // clio only
|
||||
{"nft_sell_offers", {NFTSellOffersHandler{backend}}},
|
||||
{"noripple_check", {NoRippleCheckHandler{backend}}},
|
||||
{"ping", {PingHandler{}}},
|
||||
{"random", {RandomHandler{}}},
|
||||
{"server_info", {ServerInfoHandler{backend, subscriptionManager, balancer, etl, counters}}},
|
||||
{"transaction_entry", {TransactionEntryHandler{backend}}},
|
||||
{"tx", {TxHandler{backend, etl}}},
|
||||
{"subscribe", {SubscribeHandler{backend, subscriptionManager}}},
|
||||
{"unsubscribe", {UnsubscribeHandler{subscriptionManager}}},
|
||||
{"version", {VersionHandler{config}}},
|
||||
{"account_channels", {.handler = AccountChannelsHandler{backend}}},
|
||||
{"account_currencies", {.handler = AccountCurrenciesHandler{backend}}},
|
||||
{"account_info", {.handler = AccountInfoHandler{backend, amendmentCenter}}},
|
||||
{"account_lines", {.handler = AccountLinesHandler{backend}}},
|
||||
{"account_nfts", {.handler = AccountNFTsHandler{backend}}},
|
||||
{"account_objects", {.handler = AccountObjectsHandler{backend}}},
|
||||
{"account_offers", {.handler = AccountOffersHandler{backend}}},
|
||||
{"account_tx", {.handler = AccountTxHandler{backend}}},
|
||||
{"amm_info", {.handler = AMMInfoHandler{backend}}},
|
||||
{"book_changes", {.handler = BookChangesHandler{backend}}},
|
||||
{"book_offers", {.handler = BookOffersHandler{backend}}},
|
||||
{"deposit_authorized", {.handler = DepositAuthorizedHandler{backend}}},
|
||||
{"feature", {.handler = FeatureHandler{backend, amendmentCenter}}},
|
||||
{"gateway_balances", {.handler = GatewayBalancesHandler{backend}}},
|
||||
{"get_aggregate_price", {.handler = GetAggregatePriceHandler{backend}}},
|
||||
{"ledger", {.handler = LedgerHandler{backend}}},
|
||||
{"ledger_data", {.handler = LedgerDataHandler{backend}}},
|
||||
{"ledger_entry", {.handler = LedgerEntryHandler{backend}}},
|
||||
{"ledger_index", {.handler = LedgerIndexHandler{backend}, .isClioOnly = true}}, // clio only
|
||||
{"ledger_range", {.handler = LedgerRangeHandler{backend}}},
|
||||
{"mpt_holders", {.handler = MPTHoldersHandler{backend}, .isClioOnly = true}}, // clio only
|
||||
{"nfts_by_issuer", {.handler = NFTsByIssuerHandler{backend}, .isClioOnly = true}}, // clio only
|
||||
{"nft_history", {.handler = NFTHistoryHandler{backend}, .isClioOnly = true}}, // clio only
|
||||
{"nft_buy_offers", {.handler = NFTBuyOffersHandler{backend}}},
|
||||
{"nft_info", {.handler = NFTInfoHandler{backend}, .isClioOnly = true}}, // clio only
|
||||
{"nft_sell_offers", {.handler = NFTSellOffersHandler{backend}}},
|
||||
{"noripple_check", {.handler = NoRippleCheckHandler{backend}}},
|
||||
{"ping", {.handler = PingHandler{}}},
|
||||
{"random", {.handler = RandomHandler{}}},
|
||||
{"server_info", {.handler = ServerInfoHandler{backend, subscriptionManager, balancer, etl, counters}}},
|
||||
{"transaction_entry", {.handler = TransactionEntryHandler{backend}}},
|
||||
{"tx", {.handler = TxHandler{backend, etl}}},
|
||||
{"subscribe", {.handler = SubscribeHandler{backend, subscriptionManager}}},
|
||||
{"unsubscribe", {.handler = UnsubscribeHandler{subscriptionManager}}},
|
||||
{"version", {.handler = VersionHandler{config}}},
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountInfoHandl
|
||||
|
||||
boost::json::object acctFlags;
|
||||
for (auto const& lsf : lsFlags)
|
||||
acctFlags[lsf.first.data()] = output.accountData.isFlag(lsf.second);
|
||||
acctFlags[lsf.first] = output.accountData.isFlag(lsf.second);
|
||||
|
||||
jv.as_object()[JS(account_flags)] = std::move(acctFlags);
|
||||
|
||||
|
||||
@@ -121,9 +121,9 @@ void
|
||||
tag_invoke(boost::json::value_from_tag, boost::json::value& jv, AccountObjectsHandler::Output const& output)
|
||||
{
|
||||
auto objects = boost::json::array{};
|
||||
std::transform(
|
||||
std::cbegin(output.accountObjects),
|
||||
std::cend(output.accountObjects),
|
||||
std::ranges::transform(
|
||||
output.accountObjects,
|
||||
|
||||
std::back_inserter(objects),
|
||||
[](auto const& sle) { return toJson(sle); }
|
||||
);
|
||||
|
||||
@@ -132,7 +132,7 @@ AccountTxHandler::process(AccountTxHandler::Input input, Context const& ctx) con
|
||||
Output response;
|
||||
|
||||
if (retCursor)
|
||||
response.marker = {retCursor->ledgerSequence, retCursor->transactionIndex};
|
||||
response.marker = {.ledger = retCursor->ledgerSequence, .seq = retCursor->transactionIndex};
|
||||
|
||||
for (auto const& txnPlusMeta : blobs) {
|
||||
// over the range
|
||||
@@ -265,8 +265,8 @@ tag_invoke(boost::json::value_to_tag<AccountTxHandler::Input>, boost::json::valu
|
||||
|
||||
if (jsonObject.contains(JS(marker))) {
|
||||
input.marker = AccountTxHandler::Marker{
|
||||
jsonObject.at(JS(marker)).as_object().at(JS(ledger)).as_int64(),
|
||||
jsonObject.at(JS(marker)).as_object().at(JS(seq)).as_int64()
|
||||
.ledger = jsonObject.at(JS(marker)).as_object().at(JS(ledger)).as_int64(),
|
||||
.seq = jsonObject.at(JS(marker)).as_object().at(JS(seq)).as_int64()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ GatewayBalancesHandler::process(GatewayBalancesHandler::Input input, Context con
|
||||
return Error{*status};
|
||||
|
||||
auto inHotbalances = [&](auto const& hw) { return output.hotBalances.contains(hw); };
|
||||
if (not std::all_of(input.hotWallets.begin(), input.hotWallets.end(), inHotbalances))
|
||||
if (not std::ranges::all_of(input.hotWallets, inHotbalances))
|
||||
return Error{Status{ClioError::rpcINVALID_HOT_WALLET}};
|
||||
|
||||
output.accountID = input.account;
|
||||
@@ -233,9 +233,9 @@ tag_invoke(boost::json::value_to_tag<GatewayBalancesHandler::Input>, boost::json
|
||||
input.hotWallets.insert(*accountFromStringStrict(boost::json::value_to<std::string>(jv.at(JS(hotwallet)))));
|
||||
} else {
|
||||
auto const& hotWallets = jv.at(JS(hotwallet)).as_array();
|
||||
std::transform(
|
||||
hotWallets.begin(),
|
||||
hotWallets.end(),
|
||||
std::ranges::transform(
|
||||
hotWallets,
|
||||
|
||||
std::inserter(input.hotWallets, input.hotWallets.begin()),
|
||||
[](auto const& hotWallet) {
|
||||
return *accountFromStringStrict(boost::json::value_to<std::string>(hotWallet));
|
||||
|
||||
@@ -147,11 +147,11 @@ GetAggregatePriceHandler::process(GetAggregatePriceHandler::Input input, Context
|
||||
avg = divide(avg, ripple::STAmount{ripple::noIssue(), size, 0}, ripple::noIssue());
|
||||
if (size > 1) {
|
||||
sd = std::accumulate(begin, end, sd, [&](ripple::Number const& acc, auto const& it) {
|
||||
return acc + (it.first - avg) * (it.first - avg);
|
||||
return acc + ((it.first - avg) * (it.first - avg));
|
||||
});
|
||||
sd = root2(sd / (size - 1));
|
||||
}
|
||||
return {avg, sd, size};
|
||||
return {.avg = avg, .sd = sd, .size = size};
|
||||
};
|
||||
|
||||
out.extireStats = getStats(timestampPricesBiMap.right.begin(), timestampPricesBiMap.right.end());
|
||||
|
||||
@@ -348,11 +348,10 @@ tag_invoke(boost::json::value_to_tag<LedgerEntryHandler::Input>, boost::json::va
|
||||
return ripple::keylet::credential(*subject, *issuer, ripple::Slice(credType->data(), credType->size())).key;
|
||||
};
|
||||
|
||||
auto const indexFieldType =
|
||||
std::find_if(indexFieldTypeMap.begin(), indexFieldTypeMap.end(), [&jsonObject](auto const& pair) {
|
||||
auto const& [field, _] = pair;
|
||||
return jsonObject.contains(field) && jsonObject.at(field).is_string();
|
||||
});
|
||||
auto const indexFieldType = std::ranges::find_if(indexFieldTypeMap, [&jsonObject](auto const& pair) {
|
||||
auto const& [field, _] = pair;
|
||||
return jsonObject.contains(field) && jsonObject.at(field).is_string();
|
||||
});
|
||||
|
||||
if (indexFieldType != indexFieldTypeMap.end()) {
|
||||
input.index = boost::json::value_to<std::string>(jv.at(indexFieldType->first));
|
||||
|
||||
@@ -115,7 +115,7 @@ NFTHistoryHandler::process(NFTHistoryHandler::Input input, Context const& ctx) c
|
||||
auto const [blobs, retCursor] = txnsAndCursor;
|
||||
|
||||
if (retCursor)
|
||||
response.marker = {retCursor->ledgerSequence, retCursor->transactionIndex};
|
||||
response.marker = {.ledger = retCursor->ledgerSequence, .seq = retCursor->transactionIndex};
|
||||
|
||||
for (auto const& txnPlusMeta : blobs) {
|
||||
// over the range
|
||||
@@ -232,8 +232,8 @@ tag_invoke(boost::json::value_to_tag<NFTHistoryHandler::Input>, boost::json::val
|
||||
|
||||
if (jsonObject.contains(JS(marker))) {
|
||||
input.marker = NFTHistoryHandler::Marker{
|
||||
jsonObject.at(JS(marker)).as_object().at(JS(ledger)).as_int64(),
|
||||
jsonObject.at(JS(marker)).as_object().at(JS(seq)).as_int64()
|
||||
.ledger = jsonObject.at(JS(marker)).as_object().at(JS(ledger)).as_int64(),
|
||||
.seq = jsonObject.at(JS(marker)).as_object().at(JS(seq)).as_int64()
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ using namespace ::rpc;
|
||||
namespace ripple {
|
||||
|
||||
// TODO: move to some common serialization impl place
|
||||
inline void
|
||||
inline static void
|
||||
tag_invoke(boost::json::value_from_tag, boost::json::value& jv, SLE const& offer)
|
||||
{
|
||||
auto amount = ::toBoostJson(offer.getFieldAmount(sfAmount).getJson(JsonOptions::none));
|
||||
@@ -165,7 +165,7 @@ NFTOffersHandlerBase::iterateOfferDirectory(
|
||||
offers.pop_back();
|
||||
}
|
||||
|
||||
std::move(std::begin(offers), std::end(offers), std::back_inserter(output.offers));
|
||||
std::ranges::move(offers, std::back_inserter(output.offers));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user