1#include <xrpld/rpc/detail/PathRequest.h>
3#include <xrpld/app/main/Application.h>
4#include <xrpld/core/Config.h>
5#include <xrpld/rpc/detail/AccountAssets.h>
6#include <xrpld/rpc/detail/PathRequestManager.h>
7#include <xrpld/rpc/detail/Pathfinder.h>
8#include <xrpld/rpc/detail/PathfinderUtils.h>
9#include <xrpld/rpc/detail/Tuning.h>
11#include <xrpl/basics/Log.h>
12#include <xrpl/basics/UnorderedContainers.h>
13#include <xrpl/basics/base_uint.h>
14#include <xrpl/beast/utility/Journal.h>
15#include <xrpl/beast/utility/Zero.h>
16#include <xrpl/beast/utility/instrumentation.h>
17#include <xrpl/json/json_value.h>
18#include <xrpl/ledger/ApplyView.h>
19#include <xrpl/ledger/PaymentSandbox.h>
20#include <xrpl/protocol/AccountID.h>
21#include <xrpl/protocol/Asset.h>
22#include <xrpl/protocol/ErrorCodes.h>
23#include <xrpl/protocol/Indexes.h>
24#include <xrpl/protocol/LedgerFormats.h>
25#include <xrpl/protocol/PathAsset.h>
26#include <xrpl/protocol/Protocol.h>
27#include <xrpl/protocol/RPCErr.h>
28#include <xrpl/protocol/STAmount.h>
29#include <xrpl/protocol/STPathSet.h>
30#include <xrpl/protocol/SystemParameters.h>
31#include <xrpl/protocol/TER.h>
32#include <xrpl/protocol/UintTypes.h>
33#include <xrpl/protocol/jss.h>
34#include <xrpl/resource/Consumer.h>
35#include <xrpl/server/InfoSub.h>
36#include <xrpl/server/LoadFeeTrack.h>
37#include <xrpl/tx/paths/RippleCalc.h>
167 XRPL_ASSERT(
inProgress_,
"xrpl::PathRequest::updateComplete : in progress");
190 auto const& lrLedger = crCache->getLedger();
222 bool const disallowXRP(sleDest->isFlag(lsfDisallowXRP));
226 for (
auto const& asset : destAssets)
229 jvStatus_[jss::destination_tag] = (sleDest->getFlags() & lsfRequireDestTag);
233 jvStatus_[jss::ledger_index] = lrLedger->seq();
277 if (!jvParams.
isMember(jss::source_account))
280 return PFR_PJ_INVALID;
283 if (!jvParams.
isMember(jss::destination_account))
286 return PFR_PJ_INVALID;
289 if (!jvParams.
isMember(jss::destination_amount))
292 return PFR_PJ_INVALID;
299 return PFR_PJ_INVALID;
306 return PFR_PJ_INVALID;
312 return PFR_PJ_INVALID;
320 return PFR_PJ_INVALID;
323 if (jvParams.
isMember(jss::send_max))
329 return PFR_PJ_INVALID;
339 return PFR_PJ_INVALID;
343 if (jvParams.
isMember(jss::source_currencies))
345 json::Value const& jvSrcCurrencies = jvParams[jss::source_currencies];
346 if (!jvSrcCurrencies.
isArray() || jvSrcCurrencies.
size() == 0 ||
350 return PFR_PJ_INVALID;
355 for (
auto const& c : jvSrcCurrencies)
361 return PFR_PJ_INVALID;
365 if (c.isMember(jss::currency))
368 if (!c[jss::currency].isString() ||
369 !
toCurrency(currency, c[jss::currency].asString()))
372 return PFR_PJ_INVALID;
374 srcPathAsset = currency;
379 if (!c[jss::mpt_issuance_id].isString() ||
380 !u.
parseHex(c[jss::mpt_issuance_id].asString()))
383 return PFR_PJ_INVALID;
390 if (c.isMember(jss::issuer) &&
391 (c.isMember(jss::mpt_issuance_id) || !c[jss::issuer].isString() ||
392 !
toIssuer(srcIssuerID, c[jss::issuer].asString())))
395 return PFR_PJ_INVALID;
405 return PFR_PJ_INVALID;
408 else if (srcIssuerID.
isZero())
419 auto const status = srcPathAsset.
visit(
430 return PFR_PJ_INVALID;
447 return PFR_PJ_NOCHANGE;
449 [&](
MPTID const& mpt) {
451 return PFR_PJ_NOCHANGE;
453 if (status == PFR_PJ_INVALID)
469 jvId_ = jvParams[jss::id];
474 if (!jvParams[jss::domain].isString() || !num.
parseHex(jvParams[jss::domain].
asString()))
477 return PFR_PJ_INVALID;
483 return PFR_PJ_NOCHANGE;
518 auto i = currencyMap.find(currency);
519 if (i != currencyMap.end())
533 if (pathfinder->findPaths(level, continueCallback))
535 pathfinder->computePathRanks(
kMaxPaths, continueCallback);
541 return currencyMap[currency] = std::move(pathfinder);
556 if (sourceAssets.empty())
562 for (
auto const& asset : assets)
565 [&]<
typename TAsset>(TAsset
const& a) {
591 for (
auto const& asset : sourceAssets)
593 if (continueCallback && !continueCallback())
607 auto ps = pathfinder->getBestPaths(
608 kMaxPaths, fullLiquidityPath,
context_[asset], asset.getIssuer(), continueCallback);
611 auto const& sourceAccount = [&] {
612 if (!
isXRP(asset.getIssuer()))
613 return asset.getIssuer();
621 STAmount const saMaxAmount = [&]() {
625 [&](
Issue const& issue) {
656 ps.pushBack(fullLiquidityPath);
686 if (rc.actualAmountIn.holds<
Issue>())
687 rc.actualAmountIn.get<
Issue>().account = sourceAccount;
693 jvEntry[jss::destination_amount] =
716 int const size = sourceAssets.size();
745 for (
auto const& asset : assets)
754 newStatus[jss::full_reply] = !fast;
757 newStatus[jss::id] =
jvId_;
759 bool const loaded =
app_.getFeeTrack().isLoadedLocal();
773 else if ((
iLevel_ ==
app_.config().pathSearchFast) && !fast)
777 if (loaded && (
iLevel_ >
app_.config().pathSearchFast))
784 (loaded && (
iLevel_ >
app_.config().pathSearchFast)))
790 if (!loaded && (
iLevel_ <
app_.config().pathSearchMax))
792 if (loaded && (
iLevel_ >
app_.config().pathSearchFast))
802 newStatus[jss::alternatives] = std::move(jvArray);
810 if (fast &&
quickReply_ == steady_clock::time_point{})
815 else if (!fast &&
fullReply_ == steady_clock::time_point{})
A generic endpoint for log messages.
Value & append(Value const &value)
Append value to array at the end.
UInt size() const
Number of values in array or object.
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.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
std::shared_ptr< InfoSub > pointer
A currency issued by an account.
constexpr auto visit(Visitors &&... visitors) const -> decltype(auto)
constexpr bool holds() const
PathRequest(Application &app, std::shared_ptr< InfoSub > const &subscriber, int id, PathRequestManager &, beast::Journal journal)
std::recursive_mutex lock_
std::chrono::steady_clock::time_point quickReply_
int parseJson(json::Value const &)
static unsigned int const kMaxPaths
std::unique_ptr< Pathfinder > const & getPathFinder(std::shared_ptr< AssetCache > const &, HashMap< PathAsset, std::unique_ptr< Pathfinder > > &, PathAsset const &, STAmount const &, int const, std::function< bool(void)> const &)
bool isValid(std::shared_ptr< AssetCache > const &crCache)
PathRequestManager & owner_
std::optional< UInt256 > domain_
std::chrono::steady_clock::time_point const created_
bool needsUpdate(bool newOnly, LedgerIndex index)
resource::Consumer & consumer_
json::Value doClose() override
std::recursive_mutex indexLock_
std::weak_ptr< InfoSub > wpSubscriber_
InfoSub::pointer getSubscriber() const
json::Value doStatus(json::Value const &) override
json::Value doUpdate(std::shared_ptr< AssetCache > const &, bool fast, std::function< bool(void)> const &continueCallback={})
std::optional< STAmount > saSendMax_
std::chrono::steady_clock::time_point fullReply_
std::set< Asset > sciSourceAssets_
std::optional< AccountID > raDstAccount_
std::function< void(void)> fCompletion_
std::pair< bool, json::Value > doCreate(std::shared_ptr< AssetCache > const &, json::Value const &)
bool findPaths(std::shared_ptr< AssetCache > const &, int const, json::Value &, std::function< bool(void)> const &)
Finds and sets a PathSet in the JSON argument.
std::optional< AccountID > raSrcAccount_
std::map< Asset, STPathSet > context_
std::string getFullText() const override
static Output rippleCalculate(PaymentSandbox &view, STAmount const &saMaxAmountReq, STAmount const &saDstAmountReq, AccountID const &uDstAccountID, AccountID const &uSrcAccountID, STPathSet const &spsPaths, std::optional< UInt256 > const &domainID, ServiceRegistry ®istry, Input const *const pInputs=nullptr)
An endpoint that consumes resources.
T duration_cast(T... args)
JSON (JavaScript Object Notation).
@ Array
array value (ordered list)
@ Object
object value (collection of name/value pairs).
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet account(AccountID const &id) noexcept
AccountID root.
static constexpr int kMaxSrcCur
Maximum number of source currencies allowed in a path find request.
static constexpr int kMaxAutoSrcCur
Maximum number of auto source currencies in a path find request.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
STAmount convertAmount(STAmount const &amt, bool all)
bool isXRP(AccountID const &c)
std::optional< AccountID > parseBase58(std::string const &s)
Parse AccountID from checked, base58 string.
std::uint32_t LedgerIndex
A ledger index.
bool validJSONAsset(json::Value const &jv)
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
BaseUInt< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
std::string transHuman(TER code)
bool toCurrency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
bool validAsset(Asset const &asset)
std::string to_string(BaseUInt< Bits, Tag > const &a)
HashSet< PathAsset > accountDestAssets(AccountID const &account, std::shared_ptr< AssetCache > const &lrCache, bool includeXRP)
json::Value rpcError(ErrorCodeI iError)
bool amountFromJsonNoThrow(STAmount &result, json::Value const &jvSource)
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
HashSet< PathAsset > accountSourceAssets(AccountID const &account, std::shared_ptr< AssetCache > const &lrCache, bool includeXRP)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
bool isTesSuccess(TER x) noexcept
AccountID const & xrpAccount()
Compute AccountID from public key.
static std::string const & systemCurrencyCode()
std::unordered_map< Key, Value, Hash, Pred, Allocator > HashMap
bool toIssuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.