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:
JoelKatz
2013-11-02 17:40:44 -07:00
parent 3296ac5628
commit 6b2f654a30
4 changed files with 64 additions and 19 deletions

View File

@@ -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);

View File

@@ -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);
} }

View File

@@ -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

View File

@@ -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);