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#include <xrpl/basics/Log.h>
31#include <xrpl/beast/core/LexicalCast.h>
32#include <xrpl/protocol/ErrorCodes.h>
33#include <xrpl/protocol/RPCErr.h>
34#include <xrpl/protocol/UintTypes.h>
35
36#include <optional>
37#include <tuple>
38
39namespace ripple {
40
42 Application& app,
43 const std::shared_ptr<InfoSub>& subscriber,
44 int id,
45 PathRequests& owner,
46 beast::Journal journal)
47 : app_(app)
48 , m_journal(journal)
49 , mOwner(owner)
50 , wpSubscriber(subscriber)
51 , consumer_(subscriber->getConsumer())
52 , jvStatus(Json::objectValue)
53 , mLastIndex(0)
54 , mInProgress(false)
55 , iLevel(0)
56 , bLastSuccess(false)
57 , iIdentifier(id)
58 , created_(std::chrono::steady_clock::now())
59{
60 JLOG(m_journal.debug()) << iIdentifier << " created";
61}
62
64 Application& app,
65 std::function<void(void)> const& completion,
66 Resource::Consumer& consumer,
67 int id,
68 PathRequests& owner,
69 beast::Journal journal)
70 : app_(app)
71 , m_journal(journal)
72 , mOwner(owner)
73 , fCompletion(completion)
74 , consumer_(consumer)
75 , jvStatus(Json::objectValue)
76 , mLastIndex(0)
77 , mInProgress(false)
78 , iLevel(0)
79 , bLastSuccess(false)
80 , iIdentifier(id)
81 , created_(std::chrono::steady_clock::now())
82{
83 JLOG(m_journal.debug()) << iIdentifier << " created";
84}
85
87{
88 using namespace std::chrono;
89 auto stream = m_journal.info();
90 if (!stream)
91 return;
92
93 std::string fast, full;
94 if (quick_reply_ != steady_clock::time_point{})
95 {
96 fast = " fast:";
97 fast += std::to_string(
98 duration_cast<milliseconds>(quick_reply_ - created_).count());
99 fast += "ms";
100 }
101 if (full_reply_ != steady_clock::time_point{})
102 {
103 full = " full:";
104 full += std::to_string(
105 duration_cast<milliseconds>(full_reply_ - created_).count());
106 full += "ms";
107 }
108 stream
109 << iIdentifier << " complete:" << fast << full << " total:"
110 << duration_cast<milliseconds>(steady_clock::now() - created_).count()
111 << "ms";
112}
113
114bool
116{
118
119 // does this path request still need its first full path
120 return mLastIndex == 0;
121}
122
123bool
125{
127
128 if (mInProgress)
129 {
130 // Another thread is handling this
131 return false;
132 }
133
134 if (newOnly && (mLastIndex != 0))
135 {
136 // Only handling new requests, this isn't new
137 return false;
138 }
139
140 if (mLastIndex >= index)
141 {
142 return false;
143 }
144
145 mInProgress = true;
146 return true;
147}
148
149bool
151{
152 return bool(fCompletion);
153}
154
155void
157{
159
160 XRPL_ASSERT(
161 mInProgress, "ripple::PathRequest::updateComplete : in progress");
162 mInProgress = false;
163
164 if (fCompletion)
165 {
166 fCompletion();
168 }
169}
170
171bool
173{
174 if (!raSrcAccount || !raDstAccount)
175 return false;
176
177 if (!convert_all_ && (saSendMax || saDstAmount <= beast::zero))
178 {
179 // If send max specified, dst amt must be -1.
181 return false;
182 }
183
184 auto const& lrLedger = crCache->getLedger();
185
186 if (!lrLedger->exists(keylet::account(*raSrcAccount)))
187 {
188 // Source account does not exist.
190 return false;
191 }
192
193 auto const sleDest = lrLedger->read(keylet::account(*raDstAccount));
194
195 Json::Value& jvDestCur =
196 (jvStatus[jss::destination_currencies] = Json::arrayValue);
197
198 if (!sleDest)
199 {
201 if (!saDstAmount.native())
202 {
203 // Only XRP can be send to a non-existent account.
205 return false;
206 }
207
208 if (!convert_all_ &&
209 saDstAmount < STAmount(lrLedger->fees().accountReserve(0)))
210 {
211 // Payment must meet reserve.
213 return false;
214 }
215 }
216 else
217 {
218 bool const disallowXRP(sleDest->getFlags() & lsfDisallowXRP);
219
220 auto usDestCurrID =
221 accountDestCurrencies(*raDstAccount, crCache, !disallowXRP);
222
223 for (auto const& currency : usDestCurrID)
224 jvDestCur.append(to_string(currency));
225 jvStatus[jss::destination_tag] =
226 (sleDest->getFlags() & lsfRequireDestTag);
227 }
228
229 jvStatus[jss::ledger_hash] = to_string(lrLedger->info().hash);
230 jvStatus[jss::ledger_index] = lrLedger->seq();
231 return true;
232}
233
234/* If this is a normal path request, we want to run it once "fast" now
235 to give preliminary results.
236
237 If this is a legacy path request, we are only going to run it once,
238 and we can't run it in full now, so we don't want to run it at all.
239
240 If there's an error, we need to be sure to return it to the caller
241 in all cases.
242*/
246 Json::Value const& value)
247{
248 bool valid = false;
249
250 if (parseJson(value) != PFR_PJ_INVALID)
251 {
252 valid = isValid(cache);
253 if (!hasCompletion() && valid)
254 doUpdate(cache, true);
255 }
256
257 if (auto stream = m_journal.debug())
258 {
259 if (valid)
260 {
261 stream << iIdentifier << " valid: " << toBase58(*raSrcAccount);
262 stream << iIdentifier << " deliver: " << saDstAmount.getFullText();
263 }
264 else
265 {
266 stream << iIdentifier << " invalid";
267 }
268 }
269
270 return {valid, jvStatus};
271}
272
273int
275{
276 if (!jvParams.isMember(jss::source_account))
277 {
279 return PFR_PJ_INVALID;
280 }
281
282 if (!jvParams.isMember(jss::destination_account))
283 {
285 return PFR_PJ_INVALID;
286 }
287
288 if (!jvParams.isMember(jss::destination_amount))
289 {
291 return PFR_PJ_INVALID;
292 }
293
295 parseBase58<AccountID>(jvParams[jss::source_account].asString());
296 if (!raSrcAccount)
297 {
299 return PFR_PJ_INVALID;
300 }
301
303 parseBase58<AccountID>(jvParams[jss::destination_account].asString());
304 if (!raDstAccount)
305 {
307 return PFR_PJ_INVALID;
308 }
309
310 if (!amountFromJsonNoThrow(saDstAmount, jvParams[jss::destination_amount]))
311 {
313 return PFR_PJ_INVALID;
314 }
315
317
318 if ((saDstAmount.getCurrency().isZero() &&
321 (!convert_all_ && saDstAmount <= beast::zero))
322 {
324 return PFR_PJ_INVALID;
325 }
326
327 if (jvParams.isMember(jss::send_max))
328 {
329 // Send_max requires destination amount to be -1.
330 if (!convert_all_)
331 {
333 return PFR_PJ_INVALID;
334 }
335
337 if (!amountFromJsonNoThrow(*saSendMax, jvParams[jss::send_max]) ||
338 (saSendMax->getCurrency().isZero() &&
339 saSendMax->getIssuer().isNonZero()) ||
340 (saSendMax->getCurrency() == badCurrency()) ||
341 (*saSendMax <= beast::zero &&
342 *saSendMax != STAmount(saSendMax->issue(), 1u, 0, true)))
343 {
345 return PFR_PJ_INVALID;
346 }
347 }
348
349 if (jvParams.isMember(jss::source_currencies))
350 {
351 Json::Value const& jvSrcCurrencies = jvParams[jss::source_currencies];
352 if (!jvSrcCurrencies.isArray() || jvSrcCurrencies.size() == 0 ||
353 jvSrcCurrencies.size() > RPC::Tuning::max_src_cur)
354 {
356 return PFR_PJ_INVALID;
357 }
358
359 sciSourceCurrencies.clear();
360
361 for (auto const& c : jvSrcCurrencies)
362 {
363 // Mandatory currency
364 Currency srcCurrencyID;
365 if (!c.isObject() || !c.isMember(jss::currency) ||
366 !c[jss::currency].isString() ||
367 !to_currency(srcCurrencyID, c[jss::currency].asString()))
368 {
370 return PFR_PJ_INVALID;
371 }
372
373 // Optional issuer
374 AccountID srcIssuerID;
375 if (c.isMember(jss::issuer) &&
376 (!c[jss::issuer].isString() ||
377 !to_issuer(srcIssuerID, c[jss::issuer].asString())))
378 {
380 return PFR_PJ_INVALID;
381 }
382
383 if (srcCurrencyID.isZero())
384 {
385 if (srcIssuerID.isNonZero())
386 {
388 return PFR_PJ_INVALID;
389 }
390 }
391 else if (srcIssuerID.isZero())
392 {
393 srcIssuerID = *raSrcAccount;
394 }
395
396 if (saSendMax)
397 {
398 // If the currencies don't match, ignore the source currency.
399 if (srcCurrencyID == saSendMax->getCurrency())
400 {
401 // If neither is the source and they are not equal, then the
402 // source issuer is illegal.
403 if (srcIssuerID != *raSrcAccount &&
404 saSendMax->getIssuer() != *raSrcAccount &&
405 srcIssuerID != saSendMax->getIssuer())
406 {
408 return PFR_PJ_INVALID;
409 }
410
411 // If both are the source, use the source.
412 // Otherwise, use the one that's not the source.
413 if (srcIssuerID != *raSrcAccount)
414 {
415 sciSourceCurrencies.insert(
416 {srcCurrencyID, srcIssuerID});
417 }
418 else if (saSendMax->getIssuer() != *raSrcAccount)
419 {
420 sciSourceCurrencies.insert(
421 {srcCurrencyID, saSendMax->getIssuer()});
422 }
423 else
424 {
425 sciSourceCurrencies.insert(
426 {srcCurrencyID, *raSrcAccount});
427 }
428 }
429 }
430 else
431 {
432 sciSourceCurrencies.insert({srcCurrencyID, srcIssuerID});
433 }
434 }
435 }
436
437 if (jvParams.isMember(jss::id))
438 jvId = jvParams[jss::id];
439
440 return PFR_PJ_NOCHANGE;
441}
442
445{
446 JLOG(m_journal.debug()) << iIdentifier << " closed";
448 jvStatus[jss::closed] = true;
449 return jvStatus;
450}
451
454{
456 jvStatus[jss::status] = jss::success;
457 return jvStatus;
458}
459
460void
462{
463 JLOG(m_journal.info()) << iIdentifier << " aborting early";
464}
465
470 Currency const& currency,
471 STAmount const& dst_amount,
472 int const level,
473 std::function<bool(void)> const& continueCallback)
474{
475 auto i = currency_map.find(currency);
476 if (i != currency_map.end())
477 return i->second;
478 auto pathfinder = std::make_unique<Pathfinder>(
479 cache,
482 currency,
483 std::nullopt,
484 dst_amount,
485 saSendMax,
486 app_);
487 if (pathfinder->findPaths(level, continueCallback))
488 pathfinder->computePathRanks(max_paths_, continueCallback);
489 else
490 pathfinder.reset(); // It's a bad request - clear it.
491 return currency_map[currency] = std::move(pathfinder);
492}
493
494bool
497 int const level,
498 Json::Value& jvArray,
499 std::function<bool(void)> const& continueCallback)
500{
501 auto sourceCurrencies = sciSourceCurrencies;
502 if (sourceCurrencies.empty() && saSendMax)
503 {
504 sourceCurrencies.insert(saSendMax->issue());
505 }
506 if (sourceCurrencies.empty())
507 {
508 auto currencies = accountSourceCurrencies(*raSrcAccount, cache, true);
509 bool const sameAccount = *raSrcAccount == *raDstAccount;
510 for (auto const& c : currencies)
511 {
512 if (!sameAccount || c != saDstAmount.getCurrency())
513 {
514 if (sourceCurrencies.size() >= RPC::Tuning::max_auto_src_cur)
515 return false;
516 sourceCurrencies.insert(
517 {c, c.isZero() ? xrpAccount() : *raSrcAccount});
518 }
519 }
520 }
521
522 auto const dst_amount = convertAmount(saDstAmount, convert_all_);
524 for (auto const& issue : sourceCurrencies)
525 {
526 if (continueCallback && !continueCallback())
527 break;
528 JLOG(m_journal.debug())
529 << iIdentifier
530 << " Trying to find paths: " << STAmount(issue, 1).getFullText();
531
532 auto& pathfinder = getPathFinder(
533 cache,
534 currency_map,
535 issue.currency,
536 dst_amount,
537 level,
538 continueCallback);
539 if (!pathfinder)
540 {
541 JLOG(m_journal.debug()) << iIdentifier << " No paths found";
542 continue;
543 }
544
545 STPath fullLiquidityPath;
546 auto ps = pathfinder->getBestPaths(
548 fullLiquidityPath,
549 mContext[issue],
550 issue.account,
551 continueCallback);
552 mContext[issue] = ps;
553
554 auto const& sourceAccount = [&] {
555 if (!isXRP(issue.account))
556 return issue.account;
557
558 if (isXRP(issue.currency))
559 return xrpAccount();
560
561 return *raSrcAccount;
562 }();
563
564 STAmount saMaxAmount = saSendMax.value_or(
565 STAmount(Issue{issue.currency, sourceAccount}, 1u, 0, true));
566
567 JLOG(m_journal.debug())
568 << iIdentifier << " Paths found, calling rippleCalc";
569
571 if (convert_all_)
572 rcInput.partialPaymentAllowed = true;
573 auto sandbox =
574 std::make_unique<PaymentSandbox>(&*cache->getLedger(), tapNONE);
576 *sandbox,
577 saMaxAmount, // --> Amount to send is unlimited
578 // to get an estimate.
579 dst_amount, // --> Amount to deliver.
580 *raDstAccount, // --> Account to deliver to.
581 *raSrcAccount, // --> Account sending from.
582 ps, // --> Path set.
583 app_.logs(),
584 &rcInput);
585
586 if (!convert_all_ && !fullLiquidityPath.empty() &&
587 (rc.result() == terNO_LINE || rc.result() == tecPATH_PARTIAL))
588 {
589 JLOG(m_journal.debug())
590 << iIdentifier << " Trying with an extra path element";
591
592 ps.push_back(fullLiquidityPath);
593 sandbox =
594 std::make_unique<PaymentSandbox>(&*cache->getLedger(), tapNONE);
596 *sandbox,
597 saMaxAmount, // --> Amount to send is unlimited
598 // to get an estimate.
599 dst_amount, // --> Amount to deliver.
600 *raDstAccount, // --> Account to deliver to.
601 *raSrcAccount, // --> Account sending from.
602 ps, // --> Path set.
603 app_.logs());
604
605 if (rc.result() != tesSUCCESS)
606 {
607 JLOG(m_journal.warn())
608 << iIdentifier << " Failed with covering path "
609 << transHuman(rc.result());
610 }
611 else
612 {
613 JLOG(m_journal.debug())
614 << iIdentifier << " Extra path element gives "
615 << transHuman(rc.result());
616 }
617 }
618
619 if (rc.result() == tesSUCCESS)
620 {
622 rc.actualAmountIn.setIssuer(sourceAccount);
623 jvEntry[jss::source_amount] =
624 rc.actualAmountIn.getJson(JsonOptions::none);
625 jvEntry[jss::paths_computed] = ps.getJson(JsonOptions::none);
626
627 if (convert_all_)
628 jvEntry[jss::destination_amount] =
629 rc.actualAmountOut.getJson(JsonOptions::none);
630
631 if (hasCompletion())
632 {
633 // Old ripple_path_find API requires this
634 jvEntry[jss::paths_canonical] = Json::arrayValue;
635 }
636
637 jvArray.append(jvEntry);
638 }
639 else
640 {
641 JLOG(m_journal.debug()) << iIdentifier << " rippleCalc returns "
642 << transHuman(rc.result());
643 }
644 }
645
646 /* The resource fee is based on the number of source currencies used.
647 The minimum cost is 50 and the maximum is 400. The cost increases
648 after four source currencies, 50 - (4 * 4) = 34.
649 */
650 int const size = sourceCurrencies.size();
651 consumer_.charge({std::clamp(size * size + 34, 50, 400), "path update"});
652 return true;
653}
654
658 bool fast,
659 std::function<bool(void)> const& continueCallback)
660{
661 using namespace std::chrono;
662 JLOG(m_journal.debug())
663 << iIdentifier << " update " << (fast ? "fast" : "normal");
664
665 {
667
668 if (!isValid(cache))
669 return jvStatus;
670 }
671
672 Json::Value newStatus = Json::objectValue;
673
674 if (hasCompletion())
675 {
676 // Old ripple_path_find API gives destination_currencies
677 auto& destCurrencies =
678 (newStatus[jss::destination_currencies] = Json::arrayValue);
679 auto usCurrencies = accountDestCurrencies(*raDstAccount, cache, true);
680 for (auto const& c : usCurrencies)
681 destCurrencies.append(to_string(c));
682 }
683
684 newStatus[jss::source_account] = toBase58(*raSrcAccount);
685 newStatus[jss::destination_account] = toBase58(*raDstAccount);
686 newStatus[jss::destination_amount] = saDstAmount.getJson(JsonOptions::none);
687 newStatus[jss::full_reply] = !fast;
688
689 if (jvId)
690 newStatus[jss::id] = jvId;
691
692 bool loaded = app_.getFeeTrack().isLoadedLocal();
693
694 if (iLevel == 0)
695 {
696 // first pass
697 if (loaded || fast)
699 else
701 }
702 else if ((iLevel == app_.config().PATH_SEARCH_FAST) && !fast)
703 {
704 // leaving fast pathfinding
706 if (loaded && (iLevel > app_.config().PATH_SEARCH_FAST))
707 --iLevel;
708 }
709 else if (bLastSuccess)
710 {
711 // decrement, if possible
712 if (iLevel > app_.config().PATH_SEARCH ||
713 (loaded && (iLevel > app_.config().PATH_SEARCH_FAST)))
714 --iLevel;
715 }
716 else
717 {
718 // adjust as needed
719 if (!loaded && (iLevel < app_.config().PATH_SEARCH_MAX))
720 ++iLevel;
721 if (loaded && (iLevel > app_.config().PATH_SEARCH_FAST))
722 --iLevel;
723 }
724
725 JLOG(m_journal.debug()) << iIdentifier << " processing at level " << iLevel;
726
728 if (findPaths(cache, iLevel, jvArray, continueCallback))
729 {
730 bLastSuccess = jvArray.size() != 0;
731 newStatus[jss::alternatives] = std::move(jvArray);
732 }
733 else
734 {
735 bLastSuccess = false;
736 newStatus = rpcError(rpcINTERNAL);
737 }
738
739 if (fast && quick_reply_ == steady_clock::time_point{})
740 {
741 quick_reply_ = steady_clock::now();
742 mOwner.reportFast(duration_cast<milliseconds>(quick_reply_ - created_));
743 }
744 else if (!fast && full_reply_ == steady_clock::time_point{})
745 {
746 full_reply_ = steady_clock::now();
747 mOwner.reportFull(duration_cast<milliseconds>(full_reply_ - created_));
748 }
749
750 {
752 jvStatus = newStatus;
753 }
754
755 JLOG(m_journal.debug())
756 << iIdentifier << " update finished " << (fast ? "fast" : "normal");
757 return newStatus;
758}
759
762{
763 return wpSubscriber.lock();
764}
765
766} // namespace ripple
T clamp(T... args)
Represents a JSON value.
Definition: json_value.h:148
bool isArray() const
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:712
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:897
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:949
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:153
std::function< void(void)> fCompletion
Definition: PathRequest.h:143
static unsigned int const max_paths_
Definition: PathRequest.h:173
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:142
Json::Value doStatus(Json::Value const &) override
std::set< Issue > sciSourceCurrencies
Definition: PathRequest.h:155
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:41
std::recursive_mutex mLock
Definition: PathRequest.h:138
int const iIdentifier
Definition: PathRequest.h:167
std::recursive_mutex mIndexLock
Definition: PathRequest.h:160
Resource::Consumer & consumer_
Definition: PathRequest.h:144
std::optional< AccountID > raSrcAccount
Definition: PathRequest.h:150
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:140
std::chrono::steady_clock::time_point full_reply_
Definition: PathRequest.h:171
LedgerIndex mLastIndex
Definition: PathRequest.h:161
std::pair< bool, Json::Value > doCreate(std::shared_ptr< RippleLineCache > const &, Json::Value const &)
Application & app_
Definition: PathRequest.h:135
Json::Value jvStatus
Definition: PathRequest.h:147
void doAborting() const
std::chrono::steady_clock::time_point quick_reply_
Definition: PathRequest.h:170
Json::Value jvId
Definition: PathRequest.h:146
std::map< Issue, STPathSet > mContext
Definition: PathRequest.h:156
std::optional< AccountID > raDstAccount
Definition: PathRequest.h:151
std::chrono::steady_clock::time_point const created_
Definition: PathRequest.h:169
beast::Journal m_journal
Definition: PathRequest.h:136
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) const override
Definition: STAmount.cpp:636
Currency const & getCurrency() const
Definition: STAmount.h:493
AccountID const & getIssuer() const
Definition: STAmount.h:499
Issue const & issue() const
Definition: STAmount.h:487
std::string getFullText() const override
Definition: STAmount.cpp:537
bool native() const noexcept
Definition: STAmount.h:449
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:31
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:43
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:44
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:175
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:266
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:269
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
Definition: STAmount.cpp:1061
@ tesSUCCESS
Definition: TER.h:242
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
@ tapNONE
Definition: ApplyView.h:31
@ 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)