From ae7fc56e6b996b5d5b60073a6db6260126812923 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 7 Apr 2013 23:21:26 -0700 Subject: [PATCH] Statistical path exploration. Phase one. --- src/cpp/ripple/Pathfinder.cpp | 80 ++++++++++++++++++++++++++++------- src/cpp/ripple/Pathfinder.h | 3 ++ 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/cpp/ripple/Pathfinder.cpp b/src/cpp/ripple/Pathfinder.cpp index 2ac942aebd..3943271e09 100644 --- a/src/cpp/ripple/Pathfinder.cpp +++ b/src/cpp/ripple/Pathfinder.cpp @@ -117,6 +117,16 @@ bool Pathfinder::bDefaultPath(const STPath& spPath) return false; } +typedef std::pair candidate_t; +bool candCmp(uint32 seq, const candidate_t& first, const candidate_t& second) +{ + if (first.first < second.first) + return true; + if (first.first > second.first) + return false; + return (first.first ^ seq) < (second.first ^ seq); +} + Pathfinder::Pathfinder(Ledger::ref ledger, const RippleAddress& uSrcAccountID, const RippleAddress& uDstAccountID, const uint160& uSrcCurrencyID, const uint160& uSrcIssuerID, const STAmount& saDstAmount) @@ -408,10 +418,10 @@ bool Pathfinder::findPaths(const unsigned int iMaxSteps, const unsigned int iMax // On a non-XRP account: // True, the cursor requires the next node to be authorized. bool bRequireAuth = isSetBit(sleEnd->getFieldU32(sfFlags), lsfRequireAuth); + bool dstCurrency = speEnd.mCurrencyID == mDstAmount.getCurrency(); AccountItems& rippleLines(getRippleLines(speEnd.mAccountID)); - typedef std::pair candidate_t; std::vector< std::pair > candidates; candidates.reserve(rippleLines.getItems().size()); @@ -452,30 +462,47 @@ bool Pathfinder::findPaths(const unsigned int iMaxSteps, const unsigned int iMax % rspEntry->getLimitPeer().getFullText() ); } + else if (dstCurrency && (uPeerID == mDstAccountID)) + { // never skip the destination node + candidates.push_back(std::make_pair(-1, uPeerID)); + } else { // save this candidate - candidates.push_back(std::make_pair(1, uPeerID)); + int paths_out = getPathsOut(speEnd.mCurrencyID, uPeerID); + if (paths_out != 0) + candidates.push_back(std::make_pair(paths_out, uPeerID)); } } - BOOST_FOREACH(const candidate_t& candidate, candidates) + if (!candidates.empty()) { - STPath spNew(spPath); - STPathElement speNew(candidate.second, speEnd.mCurrencyID, candidate.second); + bFound = true; - spNew.mPath.push_back(speNew); - qspExplore.push(spNew); + std::sort(candidates.begin(), candidates.end(), + BIND_TYPE(candCmp, mLedger->getLedgerSeq(), P_1, P_2)); + int count = candidates.size(); + if (count > 10) + count /= 3; + std::vector< std::pair >::iterator it = candidates.begin(); + while (--count != 0) + { + STPath spNew(spPath); + STPathElement speNew(it->second, speEnd.mCurrencyID, it->second); - bContinued = true; + spNew.mPath.push_back(speNew); + qspExplore.push(spNew); - cLog(lsTRACE) << - boost::str(boost::format("findPaths: push explore: %s/%s -> %s/%s") - % STAmount::createHumanCurrency(speEnd.mCurrencyID) - % RippleAddress::createHumanAccountID(speEnd.mAccountID) - % STAmount::createHumanCurrency(speEnd.mCurrencyID) - % RippleAddress::createHumanAccountID(candidate.second)); + bContinued = true; + + cLog(lsTRACE) << + boost::str(boost::format("findPaths: push explore: %s/%s -> %s/%s") + % STAmount::createHumanCurrency(speEnd.mCurrencyID) + % RippleAddress::createHumanAccountID(speEnd.mAccountID) + % STAmount::createHumanCurrency(speEnd.mCurrencyID) + % RippleAddress::createHumanAccountID(it->second)); + ++it; + } } - } @@ -800,4 +827,27 @@ bool Pathfinder::matchesOrigin(const uint160& currency, const uint160& issuer) return (currency == mSrcCurrencyID) && (issuer == mSrcIssuerID); } +int Pathfinder::getPathsOut(const uint160& currencyID, const uint160& accountID) +{ + std::pair accountCurrency(currencyID, accountID); + boost::unordered_map, int>::iterator it = mPOMap.find(accountCurrency); + if (it != mPOMap.end()) + return it->second; + + int count = 0; + AccountItems& rippleLines(getRippleLines(accountID)); + BOOST_FOREACH(AccountItem::ref item, rippleLines.getItems()) + { + RippleState* rspEntry = (RippleState*) item.get(); + if (currencyID != rspEntry->getLimit().getCurrency()) + nothing(); + else if (!rspEntry->getBalance().isPositive() && !rspEntry->getLimitPeer().isPositive()) // no credit + nothing(); + else + ++count; + } + mPOMap[accountCurrency] = count; + return count; +} + // vim:ts=4 diff --git a/src/cpp/ripple/Pathfinder.h b/src/cpp/ripple/Pathfinder.h index de61977b7b..5e1e9a0e13 100644 --- a/src/cpp/ripple/Pathfinder.h +++ b/src/cpp/ripple/Pathfinder.h @@ -49,6 +49,7 @@ class Pathfinder LoadEvent::pointer mLoadMonitor; boost::unordered_map mRLMap; + boost::unordered_map, int> mPOMap; // std::list mBuildingPaths; // std::list mCompletePaths; @@ -64,6 +65,8 @@ class Pathfinder AccountItems& getRippleLines(const uint160& accountID); + int getPathsOut(const uint160& currency, const uint160& accountID); + public: Pathfinder(Ledger::ref ledger, const RippleAddress& srcAccountID, const RippleAddress& dstAccountID,