From 9755563e186423bb356b3e5029a61052150da38e Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 20 Nov 2012 18:52:42 -0800 Subject: [PATCH] Cosmetic changes for path finding. --- src/cpp/ripple/Pathfinder.cpp | 183 ++++++++++++++++++---------------- src/cpp/ripple/RPCHandler.cpp | 101 +++++++++++-------- src/cpp/ripple/RPCHandler.h | 2 + 3 files changed, 160 insertions(+), 126 deletions(-) diff --git a/src/cpp/ripple/Pathfinder.cpp b/src/cpp/ripple/Pathfinder.cpp index 318d76371..4fd581157 100644 --- a/src/cpp/ripple/Pathfinder.cpp +++ b/src/cpp/ripple/Pathfinder.cpp @@ -36,27 +36,24 @@ Test XRP to USD Test USD to EUR */ - // we sort the options by: // cost of path // length of path // width of path // correct currency at the end - - bool sortPathOptions(PathOption::pointer first, PathOption::pointer second) { - if(first->mTotalCostmTotalCost) return(true); - if(first->mTotalCost>second->mTotalCost) return(false); + if (first->mTotalCostmTotalCost) return(true); + if (first->mTotalCost>second->mTotalCost) return(false); - if(first->mCorrectCurrency && !second->mCorrectCurrency) return(true); - if(!first->mCorrectCurrency && second->mCorrectCurrency) return(false); + if (first->mCorrectCurrency && !second->mCorrectCurrency) return(true); + if (!first->mCorrectCurrency && second->mCorrectCurrency) return(false); - if(first->mPath.getElementCount()mPath.getElementCount()) return(true); - if(first->mPath.getElementCount()>second->mPath.getElementCount()) return(false); + if (first->mPath.getElementCount()mPath.getElementCount()) return(true); + if (first->mPath.getElementCount()>second->mPath.getElementCount()) return(false); - if(first->mMinWidthmMinWidth) return true; + if (first->mMinWidthmMinWidth) return true; return false; } @@ -76,98 +73,115 @@ PathOption::PathOption(PathOption::pointer other) } -Pathfinder::Pathfinder(RippleAddress& srcAccountID, RippleAddress& dstAccountID, uint160& srcCurrencyID, STAmount dstAmount) : +Pathfinder::Pathfinder(RippleAddress& srcAccountID, RippleAddress& dstAccountID, uint160& srcCurrencyID, STAmount dstAmount) : mSrcAccountID(srcAccountID.getAccountID()), mDstAccountID(dstAccountID.getAccountID()), mDstAmount(dstAmount), mSrcCurrencyID(srcCurrencyID), mOrderBook(theApp->getMasterLedger().getCurrentLedger()) { mLedger=theApp->getMasterLedger().getCurrentLedger(); } +// Returns a single path, if possible. +// --> maxSearchSteps: unused +// --> maxPay: unused bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet) { - if(mLedger) { - std::queue pqueue; - STPathElement ele(mSrcAccountID, - mSrcCurrencyID, - uint160()); - STPath path; - path.addElement(ele); - pqueue.push(path); - while(pqueue.size()) { + if (mLedger) { + std::queue pqueue; + STPathElement ele(mSrcAccountID, + mSrcCurrencyID, + uint160()); + STPath path; - STPath path = pqueue.front(); - pqueue.pop(); - // get the first path from the queue + path.addElement(ele); // Add the source. - ele = path.mPath.back(); - // get the last node from the path + pqueue.push(path); - if (ele.mAccountID == mDstAccountID) { - path.mPath.erase(path.mPath.begin()); - path.mPath.erase(path.mPath.begin() + path.mPath.size()-1); - if (path.mPath.size() == 0) { - continue; - } - retPathSet.addPath(path); - return true; - } - // found the destination + while (pqueue.size()) { + STPath path = pqueue.front(); - if (!ele.mCurrencyID) { - BOOST_FOREACH(OrderBook::pointer book,mOrderBook.getXRPInBooks()) - { - //if (!path.hasSeen(line->getAccountIDPeer().getAccountID())) - { + pqueue.pop(); // Pop the first path from the queue. - STPath new_path(path); - STPathElement new_ele(uint160(), book->getCurrencyOut(), book->getIssuerOut()); - new_path.mPath.push_back(new_ele); - new_path.mCurrencyID = book->getCurrencyOut(); - new_path.mCurrentAccount = book->getCurrencyOut(); + ele = path.mPath.back(); // Get the last node from the path. - pqueue.push(new_path); + // Determine if path is solved. + if (ele.mAccountID == mDstAccountID) { + // Found a path to the destination. - } - } + if (2 == path.mPath.size()) { + // Empty path is default. Drop it. + continue; + } - } else { - RippleLines rippleLines(ele.mAccountID); - BOOST_FOREACH(RippleState::pointer line,rippleLines.getLines()) - { - if (!path.hasSeen(line->getAccountIDPeer().getAccountID())) - { - STPath new_path(path); - STPathElement new_ele(line->getAccountIDPeer().getAccountID(), - ele.mCurrencyID, - uint160()); - - new_path.mPath.push_back(new_ele); - pqueue.push(new_path); - } - } // BOOST_FOREACHE + // Remove implied first and last nodes. + path.mPath.erase(path.mPath.begin()); + path.mPath.erase(path.mPath.begin() + path.mPath.size()-1); - // every offer that wants the source currency - std::vector books; - mOrderBook.getBooks(path.mCurrentAccount, path.mCurrencyID, books); + // Return the path. + retPathSet.addPath(path); - BOOST_FOREACH(OrderBook::pointer book,books) - { - STPath new_path(path); - STPathElement new_ele(uint160(), book->getCurrencyOut(), book->getIssuerOut()); + return true; + } - new_path.mPath.push_back(new_ele); - new_path.mCurrentAccount=book->getIssuerOut(); - new_path.mCurrencyID=book->getCurrencyOut(); + if (!ele.mCurrencyID) { + // Last element is for XRP continue with qualifying books. - pqueue.push(new_path); + BOOST_FOREACH(OrderBook::pointer book, mOrderBook.getXRPInBooks()) + { + //if (!path.hasSeen(line->getAccountIDPeer().getAccountID())) + { + STPath new_path(path); + STPathElement new_ele(uint160(), book->getCurrencyOut(), book->getIssuerOut()); - } + new_path.mPath.push_back(new_ele); + new_path.mCurrencyID = book->getCurrencyOut(); + new_path.mCurrentAccount = book->getCurrencyOut(); - } // else - // enumerate all adjacent nodes, construct a new path and push it into the queue - } // While - } // if there is a ledger + pqueue.push(new_path); + } + } - return false; + } else { + // Last element is for non-XRP continue by adding ripple lines and order books. + + // Create new paths for each outbound account not already in the path. + RippleLines rippleLines(ele.mAccountID); + + BOOST_FOREACH(RippleState::pointer line, rippleLines.getLines()) + { + if (!path.hasSeen(line->getAccountIDPeer().getAccountID())) + { + STPath new_path(path); + STPathElement new_ele(line->getAccountIDPeer().getAccountID(), + ele.mCurrencyID, + uint160()); + + new_path.mPath.push_back(new_ele); + pqueue.push(new_path); + } + } + + // Every book that wants the source currency. + std::vector books; + + mOrderBook.getBooks(path.mCurrentAccount, path.mCurrencyID, books); + + BOOST_FOREACH(OrderBook::pointer book,books) + { + STPath new_path(path); + STPathElement new_ele(uint160(), book->getCurrencyOut(), book->getIssuerOut()); + + new_path.mPath.push_back(new_ele); + new_path.mCurrentAccount=book->getIssuerOut(); + new_path.mCurrencyID=book->getCurrencyOut(); + + pqueue.push(new_path); + } + } + + // enumerate all adjacent nodes, construct a new path and push it into the queue + } // While + } // if there is a ledger + + return false; } bool Pathfinder::checkComplete(STPathSet& retPathSet) @@ -196,9 +210,9 @@ bool Pathfinder::checkComplete(STPathSet& retPathSet) void Pathfinder::addOptions(PathOption::pointer tail) { - if(!tail->mCurrencyID) + if (!tail->mCurrencyID) { // source XRP - BOOST_FOREACH(OrderBook::pointer book,mOrderBook.getXRPInBooks()) + BOOST_FOREACH(OrderBook::pointer book, mOrderBook.getXRPInBooks()) { PathOption::pointer pathOption(new PathOption(tail)); @@ -209,13 +223,14 @@ void Pathfinder::addOptions(PathOption::pointer tail) pathOption->mCurrencyID=book->getCurrencyOut(); addPathOption(pathOption); } - }else + } + else { // ripple RippleLines rippleLines(tail->mCurrentAccount); BOOST_FOREACH(RippleState::pointer line,rippleLines.getLines()) { // TODO: make sure we can move in the correct direction - STAmount balance=line->getBalance(); + STAmount balance=line->getBalance(); if(balance.getCurrency()==tail->mCurrencyID) { // we have a ripple line from the tail to somewhere else PathOption::pointer pathOption(new PathOption(tail)); diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 2273f2c18..001fe40a5 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -526,11 +526,19 @@ Json::Value RPCHandler::doOwnerInfo(const Json::Value& params) } +Json::Value RPCHandler::doPathFind(const Json::Value& params) +{ + Json::Value ret(Json::objectValue); + + return ret; +} + Json::Value RPCHandler::doPeers(const Json::Value& params) { - // peers Json::Value obj(Json::objectValue); + obj["peers"]=theApp->getConnectionPool().getPeersJson(); + return obj; } @@ -759,20 +767,21 @@ Json::Value RPCHandler::handleJSONSubmit(const Json::Value& jvRequest) return rpcError(rpcDST_ACT_MALFORMED); } - if(!txJSON.isMember("Fee")) + if (!txJSON.isMember("Fee")) { - if(mNetOps->getAccountState(uint256(0), dstAccountID)) + if (mNetOps->getAccountState(uint256(0), dstAccountID)) txJSON["Fee"]=(int)theConfig.FEE_DEFAULT; else txJSON["Fee"]=(int)theConfig.FEE_ACCOUNT_CREATE; } - if(!txJSON.isMember("Paths") && jvRequest.isMember("build_path") ) + if (!txJSON.isMember("Paths") && jvRequest.isMember("build_path")) { - if(txJSON["Amount"].isObject() || txJSON.isMember("SendMax") ) + if (txJSON["Amount"].isObject() || txJSON.isMember("SendMax")) { // we need a ripple path STPathSet spsPaths; uint160 srcCurrencyID; - if(txJSON.isMember("SendMax") && txJSON["SendMax"].isMember("currency")) + + if (txJSON.isMember("SendMax") && txJSON["SendMax"].isMember("currency")) { STAmount::currencyFromString(srcCurrencyID, txJSON["SendMax"]["currency"].asString()); } @@ -782,7 +791,8 @@ Json::Value RPCHandler::handleJSONSubmit(const Json::Value& jvRequest) } STAmount dstAmount; - if(txJSON["Amount"].isObject()) + + if (txJSON["Amount"].isObject()) { std::string issuerStr; if( txJSON["Amount"].isMember("issuer")) issuerStr=txJSON["Amount"]["issuer"].asString(); @@ -791,14 +801,17 @@ Json::Value RPCHandler::handleJSONSubmit(const Json::Value& jvRequest) { return rpcError(rpcDST_AMT_MALFORMED); } - }else if (!dstAmount.setFullValue(txJSON["Amount"].asString())) + } + else if (!dstAmount.setFullValue(txJSON["Amount"].asString())) { return rpcError(rpcDST_AMT_MALFORMED); } Pathfinder pf(srcAddress, dstAccountID, srcCurrencyID, dstAmount); + pf.findPaths(5, 1, spsPaths); - if(!spsPaths.isEmpty()) + + if (!spsPaths.isEmpty()) { txJSON["Paths"]=spsPaths.getJson(0); if(txJSON.isMember("Flags")) txJSON["Flags"]=txJSON["Flags"].asUInt() | 2; @@ -806,16 +819,18 @@ Json::Value RPCHandler::handleJSONSubmit(const Json::Value& jvRequest) } } } - - }else if( txJSON["type"]=="OfferCreate" ) + } + else if( txJSON["type"]=="OfferCreate" ) { txJSON["TransactionType"]=7; if(!txJSON.isMember("Fee")) txJSON["Fee"]=(int)theConfig.FEE_DEFAULT; - }else if( txJSON["type"]=="TrustSet") + } + else if( txJSON["type"]=="TrustSet") { txJSON["TransactionType"]=20; if(!txJSON.isMember("Fee")) txJSON["Fee"]=(int)theConfig.FEE_DEFAULT; - }else if( txJSON["type"]=="OfferCancel") + } + else if( txJSON["type"]=="OfferCancel") { txJSON["TransactionType"]=8; if(!txJSON.isMember("Fee")) txJSON["Fee"]=(int)theConfig.FEE_DEFAULT; @@ -1332,55 +1347,57 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param unsigned int iOptions; } commandsA[] = { // Request-response methods - { "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true }, + { "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true, false, optNone }, { "account_info", &RPCHandler::doAccountInfo, 1, 2, false, false, optCurrent }, { "account_tx", &RPCHandler::doAccountTransactions, 2, 3, false, false, optNetwork }, - { "connect", &RPCHandler::doConnect, 1, 2, true }, - { "data_delete", &RPCHandler::doDataDelete, 1, 1, true }, - { "data_fetch", &RPCHandler::doDataFetch, 1, 1, true }, - { "data_store", &RPCHandler::doDataStore, 2, 2, true }, - { "get_counts", &RPCHandler::doGetCounts, 0, 1, true }, + { "connect", &RPCHandler::doConnect, 1, 2, true, false, optNone }, + { "data_delete", &RPCHandler::doDataDelete, 1, 1, true, false, optNone }, + { "data_fetch", &RPCHandler::doDataFetch, 1, 1, true, false, optNone }, + { "data_store", &RPCHandler::doDataStore, 2, 2, true, false, optNone }, + { "get_counts", &RPCHandler::doGetCounts, 0, 1, true, false, optNone }, { "ledger", &RPCHandler::doLedger, 0, 2, false, false, optNetwork }, { "ledger_accept", &RPCHandler::doLedgerAccept, 0, 0, true, false, optCurrent }, { "ledger_closed", &RPCHandler::doLedgerClosed, 0, 0, false, false, optClosed }, { "ledger_current", &RPCHandler::doLedgerCurrent, 0, 0, false, false, optCurrent }, - { "ledger_entry", &RPCHandler::doLedgerEntry, -1, -1, false, false, optCurrent }, - { "ledger_header", &RPCHandler::doLedgerHeader, -1, -1, false, false, optCurrent }, - { "log_level", &RPCHandler::doLogLevel, 0, 2, true }, - { "logrotate", &RPCHandler::doLogRotate, 0, 0, true }, + { "ledger_entry", &RPCHandler::doLedgerEntry, -1, -1, false, false, optCurrent }, + { "ledger_header", &RPCHandler::doLedgerHeader, -1, -1, false, false, optCurrent }, + { "log_level", &RPCHandler::doLogLevel, 0, 2, true, false, optNone }, + { "logrotate", &RPCHandler::doLogRotate, 0, 0, true, false, optNone }, { "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, false, optCurrent }, { "owner_info", &RPCHandler::doOwnerInfo, 1, 2, false, false, optCurrent }, - { "peers", &RPCHandler::doPeers, 0, 0, true }, + { "path_find", &RPCHandler::doPathFind, -1, -1, false, false, optCurrent }, + { "peers", &RPCHandler::doPeers, 0, 0, true, false, optNone }, { "profile", &RPCHandler::doProfile, 1, 9, false, false, optCurrent }, { "ripple_lines_get", &RPCHandler::doRippleLinesGet, 1, 2, false, false, optCurrent }, { "submit", &RPCHandler::doSubmit, 2, 2, false, false, optCurrent }, { "submit_json", &RPCHandler::doSubmitJson, -1, -1, false, false, optCurrent }, - { "server_info", &RPCHandler::doServerInfo, 0, 0, true }, - { "stop", &RPCHandler::doStop, 0, 0, true }, + { "server_info", &RPCHandler::doServerInfo, 0, 0, true, false, optNone }, + { "stop", &RPCHandler::doStop, 0, 0, true, false, optNone }, { "transaction_entry", &RPCHandler::doTransactionEntry, -1, -1, false, false, optCurrent }, - { "tx", &RPCHandler::doTx, 1, 1, true }, - { "tx_history", &RPCHandler::doTxHistory, 1, 1, false, }, + { "tx", &RPCHandler::doTx, 1, 1, true, false, optNone }, + { "tx_history", &RPCHandler::doTxHistory, 1, 1, false, false, optNone }, - { "unl_add", &RPCHandler::doUnlAdd, 1, 2, true }, - { "unl_delete", &RPCHandler::doUnlDelete, 1, 1, true }, - { "unl_list", &RPCHandler::doUnlList, 0, 0, true }, - { "unl_load", &RPCHandler::doUnlLoad, 0, 0, true }, - { "unl_network", &RPCHandler::doUnlNetwork, 0, 0, true }, - { "unl_reset", &RPCHandler::doUnlReset, 0, 0, true }, - { "unl_score", &RPCHandler::doUnlScore, 0, 0, true }, + { "unl_add", &RPCHandler::doUnlAdd, 1, 2, true, false, optNone }, + { "unl_delete", &RPCHandler::doUnlDelete, 1, 1, true, false, optNone }, + { "unl_list", &RPCHandler::doUnlList, 0, 0, true, false, optNone }, + { "unl_load", &RPCHandler::doUnlLoad, 0, 0, true, false, optNone }, + { "unl_network", &RPCHandler::doUnlNetwork, 0, 0, true, false, optNone }, + { "unl_reset", &RPCHandler::doUnlReset, 0, 0, true, false, optNone }, + { "unl_score", &RPCHandler::doUnlScore, 0, 0, true, false, optNone }, - { "validation_create", &RPCHandler::doValidationCreate, 0, 1, false }, - { "validation_seed", &RPCHandler::doValidationSeed, 0, 1, false }, + { "validation_create", &RPCHandler::doValidationCreate, 0, 1, false, false, optNone }, + { "validation_seed", &RPCHandler::doValidationSeed, 0, 1, false, false, optNone }, { "wallet_accounts", &RPCHandler::doWalletAccounts, 1, 1, false, false, optCurrent }, - { "wallet_propose", &RPCHandler::doWalletPropose, 0, 1, false, }, - { "wallet_seed", &RPCHandler::doWalletSeed, 0, 1, false, }, + { "wallet_propose", &RPCHandler::doWalletPropose, 0, 1, false, false, optNone }, + { "wallet_seed", &RPCHandler::doWalletSeed, 0, 1, false, false, optNone }, - { "login", &RPCHandler::doLogin, 2, 2, true }, + { "login", &RPCHandler::doLogin, 2, 2, true, false, optNone }, // Evented methods - { "subscribe", &RPCHandler::doSubscribe, -1, -1, false, true }, - { "unsubscribe", &RPCHandler::doUnsubscribe, -1, -1, false, true }, }; + { "subscribe", &RPCHandler::doSubscribe, -1, -1, false, true, optNone }, + { "unsubscribe", &RPCHandler::doUnsubscribe, -1, -1, false, true, optNone }, + }; int i = NUMBER(commandsA); diff --git a/src/cpp/ripple/RPCHandler.h b/src/cpp/ripple/RPCHandler.h index 0b742c8dd..e2f1a25b7 100644 --- a/src/cpp/ripple/RPCHandler.h +++ b/src/cpp/ripple/RPCHandler.h @@ -12,6 +12,7 @@ class RPCHandler typedef Json::Value (RPCHandler::*doFuncPtr)(const Json::Value ¶ms); enum { + optNone = 0, optNetwork = 1, // Need network optCurrent = 2+optNetwork, // Need current ledger optClosed = 4+optNetwork, // Need closed ledger @@ -50,6 +51,7 @@ class RPCHandler Json::Value doOwnerInfo(const Json::Value& params); Json::Value doProfile(const Json::Value& params); + Json::Value doPathFind(const Json::Value& params); Json::Value doPeers(const Json::Value& params); Json::Value doRippleLinesGet(const Json::Value ¶ms);