rippled
Loading...
Searching...
No Matches
PathRequest.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012, 2013 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/main/Application.h>
21#include <xrpld/app/misc/LoadFeeTrack.h>
22#include <xrpld/app/misc/NetworkOPs.h>
23#include <xrpld/app/paths/AccountCurrencies.h>
24#include <xrpld/app/paths/PathRequest.h>
25#include <xrpld/app/paths/PathRequests.h>
26#include <xrpld/app/paths/RippleCalc.h>
27#include <xrpld/app/paths/detail/PathfinderUtils.h>
28#include <xrpld/core/Config.h>
29#include <xrpld/rpc/detail/Tuning.h>
30
31#include <xrpl/basics/Log.h>
32#include <xrpl/beast/core/LexicalCast.h>
33#include <xrpl/protocol/ErrorCodes.h>
34#include <xrpl/protocol/RPCErr.h>
35#include <xrpl/protocol/UintTypes.h>
36
37#include <optional>
38#include <tuple>
39
40namespace ripple {
41
43 Application& app,
44 std::shared_ptr<InfoSub> const& subscriber,
45 int id,
46 PathRequests& owner,
47 beast::Journal journal)
48 : app_(app)
49 , m_journal(journal)
50 , mOwner(owner)
51 , wpSubscriber(subscriber)
52 , consumer_(subscriber->getConsumer())
53 , jvStatus(Json::objectValue)
54 , mLastIndex(0)
55 , mInProgress(false)
56 , iLevel(0)
57 , bLastSuccess(false)
58 , iIdentifier(id)
59 , created_(std::chrono::steady_clock::now())
60{
61 JLOG(m_journal.debug()) << iIdentifier << " created";
62}
63
65 Application& app,
66 std::function<void(void)> const& completion,
67 Resource::Consumer& consumer,
68 int id,
69 PathRequests& owner,
70 beast::Journal journal)
71 : app_(app)
72 , m_journal(journal)
73 , mOwner(owner)
74 , fCompletion(completion)
75 , consumer_(consumer)
76 , jvStatus(Json::objectValue)
77 , mLastIndex(0)
78 , mInProgress(false)
79 , iLevel(0)
80 , bLastSuccess(false)
81 , iIdentifier(id)
82 , created_(std::chrono::steady_clock::now())
83{
84 JLOG(m_journal.debug()) << iIdentifier << " created";
85}
86
88{
89 using namespace std::chrono;
90 auto stream = m_journal.info();
91 if (!stream)
92 return;
93
94 std::string fast, full;
95 if (quick_reply_ != steady_clock::time_point{})
96 {
97 fast = " fast:";
98 fast += std::to_string(
99 duration_cast<milliseconds>(quick_reply_ - created_).count());
100 fast += "ms";
101 }
102 if (full_reply_ != steady_clock::time_point{})
103 {
104 full = " full:";
105 full += std::to_string(
106 duration_cast<milliseconds>(full_reply_ - created_).count());
107 full += "ms";
108 }
109 stream
110 << iIdentifier << " complete:" << fast << full << " total:"
111 << duration_cast<milliseconds>(steady_clock::now() - created_).count()
112 << "ms";
113}
114
115bool
117{
119
120 // does this path request still need its first full path
121 return mLastIndex == 0;
122}
123
124bool
126{
128
129 if (mInProgress)
130 {
131 // Another thread is handling this
132 return false;
133 }
134
135 if (newOnly && (mLastIndex != 0))
136 {
137 // Only handling new requests, this isn't new
138 return false;
139 }
140
141 if (mLastIndex >= index)
142 {
143 return false;
144 }
145
146 mInProgress = true;
147 return true;
148}
149
150bool
152{
153 return bool(fCompletion);
154}
155
156void
158{
160
161 XRPL_ASSERT(
162 mInProgress, "ripple::PathRequest::updateComplete : in progress");
163 mInProgress = false;
164
165 if (fCompletion)
166 {
167 fCompletion();
169 }
170}
171
172bool
174{
175 if (!raSrcAccount || !raDstAccount)
176 return false;
177
178 if (!convert_all_ && (saSendMax || saDstAmount <= beast::zero))
179 {
180 // If send max specified, dst amt must be -1.
182 return false;
183 }
184
185 auto const& lrLedger = crCache->getLedger();
186
187 if (!lrLedger->exists(keylet::account(*raSrcAccount)))
188 {
189 // Source account does not exist.
191 return false;
192 }
193
194 auto const sleDest = lrLedger->read(keylet::account(*raDstAccount));
195
196 Json::Value& jvDestCur =
197 (jvStatus[jss::destination_currencies] = Json::arrayValue);
198
199 if (!sleDest)
200 {
202 if (!saDstAmount.native())
203 {
204 // Only XRP can be send to a non-existent account.
206 return false;
207 }
208
209 if (!convert_all_ &&
210 saDstAmount < STAmount(lrLedger->fees().accountReserve(0)))
211 {
212 // Payment must meet reserve.
214 return false;
215 }
216 }
217 else
218 {
219 bool const disallowXRP(sleDest->getFlags() & lsfDisallowXRP);
220
221 auto usDestCurrID =
222 accountDestCurrencies(*raDstAccount, crCache, !disallowXRP);
223
224 for (auto const& currency : usDestCurrID)
225 jvDestCur.append(to_string(currency));
226 jvStatus[jss::destination_tag] =
227 (sleDest->getFlags() & lsfRequireDestTag);
228 }
229
230 jvStatus[jss::ledger_hash] = to_string(lrLedger->info().hash);
231 jvStatus[jss::ledger_index] = lrLedger->seq();
232 return true;
233}
234
235/* If this is a normal path request, we want to run it once "fast" now
236 to give preliminary results.
237
238 If this is a legacy path request, we are only going to run it once,
239 and we can't run it in full now, so we don't want to run it at all.
240
241 If there's an error, we need to be sure to return it to the caller
242 in all cases.
243*/
247 Json::Value const& value)
248{
249 bool valid = false;
250
251 if (parseJson(value) != PFR_PJ_INVALID)
252 {
253 valid = isValid(cache);
254 if (!hasCompletion() && valid)
255 doUpdate(cache, true);
256 }
257
258 if (auto stream = m_journal.debug())
259 {
260 if (valid)
261 {
262 stream << iIdentifier << " valid: " << toBase58(*raSrcAccount);
263 stream << iIdentifier << " deliver: " << saDstAmount.getFullText();
264 }
265 else
266 {
267 stream << iIdentifier << " invalid";
268 }
269 }
270
271 return {valid, jvStatus};
272}
273
274int
276{
277 if (!jvParams.isMember(jss::source_account))
278 {
280 return PFR_PJ_INVALID;
281 }
282
283 if (!jvParams.isMember(jss::destination_account))
284 {
286 return PFR_PJ_INVALID;
287 }
288
289 if (!jvParams.isMember(jss::destination_amount))
290 {
292 return PFR_PJ_INVALID;
293 }
294
296 parseBase58<AccountID>(jvParams[jss::source_account].asString());
297 if (!raSrcAccount)
298 {
300 return PFR_PJ_INVALID;
301 }
302
304 parseBase58<AccountID>(jvParams[jss::destination_account].asString());
305 if (!raDstAccount)
306 {
308 return PFR_PJ_INVALID;
309 }
310
311 if (!amountFromJsonNoThrow(saDstAmount, jvParams[jss::destination_amount]))
312 {
314 return PFR_PJ_INVALID;
315 }
316
318
319 if ((saDstAmount.getCurrency().isZero() &&
322 (!convert_all_ && saDstAmount <= beast::zero))
323 {
325 return PFR_PJ_INVALID;
326 }
327
328 if (jvParams.isMember(jss::send_max))
329 {
330 // Send_max requires destination amount to be -1.
331 if (!convert_all_)
332 {
334 return PFR_PJ_INVALID;
335 }
336
338 if (!amountFromJsonNoThrow(*saSendMax, jvParams[jss::send_max]) ||
339 (saSendMax->getCurrency().isZero() &&
340 saSendMax->getIssuer().isNonZero()) ||
341 (saSendMax->getCurrency() == badCurrency()) ||
342 (*saSendMax <= beast::zero &&
343 *saSendMax != STAmount(saSendMax->issue(), 1u, 0, true)))
344 {
346 return PFR_PJ_INVALID;
347 }
348 }
349
350 if (jvParams.isMember(jss::source_currencies))
351 {
352 Json::Value const& jvSrcCurrencies = jvParams[jss::source_currencies];
353 if (!jvSrcCurrencies.isArray() || jvSrcCurrencies.size() == 0 ||
354 jvSrcCurrencies.size() > RPC::Tuning::max_src_cur)
355 {
357 return PFR_PJ_INVALID;
358 }
359
360 sciSourceCurrencies.clear();
361
362 for (auto const& c : jvSrcCurrencies)
363 {
364 // Mandatory currency
365 Currency srcCurrencyID;
366 if (!c.isObject() || !c.isMember(jss::currency) ||
367 !c[jss::currency].isString() ||
368 !to_currency(srcCurrencyID, c[jss::currency].asString()))
369 {
371 return PFR_PJ_INVALID;
372 }
373
374 // Optional issuer
375 AccountID srcIssuerID;
376 if (c.isMember(jss::issuer) &&
377 (!c[jss::issuer].isString() ||
378 !to_issuer(srcIssuerID, c[jss::issuer].asString())))
379 {
381 return PFR_PJ_INVALID;
382 }
383
384 if (srcCurrencyID.isZero())
385 {
386 if (srcIssuerID.isNonZero())
387 {
389 return PFR_PJ_INVALID;
390 }
391 }
392 else if (srcIssuerID.isZero())
393 {
394 srcIssuerID = *raSrcAccount;
395 }
396
397 if (saSendMax)
398 {
399 // If the currencies don't match, ignore the source currency.
400 if (srcCurrencyID == saSendMax->getCurrency())
401 {
402 // If neither is the source and they are not equal, then the
403 // source issuer is illegal.
404 if (srcIssuerID != *raSrcAccount &&
405 saSendMax->getIssuer() != *raSrcAccount &&
406 srcIssuerID != saSendMax->getIssuer())
407 {
409 return PFR_PJ_INVALID;
410 }
411
412 // If both are the source, use the source.
413 // Otherwise, use the one that's not the source.
414 if (srcIssuerID != *raSrcAccount)
415 {
416 sciSourceCurrencies.insert(
417 {srcCurrencyID, srcIssuerID});
418 }
419 else if (saSendMax->getIssuer() != *raSrcAccount)
420 {
421 sciSourceCurrencies.insert(
422 {srcCurrencyID, saSendMax->getIssuer()});
423 }
424 else
425 {
426 sciSourceCurrencies.insert(
427 {srcCurrencyID, *raSrcAccount});
428 }
429 }
430 }
431 else
432 {
433 sciSourceCurrencies.insert({srcCurrencyID, srcIssuerID});
434 }
435 }
436 }
437
438 if (jvParams.isMember(jss::id))
439 jvId = jvParams[jss::id];
440
441 return PFR_PJ_NOCHANGE;
442}
443
446{
447 JLOG(m_journal.debug()) << iIdentifier << " closed";
449 jvStatus[jss::closed] = true;
450 return jvStatus;
451}
452
455{
457 jvStatus[jss::status] = jss::success;
458 return jvStatus;
459}
460
461void
463{
464 JLOG(m_journal.info()) << iIdentifier << " aborting early";
465}
466
471 Currency const& currency,
472 STAmount const& dst_amount,
473 int const level,
474 std::function<bool(void)> const& continueCallback)
475{
476 auto i = currency_map.find(currency);
477 if (i != currency_map.end())
478 return i->second;
479 auto pathfinder = std::make_unique<Pathfinder>(
480 cache,
483 currency,
484 std::nullopt,
485 dst_amount,
486 saSendMax,
487 app_);
488 if (pathfinder->findPaths(level, continueCallback))
489 pathfinder->computePathRanks(max_paths_, continueCallback);
490 else
491 pathfinder.reset(); // It's a bad request - clear it.
492 return currency_map[currency] = std::move(pathfinder);
493}
494
495bool
498 int const level,
499 Json::Value& jvArray,
500 std::function<bool(void)> const& continueCallback)
501{
502 auto sourceCurrencies = sciSourceCurrencies;
503 if (sourceCurrencies.empty() && saSendMax)
504 {
505 sourceCurrencies.insert(saSendMax->issue());
506 }
507 if (sourceCurrencies.empty())
508 {
509 auto currencies = accountSourceCurrencies(*raSrcAccount, cache, true);
510 bool const sameAccount = *raSrcAccount == *raDstAccount;
511 for (auto const& c : currencies)
512 {
513 if (!sameAccount || c != saDstAmount.getCurrency())
514 {
515 if (sourceCurrencies.size() >= RPC::Tuning::max_auto_src_cur)
516 return false;
517 sourceCurrencies.insert(
518 {c, c.isZero() ? xrpAccount() : *raSrcAccount});
519 }
520 }
521 }
522
523 auto const dst_amount = convertAmount(saDstAmount, convert_all_);
525 for (auto const& issue : sourceCurrencies)
526 {
527 if (continueCallback && !continueCallback())
528 break;
529 JLOG(m_journal.debug())
530 << iIdentifier
531 << " Trying to find paths: " << STAmount(issue, 1).getFullText();
532
533 auto& pathfinder = getPathFinder(
534 cache,
535 currency_map,
536 issue.currency,
537 dst_amount,
538 level,
539 continueCallback);
540 if (!pathfinder)
541 {
542 JLOG(m_journal.debug()) << iIdentifier << " No paths found";
543 continue;
544 }
545
546 STPath fullLiquidityPath;
547 auto ps = pathfinder->getBestPaths(
549 fullLiquidityPath,
550 mContext[issue],
551 issue.account,
552 continueCallback);
553 mContext[issue] = ps;
554
555 auto const& sourceAccount = [&] {
556 if (!isXRP(issue.account))
557 return issue.account;
558
559 if (isXRP(issue.currency))
560 return xrpAccount();
561
562 return *raSrcAccount;
563 }();
564
565 STAmount saMaxAmount = saSendMax.value_or(
566 STAmount(Issue{issue.currency, sourceAccount}, 1u, 0, true));
567
568 JLOG(m_journal.debug())
569 << iIdentifier << " Paths found, calling rippleCalc";
570
572 if (convert_all_)
573 rcInput.partialPaymentAllowed = true;
574 auto sandbox =
575 std::make_unique<PaymentSandbox>(&*cache->getLedger(), tapNONE);
577 *sandbox,
578 saMaxAmount, // --> Amount to send is unlimited
579 // to get an estimate.
580 dst_amount, // --> Amount to deliver.
581 *raDstAccount, // --> Account to deliver to.
582 *raSrcAccount, // --> Account sending from.
583 ps, // --> Path set.
584 app_.logs(),
585 &rcInput);
586
587 if (!convert_all_ && !fullLiquidityPath.empty() &&
588 (rc.result() == terNO_LINE || rc.result() == tecPATH_PARTIAL))
589 {
590 JLOG(m_journal.debug())
591 << iIdentifier << " Trying with an extra path element";
592
593 ps.push_back(fullLiquidityPath);
594 sandbox =
595 std::make_unique<PaymentSandbox>(&*cache->getLedger(), tapNONE);
597 *sandbox,
598 saMaxAmount, // --> Amount to send is unlimited
599 // to get an estimate.
600 dst_amount, // --> Amount to deliver.
601 *raDstAccount, // --> Account to deliver to.
602 *raSrcAccount, // --> Account sending from.
603 ps, // --> Path set.
604 app_.logs());
605
606 if (rc.result() != tesSUCCESS)
607 {
608 JLOG(m_journal.warn())
609 << iIdentifier << " Failed with covering path "
610 << transHuman(rc.result());
611 }
612 else
613 {
614 JLOG(m_journal.debug())
615 << iIdentifier << " Extra path element gives "
616 << transHuman(rc.result());
617 }
618 }
619
620 if (rc.result() == tesSUCCESS)
621 {
623 rc.actualAmountIn.setIssuer(sourceAccount);
624 jvEntry[jss::source_amount] =
625 rc.actualAmountIn.getJson(JsonOptions::none);
626 jvEntry[jss::paths_computed] = ps.getJson(JsonOptions::none);
627
628 if (convert_all_)
629 jvEntry[jss::destination_amount] =
630 rc.actualAmountOut.getJson(JsonOptions::none);
631
632 if (hasCompletion())
633 {
634 // Old ripple_path_find API requires this
635 jvEntry[jss::paths_canonical] = Json::arrayValue;
636 }
637
638 jvArray.append(jvEntry);
639 }
640 else
641 {
642 JLOG(m_journal.debug()) << iIdentifier << " rippleCalc returns "
643 << transHuman(rc.result());
644 }
645 }
646
647 /* The resource fee is based on the number of source currencies used.
648 The minimum cost is 50 and the maximum is 400. The cost increases
649 after four source currencies, 50 - (4 * 4) = 34.
650 */
651 int const size = sourceCurrencies.size();
652 consumer_.charge({std::clamp(size * size + 34, 50, 400), "path update"});
653 return true;
654}
655
659 bool fast,
660 std::function<bool(void)> const& continueCallback)
661{
662 using namespace std::chrono;
663 JLOG(m_journal.debug())
664 << iIdentifier << " update " << (fast ? "fast" : "normal");
665
666 {
668
669 if (!isValid(cache))
670 return jvStatus;
671 }
672
673 Json::Value newStatus = Json::objectValue;
674
675 if (hasCompletion())
676 {
677 // Old ripple_path_find API gives destination_currencies
678 auto& destCurrencies =
679 (newStatus[jss::destination_currencies] = Json::arrayValue);
680 auto usCurrencies = accountDestCurrencies(*raDstAccount, cache, true);
681 for (auto const& c : usCurrencies)
682 destCurrencies.append(to_string(c));
683 }
684
685 newStatus[jss::source_account] = toBase58(*raSrcAccount);
686 newStatus[jss::destination_account] = toBase58(*raDstAccount);
687 newStatus[jss::destination_amount] = saDstAmount.getJson(JsonOptions::none);
688 newStatus[jss::full_reply] = !fast;
689
690 if (jvId)
691 newStatus[jss::id] = jvId;
692
693 bool loaded = app_.getFeeTrack().isLoadedLocal();
694
695 if (iLevel == 0)
696 {
697 // first pass
698 if (loaded || fast)
700 else
702 }
703 else if ((iLevel == app_.config().PATH_SEARCH_FAST) && !fast)
704 {
705 // leaving fast pathfinding
707 if (loaded && (iLevel > app_.config().PATH_SEARCH_FAST))
708 --iLevel;
709 }
710 else if (bLastSuccess)
711 {
712 // decrement, if possible
713 if (iLevel > app_.config().PATH_SEARCH ||
714 (loaded && (iLevel > app_.config().PATH_SEARCH_FAST)))
715 --iLevel;
716 }
717 else
718 {
719 // adjust as needed
720 if (!loaded && (iLevel < app_.config().PATH_SEARCH_MAX))
721 ++iLevel;
722 if (loaded && (iLevel > app_.config().PATH_SEARCH_FAST))
723 --iLevel;
724 }
725
726 JLOG(m_journal.debug()) << iIdentifier << " processing at level " << iLevel;
727
729 if (findPaths(cache, iLevel, jvArray, continueCallback))
730 {
731 bLastSuccess = jvArray.size() != 0;
732 newStatus[jss::alternatives] = std::move(jvArray);
733 }
734 else
735 {
736 bLastSuccess = false;
737 newStatus = rpcError(rpcINTERNAL);
738 }
739
740 if (fast && quick_reply_ == steady_clock::time_point{})
741 {
742 quick_reply_ = steady_clock::now();
743 mOwner.reportFast(duration_cast<milliseconds>(quick_reply_ - created_));
744 }
745 else if (!fast && full_reply_ == steady_clock::time_point{})
746 {
747 full_reply_ = steady_clock::now();
748 mOwner.reportFull(duration_cast<milliseconds>(full_reply_ - created_));
749 }
750
751 {
753 jvStatus = newStatus;
754 }
755
756 JLOG(m_journal.debug())
757 << iIdentifier << " update finished " << (fast ? "fast" : "normal");
758 return newStatus;
759}
760
763{
764 return wpSubscriber.lock();
765}
766
767} // namespace ripple
T clamp(T... args)
Represents a JSON value.
Definition: json_value.h:150
bool isArray() const
Value & append(Value const &value)
Append value to array at the end.
Definition: json_value.cpp:910
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:719
bool isMember(char const *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:962
A generic endpoint for log messages.
Definition: Journal.h:60
Stream debug() const
Definition: Journal.h:328
Stream info() const
Definition: Journal.h:334
Stream warn() const
Definition: Journal.h:340
virtual Config & config()=0
virtual LoadFeeTrack & getFeeTrack()=0
virtual Logs & logs()=0
int PATH_SEARCH
Definition: Config.h:196
int PATH_SEARCH_MAX
Definition: Config.h:198
int PATH_SEARCH_FAST
Definition: Config.h:197
A currency issued by an account.
Definition: Issue.h:36
Currency currency
Definition: Issue.h:38
bool isLoadedLocal() const
Definition: LoadFeeTrack.h:126
std::optional< STAmount > saSendMax
Definition: PathRequest.h:154
std::function< void(void)> fCompletion
Definition: PathRequest.h:144
static unsigned int const max_paths_
Definition: PathRequest.h:174
bool findPaths(std::shared_ptr< RippleLineCache > const &, int const, Json::Value &, std::function< bool(void)> const &)
Finds and sets a PathSet in the JSON argument.
Json::Value doClose() override
std::weak_ptr< InfoSub > wpSubscriber
Definition: PathRequest.h:143
Json::Value doStatus(Json::Value const &) override
std::set< Issue > sciSourceCurrencies
Definition: PathRequest.h:156
int parseJson(Json::Value const &)
bool needsUpdate(bool newOnly, LedgerIndex index)
PathRequest(Application &app, std::shared_ptr< InfoSub > const &subscriber, int id, PathRequests &, beast::Journal journal)
Definition: PathRequest.cpp:42
std::recursive_mutex mLock
Definition: PathRequest.h:139
int const iIdentifier
Definition: PathRequest.h:168
std::recursive_mutex mIndexLock
Definition: PathRequest.h:161
Resource::Consumer & consumer_
Definition: PathRequest.h:145
std::optional< AccountID > raSrcAccount
Definition: PathRequest.h:151
InfoSub::pointer getSubscriber() const
Json::Value doUpdate(std::shared_ptr< RippleLineCache > const &, bool fast, std::function< bool(void)> const &continueCallback={})
PathRequests & mOwner
Definition: PathRequest.h:141
std::chrono::steady_clock::time_point full_reply_
Definition: PathRequest.h:172
LedgerIndex mLastIndex
Definition: PathRequest.h:162
std::pair< bool, Json::Value > doCreate(std::shared_ptr< RippleLineCache > const &, Json::Value const &)
Application & app_
Definition: PathRequest.h:136
Json::Value jvStatus
Definition: PathRequest.h:148
void doAborting() const
std::chrono::steady_clock::time_point quick_reply_
Definition: PathRequest.h:171
Json::Value jvId
Definition: PathRequest.h:147
std::map< Issue, STPathSet > mContext
Definition: PathRequest.h:157
std::optional< AccountID > raDstAccount
Definition: PathRequest.h:152
std::chrono::steady_clock::time_point const created_
Definition: PathRequest.h:170
beast::Journal m_journal
Definition: PathRequest.h:137
std::unique_ptr< Pathfinder > const & getPathFinder(std::shared_ptr< RippleLineCache > const &, hash_map< Currency, std::unique_ptr< Pathfinder > > &, Currency const &, STAmount const &, int const, std::function< bool(void)> const &)
bool isValid(std::shared_ptr< RippleLineCache > const &crCache)
void reportFast(std::chrono::milliseconds ms)
Definition: PathRequests.h:90
void reportFull(std::chrono::milliseconds ms)
Definition: PathRequests.h:96
An endpoint that consumes resources.
Definition: Consumer.h:35
Disposition charge(Charge const &fee, std::string const &context={})
Apply a load charge to the consumer.
Definition: Consumer.cpp:106
Json::Value getJson(JsonOptions=JsonOptions::none) const override
Definition: STAmount.cpp:639
Currency const & getCurrency() const
Definition: STAmount.h:502
AccountID const & getIssuer() const
Definition: STAmount.h:508
Issue const & issue() const
Definition: STAmount.h:496
std::string getFullText() const override
Definition: STAmount.cpp:540
bool native() const noexcept
Definition: STAmount.h:458
bool empty() const
Definition: STPathSet.h:404
bool isZero() const
Definition: base_uint.h:540
bool isNonZero() const
Definition: base_uint.h:545
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)
Definition: RippleCalc.cpp:32
T emplace(T... args)
T lock(T... args)
JSON (JavaScript Object Notation).
Definition: json_errors.h:25
@ arrayValue
array value (ordered list)
Definition: json_value.h:45
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:46
static int constexpr max_src_cur
Maximum number of source currencies allowed in a path find request.
static int constexpr max_auto_src_cur
Maximum number of auto source currencies in a path find request.
TER valid(PreclaimContext const &ctx, AccountID const &src)
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:177
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::string transHuman(TER code)
Definition: TER.cpp:271
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:114
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
Definition: UintTypes.cpp:133
STAmount convertAmount(STAmount const &amt, bool all)
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
AccountID const & xrpAccount()
Compute AccountID from public key.
Definition: AccountID.cpp:178
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
Definition: AccountID.cpp:192
@ rpcACT_NOT_FOUND
Definition: ErrorCodes.h:70
@ rpcDST_ACT_MISSING
Definition: ErrorCodes.h:104
@ rpcSRC_ACT_NOT_FOUND
Definition: ErrorCodes.h:122
@ rpcSENDMAX_MALFORMED
Definition: ErrorCodes.h:119
@ rpcINTERNAL
Definition: ErrorCodes.h:130
@ rpcSRC_ACT_MALFORMED
Definition: ErrorCodes.h:120
@ rpcSRC_ISR_MALFORMED
Definition: ErrorCodes.h:125
@ rpcDST_AMT_MALFORMED
Definition: ErrorCodes.h:106
@ rpcDST_ACT_MALFORMED
Definition: ErrorCodes.h:103
@ rpcSRC_CUR_MALFORMED
Definition: ErrorCodes.h:124
@ rpcDST_AMT_MISSING
Definition: ErrorCodes.h:107
@ rpcSRC_ACT_MISSING
Definition: ErrorCodes.h:121
hash_set< Currency > accountDestCurrencies(AccountID const &account, std::shared_ptr< RippleLineCache > const &lrCache, bool includeXRP)
hash_set< Currency > accountSourceCurrencies(AccountID const &account, std::shared_ptr< RippleLineCache > const &lrCache, bool includeXRP)
@ lsfRequireDestTag
@ lsfDisallowXRP
static std::string const & systemCurrencyCode()
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:31
@ tecPATH_PARTIAL
Definition: TER.h:282
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
Definition: STAmount.cpp:1007
@ tesSUCCESS
Definition: TER.h:244
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
@ tapNONE
Definition: ApplyView.h:32
@ terNO_LINE
Definition: TER.h:219
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:84
STL namespace.
T to_string(T... args)
T value_or(T... args)