From 2268989609301d497699d923d602923c8ef0af4c Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 28 Nov 2012 19:19:39 -0800 Subject: [PATCH] Work toward ripple_path_find. --- src/cpp/ripple/PaymentTransactor.cpp | 2 + src/cpp/ripple/RPCHandler.cpp | 29 +- src/cpp/ripple/RippleCalc.cpp | 483 +++++++++++++++++---------- src/cpp/ripple/RippleCalc.h | 79 ++--- src/cpp/ripple/SerializedTypes.h | 16 +- 5 files changed, 381 insertions(+), 228 deletions(-) diff --git a/src/cpp/ripple/PaymentTransactor.cpp b/src/cpp/ripple/PaymentTransactor.cpp index 81404c24f0..e718d59045 100644 --- a/src/cpp/ripple/PaymentTransactor.cpp +++ b/src/cpp/ripple/PaymentTransactor.cpp @@ -115,6 +115,7 @@ TER PaymentTransactor::doApply() // Ripple payment STPathSet spsPaths = mTxn.getFieldPathSet(sfPaths); + std::vector vpsExpanded; STAmount saMaxAmountAct; STAmount saDstAmountAct; @@ -124,6 +125,7 @@ TER PaymentTransactor::doApply() mEngine->getNodes(), saMaxAmountAct, saDstAmountAct, + vpsExpanded, saMaxAmount, saDstAmount, uDstAccountID, diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 1765efcdf2..cc181caaba 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -779,13 +779,14 @@ Json::Value RPCHandler::doRipplePathFind(const Json::Value& jvRequest) return rpcError(rpcINVALID_PARAMS); } - STPathSet spsPaths; + STPathSet spsComputed; + std::vector vpsExpanded; - Pathfinder pf(raSrc, raDst, uSrcCurrencyID, uSrcIssuerID, saDstAmount); + Pathfinder pf(raSrc, raDst, uSrcCurrencyID, uSrcIssuerID, saDstAmount); - pf.findPaths(5, 1, spsPaths, true); + pf.findPaths(5, 1, spsComputed, true); - if (spsPaths.isEmpty()) + if (spsComputed.isEmpty()) { cLog(lsDEBUG) << "ripple_path_find: No paths found."; } @@ -804,9 +805,9 @@ Json::Value RPCHandler::doRipplePathFind(const Json::Value& jvRequest) saMaxAmount.negate(); // Strip empty/default path. - if (1 == spsPaths.size() && !spsPaths.begin()->size()) + if (1 == spsComputed.size() && !spsComputed.begin()->size()) { - spsPaths.clear(); + spsComputed.clear(); } TER terResult = @@ -814,11 +815,12 @@ Json::Value RPCHandler::doRipplePathFind(const Json::Value& jvRequest) lesSnapshot, saMaxAmountAct, saDstAmountAct, + vpsExpanded, saMaxAmount, // --> Amount to send is unlimited to get an estimate. saDstAmount, // --> Amount to deliver. raDst.getAccountID(), // --> Account to deliver to. raSrc.getAccountID(), // --> Account sending from. - spsPaths, // --> Path set. + spsComputed, // --> Path set. false, // --> Don't allow partial payment. This is for normal fill or kill payments. // Must achive delivery goal. false, // --> Don't limit quality. Average quality is wanted for normal payments. @@ -836,8 +838,13 @@ Json::Value RPCHandler::doRipplePathFind(const Json::Value& jvRequest) { Json::Value jvEntry(Json::objectValue); + STPathSet spsCanonical; + + RippleCalc::setCanonical(spsCanonical, vpsExpanded); + jvEntry["source_amount"] = saMaxAmountAct.getJson(0); - jvEntry["paths_expanded"] = spsPaths.getJson(0); +// jvEntry["paths_expanded"] = spsExpanded.getJson(0); + jvEntry["paths_canonical"] = spsCanonical.getJson(0); jvArray.append(jvEntry); } @@ -852,7 +859,7 @@ Json::Value RPCHandler::doRipplePathFind(const Json::Value& jvRequest) << boost::str(boost::format("ripple_path_find: %s %s %s") % strToken % strHuman - % spsPaths.getJson(0)); + % spsComputed.getJson(0)); } } } @@ -860,6 +867,10 @@ Json::Value RPCHandler::doRipplePathFind(const Json::Value& jvRequest) jvResult["alternatives"] = jvArray; } + cLog(lsDEBUG) + << boost::str(boost::format("ripple_path_find< %s") + % jvResult); + return jvResult; } diff --git a/src/cpp/ripple/RippleCalc.cpp b/src/cpp/ripple/RippleCalc.cpp index 0e077d309d..f730ee3ca0 100644 --- a/src/cpp/ripple/RippleCalc.cpp +++ b/src/cpp/ripple/RippleCalc.cpp @@ -32,17 +32,17 @@ std::size_t hash_value(const aciSource& asValue) // // Return true, iff lhs has less priority than rhs. -bool PathState::lessPriority(PathState::ref lhs, PathState::ref rhs) +bool PathState::lessPriority(PathState& lhs, PathState& rhs) { - if (lhs->uQuality != rhs->uQuality) - return lhs->uQuality > rhs->uQuality; // Bigger is worse. + if (lhs.uQuality != rhs.uQuality) + return lhs.uQuality > rhs.uQuality; // Bigger is worse. // Best quanity is second rank. - if (lhs->saOutPass != rhs->saOutPass) - return lhs->saOutPass < rhs->saOutPass; // Smaller is worse. + if (lhs.saOutPass != rhs.saOutPass) + return lhs.saOutPass < rhs.saOutPass; // Smaller is worse. // Path index is third rank. - return lhs->mIndex > rhs->mIndex; // Bigger is worse. + return lhs.mIndex > rhs.mIndex; // Bigger is worse. } // Make sure last path node delivers to uAccountID: uCurrencyID from uIssuerID. @@ -420,7 +420,7 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: receiver implied: account= } } - cLog(lsINFO) << boost::str(boost::format("PathState: in=%s/%s out=%s/%s %s") + cLog(lsDEBUG) << boost::str(boost::format("PathState: in=%s/%s out=%s/%s %s") % STAmount::createHumanCurrency(uMaxCurrencyID) % RippleAddress::createHumanAccountID(uMaxIssuerID) % STAmount::createHumanCurrency(uOutCurrencyID) @@ -429,10 +429,159 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: receiver implied: account= } void PathState::setCanonical( - PathState::ref pspExpanded + const PathState& psExpanded ) { - ; + saInAct = psExpanded.saInAct; + saOutAct = psExpanded.saOutAct; + + const uint160 uMaxCurrencyID = saInAct.getCurrency(); + const uint160 uMaxIssuerID = saInAct.getIssuer(); + + const uint160 uOutCurrencyID = saOutAct.getCurrency(); + const uint160 uOutIssuerID = saOutAct.getIssuer(); + + unsigned int uNode = 0; + + unsigned int uEnd = psExpanded.vpnNodes.size(); // The node, indexed by 0, not to include. + + uint160 uDstAccountID = psExpanded.vpnNodes[uEnd].uAccountID; + + uint160 uAccountID = psExpanded.vpnNodes[0].uAccountID; + uint160 uCurrencyID = uMaxCurrencyID; + uint160 uIssuerID = uMaxIssuerID; + + // Node 0 is a composit of the sending account and saInAct. + ++uNode; // skip node 0 + + // Last node is implied: Always skip last node + --uEnd; // skip last node + + // saInAct + // - currency is always the same as vpnNodes[0]. + if (uMaxIssuerID != uAccountID); + { + // saInAct issuer is not the sender. This forces an implied node. + + // skip node 1 + + uIssuerID = psExpanded.vpnNodes[uNode].uIssuerID; + + ++uNode; + } + + if (uNode != uEnd && !!uOutCurrencyID && uOutIssuerID != uDstAccountID) + { + // The next to last node is saOutAct if an issuer different from receiver is supplied. + // The next to last node can be implied. + + --uEnd; + } + + const PaymentNode& pnEnd = psExpanded.vpnNodes[uEnd]; + + if (uNode != uEnd + && !pnEnd.uAccountID && pnEnd.uCurrencyID == uOutCurrencyID && pnEnd.uIssuerID == uOutIssuerID) + { + // The current end node is an offer converting to saOutAct's currency and issuer and can be implied. + --uEnd; + } + + // Do not include uEnd. + for (; uNode != uEnd; ++uNode) + { + const PaymentNode& pnPrv = psExpanded.vpnNodes[uNode-1]; + const PaymentNode& pnCur = psExpanded.vpnNodes[uNode]; + const PaymentNode& pnNxt = psExpanded.vpnNodes[uNode+1]; + + const bool bPrvAccount = isSetBit(pnPrv.uFlags, STPathElement::typeAccount); + const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); + const bool bNxtAccount = isSetBit(pnNxt.uFlags, STPathElement::typeAccount); + + bool bSkip = false; + + if (bCurAccount) + { + // Currently at an account. + + if (!!pnCur.uCurrencyID && pnCur.uIssuerID == pnCur.uAccountID) + { + // Account issues itself. + + bSkip = true; + } + } + else + { + // Currently at an offer. + + if (bPrvAccount && bNxtAccount // Offer surrounded by accounts. + && pnPrv.uCurrencyID != pnNxt.uCurrencyID) + { + // Offer can be implied by currenct change. + + bSkip = true; + } + } + + if (!bSkip) + { + // Copy node + PaymentNode pnNew; + + bool bSetAccount = bCurAccount; + bool bSetCurrency = uCurrencyID != pnCur.uCurrencyID; + bool bSetIssuer = !uCurrencyID && uIssuerID != pnCur.uIssuerID; + + pnNew.uFlags = (bSetAccount ? STPathElement::typeAccount : 0) + | (bSetCurrency ? STPathElement::typeCurrency : 0) + | (bSetIssuer ? STPathElement::typeIssuer : 0); + + if (bSetAccount) + pnNew.uAccountID = pnCur.uAccountID; + + if (bSetCurrency) + { + pnNew.uCurrencyID = pnCur.uCurrencyID; + uCurrencyID = pnNew.uCurrencyID; + } + + if (bSetIssuer) + pnNew.uIssuerID = pnCur.uIssuerID; + + if (bSetCurrency && !uCurrencyID) + uIssuerID.zero(); + + vpnNodes.push_back(pnNew); + } + } + + cLog(lsDEBUG) << boost::str(boost::format("setCanonical: in=%s/%s out=%s/%s %s") + % STAmount::createHumanCurrency(uMaxCurrencyID) + % RippleAddress::createHumanAccountID(uMaxIssuerID) + % STAmount::createHumanCurrency(uOutCurrencyID) + % RippleAddress::createHumanAccountID(uOutIssuerID) + % getJson()); +} + +void RippleCalc::setCanonical(STPathSet& spsDst, const std::vector& vpsExpanded) +{ + BOOST_FOREACH(PathState::ref pspExpanded, vpsExpanded) + { + PathState psCanonical(*pspExpanded, false); + + psCanonical.setCanonical(*pspExpanded); + + STPath spCanonical; + + BOOST_FOREACH(const PaymentNode& pnElem, psCanonical.vpnNodes) + { + STPathElement speElem(pnElem.uFlags, pnElem.uAccountID, pnElem.uCurrencyID, pnElem.uIssuerID); + spCanonical.addElement(speElem); + } + + spsDst.addPath(spCanonical); + } } Json::Value PathState::getJson() const @@ -460,22 +609,22 @@ Json::Value PathState::getJson() const if (!!pnNode.uIssuerID) jvNode["issuer"] = RippleAddress::createHumanAccountID(pnNode.uIssuerID); - // if (pnNode.saRevRedeem) + if (pnNode.saRevRedeem) jvNode["rev_redeem"] = pnNode.saRevRedeem.getFullText(); - // if (pnNode.saRevIssue) + if (pnNode.saRevIssue) jvNode["rev_issue"] = pnNode.saRevIssue.getFullText(); - // if (pnNode.saRevDeliver) + if (pnNode.saRevDeliver) jvNode["rev_deliver"] = pnNode.saRevDeliver.getFullText(); - // if (pnNode.saFwdRedeem) + if (pnNode.saFwdRedeem) jvNode["fwd_redeem"] = pnNode.saFwdRedeem.getFullText(); - // if (pnNode.saFwdIssue) + if (pnNode.saFwdIssue) jvNode["fwd_issue"] = pnNode.saFwdIssue.getFullText(); - // if (pnNode.saFwdDeliver) + if (pnNode.saFwdDeliver) jvNode["fwd_deliver"] = pnNode.saFwdDeliver.getFullText(); jvNodes.append(jvNode); @@ -519,12 +668,12 @@ Json::Value PathState::getJson() const // <-- uOfferIndex : 0=end of list. TER RippleCalc::calcNodeAdvance( const unsigned int uNode, // 0 < uNode < uLast - PathState::ref pspCur, + PathState& psCur, const bool bMultiQuality, const bool bReverse) { - PaymentNode& pnPrv = pspCur->vpnNodes[uNode-1]; - PaymentNode& pnCur = pspCur->vpnNodes[uNode]; + PaymentNode& pnPrv = psCur.vpnNodes[uNode-1]; + PaymentNode& pnCur = psCur.vpnNodes[uNode]; const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; const uint160& uPrvIssuerID = pnPrv.uIssuerID; @@ -668,8 +817,8 @@ TER RippleCalc::calcNodeAdvance( // XXX This can get called multiple times for same source in a row, caching result would be nice. // XXX Going forward could we fund something with a worse quality which was previously skipped? Might need to check // quality. - curIssuerNodeConstIterator itForward = pspCur->umForward.find(asLine); - const bool bFoundForward = itForward != pspCur->umForward.end(); + curIssuerNodeConstIterator itForward = psCur.umForward.find(asLine); + const bool bFoundForward = itForward != psCur.umForward.end(); if (bFoundForward && itForward->second != uNode) { @@ -692,8 +841,8 @@ TER RippleCalc::calcNodeAdvance( continue; } - curIssuerNodeConstIterator itReverse = pspCur->umReverse.find(asLine); - bool bFoundReverse = itReverse != pspCur->umReverse.end(); + curIssuerNodeConstIterator itReverse = psCur.umReverse.find(asLine); + bool bFoundReverse = itReverse != psCur.umReverse.end(); if (bFoundReverse && itReverse->second != uNode) { @@ -735,7 +884,7 @@ TER RippleCalc::calcNodeAdvance( % STAmount::createHumanCurrency(uCurCurrencyID) % RippleAddress::createHumanAccountID(uCurIssuerID)); - pspCur->umReverse.insert(std::make_pair(asLine, uNode)); + psCur.umReverse.insert(std::make_pair(asLine, uNode)); } bFundsDirty = false; @@ -761,7 +910,7 @@ TER RippleCalc::calcNodeAdvance( // till request is satisified while we the rate does not increase past the initial rate. TER RippleCalc::calcNodeDeliverRev( const unsigned int uNode, // 0 < uNode < uLast - PathState::ref pspCur, + PathState& psCur, const bool bMultiQuality, const uint160& uOutAccountID, // --> Output owner's account. const STAmount& saOutReq, // --> Funds wanted. @@ -769,8 +918,8 @@ TER RippleCalc::calcNodeDeliverRev( { TER terResult = tesSUCCESS; - PaymentNode& pnPrv = pspCur->vpnNodes[uNode-1]; - PaymentNode& pnCur = pspCur->vpnNodes[uNode]; + PaymentNode& pnPrv = psCur.vpnNodes[uNode-1]; + PaymentNode& pnCur = psCur.vpnNodes[uNode]; const uint160& uCurIssuerID = pnCur.uIssuerID; const uint160& uPrvAccountID = pnPrv.uAccountID; @@ -802,7 +951,7 @@ TER RippleCalc::calcNodeDeliverRev( STAmount& saTakerGets = pnCur.saTakerGets; STAmount& saRateMax = pnCur.saRateMax; - terResult = calcNodeAdvance(uNode, pspCur, bMultiQuality, true); // If needed, advance to next funded offer. + terResult = calcNodeAdvance(uNode, psCur, bMultiQuality, true); // If needed, advance to next funded offer. if (tesSUCCESS != terResult || !uOfferIndex) { @@ -908,7 +1057,7 @@ TER RippleCalc::calcNodeDeliverRev( terResult = calcNodeDeliverRev( uNode-1, - pspCur, + psCur, bMultiQuality, uOfrOwnerID, saInPassReq, @@ -969,7 +1118,7 @@ TER RippleCalc::calcNodeDeliverRev( // <-- pnCur.saFwdDeliver: For calcNodeAccountFwd to know how much went through TER RippleCalc::calcNodeDeliverFwd( const unsigned int uNode, // 0 < uNode < uLast - PathState::ref pspCur, + PathState& psCur, const bool bMultiQuality, const uint160& uInAccountID, // --> Input owner's account. const STAmount& saInReq, // --> Amount to deliver. @@ -978,9 +1127,9 @@ TER RippleCalc::calcNodeDeliverFwd( { TER terResult = tesSUCCESS; - PaymentNode& pnPrv = pspCur->vpnNodes[uNode-1]; - PaymentNode& pnCur = pspCur->vpnNodes[uNode]; - PaymentNode& pnNxt = pspCur->vpnNodes[uNode+1]; + PaymentNode& pnPrv = psCur.vpnNodes[uNode-1]; + PaymentNode& pnCur = psCur.vpnNodes[uNode]; + PaymentNode& pnNxt = psCur.vpnNodes[uNode+1]; const uint160& uNxtAccountID = pnNxt.uAccountID; const uint160& uCurCurrencyID = pnCur.uCurrencyID; @@ -1002,7 +1151,7 @@ TER RippleCalc::calcNodeDeliverFwd( && saInAct + saInFees != saInReq) // Did not deliver all funds. { // Determine values for pass to adjust saInAct, saInFees, and saCurDeliverAct - terResult = calcNodeAdvance(uNode, pspCur, bMultiQuality, false); // If needed, advance to next funded offer. + terResult = calcNodeAdvance(uNode, psCur, bMultiQuality, false); // If needed, advance to next funded offer. if (tesSUCCESS == terResult) { @@ -1079,7 +1228,7 @@ TER RippleCalc::calcNodeDeliverFwd( // Therefore, immediately push through output for current offer. terResult = RippleCalc::calcNodeDeliverFwd( uNode+1, - pspCur, + psCur, bMultiQuality, uOfrOwnerID, // --> Current holder. saOutPassMax, // --> Amount available. @@ -1138,7 +1287,7 @@ TER RippleCalc::calcNodeDeliverFwd( if (saOutPassAct == saOutFunded) { // Offer became unfunded. - pspCur->vUnfundedBecame.push_back(uOfferIndex); + psCur.vUnfundedBecame.push_back(uOfferIndex); bEntryAdvance = true; } @@ -1161,13 +1310,13 @@ TER RippleCalc::calcNodeDeliverFwd( // Called to drive from the last offer node in a chain. TER RippleCalc::calcNodeOfferRev( const unsigned int uNode, // 0 < uNode < uLast - PathState::ref pspCur, + PathState& psCur, const bool bMultiQuality) { TER terResult; - PaymentNode& pnCur = pspCur->vpnNodes[uNode]; - PaymentNode& pnNxt = pspCur->vpnNodes[uNode+1]; + PaymentNode& pnCur = psCur.vpnNodes[uNode]; + PaymentNode& pnNxt = psCur.vpnNodes[uNode+1]; if (!!pnNxt.uAccountID) { @@ -1176,7 +1325,7 @@ TER RippleCalc::calcNodeOfferRev( terResult = calcNodeDeliverRev( uNode, - pspCur, + psCur, bMultiQuality, pnNxt.uAccountID, @@ -1201,12 +1350,12 @@ TER RippleCalc::calcNodeOfferRev( // - Deliver is set without transfer fees. TER RippleCalc::calcNodeOfferFwd( const unsigned int uNode, // 0 < uNode < uLast - PathState::ref pspCur, + PathState& psCur, const bool bMultiQuality ) { TER terResult; - PaymentNode& pnPrv = pspCur->vpnNodes[uNode-1]; + PaymentNode& pnPrv = psCur.vpnNodes[uNode-1]; if (!!pnPrv.uAccountID) { @@ -1216,7 +1365,7 @@ TER RippleCalc::calcNodeOfferFwd( terResult = calcNodeDeliverFwd( uNode, - pspCur, + psCur, bMultiQuality, pnPrv.uAccountID, pnPrv.saFwdDeliver, // Previous is sending this much. @@ -1353,16 +1502,16 @@ void RippleCalc::calcNodeRipple( // Issues are limited based on credit limits and amount owed. // No account balance adjustments as we don't know how much is going to actually be pushed through yet. // <-- tesSUCCESS or tepPATH_DRY -TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality) +TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState& psCur, const bool bMultiQuality) { TER terResult = tesSUCCESS; - const unsigned int uLast = pspCur->vpnNodes.size() - 1; + const unsigned int uLast = psCur.vpnNodes.size() - 1; uint64 uRateMax = 0; - PaymentNode& pnPrv = pspCur->vpnNodes[uNode ? uNode-1 : 0]; - PaymentNode& pnCur = pspCur->vpnNodes[uNode]; - PaymentNode& pnNxt = pspCur->vpnNodes[uNode == uLast ? uLast : uNode+1]; + PaymentNode& pnPrv = psCur.vpnNodes[uNode ? uNode-1 : 0]; + PaymentNode& pnCur = psCur.vpnNodes[uNode]; + PaymentNode& pnNxt = psCur.vpnNodes[uNode == uLast ? uLast : uNode+1]; // Current is allowed to redeem to next. const bool bPrvAccount = !uNode || isSetBit(pnPrv.uFlags, STPathElement::typeAccount); @@ -1433,7 +1582,7 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState::ref pspC % saCurIssueReq.getFullText() % saNxtOwed.getFullText()); - cLog(lsINFO) << pspCur->getJson(); + cLog(lsINFO) << psCur.getJson(); assert(!saCurRedeemReq || (-saNxtOwed) >= saCurRedeemReq); // Current redeem req can't be more than IOUs on hand. assert(!saCurIssueReq // If not issuing, fine. @@ -1454,8 +1603,8 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState::ref pspC // account --> ACCOUNT --> $ // Overall deliverable. const STAmount& saCurWantedReq = bPrvAccount - ? std::min(pspCur->saOutReq-pspCur->saOutAct, saPrvLimit+saPrvOwed) // If previous is an account, limit. - : pspCur->saOutReq-pspCur->saOutAct; // Previous is an offer, no limit: redeem own IOUs. + ? std::min(psCur.saOutReq-psCur.saOutAct, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : psCur.saOutReq-psCur.saOutAct; // Previous is an offer, no limit: redeem own IOUs. STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $ : saCurWantedReq=%s") @@ -1618,8 +1767,8 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState::ref pspC { // offer --> ACCOUNT --> $ const STAmount& saCurWantedReq = bPrvAccount - ? std::min(pspCur->saOutReq-pspCur->saOutAct, saPrvLimit+saPrvOwed) // If previous is an account, limit. - : pspCur->saOutReq-pspCur->saOutAct; // Previous is an offer, no limit: redeem own IOUs. + ? std::min(psCur.saOutReq-psCur.saOutAct, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : psCur.saOutReq-psCur.saOutAct; // Previous is an offer, no limit: redeem own IOUs. STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); cLog(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $ : saCurWantedReq=%s") @@ -1702,17 +1851,17 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState::ref pspC // - If next node is an offer and output is XRP then we need to deliver funds to limbo. TER RippleCalc::calcNodeAccountFwd( const unsigned int uNode, // 0 <= uNode <= uLast - PathState::ref pspCur, + PathState& psCur, const bool bMultiQuality) { TER terResult = tesSUCCESS; - const unsigned int uLast = pspCur->vpnNodes.size() - 1; + const unsigned int uLast = psCur.vpnNodes.size() - 1; uint64 uRateMax = 0; - PaymentNode& pnPrv = pspCur->vpnNodes[uNode ? uNode-1 : 0]; - PaymentNode& pnCur = pspCur->vpnNodes[uNode]; - PaymentNode& pnNxt = pspCur->vpnNodes[uNode == uLast ? uLast : uNode+1]; + PaymentNode& pnPrv = psCur.vpnNodes[uNode ? uNode-1 : 0]; + PaymentNode& pnCur = psCur.vpnNodes[uNode]; + PaymentNode& pnNxt = psCur.vpnNodes[uNode == uLast ? uLast : uNode+1]; const bool bPrvAccount = isSetBit(pnPrv.uFlags, STPathElement::typeAccount); const bool bNxtAccount = isSetBit(pnNxt.uFlags, STPathElement::typeAccount); @@ -1754,7 +1903,7 @@ TER RippleCalc::calcNodeAccountFwd( STAmount& saCurDeliverAct = pnCur.saFwdDeliver; // For !uNode - STAmount& saCurSendMaxPass = pspCur->saInPass; // Report how much pass sends. + STAmount& saCurSendMaxPass = psCur.saInPass; // Report how much pass sends. cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uNode=%d/%d saPrvRedeemReq=%s saPrvIssueReq=%s saPrvDeliverReq=%s saCurRedeemReq=%s saCurIssueReq=%s saCurDeliverReq=%s") % uNode @@ -1780,10 +1929,10 @@ TER RippleCalc::calcNodeAccountFwd( saCurRedeemAct = saCurRedeemReq; - if (!pspCur->saInReq.isNegative()) + if (!psCur.saInReq.isNegative()) { // Limit by send max. - saCurRedeemAct = std::min(saCurRedeemAct, pspCur->saInReq-pspCur->saInAct); + saCurRedeemAct = std::min(saCurRedeemAct, psCur.saInReq-psCur.saInAct); } saCurSendMaxPass = saCurRedeemAct; @@ -1792,17 +1941,17 @@ TER RippleCalc::calcNodeAccountFwd( ? saCurIssueReq : STAmount(saCurIssueReq); - if (!!saCurIssueAct && !pspCur->saInReq.isNegative()) + if (!!saCurIssueAct && !psCur.saInReq.isNegative()) { // Limit by send max. - saCurIssueAct = std::min(saCurIssueAct, pspCur->saInReq-pspCur->saInAct-saCurRedeemAct); + saCurIssueAct = std::min(saCurIssueAct, psCur.saInReq-psCur.saInAct-saCurRedeemAct); } saCurSendMaxPass += saCurIssueAct; cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saInReq=%s saInAct=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s saCurSendMaxPass=%s") - % pspCur->saInReq.getFullText() - % pspCur->saInAct.getFullText() + % psCur.saInReq.getFullText() + % psCur.saInAct.getFullText() % saCurRedeemAct.getFullText() % saCurIssueReq.getFullText() % saCurIssueAct.getFullText() @@ -1819,7 +1968,7 @@ TER RippleCalc::calcNodeAccountFwd( // Last node. Accept all funds. Calculate amount actually to credit. - STAmount& saCurReceive = pspCur->saOutPass; + STAmount& saCurReceive = psCur.saOutPass; STAmount saIssueCrd = uQualityIn >= QUALITY_ONE ? saPrvIssueReq // No fee. @@ -1916,10 +2065,10 @@ TER RippleCalc::calcNodeAccountFwd( saCurDeliverAct = saCurDeliverReq; // If limited, then limit by send max and available. - if (!pspCur->saInReq.isNegative()) + if (!psCur.saInReq.isNegative()) { // Limit by send max. - saCurDeliverAct = std::min(saCurDeliverAct, pspCur->saInReq-pspCur->saInAct); + saCurDeliverAct = std::min(saCurDeliverAct, psCur.saInReq-psCur.saInAct); // Limit XRP by available. No limit for non-XRP as issuer. if (!uCurAccountID) @@ -1956,7 +2105,7 @@ TER RippleCalc::calcNodeAccountFwd( // offer --> ACCOUNT --> $ cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $ : %s") % saPrvDeliverReq.getFullText()); - STAmount& saCurReceive = pspCur->saOutPass; + STAmount& saCurReceive = psCur.saOutPass; // Amount to credit. saCurReceive = saPrvDeliverReq; @@ -2012,20 +2161,20 @@ TER RippleCalc::calcNodeAccountFwd( return terResult; } -TER RippleCalc::calcNodeFwd(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality) +TER RippleCalc::calcNodeFwd(const unsigned int uNode, PathState& psCur, const bool bMultiQuality) { - const PaymentNode& pnCur = pspCur->vpnNodes[uNode]; + const PaymentNode& pnCur = psCur.vpnNodes[uNode]; const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); cLog(lsINFO) << boost::str(boost::format("calcNodeFwd> uNode=%d") % uNode); TER terResult = bCurAccount - ? calcNodeAccountFwd(uNode, pspCur, bMultiQuality) - : calcNodeOfferFwd(uNode, pspCur, bMultiQuality); + ? calcNodeAccountFwd(uNode, psCur, bMultiQuality) + : calcNodeOfferFwd(uNode, psCur, bMultiQuality); - if (tesSUCCESS == terResult && uNode + 1 != pspCur->vpnNodes.size()) + if (tesSUCCESS == terResult && uNode + 1 != psCur.vpnNodes.size()) { - terResult = calcNodeFwd(uNode+1, pspCur, bMultiQuality); + terResult = calcNodeFwd(uNode+1, psCur, bMultiQuality); } cLog(lsINFO) << boost::str(boost::format("calcNodeFwd< uNode=%d terResult=%d") % uNode % terResult); @@ -2042,9 +2191,9 @@ TER RippleCalc::calcNodeFwd(const unsigned int uNode, PathState::ref pspCur, con // --> [all]saWanted.mCurrency // --> [all]saAccount // <-> [0]saWanted.mAmount : --> limit, <-- actual -TER RippleCalc::calcNodeRev(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality) +TER RippleCalc::calcNodeRev(const unsigned int uNode, PathState& psCur, const bool bMultiQuality) { - PaymentNode& pnCur = pspCur->vpnNodes[uNode]; + PaymentNode& pnCur = psCur.vpnNodes[uNode]; const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); TER terResult; @@ -2060,8 +2209,8 @@ TER RippleCalc::calcNodeRev(const unsigned int uNode, PathState::ref pspCur, con % saTransferRate.getFullText()); terResult = bCurAccount - ? calcNodeAccountRev(uNode, pspCur, bMultiQuality) - : calcNodeOfferRev(uNode, pspCur, bMultiQuality); + ? calcNodeAccountRev(uNode, psCur, bMultiQuality) + : calcNodeOfferRev(uNode, psCur, bMultiQuality); // Do previous. if (tesSUCCESS != terResult) @@ -2073,7 +2222,7 @@ TER RippleCalc::calcNodeRev(const unsigned int uNode, PathState::ref pspCur, con { // Continue in reverse. - terResult = calcNodeRev(uNode-1, pspCur, bMultiQuality); + terResult = calcNodeRev(uNode-1, psCur, bMultiQuality); } cLog(lsINFO) << boost::str(boost::format("calcNodeRev< uNode=%d terResult=%s/%d") % uNode % transToken(terResult) % terResult); @@ -2083,68 +2232,68 @@ TER RippleCalc::calcNodeRev(const unsigned int uNode, PathState::ref pspCur, con // Calculate the next increment of a path. // The increment is what can satisfy a portion or all of the requested output at the best quality. -// <-- pspCur->uQuality -void RippleCalc::pathNext(PathState::ref pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent) +// <-- psCur.uQuality +void RippleCalc::pathNext(PathState& psCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent) { // The next state is what is available in preference order. // This is calculated when referenced accounts changed. const bool bMultiQuality = iPaths == 1; - const unsigned int uLast = pspCur->vpnNodes.size() - 1; + const unsigned int uLast = psCur.vpnNodes.size() - 1; - pspCur->bConsumed = false; + psCur.bConsumed = false; // YYY This clearing should only be needed for nice logging. - pspCur->saInPass = STAmount(pspCur->saInReq.getCurrency(), pspCur->saInReq.getIssuer()); - pspCur->saOutPass = STAmount(pspCur->saOutReq.getCurrency(), pspCur->saOutReq.getIssuer()); + psCur.saInPass = STAmount(psCur.saInReq.getCurrency(), psCur.saInReq.getIssuer()); + psCur.saOutPass = STAmount(psCur.saOutReq.getCurrency(), psCur.saOutReq.getIssuer()); - pspCur->vUnfundedBecame.clear(); - pspCur->umReverse.clear(); + psCur.vUnfundedBecame.clear(); + psCur.umReverse.clear(); - cLog(lsINFO) << "Path In: " << pspCur->getJson(); + cLog(lsINFO) << "Path In: " << psCur.getJson(); - assert(pspCur->vpnNodes.size() >= 2); + assert(psCur.vpnNodes.size() >= 2); lesCurrent = lesCheckpoint; // Restore from checkpoint. lesCurrent.bumpSeq(); // Begin ledger varance. - pspCur->terStatus = calcNodeRev(uLast, pspCur, bMultiQuality); + psCur.terStatus = calcNodeRev(uLast, psCur, bMultiQuality); - cLog(lsINFO) << "Path after reverse: " << pspCur->getJson(); + cLog(lsINFO) << "Path after reverse: " << psCur.getJson(); - if (tesSUCCESS == pspCur->terStatus) + if (tesSUCCESS == psCur.terStatus) { // Do forward. lesCurrent = lesCheckpoint; // Restore from checkpoint. lesCurrent.bumpSeq(); // Begin ledger varance. - pspCur->terStatus = calcNodeFwd(0, pspCur, bMultiQuality); + psCur.terStatus = calcNodeFwd(0, psCur, bMultiQuality); } - if (tesSUCCESS == pspCur->terStatus) + if (tesSUCCESS == psCur.terStatus) { - tLog(!pspCur->saInPass || !pspCur->saOutPass, lsDEBUG) + tLog(!psCur.saInPass || !psCur.saOutPass, lsDEBUG) << boost::str(boost::format("saOutPass=%s saInPass=%s") - % pspCur->saOutPass.getFullText() - % pspCur->saInPass.getFullText()); + % psCur.saOutPass.getFullText() + % psCur.saInPass.getFullText()); - assert(!!pspCur->saOutPass && !!pspCur->saInPass); + assert(!!psCur.saOutPass && !!psCur.saInPass); - pspCur->uQuality = STAmount::getRate(pspCur->saOutPass, pspCur->saInPass); // Calculate relative quality. + psCur.uQuality = STAmount::getRate(psCur.saOutPass, psCur.saInPass); // Calculate relative quality. - cLog(lsINFO) << "Path after forward: " << pspCur->getJson(); + cLog(lsINFO) << "Path after forward: " << psCur.getJson(); } else { - pspCur->uQuality = 0; + psCur.uQuality = 0; } } TER RippleCalc::rippleCalc( // Compute paths vs this ledger entry set. Up to caller to actually apply to ledger. - LedgerEntrySet& lesActive, // <-> --> = Fee already applied to src balance. - STAmount& saMaxAmountAct, // <-- The computed input amount. - STAmount& saDstAmountAct, // <-- The computed output amount. - + LedgerEntrySet& lesActive, // <-> --> = Fee already applied to src balance. + STAmount& saMaxAmountAct, // <-- The computed input amount. + STAmount& saDstAmountAct, // <-- The computed output amount. + std::vector& vpsExpanded, // Issuer: // XRP: ACCOUNT_XRP // non-XRP: uSrcAccountID (for any issuer) or another account with trust node. @@ -2178,44 +2327,38 @@ TER RippleCalc::rippleCalc( } // Incrementally search paths. - std::vector vpsPaths; if (!bNoRippleDirect) { // Direct path. // XXX Might also make a XRP bridge by default. - PathState::pointer pspDirect = PathState::createExpanded( - lesActive, - STPath(), - uDstAccountID, - uSrcAccountID, - saDstAmountReq, - saMaxAmountReq); + PathState::pointer pspDirect = boost::make_shared(saDstAmountReq, saMaxAmountReq, lesActive.getLedgerRef()); - pspDirect->setIndex(vpsPaths.size()); + if (!pspDirect) + return temUNKNOWN; -cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Build direct: add: %d status: %s") - % !!pspDirect - % transToken(pspDirect ? pspDirect->terStatus : temUNKNOWN)); - if (pspDirect) - { - // Return if malformed. - if (isTemMalformed(pspDirect->terStatus)) - return pspDirect->terStatus; + pspDirect->setExpanded(lesActive, STPath(), uDstAccountID, uSrcAccountID); - if (tesSUCCESS == pspDirect->terStatus) - { - // Had a success. - terResult = tesSUCCESS; + pspDirect->setIndex(vpsExpanded.size()); - vpsPaths.push_back(pspDirect); - } - else if (terNO_LINE != pspDirect->terStatus) - { - terResult = pspDirect->terStatus; - } - } +cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Build direct: status: %s") + % transToken(pspDirect->terStatus)); + // Return if malformed. + if (isTemMalformed(pspDirect->terStatus)) + return pspDirect->terStatus; + + if (tesSUCCESS == pspDirect->terStatus) + { + // Had a success. + terResult = tesSUCCESS; + + vpsExpanded.push_back(pspDirect); + } + else if (terNO_LINE != pspDirect->terStatus) + { + terResult = pspDirect->terStatus; + } } cLog(lsINFO) << "rippleCalc: Paths in set: " << spsPaths.size(); @@ -2223,37 +2366,32 @@ cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Build direct: add: %d sta int iIndex = 0; BOOST_FOREACH(const STPath& spPath, spsPaths) { - PathState::pointer pspExpanded = PathState::createExpanded( - lesActive, - spPath, - uDstAccountID, - uSrcAccountID, - saDstAmountReq, - saMaxAmountReq); + PathState::pointer pspExpanded = boost::make_shared(saDstAmountReq, saMaxAmountReq, lesActive.getLedgerRef()); -cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Build path: %d: add: %d status: %s") + if (!pspExpanded) + return temUNKNOWN; + + pspExpanded->setExpanded(lesActive, spPath, uDstAccountID, uSrcAccountID); + +cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Build path: %d: status: %s") % ++iIndex - % !!pspExpanded - % transToken(pspExpanded ? pspExpanded->terStatus : temUNKNOWN)); + % transToken(pspExpanded->terStatus)); - if (pspExpanded) - { - // Return, if the path specification was malformed. - if (isTemMalformed(pspExpanded->terStatus)) - return pspExpanded->terStatus; + // Return, if the path specification was malformed. + if (isTemMalformed(pspExpanded->terStatus)) + return pspExpanded->terStatus; - if (tesSUCCESS == pspExpanded->terStatus) { - terResult = tesSUCCESS; // Had a success. + if (tesSUCCESS == pspExpanded->terStatus) { + terResult = tesSUCCESS; // Had a success. - pspExpanded->setIndex(vpsPaths.size()); + pspExpanded->setIndex(vpsExpanded.size()); - vpsPaths.push_back(pspExpanded); - } - else if (terNO_LINE != pspExpanded->terStatus) - { - terResult = pspExpanded->terStatus; - } - } + vpsExpanded.push_back(pspExpanded); + } + else if (terNO_LINE != pspExpanded->terStatus) + { + terResult = pspExpanded->terStatus; + } } if (tesSUCCESS != terResult) @@ -2276,19 +2414,19 @@ cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Build path: %d: add: %d s int iPass = 0; while (temUNCERTAIN == terResult) { - PathState::pointer pspBest; + int iBest = -1; const LedgerEntrySet lesCheckpoint = lesActive; int iDry = 0; // Find the best path. - BOOST_FOREACH(PathState::pointer& pspCur, vpsPaths) + BOOST_FOREACH(PathState::pointer pspCur, vpsExpanded) { if (pspCur->uQuality) { - pspCur->saInAct = saMaxAmountAct; // Update to current amount processed. + pspCur->saInAct = saMaxAmountAct; // Update to current amount processed. pspCur->saOutAct = saDstAmountAct; - rc.pathNext(pspCur, vpsPaths.size(), lesCheckpoint, lesActive); // Compute increment. + rc.pathNext(*pspCur, vpsExpanded.size(), lesCheckpoint, lesActive); // Compute increment. if (!pspCur->uQuality) { // Path was dry. @@ -2304,9 +2442,9 @@ int iPass = 0; assert(!!pspCur->saInPass && !!pspCur->saOutPass); - if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality. - && (!pspBest // Best is not yet set. - || PathState::lessPriority(pspBest, pspCur))) // Current is better than set. + if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality. + && (iBest < 0 // Best is not yet set. + || PathState::lessPriority(*vpsExpanded[iBest], *pspCur))) // Current is better than set. { cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: better: uQuality=%s saInPass=%s saOutPass=%s") % STAmount::saFromRate(pspCur->uQuality) @@ -2314,20 +2452,21 @@ int iPass = 0; % pspCur->saOutPass.getFullText()); lesActive.swapWith(pspCur->lesEntries); // For the path, save ledger state. - pspBest = pspCur; + iBest = pspCur->getIndex(); } } } } -cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Summary: Pass: %d Dry: %d Paths: %d") % ++iPass % iDry % vpsPaths.size()); - BOOST_FOREACH(PathState::pointer& pspCur, vpsPaths) +cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Summary: Pass: %d Dry: %d Paths: %d") % ++iPass % iDry % vpsExpanded.size()); + BOOST_FOREACH(PathState::ref pspCur, vpsExpanded) { -cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Summary: %d quality:%d best: %d consumed: %d") % pspCur->mIndex % pspCur->uQuality % (pspBest == pspCur) % pspCur->bConsumed); +cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Summary: %d quality:%d best: %d consumed: %d") % pspCur->mIndex % pspCur->uQuality % (iBest == pspCur->getIndex()) % pspCur->bConsumed); } - if (pspBest) + if (iBest >= 0) { // Apply best path. + PathState::pointer pspBest = vpsExpanded[iBest]; cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: best: uQuality=%s saInPass=%s saOutPass=%s") % STAmount::saFromRate(pspBest->uQuality) @@ -2340,7 +2479,7 @@ cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Summary: %d quality:%d be // Record best pass' LedgerEntrySet to build off of and potentially return. lesActive.swapWith(pspBest->lesEntries); - saMaxAmountAct += pspBest->saInPass; + saMaxAmountAct += pspBest->saInPass; saDstAmountAct += pspBest->saOutPass; if (pspBest->bConsumed) @@ -2355,7 +2494,7 @@ cLog(lsDEBUG) << boost::str(boost::format("rippleCalc: Summary: %d quality:%d be terResult = tesSUCCESS; } - else if (saMaxAmountAct != saMaxAmountReq && iDry != vpsPaths.size()) + else if (saMaxAmountAct != saMaxAmountReq && iDry != vpsExpanded.size()) { // Have not met requested amount or max send, try to do more. Prepare for next pass. diff --git a/src/cpp/ripple/RippleCalc.h b/src/cpp/ripple/RippleCalc.h index a816dd4c37..c8abb2fc71 100644 --- a/src/cpp/ripple/RippleCalc.h +++ b/src/cpp/ripple/RippleCalc.h @@ -107,12 +107,17 @@ public: return this; } + int getIndex() { return mIndex; }; + PathState( const STAmount& saSend, const STAmount& saSendMax, const Ledger::ref lrLedger = Ledger::pointer() ) : mLedger(lrLedger), saInReq(saSendMax), saOutReq(saSend) { ; } + PathState(const PathState& psSrc, bool bUnsed) + : mLedger(psSrc.mLedger), saInReq(psSrc.saInReq), saOutReq(psSrc.saOutReq) { ; } + void setExpanded( const LedgerEntrySet& lesSource, const STPath& spSourcePath, @@ -121,29 +126,14 @@ public: ); void setCanonical( - PathState::ref pspExpanded + const PathState& psExpanded ); Json::Value getJson() const; - static PathState::pointer createExpanded( - const LedgerEntrySet& lesSource, - const STPath& spSourcePath, - const uint160& uReceiverID, - const uint160& uSenderID, - const STAmount& saSend, - const STAmount& saSendMax - ) - { - PathState::pointer pspNew = boost::make_shared(saSend, saSendMax, lesSource.getLedgerRef()); - - pspNew->setExpanded(lesSource, spSourcePath, uReceiverID, uSenderID); - - return pspNew; - } - +#if 0 static PathState::pointer createCanonical( - PathState::ref pspExpanded + PathState&ref pspExpanded ) { PathState::pointer pspNew = boost::make_shared(pspExpanded->saOutAct, pspExpanded->saInAct); @@ -152,8 +142,8 @@ public: return pspNew; } - - static bool lessPriority(PathState::ref lhs, PathState::ref rhs); +#endif + static bool lessPriority(PathState& lhs, PathState& rhs); }; class RippleCalc @@ -168,18 +158,18 @@ public: // If the transaction fails to meet some constraint, still need to delete unfunded offers. boost::unordered_set musUnfundedFound; // Offers that were found unfunded. - void pathNext(PathState::ref pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent); - TER calcNode(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); - TER calcNodeRev(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); - TER calcNodeFwd(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); - TER calcNodeOfferRev(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); - TER calcNodeOfferFwd(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); - TER calcNodeAccountRev(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); - TER calcNodeAccountFwd(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality); - TER calcNodeAdvance(const unsigned int uNode, PathState::ref pspCur, const bool bMultiQuality, const bool bReverse); + void pathNext(PathState& psCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent); + TER calcNode(const unsigned int uNode, PathState& psCur, const bool bMultiQuality); + TER calcNodeRev(const unsigned int uNode, PathState& psCur, const bool bMultiQuality); + TER calcNodeFwd(const unsigned int uNode, PathState& psCur, const bool bMultiQuality); + TER calcNodeOfferRev(const unsigned int uNode, PathState& psCur, const bool bMultiQuality); + TER calcNodeOfferFwd(const unsigned int uNode, PathState& psCur, const bool bMultiQuality); + TER calcNodeAccountRev(const unsigned int uNode, PathState& psCur, const bool bMultiQuality); + TER calcNodeAccountFwd(const unsigned int uNode, PathState& psCur, const bool bMultiQuality); + TER calcNodeAdvance(const unsigned int uNode, PathState& psCur, const bool bMultiQuality, const bool bReverse); TER calcNodeDeliverRev( const unsigned int uNode, - PathState::ref pspCur, + PathState& psCur, const bool bMultiQuality, const uint160& uOutAccountID, const STAmount& saOutReq, @@ -187,7 +177,7 @@ public: TER calcNodeDeliverFwd( const unsigned int uNode, - PathState::ref pspCur, + PathState& psCur, const bool bMultiQuality, const uint160& uInAccountID, const STAmount& saInReq, @@ -202,19 +192,22 @@ public: RippleCalc(LedgerEntrySet& lesNodes) : lesActive(lesNodes) { ; } static TER rippleCalc( - LedgerEntrySet& lesActive, - STAmount& saMaxAmountAct, - STAmount& saDstAmountAct, - const STAmount& saDstAmountReq, - const STAmount& saMaxAmountReq, - const uint160& uDstAccountID, - const uint160& uSrcAccountID, - const STPathSet& spsPaths, - const bool bPartialPayment, - const bool bLimitQuality, - const bool bNoRippleDirect, - const bool bStandAlone + LedgerEntrySet& lesActive, + STAmount& saMaxAmountAct, + STAmount& saDstAmountAct, + std::vector& vpsExpanded, + const STAmount& saDstAmountReq, + const STAmount& saMaxAmountReq, + const uint160& uDstAccountID, + const uint160& uSrcAccountID, + const STPathSet& spsPaths, + const bool bPartialPayment, + const bool bLimitQuality, + const bool bNoRippleDirect, + const bool bStandAlone ); + + static void setCanonical(STPathSet& spsDst, const std::vector& vpsExpanded); }; #endif diff --git a/src/cpp/ripple/SerializedTypes.h b/src/cpp/ripple/SerializedTypes.h index 7b97970033..c29e4c69f8 100644 --- a/src/cpp/ripple/SerializedTypes.h +++ b/src/cpp/ripple/SerializedTypes.h @@ -570,10 +570,10 @@ public: }; protected: - int mType; - uint160 mAccountID; - uint160 mCurrencyID; - uint160 mIssuerID; + unsigned int mType; + uint160 mAccountID; + uint160 mCurrencyID; + uint160 mIssuerID; public: STPathElement(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID, @@ -586,6 +586,12 @@ public: | (uIssuerID.isZero() ? 0 : STPathElement::typeIssuer); } + STPathElement(unsigned int uType, const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID) + : mType(uType), mAccountID(uAccountID), mCurrencyID(uCurrencyID), mIssuerID(uIssuerID) + { + ; + } + int getNodeType() const { return mType; } bool isOffer() const { return mAccountID.isZero(); } bool isAccount() const { return !isOffer(); } @@ -634,6 +640,8 @@ public: std::vector::const_iterator end() const { return mPath.end(); } bool operator==(const STPath& t) const { return mPath == t.mPath; } + + void setCanonical(const STPath& spExpanded); }; inline std::vector::iterator range_begin(STPath & x)