Warn about deprecated fields (#1314)

Fixes #1251.
This commit is contained in:
Sergey Kuznetsov
2024-04-11 15:23:59 +01:00
committed by GitHub
parent 230212213b
commit e744a5a8a9
64 changed files with 1902 additions and 761 deletions

View File

@@ -59,6 +59,9 @@ getWarningInfo(WarningCode code)
"'ledger_index':'current' in your request"},
{warnRPC_OUTDATED, "This server may be out of date"},
{warnRPC_RATE_LIMIT, "You are about to be rate limited"},
{warnRPC_DEPRECATED,
"Some fields from your request are deprecated. Please check the documentation at "
"https://xrpl.org/docs/references/http-websocket-apis/ and update your request."}
};
auto matchByCode = [code](auto const& info) { return info.code == code; };
@@ -73,10 +76,8 @@ makeWarning(WarningCode code)
{
auto json = boost::json::object{};
auto const& info = getWarningInfo(code);
json["id"] = code;
json["message"] = static_cast<string>(info.message);
json["message"] = info.message;
return json;
}
@@ -128,9 +129,9 @@ makeError(ClioError err, std::optional<std::string_view> customError, std::optio
boost::json::object json;
auto const& info = getErrorInfo(err);
json["error"] = customError.value_or(info.error).data();
json["error"] = customError.value_or(info.error);
json["error_code"] = static_cast<uint32_t>(info.code);
json["error_message"] = customMessage.value_or(info.message).data();
json["error_message"] = customMessage.value_or(info.message);
json["status"] = "error";
json["type"] = "response";

View File

@@ -128,6 +128,9 @@ struct Status {
{
}
bool
operator==(Status const& other) const = default;
/**
* @brief Check if the status is not OK
*
@@ -173,7 +176,13 @@ struct Status {
};
/** @brief Warning codes that can be returned by clio. */
enum WarningCode { warnUNKNOWN = -1, warnRPC_CLIO = 2001, warnRPC_OUTDATED = 2002, warnRPC_RATE_LIMIT = 2003 };
enum WarningCode {
warnUNKNOWN = -1,
warnRPC_CLIO = 2001,
warnRPC_OUTDATED = 2002,
warnRPC_RATE_LIMIT = 2003,
warnRPC_DEPRECATED = 2004
};
/** @brief Holds information about a clio warning. */
struct WarningInfo {

View File

@@ -41,6 +41,7 @@
#include <memory>
#include <optional>
#include <string>
#include <utility>
// forward declarations
namespace feed {
@@ -139,38 +140,37 @@ public:
if (backend_->isTooBusy()) {
LOG(log_.error()) << "Database is too busy. Rejecting request";
notifyTooBusy(); // TODO: should we add ctx.method if we have it?
return Status{RippledError::rpcTOO_BUSY};
return Result{Status{RippledError::rpcTOO_BUSY}};
}
auto const method = handlerProvider_->getHandler(ctx.method);
if (!method) {
notifyUnknownCommand();
return Status{RippledError::rpcUNKNOWN_COMMAND};
return Result{Status{RippledError::rpcUNKNOWN_COMMAND}};
}
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 v = (*method).process(ctx.params, context);
auto v = (*method).process(ctx.params, context);
LOG(perfLog_.debug()) << ctx.tag() << " finish executing rpc `" << ctx.method << '`';
if (v)
return v->as_object();
if (not v)
notifyErrored(ctx.method);
notifyErrored(ctx.method);
return Status{v.error()};
return Result{std::move(v)};
} catch (data::DatabaseTimeout const& t) {
LOG(log_.error()) << "Database timeout";
notifyTooBusy();
return Status{RippledError::rpcTOO_BUSY};
return Result{Status{RippledError::rpcTOO_BUSY}};
} catch (std::exception const& ex) {
LOG(log_.error()) << ctx.tag() << "Caught exception: " << ex.what();
notifyInternalError();
return Status{RippledError::rpcINTERNAL};
return Result{Status{RippledError::rpcINTERNAL}};
}
}

134
src/rpc/common/Checkers.hpp Normal file
View File

@@ -0,0 +1,134 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, 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 "rpc/Errors.hpp"
#include "rpc/common/ValidationHelpers.hpp"
#include <boost/json/value.hpp>
#include <boost/json/value_to.hpp>
#include <fmt/core.h>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
namespace rpc::check {
/**
* @brief Warning that checks can return
*/
struct Warning {
/**
* @brief Construct a new Warning object
*
* @param code The warning code
* @param message The warning message
*/
Warning(WarningCode code, std::string message) : warningCode(code), extraMessage(std::move(message))
{
}
bool
operator==(Warning const& other) const = default;
WarningCode warningCode;
std::string extraMessage;
};
using Warnings = std::vector<Warning>;
/**
* @brief Check for a deprecated fields
*/
template <typename... T>
class Deprecated;
/**
* @brief Check if a field is deprecated
*/
template <>
class Deprecated<> final {
public:
/**
* @brief Check if a field is deprecated
*
* @param value The json value to check
* @param key The key to check
* @return A warning if the field is deprecated or std::nullopt otherwise
*/
[[nodiscard]] static std::optional<Warning>
check(boost::json::value const& value, std::string_view key)
{
if (value.is_object() and value.as_object().contains(key))
return Warning{WarningCode::warnRPC_DEPRECATED, fmt::format("Field '{}' is deprecated.", key)};
return std::nullopt;
}
};
/**
* @brief Check if a value of a field is deprecated
* @tparam T The type of the field
*/
template <typename T>
class Deprecated<T> final {
T value_;
public:
/**
* @brief Construct a new Deprecated object
*
* @param val The value that is deprecated
*/
Deprecated(T val) : value_(val)
{
}
/**
* @brief Check if a value of a field is deprecated
*
* @param value The json value to check
* @param key The key to check
* @return A warning if the field is deprecated or std::nullopt otherwise
*/
[[nodiscard]] std::optional<Warning>
check(boost::json::value const& value, std::string_view key) const
{
if (value.is_object() and value.as_object().contains(key) and
validation::checkType<T>(value.as_object().at(key))) {
using boost::json::value_to;
auto const res = value_to<T>(value.as_object().at(key));
if (value_ == res) {
return Warning{
WarningCode::warnRPC_DEPRECATED, fmt::format("Value '{}' for field '{}' is deprecated", value_, key)
};
}
}
return std::nullopt;
}
};
/**
* @brief Deduction guide for Deprecated
*/
template <typename... T>
Deprecated(T&&...) -> Deprecated<T...>;
} // namespace rpc::check

View File

@@ -19,6 +19,8 @@
#pragma once
#include "rpc/Errors.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/Types.hpp"
#include <boost/json/value.hpp>
@@ -26,6 +28,7 @@
#include <boost/json/value_to.hpp>
#include <cstdint>
#include <optional>
#include <string>
namespace rpc {
@@ -52,6 +55,16 @@ concept SomeModifier = requires(T a, boost::json::value lval) {
} -> std::same_as<MaybeError>;
};
/**
* @brief Specifies what a check used with @ref rpc::FieldSpec must provide.
*/
template <typename T>
concept SomeCheck = requires(T a, boost::json::value lval) {
{
a.check(lval, std::string{})
} -> std::same_as<std::optional<check::Warning>>;
};
/**
* @brief The requirements of a processor to be used with @ref rpc::FieldSpec.
*/

View File

@@ -106,7 +106,7 @@ public:
* @param requirements The requirements to validate against
*/
template <SomeRequirement... Requirements>
IfType(Requirements&&... requirements)
explicit IfType(Requirements&&... requirements)
: processor_(
[... r = std::forward<Requirements>(requirements
)](boost::json::value& j, std::string_view key) -> MaybeError {
@@ -133,6 +133,9 @@ public:
{
}
IfType(IfType const&) = default;
IfType(IfType&&) = default;
/**
* @brief Verify that the element is valid according to the stored requirements when type matches.
*

View File

@@ -19,10 +19,18 @@
#include "rpc/common/Specs.hpp"
#include "rpc/Errors.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/Types.hpp"
#include <boost/json/array.hpp>
#include <boost/json/value.hpp>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
namespace rpc {
[[nodiscard]] MaybeError
@@ -31,6 +39,12 @@ FieldSpec::process(boost::json::value& value) const
return processor_(value);
}
[[nodiscard]] check::Warnings
FieldSpec::check(boost::json::value const& value) const
{
return checker_(value);
}
[[nodiscard]] MaybeError
RpcSpec::process(boost::json::value& value) const
{
@@ -42,4 +56,27 @@ RpcSpec::process(boost::json::value& value) const
return {};
}
[[nodiscard]] boost::json::array
RpcSpec::check(boost::json::value const& value) const
{
std::unordered_map<WarningCode, std::vector<std::string>> warnings;
for (auto const& field : fields_) {
auto fieldWarnings = field.check(value);
for (auto& fw : fieldWarnings) {
warnings[fw.warningCode].push_back(std::move(fw.extraMessage));
}
}
boost::json::array result;
for (auto const& [code, messages] : warnings) {
auto warningObject = makeWarning(code);
auto& warningMessage = warningObject["message"].as_string();
for (auto const& message : messages) {
warningMessage.append(" ").append(message);
}
result.push_back(std::move(warningObject));
}
return result;
}
} // namespace rpc

View File

@@ -19,15 +19,17 @@
#pragma once
#include "rpc/common/Checkers.hpp"
#include "rpc/common/Concepts.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/impl/Factories.hpp"
#include <boost/json/array.hpp>
#include <boost/json/value.hpp>
#include <functional>
#include <initializer_list>
#include <string>
#include <utility>
#include <vector>
namespace rpc {
@@ -46,11 +48,26 @@ struct FieldSpec final {
template <SomeProcessor... Processors>
FieldSpec(std::string const& key, Processors&&... processors)
: processor_{impl::makeFieldProcessor<Processors...>(key, std::forward<Processors>(processors)...)}
, checker_{impl::EMPTY_FIELD_CHECKER}
{
}
/**
* @brief Processos the passed JSON value using the stored processors.
* @brief Construct a field specification out of a set of checkers.
*
* @tparam Checks The types of checkers
* @param key The key in a JSON object that the field validates
* @param checks The checks, each of them have to fulfil the @ref rpc::SomeCheck concept
*/
template <SomeCheck... Checks>
FieldSpec(std::string const& key, Checks&&... checks)
: processor_{impl::EMPTY_FIELD_PROCESSOR}
, checker_{impl::makeFieldChecker<Checks...>(key, std::forward<Checks>(checks)...)}
{
}
/**
* @brief Processes the passed JSON value using the stored processors.
*
* @param value The JSON value to validate and/or modify
* @return Nothing on success; @ref Status on error
@@ -58,8 +75,18 @@ struct FieldSpec final {
[[nodiscard]] MaybeError
process(boost::json::value& value) const;
/**
* @brief Checks the passed JSON value using the stored checkers.
*
* @param value The JSON value to validate
* @return A vector of warnings (empty if no warnings)
*/
[[nodiscard]] check::Warnings
check(boost::json::value const& value) const;
private:
std::function<MaybeError(boost::json::value&)> processor_;
impl::FieldSpecProcessor processor_;
impl::FieldChecker checker_;
};
/**
@@ -91,7 +118,7 @@ struct RpcSpec final {
}
/**
* @brief Processos the passed JSON value using the stored field specs.
* @brief Processes the passed JSON value using the stored field specs.
*
* @param value The JSON value to validate and/or modify
* @return Nothing on success; @ref Status on error
@@ -99,6 +126,15 @@ struct RpcSpec final {
[[nodiscard]] MaybeError
process(boost::json::value& value) const;
/**
* @brief Checks the passed JSON value using the stored field specs.
*
* @param value The JSON value to validate
* @return JSON array of warnings (empty if no warnings)
*/
[[nodiscard]] boost::json::array
check(boost::json::value const& value) const;
private:
std::vector<FieldSpec> fields_;
};

View File

@@ -22,6 +22,7 @@
#include "rpc/Errors.hpp"
#include <boost/asio/spawn.hpp>
#include <boost/json/array.hpp>
#include <boost/json/conversion.hpp>
#include <boost/json/object.hpp>
#include <boost/json/value.hpp>
@@ -33,6 +34,7 @@
#include <expected>
#include <memory>
#include <string>
#include <utility>
#include <variant>
namespace etl {
@@ -55,6 +57,21 @@ class Counters;
*/
using MaybeError = std::expected<void, Status>;
/**
* @brief Check if two MaybeError objects are equal
*
* @param lhs The first MaybeError object
* @param rhs The second MaybeError object
* @return true if the two MaybeError objects are equal, false otherwise
*/
inline bool
operator==(MaybeError const& lhs, MaybeError const& rhs)
{
bool const lhsHasError = !static_cast<bool>(lhs);
bool const rhsHasError = !static_cast<bool>(rhs);
return lhsHasError == rhsHasError && (!lhsHasError || lhs.error() == rhs.error());
}
/**
* @brief The type that represents just the error part of @ref MaybeError
*/
@@ -69,7 +86,29 @@ using HandlerReturnType = std::expected<OutputType, Status>;
/**
* @brief The final return type out of RPC engine
*/
using ReturnType = std::expected<boost::json::value, Status>;
struct ReturnType {
/**
* @brief Construct a new Return Type object
*
* @param result The result of the RPC call
* @param warnings The warnings generated by the RPC call
*/
ReturnType(std::expected<boost::json::value, Status> result, boost::json::array warnings = {})
: result{std::move(result)}, warnings{std::move(warnings)}
{
}
/**
* @brief operator bool to check whether the ReturnType contains a response
*/
operator bool() const
{
return result.operator bool();
}
std::expected<boost::json::value, Status> result;
boost::json::array warnings;
};
/**
* @brief An empty type used as Output for handlers than don't actually produce output.
@@ -90,7 +129,43 @@ struct Context {
/**
* @brief Result type used to return responses or error statuses to the Webserver subsystem.
*/
using Result = std::variant<Status, boost::json::object>;
struct Result {
/**
* @brief Construct a new Result object from ReturnType
*
* @param returnType The ReturnType to construct the result from
*/
explicit Result(ReturnType returnType)
{
if (returnType) {
response = std::move(returnType.result).value().as_object();
} else {
response = std::move(returnType.result).error();
}
warnings = std::move(returnType.warnings);
}
/**
* @brief Construct a new Result object from Status
*
* @param status The status to construct the result from
*/
explicit Result(Status status) : response{std::move(status)}
{
}
/**
* @brief Construct a new Result object from a response object
*
* @param response The response to construct the result from
*/
explicit Result(boost::json::object response) : response{std::move(response)}
{
}
std::variant<Status, boost::json::object> response;
boost::json::array warnings;
};
/**
* @brief A cursor object used to traverse nodes owned by an account.

View File

@@ -0,0 +1,70 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2024, 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 <boost/json/array.hpp>
#include <boost/json/object.hpp>
#include <boost/json/value.hpp>
#include <cstdint>
#include <string>
namespace rpc::validation {
/**
* @brief Check that the type is the same as what was expected.
*
* @tparam Expected The expected type that value should be convertible to
* @param value The json value to check the type of
* @return true if convertible; false otherwise
*/
template <typename Expected>
[[nodiscard]] bool static checkType(boost::json::value const& value)
{
auto hasError = false;
if constexpr (std::is_same_v<Expected, bool>) {
if (not value.is_bool())
hasError = true;
} else if constexpr (std::is_same_v<Expected, std::string>) {
if (not value.is_string())
hasError = true;
} else if constexpr (std::is_same_v<Expected, double> or std::is_same_v<Expected, float>) {
if (not value.is_double())
hasError = true;
} else if constexpr (std::is_same_v<Expected, boost::json::array>) {
if (not value.is_array())
hasError = true;
} else if constexpr (std::is_same_v<Expected, boost::json::object>) {
if (not value.is_object())
hasError = true;
} else if constexpr (std::is_convertible_v<Expected, uint64_t> or std::is_convertible_v<Expected, int64_t>) {
if (not value.is_int64() && not value.is_uint64())
hasError = true;
// specify the type is unsigened, it can not be negative
if constexpr (std::is_unsigned_v<Expected>) {
if (value.is_int64() and value.as_int64() < 0)
hasError = true;
}
}
return not hasError;
}
} // namespace rpc::validation

View File

@@ -21,6 +21,7 @@
#include "rpc/Errors.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/ValidationHelpers.hpp"
#include <boost/json/array.hpp>
#include <boost/json/object.hpp>
@@ -38,45 +39,6 @@
namespace rpc::validation {
/**
* @brief Check that the type is the same as what was expected.
*
* @tparam Expected The expected type that value should be convertible to
* @param value The json value to check the type of
* @return true if convertible; false otherwise
*/
template <typename Expected>
[[nodiscard]] bool static checkType(boost::json::value const& value)
{
auto hasError = false;
if constexpr (std::is_same_v<Expected, bool>) {
if (not value.is_bool())
hasError = true;
} else if constexpr (std::is_same_v<Expected, std::string>) {
if (not value.is_string())
hasError = true;
} else if constexpr (std::is_same_v<Expected, double> or std::is_same_v<Expected, float>) {
if (not value.is_double())
hasError = true;
} else if constexpr (std::is_same_v<Expected, boost::json::array>) {
if (not value.is_array())
hasError = true;
} else if constexpr (std::is_same_v<Expected, boost::json::object>) {
if (not value.is_object())
hasError = true;
} else if constexpr (std::is_convertible_v<Expected, uint64_t> or std::is_convertible_v<Expected, int64_t>) {
if (not value.is_int64() && not value.is_uint64())
hasError = true;
// specify the type is unsigened, it can not be negative
if constexpr (std::is_unsigned_v<Expected>) {
if (value.is_int64() and value.as_int64() < 0)
hasError = true;
}
}
return not hasError;
}
/**
* @brief A validator that simply requires a field to be present.
*/

View File

@@ -20,21 +20,31 @@
#pragma once
#include "rpc/Errors.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/Concepts.hpp"
#include "rpc/common/Types.hpp"
#include <boost/json/array.hpp>
#include <boost/json/value.hpp>
#include <expected>
#include <functional>
#include <optional>
#include <string>
#include <utility>
#include <vector>
namespace rpc::impl {
template <typename>
static constexpr bool unsupported_v = false;
using FieldSpecProcessor = std::function<MaybeError(boost::json::value&)>;
static FieldSpecProcessor const EMPTY_FIELD_PROCESSOR = [](boost::json::value&) -> MaybeError { return {}; };
template <SomeProcessor... Processors>
[[nodiscard]] auto
[[nodiscard]] FieldSpecProcessor
makeFieldProcessor(std::string const& key, Processors&&... procs)
{
return [key, ... proc = std::forward<Processors>(procs)](boost::json::value& j) -> MaybeError {
@@ -61,10 +71,32 @@ makeFieldProcessor(std::string const& key, Processors&&... procs)
);
if (firstFailure)
return Error{firstFailure.value()};
return std::unexpected{std::move(firstFailure).value()};
return {};
};
}
using FieldChecker = std::function<check::Warnings(boost::json::value const&)>;
static FieldChecker const EMPTY_FIELD_CHECKER = [](boost::json::value const&) -> check::Warnings { return {}; };
template <SomeCheck... Checks>
[[nodiscard]] FieldChecker
makeFieldChecker(std::string const& key, Checks&&... checks)
{
return [key, ... checks = std::forward<Checks>(checks)](boost::json::value const& j) -> check::Warnings {
check::Warnings warnings;
// This expands in order of Checks and collects all warnings into a WarningsCollection
(
[&j, &key, &warnings, req = &checks]() {
if (auto res = req->check(j, key); res)
warnings.push_back(std::move(res).value());
}(),
...
);
return warnings;
};
}
} // namespace rpc::impl

View File

@@ -91,14 +91,14 @@ public:
auto toForward = ctx.params;
toForward["command"] = ctx.method;
auto const res = balancer_->forwardToRippled(toForward, ctx.clientIp, ctx.yield);
auto res = balancer_->forwardToRippled(toForward, ctx.clientIp, ctx.yield);
if (not res) {
notifyFailedToForward(ctx.method);
return Status{RippledError::rpcFAILED_TO_FORWARD};
return Result{Status{RippledError::rpcFAILED_TO_FORWARD}};
}
notifyForwarded(ctx.method);
return *res;
return Result{std::move(res).value()};
}
bool

View File

@@ -38,27 +38,29 @@ struct DefaultProcessor final {
using boost::json::value_to;
if constexpr (SomeHandlerWithInput<HandlerType>) {
// first we run validation against specified API version
auto const spec = handler.spec(ctx.apiVersion);
auto warnings = spec.check(value);
auto input = value; // copy here, spec require mutable data
if (auto const ret = spec.process(input); not ret)
return Error{ret.error()}; // forward Status
return ReturnType{Error{ret.error()}, std::move(warnings)}; // forward Status
auto const inData = value_to<typename HandlerType::Input>(input);
auto const ret = handler.process(inData, ctx);
auto ret = handler.process(inData, ctx);
// real handler is given expected Input, not json
if (!ret) {
return Error{ret.error()}; // forward Status
return ReturnType{Error{std::move(ret).error()}, std::move(warnings)}; // forward Status
}
return value_from(ret.value());
return ReturnType{value_from(std::move(ret).value()), std::move(warnings)};
} else if constexpr (SomeHandlerWithoutInput<HandlerType>) {
// no input to pass, ignore the value
auto const ret = handler.process(ctx);
if (not ret) {
return Error{ret.error()}; // forward Status
return ReturnType{Error{ret.error()}}; // forward Status
}
return value_from(ret.value());
return ReturnType{value_from(ret.value())};
} else {
// when concept SomeHandlerWithInput and SomeHandlerWithoutInput not cover all Handler case
static_assert(unsupported_handler_v<HandlerType>);

View File

@@ -21,6 +21,7 @@
#include "data/BackendInterface.hpp"
#include "rpc/JS.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/Validators.hpp"
@@ -93,7 +94,9 @@ public:
static auto const rpcSpec = RpcSpec{
{JS(account), validation::Required{}, validation::AccountValidator},
{JS(ledger_hash), validation::Uint256HexStringValidator},
{JS(ledger_index), validation::LedgerIndexValidator}
{JS(ledger_index), validation::LedgerIndexValidator},
{"account_index", check::Deprecated{}},
{JS(strict), check::Deprecated{}}
};
return rpcSpec;

View File

@@ -21,6 +21,7 @@
#include "data/BackendInterface.hpp"
#include "rpc/JS.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/JsonBool.hpp"
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
@@ -131,8 +132,11 @@ public:
static auto const rpcSpecV1 = RpcSpec{
{JS(account), validation::AccountValidator},
{JS(ident), validation::AccountValidator},
{JS(ident), check::Deprecated{}},
{JS(ledger_hash), validation::Uint256HexStringValidator},
{JS(ledger_index), validation::LedgerIndexValidator}
{JS(ledger_index), validation::LedgerIndexValidator},
{JS(ledger), check::Deprecated{}},
{JS(strict), check::Deprecated{}}
};
static auto const rpcSpec = RpcSpec{rpcSpecV1, {{JS(signer_lists), validation::Type<bool>{}}}};

View File

@@ -22,6 +22,7 @@
#include "data/BackendInterface.hpp"
#include "rpc/Errors.hpp"
#include "rpc/JS.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/MetaProcessors.hpp"
#include "rpc/common/Modifiers.hpp"
#include "rpc/common/Types.hpp"
@@ -136,6 +137,8 @@ public:
modifiers::Clamp<int32_t>{LIMIT_MIN, LIMIT_MAX}},
{JS(ledger_index), validation::LedgerIndexValidator},
{JS(marker), validation::AccountMarkerValidator},
{JS(ledger), check::Deprecated{}},
{"peer_index", check::Deprecated{}},
};
return rpcSpec;

View File

@@ -21,6 +21,7 @@
#include "data/BackendInterface.hpp"
#include "rpc/JS.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/Modifiers.hpp"
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
@@ -118,7 +119,9 @@ public:
{JS(limit),
validation::Type<uint32_t>{},
validation::Min(1u),
modifiers::Clamp<int32_t>{LIMIT_MIN, LIMIT_MAX}}
modifiers::Clamp<int32_t>{LIMIT_MIN, LIMIT_MAX}},
{JS(ledger), check::Deprecated{}},
{JS(strict), check::Deprecated{}},
};
return rpcSpec;

View File

@@ -21,6 +21,7 @@
#include "data/BackendInterface.hpp"
#include "rpc/JS.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/Validators.hpp"
@@ -102,7 +103,9 @@ public:
{
static auto const rpcSpec = RpcSpec{
{JS(full), validation::Type<bool>{}, validation::NotSupported{true}},
{JS(full), check::Deprecated{}},
{JS(accounts), validation::Type<bool>{}, validation::NotSupported{true}},
{JS(accounts), check::Deprecated{}},
{JS(owner_funds), validation::Type<bool>{}},
{JS(queue), validation::Type<bool>{}, validation::NotSupported{true}},
{JS(ledger_hash), validation::Uint256HexStringValidator},
@@ -111,6 +114,8 @@ public:
{JS(expand), validation::Type<bool>{}},
{JS(binary), validation::Type<bool>{}},
{"diff", validation::Type<bool>{}},
{JS(ledger), check::Deprecated{}},
{JS(type), check::Deprecated{}},
};
return rpcSpec;

View File

@@ -22,6 +22,7 @@
#include "data/BackendInterface.hpp"
#include "rpc/Errors.hpp"
#include "rpc/JS.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/MetaProcessors.hpp"
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
@@ -128,7 +129,7 @@ public:
validation::Type<std::string>{}, Status{ripple::rpcINVALID_PARAMS, "Invalid field 'type', not string."}
},
validation::OneOf<std::string>(ledgerTypeStrs.cbegin(), ledgerTypeStrs.cend())},
{JS(ledger), check::Deprecated{}},
};
return rpcSpec;
}

View File

@@ -22,6 +22,7 @@
#include "data/BackendInterface.hpp"
#include "rpc/Errors.hpp"
#include "rpc/JS.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/MetaProcessors.hpp"
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
@@ -297,7 +298,8 @@ public:
meta::WithCustomError{
validation::Type<uint32_t>{}, Status(ClioError::rpcMALFORMED_ORACLE_DOCUMENT_ID)
}},
}}}
}}},
{JS(ledger), check::Deprecated{}},
};
return rpcSpec;

View File

@@ -24,6 +24,7 @@
#include "rpc/Errors.hpp"
#include "rpc/JS.hpp"
#include "rpc/RPCHelpers.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/MetaProcessors.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/Validators.hpp"
@@ -122,8 +123,8 @@ public:
* @param apiVersion The api version to return the spec for
* @return The spec for the given apiVersion
*/
RpcSpecConstRef
spec([[maybe_unused]] uint32_t apiVersion) const
static RpcSpecConstRef
spec([[maybe_unused]] uint32_t apiVersion)
{
static auto const booksValidator =
validation::CustomValidator{[](boost::json::value const& value, std::string_view key) -> MaybeError {
@@ -163,6 +164,9 @@ public:
{JS(accounts), validation::SubscribeAccountsValidator},
{JS(accounts_proposed), validation::SubscribeAccountsValidator},
{JS(books), booksValidator},
{"user", check::Deprecated{}},
{JS(password), check::Deprecated{}},
{JS(rt_accounts), check::Deprecated{}}
};
return rpcSpec;

View File

@@ -23,6 +23,7 @@
#include "rpc/Errors.hpp"
#include "rpc/JS.hpp"
#include "rpc/RPCHelpers.hpp"
#include "rpc/common/Checkers.hpp"
#include "rpc/common/Specs.hpp"
#include "rpc/common/Types.hpp"
#include "rpc/common/Validators.hpp"
@@ -98,8 +99,8 @@ public:
* @param apiVersion The api version to return the spec for
* @return The spec for the given apiVersion
*/
RpcSpecConstRef
spec([[maybe_unused]] uint32_t apiVersion) const
static RpcSpecConstRef
spec([[maybe_unused]] uint32_t apiVersion)
{
static auto const booksValidator =
validation::CustomValidator{[](boost::json::value const& value, std::string_view key) -> MaybeError {
@@ -126,6 +127,9 @@ public:
{JS(accounts), validation::SubscribeAccountsValidator},
{JS(accounts_proposed), validation::SubscribeAccountsValidator},
{JS(books), booksValidator},
{JS(url), check::Deprecated{}},
{JS(rt_accounts), check::Deprecated{}},
{"rt_transactions", check::Deprecated{}},
};
return rpcSpec;

View File

@@ -194,7 +194,8 @@ private:
rpc::logDuration(*context, us);
boost::json::object response;
if (auto const status = std::get_if<rpc::Status>(&result)) {
if (auto const status = std::get_if<rpc::Status>(&result.response)) {
// note: error statuses are counted/notified in buildResponse itself
response = web::impl::ErrorHelper(connection, request).composeError(*status);
auto const responseStr = boost::json::serialize(response);
@@ -205,7 +206,7 @@ private:
// This can still technically be an error. Clio counts forwarded requests as successful.
rpcEngine_->notifyComplete(context->method, us);
auto& json = std::get<boost::json::object>(result);
auto& json = std::get<boost::json::object>(result.response);
auto const isForwarded =
json.contains("forwarded") && json.at("forwarded").is_bool() && json.at("forwarded").as_bool();
@@ -246,7 +247,7 @@ private:
}
}
boost::json::array warnings;
boost::json::array warnings = std::move(result.warnings);
warnings.emplace_back(rpc::makeWarning(rpc::warnRPC_CLIO));
if (etl_->lastCloseAgeSeconds() >= 60)