Files
clio/src/rpc/Errors.hpp
Peter Chen 371237487b feat: Support single asset vault (#1979)
fixes #1921

---------

Co-authored-by: Sergey Kuznetsov <skuznetsov@ripple.com>
Co-authored-by: Ayaz Salikhov <mathbunnyru@users.noreply.github.com>
2025-06-27 15:27:34 +01:00

336 lines
8.8 KiB
C++

//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2022, 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.
*/
//==============================================================================
/** @file */
#pragma once
#include <boost/json/object.hpp>
#include <xrpl/protocol/ErrorCodes.h>
#include <exception>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <variant>
namespace rpc {
/** @brief Custom clio RPC Errors. */
enum class ClioError {
// normal clio errors start with 5000
RpcMalformedCurrency = 5000,
RpcMalformedRequest = 5001,
RpcMalformedOwner = 5002,
RpcMalformedAddress = 5003,
RpcUnknownOption = 5005,
RpcFieldNotFoundTransaction = 5006,
RpcMalformedOracleDocumentId = 5007,
RpcMalformedAuthorizedCredentials = 5008,
RpcEntryNotFound = 5009,
// special system errors start with 6000
RpcInvalidApiVersion = 6000,
RpcCommandIsMissing = 6001,
RpcCommandNotString = 6002,
RpcCommandIsEmpty = 6003,
RpcParamsUnparsable = 6004,
// TODO: Since it is not only rpc errors here now, we should move it to util
// etl related errors start with 7000
// Higher value in this errors means better progress in the forwarding
EtlConnectionError = 7000,
EtlRequestError = 7001,
EtlRequestTimeout = 7002,
EtlInvalidResponse = 7003,
};
/** @brief Holds info about a particular @ref ClioError. */
struct ClioErrorInfo {
ClioError const code;
std::string_view const error;
std::string_view const message;
};
/** @brief Clio uses compatible Rippled error codes for most RPC errors. */
using RippledError = ripple::error_code_i;
/**
* @brief Clio operates on a combination of Rippled and Custom Clio error codes.
*
* @see RippledError For rippled error codes
* @see ClioError For custom clio error codes
*/
using CombinedError = std::variant<RippledError, ClioError>;
/** @brief A status returned from any RPC handler. */
struct Status {
CombinedError code = RippledError::rpcSUCCESS;
std::string error;
std::string message;
std::optional<boost::json::object> extraInfo;
Status() = default;
/**
* @brief Construct a new Status object
*
* @param code The error code
*/
/* implicit */ Status(CombinedError code) : code(code) {};
/**
* @brief Construct a new Status object
*
* @param code The error code
* @param extraInfo The extra info
*/
Status(CombinedError code, boost::json::object&& extraInfo) : code(code), extraInfo(std::move(extraInfo)) {};
/**
* @brief Construct a new Status object with a custom message
*
* @note HACK. Some rippled handlers explicitly specify errors. This means that we have to be able to duplicate this
* functionality.
*
* @param message The message
*/
explicit Status(std::string message) : code(ripple::rpcUNKNOWN), message(std::move(message))
{
}
/**
* @brief Construct a new Status object
*
* @param code The error code
* @param message The message
*/
Status(CombinedError code, std::string message) : code(code), message(std::move(message))
{
}
/**
* @brief Construct a new Status object
*
* @param code The error code
* @param error The error
* @param message The message
*/
Status(CombinedError code, std::string error, std::string message)
: code(code), error(std::move(error)), message(std::move(message))
{
}
bool
operator==(Status const& other) const = default;
/**
* @brief Check if the status is not OK
*
* @return true if the status is not OK; false otherwise
*/
operator bool() const
{
if (auto err = std::get_if<RippledError>(&code))
return *err != RippledError::rpcSUCCESS;
return true;
}
/**
* @brief Returns true if the @ref rpc::Status contains the desired @ref rpc::RippledError
*
* @param other The @ref rpc::RippledError to match
* @return true if status matches given error; false otherwise
*/
bool
operator==(RippledError other) const
{
if (auto err = std::get_if<RippledError>(&code))
return *err == other;
return false;
}
/**
* @brief Returns true if the Status contains the desired @ref ClioError
*
* @param other The RippledError to match
* @return true if status matches given error; false otherwise
*/
bool
operator==(ClioError other) const
{
if (auto err = std::get_if<ClioError>(&code))
return *err == other;
return false;
}
};
/** @brief Warning codes that can be returned by clio. */
enum WarningCode {
WarnUnknown = -1,
WarnRpcClio = 2001,
WarnRpcOutdated = 2002,
WarnRpcRateLimit = 2003,
WarnRpcDeprecated = 2004
};
/** @brief Holds information about a clio warning. */
struct WarningInfo {
constexpr WarningInfo() = default;
/**
* @brief Construct a new Warning Info object
*
* @param code The warning code
* @param message The warning message
*/
constexpr WarningInfo(WarningCode code, char const* message) : code(code), message(message)
{
}
WarningCode code = WarnUnknown;
std::string_view const message = "unknown warning";
};
/** @brief Invalid parameters error. */
class InvalidParamsError : public std::exception {
std::string msg_;
public:
/**
* @brief Construct a new Invalid Params Error object
*
* @param msg The error message
*/
explicit InvalidParamsError(std::string msg) : msg_(std::move(msg))
{
}
/**
* @brief Get the error message as a C string
*
* @return The error message
*/
char const*
what() const throw() override
{
return msg_.c_str();
}
};
/** @brief Account not found error. */
class AccountNotFoundError : public std::exception {
std::string account_;
public:
/**
* @brief Construct a new Account Not Found Error object
*
* @param acct The account
*/
explicit AccountNotFoundError(std::string acct) : account_(std::move(acct))
{
}
/**
* @brief Get the error message as a C string
*
* @return The error message
*/
char const*
what() const throw() override
{
return account_.c_str();
}
};
/** @brief A globally available @ref rpc::Status that represents a successful state. */
static Status gOk;
/**
* @brief Get the warning info object from a warning code.
*
* @param code The warning code
* @return A reference to the static warning info
*/
WarningInfo const&
getWarningInfo(WarningCode code);
/**
* @brief Get the error info object from an clio-specific error code.
*
* @param code The error code
* @return A reference to the static error info
*/
ClioErrorInfo const&
getErrorInfo(ClioError code);
/**
* @brief Generate JSON from a @ref rpc::WarningCode.
*
* @param code The warning code
* @return The JSON output
*/
boost::json::object
makeWarning(WarningCode code);
/**
* @brief Generate JSON from a @ref rpc::Status.
*
* @param status The status object
* @return The JSON output
*/
boost::json::object
makeError(Status const& status);
/**
* @brief Generate JSON from a @ref rpc::RippledError.
*
* @param err The rippled error
* @param customError A custom error
* @param customMessage A custom message
* @return The JSON output
*/
boost::json::object
makeError(
RippledError err,
std::optional<std::string_view> customError = std::nullopt,
std::optional<std::string_view> customMessage = std::nullopt
);
/**
* @brief Generate JSON from a @ref rpc::ClioError.
*
* @param err The clio's custom error
* @param customError A custom error
* @param customMessage A custom message
* @return The JSON output
*/
boost::json::object
makeError(
ClioError err,
std::optional<std::string_view> customError = std::nullopt,
std::optional<std::string_view> customMessage = std::nullopt
);
} // namespace rpc