Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast) { m_journal.debug << iIdentifier << " update " << (fast ? "fast" : "normal"); ScopedLockType sl (mLock); if (!isValid (cache)) return jvStatus; jvStatus = Json::objectValue; auto sourceCurrencies = sciSourceCurrencies; if (sourceCurrencies.empty ()) { auto usCurrencies = usAccountSourceCurrencies (raSrcAccount, cache, true); bool sameAccount = raSrcAccount == raDstAccount; for (auto const& c: usCurrencies) { if (!sameAccount || (c != saDstAmount.getCurrency ())) { if (c.isZero ()) sourceCurrencies.insert (std::make_pair (c, xrpAccount())); else sourceCurrencies.insert (std::make_pair (c, raSrcAccount.getAccountID ())); } } } jvStatus["source_account"] = raSrcAccount.humanAccountID (); jvStatus["destination_account"] = raDstAccount.humanAccountID (); jvStatus["destination_amount"] = saDstAmount.getJson (0); if (!jvId.isNull ()) jvStatus["id"] = jvId; Json::Value jvArray = Json::arrayValue; int iLevel = iLastLevel; bool loaded = getApp().getFeeTrack().isLoadedLocal(); if (iLevel == 0) { // first pass if (loaded || fast) iLevel = getConfig().PATH_SEARCH_FAST; else iLevel = getConfig().PATH_SEARCH; } else if ((iLevel == getConfig().PATH_SEARCH_FAST) && !fast) { // leaving fast pathfinding iLevel = getConfig().PATH_SEARCH; if (loaded && (iLevel > getConfig().PATH_SEARCH_FAST)) --iLevel; } else if (bLastSuccess) { // decrement, if possible if (iLevel > getConfig().PATH_SEARCH || (loaded && (iLevel > getConfig().PATH_SEARCH_FAST))) --iLevel; } else { // adjust as needed if (!loaded && (iLevel < getConfig().PATH_SEARCH_MAX)) ++iLevel; if (loaded && (iLevel > getConfig().PATH_SEARCH_FAST)) --iLevel; } m_journal.debug << iIdentifier << " processing at level " << iLevel; bool found = false; for (auto const& currIssuer: sourceCurrencies) { { STAmount test ({currIssuer.first, currIssuer.second}, 1); if (m_journal.debug) { m_journal.debug << iIdentifier << " Trying to find paths: " << test.getFullText (); } } bool valid; STPathSet& spsPaths = mContext[currIssuer]; Pathfinder pf (cache, raSrcAccount, raDstAccount, currIssuer.first, currIssuer.second, saDstAmount, valid); CondLog (!valid, lsDEBUG, PathRequest) << iIdentifier << " PF request not valid"; STPath extraPath; if (valid && pf.findPaths (iLevel, 4, spsPaths, extraPath)) { LedgerEntrySet lesSandbox (cache->getLedger (), tapNONE); PathState::List pathStateList; STAmount saMaxAmountAct; STAmount saDstAmountAct; auto& account = currIssuer.second.isNonZero () ? Account(currIssuer.second) : isXRP (currIssuer.first) ? xrpAccount() : raSrcAccount.getAccountID (); STAmount saMaxAmount ({currIssuer.first, account}, 1); saMaxAmount.negate (); m_journal.debug << iIdentifier << " Paths found, calling rippleCalc"; TER resultCode = path::rippleCalculate ( lesSandbox, saMaxAmountAct, saDstAmountAct, pathStateList, saMaxAmount, saDstAmount, raDstAccount.getAccountID (), raSrcAccount.getAccountID (), spsPaths, false, false, false, true); if ((extraPath.size() > 0) && ((resultCode == terNO_LINE) || (resultCode == tecPATH_PARTIAL))) { m_journal.debug << iIdentifier << " Trying with an extra path element"; spsPaths.addPath(extraPath); pathStateList.clear (); resultCode = path::rippleCalculate ( lesSandbox, saMaxAmountAct, saDstAmountAct, pathStateList, saMaxAmount, saDstAmount, raDstAccount.getAccountID (), raSrcAccount.getAccountID (), spsPaths, false, false, false, true); m_journal.debug << iIdentifier << " Extra path element gives " << transHuman (resultCode); } if (resultCode == tesSUCCESS) { Json::Value jvEntry (Json::objectValue); jvEntry["source_amount"] = saMaxAmountAct.getJson (0); jvEntry["paths_computed"] = spsPaths.getJson (0); found = true; jvArray.append (jvEntry); } else { m_journal.debug << iIdentifier << " rippleCalc returns " << transHuman (resultCode); } } else { m_journal.debug << iIdentifier << " No paths found"; } } iLastLevel = iLevel; bLastSuccess = found; if (fast && ptQuickReply.is_not_a_date_time()) { ptQuickReply = boost::posix_time::microsec_clock::universal_time(); mOwner.reportFast ((ptQuickReply-ptCreated).total_milliseconds()); } else if (!fast && ptFullReply.is_not_a_date_time()) { ptFullReply = boost::posix_time::microsec_clock::universal_time(); mOwner.reportFull ((ptFullReply-ptCreated).total_milliseconds()); } jvStatus["alternatives"] = jvArray; return jvStatus; }
static Json::Value signPayment( Json::Value const& params, Json::Value& tx_json, RippleAddress const& raSrcAddressID, Ledger::pointer lSnapshot, int role) { RippleAddress dstAccountID; if (!tx_json.isMember ("Amount")) return RPC::missing_field_error ("tx_json.Amount"); STAmount amount; if (!amount.bSetJson (tx_json ["Amount"])) return RPC::invalid_field_error ("tx_json.Amount"); if (!tx_json.isMember ("Destination")) return RPC::missing_field_error ("tx_json.Destination"); if (!dstAccountID.setAccountID (tx_json["Destination"].asString ())) return RPC::invalid_field_error ("tx_json.Destination"); if (tx_json.isMember ("Paths") && params.isMember ("build_path")) return RPC::make_error (rpcINVALID_PARAMS, "Cannot specify both 'tx_json.Paths' and 'tx_json.build_path'"); if (!tx_json.isMember ("Paths") && tx_json.isMember ("Amount") && params.isMember ("build_path")) { // Need a ripple path. STPathSet spsPaths; uint160 uSrcCurrencyID; uint160 uSrcIssuerID; STAmount saSendMax; if (tx_json.isMember ("SendMax")) { if (!saSendMax.bSetJson (tx_json ["SendMax"])) return RPC::invalid_field_error ("tx_json.SendMax"); } else { // If no SendMax, default to Amount with sender as issuer. saSendMax = amount; saSendMax.setIssuer (raSrcAddressID.getAccountID ()); } if (saSendMax.isNative () && amount.isNative ()) return RPC::make_error (rpcINVALID_PARAMS, "Cannot build STR to STR paths."); { LegacyPathFind lpf (role == Config::ADMIN); if (!lpf.isOk ()) return rpcError (rpcTOO_BUSY); bool bValid; auto cache = boost::make_shared<RippleLineCache> (lSnapshot); Pathfinder pf (cache, raSrcAddressID, dstAccountID, saSendMax.getCurrency (), saSendMax.getIssuer (), amount, bValid); STPath extraPath; if (!bValid || !pf.findPaths (getConfig ().PATH_SEARCH_OLD, 4, spsPaths, extraPath)) { WriteLog (lsDEBUG, RPCHandler) << "transactionSign: build_path: No paths found."; return rpcError (rpcNO_PATH); } WriteLog (lsDEBUG, RPCHandler) << "transactionSign: build_path: " << spsPaths.getJson (0); if (!spsPaths.isEmpty ()) tx_json["Paths"] = spsPaths.getJson (0); } } return Json::Value(); }