1#include <xrpld/app/ledger/LedgerMaster.h>
2#include <xrpld/app/main/Application.h>
3#include <xrpld/rpc/Context.h>
4#include <xrpld/rpc/RPCSub.h>
5#include <xrpld/rpc/Role.h>
6#include <xrpld/rpc/detail/RPCHelpers.h>
7#include <xrpld/rpc/detail/Tuning.h>
9#include <xrpl/basics/Log.h>
10#include <xrpl/basics/UnorderedContainers.h>
11#include <xrpl/basics/base_uint.h>
12#include <xrpl/json/json_value.h>
13#include <xrpl/ledger/ReadView.h>
14#include <xrpl/protocol/AccountID.h>
15#include <xrpl/protocol/Book.h>
16#include <xrpl/protocol/ErrorCodes.h>
17#include <xrpl/protocol/RPCErr.h>
18#include <xrpl/protocol/jss.h>
19#include <xrpl/resource/Fees.h>
20#include <xrpl/server/InfoSub.h>
21#include <xrpl/server/NetworkOPs.h>
42wouldExceedSubscriptionCap(
InfoSub::ref ispSub, std::size_t additional, std::size_t cap)
58 JLOG(context.
j.
info()) <<
"doSubscribe: RPC subscribe requires a url";
86 JLOG(context.
j.
debug()) <<
"doSubscribe: building: " << strUrl;
107 JLOG(context.
j.
trace()) <<
"doSubscribe: reusing: " << strUrl;
115 rpcSub->setUsername(strUsername);
118 rpcSub->setPassword(strPassword);
137 JLOG(context.
j.
info()) <<
"doSubscribe: streams requires an array.";
141 for (
auto const& it : context.
params[jss::streams])
147 if (streamName ==
"server")
151 else if (streamName ==
"ledger")
155 else if (streamName ==
"book_changes")
159 else if (streamName ==
"manifests")
163 else if (streamName ==
"transactions")
168 streamName ==
"transactions_proposed" ||
169 streamName ==
"rt_transactions")
173 else if (streamName ==
"validations")
177 else if (streamName ==
"peer_status")
183 else if (streamName ==
"consensus")
203 auto accountsProposed = context.
params.
isMember(jss::accounts_proposed)
204 ? jss::accounts_proposed
206 bool const hasProposed = context.
params.
isMember(accountsProposed);
218 if (proposedIds.
empty())
228 if (accountIds.
empty())
232 if (hasProposed || hasAccounts)
246 JLOG(context.
j.
debug()) <<
"doSubscribe: accounts: " << accountIds.
size();
255 auto const& req = context.
params[jss::account_history_tx_stream];
256 if (!req.isMember(jss::account) || !req[jss::account].isString())
267 if (wouldExceedSubscriptionCap(ispSub, historyCharge, subscriptionCap))
275 jvResult[jss::warning] =
276 "account_history_tx_stream is an experimental feature and likely "
277 "to be removed in the future";
278 JLOG(context.
j.
debug()) <<
"doSubscribe: account_history_tx_stream: " <<
toBase58(*
id);
290 for (
auto& j : context.
params[jss::books])
292 if (!j.isObject() || !j.isMember(jss::taker_pays) || !j.isMember(jss::taker_gets) ||
293 !j[jss::taker_pays].isObjectOrNull() || !j[jss::taker_gets].isObjectOrNull())
306 if (book.in == book.out)
308 JLOG(context.
j.
info()) <<
"taker_gets same as taker_pays.";
314 if (j.isMember(jss::taker))
316 if (!j[jss::taker].isString())
323 if (j.isMember(jss::domain))
326 if (!j[jss::domain].isString() || !domain.
parseHex(j[jss::domain].asString()))
331 book.domain = domain;
336 JLOG(context.
j.
warn()) <<
"Bad market: " << book;
343 bool const both = (j.isMember(jss::both) && j[jss::both].asBool()) ||
344 (j.isMember(jss::both_sides) && j[jss::both_sides].asBool());
350 if ((j.isMember(jss::snapshot) && j[jss::snapshot].asBool()) ||
351 (j.isMember(jss::state_now) && j[jss::state_now].asBool()))
364 field == jss::asks ?
reversed(book) : book,
374 for (
auto const& e : jvOffers[jss::offers])
379 jvResult[field] = jvOffers[jss::offers];
Stream trace() const
Severity stream access functions.
Lightweight wrapper to tag static string.
Value & append(Value const &value)
Append value to array at the end.
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
virtual Config & config()=0
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
std::optional< std::size_t > maxSubscriptionsPerConnection
virtual ErrorCodeI subAccountHistory(ref ispListener, AccountID const &account)=0
subscribe an account's new transactions and retrieve the account's historical transactions
virtual bool subTransactions(ref ispListener)=0
virtual bool subPeerStatus(ref ispListener)=0
virtual bool subServer(ref ispListener, json::Value &jvResult, bool admin)=0
virtual bool subConsensus(ref ispListener)=0
virtual void subAccount(ref ispListener, hash_set< AccountID > const &vnaAccountIDs, bool realTime)=0
virtual bool subBook(ref ispListener, Book const &)=0
virtual bool subValidations(ref ispListener)=0
virtual bool subRTTransactions(ref ispListener)=0
virtual bool subLedger(ref ispListener, json::Value &jvResult)=0
virtual bool subBookChanges(ref ispListener)=0
virtual pointer addRpcSub(std::string const &strUrl, ref rspEntry)=0
virtual bool subManifests(ref ispListener)=0
virtual pointer findRpcSub(std::string const &strUrl)=0
std::shared_ptr< InfoSub > pointer
bool tryReserveAccountSubscriptions(hash_set< AccountID > const &proposedAccounts, hash_set< AccountID > const &normalAccounts, std::size_t cap)
Enforce the cap and reserve a request's net-new accounts, atomically.
void setApiVersion(unsigned int apiVersion)
std::shared_ptr< InfoSub > const & ref
bool hasAccountHistorySubscription(AccountID const &account) const
Whether this connection already tracks an account-history for account.
std::shared_ptr< ReadView const > getPublishedLedger()
virtual void getBookPage(std::shared_ptr< ReadView const > &lpLedger, Book const &book, AccountID const &uTakerID, bool const bProof, unsigned int iLimit, json::Value const &jvMarker, json::Value &jvResult)=0
virtual JobQueue & getJobQueue()=0
virtual NetworkOPs & getOPs()=0
virtual LedgerMaster & getLedgerMaster()=0
virtual boost::asio::io_context & getIOContext()=0
@ Object
object value (collection of name/value pairs).
Charge const kFeeMediumBurdenRpc
static constexpr LimitRange kBookOffers
Limits for the book_offers command.
json::Value makeParamError(std::string const &message)
Returns a new json object that indicates invalid parameters.
ErrorCodeI parseSubUnsubJson(Asset &asset, json::Value const ¶ms, json::StaticString const &name, beast::Journal j)
Parse subscribe/unsubscribe parameters.
hash_set< AccountID > parseAccountIds(json::Value const &jvArray)
Parses an array of account IDs from a JSON value.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::unordered_set< Value, Hash, Pred, Allocator > hash_set
std::shared_ptr< RPCSub > makeRPCSub(InfoSub::Source &source, boost::asio::io_context &ioContext, JobQueue &jobQueue, std::string const &strUrl, std::string const &strUsername, std::string const &strPassword, ServiceRegistry ®istry)
json::Value rpcError(ErrorCodeI iError)
Book reversed(Book const &book)
constexpr std::size_t kMaxSubscriptionsPerConnection
Maximum number of subscriptions a single client connection may hold at once.
AccountID const & noAccount()
A placeholder for empty accounts.
constexpr bool exceedsSubscriptionCap(std::size_t current, std::size_t additional, std::size_t cap=kMaxSubscriptionsPerConnection)
Whether adding additional subscriptions to a connection already holding current would exceed the cap.
json::Value doSubscribe(rpc::JsonContext &)
bool isConsistent(Asset const &asset)
T dynamic_pointer_cast(T... args)
resource::Charge & loadType