This commit is contained in:
CJ Cobb
2021-08-02 15:49:09 -04:00
parent 26530b0cfa
commit 56e81eb1d8
42 changed files with 382 additions and 666 deletions

View File

@@ -68,39 +68,37 @@ target_sources(clio PRIVATE
src/backend/BackendInterface.cpp
src/backend/Pg.cpp
src/backend/DBHelpers.cpp
## Reporting
## ETL
src/etl/ETLSource.cpp
src/etl/ReportingETL.cpp
## Server
src/webserver/SubscriptionManager.cpp
## Handlers
src/handlers/Status.cpp
src/handlers/RPCHelpers.cpp
src/handlers/Handlers.cpp
src/handlers/Context.cpp
## Methods
## RPC
src/rpc/RPC.cpp
src/rpc/RPCHelpers.cpp
## RPC Methods
# Account
src/handlers/methods/impl/AccountChannels.cpp
src/handlers/methods/impl/AccountCurrencies.cpp
src/handlers/methods/impl/AccountInfo.cpp
src/handlers/methods/impl/AccountLines.cpp
src/handlers/methods/impl/AccountOffers.cpp
src/handlers/methods/impl/AccountObjects.cpp
src/rpc/handlers/AccountChannels.cpp
src/rpc/handlers/AccountCurrencies.cpp
src/rpc/handlers/AccountInfo.cpp
src/rpc/handlers/AccountLines.cpp
src/rpc/handlers/AccountOffers.cpp
src/rpc/handlers/AccountObjects.cpp
# Ledger
src/handlers/methods/impl/Ledger.cpp
src/handlers/methods/impl/LedgerData.cpp
src/handlers/methods/impl/LedgerEntry.cpp
src/handlers/methods/impl/LedgerRange.cpp
src/rpc/handlers/Ledger.cpp
src/rpc/handlers/LedgerData.cpp
src/rpc/handlers/LedgerEntry.cpp
src/rpc/handlers/LedgerRange.cpp
# Transaction
src/handlers/methods/impl/Tx.cpp
src/handlers/methods/impl/AccountTx.cpp
src/rpc/handlers/Tx.cpp
src/rpc/handlers/AccountTx.cpp
# Dex
src/handlers/methods/impl/BookOffers.cpp
src/rpc/handlers/BookOffers.cpp
# Payment Channel
src/handlers/methods/impl/ChannelAuthorize.cpp
src/handlers/methods/impl/ChannelVerify.cpp
src/rpc/handlers/ChannelAuthorize.cpp
src/rpc/handlers/ChannelVerify.cpp
# Subscribe
src/handlers/methods/impl/Subscribe.cpp)
src/rpc/handlers/Subscribe.cpp)
message(${Boost_LIBRARIES})

View File

@@ -7,6 +7,7 @@
"contact_points":"127.0.0.1",
"port":9042,
"keyspace":"clio",
"replication_factor":1,
"table_prefix":"",
"max_requests_outstanding":25000,
"threads":8
@@ -22,7 +23,7 @@
[
{
"ip":"127.0.0.1",
"ws_port":"6005",
"ws_port":"6006",
"grpc_port":"50051"
}
],
@@ -37,5 +38,5 @@
"log_level":"debug",
"online_delete":0,
"extractor_threads":8,
"read_only":false
"read_only":true
}

View File

@@ -15,7 +15,7 @@ processAsyncWriteResponse(T& requestParams, CassFuture* fut, F func)
auto wait = std::chrono::milliseconds(
lround(std::pow(2, std::min(10u, requestParams.currentRetries))));
BOOST_LOG_TRIVIAL(error)
<< "ERROR!!! Cassandra ETL insert error: " << rc << ", "
<< "ERROR!!! Cassandra write error: " << rc << ", "
<< cass_error_desc(rc) << ", retrying in " << wait.count()
<< " milliseconds";
++requestParams.currentRetries;

View File

@@ -1051,9 +1051,8 @@ public:
{
std::stringstream ss;
ss << "Cassandra executeSyncRead error";
ss << ", retrying";
ss << ": " << cass_error_desc(rc);
BOOST_LOG_TRIVIAL(warning) << ss.str();
BOOST_LOG_TRIVIAL(error) << ss.str();
}
if (isTimeout(rc))
{

View File

@@ -1,71 +0,0 @@
#include <handlers/Context.h>
namespace RPC
{
std::optional<Context>
make_WsContext(
boost::json::object const& request,
std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
std::shared_ptr<ETLLoadBalancer> const& balancer,
std::shared_ptr<WsBase> const& session,
Backend::LedgerRange const& range)
{
if (!request.contains("command"))
return {};
std::string command = request.at("command").as_string().c_str();
return Context{
command,
1,
request,
backend,
subscriptions,
balancer,
session,
range
};
}
std::optional<Context>
make_HttpContext(
boost::json::object const& request,
std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
std::shared_ptr<ETLLoadBalancer> const& balancer,
Backend::LedgerRange const& range)
{
if (!request.contains("method") || !request.at("method").is_string())
return {};
std::string const& command = request.at("method").as_string().c_str();
if (command == "subscribe" || command == "unsubscribe")
return {};
if (!request.contains("params") || !request.at("params").is_array())
return {};
boost::json::array const& array = request.at("params").as_array();
if (array.size() != 1)
return {};
if (!array.at(0).is_object())
return {};
return Context{
command,
1,
array.at(0).as_object(),
backend,
subscriptions,
balancer,
nullptr,
range
};
}
} // namespace RPC

View File

@@ -1,77 +0,0 @@
#include <etl/ETLSource.h>
#include <handlers/Handlers.h>
#include <handlers/methods/Account.h>
#include <handlers/methods/Channel.h>
#include <handlers/methods/Exchange.h>
#include <handlers/methods/Ledger.h>
#include <handlers/methods/Subscribe.h>
#include <handlers/methods/Transaction.h>
namespace RPC {
static std::unordered_map<std::string, std::function<Result(Context const&)>>
handlerTable{
{"account_channels", &doAccountChannels},
{"account_currencies", &doAccountCurrencies},
{"account_info", &doAccountInfo},
{"account_lines", &doAccountLines},
{"account_objects", &doAccountObjects},
{"account_offers", &doAccountOffers},
{"account_tx", &doAccountTx},
{"book_offers", &doBookOffers},
{"channel_authorize", &doChannelAuthorize},
{"channel_verify", &doChannelVerify},
{"ledger", &doLedger},
{"ledger_data", &doLedgerData},
{"ledger_entry", &doLedgerEntry},
{"ledger_range", &doLedgerRange},
{"ledger_data", &doLedgerData},
{"subscribe", &doSubscribe},
{"unsubscribe", &doUnsubscribe},
{"tx", &doTx},
};
static std::unordered_set<std::string> forwardCommands{
"submit",
"submit_multisigned",
"fee",
"path_find",
"ripple_path_find",
"manifest"};
bool
shouldForwardToRippled(Context const& ctx)
{
auto request = ctx.params;
if (forwardCommands.find(ctx.method) != forwardCommands.end())
return true;
if (request.contains("ledger_index"))
{
auto indexValue = request.at("ledger_index");
if (indexValue.is_string())
{
std::string index = indexValue.as_string().c_str();
return index == "current" || index == "closed";
}
}
return false;
}
Result
buildResponse(Context const& ctx)
{
if (shouldForwardToRippled(ctx))
return ctx.balancer->forwardToRippled(ctx.params);
if (handlerTable.find(ctx.method) == handlerTable.end())
return Status{Error::rpcUNKNOWN_COMMAND};
auto method = handlerTable[ctx.method];
return method(ctx);
}
} // namespace RPC

View File

@@ -1,29 +0,0 @@
#include <handlers/Context.h>
#include <handlers/Status.h>
#include <unordered_map>
#include <functional>
#include <iostream>
#ifndef RIPPLE_REPORTING_HANDLERS_H
#define RIPPLE_REPORTING_HANDLERS_H
namespace RPC
{
// Maximum and minimum supported API versions
// Defaults to APIVersionIfUnspecified
constexpr unsigned int APIVersionIfUnspecified = 1;
constexpr unsigned int ApiMinimumSupportedVersion = 1;
constexpr unsigned int ApiMaximumSupportedVersion = 1;
constexpr unsigned int APINumberVersionSupported =
ApiMaximumSupportedVersion - ApiMinimumSupportedVersion + 1;
static_assert(ApiMinimumSupportedVersion >= APIVersionIfUnspecified);
static_assert(ApiMaximumSupportedVersion >= ApiMinimumSupportedVersion);
Result
buildResponse(Context const& ctx);
} // namespace RPC
#endif // RIPPLE_REPORTING_HANDLERS_H

View File

@@ -1,10 +0,0 @@
This folder contains all of the RPC handlers.
Generally, handlers parse the request and call the appropriate method of `BackendInterface`
to read from the database.
Certain RPCs, such as `fee` and `submit`, are just forwarded to `rippled`, and the response
is propagated back to the client.
If the database returns a timeout, an error is returned to the client.
This automatically happens, and is caught at a higher level, outside of the handler.

View File

@@ -1,62 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2021 Ripple Labs Inc.
Permission to use, copy, modify, and/or 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.
*/
//==============================================================================
#include <handlers/Status.h>
#include <unordered_map>
#include <variant>
namespace RPC
{
void
inject_error(Error err, boost::json::object& json)
{
ripple::RPC::ErrorInfo const& info(ripple::RPC::get_error_info(err));
json["error"] = info.token;
json["error_code"] = static_cast<std::uint32_t>(err);
json["error_message"] = info.message;
json["status"] = "error";
json["type"] = "response";
}
void
inject_error(Error err, std::string const& message, boost::json::object& json)
{
ripple::RPC::ErrorInfo const& info(ripple::RPC::get_error_info(err));
json["error"] = info.token;
json["error_code"] = static_cast<std::uint32_t>(err);
json["error_message"] = message;
json["status"] = "error";
json["type"] = "response";
}
boost::json::object
make_error(Error err)
{
boost::json::object json{};
inject_error(err, json);
return json;
}
boost::json::object
make_error(Error err, std::string const& message)
{
boost::json::object json{};
inject_error(err, message, json);
return json;
}
}

View File

@@ -1,72 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2021 Ripple Labs Inc.
Permission to use, copy, modify, and/or 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.
*/
//==============================================================================
#ifndef RPC_ERRORCODES_H_INCLUDED
#define RPC_ERRORCODES_H_INCLUDED
#include <string>
#include <variant>
#include <boost/json.hpp>
#include <ripple/protocol/ErrorCodes.h>
namespace RPC
{
using Error = ripple::error_code_i;
struct Status
{
Error error = Error::rpcSUCCESS;
std::string message = "";
Status() {};
Status(Error error_) : error(error_) {};
Status(Error error_, std::string message_)
: error(error_)
, message(message_)
{}
/** Returns true if the Status is *not* OK. */
operator bool() const
{
return error != Error::rpcSUCCESS;
}
};
static Status OK;
using Result = std::variant<Status, boost::json::object>;
void
inject_error(Error err, boost::json::object& json);
void
inject_error(Error err, std::string const& message, boost::json::object& json);
boost::json::object
make_error(Error err);
boost::json::object
make_error(Error err, std::string const& message);
} // namespace RPC
#endif // RPC_ERRORCODES_H_INCLUDED

View File

@@ -1,51 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2021 Ripple Labs Inc.
Permission to use, copy, modify, and/or 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.
*/
//==============================================================================
#ifndef REPORTING_ACCOUNT_HANDLER_H_INCLUDED
#define REPORTING_ACCOUNT_HANDLER_H_INCLUDED
#include <handlers/Context.h>
#include <handlers/Status.h>
#include <handlers/Handlers.h>
#include <boost/json.hpp>
namespace RPC
{
Result
doAccountInfo(Context const& context);
Result
doAccountChannels(Context const& context);
Result
doAccountCurrencies(Context const& context);
Result
doAccountLines(Context const& context);
Result
doAccountObjects(Context const& context);
Result
doAccountOffers(Context const& context);
} // namespace RPC
#endif // REPORTING_ACCOUNT_HANDLER_H_INCLUDED

View File

@@ -1,38 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2021 Ripple Labs Inc.
Permission to use, copy, modify, and/or 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.
*/
//==============================================================================
#ifndef REPORTING_CHANNEL_HANDLER_H_INCLUDED
#define REPORTING_CHANNEL_HANDLER_H_INCLUDED
#include <handlers/Context.h>
#include <handlers/Status.h>
#include <handlers/Handlers.h>
namespace RPC
{
Result
doChannelAuthorize(Context const& context);
Result
doChannelVerify(Context const& context);
} // namespace RPC
#endif // REPORTING_CHANNEL_HANDLER_H_INCLUDED

View File

@@ -1,36 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2021 Ripple Labs Inc.
Permission to use, copy, modify, and/or 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.
*/
//==============================================================================
#ifndef REPORTING_EXCHANGE_HANDLER_H_INCLUDED
#define REPORTING_EXCHANGE_HANDLER_H_INCLUDED
#include <handlers/Context.h>
#include <handlers/Status.h>
#include <handlers/Handlers.h>
#include <boost/json.hpp>
namespace RPC
{
Result
doBookOffers(Context const& context);
} // namespace RPC
#endif // REPORTING_CHANNEL_HANDLER_H_INCLUDED

View File

@@ -1,45 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2021 Ripple Labs Inc.
Permission to use, copy, modify, and/or 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.
*/
//==============================================================================
#ifndef REPORTING_LEDGER_HANDLER_H_INCLUDED
#define REPORTING_LEDGER_HANDLER_H_INCLUDED
#include <handlers/Context.h>
#include <handlers/Status.h>
#include <handlers/Handlers.h>
#include <boost/json.hpp>
namespace RPC
{
Result
doLedger(Context const& context);
Result
doLedgerEntry(Context const& context);
Result
doLedgerData(Context const& context);
Result
doLedgerRange(Context const& context);
} // namespace RPC
#endif // REPORTING_LEDGER_HANDLER_H_INCLUDED

View File

@@ -1,39 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2021 Ripple Labs Inc.
Permission to use, copy, modify, and/or 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.
*/
//==============================================================================
#ifndef REPORTING_SUBSCRIBE_HANDLER_H_INCLUDED
#define REPORTING_SUBSCRIBE_HANDLER_H_INCLUDED
#include <handlers/Context.h>
#include <handlers/Status.h>
#include <handlers/Handlers.h>
#include <boost/json.hpp>
namespace RPC
{
Result
doSubscribe(Context const& context);
Result
doUnsubscribe(Context const& context);
} // namespace RPC
#endif // REPORTING_SUBSCRIBE_HANDLER_H_INCLUDED

View File

@@ -1,39 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2021 Ripple Labs Inc.
Permission to use, copy, modify, and/or 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.
*/
//==============================================================================
#ifndef REPORTING_TRANSACTION_HANDLER_H_INCLUDED
#define REPORTING_TRANSACTION_HANDLER_H_INCLUDED
#include <handlers/Context.h>
#include <handlers/Status.h>
#include <handlers/Handlers.h>
#include <boost/json.hpp>
namespace RPC
{
Result
doTx(Context const& context);
Result
doAccountTx(Context const& context);
} // namespace RPC
#endif // REPORTING_TRANSACTION_HANDLER_H_INCLUDED

71
src/rpc/Handlers.h Normal file
View File

@@ -0,0 +1,71 @@
#ifndef REPORTING_HANDLERS_H_INCLUDED
#define REPORTING_HANDLERS_H_INCLUDED
#include <rpc/RPC.h>
namespace RPC
{
/*
* This file just contains declarations for all of the handlers
*/
// account state methods
Result
doAccountInfo(Context const& context);
Result
doAccountChannels(Context const& context);
Result
doAccountCurrencies(Context const& context);
Result
doAccountLines(Context const& context);
Result
doAccountObjects(Context const& context);
Result
doAccountOffers(Context const& context);
// channels methods
Result
doChannelAuthorize(Context const& context);
Result
doChannelVerify(Context const& context);
// offers methods
Result
doBookOffers(Context const& context);
// ledger methods
Result
doLedger(Context const& context);
Result
doLedgerEntry(Context const& context);
Result
doLedgerData(Context const& context);
Result
doLedgerRange(Context const& context);
// transaction methods
Result
doTx(Context const& context);
Result
doAccountTx(Context const& context);
// subscriptions
Result
doSubscribe(Context const& context);
Result
doUnsubscribe(Context const& context);
} // namespace RPC
#endif

175
src/rpc/RPC.cpp Normal file
View File

@@ -0,0 +1,175 @@
#include <unordered_map>
#include <etl/ETLSource.h>
#include <rpc/Handlers.h>
namespace RPC
{
std::optional<Context>
make_WsContext(
boost::json::object const& request,
std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
std::shared_ptr<ETLLoadBalancer> const& balancer,
std::shared_ptr<WsBase> const& session,
Backend::LedgerRange const& range)
{
if (!request.contains("command"))
return {};
std::string command = request.at("command").as_string().c_str();
return Context{
command,
1,
request,
backend,
subscriptions,
balancer,
session,
range
};
}
std::optional<Context>
make_HttpContext(
boost::json::object const& request,
std::shared_ptr<BackendInterface> const& backend,
std::shared_ptr<SubscriptionManager> const& subscriptions,
std::shared_ptr<ETLLoadBalancer> const& balancer,
Backend::LedgerRange const& range)
{
if (!request.contains("method") || !request.at("method").is_string())
return {};
std::string const& command = request.at("method").as_string().c_str();
if (command == "subscribe" || command == "unsubscribe")
return {};
if (!request.contains("params") || !request.at("params").is_array())
return {};
boost::json::array const& array = request.at("params").as_array();
if (array.size() != 1)
return {};
if (!array.at(0).is_object())
return {};
return Context{
command,
1,
array.at(0).as_object(),
backend,
subscriptions,
balancer,
nullptr,
range
};
}
void
inject_error(Error err, boost::json::object& json)
{
ripple::RPC::ErrorInfo const& info(ripple::RPC::get_error_info(err));
json["error"] = info.token;
json["error_code"] = static_cast<std::uint32_t>(err);
json["error_message"] = info.message;
json["status"] = "error";
json["type"] = "response";
}
void
inject_error(Error err, std::string const& message, boost::json::object& json)
{
ripple::RPC::ErrorInfo const& info(ripple::RPC::get_error_info(err));
json["error"] = info.token;
json["error_code"] = static_cast<std::uint32_t>(err);
json["error_message"] = message;
json["status"] = "error";
json["type"] = "response";
}
boost::json::object
make_error(Error err)
{
boost::json::object json{};
inject_error(err, json);
return json;
}
boost::json::object
make_error(Error err, std::string const& message)
{
boost::json::object json{};
inject_error(err, message, json);
return json;
}
static std::unordered_map<std::string, std::function<Result(Context const&)>>
handlerTable{
{"account_channels", &doAccountChannels},
{"account_currencies", &doAccountCurrencies},
{"account_info", &doAccountInfo},
{"account_lines", &doAccountLines},
{"account_objects", &doAccountObjects},
{"account_offers", &doAccountOffers},
{"account_tx", &doAccountTx},
{"book_offers", &doBookOffers},
{"channel_authorize", &doChannelAuthorize},
{"channel_verify", &doChannelVerify},
{"ledger", &doLedger},
{"ledger_data", &doLedgerData},
{"ledger_entry", &doLedgerEntry},
{"ledger_range", &doLedgerRange},
{"ledger_data", &doLedgerData},
{"subscribe", &doSubscribe},
{"unsubscribe", &doUnsubscribe},
{"tx", &doTx},
};
static std::unordered_set<std::string> forwardCommands{
"submit",
"submit_multisigned",
"fee",
"path_find",
"ripple_path_find",
"manifest"};
bool
shouldForwardToRippled(Context const& ctx)
{
auto request = ctx.params;
if (forwardCommands.find(ctx.method) != forwardCommands.end())
return true;
if (request.contains("ledger_index"))
{
auto indexValue = request.at("ledger_index");
if (indexValue.is_string())
{
std::string index = indexValue.as_string().c_str();
return index == "current" || index == "closed";
}
}
return false;
}
Result
buildResponse(Context const& ctx)
{
if (shouldForwardToRippled(ctx))
return ctx.balancer->forwardToRippled(ctx.params);
if (handlerTable.find(ctx.method) == handlerTable.end())
return Status{Error::rpcUNKNOWN_COMMAND};
auto method = handlerTable[ctx.method];
return method(ctx);
}
}

View File

@@ -1,28 +1,22 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2021 Ripple Labs Inc.
Permission to use, copy, modify, and/or 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.
*/
//==============================================================================
#ifndef REPORTING_CONTEXT_H_INCLUDED
#define REPORTING_CONTEXT_H_INCLUDED
#include <boost/json.hpp>
#ifndef REPORTING_RPC_H_INCLUDED
#define REPORTING_RPC_H_INCLUDED
#include <optional>
#include <string>
#include <variant>
#include <boost/json.hpp>
#include <ripple/protocol/ErrorCodes.h>
#include <backend/BackendInterface.h>
/*
* This file contains various classes necessary for executing RPC handlers.
* Context gives the handlers access to various other parts of the application
* Status is used to report errors.
* And lastly, there are various functions for making Contexts, Statuses and
* serializing Status to JSON.
* This file is meant to contain any class or function that code outside of the
* rpc folder needs to use. For helper functions or classes used within the rpc
* folder, use RPCHelpers.h.
*/
class WsBase;
class SubscriptionManager;
@@ -61,6 +55,44 @@ struct Context
, range(range_)
{}
};
using Error = ripple::error_code_i;
struct Status
{
Error error = Error::rpcSUCCESS;
std::string message = "";
Status() {};
Status(Error error_) : error(error_) {};
Status(Error error_, std::string message_)
: error(error_)
, message(message_)
{}
/** Returns true if the Status is *not* OK. */
operator bool() const
{
return error != Error::rpcSUCCESS;
}
};
static Status OK;
using Result = std::variant<Status, boost::json::object>;
void
inject_error(Error err, boost::json::object& json);
void
inject_error(Error err, std::string const& message, boost::json::object& json);
boost::json::object
make_error(Error err);
boost::json::object
make_error(Error err, std::string const& message);
std::optional<Context>
@@ -80,6 +112,9 @@ make_HttpContext(
std::shared_ptr<ETLLoadBalancer> const& balancer,
Backend::LedgerRange const& range);
Result
buildResponse(Context const& ctx);
} // namespace RPC
#endif //REPORTING_CONTEXT_H_INCLUDED
#endif //REPORTING_RPC_H_INCLUDED

View File

@@ -1,6 +1,5 @@
#include <backend/BackendInterface.h>
#include <handlers/RPCHelpers.h>
#include <handlers/Status.h>
#include <rpc/RPCHelpers.h>
std::optional<ripple::STAmount>
getDeliveredAmount(

View File

@@ -1,16 +1,18 @@
#ifndef XRPL_REPORTING_RPCHELPERS_H_INCLUDED
#define XRPL_REPORTING_RPCHELPERS_H_INCLUDED
/*
* This file contains a variety of utility functions used when executing
* the handlers
*/
#include <ripple/app/ledger/Ledger.h>
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <ripple/protocol/STTx.h>
#include <ripple/protocol/jss.h>
#include <boost/json.hpp>
#include <backend/BackendInterface.h>
#include <handlers/Context.h>
#include <handlers/Status.h>
#include <rpc/RPC.h>
std::optional<ripple::AccountID>
accountFromStringStrict(std::string const& account);
@@ -46,6 +48,13 @@ using RippledJson = Json::Value;
boost::json::value
toBoostJson(RippledJson const& value);
boost::json::object
generatePubLedgerMessage(ripple::LedgerInfo const& lgrInfo,
ripple::Fees const& fees,
std::string const& ledgerRange,
uint32_t txnCount);
std::variant<RPC::Status, ripple::LedgerInfo>
ledgerInfoFromRequest(RPC::Context const& ctx);

View File

@@ -6,8 +6,7 @@
#include <ripple/protocol/jss.h>
#include <boost/json.hpp>
#include <algorithm>
#include <handlers/methods/Account.h>
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
#include <backend/BackendInterface.h>
#include <backend/DBHelpers.h>
#include <backend/Pg.h>

View File

@@ -6,8 +6,8 @@
#include <ripple/protocol/jss.h>
#include <boost/json.hpp>
#include <algorithm>
#include <handlers/methods/Account.h>
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
#include <backend/BackendInterface.h>
#include <backend/DBHelpers.h>
#include <backend/Pg.h>

View File

@@ -20,8 +20,8 @@
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <boost/json.hpp>
#include <handlers/methods/Account.h>
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
#include <backend/BackendInterface.h>
// {

View File

@@ -6,9 +6,9 @@
#include <ripple/protocol/STLedgerEntry.h>
#include <ripple/protocol/jss.h>
#include <boost/json.hpp>
#include <handlers/methods/Account.h>
#include <algorithm>
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
#include <backend/BackendInterface.h>
#include <backend/DBHelpers.h>

View File

@@ -7,8 +7,8 @@
#include <ripple/protocol/jss.h>
#include <boost/json.hpp>
#include <algorithm>
#include <handlers/RPCHelpers.h>
#include <handlers/methods/Account.h>
#include <rpc/RPCHelpers.h>
#include <backend/BackendInterface.h>
#include <backend/DBHelpers.h>

View File

@@ -7,8 +7,8 @@
#include <ripple/protocol/jss.h>
#include <boost/json.hpp>
#include <algorithm>
#include <handlers/RPCHelpers.h>
#include <handlers/methods/Account.h>
#include <rpc/RPCHelpers.h>
#include <backend/BackendInterface.h>
#include <backend/DBHelpers.h>

View File

@@ -19,8 +19,8 @@
#include <backend/BackendInterface.h>
#include <backend/Pg.h>
#include <handlers/RPCHelpers.h>
#include <handlers/methods/Transaction.h>
#include <rpc/RPCHelpers.h>
namespace RPC {

View File

@@ -6,8 +6,8 @@
#include <ripple/protocol/jss.h>
#include <boost/json.hpp>
#include <algorithm>
#include <handlers/RPCHelpers.h>
#include <handlers/methods/Exchange.h>
#include <rpc/RPCHelpers.h>
#include <backend/BackendInterface.h>
#include <backend/DBHelpers.h>
#include <backend/Pg.h>

View File

@@ -23,8 +23,8 @@
#include <ripple/protocol/STAccount.h>
#include <ripple/protocol/jss.h>
#include <ripple/resource/Fees.h>
#include <handlers/methods/Channel.h>
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
#include <optional>
namespace RPC

View File

@@ -23,8 +23,8 @@
#include <ripple/protocol/STAccount.h>
#include <ripple/protocol/jss.h>
#include <ripple/resource/Fees.h>
#include <handlers/methods/Channel.h>
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
#include <optional>
namespace RPC

View File

@@ -1,6 +1,6 @@
#include <backend/BackendInterface.h>
#include <handlers/RPCHelpers.h>
#include <handlers/methods/Ledger.h>
#include <rpc/RPCHelpers.h>
namespace RPC {

View File

@@ -20,8 +20,8 @@
#include <ripple/app/ledger/LedgerToJson.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <boost/json.hpp>
#include <handlers/methods/Ledger.h>
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
#include <backend/BackendInterface.h>
// Get state nodes from a ledger
// Inputs:

View File

@@ -1,8 +1,8 @@
#include <ripple/protocol/Indexes.h>
#include <ripple/protocol/STLedgerEntry.h>
#include <boost/json.hpp>
#include <handlers/methods/Ledger.h>
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
#include <backend/BackendInterface.h>
// {
// ledger_hash : <ledger>

View File

@@ -1,5 +1,5 @@
#include <handlers/methods/Ledger.h>
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
#include <backend/BackendInterface.h>
namespace RPC

View File

@@ -1,8 +1,8 @@
#include <boost/json.hpp>
#include <webserver/WsBase.h>
#include <webserver/SubscriptionManager.h>
#include <handlers/methods/Subscribe.h>
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
namespace RPC
{

View File

@@ -19,8 +19,8 @@
#include <backend/BackendInterface.h>
#include <backend/Pg.h>
#include <handlers/RPCHelpers.h>
#include <handlers/methods/Transaction.h>
#include <rpc/RPCHelpers.h>
namespace RPC {

View File

@@ -36,7 +36,7 @@
#include <string>
#include <thread>
#include <handlers/Handlers.h>
#include <rpc/RPC.h>
#include <vector>
#include <webserver/DOSGuard.h>

View File

@@ -27,7 +27,7 @@
#include <boost/beast/websocket/ssl.hpp>
#include <etl/ReportingETL.h>
#include <handlers/Handlers.h>
#include <rpc/RPC.h>
#include <webserver/WsBase.h>
#include <webserver/Listener.h>

View File

@@ -1,4 +1,4 @@
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
#include <webserver/SubscriptionManager.h>
#include <webserver/WsBase.h>

View File

@@ -28,8 +28,7 @@
#include <backend/BackendInterface.h>
#include <etl/ETLSource.h>
#include <handlers/Handlers.h>
#include <handlers/Status.h>
#include <rpc/RPC.h>
#include <webserver/DOSGuard.h>
#include <webserver/SubscriptionManager.h>

View File

@@ -1,7 +1,7 @@
#include <algorithm>
#include <backend/DBHelpers.h>
#include <gtest/gtest.h>
#include <handlers/RPCHelpers.h>
#include <rpc/RPCHelpers.h>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>