From d193608aa1929ea7e386b0648c2277022e60e69e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 2 May 2013 01:04:16 -0700 Subject: [PATCH] More PFRequest work. Advanced features. --- src/cpp/ripple/PFRequest.cpp | 87 +++++++++++++++++++++++++++++++++-- src/cpp/ripple/PFRequest.h | 5 +- src/cpp/ripple/Pathfinder.cpp | 4 +- src/cpp/ripple/Pathfinder.h | 6 ++- src/cpp/ripple/RPCHandler.cpp | 10 ++-- 5 files changed, 100 insertions(+), 12 deletions(-) diff --git a/src/cpp/ripple/PFRequest.cpp b/src/cpp/ripple/PFRequest.cpp index a613cf1c3..74ec431c8 100644 --- a/src/cpp/ripple/PFRequest.cpp +++ b/src/cpp/ripple/PFRequest.cpp @@ -4,6 +4,9 @@ #include "RPCErr.h" #include "Ledger.h" #include "Application.h" +#include "Pathfinder.h" +#include "RippleCalc.h" +#include "LedgerFormats.h" boost::recursive_mutex PFRequest::sLock; std::set PFRequest::sRequests; @@ -35,8 +38,10 @@ bool PFRequest::isValid(Ledger::ref lrLedger) else { AccountState::pointer asDst = theApp->getOPs().getAccountState(lrLedger, raDstAccount); + Json::Value jvDestCur; if (!asDst) { // no destination account + jvDestCur.append(Json::Value("XRP")); if(!saDstAmount.isNative()) { // only XRP can be send to a non-existent account bValid = false; @@ -48,21 +53,41 @@ bool PFRequest::isValid(Ledger::ref lrLedger) jvStatus = rpcError(rpcDST_AMT_MALFORMED); } } + else + { + boost::unordered_set usDestCurrID = usAccountDestCurrencies(raDstAccount, lrLedger, true); + BOOST_FOREACH(const uint160& uCurrency, usDestCurrID) + jvDestCur.append(STAmount::createHumanCurrency(uCurrency)); + jvStatus["destination_tag"] = (asDst->peekSLE().getFlags() & lsfRequireDestTag) != 0; + } + jvStatus["destination_currencies"] = jvDestCur; } } + jvStatus["ledger_hash"] = lrLedger->getHash().GetHex(); + jvStatus["ledger_index"] = lrLedger->getLedgerSeq(); return bValid; } Json::Value PFRequest::doCreate(Ledger::ref lrLedger, const Json::Value& value) { + assert(lrLedger->isClosed()); + Json::Value status; bool mValid; { boost::recursive_mutex::scoped_lock sl(mLock); - parseJson(value, true); - status = jvStatus; - mValid = isValid(lrLedger); + if (parseJson(value, true) != PFR_PJ_INVALID) + { + mValid = isValid(lrLedger); + if (mValid) + { + RLCache::pointer cache = boost::make_shared(lrLedger); + doUpdate(cache, true); + } + } + else + mValid = false; } if (mValid) @@ -167,4 +192,60 @@ Json::Value PFRequest::doStatus(const Json::Value&) return jvStatus; } +bool PFRequest::doUpdate(RLCache::ref cache, bool fast) +{ + boost::recursive_mutex::scoped_lock sl(mLock); + jvStatus = Json::objectValue; + if (!isValid(cache->getLedger())) + return false; + + std::set sourceCurrencies(sciSourceCurrencies); + if (sourceCurrencies.empty()) + { + boost::unordered_set usCurrencies = + usAccountSourceCurrencies(raSrcAccount, cache->getLedger(), true); + bool sameAccount = raSrcAccount == raDstAccount; + BOOST_FOREACH(const uint160& c, usCurrencies) + { + if (!sameAccount || (c != saDstAmount.getCurrency())) + sourceCurrencies.insert(std::make_pair(c, ACCOUNT_XRP)); + } + } + + jvStatus["source_account"] = raSrcAccount.humanAccountID(); + jvStatus["destination_account"] = raDstAccount.humanAccountID(); + + Json::Value jvArray = Json::arrayValue; + + BOOST_FOREACH(const currIssuer_t& currIssuer, sourceCurrencies) + { + bool valid; + STPathSet spsPaths; + Pathfinder pf(cache, raSrcAccount, raDstAccount, + currIssuer.first, currIssuer.second, saDstAmount, valid); + if (valid && pf.findPaths(theConfig.PATH_SEARCH_SIZE - (fast ? 0 : 1), 3, spsPaths)) + { + LedgerEntrySet lesSandbox(cache->getLedger(), tapNONE); + std::vector vpsExpanded; + STAmount saMaxAmountAct; + STAmount saDstAmountAct; + STAmount saMaxAmount(currIssuer.first, + currIssuer.second.isNonZero() ? currIssuer.second : + (currIssuer.first.isZero() ? ACCOUNT_XRP : raSrcAccount.getAccountID()), 1); + TER terResult = RippleCalc::rippleCalc(lesSandbox, saMaxAmountAct, saDstAmountAct, + vpsExpanded, saMaxAmount, saDstAmount, raDstAccount.getAccountID(), raSrcAccount.getAccountID(), + spsPaths, false, false, false, true); + if (terResult == tesSUCCESS) + { + Json::Value jvEntry(Json::objectValue); + jvEntry["source_amount"] = saMaxAmountAct.getJson(0); + jvEntry["paths_computed"] = spsPaths.getJson(0); + jvArray.append(jvEntry); + } + } + } + jvStatus["alternatives"] = jvArray; + return true; +} + // vim:ts=4 diff --git a/src/cpp/ripple/PFRequest.h b/src/cpp/ripple/PFRequest.h index 30c40ff91..618bb5b9d 100644 --- a/src/cpp/ripple/PFRequest.h +++ b/src/cpp/ripple/PFRequest.h @@ -14,6 +14,7 @@ #include "uint256.h" #include "RippleAddress.h" #include "SerializedTypes.h" +#include "Pathfinder.h" // A pathfinding request submitted by a client // The request issuer must maintain a strong pointer @@ -21,6 +22,7 @@ class Ledger; class InfoSub; class STAmount; +class RLCache; // Return values from parseJson <0 = invalid, >0 = valid #define PFR_PJ_INVALID -1 @@ -69,8 +71,7 @@ public: Json::Value doClose(const Json::Value&); Json::Value doStatus(const Json::Value&); - void doUpdate(); // do an update - void trigger(); // schedule an update + bool doUpdate(const boost::shared_ptr&, bool fast); // update jvStatus static void updateAll(const boost::shared_ptr &); }; diff --git a/src/cpp/ripple/Pathfinder.cpp b/src/cpp/ripple/Pathfinder.cpp index 35a55da78..7101f9458 100644 --- a/src/cpp/ripple/Pathfinder.cpp +++ b/src/cpp/ripple/Pathfinder.cpp @@ -138,7 +138,7 @@ static int getEffectiveLength(const STPath& spPath) return length; } -Pathfinder::Pathfinder(Ledger::ref ledger, RLCache::ref cache, +Pathfinder::Pathfinder(RLCache::ref cache, const RippleAddress& uSrcAccountID, const RippleAddress& uDstAccountID, const uint160& uSrcCurrencyID, const uint160& uSrcIssuerID, const STAmount& saDstAmount, bool& bValid) : mSrcAccountID(uSrcAccountID.getAccountID()), @@ -147,7 +147,7 @@ Pathfinder::Pathfinder(Ledger::ref ledger, RLCache::ref cache, mSrcCurrencyID(uSrcCurrencyID), mSrcIssuerID(uSrcIssuerID), mSrcAmount(uSrcCurrencyID, uSrcIssuerID, 1u, 0, true), - mLedger(ledger), mRLCache(cache) + mLedger(cache->getLedger()), mRLCache(cache) { if (((mSrcAccountID == mDstAccountID) && (mSrcCurrencyID == mDstAmount.getCurrency())) || mDstAmount.isZero()) diff --git a/src/cpp/ripple/Pathfinder.h b/src/cpp/ripple/Pathfinder.h index c1a9df966..3ddbb486b 100644 --- a/src/cpp/ripple/Pathfinder.h +++ b/src/cpp/ripple/Pathfinder.h @@ -47,7 +47,9 @@ public: typedef const pointer& ref; RLCache(Ledger::ref l) : mLedger(l) { ; } - AccountItems& getRippleLines(const uint160& accountID); + Ledger::ref getLedger() { return mLedger; } + + AccountItems& getRippleLines(const uint160& accountID); }; class Pathfinder @@ -83,7 +85,7 @@ class Pathfinder bool isAuthRequired, bool isDestCurrency, const uint160& dest); public: - Pathfinder(Ledger::ref ledger, RLCache::ref cache, + Pathfinder(RLCache::ref cache, const RippleAddress& srcAccountID, const RippleAddress& dstAccountID, const uint160& srcCurrencyID, const uint160& srcIssuerID, const STAmount& dstAmount, bool& bValid); diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 82abd03ac..28f968461 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -182,7 +182,7 @@ Json::Value RPCHandler::transactionSign(Json::Value jvRequest, bool bSubmit) ScopedUnlock su(theApp->getMasterLock()); bool bValid; RLCache::pointer cache = boost::make_shared(lSnapshot); - Pathfinder pf(lSnapshot, cache, raSrcAddressID, dstAccountID, + Pathfinder pf(cache, raSrcAddressID, dstAccountID, saSendMax.getCurrency(), saSendMax.getIssuer(), saSend, bValid); if (!bValid || !pf.findPaths(theConfig.PATH_SEARCH_SIZE, 3, spsPaths)) @@ -1173,13 +1173,17 @@ Json::Value RPCHandler::doPathFind(Json::Value jvRequest, int& cost, ScopedLock& { if (!jvRequest.isMember("subcommand") || !jvRequest["subcommand"].isString()) return rpcError(rpcINVALID_PARAMS); + + if (!mInfoSub) + return rpcError(rpcNO_EVENTS); + std::string sSubCommand = jvRequest["subcommand"].asString(); if (sSubCommand == "create") { mInfoSub->clearPFRequest(); PFRequest::pointer request = boost::make_shared(mInfoSub); - Json::Value result = request->doCreate(mNetOps->getCurrentLedger(), jvRequest); + Json::Value result = request->doCreate(mNetOps->getClosedLedger(), jvRequest); if (request->isValid()) mInfoSub->setPFRequest(request); return result; @@ -1342,7 +1346,7 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest, int& cost, Scope STPathSet spsComputed; bool bValid; - Pathfinder pf(lSnapShot, cache, raSrc, raDst, uSrcCurrencyID, uSrcIssuerID, saDstAmount, bValid); + Pathfinder pf(cache, raSrc, raDst, uSrcCurrencyID, uSrcIssuerID, saDstAmount, bValid); if (!bValid || !pf.findPaths(theConfig.PATH_SEARCH_SIZE, 3, spsComputed)) {