mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Improve path filtering:
1) Ignore paths with very low liquidity 2) Allow an extra filling path to be added if needed
This commit is contained in:
@@ -331,7 +331,8 @@ bool PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
|
|||||||
currIssuer.first, currIssuer.second, saDstAmount, valid);
|
currIssuer.first, currIssuer.second, saDstAmount, valid);
|
||||||
CondLog (!valid, lsINFO, PathRequest) << "PF request not valid";
|
CondLog (!valid, lsINFO, PathRequest) << "PF request not valid";
|
||||||
|
|
||||||
if (valid && pf.findPaths (iLevel, 4, spsPaths))
|
STPath extraPath;
|
||||||
|
if (valid && pf.findPaths (iLevel, 4, spsPaths, extraPath))
|
||||||
{
|
{
|
||||||
LedgerEntrySet lesSandbox (cache->getLedger (), tapNONE);
|
LedgerEntrySet lesSandbox (cache->getLedger (), tapNONE);
|
||||||
std::vector<PathState::pointer> vpsExpanded;
|
std::vector<PathState::pointer> vpsExpanded;
|
||||||
@@ -343,9 +344,23 @@ bool PathRequest::doUpdate (RippleLineCache::ref cache, bool fast)
|
|||||||
saMaxAmount.negate ();
|
saMaxAmount.negate ();
|
||||||
WriteLog (lsDEBUG, PathRequest) << "Paths found, calling rippleCalc";
|
WriteLog (lsDEBUG, PathRequest) << "Paths found, calling rippleCalc";
|
||||||
TER terResult = RippleCalc::rippleCalc (lesSandbox, saMaxAmountAct, saDstAmountAct,
|
TER terResult = RippleCalc::rippleCalc (lesSandbox, saMaxAmountAct, saDstAmountAct,
|
||||||
vpsExpanded, saMaxAmount, saDstAmount, raDstAccount.getAccountID (), raSrcAccount.getAccountID (),
|
vpsExpanded, saMaxAmount, saDstAmount,
|
||||||
|
raDstAccount.getAccountID (), raSrcAccount.getAccountID (),
|
||||||
spsPaths, false, false, false, true);
|
spsPaths, false, false, false, true);
|
||||||
|
|
||||||
|
|
||||||
|
if ((extraPath.size() > 0) && ((terResult == terNO_LINE) || (terResult == tecPATH_PARTIAL)))
|
||||||
|
{
|
||||||
|
WriteLog (lsDEBUG, PathRequest) << "Trying with an extra path element";
|
||||||
|
spsPaths.addPath(extraPath);
|
||||||
|
vpsExpanded.clear ();
|
||||||
|
terResult = RippleCalc::rippleCalc (lesSandbox, saMaxAmountAct, saDstAmountAct,
|
||||||
|
vpsExpanded, saMaxAmount, saDstAmount,
|
||||||
|
raDstAccount.getAccountID (), raSrcAccount.getAccountID (),
|
||||||
|
spsPaths, false, false, false, true);
|
||||||
|
WriteLog (lsDEBUG, PathRequest) << "Extra path element gives " << transHuman (terResult);
|
||||||
|
}
|
||||||
|
|
||||||
if (terResult == tesSUCCESS)
|
if (terResult == tesSUCCESS)
|
||||||
{
|
{
|
||||||
Json::Value jvEntry (Json::objectValue);
|
Json::Value jvEntry (Json::objectValue);
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ Pathfinder::Pathfinder (RippleLineCache::ref cache,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pathfinder::findPaths (int iLevel, const unsigned int iMaxPaths, STPathSet& pathsOut)
|
bool Pathfinder::findPaths (int iLevel, const unsigned int iMaxPaths, STPathSet& pathsOut, STPath& extraPath)
|
||||||
{ // pathsOut contains only non-default paths without source or destiation
|
{ // pathsOut contains only non-default paths without source or destiation
|
||||||
// On input, pathsOut contains any paths you want to ensure are included if still good
|
// On input, pathsOut contains any paths you want to ensure are included if still good
|
||||||
|
|
||||||
@@ -221,14 +221,14 @@ bool Pathfinder::findPaths (int iLevel, const unsigned int iMaxPaths, STPathSet&
|
|||||||
WriteLog (lsDEBUG, Pathfinder) << mCompletePaths.size() << " paths to filter";
|
WriteLog (lsDEBUG, Pathfinder) << mCompletePaths.size() << " paths to filter";
|
||||||
|
|
||||||
if (mCompletePaths.size() > iMaxPaths)
|
if (mCompletePaths.size() > iMaxPaths)
|
||||||
pathsOut = filterPaths(iMaxPaths);
|
pathsOut = filterPaths(iMaxPaths, extraPath);
|
||||||
else
|
else
|
||||||
pathsOut = mCompletePaths;
|
pathsOut = mCompletePaths;
|
||||||
|
|
||||||
return true; // Even if we find no paths, default paths may work, and we don't check them currently
|
return true; // Even if we find no paths, default paths may work, and we don't check them currently
|
||||||
}
|
}
|
||||||
|
|
||||||
STPathSet Pathfinder::filterPaths(int iMaxPaths)
|
STPathSet Pathfinder::filterPaths(int iMaxPaths, STPath& extraPath)
|
||||||
{
|
{
|
||||||
if (mCompletePaths.size() <= iMaxPaths)
|
if (mCompletePaths.size() <= iMaxPaths)
|
||||||
return mCompletePaths;
|
return mCompletePaths;
|
||||||
@@ -274,6 +274,9 @@ STPathSet Pathfinder::filterPaths(int iMaxPaths)
|
|||||||
|
|
||||||
std::vector<path_LQ_t> vMap;
|
std::vector<path_LQ_t> vMap;
|
||||||
|
|
||||||
|
// Ignore paths that move only very small amounts
|
||||||
|
STAmount saMinDstAmount = STAmount::divide(mDstAmount, STAmount(iMaxPaths + 2), mDstAmount);
|
||||||
|
|
||||||
// Build map of quality to entry.
|
// Build map of quality to entry.
|
||||||
for (int i = mCompletePaths.size (); i--;)
|
for (int i = mCompletePaths.size (); i--;)
|
||||||
{
|
{
|
||||||
@@ -293,8 +296,8 @@ STPathSet Pathfinder::filterPaths(int iMaxPaths)
|
|||||||
|
|
||||||
terResult = RippleCalc::rippleCalc (
|
terResult = RippleCalc::rippleCalc (
|
||||||
lesSandbox,
|
lesSandbox,
|
||||||
saMaxAmountAct,
|
saMaxAmountAct, // --> computed input
|
||||||
saDstAmountAct,
|
saDstAmountAct, // --> computed output
|
||||||
vpsExpanded,
|
vpsExpanded,
|
||||||
mSrcAmount, // --> amount to send max.
|
mSrcAmount, // --> amount to send max.
|
||||||
mDstAmount, // --> amount to deliver.
|
mDstAmount, // --> amount to deliver.
|
||||||
@@ -313,7 +316,21 @@ STPathSet Pathfinder::filterPaths(int iMaxPaths)
|
|||||||
terResult = tefEXCEPTION;
|
terResult = tefEXCEPTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tesSUCCESS == terResult)
|
if (tesSUCCESS != terResult)
|
||||||
|
{
|
||||||
|
WriteLog (lsDEBUG, Pathfinder)
|
||||||
|
<< boost::str (boost::format ("findPaths: dropping: %s: %s")
|
||||||
|
% transToken (terResult)
|
||||||
|
% spCurrent.getJson (0));
|
||||||
|
}
|
||||||
|
else if (saDstAmountAct < saMinDstAmount)
|
||||||
|
{
|
||||||
|
WriteLog (lsDEBUG, Pathfinder)
|
||||||
|
<< boost::str (boost::format ("findPaths: dropping: outputs %s: %s")
|
||||||
|
% saDstAmountAct
|
||||||
|
% spCurrent.getJson (0));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
uint64 uQuality = STAmount::getRate (saDstAmountAct, saMaxAmountAct);
|
uint64 uQuality = STAmount::getRate (saDstAmountAct, saMaxAmountAct);
|
||||||
|
|
||||||
@@ -324,13 +341,6 @@ STPathSet Pathfinder::filterPaths(int iMaxPaths)
|
|||||||
|
|
||||||
vMap.push_back (path_LQ_t (uQuality, spCurrent.mPath.size (), saDstAmountAct, i));
|
vMap.push_back (path_LQ_t (uQuality, spCurrent.mPath.size (), saDstAmountAct, i));
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
WriteLog (lsDEBUG, Pathfinder)
|
|
||||||
<< boost::str (boost::format ("findPaths: dropping: %s: %s")
|
|
||||||
% transToken (terResult)
|
|
||||||
% spCurrent.getJson (0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STPathSet spsDst;
|
STPathSet spsDst;
|
||||||
@@ -351,6 +361,12 @@ STPathSet Pathfinder::filterPaths(int iMaxPaths)
|
|||||||
remaining -= lqt.get<2> ();
|
remaining -= lqt.get<2> ();
|
||||||
spsDst.addPath (mCompletePaths[lqt.get<3> ()]);
|
spsDst.addPath (mCompletePaths[lqt.get<3> ()]);
|
||||||
}
|
}
|
||||||
|
else if ((iPathsLeft == 0) && (lqt.get<2>() >= mDstAmount) && (extraPath.size() == 0))
|
||||||
|
{
|
||||||
|
// found an extra path that can move the whole amount
|
||||||
|
extraPath = mCompletePaths[lqt.get<3>()];
|
||||||
|
WriteLog (lsDEBUG, Pathfinder) << "Found extra full path: " << extraPath.getJson(0);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
WriteLog (lsDEBUG, Pathfinder) << "Skipping a non-filling path: " << mCompletePaths[lqt.get<3> ()].getJson (0);
|
WriteLog (lsDEBUG, Pathfinder) << "Skipping a non-filling path: " << mCompletePaths[lqt.get<3> ()].getJson (0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public:
|
|||||||
const uint160& srcCurrencyID, const uint160& srcIssuerID, const STAmount& dstAmount, bool& bValid);
|
const uint160& srcCurrencyID, const uint160& srcIssuerID, const STAmount& dstAmount, bool& bValid);
|
||||||
|
|
||||||
static void initPathTable();
|
static void initPathTable();
|
||||||
bool findPaths (int iLevel, const unsigned int iMaxPaths, STPathSet& spsDst);
|
bool findPaths (int iLevel, const unsigned int iMaxPaths, STPathSet& spsDst, STPath& spExtraPath);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ private:
|
|||||||
void addLink(const STPath& currentPath, STPathSet& incompletePaths, int addFlags);
|
void addLink(const STPath& currentPath, STPathSet& incompletePaths, int addFlags);
|
||||||
void addLink(const STPathSet& currentPaths, STPathSet& incompletePaths, int addFlags);
|
void addLink(const STPathSet& currentPaths, STPathSet& incompletePaths, int addFlags);
|
||||||
STPathSet& getPaths(const PathType_t& type, bool addComplete = true);
|
STPathSet& getPaths(const PathType_t& type, bool addComplete = true);
|
||||||
STPathSet filterPaths(int iMaxPaths);
|
STPathSet filterPaths(int iMaxPaths, STPath& extraPath);
|
||||||
|
|
||||||
// Our main table of paths
|
// Our main table of paths
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,8 @@ Json::Value RPCHandler::transactionSign (Json::Value params, bool bSubmit, bool
|
|||||||
Pathfinder pf (cache, raSrcAddressID, dstAccountID,
|
Pathfinder pf (cache, raSrcAddressID, dstAccountID,
|
||||||
saSendMax.getCurrency (), saSendMax.getIssuer (), saSend, bValid);
|
saSendMax.getCurrency (), saSendMax.getIssuer (), saSend, bValid);
|
||||||
|
|
||||||
if (!bValid || !pf.findPaths (getConfig ().PATH_SEARCH_OLD, 4, spsPaths))
|
STPath extraPath;
|
||||||
|
if (!bValid || !pf.findPaths (getConfig ().PATH_SEARCH_OLD, 4, spsPaths, extraPath))
|
||||||
{
|
{
|
||||||
WriteLog (lsDEBUG, RPCHandler) << "transactionSign: build_path: No paths found.";
|
WriteLog (lsDEBUG, RPCHandler) << "transactionSign: build_path: No paths found.";
|
||||||
|
|
||||||
@@ -1560,7 +1561,8 @@ Json::Value RPCHandler::doRipplePathFind (Json::Value params, LoadType* loadType
|
|||||||
int level = getConfig().PATH_SEARCH_OLD;
|
int level = getConfig().PATH_SEARCH_OLD;
|
||||||
if ((getConfig().PATH_SEARCH_MAX > level) && !getApp().getFeeTrack().isLoadedLocal())
|
if ((getConfig().PATH_SEARCH_MAX > level) && !getApp().getFeeTrack().isLoadedLocal())
|
||||||
++level;
|
++level;
|
||||||
if (!bValid || !pf.findPaths (level, 4, spsComputed))
|
STPath extraPath;
|
||||||
|
if (!bValid || !pf.findPaths (level, 4, spsComputed, extraPath))
|
||||||
{
|
{
|
||||||
WriteLog (lsWARNING, RPCHandler) << "ripple_path_find: No paths found.";
|
WriteLog (lsWARNING, RPCHandler) << "ripple_path_find: No paths found.";
|
||||||
}
|
}
|
||||||
@@ -1608,6 +1610,18 @@ Json::Value RPCHandler::doRipplePathFind (Json::Value params, LoadType* loadType
|
|||||||
% saMaxAmountAct
|
% saMaxAmountAct
|
||||||
% saDstAmountAct);
|
% saDstAmountAct);
|
||||||
|
|
||||||
|
if ((extraPath.size() > 0) && ((terResult == terNO_LINE) || (terResult == tecPATH_PARTIAL)))
|
||||||
|
{
|
||||||
|
WriteLog (lsDEBUG, PathRequest) << "Trying with an extra path element";
|
||||||
|
spsComputed.addPath(extraPath);
|
||||||
|
vpsExpanded.clear ();
|
||||||
|
terResult = RippleCalc::rippleCalc (lesSandbox, saMaxAmountAct, saDstAmountAct,
|
||||||
|
vpsExpanded, saMaxAmount, saDstAmount,
|
||||||
|
raDst.getAccountID (), raSrc.getAccountID (),
|
||||||
|
spsComputed, false, false, false, true);
|
||||||
|
WriteLog (lsDEBUG, PathRequest) << "Extra path element gives " << transHuman (terResult);
|
||||||
|
}
|
||||||
|
|
||||||
if (tesSUCCESS == terResult)
|
if (tesSUCCESS == terResult)
|
||||||
{
|
{
|
||||||
Json::Value jvEntry (Json::objectValue);
|
Json::Value jvEntry (Json::objectValue);
|
||||||
|
|||||||
Reference in New Issue
Block a user