20 #include <ripple/app/paths/AccountCurrencies.h>
21 #include <ripple/app/paths/RippleCalc.h>
22 #include <ripple/app/paths/PathRequest.h>
23 #include <ripple/app/paths/PathRequests.h>
24 #include <ripple/app/main/Application.h>
25 #include <ripple/app/misc/LoadFeeTrack.h>
26 #include <ripple/app/misc/NetworkOPs.h>
27 #include <ripple/basics/Log.h>
28 #include <ripple/core/Config.h>
29 #include <ripple/net/RPCErr.h>
30 #include <ripple/protocol/ErrorCodes.h>
31 #include <ripple/protocol/UintTypes.h>
32 #include <ripple/rpc/impl/Tuning.h>
33 #include <ripple/beast/core/LexicalCast.h>
34 #include <boost/algorithm/clamp.hpp>
35 #include <boost/optional.hpp>
49 , wpSubscriber (subscriber)
50 , consumer_(subscriber->getConsumer())
51 , jvStatus (
Json::objectValue)
55 , bLastSuccess (false)
57 , created_ (
std::chrono::steady_clock::now())
73 , fCompletion (completion)
74 , consumer_ (consumer)
75 , jvStatus (
Json::objectValue)
79 , bLastSuccess (false)
81 , created_ (
std::chrono::steady_clock::now())
109 stream <<
iIdentifier <<
" complete:" << fast << full <<
110 " total:" << duration_cast<milliseconds>(steady_clock::now() -
178 auto const& lrLedger = crCache->getLedger();
187 auto const sleDest = lrLedger->read(
204 STAmount (lrLedger->fees().accountReserve (0)))
213 bool const disallowXRP (
219 for (
auto const& currency : usDestCurrID)
226 jvStatus[jss::ledger_index] = lrLedger->seq();
273 if (! jvParams.
isMember(jss::source_account))
276 return PFR_PJ_INVALID;
279 if (! jvParams.
isMember(jss::destination_account))
282 return PFR_PJ_INVALID;
285 if (! jvParams.
isMember(jss::destination_amount))
288 return PFR_PJ_INVALID;
292 jvParams[jss::source_account].asString());
296 return PFR_PJ_INVALID;
300 jvParams[jss::destination_account].asString());
304 return PFR_PJ_INVALID;
311 return PFR_PJ_INVALID;
322 return PFR_PJ_INVALID;
325 if (jvParams.
isMember(jss::send_max))
331 return PFR_PJ_INVALID;
344 return PFR_PJ_INVALID;
348 if (jvParams.
isMember (jss::source_currencies))
350 Json::Value const& jvSrcCurrencies = jvParams[jss::source_currencies];
351 if (! jvSrcCurrencies.
isArray() || jvSrcCurrencies.
size() == 0 ||
355 return PFR_PJ_INVALID;
360 for (
auto const& c : jvSrcCurrencies)
364 if (! c.isObject() ||
365 ! c.isMember(jss::currency) ||
366 ! c[jss::currency].isString() ||
367 !
to_currency(srcCurrencyID, c[jss::currency].asString()))
370 return PFR_PJ_INVALID;
375 if (c.isMember (jss::issuer) &&
376 (! c[jss::issuer].isString() ||
377 !
to_issuer(srcIssuerID, c[jss::issuer].asString())))
380 return PFR_PJ_INVALID;
383 if (srcCurrencyID.
isZero())
388 return PFR_PJ_INVALID;
391 else if (srcIssuerID.
isZero())
399 if (srcCurrencyID ==
saSendMax->getCurrency())
408 return PFR_PJ_INVALID;
416 {srcCurrencyID, srcIssuerID});
421 {srcCurrencyID,
saSendMax->getIssuer()});
438 jvId = jvParams[jss::id];
440 return PFR_PJ_NOCHANGE;
454 jvStatus[jss::status] = jss::success;
464 auto i = currency_map.find(currency);
465 if (i != currency_map.end())
467 auto pathfinder = std::make_unique<Pathfinder>(
470 if (pathfinder->findPaths(level))
474 return currency_map[currency] = std::move(pathfinder);
482 if (sourceCurrencies.empty ())
486 for (
auto const& c : currencies)
492 sourceCurrencies.insert(
502 for (
auto const& issue : sourceCurrencies)
506 <<
" Trying to find paths: "
510 issue.currency, dst_amount, level);
519 auto ps = pathfinder->getBestPaths(
max_paths_,
520 fullLiquidityPath,
mContext[issue], issue.account);
523 auto& sourceAccount = !
isXRP(issue.account)
525 :
isXRP(issue.currency)
529 STAmount({issue.currency, sourceAccount}, 1u, 0,
true));
532 <<
" Paths found, calling rippleCalc";
537 auto sandbox = std::make_unique<PaymentSandbox>
538 (&*cache->getLedger(),
tapNONE);
551 ! fullLiquidityPath.
empty() &&
555 <<
" Trying with an extra path element";
557 ps.push_back(fullLiquidityPath);
558 sandbox = std::make_unique<PaymentSandbox>
559 (&*cache->getLedger(),
tapNONE);
573 <<
" Failed with covering path "
579 <<
" Extra path element gives "
587 rc.actualAmountIn.setIssuer (sourceAccount);
588 jvEntry[jss::source_amount] =
593 jvEntry[jss::destination_amount] =
615 int const size = sourceCurrencies.size();
626 <<
" update " << (fast ?
"fast" :
"normal");
640 auto& destCurrencies = (newStatus[jss::destination_currencies] =
Json::arrayValue);
642 for (
auto const& c : usCurrencies)
648 newStatus[jss::destination_amount] =
650 newStatus[jss::full_reply] = ! fast;
653 newStatus[jss::id] =
jvId;
689 <<
" processing at level " <<
iLevel;
695 newStatus[jss::alternatives] = std::move (jvArray);
708 else if (! fast &&
full_reply_ == steady_clock::time_point{})
Json::Value doClose(Json::Value const &)
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
static std::string const & systemCurrencyCode()
bool to_currency(Currency ¤cy, std::string const &code)
Tries to convert a string to a Currency, returns true on success.
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
std::map< Issue, STPathSet > mContext
std::unique_ptr< Pathfinder > const & getPathFinder(std::shared_ptr< RippleLineCache > const &, hash_map< Currency, std::unique_ptr< Pathfinder >> &, Currency const &, STAmount const &, int const)
@ arrayValue
array value (ordered list)
hash_set< Currency > accountDestCurrencies(AccountID const &account, std::shared_ptr< RippleLineCache > const &lrCache, bool includeXRP)
Json::Value getJson(JsonOptions) const override
boost::optional< AccountID > raDstAccount
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
std::chrono::steady_clock::time_point full_reply_
std::recursive_mutex mIndexLock
std::string to_string(ListDisposition disposition)
Resource::Consumer & consumer_
virtual AccountIDCache const & accountIDCache() const =0
virtual LoadFeeTrack & getFeeTrack()=0
std::chrono::steady_clock::time_point quick_reply_
bool isLoadedLocal() const
std::string getFullText() const override
JSON (JavaScript Object Notation).
Value & append(const Value &value)
Append value to array at the end.
@ objectValue
object value (collection of name/value pairs).
PathRequest(Application &app, std::shared_ptr< InfoSub > const &subscriber, int id, PathRequests &, beast::Journal journal)
static unsigned const int max_paths_
std::set< Issue > sciSourceCurrencies
static const account_t account
static constexpr int max_src_cur
Maximum number of source currencies allowed in a path find request.
virtual Config & config()=0
InfoSub::pointer getSubscriber()
AccountID const & xrpAccount()
Compute AccountID from public key.
UInt size() const
Number of values in array or object.
bool findPaths(std::shared_ptr< RippleLineCache > const &, int const, Json::Value &)
Finds and sets a PathSet in the JSON argument.
bool isXRP(AccountID const &c)
bool isMember(const char *key) const
Return true if the object has a member named key.
A generic endpoint for log messages.
bool isValid(std::shared_ptr< RippleLineCache > const &crCache)
Json::Value rpcError(int iError, Json::Value jvResult)
std::function< void(void)> fCompletion
std::string transHuman(TER code)
Currency const & getCurrency() const
AccountID const & getIssuer() const
std::pair< bool, Json::Value > doCreate(std::shared_ptr< RippleLineCache > const &, Json::Value const &)
bool native() const noexcept
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
void reportFast(std::chrono::milliseconds ms)
std::recursive_mutex mLock
const std::chrono::steady_clock::time_point created_
Json::Value doUpdate(std::shared_ptr< RippleLineCache > const &, bool fast)
std::weak_ptr< InfoSub > wpSubscriber
Json::Value doStatus(Json::Value const &)
Issue const & issue() const
static constexpr int max_auto_src_cur
Maximum number of auto source currencies in a path find request.
An endpoint that consumes resources.
static Output rippleCalculate(PaymentSandbox &view, STAmount const &saMaxAmountReq, STAmount const &saDstAmountReq, AccountID const &uDstAccountID, AccountID const &uSrcAccountID, STPathSet const &spsPaths, Logs &l, Input const *const pInputs=nullptr)
void reportFull(std::chrono::milliseconds ms)
boost::optional< STAmount > saSendMax
hash_set< Currency > accountSourceCurrencies(AccountID const &account, std::shared_ptr< RippleLineCache > const &lrCache, bool includeXRP)
static const int cMaxOffset
Disposition charge(Charge const &fee)
Apply a load charge to the consumer.
bool needsUpdate(bool newOnly, LedgerIndex index)
int parseJson(Json::Value const &)
static const std::uint64_t cMaxValue
boost::optional< AccountID > raSrcAccount
std::string toBase58(AccountID const &) const
Return ripple::toBase58 for the AccountID.
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.