Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion conan.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"requires": [
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1782392402.122708",
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1782392402.420688",
"xrpl-rpc-spec/0.1.6#0147dce06088874791dca62dc8503b6c%1787751048.16847",
"xrpl-rpc-spec/0.1.7#774d2f93c4b48a1523d8d5a94a2b082a%1787768955.574105",
"xrpl/3.3.0#5e356a24ae1f0d6da6bd617b926f92e6%1786467262.262007",
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1782392403.185447",
"spdlog/1.17.0#bcbaaf7147bda6ad24ffbd1ac3d7142c%1782736610.443882",
Expand Down
2 changes: 1 addition & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ClioConan(ConanFile):
"fmt/12.1.0",
"libbacktrace/cci.20210118",
"spdlog/1.17.0",
"xrpl-rpc-spec/0.1.6",
"xrpl-rpc-spec/0.1.7",
"xrpl/3.3.0",
]

Expand Down
1 change: 1 addition & 0 deletions src/app/WebHandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include <boost/asio/spawn.hpp>
#include <boost/beast/http/status.hpp>
#include <rpcspec/Errors.hpp>

#include <functional>
#include <memory>
Expand Down
2 changes: 1 addition & 1 deletion src/etl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ target_sources(
impl/ext/Successor.cpp
)

target_link_libraries(clio_etl PUBLIC clio_data clio_util)
target_link_libraries(clio_etl PUBLIC clio_data clio_util rpcspec::rpcspec)
4 changes: 2 additions & 2 deletions src/etl/LoadBalancer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
#include "etl/NetworkValidatedLedgersInterface.hpp"
#include "etl/Source.hpp"
#include "feed/SubscriptionManagerInterface.hpp"
#include "rpc/Errors.hpp"
#include "util/Assert.hpp"
#include "util/CoroutineGroup.hpp"
#include "util/Profiler.hpp"
Expand All @@ -27,6 +26,7 @@
#include <boost/json/value.hpp>
#include <boost/json/value_to.hpp>
#include <fmt/format.h>
#include <rpcspec/Errors.hpp>

#include <algorithm>
#include <chrono>
Expand Down Expand Up @@ -292,7 +292,7 @@ LoadBalancer::forwardToRippled(
auto xUserValue = isAdmin ? kAdminForwardingXUserValue : kUserForwardingXUserValue;

std::optional<boost::json::object> response;
rpc::ClioError error = rpc::ClioError::EtlConnectionError;
rpc::ClioError error = rpc::ClioError::RpcForwardingConnectionError;
while (numAttempts < sources_.size()) {
auto [res, duration] = util::timed([&]() {
return sources_[sourceIdx]->forwardToRippled(request, clientIp, xUserValue, yield);
Expand Down
2 changes: 1 addition & 1 deletion src/etl/Source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include "etl/LoadBalancerInterface.hpp"
#include "etl/NetworkValidatedLedgersInterface.hpp"
#include "feed/SubscriptionManagerInterface.hpp"
#include "rpc/Errors.hpp"
#include "util/config/ObjectView.hpp"

#include <boost/asio/io_context.hpp>
Expand All @@ -13,6 +12,7 @@
#include <boost/uuid/uuid.hpp>
#include <grpcpp/support/status.h>
#include <org/xrpl/rpc/v1/get_ledger.pb.h>
#include <rpcspec/Errors.hpp>

#include <chrono>
#include <cstdint>
Expand Down
12 changes: 6 additions & 6 deletions src/etl/impl/ForwardingSource.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "etl/impl/ForwardingSource.hpp"

#include "rpc/Errors.hpp"
#include "util/log/Logger.hpp"

#include <boost/asio/spawn.hpp>
Expand All @@ -10,6 +9,7 @@
#include <boost/json/parse.hpp>
#include <boost/json/serialize.hpp>
#include <fmt/format.h>
#include <rpcspec/Errors.hpp>

#include <chrono>
#include <exception>
Expand Down Expand Up @@ -58,25 +58,25 @@ ForwardingSource::forwardToRippled(
auto expectedConnection = connectionBuilder.connect(yield);
if (not expectedConnection) {
LOG(log_.debug()) << "Couldn't connect to rippled to forward request.";
return std::unexpected{rpc::ClioError::EtlConnectionError};
return std::unexpected{rpc::ClioError::RpcForwardingConnectionError};
}
auto& connection = expectedConnection.value();

auto writeError = connection->write(boost::json::serialize(request), yield, forwardingTimeout_);
if (writeError) {
LOG(log_.debug()) << "Error sending request to rippled to forward request.";
return std::unexpected{rpc::ClioError::EtlRequestError};
return std::unexpected{rpc::ClioError::RpcForwardingRequestError};
}

auto response = connection->read(yield, forwardingTimeout_);
if (not response) {
if (auto errorCode = response.error().errorCode();
errorCode.has_value() and errorCode->value() == boost::system::errc::timed_out) {
LOG(log_.debug()) << "Request to rippled timed out";
return std::unexpected{rpc::ClioError::EtlRequestTimeout};
return std::unexpected{rpc::ClioError::RpcForwardingTimeout};
}
LOG(log_.debug()) << "Error sending request to rippled to forward request.";
return std::unexpected{rpc::ClioError::EtlRequestError};
return std::unexpected{rpc::ClioError::RpcForwardingRequestError};
}

boost::json::value parsedResponse;
Expand All @@ -87,7 +87,7 @@ ForwardingSource::forwardToRippled(
} catch (std::exception const& e) {
LOG(log_.debug()) << "Error parsing response from rippled: " << e.what()
<< ". Response: " << *response;
return std::unexpected{rpc::ClioError::EtlInvalidResponse};
return std::unexpected{rpc::ClioError::RpcForwardingInvalidResponse};
}

auto responseObject = parsedResponse.as_object();
Expand Down
2 changes: 1 addition & 1 deletion src/etl/impl/ForwardingSource.hpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#pragma once

#include "rpc/Errors.hpp"
#include "util/log/Logger.hpp"
#include "util/requests/WsConnection.hpp"

#include <boost/asio/spawn.hpp>
#include <boost/json/object.hpp>
#include <rpcspec/Errors.hpp>

#include <chrono>
#include <expected>
Expand Down
2 changes: 1 addition & 1 deletion src/etl/impl/SourceImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
#include "etl/impl/ForwardingSource.hpp"
#include "etl/impl/GrpcSource.hpp"
#include "etl/impl/SubscriptionSource.hpp"
#include "rpc/Errors.hpp"

#include <boost/asio/spawn.hpp>
#include <boost/json/object.hpp>
#include <grpcpp/support/status.h>
#include <org/xrpl/rpc/v1/get_ledger.pb.h>
#include <rpcspec/Errors.hpp>

#include <chrono>
#include <cstdint>
Expand Down
2 changes: 1 addition & 1 deletion src/feed/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ target_sources(
impl/SingleFeedBase.cpp
)

target_link_libraries(clio_feed PRIVATE clio_util)
target_link_libraries(clio_feed PRIVATE clio_util rpcspec::rpcspec)
2 changes: 1 addition & 1 deletion src/rpc/CredentialHelpers.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#include "data/BackendInterface.hpp"
#include "rpc/Errors.hpp"
#include "rpc/JS.hpp"
#include "rpc/common/Types.hpp"
#include "util/Assert.hpp"

#include <boost/asio/spawn.hpp>
#include <boost/json/array.hpp>
#include <boost/json/value_to.hpp>
#include <rpcspec/Errors.hpp>
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/StringUtilities.h>
#include <xrpl/basics/base_uint.h>
Expand Down
190 changes: 101 additions & 89 deletions src/rpc/Errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
#include "util/OverloadSet.hpp"

#include <boost/json/object.hpp>
#include <rpcspec/Errors.hpp>
#include <xrpl/protocol/ErrorCodes.h>
#include <xrpl/protocol/jss.h>

#include <algorithm>
#include <array>
#include <cstdint>
#include <iterator>
#include <optional>
Expand All @@ -22,6 +24,16 @@ using namespace std;

namespace rpc {

/**
* @brief Stream a Status in human readable form.
*
* Declared in rpcspec but implemented here: rendering a code needs Clio's
* getErrorInfo table and xrpl::RPC::getErrorInfo.
*
* @param stream The stream to write to
* @param status The status to write
* @return The same stream
*/
std::ostream&
operator<<(std::ostream& stream, Status const& status)
{
Expand Down Expand Up @@ -57,100 +69,100 @@ operator<<(std::ostream& stream, Status const& status)
return stream;
}

WarningInfo const&
getWarningInfo(WarningCode code)
{
static constexpr WarningInfo kInfos[]{
{WarningCode::WarnUnknown, "Unknown warning"},
{WarningCode::WarnRpcClio,
"This is a clio server. clio only serves validated data. If you want to talk to rippled, "
"include "
"'ledger_index':'current' in your request"},
{WarningCode::WarnRpcOutdated, "This server may be out of date"},
{WarningCode::WarnRpcRateLimit, "You are about to be rate limited"},
{WarningCode::WarnRpcDeprecated,
"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; };
if (auto it = ranges::find_if(kInfos, matchByCode); it != end(kInfos))
return *it;

throw(out_of_range("Invalid WarningCode"));
}

boost::json::object
makeWarning(WarningCode code)
{
auto json = boost::json::object{};
auto const& info = getWarningInfo(code);
json["id"] = static_cast<int>(code);
json["message"] = info.message;
return json;
}

ClioErrorInfo const&
getErrorInfo(ClioError code)
{
static constexpr ClioErrorInfo kInfos[]{
{.code = ClioError::RpcMalformedCurrency,
.error = "malformedCurrency",
.message = "Malformed currency."},
{.code = ClioError::RpcMalformedRequest,
.error = "malformedRequest",
.message = "Malformed request."},
{.code = ClioError::RpcMalformedOwner,
.error = "malformedOwner",
.message = "Malformed owner."},
{.code = ClioError::RpcMalformedAddress,
.error = "malformedAddress",
.message = "Malformed address."},
{.code = ClioError::RpcUnknownOption,
.error = "unknownOption",
.message = "Unknown option."},
{.code = ClioError::RpcFieldNotFoundTransaction,
.error = "fieldNotFoundTransaction",
.message = "Missing field."},
{.code = ClioError::RpcMalformedOracleDocumentId,
.error = "malformedDocumentID",
.message = "Malformed oracle_document_id."},
{.code = ClioError::RpcMalformedAuthorizedCredentials,
.error = "malformedAuthorizedCredentials",
.message = "Malformed authorized credentials."},
static constexpr auto kInfos = std::to_array<ClioErrorInfo>({
{
.code = ClioError::RpcMalformedCurrency,
.error = "malformedCurrency",
.message = "Malformed currency.",
},
{
.code = ClioError::RpcMalformedRequest,
.error = "malformedRequest",
.message = "Malformed request.",
},
{
.code = ClioError::RpcMalformedOwner,
.error = "malformedOwner",
.message = "Malformed owner.",
},
{
.code = ClioError::RpcMalformedAddress,
.error = "malformedAddress",
.message = "Malformed address.",
},
{
.code = ClioError::RpcUnknownOption,
.error = "unknownOption",
.message = "Unknown option.",
},
{
.code = ClioError::RpcFieldNotFoundTransaction,
.error = "fieldNotFoundTransaction",
.message = "Missing field.",
},
{
.code = ClioError::RpcMalformedOracleDocumentId,
.error = "malformedDocumentID",
.message = "Malformed oracle_document_id.",
},
{
.code = ClioError::RpcMalformedAuthorizedCredentials,
.error = "malformedAuthorizedCredentials",
.message = "Malformed authorized credentials.",
},
// special system errors
{.code = ClioError::RpcInvalidApiVersion,
.error = JS(invalid_API_version),
.message = "Invalid API version."},
{.code = ClioError::RpcCommandIsMissing,
.error = JS(missingCommand),
.message = "Method is not specified or is not a string."},
{.code = ClioError::RpcCommandNotString,
.error = "commandNotString",
.message = "Method is not a string."},
{.code = ClioError::RpcCommandIsEmpty,
.error = "emptyCommand",
.message = "Method is an empty string."},
{.code = ClioError::RpcParamsUnparsable,
.error = "paramsUnparsable",
.message = "Params must be an array holding exactly one object."},
// etl related errors
{.code = ClioError::EtlConnectionError,
.error = "connectionError",
.message = "Couldn't connect to rippled."},
{.code = ClioError::EtlRequestError,
.error = "requestError",
.message = "Error sending request to rippled."},
{.code = ClioError::EtlRequestTimeout,
.error = "timeout",
.message = "Request to rippled timed out."},
{.code = ClioError::EtlInvalidResponse,
.error = "invalidResponse",
.message = "Rippled returned an invalid response."}
};
{
.code = ClioError::RpcInvalidApiVersion,
.error = JS(invalid_API_version),
.message = "Invalid API version.",
},
{
.code = ClioError::RpcCommandIsMissing,
.error = JS(missingCommand),
.message = "Method is not specified or is not a string.",
},
{
.code = ClioError::RpcCommandNotString,
.error = "commandNotString",
.message = "Method is not a string.",
},
{
.code = ClioError::RpcCommandIsEmpty,
.error = "emptyCommand",
.message = "Method is an empty string.",
},
{
.code = ClioError::RpcParamsUnparsable,
.error = "paramsUnparsable",
.message = "Params must be an array holding exactly one object.",
},
// errors from forwarding to an upstream rippled source
{
.code = ClioError::RpcForwardingConnectionError,
.error = "connectionError",
.message = "Couldn't connect to rippled.",
},
{
.code = ClioError::RpcForwardingRequestError,
.error = "requestError",
.message = "Error sending request to rippled.",
},
{
.code = ClioError::RpcForwardingTimeout,
.error = "timeout",
.message = "Request to rippled timed out.",
},
{
.code = ClioError::RpcForwardingInvalidResponse,
.error = "invalidResponse",
.message = "Rippled returned an invalid response.",
},
});

auto matchByCode = [code](auto const& info) { return info.code == code; };
if (auto it = ranges::find_if(kInfos, matchByCode); it != end(kInfos))
if (auto it = ranges::find(kInfos, code, &ClioErrorInfo::code); it != end(kInfos))
return *it;

throw(out_of_range("Invalid error code"));
Expand Down
Loading
Loading