From 6b3091a4567772da36230704598c91c05a7ce38a Mon Sep 17 00:00:00 2001 From: CJ Cobb Date: Tue, 21 Sep 2021 12:15:10 -0400 Subject: [PATCH] Add server_info. Make forwardToRippled return optional --- src/etl/ETLSource.cpp | 32 ++++++++++----------------- src/etl/ETLSource.h | 6 ++--- src/rpc/RPC.cpp | 4 ++-- src/rpc/handlers/ServerInfo.cpp | 31 +++++++++++++++++++++++++- src/webserver/SubscriptionManager.cpp | 3 +-- 5 files changed, 48 insertions(+), 28 deletions(-) diff --git a/src/etl/ETLSource.cpp b/src/etl/ETLSource.cpp index c8926292..9e7d5ad1 100644 --- a/src/etl/ETLSource.cpp +++ b/src/etl/ETLSource.cpp @@ -647,29 +647,21 @@ ETLLoadBalancer::getRippledForwardingStub() const return nullptr; } -boost::json::object +std::optional ETLLoadBalancer::forwardToRippled(boost::json::object const& request) const { - boost::json::object res; - if (sources_.size() == 0) - return res; srand((unsigned)time(0)); auto sourceIdx = rand() % sources_.size(); auto numAttempts = 0; while (numAttempts < sources_.size()) { - res = sources_[sourceIdx]->forwardToRippled(request); + if (auto res = sources_[sourceIdx]->forwardToRippled(request)) + return res; - if (!res.contains("forwarded") || res.at("forwarded") != true) - { - sourceIdx = (sourceIdx + 1) % sources_.size(); - ++numAttempts; - continue; - } - return res; + sourceIdx = (sourceIdx + 1) % sources_.size(); + ++numAttempts; } - res["error"] = "Failed to forward"; - return res; + return {}; } std::unique_ptr @@ -693,7 +685,7 @@ ETLSource::getRippledForwardingStub() const } } -boost::json::object +std::optional ETLSource::forwardToRippled(boost::json::object const& request) const { BOOST_LOG_TRIVIAL(debug) << "Attempting to forward request to tx. " @@ -704,7 +696,7 @@ ETLSource::forwardToRippled(boost::json::object const& request) const { BOOST_LOG_TRIVIAL(error) << "Attempted to proxy but failed to connect to tx"; - return response; + return {}; } namespace beast = boost::beast; // from namespace http = beast::http; // from @@ -764,9 +756,9 @@ ETLSource::forwardToRippled(boost::json::object const& request) const if (!parsed.is_object()) { - BOOST_LOG_TRIVIAL(error) << "Error parsing response"; - response["error"] = "Error parsing response from tx"; - return response; + BOOST_LOG_TRIVIAL(error) + << "Error parsing response: " << std::string{begin, end}; + return {}; } BOOST_LOG_TRIVIAL(debug) << "Successfully forward request"; @@ -778,7 +770,7 @@ ETLSource::forwardToRippled(boost::json::object const& request) const catch (std::exception const& e) { BOOST_LOG_TRIVIAL(error) << "Encountered exception : " << e.what(); - return response; + return {}; } } diff --git a/src/etl/ETLSource.h b/src/etl/ETLSource.h index cd63c691..85260231 100644 --- a/src/etl/ETLSource.h +++ b/src/etl/ETLSource.h @@ -29,8 +29,8 @@ #include #include "org/xrpl/rpc/v1/xrp_ledger.grpc.pb.h" -#include #include +#include class ETLLoadBalancer; class SubscriptionManager; @@ -321,7 +321,7 @@ public: std::unique_ptr getRippledForwardingStub() const; - boost::json::object + std::optional forwardToRippled(boost::json::object const& request) const; }; /// This class is used to manage connections to transaction processing processes @@ -428,7 +428,7 @@ public: /// Forward a JSON RPC request to a randomly selected rippled node /// @param request JSON-RPC request /// @return response received from rippled node - boost::json::object + std::optional forwardToRippled(boost::json::object const& request) const; private: diff --git a/src/rpc/RPC.cpp b/src/rpc/RPC.cpp index 02319ef8..8ea88905 100644 --- a/src/rpc/RPC.cpp +++ b/src/rpc/RPC.cpp @@ -152,9 +152,9 @@ buildResponse(Context const& ctx) if (shouldForwardToRippled(ctx)) { auto res = ctx.balancer->forwardToRippled(ctx.params); - if (res.size() == 0) + if (!res) return Status{Error::rpcFAILED_TO_FORWARD}; - return res; + return *res; } if (ctx.method == "ping") return boost::json::object{}; diff --git a/src/rpc/handlers/ServerInfo.cpp b/src/rpc/handlers/ServerInfo.cpp index 6b444518..c46714e8 100644 --- a/src/rpc/handlers/ServerInfo.cpp +++ b/src/rpc/handlers/ServerInfo.cpp @@ -1,5 +1,6 @@ #include +#include #include namespace RPC { @@ -12,7 +13,10 @@ doServerInfo(Context const& context) auto range = context.backend->fetchLedgerRange(); if (!range) { - return Status{Error::rpcNOT_READY, "rangeNotFound"}; + return Status{ + Error::rpcNOT_READY, + "emptyDatabase", + "The server has no data in the database"}; } else { @@ -21,6 +25,31 @@ doServerInfo(Context const& context) std::to_string(range->minSequence) + " - " + std::to_string(range->maxSequence); } + + auto serverInfoRippled = context.balancer->forwardToRippled(context.params); + if (serverInfoRippled && !serverInfoRippled->contains("error")) + response["info"].as_object()["load_factor"] = 1; + + auto lgrInfo = context.backend->fetchLedgerBySequence(range->maxSequence); + assert(lgrInfo.has_value()); + auto age = std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch()) + .count() - + lgrInfo->closeTime.time_since_epoch().count() - 946684800; + auto& validatedLgr = + (response["validated_ledger"] = boost::json::object{}).as_object(); + validatedLgr["age"] = age; + validatedLgr["hash"] = ripple::strHex(lgrInfo->hash); + validatedLgr["seq"] = lgrInfo->seq; + auto fees = context.backend->fetchFees(lgrInfo->seq); + assert(fees.has_value()); + validatedLgr["base_fee_xrp"] = fees->base.decimalXRP(); + validatedLgr["reserve_base_xrp"] = fees->reserve.decimalXRP(); + validatedLgr["reserve_inc_xrp"] = fees->increment.decimalXRP(); + + response["note"] = + "This is a clio server. If you want to talk to rippled, include " + "\"ledger_index\":\"current\" in your request"; return response; } } // namespace RPC diff --git a/src/webserver/SubscriptionManager.cpp b/src/webserver/SubscriptionManager.cpp index ef220e5a..1301895f 100644 --- a/src/webserver/SubscriptionManager.cpp +++ b/src/webserver/SubscriptionManager.cpp @@ -18,8 +18,7 @@ getLedgerPubMessage( pubMsg["fee_ref"] = RPC::toBoostJson(fees.units.jsonClipped()); pubMsg["fee_base"] = RPC::toBoostJson(fees.base.jsonClipped()); - pubMsg["reserve_base"] = - RPC::toBoostJson(fees.accountReserve(0).jsonClipped()); + pubMsg["reserve_base"] = RPC::toBoostJson(fees.reserve.jsonClipped()); pubMsg["reserve_inc"] = RPC::toBoostJson(fees.increment.jsonClipped()); pubMsg["validated_ledgers"] = ledgerRange;