Compare commits

...

3 Commits

Author SHA1 Message Date
Vinnie Falco
95f31b98a8 Set version to 0.26.4-sp2 2014-11-11 14:22:37 -08:00
Miguel Portilla
10d74ed100 Fix account_lines, account_offers and book_offers result (RIPD-682):
The RPC account_lines and account_offers commands respond with the correct ledger info. account_offers, account_lines and book_offers allow admins unlimited size on the limit param. Specifying a negative value on limit clamps to the minimum value allowed. Incorrect types for limit are correctly reported in the result.
2014-11-11 14:21:49 -08:00
Vinnie Falco
8a7f612d5b Revert pathfinding changes:
* 5e7c527 Revert "Fix account_lines, account_offers and book_offers result (RIPD-682):"
* b3417ca Revert "Fix pathfinding with multiple issuers for one currency (RIPD-618)."
* 00db7f5 Revert "Clean up Pathfinder."
2014-11-11 14:21:40 -08:00
19 changed files with 686 additions and 1321 deletions

View File

@@ -1,5 +1,5 @@
Name: rippled
Version: 0.26.4-sp1
Version: 0.26.4-sp2
Release: 1%{?dist}
Summary: Ripple peer-to-peer network daemon

View File

@@ -24,7 +24,6 @@
#include <ripple/common/RippleSSLContext.h>
#include <ripple/app/main/Tuning.h>
#include <ripple/app/misc/ProofOfWorkFactory.h>
#include <ripple/app/paths/FindPaths.h>
#include <ripple/core/LoadFeeTrack.h>
#include <ripple/rpc/Manager.h>
#include <ripple/nodestore/Database.h>
@@ -653,7 +652,7 @@ public:
updateTables ();
m_amendmentTable->addInitial();
initializePathfinding ();
Pathfinder::initPathTable ();
m_ledgerMaster->setMinValidations (getConfig ().VALIDATION_QUORUM);

View File

@@ -1,93 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/app/paths/AccountCurrencies.h>
namespace ripple {
CurrencySet accountSourceCurrencies (
RippleAddress const& raAccountID,
RippleLineCache::ref lrCache,
bool includeXRP)
{
CurrencySet currencies;
// YYY Only bother if they are above reserve
if (includeXRP)
currencies.insert (xrpCurrency());
// List of ripple lines.
auto& rippleLines (lrCache->getRippleLines (raAccountID.getAccountID ()));
for (auto const& item : rippleLines)
{
auto rspEntry = (RippleState*) item.get ();
assert (rspEntry);
if (!rspEntry)
continue;
auto& saBalance = rspEntry->getBalance ();
// Filter out non
if (saBalance > zero
// Have IOUs to send.
|| (rspEntry->getLimitPeer ()
// Peer extends credit.
&& ((-saBalance) < rspEntry->getLimitPeer ()))) // Credit left.
{
currencies.insert (saBalance.getCurrency ());
}
}
currencies.erase (badCurrency());
return currencies;
}
CurrencySet accountDestCurrencies (
RippleAddress const& raAccountID,
RippleLineCache::ref lrCache,
bool includeXRP)
{
CurrencySet currencies;
if (includeXRP)
currencies.insert (xrpCurrency());
// Even if account doesn't exist
// List of ripple lines.
auto& rippleLines (lrCache->getRippleLines (raAccountID.getAccountID ()));
for (auto const& item : rippleLines)
{
auto rspEntry = (RippleState*) item.get ();
assert (rspEntry);
if (!rspEntry)
continue;
auto& saBalance = rspEntry->getBalance ();
if (saBalance < rspEntry->getLimit ()) // Can take more
currencies.insert (saBalance.getCurrency ());
}
currencies.erase (badCurrency());
return currencies;
}
} // ripple

View File

@@ -1,37 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLED_RIPPLE_APP_PATHS_ACCOUNTCURRENCIES_H
#define RIPPLED_RIPPLE_APP_PATHS_ACCOUNTCURRENCIES_H
namespace ripple {
CurrencySet accountDestCurrencies
(RippleAddress const& raAccountID,
RippleLineCache::ref cache,
bool includeXRP);
CurrencySet accountSourceCurrencies
(RippleAddress const& raAccountID,
RippleLineCache::ref lrLedger,
bool includeXRP);
} // ripple
#endif

View File

@@ -1,73 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/app/paths/Credit.h>
namespace ripple {
STAmount creditLimit (
LedgerEntrySet& ledger,
Account const& account,
Account const& issuer,
Currency const& currency)
{
STAmount result ({currency, account});
auto sleRippleState = ledger.entryCache (ltRIPPLE_STATE,
Ledger::getRippleStateIndex (account, issuer, currency));
if (sleRippleState)
{
result = sleRippleState->getFieldAmount (
account < issuer ? sfLowLimit : sfHighLimit);
result.setIssuer (account);
}
assert (result.getIssuer () == account);
assert (result.getCurrency () == currency);
return result;
}
STAmount creditBalance (
LedgerEntrySet& ledger,
Account const& account,
Account const& issuer,
Currency const& currency)
{
STAmount result ({currency, account});
auto sleRippleState = ledger.entryCache (ltRIPPLE_STATE,
Ledger::getRippleStateIndex (account, issuer, currency));
if (sleRippleState)
{
result = sleRippleState->getFieldAmount (sfBalance);
if (account < issuer)
result.negate ();
result.setIssuer (account);
}
assert (result.getIssuer () == account);
assert (result.getCurrency () == currency);
return result;
}
} // ripple

View File

@@ -1,52 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLED_RIPPLE_APP_PATHS_CREDIT_H
#define RIPPLED_RIPPLE_APP_PATHS_CREDIT_H
namespace ripple {
/** Calculate the maximum amount of IOUs that an account can hold
@param ledger the ledger to check against.
@param account the account of interest.
@param issuer the issuer of the IOU.
@param currency the IOU to check.
@return The maximum amount that can be held.
*/
STAmount creditLimit (
LedgerEntrySet& ledger,
Account const& account,
Account const& issuer,
Currency const& currency);
/** Returns the amount of IOUs issued by issuer that are held by an account
@param ledger the ledger to check against.
@param account the account of interest.
@param issuer the issuer of the IOU.
@param currency the IOU to check.
*/
STAmount creditBalance (
LedgerEntrySet& ledger,
Account const& account,
Account const& issuer,
Currency const& currency);
} // ripple
#endif

View File

@@ -1,141 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/app/paths/FindPaths.h>
#include <ripple/app/paths/Pathfinder.h>
namespace ripple {
class FindPaths::Impl {
public:
Impl (
RippleLineCache::ref cache,
Account const& srcAccount,
Account const& dstAccount,
STAmount const& dstAmount,
int searchLevel,
unsigned int maxPaths)
: cache_ (cache),
srcAccount_ (srcAccount),
dstAccount_ (dstAccount),
dstAmount_ (dstAmount),
searchLevel_ (searchLevel),
maxPaths_ (maxPaths)
{
}
bool findPathsForIssue (
Issue const& issue,
STPathSet& pathsOut,
STPath& fullLiquidityPath)
{
if (auto& pathfinder = getPathFinder (issue.currency))
{
pathsOut = pathfinder->getBestPaths (
maxPaths_, fullLiquidityPath, issue.account);
return true;
}
return false;
}
private:
hash_map<Currency, std::unique_ptr<Pathfinder>> currencyMap_;
RippleLineCache::ref cache_;
Account const srcAccount_;
Account const dstAccount_;
STAmount const dstAmount_;
int const searchLevel_;
unsigned int const maxPaths_;
std::unique_ptr<Pathfinder> const& getPathFinder (Currency const& currency)
{
auto i = currencyMap_.find (currency);
if (i != currencyMap_.end ())
return i->second;
auto pathfinder = std::make_unique<Pathfinder> (
cache_, srcAccount_, dstAccount_, currency, dstAmount_);
if (pathfinder->findPaths (searchLevel_))
pathfinder->computePathRanks (maxPaths_);
else
pathfinder.reset (); // It's a bad request - clear it.
return currencyMap_[currency] = std::move (pathfinder);
// TODO(tom): why doesn't this faster way compile?
// return currencyMap_.insert (i, std::move (pathfinder)).second;
}
};
FindPaths::FindPaths (
RippleLineCache::ref cache,
Account const& srcAccount,
Account const& dstAccount,
STAmount const& dstAmount,
int level,
unsigned int maxPaths)
: impl_ (std::make_unique<Impl> (
cache, srcAccount, dstAccount, dstAmount, level, maxPaths))
{
}
FindPaths::~FindPaths() = default;
bool FindPaths::findPathsForIssue (
Issue const& issue,
STPathSet& pathsOut,
STPath& fullLiquidityPath)
{
return impl_->findPathsForIssue (issue, pathsOut, fullLiquidityPath);
}
bool findPathsForOneIssuer (
RippleLineCache::ref cache,
Account const& srcAccount,
Account const& dstAccount,
Issue const& srcIssue,
STAmount const& dstAmount,
int searchLevel,
unsigned int const maxPaths,
STPathSet& pathsOut,
STPath& fullLiquidityPath)
{
Pathfinder pf (
cache,
srcAccount,
dstAccount,
srcIssue.currency,
srcIssue.account,
dstAmount);
if (!pf.findPaths (searchLevel))
return false;
pf.addPathsFromPreviousPathfinding (pathsOut);
pf.computePathRanks (maxPaths);
pathsOut = pf.getBestPaths(maxPaths, fullLiquidityPath, srcIssue.account);
return true;
}
void initializePathfinding ()
{
Pathfinder::initPathTable ();
}
} // ripple

View File

@@ -1,93 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef RIPPLED_RIPPLE_APP_PATHS_FINDPATHS_H
#define RIPPLED_RIPPLE_APP_PATHS_FINDPATHS_H
namespace ripple {
class FindPaths
{
public:
FindPaths (
RippleLineCache::ref cache,
Account const& srcAccount,
Account const& dstAccount,
STAmount const& dstAmount,
/** searchLevel is the maximum search level allowed in an output path.
*/
int searchLevel,
/** maxPaths is the maximum number of paths that can be returned in
pathsOut. */
unsigned int const maxPaths);
~FindPaths();
bool findPathsForIssue (
Issue const& issue,
/** On input, pathsOut contains any paths you want to ensure are
included if still good.
On output, pathsOut will have any additional paths found. Only
non-default paths without source or destination will be added. */
STPathSet& pathsOut,
/** On input, fullLiquidityPath must be an empty STPath.
On output, if fullLiquidityPath is non-empty, it contains one extra
path that can move the entire liquidity requested. */
STPath& fullLiquidityPath);
private:
class Impl;
std::unique_ptr<Impl> impl_;
};
bool findPathsForOneIssuer (
RippleLineCache::ref cache,
Account const& srcAccount,
Account const& dstAccount,
Issue const& srcIssue,
STAmount const& dstAmount,
/** searchLevel is the maximum search level allowed in an output path. */
int searchLevel,
/** maxPaths is the maximum number of paths that can be returned in
pathsOut. */
unsigned int const maxPaths,
/** On input, pathsOut contains any paths you want to ensure are included if
still good.
On output, pathsOut will have any additional paths found. Only
non-default paths without source or destination will be added. */
STPathSet& pathsOut,
/** On input, fullLiquidityPath must be an empty STPath.
On output, if fullLiquidityPath is non-empty, it contains one extra path
that can move the entire liquidity requested. */
STPath& fullLiquidityPath);
void initializePathfinding ();
} // ripple
#endif

View File

@@ -17,31 +17,27 @@
*/
//==============================================================================
#include <ripple/app/paths/AccountCurrencies.h>
#include <ripple/app/paths/FindPaths.h>
#include <ripple/types/UintTypes.h>
#include <ripple/core/Config.h>
#include <ripple/core/LoadFeeTrack.h>
#include <ripple/types/UintTypes.h>
#include <boost/log/trivial.hpp>
#include <tuple>
namespace ripple {
PathRequest::PathRequest (
const std::shared_ptr<InfoSub>& subscriber,
int id,
PathRequests& owner,
const std::shared_ptr<InfoSub>& subscriber, int id, PathRequests& owner,
beast::Journal journal)
: m_journal (journal)
, mOwner (owner)
, wpSubscriber (subscriber)
, jvStatus (Json::objectValue)
, bValid (false)
, mLastIndex (0)
, mInProgress (false)
, iLastLevel (0)
, bLastSuccess (false)
, iIdentifier (id)
: m_journal (journal)
, mOwner (owner)
, wpSubscriber (subscriber)
, jvStatus (Json::objectValue)
, bValid (false)
, mLastIndex (0)
, mInProgress (false)
, iLastLevel (0)
, bLastSuccess (false)
, iIdentifier (id)
{
if (m_journal.debug)
m_journal.debug << iIdentifier << " created";
@@ -49,8 +45,7 @@ PathRequest::PathRequest (
}
static std::string const get_milli_diff (
boost::posix_time::ptime const& after,
boost::posix_time::ptime
boost::posix_time::ptime const& after, boost::posix_time::ptime
const& before)
{
return beast::lexicalCastThrow <std::string> (
@@ -179,7 +174,7 @@ bool PathRequest::isValid (RippleLineCache::ref crCache)
bool const disallowXRP (
asDst->peekSLE ().getFlags() & lsfDisallowXRP);
auto usDestCurrID = accountDestCurrencies (
auto usDestCurrID = usAccountDestCurrencies (
raDstAccount, crCache, !disallowXRP);
for (auto const& currency : usDestCurrID)
@@ -228,15 +223,11 @@ Json::Value PathRequest::doCreate (
{
if (bValid)
{
m_journal.debug << iIdentifier
<< " valid: " << raSrcAccount.humanAccountID ();
m_journal.debug << iIdentifier
<< " Deliver: " << saDstAmount.getFullText ();
m_journal.debug << iIdentifier << " valid: " << raSrcAccount.humanAccountID ();
m_journal.debug << iIdentifier << " Deliver: " << saDstAmount.getFullText ();
}
else
{
m_journal.debug << iIdentifier << " invalid";
}
}
valid = bValid;
@@ -277,12 +268,10 @@ int PathRequest::parseJson (Json::Value const& jvParams, bool complete)
if (jvParams.isMember ("destination_amount"))
{
if (! amountFromJsonNoThrow (
saDstAmount, jvParams["destination_amount"]) ||
(saDstAmount.getCurrency ().isZero () &&
saDstAmount.getIssuer ().isNonZero ()) ||
(saDstAmount.getCurrency () == badCurrency ()) ||
saDstAmount <= zero)
if (! amountFromJsonNoThrow (saDstAmount, jvParams["destination_amount"]) ||
(saDstAmount.getCurrency ().isZero () && saDstAmount.getIssuer ().isNonZero ()) ||
(saDstAmount.getCurrency () == badCurrency()) ||
saDstAmount <= zero)
{
jvStatus = rpcError (rpcDST_AMT_MALFORMED);
return PFR_PJ_INVALID;
@@ -331,11 +320,6 @@ int PathRequest::parseJson (Json::Value const& jvParams, bool complete)
return PFR_PJ_INVALID;
}
if (uCur.isNonZero() && uIss.isZero())
{
uIss = raSrcAccount.getAccountID();
}
sciSourceCurrencies.insert ({uCur, uIss});
}
}
@@ -379,16 +363,16 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
if (sourceCurrencies.empty ())
{
auto usCurrencies =
accountSourceCurrencies (raSrcAccount, cache, true);
usAccountSourceCurrencies (raSrcAccount, cache, true);
bool sameAccount = raSrcAccount == raDstAccount;
for (auto const& c: usCurrencies)
{
if (!sameAccount || (c != saDstAmount.getCurrency ()))
{
if (c.isZero ())
sourceCurrencies.insert ({c, xrpAccount()});
sourceCurrencies.insert (std::make_pair (c, xrpAccount()));
else
sourceCurrencies.insert ({c, raSrcAccount.getAccountID ()});
sourceCurrencies.insert (std::make_pair (c, raSrcAccount.getAccountID ()));
}
}
}
@@ -406,30 +390,26 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
bool loaded = getApp().getFeeTrack().isLoadedLocal();
if (iLevel == 0)
{
// first pass
{ // first pass
if (loaded || fast)
iLevel = getConfig().PATH_SEARCH_FAST;
else
iLevel = getConfig().PATH_SEARCH;
}
else if ((iLevel == getConfig().PATH_SEARCH_FAST) && !fast)
{
// leaving fast pathfinding
{ // leaving fast pathfinding
iLevel = getConfig().PATH_SEARCH;
if (loaded && (iLevel > getConfig().PATH_SEARCH_FAST))
--iLevel;
}
else if (bLastSuccess)
{
// decrement, if possible
{ // decrement, if possible
if (iLevel > getConfig().PATH_SEARCH ||
(loaded && (iLevel > getConfig().PATH_SEARCH_FAST)))
--iLevel;
}
else
{
// adjust as needed
{ // adjust as needed
if (!loaded && (iLevel < getConfig().PATH_SEARCH_MAX))
++iLevel;
if (loaded && (iLevel > getConfig().PATH_SEARCH_FAST))
@@ -440,17 +420,10 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
bool found = false;
FindPaths fp (
cache,
raSrcAccount.getAccountID (),
raDstAccount.getAccountID (),
saDstAmount,
iLevel,
4); // iMaxPaths
for (auto const& currIssuer: sourceCurrencies)
{
{
STAmount test (currIssuer, 1);
STAmount test ({currIssuer.first, currIssuer.second}, 1);
if (m_journal.debug)
{
m_journal.debug
@@ -458,28 +431,26 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
<< " Trying to find paths: " << test.getFullText ();
}
}
bool valid;
STPathSet& spsPaths = mContext[currIssuer];
STPath fullLiquidityPath;
auto valid = fp.findPathsForIssue (
currIssuer,
spsPaths,
fullLiquidityPath);
Pathfinder pf (cache, raSrcAccount, raDstAccount,
currIssuer.first, currIssuer.second, saDstAmount, valid);
CondLog (!valid, lsDEBUG, PathRequest)
<< iIdentifier << " PF request not valid";
if (valid)
STPath extraPath;
if (valid && pf.findPaths (iLevel, 4, spsPaths, extraPath))
{
LedgerEntrySet lesSandbox (cache->getLedger (), tapNONE);
auto& sourceAccount = !isXRP (currIssuer.account)
? currIssuer.account
: isXRP (currIssuer.currency)
auto& account = currIssuer.second.isNonZero ()
? Account(currIssuer.second)
: isXRP (currIssuer.first)
? xrpAccount()
: raSrcAccount.getAccountID ();
STAmount saMaxAmount ({currIssuer.currency, sourceAccount}, 1);
STAmount saMaxAmount ({currIssuer.first, account}, 1);
saMaxAmount.negate ();
m_journal.debug << iIdentifier
<< " Paths found, calling rippleCalc";
m_journal.debug << iIdentifier << " Paths found, calling rippleCalc";
auto rc = path::RippleCalc::rippleCalculate (
lesSandbox,
saMaxAmount,
@@ -488,15 +459,13 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
raSrcAccount.getAccountID (),
spsPaths);
if (!fullLiquidityPath.empty() &&
if (!extraPath.empty() &&
(rc.result () == terNO_LINE || rc.result () == tecPATH_PARTIAL))
{
m_journal.debug
<< iIdentifier << " Trying with an extra path element";
spsPaths.push_back (fullLiquidityPath);
lesSandbox.clear();
rc = path::RippleCalc::rippleCalculate (
lesSandbox,
spsPaths.push_back (extraPath);
rc = path::RippleCalc::rippleCalculate (lesSandbox,
saMaxAmount,
saDstAmount,
raDstAccount.getAccountID (),
@@ -515,10 +484,8 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
if (rc.result () == tesSUCCESS)
{
Json::Value jvEntry (Json::objectValue);
rc.actualAmountIn.setIssuer (sourceAccount);
jvEntry["source_amount"] = rc.actualAmountIn.getJson (0);
jvEntry["paths_computed"] = spsPaths.getJson (0);
jvEntry["source_amount"] = rc.actualAmountIn.getJson (0);
jvEntry["paths_computed"] = spsPaths.getJson (0);
found = true;
jvArray.append (jvEntry);
}

View File

@@ -45,13 +45,13 @@ public:
typedef const pointer& ref;
typedef const wptr& wref;
// TODO(tom): Use Issue instead!
typedef std::pair<Currency, Account> CurrencyIssuer;
public:
// VFALCO TODO Break the cyclic dependency on InfoSub
PathRequest (
std::shared_ptr <InfoSub> const& subscriber,
int id,
PathRequests&,
beast::Journal journal);
PathRequest (std::shared_ptr <InfoSub> const& subscriber,
int id, PathRequests&, beast::Journal journal);
~PathRequest ();
@@ -97,8 +97,8 @@ private:
RippleAddress raDstAccount;
STAmount saDstAmount;
std::set<Issue> sciSourceCurrencies;
std::map<Issue, STPathSet> mContext;
std::set<CurrencyIssuer> sciSourceCurrencies;
std::map<CurrencyIssuer, STPathSet> mContext;
bool bValid;

View File

@@ -17,8 +17,6 @@
*/
//==============================================================================
#include <ripple/app/paths/Credit.h>
namespace ripple {
// OPTIMIZE: When calculating path increment, note if increment consumes all
@@ -316,13 +314,13 @@ TER PathState::pushNode (
if (resultCode == tesSUCCESS)
{
STAmount saOwed = creditBalance (lesEntries,
STAmount saOwed = credit_balance (lesEntries,
node.account_, backNode.account_,
node.issue_.currency);
STAmount saLimit;
if (saOwed <= zero) {
saLimit = creditLimit (lesEntries,
saLimit = credit_limit (lesEntries,
node.account_,
backNode.account_,
node.issue_.currency);

File diff suppressed because it is too large Load Diff

View File

@@ -31,160 +31,114 @@ namespace ripple {
class Pathfinder
{
public:
/** Construct a pathfinder with an issuer.*/
Pathfinder (
RippleLineCache::ref cache,
Account const& srcAccount,
Account const& dstAccount,
Currency const& uSrcCurrency,
Account const& uSrcIssuer,
STAmount const& dstAmount);
RippleAddress const& srcAccountID,
RippleAddress const& dstAccountID,
Currency const& srcCurrencyID,
Account const& srcIssuerID,
STAmount const& dstAmount,
bool& bValid);
/** Construct a pathfinder without an issuer.*/
Pathfinder (
RippleLineCache::ref cache,
Account const& srcAccount,
Account const& dstAccount,
Currency const& uSrcCurrency,
STAmount const& dstAmount);
static void initPathTable();
~Pathfinder();
bool findPaths (
int iLevel,
unsigned int const iMaxPaths,
STPathSet& spsDst,
STPath& spExtraPath);
static void initPathTable ();
bool findPaths (int searchLevel);
/** Make sure that all the input paths are included in mCompletePaths. */
void addPathsFromPreviousPathfinding (STPathSet&);
/** Compute the rankings of the paths. */
void computePathRanks (int maxPaths);
/* Get the best paths, up to maxPaths in number, from mCompletePaths.
On return, if fullLiquidityPath is not empty, then it contains the best
additional single path which can consume all the liquidity.
*/
STPathSet getBestPaths (
int maxPaths,
STPath& fullLiquidityPath,
Account const& srcIssuer);
enum NodeType
{
nt_SOURCE, // The source account: with an issuer account, if needed.
nt_ACCOUNTS, // Accounts that connect from this source/currency.
nt_BOOKS, // Order books that connect to this currency.
nt_XRP_BOOK, // The order book from this currency to XRP.
nt_DEST_BOOK, // The order book to the destination currency/issuer.
nt_DESTINATION // The destination account only.
};
// The PathType is a list of the NodeTypes for a path.
using PathType = std::vector <NodeType>;
// PaymentType represents the types of the source and destination currencies
// in a path request.
private:
enum PaymentType
{
pt_XRP_to_XRP,
pt_XRP_to_nonXRP,
pt_nonXRP_to_XRP,
pt_nonXRP_to_same, // Destination currency is the same as source.
pt_nonXRP_to_nonXRP // Destination currency is NOT the same as source.
pt_nonXRP_to_same,
pt_nonXRP_to_nonXRP
};
struct PathRank
enum NodeType
{
std::uint64_t quality;
std::uint64_t length;
STAmount liquidity;
int index;
nt_SOURCE, // The source account with an issuer account, if required
nt_ACCOUNTS, // Accounts that connect from this source/currency
nt_BOOKS, // Order books that connect to this currency
nt_XRP_BOOK, // The order book from this currency to XRP
nt_DEST_BOOK, // The order book to the destination currency/issuer
nt_DESTINATION // The destination account only
};
private:
/*
Call graph of Pathfinder methods.
typedef std::vector<NodeType> PathType_t;
typedef std::pair<int, PathType_t> CostedPath_t;
typedef std::vector<CostedPath_t> CostedPathList_t;
findPaths:
addPathsForType:
addLinks:
addLink:
getPathsOut
issueMatchesOrigin
isNoRippleOut:
isNoRipple
typedef std::pair<int, const char*> PathCost;
typedef std::vector<PathCost> PathCostList;
addPathsFromPreviousPathfinding
computePathRanks:
rippleCalculate
getPathLiquidity:
rippleCalculate
getBestPaths
*/
typedef std::map<PaymentType, CostedPathList_t> PathTable;
// Add all paths of one type to mCompletePaths.
STPathSet& addPathsForType (PathType const& type);
/** Fill a CostedPathList_t from its description. */
static void fillPaths(PaymentType type,
PathCostList const& costs);
bool issueMatchesOrigin (Issue const&);
/** @return true if any building paths are now complete. */
bool checkComplete (STPathSet& retPathSet);
static std::string pathTypeToString(PathType_t const&);
bool matchesOrigin (Issue const&);
int getPathsOut (
Currency const& currency,
Account const& account,
Account const& accountID,
bool isDestCurrency,
Account const& dest);
void addLink (
void addLink(
STPath const& currentPath,
STPathSet& incompletePaths,
int addFlags);
// Call addLink() for each path in currentPaths.
void addLinks (
void addLink(
STPathSet const& currentPaths,
STPathSet& incompletePaths,
int addFlags);
// Compute the liquidity for a path. Return tesSUCCESS if it has has enough
// liquidity to be worth keeping, otherwise an error.
TER getPathLiquidity (
STPath const& path, // IN: The path to check.
STAmount const& minDstAmount, // IN: The minimum output this path must
// deliver to be worth keeping.
STAmount& amountOut, // OUT: The actual liquidity on the path.
uint64_t& qualityOut) const; // OUT: The returned initial quality
STPathSet& getPaths(PathType_t const& type,
bool addComplete = true);
STPathSet filterPaths(int iMaxPaths,
STPath& extraPath);
TER checkPath (STPath const& path, STAmount const& minDestAmount,
STAmount& amount, uint64_t& quality) const;
// Does this path end on an account-to-account link whose last account has
// set the "no ripple" flag on the link?
bool isNoRippleOut (STPath const& currentPath);
// Is the "no ripple" flag set from one account to another?
bool isNoRipple (
Account const& fromAccount,
Account const& toAccount,
Currency const& currency);
Account const& setByID,
Account const& setOnID,
Currency const& currencyID);
Account mSrcAccount;
Account mDstAccount;
STAmount mDstAmount;
Currency mSrcCurrency;
boost::optional<Account> mSrcIssuer;
STAmount mSrcAmount;
/** The amount remaining from mSrcAccount after the default liquidity has
been removed. */
STAmount mRemainingAmount;
// Our main table of paths
Ledger::pointer mLedger;
LoadEvent::pointer m_loadEvent;
RippleLineCache::pointer mRLCache;
static PathTable mPathTable;
static PathType_t makePath(char const*);
Account mSrcAccountID;
Account mDstAccountID;
STAmount mDstAmount;
Currency mSrcCurrencyID;
Account mSrcIssuerID;
STAmount mSrcAmount;
Ledger::pointer mLedger;
LoadEvent::pointer m_loadEvent;
RippleLineCache::pointer mRLCache;
STPathElement mSource;
STPathSet mCompletePaths;
std::vector<PathRank> mPathRanks;
std::map<PathType, STPathSet> mPaths;
std::map<PathType_t, STPathSet> mPaths;
hash_map<Issue, int> mPathsOutCountMap;
@@ -192,18 +146,51 @@ private:
static std::uint32_t const afADD_ACCOUNTS = 0x001;
// Add order books
static std::uint32_t const afADD_BOOKS = 0x002;
static std::uint32_t const afADD_BOOKS = 0x002;
// Add order book to XRP only
static std::uint32_t const afOB_XRP = 0x010;
static std::uint32_t const afOB_XRP = 0x010;
// Must link to destination currency
static std::uint32_t const afOB_LAST = 0x040;
static std::uint32_t const afOB_LAST = 0x040;
// Destination account only
static std::uint32_t const afAC_LAST = 0x080;
static std::uint32_t const afAC_LAST = 0x080;
};
CurrencySet usAccountDestCurrencies
(RippleAddress const& raAccountID,
RippleLineCache::ref cache,
bool includeXRP);
CurrencySet usAccountSourceCurrencies
(RippleAddress const& raAccountID,
RippleLineCache::ref lrLedger,
bool includeXRP);
/** Calculate the maximum amount of IOUs that an account can hold
@param ledger the ledger to check against.
@param account the account of interest.
@param issuer the issuer of the IOU.
@param currency the IOU to check.
@return The maximum amount that can be held.
*/
STAmount
credit_limit (
LedgerEntrySet& ledger, Account const& account,
Account const& issuer, Currency const& currency);
/** Returns the amount of IOUs issued by issuer that are held by an account
@param ledger the ledger to check against.
@param account the account of interest.
@param issuer the issuer of the IOU.
@param currency the IOU to check.
*/
STAmount
credit_balance (
LedgerEntrySet& ledger, Account const& account,
Account const& issuer, Currency const& currency);
} // ripple
#endif

View File

@@ -18,7 +18,6 @@
//==============================================================================
#include <ripple/app/book/Quality.h>
#include <ripple/app/paths/Credit.h>
#include <ripple/app/paths/cursor/RippleLiquidity.h>
namespace ripple {
@@ -47,8 +46,8 @@ TER PathCursor::reverseLiquidityForAccount () const
auto const isFinalNode = (nodeIndex_ == lastNodeIndex);
// 0 quality means none has yet been determined.
std::uint64_t uRateMax = 0
;
std::uint64_t uRateMax = 0;
// Current is allowed to redeem to next.
const bool previousNodeIsAccount = !nodeIndex_ ||
previousNode().isAccount();
@@ -81,7 +80,7 @@ TER PathCursor::reverseLiquidityForAccount () const
// For previousNodeIsAccount:
// Previous account is already owed.
const STAmount saPrvOwed = (previousNodeIsAccount && nodeIndex_ != 0)
? creditBalance (ledger(),
? credit_balance (ledger(),
node().account_,
previousAccountID,
node().issue_.currency)
@@ -89,7 +88,7 @@ TER PathCursor::reverseLiquidityForAccount () const
// The limit amount that the previous account may owe.
const STAmount saPrvLimit = (previousNodeIsAccount && nodeIndex_ != 0)
? creditLimit (ledger(),
? credit_limit (ledger(),
node().account_,
previousAccountID,
node().issue_.currency)
@@ -97,7 +96,7 @@ TER PathCursor::reverseLiquidityForAccount () const
// Next account is owed.
const STAmount saNxtOwed = (nextNodeIsAccount && nodeIndex_ != lastNodeIndex)
? creditBalance (ledger(),
? credit_balance (ledger(),
node().account_,
nextAccountID,
node().issue_.currency)

View File

@@ -33,7 +33,7 @@ char const* getRawVersionString ()
//
// The build version number (edit this for each release)
//
"0.26.4-sp1"
"0.26.4-sp2"
//
// Must follow the format described here:
//

View File

@@ -17,8 +17,6 @@
*/
//==============================================================================
#include <ripple/app/paths/AccountCurrencies.h>
#include <ripple/app/paths/FindPaths.h>
#include <ripple/rpc/impl/LegacyPathFind.h>
namespace ripple {
@@ -121,10 +119,11 @@ Json::Value doRipplePathFind (RPC::Context& context)
}
else
{
auto currencies = accountSourceCurrencies (raSrc, cache, true);
auto usCurrencies = usAccountSourceCurrencies (raSrc, cache, true);
jvSrcCurrencies = Json::Value (Json::arrayValue);
for (auto const& uCurrency: currencies)
for (auto const& uCurrency: usCurrencies)
{
Json::Value jvCurrency (Json::objectValue);
jvCurrency["currency"] = to_string(uCurrency);
@@ -135,9 +134,7 @@ Json::Value doRipplePathFind (RPC::Context& context)
// Fill in currencies destination will accept
Json::Value jvDestCur (Json::arrayValue);
// TODO(tom): this could be optimized the same way that
// PathRequest::doUpdate() is - if we don't obsolete this code first.
auto usDestCurrID = accountDestCurrencies (raDst, cache, true);
auto usDestCurrID = usAccountDestCurrencies (raDst, cache, true);
for (auto const& uCurrency: usDestCurrID)
jvDestCur.append (to_string (uCurrency));
@@ -146,29 +143,6 @@ Json::Value doRipplePathFind (RPC::Context& context)
Json::Value jvArray (Json::arrayValue);
int level = getConfig().PATH_SEARCH_OLD;
if ((getConfig().PATH_SEARCH_MAX > level)
&& !getApp().getFeeTrack().isLoadedLocal())
{
++level;
}
if (context.params_.isMember("depth")
&& context.params_["depth"].isIntegral())
{
int rLev = context.params_["search_depth"].asInt ();
if ((rLev < level) || (context.role_ == Config::ADMIN))
level = rLev;
}
FindPaths fp (
cache,
raSrc.getAccountID(),
raDst.getAccountID(),
saDstAmount,
level,
4); // max paths
for (unsigned int i = 0; i != jvSrcCurrencies.size (); ++i)
{
Json::Value jvSource = jvSrcCurrencies[i];
@@ -203,6 +177,11 @@ Json::Value doRipplePathFind (RPC::Context& context)
return rpcError (rpcSRC_ISR_MALFORMED);
}
STPathSet spsComputed;
bool bValid;
Pathfinder pf (cache, raSrc, raDst, uSrcCurrencyID,
uSrcIssuerID, saDstAmount, bValid);
int level = getConfig().PATH_SEARCH_OLD;
if ((getConfig().PATH_SEARCH_MAX > level)
&& !getApp().getFeeTrack().isLoadedLocal())
@@ -217,7 +196,6 @@ Json::Value doRipplePathFind (RPC::Context& context)
level = rLev;
}
STPathSet spsComputed;
if (context.params_.isMember("paths"))
{
STParsedJSONObject paths ("paths", context.params_["paths"]);
@@ -227,12 +205,8 @@ Json::Value doRipplePathFind (RPC::Context& context)
spsComputed = paths.object.get()->downcast<STPathSet> ();
}
STPath fullLiquidityPath;
auto valid = fp.findPathsForIssue (
{uSrcCurrencyID, uSrcIssuerID},
spsComputed,
fullLiquidityPath);
if (!valid)
STPath extraPath;
if (!bValid || !pf.findPaths (level, 4, spsComputed, extraPath))
{
WriteLog (lsWARNING, RPCHandler)
<< "ripple_path_find: No paths found.";
@@ -267,13 +241,13 @@ Json::Value doRipplePathFind (RPC::Context& context)
<< " saMaxAmountAct=" << rc.actualAmountIn
<< " saDstAmountAct=" << rc.actualAmountOut;
if (fullLiquidityPath.size() > 0 &&
if (extraPath.size() > 0 &&
(rc.result() == terNO_LINE || rc.result() == tecPATH_PARTIAL))
{
WriteLog (lsDEBUG, PathRequest)
<< "Trying with an extra path element";
spsComputed.push_back (fullLiquidityPath);
spsComputed.push_back (extraPath);
lesSandbox.clear ();
rc = path::RippleCalc::rippleCalculate (
lesSandbox,

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#include <ripple/app/paths/FindPaths.h>
#include <ripple/basics/StringUtilities.h>
#include <ripple/rpc/impl/TransactionSign.h>
#include <beast/unit_test.h>
@@ -126,6 +125,7 @@ static Json::Value signPayment(
&& params.isMember ("build_path"))
{
// Need a ripple path.
STPathSet spsPaths;
Currency uSrcCurrencyID;
Account uSrcIssuerID;
@@ -152,21 +152,22 @@ static Json::Value signPayment(
if (!lpf.isOk ())
return rpcError (rpcTOO_BUSY);
bool bValid;
auto cache = std::make_shared<RippleLineCache> (lSnapshot);
STPathSet spsPaths;
STPath fullLiquidityPath;
auto valid = findPathsForOneIssuer (
Pathfinder pf (
cache,
raSrcAddressID.getAccountID(),
dstAccountID.getAccountID(),
saSendMax.issue (),
amount,
getConfig ().PATH_SEARCH_OLD,
4, // iMaxPaths
spsPaths,
fullLiquidityPath);
raSrcAddressID,
dstAccountID,
saSendMax.getCurrency (),
saSendMax.getIssuer (),
amount, bValid);
if (!valid)
STPath extraPath;
if (!bValid ||
!pf.findPaths (getConfig ().PATH_SEARCH_OLD,
4,
spsPaths,
extraPath))
{
WriteLog (lsDEBUG, RPCHandler)
<< "transactionSign: build_path: No paths found.";

View File

@@ -117,5 +117,7 @@
#include <ripple/app/main/ParameterTable.h>
#include <ripple/app/paths/PathState.h>
#include <ripple/app/paths/RippleCalc.h>
#include <ripple/app/paths/Pathfinder.h>
#endif

View File

@@ -29,8 +29,5 @@
#include <ripple/app/ledger/OrderBookIterator.cpp>
#include <ripple/app/consensus/DisputedTx.cpp>
#include <ripple/app/misc/HashRouter.cpp>
#include <ripple/app/paths/AccountCurrencies.cpp>
#include <ripple/app/paths/Credit.cpp>
#include <ripple/app/paths/FindPaths.cpp>
#include <ripple/app/paths/Pathfinder.cpp>
#include <ripple/app/misc/AmendmentTableImpl.cpp>