From 8df9519a1c5cd09e821ce75729d8defdfd07ab3c Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 11 Jan 2013 18:55:13 -0800 Subject: [PATCH] Add a default for currencies for ripple_find_path. --- src/cpp/ripple/Pathfinder.cpp | 26 ++++++++++++++- src/cpp/ripple/Pathfinder.h | 2 ++ src/cpp/ripple/RPCErr.cpp | 2 ++ src/cpp/ripple/RPCErr.h | 2 ++ src/cpp/ripple/RPCHandler.cpp | 63 +++++++++++++++++++++++++---------- src/cpp/ripple/RippleState.h | 1 + 6 files changed, 78 insertions(+), 18 deletions(-) diff --git a/src/cpp/ripple/Pathfinder.cpp b/src/cpp/ripple/Pathfinder.cpp index a1d37d1921..674c811d00 100644 --- a/src/cpp/ripple/Pathfinder.cpp +++ b/src/cpp/ripple/Pathfinder.cpp @@ -317,7 +317,7 @@ bool Pathfinder::findPaths(const unsigned int iMaxSteps, const unsigned int iMax % RippleAddress::createHumanAccountID(rspEntry->getAccountIDPeer().getAccountID()) % STAmount::createHumanCurrency(speEnd.mCurrencyID)); } - else if (!rspEntry->getBalance().isPositive() // Have IOUs to send. + else if (!rspEntry->getBalance().isPositive() // No IOUs to send. && (!rspEntry->getLimitPeer() // Peer does not extend credit. || *rspEntry->getBalance().negate() >= rspEntry->getLimitPeer())) // No credit left. { @@ -565,4 +565,28 @@ void Pathfinder::addPathOption(PathOption::pointer pathOption) } #endif +boost::unordered_set usAccountSourceCurrencies(const RippleAddress& raAccountID, Ledger::ref lrLedger) +{ + boost::unordered_set usCurrencies; + + // List of ripple lines. + AccountItems rippleLines(raAccountID.getAccountID(), lrLedger, AccountItem::pointer(new RippleState())); + + BOOST_FOREACH(AccountItem::ref item, rippleLines.getItems()) + { + RippleState* rspEntry = (RippleState*) item.get(); + STAmount saBalance = rspEntry->getBalance(); + + // Filter out non + if (saBalance.isPositive() // Have IOUs to send. + || (rspEntry->getLimitPeer() // Peer extends credit. + && *saBalance.negate() < rspEntry->getLimitPeer())) // Credit left. + { + // Path has no credit left. Ignore it. + usCurrencies.insert(saBalance.getCurrency()); + } + } + + return usCurrencies; +} // vim:ts=4 diff --git a/src/cpp/ripple/Pathfinder.h b/src/cpp/ripple/Pathfinder.h index b0cf3ec136..5682778e49 100644 --- a/src/cpp/ripple/Pathfinder.h +++ b/src/cpp/ripple/Pathfinder.h @@ -63,6 +63,8 @@ public: bool bDefaultPath(const STPath& spPath); }; + +boost::unordered_set usAccountSourceCurrencies(const RippleAddress& raAccountID, Ledger::ref lrLedger); #endif // vim:ts=4 diff --git a/src/cpp/ripple/RPCErr.cpp b/src/cpp/ripple/RPCErr.cpp index 61414aec3a..57eb4dadd6 100644 --- a/src/cpp/ripple/RPCErr.cpp +++ b/src/cpp/ripple/RPCErr.cpp @@ -58,6 +58,8 @@ Json::Value rpcError(int iError, Json::Value jvResult) { rpcSRC_ACT_MISSING, "srcActMissing", "Source account not provided." }, { rpcSRC_ACT_NOT_FOUND, "srcActNotFound", "Source amount not found." }, { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed." }, + { rpcSRC_CUR_MALFORMED, "srcCurMalformed", "Source currency is malformed." }, + { rpcSRC_ISR_MALFORMED, "srcIsrMalformed", "Source issuer is malformed." }, { rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." }, { rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." }, { rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown command." }, diff --git a/src/cpp/ripple/RPCErr.h b/src/cpp/ripple/RPCErr.h index 02dcda0080..858c3f9b5d 100644 --- a/src/cpp/ripple/RPCErr.h +++ b/src/cpp/ripple/RPCErr.h @@ -62,6 +62,8 @@ enum { rpcSRC_ACT_MISSING, rpcSRC_ACT_NOT_FOUND, rpcSRC_AMT_MALFORMED, + rpcSRC_CUR_MALFORMED, + rpcSRC_ISR_MALFORMED, // Internal error (should never happen) rpcINTERNAL, // Generic internal error. diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index dd2c98a56a..e1b5df4349 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -754,9 +754,9 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest) } else if ( // Checks on source_currencies. - !jvRequest.isMember("source_currencies") - || !jvRequest["source_currencies"].isArray() - || !jvRequest["source_currencies"].size() + jvRequest.isMember("source_currencies") + && (!jvRequest["source_currencies"].isArray() + || !jvRequest["source_currencies"].size()) // Don't allow empty currencies. ) { cLog(lsINFO) << "Bad source_currencies."; @@ -764,36 +764,63 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest) } else { - Json::Value jvSrcCurrencies = jvRequest["source_currencies"]; - Json::Value jvArray(Json::arrayValue); - Ledger::pointer lpCurrent = mNetOps->getCurrentLedger(); + Json::Value jvSrcCurrencies; + + if (jvRequest.isMember("source_currencies")) + { + jvSrcCurrencies = jvRequest["source_currencies"]; + } + else + { + boost::unordered_set usCurrencies = usAccountSourceCurrencies(raSrc, lpCurrent); + + // Add XRP as a source currency. + // YYY Only bother if they are above reserve. + usCurrencies.insert(uint160(CURRENCY_XRP)); + + jvSrcCurrencies = Json::Value(Json::arrayValue); + + BOOST_FOREACH(const uint160& uCurrency, usCurrencies) + { + Json::Value jvCurrency(Json::objectValue); + + jvCurrency["currency"] = STAmount::createHumanCurrency(uCurrency); + + jvSrcCurrencies.append(jvCurrency); + } + } + + LedgerEntrySet lesSnapshot(lpCurrent); ScopedUnlock su(theApp->getMasterLock()); // As long as we have a locked copy of the ledger, we can unlock. - LedgerEntrySet lesSnapshot(lpCurrent); + Json::Value jvArray(Json::arrayValue); for (unsigned int i=0; i != jvSrcCurrencies.size(); ++i) { Json::Value jvSource = jvSrcCurrencies[i]; uint160 uSrcCurrencyID; uint160 uSrcIssuerID = raSrc.getAccountID(); - if ( - // Parse currency. - !jvSource.isMember("currency") - || !STAmount::currencyFromString(uSrcCurrencyID, jvSource["currency"].asString()) + // Parse mandatory currency. + if (!jvSource.isMember("currency") + || !STAmount::currencyFromString(uSrcCurrencyID, jvSource["currency"].asString())) + { + cLog(lsINFO) << "Bad currency."; - // Parse issuer. - || ((jvSource.isMember("issuer")) + return rpcError(rpcSRC_CUR_MALFORMED); + } + // Parse optional issuer. + else if (((jvSource.isMember("issuer")) && (!jvSource["issuer"].isString() || !STAmount::issuerFromString(uSrcIssuerID, jvSource["issuer"].asString()))) - // Don't allow illegal issuers. || !uSrcIssuerID || ACCOUNT_ONE == uSrcIssuerID) { - cLog(lsINFO) << "Bad currency/issuer."; - return rpcError(rpcINVALID_PARAMS); + cLog(lsINFO) << "Bad issuer."; + + return rpcError(rpcSRC_ISR_MALFORMED); } STPathSet spsComputed; @@ -2495,7 +2522,9 @@ Json::Value RPCHandler::doCommand(Json::Value& jvRequest, int iRole) { return rpcError(rpcNO_PERMISSION); } - else if (commandsA[i].iOptions & optNetwork + + // XXX Need the master lock for getOperatingMode + if (commandsA[i].iOptions & optNetwork && mNetOps->getOperatingMode() != NetworkOPs::omTRACKING && mNetOps->getOperatingMode() != NetworkOPs::omFULL) { diff --git a/src/cpp/ripple/RippleState.h b/src/cpp/ripple/RippleState.h index f7edcbe1e8..a89c554761 100644 --- a/src/cpp/ripple/RippleState.h +++ b/src/cpp/ripple/RippleState.h @@ -34,6 +34,7 @@ private: bool mViewLowest; RippleState(SerializedLedgerEntry::ref ledgerEntry); // For accounts in a ledger + public: RippleState(){ } AccountItem::pointer makeItem(const uint160& accountID, SerializedLedgerEntry::ref ledgerEntry);