From 27620af1bf646e339e2aa05bf9c1cfd38e296921 Mon Sep 17 00:00:00 2001 From: Tom Ritchford Date: Fri, 6 Jun 2014 13:36:00 -0400 Subject: [PATCH] Further cleanups of RippleCalc. * Rename many variables. * Make most of PathState private. * Extract out common Node::isAccount() code. * Rename bConsumed to allLiquidityConsumed_. * Extract out code into PathState::clear(). --- Builds/VisualStudio2013/RippleD.vcxproj | 15 +- .../VisualStudio2013/RippleD.vcxproj.filters | 18 +- src/ripple/module/app/paths/CalcNode.cpp | 63 +-- .../module/app/paths/CalcNodeAccountFwd.cpp | 104 ++-- .../module/app/paths/CalcNodeAccountRev.cpp | 82 +-- .../module/app/paths/CalcNodeAdvance.cpp | 70 +-- .../module/app/paths/CalcNodeDeliverFwd.cpp | 68 +-- .../module/app/paths/CalcNodeDeliverRev.cpp | 62 ++- src/ripple/module/app/paths/CalcNodeOffer.cpp | 36 +- .../module/app/paths/CalcNodeRipple.cpp | 20 +- src/ripple/module/app/paths/CalcState.h | 49 +- src/ripple/module/app/paths/Calculators.h | 61 +- src/ripple/module/app/paths/Node.cpp | 82 +++ src/ripple/module/app/paths/Node.h | 95 ++++ src/ripple/module/app/paths/PathNext.cpp | 45 +- src/ripple/module/app/paths/PathRequest.cpp | 29 +- src/ripple/module/app/paths/PathRequest.h | 4 +- src/ripple/module/app/paths/PathState.cpp | 524 +++++------------- src/ripple/module/app/paths/PathState.h | 160 ++---- src/ripple/module/app/paths/Pathfinder.cpp | 21 +- .../module/app/paths/QualityConstraint.h | 31 ++ src/ripple/module/app/paths/RippleCalc.cpp | 217 ++++---- src/ripple/module/app/paths/RippleCalc.h | 4 +- src/ripple/module/app/paths/Types.h | 43 ++ src/ripple/module/app/transactors/Payment.cpp | 6 +- .../module/rpc/handlers/RipplePathFind.cpp | 23 +- 26 files changed, 955 insertions(+), 977 deletions(-) create mode 100644 src/ripple/module/app/paths/Node.cpp create mode 100644 src/ripple/module/app/paths/Node.h create mode 100644 src/ripple/module/app/paths/QualityConstraint.h create mode 100644 src/ripple/module/app/paths/Types.h diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj index 9d4940379d..4763ee1a3f 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj +++ b/Builds/VisualStudio2013/RippleD.vcxproj @@ -2233,6 +2233,11 @@ + + True + + + True @@ -2256,6 +2261,8 @@ + + True @@ -2273,6 +2280,8 @@ + + @@ -2932,6 +2941,9 @@ True + + True + True @@ -3068,9 +3080,6 @@ - - True - True diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters index 2a62985709..563dc413b2 100644 --- a/Builds/VisualStudio2013/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters @@ -3279,6 +3279,12 @@ ripple\module\app\paths + + ripple\module\app\paths + + + ripple\module\app\paths + ripple\module\app\paths @@ -3306,6 +3312,9 @@ ripple\module\app\paths + + ripple\module\app\paths + ripple\module\app\paths @@ -3327,6 +3336,9 @@ ripple\module\app\paths + + ripple\module\app\paths + ripple\module\app\peers @@ -4119,6 +4131,9 @@ ripple\module\rpc\handlers + + ripple\module\rpc\handlers + ripple\module\rpc\handlers @@ -4260,9 +4275,6 @@ ripple\module\rpc\impl - - ripple\module\rpc\impl - ripple\module\rpc\impl diff --git a/src/ripple/module/app/paths/CalcNode.cpp b/src/ripple/module/app/paths/CalcNode.cpp index 5137d32400..179f1f6568 100644 --- a/src/ripple/module/app/paths/CalcNode.cpp +++ b/src/ripple/module/app/paths/CalcNode.cpp @@ -25,34 +25,35 @@ #include namespace ripple { +namespace path { -TER calcNodeFwd ( +TER nodeFwd ( RippleCalc& rippleCalc, const unsigned int nodeIndex, PathState& pathState, const bool bMultiQuality) { - auto const& node = pathState.vpnNodes[nodeIndex]; - auto const nodeIsAccount = isAccount(node); + auto const& node = pathState.nodes()[nodeIndex]; + auto const isAccount = node.isAccount(); WriteLog (lsTRACE, RippleCalc) - << "calcNodeFwd> nodeIndex=" << nodeIndex; + << "nodeFwd> nodeIndex=" << nodeIndex; - TER errorCode = nodeIsAccount - ? calcNodeAccountFwd (rippleCalc, nodeIndex, pathState, bMultiQuality) - : calcNodeOfferFwd (rippleCalc, nodeIndex, pathState, bMultiQuality); + TER resultCode = isAccount + ? nodeAccountFwd (rippleCalc, nodeIndex, pathState, bMultiQuality) + : nodeOfferFwd (rippleCalc, nodeIndex, pathState, bMultiQuality); - if (errorCode == tesSUCCESS && nodeIndex + 1 != pathState.vpnNodes.size ()) - errorCode = calcNodeFwd (rippleCalc, nodeIndex + 1, pathState, bMultiQuality); + if (resultCode == tesSUCCESS && nodeIndex + 1 != pathState.nodes().size ()) + resultCode = nodeFwd (rippleCalc, nodeIndex + 1, pathState, bMultiQuality); - if (errorCode == tesSUCCESS && !(pathState.saInPass && pathState.saOutPass)) - errorCode = tecPATH_DRY; + if (resultCode == tesSUCCESS && !(pathState.inPass() && pathState.outPass())) + resultCode = tecPATH_DRY; WriteLog (lsTRACE, RippleCalc) - << "calcNodeFwd<" + << "nodeFwd<" << " nodeIndex:" << nodeIndex - << " errorCode:" << errorCode; + << " resultCode:" << resultCode; - return errorCode; + return resultCode; } // Calculate a node and its previous nodes. @@ -61,51 +62,51 @@ TER calcNodeFwd ( // must be asked for. // // Then work forward, figuring out how much can actually be delivered. -// <-- errorCode: tesSUCCESS or tecPATH_DRY +// <-- resultCode: tesSUCCESS or tecPATH_DRY // <-> pnNodes: // --> [end]saWanted.mAmount // --> [all]saWanted.mCurrency // --> [all]saAccount // <-> [0]saWanted.mAmount : --> limit, <-- actual -TER calcNodeRev ( +TER nodeRev ( RippleCalc& rippleCalc, const unsigned int nodeIndex, PathState& pathState, const bool bMultiQuality) { - PathState::Node& node = pathState.vpnNodes[nodeIndex]; - bool const nodeIsAccount - = is_bit_set (node.uFlags, STPathElement::typeAccount); - TER errorCode; + auto& node = pathState.nodes()[nodeIndex]; + auto const isAccount = node.isAccount(); + TER resultCode; node.saTransferRate = STAmount::saFromRate ( rippleCalc.mActiveLedger.rippleTransferRate (node.uIssuerID)); WriteLog (lsTRACE, RippleCalc) - << "calcNodeRev>" + << "nodeRev>" << " nodeIndex=" << nodeIndex - << " nodeIsAccount=" << nodeIsAccount + << " isAccount=" << isAccount << " uIssuerID=" << RippleAddress::createHumanAccountID (node.uIssuerID) << " saTransferRate=" << node.saTransferRate; - errorCode = nodeIsAccount - ? calcNodeAccountRev (rippleCalc, nodeIndex, pathState, bMultiQuality) - : calcNodeOfferRev (rippleCalc, nodeIndex, pathState, bMultiQuality); + resultCode = isAccount + ? nodeAccountRev (rippleCalc, nodeIndex, pathState, bMultiQuality) + : nodeOfferRev (rippleCalc, nodeIndex, pathState, bMultiQuality); // Do previous. - if (errorCode != tesSUCCESS) + if (resultCode != tesSUCCESS) // Error, don't continue. nothing (); else if (nodeIndex) // Continue in reverse. TODO(tom): remove unnecessary recursion. - errorCode = calcNodeRev (rippleCalc, nodeIndex - 1, pathState, bMultiQuality); + resultCode = nodeRev (rippleCalc, nodeIndex - 1, pathState, bMultiQuality); WriteLog (lsTRACE, RippleCalc) - << "calcNodeRev< " + << "nodeRev< " << "nodeIndex=" << nodeIndex - << " errorCode=%s" << transToken (errorCode) - << "/" << errorCode; + << " resultCode=%s" << transToken (resultCode) + << "/" << resultCode; - return errorCode; + return resultCode; } +} // path } // ripple diff --git a/src/ripple/module/app/paths/CalcNodeAccountFwd.cpp b/src/ripple/module/app/paths/CalcNodeAccountFwd.cpp index d54b00b0a3..0e486e8c9e 100644 --- a/src/ripple/module/app/paths/CalcNodeAccountFwd.cpp +++ b/src/ripple/module/app/paths/CalcNodeAccountFwd.cpp @@ -22,6 +22,7 @@ #include namespace ripple { +namespace path { // The reverse pass has been narrowing by credit available and inflating by fees // as it worked backwards. Now, for the current account node, take the actual @@ -38,25 +39,23 @@ namespace ripple { // do not need to push funds. // - If next node is an offer and output is XRP then we need to deliver funds to // limbo. -TER calcNodeAccountFwd ( +TER nodeAccountFwd ( RippleCalc& rippleCalc, const unsigned int nodeIndex, // 0 <= nodeIndex <= lastNodeIndex PathState& pathState, const bool bMultiQuality) { - TER errorCode = tesSUCCESS; - const unsigned int lastNodeIndex = pathState.vpnNodes.size () - 1; + TER resultCode = tesSUCCESS; + const unsigned int lastNodeIndex = pathState.nodes().size () - 1; std::uint64_t uRateMax = 0; - auto& previousNode = pathState.vpnNodes[nodeIndex ? nodeIndex - 1 : 0]; - auto& node = pathState.vpnNodes[nodeIndex]; - auto& nextNode = pathState.vpnNodes[nodeIndex == lastNodeIndex ? lastNodeIndex : nodeIndex + 1]; + auto& previousNode = pathState.nodes()[nodeIndex ? nodeIndex - 1 : 0]; + auto& node = pathState.nodes()[nodeIndex]; + auto& nextNode = pathState.nodes()[nodeIndex == lastNodeIndex ? lastNodeIndex : nodeIndex + 1]; - const bool previousNodeIsAccount - = is_bit_set (previousNode.uFlags, STPathElement::typeAccount); - const bool nextNodeIsAccount - = is_bit_set (nextNode.uFlags, STPathElement::typeAccount); + const bool previousNodeIsAccount = previousNode.isAccount(); + const bool nextNodeIsAccount = nextNode.isAccount(); const uint160& previousAccountID = previousNodeIsAccount ? previousNode.uAccountID : node.uAccountID; @@ -93,7 +92,7 @@ TER calcNodeAccountFwd ( previousNode.saFwdDeliver.getIssuer ()); WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountFwd> " + << "nodeAccountFwd> " << "nodeIndex=" << nodeIndex << "/" << lastNodeIndex << " previousNode.saFwdRedeem:" << previousNode.saFwdRedeem << " saPrvIssueReq:" << previousNode.saFwdIssue @@ -116,43 +115,43 @@ TER calcNodeAccountFwd ( // available. node.saFwdRedeem = node.saRevRedeem; - if (pathState.saInReq >= zero) + if (pathState.inReq() >= zero) { // Limit by send max. node.saFwdRedeem = std::min ( - node.saFwdRedeem, pathState.saInReq - pathState.saInAct); + node.saFwdRedeem, pathState.inReq() - pathState.inAct()); } - pathState.saInPass = node.saFwdRedeem; + pathState.inPass() = node.saFwdRedeem; node.saFwdIssue = node.saFwdRedeem == node.saRevRedeem // Fully redeemed. ? node.saRevIssue : STAmount (node.saRevIssue); - if (!!node.saFwdIssue && pathState.saInReq >= zero) + if (!!node.saFwdIssue && pathState.inReq() >= zero) { // Limit by send max. node.saFwdIssue = std::min ( node.saFwdIssue, - pathState.saInReq - pathState.saInAct - node.saFwdRedeem); + pathState.inReq() - pathState.inAct() - node.saFwdRedeem); } - pathState.saInPass += node.saFwdIssue; + pathState.inPass() += node.saFwdIssue; WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountFwd: ^ --> ACCOUNT --> account :" - << " saInReq=" << pathState.saInReq - << " saInAct=" << pathState.saInAct + << "nodeAccountFwd: ^ --> ACCOUNT --> account :" + << " saInReq=" << pathState.inReq() + << " saInAct=" << pathState.inAct() << " node.saFwdRedeem:" << node.saFwdRedeem << " node.saRevIssue:" << node.saRevIssue << " node.saFwdIssue:" << node.saFwdIssue - << " pathState.saInPass:" << pathState.saInPass; + << " pathState.saInPass:" << pathState.inPass(); } else if (nodeIndex == lastNodeIndex) { // account --> ACCOUNT --> $ WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountFwd: account --> ACCOUNT --> $ :" + << "nodeAccountFwd: account --> ACCOUNT --> $ :" << " previousAccountID=" << RippleAddress::createHumanAccountID (previousAccountID) << " node.uAccountID=" @@ -162,7 +161,7 @@ TER calcNodeAccountFwd ( // Last node. Accept all funds. Calculate amount actually to credit. - STAmount& saCurReceive = pathState.saOutPass; + STAmount& saCurReceive = pathState.outPass(); STAmount saIssueCrd = uQualityIn >= QUALITY_ONE ? previousNode.saFwdIssue // No fee. @@ -177,21 +176,21 @@ TER calcNodeAccountFwd ( if (saCurReceive) { // Actually receive. - errorCode = rippleCalc.mActiveLedger.rippleCredit ( + resultCode = rippleCalc.mActiveLedger.rippleCredit ( previousAccountID, node.uAccountID, previousNode.saFwdRedeem + previousNode.saFwdIssue, false); } else { // After applying quality, total payment was microscopic. - errorCode = tecPATH_DRY; + resultCode = tecPATH_DRY; } } else { // account --> ACCOUNT --> account WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountFwd: account --> ACCOUNT --> account"; + << "nodeAccountFwd: account --> ACCOUNT --> account"; node.saFwdRedeem.clear (node.saRevRedeem); node.saFwdIssue.clear (node.saRevIssue); @@ -201,7 +200,7 @@ TER calcNodeAccountFwd ( // Previous wants to redeem. { // Rate : 1.0 : quality out - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, uQualityOut, previousNode.saFwdRedeem, node.saRevRedeem, saPrvRedeemAct, node.saFwdRedeem, uRateMax); @@ -214,7 +213,7 @@ TER calcNodeAccountFwd ( // Current has more to redeem to next. { // Rate: quality in : quality out - calcNodeRipple ( + nodeRipple ( rippleCalc, uQualityIn, uQualityOut, previousNode.saFwdIssue, node.saRevRedeem, saPrvIssueAct, node.saFwdRedeem, uRateMax); @@ -229,7 +228,7 @@ TER calcNodeAccountFwd ( // Current wants to issue. { // Rate : 1.0 : transfer_rate - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, rippleCalc.mActiveLedger.rippleTransferRate (node.uAccountID), previousNode.saFwdRedeem, node.saRevIssue, saPrvRedeemAct, @@ -245,7 +244,7 @@ TER calcNodeAccountFwd ( // Current wants to issue. { // Rate: quality in : 1.0 - calcNodeRipple ( + nodeRipple ( rippleCalc, uQualityIn, QUALITY_ONE, previousNode.saFwdIssue, node.saRevIssue, saPrvIssueAct, node.saFwdIssue, uRateMax); @@ -254,7 +253,7 @@ TER calcNodeAccountFwd ( STAmount saProvide = node.saFwdRedeem + node.saFwdIssue; // Adjust prv --> cur balance : take all inbound - errorCode = saProvide + resultCode = saProvide ? rippleCalc.mActiveLedger.rippleCredit ( previousAccountID, node.uAccountID, previousNode.saFwdRedeem + previousNode.saFwdIssue, false) @@ -273,7 +272,7 @@ TER calcNodeAccountFwd ( { // Non-XRP, current node is the issuer. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountFwd: account --> ACCOUNT --> offer"; + << "nodeAccountFwd: account --> ACCOUNT --> offer"; node.saFwdDeliver.clear (node.saRevDeliver); @@ -286,7 +285,7 @@ TER calcNodeAccountFwd ( { // Rate : 1.0 : transfer_rate // XXX Is having the transfer rate here correct? - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, rippleCalc.mActiveLedger.rippleTransferRate (node.uAccountID), previousNode.saFwdRedeem, node.saRevDeliver, saPrvRedeemAct, @@ -300,14 +299,14 @@ TER calcNodeAccountFwd ( // Previous wants to issue. To next must be ok. { // Rate: quality in : 1.0 - calcNodeRipple ( + nodeRipple ( rippleCalc, uQualityIn, QUALITY_ONE, previousNode.saFwdIssue, node.saRevDeliver, saPrvIssueAct, node.saFwdDeliver, uRateMax); } // Adjust prv --> cur balance : take all inbound - errorCode = node.saFwdDeliver + resultCode = node.saFwdDeliver ? rippleCalc.mActiveLedger.rippleCredit ( previousAccountID, node.uAccountID, previousNode.saFwdRedeem + previousNode.saFwdIssue, false) @@ -319,11 +318,11 @@ TER calcNodeAccountFwd ( node.saFwdDeliver = node.saRevDeliver; // If limited, then limit by send max and available. - if (pathState.saInReq >= zero) + if (pathState.inReq() >= zero) { // Limit by send max. node.saFwdDeliver = std::min (node.saFwdDeliver, - pathState.saInReq - pathState.saInAct); + pathState.inReq() - pathState.inAct()); // Limit XRP by available. No limit for non-XRP as issuer. if (node.uCurrencyID.isZero ()) @@ -335,11 +334,11 @@ TER calcNodeAccountFwd ( } // Record amount sent for pass. - pathState.saInPass = node.saFwdDeliver; + pathState.inPass() = node.saFwdDeliver; if (!node.saFwdDeliver) { - errorCode = tecPATH_DRY; + resultCode = tecPATH_DRY; } else if (!!node.uCurrencyID) { @@ -348,7 +347,7 @@ TER calcNodeAccountFwd ( // which ripple balance will be adjusted. Assume just issuing. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountFwd: ^ --> ACCOUNT -- !XRP --> offer"; + << "nodeAccountFwd: ^ --> ACCOUNT -- !XRP --> offer"; // As the issuer, would only issue. // Don't need to actually deliver. As from delivering leave in @@ -358,10 +357,10 @@ TER calcNodeAccountFwd ( else { WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountFwd: ^ --> ACCOUNT -- XRP --> offer"; + << "nodeAccountFwd: ^ --> ACCOUNT -- XRP --> offer"; // Deliver XRP to limbo. - errorCode = rippleCalc.mActiveLedger.accountSend ( + resultCode = rippleCalc.mActiveLedger.accountSend ( node.uAccountID, ACCOUNT_XRP, node.saFwdDeliver); } } @@ -372,10 +371,10 @@ TER calcNodeAccountFwd ( { // offer --> ACCOUNT --> $ WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountFwd: offer --> ACCOUNT --> $ : " + << "nodeAccountFwd: offer --> ACCOUNT --> $ : " << previousNode.saFwdDeliver; - STAmount& saCurReceive = pathState.saOutPass; + STAmount& saCurReceive = pathState.outPass(); // Amount to credit. saCurReceive = previousNode.saFwdDeliver; @@ -387,7 +386,7 @@ TER calcNodeAccountFwd ( { // offer --> ACCOUNT --> account WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountFwd: offer --> ACCOUNT --> account"; + << "nodeAccountFwd: offer --> ACCOUNT --> account"; node.saFwdRedeem.clear (node.saRevRedeem); node.saFwdIssue.clear (node.saRevIssue); @@ -397,7 +396,7 @@ TER calcNodeAccountFwd ( // Previous wants to deliver and can current redeem. { // Rate : 1.0 : quality out - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, uQualityOut, previousNode.saFwdDeliver, node.saRevRedeem, saPrvDeliverAct, node.saFwdRedeem, uRateMax); @@ -413,7 +412,7 @@ TER calcNodeAccountFwd ( // Current wants issue. { // Rate : 1.0 : transfer_rate - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, rippleCalc.mActiveLedger.rippleTransferRate (node.uAccountID), previousNode.saFwdDeliver, node.saRevIssue, saPrvDeliverAct, @@ -425,7 +424,7 @@ TER calcNodeAccountFwd ( STAmount saProvide = node.saFwdRedeem + node.saFwdIssue; if (!saProvide) - errorCode = tecPATH_DRY; + resultCode = tecPATH_DRY; } } else @@ -433,7 +432,7 @@ TER calcNodeAccountFwd ( // offer --> ACCOUNT --> offer // deliver/redeem -> deliver/issue. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountFwd: offer --> ACCOUNT --> offer"; + << "nodeAccountFwd: offer --> ACCOUNT --> offer"; node.saFwdDeliver.clear (node.saRevDeliver); @@ -443,7 +442,7 @@ TER calcNodeAccountFwd ( // Current wants issue. { // Rate : 1.0 : transfer_rate - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, rippleCalc.mActiveLedger.rippleTransferRate (node.uAccountID), previousNode.saFwdDeliver, node.saRevDeliver, saPrvDeliverAct, @@ -453,10 +452,11 @@ TER calcNodeAccountFwd ( // No income balance adjustments necessary. The paying side inside the // offer paid and the next link will receive. if (!node.saFwdDeliver) - errorCode = tecPATH_DRY; + resultCode = tecPATH_DRY; } - return errorCode; + return resultCode; } +} // path } // ripple diff --git a/src/ripple/module/app/paths/CalcNodeAccountRev.cpp b/src/ripple/module/app/paths/CalcNodeAccountRev.cpp index 83817e7f3c..7c43109549 100644 --- a/src/ripple/module/app/paths/CalcNodeAccountRev.cpp +++ b/src/ripple/module/app/paths/CalcNodeAccountRev.cpp @@ -22,6 +22,7 @@ #include namespace ripple { +namespace path { // Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver from saCur, based on // required deliverable, propagate redeem, issue, and deliver requests to the @@ -36,26 +37,24 @@ namespace ripple { // // <-- tesSUCCESS or tecPATH_DRY -TER calcNodeAccountRev ( +TER nodeAccountRev ( RippleCalc& rippleCalc, const unsigned int nodeIndex, PathState& pathState, const bool bMultiQuality) { TER terResult = tesSUCCESS; - auto const lastNodeIndex = pathState.vpnNodes.size () - 1; + auto const lastNodeIndex = pathState.nodes().size () - 1; auto const isFinalNode = (nodeIndex == lastNodeIndex); std::uint64_t uRateMax = 0; - auto& previousNode = pathState.vpnNodes[nodeIndex ? nodeIndex - 1 : 0]; - auto& node = pathState.vpnNodes[nodeIndex]; - auto& nextNode = pathState.vpnNodes[isFinalNode ? lastNodeIndex : nodeIndex + 1]; + auto& previousNode = pathState.nodes()[nodeIndex ? nodeIndex - 1 : 0]; + auto& node = pathState.nodes()[nodeIndex]; + auto& nextNode = pathState.nodes()[isFinalNode ? lastNodeIndex : nodeIndex + 1]; // Current is allowed to redeem to next. - const bool previousNodeIsAccount = !nodeIndex || - is_bit_set (previousNode.uFlags, STPathElement::typeAccount); - const bool nextNodeIsAccount = isFinalNode || - is_bit_set (nextNode.uFlags, STPathElement::typeAccount); + const bool previousNodeIsAccount = !nodeIndex || previousNode.isAccount(); + const bool nextNodeIsAccount = isFinalNode || nextNode.isAccount(); const uint160& previousAccountID = previousNodeIsAccount ? previousNode.uAccountID : node.uAccountID; @@ -92,7 +91,7 @@ TER calcNodeAccountRev ( : STAmount (node.uCurrencyID, node.uAccountID); WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev>" + << "nodeAccountRev>" << " nodeIndex=%d/%d" << nodeIndex << "/" << lastNodeIndex << " previousAccountID=" << RippleAddress::createHumanAccountID (previousAccountID) @@ -143,7 +142,7 @@ TER calcNodeAccountRev ( saCurDeliverReq.getCurrency (), saCurDeliverReq.getIssuer ()); WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev:" + << "nodeAccountRev:" << " saPrvRedeemReq:" << saPrvRedeemReq << " saPrvIssueReq:" << saPrvIssueReq << " saPrvDeliverAct:" << saPrvDeliverAct @@ -178,12 +177,12 @@ TER calcNodeAccountRev ( // Overall deliverable. // If previous is an account, limit. const STAmount saCurWantedReq = std::min ( - pathState.saOutReq - pathState.saOutAct, saPrvLimit + saPrvOwed); + pathState.outReq() - pathState.outAct(), saPrvLimit + saPrvOwed); STAmount saCurWantedAct ( saCurWantedReq.getCurrency (), saCurWantedReq.getIssuer ()); WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: account --> ACCOUNT --> $ :" + << "nodeAccountRev: account --> ACCOUNT --> $ :" << " saCurWantedReq=" << saCurWantedReq; // Calculate redeem @@ -197,7 +196,7 @@ TER calcNodeAccountRev ( uRateMax = STAmount::uRateOne; WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: Redeem at 1:1" + << "nodeAccountRev: Redeem at 1:1" << " saPrvRedeemReq=" << saPrvRedeemReq << " (available) saPrvRedeemAct=" << saPrvRedeemAct << " uRateMax=" @@ -218,13 +217,13 @@ TER calcNodeAccountRev ( // If we previously redeemed and this has a poorer rate, this // won't be included the current increment. - calcNodeRipple ( + nodeRipple ( rippleCalc, uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurWantedReq, saPrvIssueAct, saCurWantedAct, uRateMax); WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: Issuing: Rate: quality in : 1.0" + << "nodeAccountRev: Issuing: Rate: quality in : 1.0" << " saPrvIssueAct:" << saPrvIssueAct << " saCurWantedAct:" << saCurWantedAct; } @@ -246,13 +245,13 @@ TER calcNodeAccountRev ( && saPrvRedeemReq) // Previous has IOUs to redeem. { // Rate : 1.0 : quality out - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax); WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: Rate : 1.0 : quality out" + << "nodeAccountRev: Rate : 1.0 : quality out" << " saPrvRedeemAct:" << saPrvRedeemAct << " saCurRedeemAct:" << saCurRedeemAct; } @@ -264,13 +263,13 @@ TER calcNodeAccountRev ( // Previous has no IOUs to redeem remaining. { // Rate: quality in : quality out - calcNodeRipple ( + nodeRipple ( rippleCalc, uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct, uRateMax); WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: Rate: quality in : quality out:" + << "nodeAccountRev: Rate: quality in : quality out:" << " saPrvIssueAct:" << saPrvIssueAct << " saCurRedeemAct:" << saCurRedeemAct; } @@ -283,7 +282,7 @@ TER calcNodeAccountRev ( // Did not complete redeeming previous IOUs. { // Rate : 1.0 : transfer_rate - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, rippleCalc.mActiveLedger.rippleTransferRate (node.uAccountID), @@ -291,7 +290,7 @@ TER calcNodeAccountRev ( saCurIssueAct, uRateMax); WriteLog (lsDEBUG, RippleCalc) - << "calcNodeAccountRev: Rate : 1.0 : transfer_rate:" + << "nodeAccountRev: Rate : 1.0 : transfer_rate:" << " saPrvRedeemAct:" << saPrvRedeemAct << " saCurIssueAct:" << saCurIssueAct; } @@ -307,13 +306,13 @@ TER calcNodeAccountRev ( // Previous can issue. { // Rate: quality in : 1.0 - calcNodeRipple ( + nodeRipple ( rippleCalc, uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax); WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: Rate: quality in : 1.0:" + << "nodeAccountRev: Rate: quality in : 1.0:" << " saPrvIssueAct:" << saPrvIssueAct << " saCurIssueAct:" << saCurIssueAct; } @@ -325,7 +324,7 @@ TER calcNodeAccountRev ( } WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: ^|account --> ACCOUNT --> account :" + << "nodeAccountRev: ^|account --> ACCOUNT --> account :" << " saCurRedeemReq:" << saCurRedeemReq << " saCurIssueReq:" << saCurIssueReq << " saPrvOwed:" << saPrvOwed @@ -339,7 +338,7 @@ TER calcNodeAccountRev ( // Note: deliver is always issue as ACCOUNT is the issuer for the offer // input. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: account --> ACCOUNT --> offer"; + << "nodeAccountRev: account --> ACCOUNT --> offer"; saPrvRedeemAct.clear (saPrvRedeemReq); saPrvIssueAct.clear (saPrvIssueReq); @@ -349,7 +348,7 @@ TER calcNodeAccountRev ( && saCurDeliverReq) // Need some issued. { // Rate : 1.0 : transfer_rate - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, rippleCalc.mActiveLedger.rippleTransferRate (node.uAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, @@ -361,7 +360,7 @@ TER calcNodeAccountRev ( && saCurDeliverReq != saCurDeliverAct) // Still need some issued. { // Rate: quality in : 1.0 - calcNodeRipple ( + nodeRipple ( rippleCalc, uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurDeliverReq, saPrvIssueAct, saCurDeliverAct, uRateMax); @@ -374,7 +373,7 @@ TER calcNodeAccountRev ( } WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: " + << "nodeAccountRev: " << " saCurDeliverReq:" << saCurDeliverReq << " saCurDeliverAct:" << saCurDeliverAct << " saPrvOwed:" << saPrvOwed; @@ -385,15 +384,15 @@ TER calcNodeAccountRev ( { // offer --> ACCOUNT --> $ // Previous is an offer, no limit: redeem own IOUs. - const STAmount& saCurWantedReq = pathState.saOutReq - pathState.saOutAct; + const STAmount& saCurWantedReq = pathState.outReq() - pathState.outAct(); STAmount saCurWantedAct ( saCurWantedReq.getCurrency (), saCurWantedReq.getIssuer ()); WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: offer --> ACCOUNT --> $ :" + << "nodeAccountRev: offer --> ACCOUNT --> $ :" << " saCurWantedReq:" << saCurWantedReq - << " saOutAct:" << pathState.saOutAct - << " saOutReq:" << pathState.saOutReq; + << " saOutAct:" << pathState.outAct() + << " saOutReq:" << pathState.outReq(); if (saCurWantedReq <= zero) { @@ -406,7 +405,7 @@ TER calcNodeAccountRev ( // TODO(tom): can only be a race condition if true! // Rate: quality in : 1.0 - calcNodeRipple ( + nodeRipple ( rippleCalc, uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct, uRateMax); @@ -418,7 +417,7 @@ TER calcNodeAccountRev ( } WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev:" + << "nodeAccountRev:" << " saPrvDeliverAct:" << saPrvDeliverAct << " saPrvDeliverReq:" << saPrvDeliverReq << " saCurWantedAct:" << saCurWantedAct @@ -429,7 +428,7 @@ TER calcNodeAccountRev ( // offer --> ACCOUNT --> account // Note: offer is always delivering(redeeming) as account is issuer. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: offer --> ACCOUNT --> account :" + << "nodeAccountRev: offer --> ACCOUNT --> account :" << " saCurRedeemReq:" << saCurRedeemReq << " saCurIssueReq:" << saCurIssueReq; @@ -437,7 +436,7 @@ TER calcNodeAccountRev ( if (saCurRedeemReq) // Next wants us to redeem. { // Rate : 1.0 : quality out - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct, uRateMax); @@ -450,7 +449,7 @@ TER calcNodeAccountRev ( // Need some issued. { // Rate : 1.0 : transfer_rate - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, rippleCalc.mActiveLedger.rippleTransferRate (node.uAccountID), @@ -459,7 +458,7 @@ TER calcNodeAccountRev ( } WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev:" + << "nodeAccountRev:" << " saCurRedeemAct:" << saCurRedeemAct << " saCurRedeemReq:" << saCurRedeemReq << " saPrvDeliverAct:" << saPrvDeliverAct @@ -477,10 +476,10 @@ TER calcNodeAccountRev ( // offer --> ACCOUNT --> offer // deliver/redeem -> deliver/issue. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAccountRev: offer --> ACCOUNT --> offer"; + << "nodeAccountRev: offer --> ACCOUNT --> offer"; // Rate : 1.0 : transfer_rate - calcNodeRipple ( + nodeRipple ( rippleCalc, QUALITY_ONE, rippleCalc.mActiveLedger.rippleTransferRate (node.uAccountID), @@ -497,4 +496,5 @@ TER calcNodeAccountRev ( return terResult; } +} // path } // ripple diff --git a/src/ripple/module/app/paths/CalcNodeAdvance.cpp b/src/ripple/module/app/paths/CalcNodeAdvance.cpp index fae8c1565c..56e3487f4e 100644 --- a/src/ripple/module/app/paths/CalcNodeAdvance.cpp +++ b/src/ripple/module/app/paths/CalcNodeAdvance.cpp @@ -22,6 +22,7 @@ #include namespace ripple { +namespace path { // OPTIMIZE: When calculating path increment, note if increment consumes all // liquidity. No need to revisit path in the future if all liquidity is used. @@ -37,15 +38,15 @@ namespace ripple { // - Automatically advances to first offer. // --> bEntryAdvance: true, to advance to next entry. false, recalculate. // <-- uOfferIndex : 0=end of list. -TER calcNodeAdvance ( +TER nodeAdvance ( RippleCalc& rippleCalc, const unsigned int nodeIndex, PathState& pathState, const bool bMultiQuality, const bool bReverse) { - auto& previousNode = pathState.vpnNodes[nodeIndex - 1]; - auto& node = pathState.vpnNodes[nodeIndex]; + auto& previousNode = pathState.nodes()[nodeIndex - 1]; + auto& node = pathState.nodes()[nodeIndex]; uint256& uDirectTip = node.uDirectTip; uint256& uDirectEnd = node.uDirectEnd; @@ -64,10 +65,10 @@ TER calcNodeAdvance ( STAmount& saTakerGets = node.saTakerGets; bool& bFundsDirty = node.bFundsDirty; - TER errorCode = tesSUCCESS; + TER resultCode = tesSUCCESS; WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: TakerPays:" + << "nodeAdvance: TakerPays:" << saTakerPays << " TakerGets:" << saTakerGets; int loopCount = 0; @@ -109,7 +110,7 @@ TER calcNodeAdvance ( bDirectRestart = false; WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: Initialize node:" + << "nodeAdvance: Initialize node:" << " uDirectTip=" << uDirectTip <<" uDirectEnd=" << uDirectEnd << " bDirectAdvance=" << bDirectAdvance; @@ -132,7 +133,7 @@ TER calcNodeAdvance ( { // Have another quality directory. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: Quality advance: uDirectTip=" + << "nodeAdvance: Quality advance: uDirectTip=" << uDirectTip; sleDirectDir = rippleCalc.mActiveLedger.entryCache (ltDIR_NODE, uDirectTip); @@ -140,7 +141,7 @@ TER calcNodeAdvance ( else if (bReverse) { WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: No more offers."; + << "nodeAdvance: No more offers."; uOfferIndex = 0; break; @@ -150,7 +151,7 @@ TER calcNodeAdvance ( // No more offers. Should be done rather than fall off end of // book. WriteLog (lsWARNING, RippleCalc) - << "calcNodeAdvance: Unreachable: " + << "nodeAdvance: Unreachable: " << "Fell off end of order book."; // FIXME: why? return rippleCalc.mOpenLedger ? telFAILED_PROCESSING : @@ -166,7 +167,7 @@ TER calcNodeAdvance ( bEntryAdvance = true; WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: directory dirty: saOfrRate=" + << "nodeAdvance: directory dirty: saOfrRate=" << saOfrRate; } @@ -185,12 +186,12 @@ TER calcNodeAdvance ( bFundsDirty = false; WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: funds dirty: saOfrRate=" + << "nodeAdvance: funds dirty: saOfrRate=" << saOfrRate; } else { - WriteLog (lsTRACE, RippleCalc) << "calcNodeAdvance: as is"; + WriteLog (lsTRACE, RippleCalc) << "nodeAdvance: as is"; } } else if (!rippleCalc.mActiveLedger.dirNext ( @@ -203,13 +204,13 @@ TER calcNodeAdvance ( // We are allowed to process multiple qualities if this is the // only path. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: next quality"; + << "nodeAdvance: next quality"; bDirectAdvance = true; // Process next quality. } else if (!bReverse) { WriteLog (lsWARNING, RippleCalc) - << "calcNodeAdvance: unreachable: ran out of offers"; + << "nodeAdvance: unreachable: ran out of offers"; return rippleCalc.mOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING; // TEMPORARY @@ -242,7 +243,7 @@ TER calcNodeAdvance ( uOfrOwnerID, node.uCurrencyID, node.uIssuerID); WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: uOfrOwnerID=" + << "nodeAdvance: uOfrOwnerID=" << RippleAddress::createHumanAccountID (uOfrOwnerID) << " saTakerPays=" << saTakerPays << " saTakerGets=" << saTakerGets @@ -254,7 +255,7 @@ TER calcNodeAdvance ( { // Offer is expired. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: expired offer"; + << "nodeAdvance: expired offer"; rippleCalc.mUnfundedOffers.insert(uOfferIndex); continue; } @@ -267,7 +268,7 @@ TER calcNodeAdvance ( { // Past internal error, offer had bad amounts. WriteLog (lsWARNING, RippleCalc) - << "calcNodeAdvance: PAST INTERNAL ERROR:" + << "nodeAdvance: PAST INTERNAL ERROR:" << " OFFER NON-POSITIVE:" << " saTakerPays=" << saTakerPays << " saTakerGets=%s" << saTakerGets; @@ -282,7 +283,7 @@ TER calcNodeAdvance ( // this in mUnfundedOffers. // Just skip it. It will be deleted. WriteLog (lsDEBUG, RippleCalc) - << "calcNodeAdvance: PAST INTERNAL ERROR:" + << "nodeAdvance: PAST INTERNAL ERROR:" << " OFFER NON-POSITIVE:" << " saTakerPays=" << saTakerPays << " saTakerGets=" << saTakerGets; @@ -293,14 +294,14 @@ TER calcNodeAdvance ( // Reverse should have previously put bad offer in list. // An internal error previously left a bad offer. WriteLog (lsWARNING, RippleCalc) - << "calcNodeAdvance: INTERNAL ERROR:" + << "nodeAdvance: INTERNAL ERROR:" <<" OFFER NON-POSITIVE:" << " saTakerPays=" << saTakerPays << " saTakerGets=" << saTakerGets; // Don't process at all, things are in an unexpected // state for this transactions. - errorCode = tefEXCEPTION; + resultCode = tefEXCEPTION; } continue; @@ -314,8 +315,8 @@ TER calcNodeAdvance ( // XXX Going forward could we fund something with a worse // quality which was previously skipped? Might need to check // quality. - auto itForward = pathState.umForward.find (asLine); - const bool bFoundForward = itForward != pathState.umForward.end (); + auto itForward = pathState.forward().find (asLine); + const bool bFoundForward = itForward != pathState.forward().end (); // Only allow a source to be used once, in the first node // encountered from initial path scan. This prevents @@ -328,15 +329,15 @@ TER calcNodeAdvance ( // Temporarily unfunded. Another node uses this source, // ignore in this offer. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: temporarily unfunded offer" + << "nodeAdvance: temporarily unfunded offer" << " (forward)"; continue; } // This is overly strict. For contributions to past. We should // only count source if actually used. - auto itReverse = pathState.umReverse.find (asLine); - bool bFoundReverse = itReverse != pathState.umReverse.end (); + auto itReverse = pathState.reverse().find (asLine); + bool bFoundReverse = itReverse != pathState.reverse().end (); // For this quality increment, only allow a source to be used // from a single node, in the first node encountered from @@ -348,7 +349,7 @@ TER calcNodeAdvance ( // Temporarily unfunded. Another node uses this source, // ignore in this offer. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: temporarily unfunded offer" + << "nodeAdvance: temporarily unfunded offer" <<" (reverse)"; continue; } @@ -367,7 +368,7 @@ TER calcNodeAdvance ( { // Offer is unfunded. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: unfunded offer"; + << "nodeAdvance: unfunded offer"; if (bReverse && !bFoundReverse && !bFoundPast) { @@ -393,14 +394,14 @@ TER calcNodeAdvance ( { // Consider source mentioned by current path state. WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: remember=" + << "nodeAdvance: remember=" << RippleAddress::createHumanAccountID (uOfrOwnerID) << "/" << STAmount::createHumanCurrency (node.uCurrencyID) << "/" << RippleAddress::createHumanAccountID (node.uIssuerID); - pathState.umReverse.insert (std::make_pair (asLine, nodeIndex)); + pathState.reverse().insert (std::make_pair (asLine, nodeIndex)); } bFundsDirty = false; @@ -408,20 +409,21 @@ TER calcNodeAdvance ( } } } - while (errorCode == tesSUCCESS && (bEntryAdvance || bDirectAdvance)); + while (resultCode == tesSUCCESS && (bEntryAdvance || bDirectAdvance)); - if (errorCode == tesSUCCESS) + if (resultCode == tesSUCCESS) { WriteLog (lsTRACE, RippleCalc) - << "calcNodeAdvance: uOfferIndex=" << uOfferIndex; + << "nodeAdvance: uOfferIndex=" << uOfferIndex; } else { WriteLog (lsDEBUG, RippleCalc) - << "calcNodeAdvance: errorCode=" << transToken (errorCode); + << "nodeAdvance: resultCode=" << transToken (resultCode); } - return errorCode; + return resultCode; } +} // path } // ripple diff --git a/src/ripple/module/app/paths/CalcNodeDeliverFwd.cpp b/src/ripple/module/app/paths/CalcNodeDeliverFwd.cpp index 18875b2640..0b49c083aa 100644 --- a/src/ripple/module/app/paths/CalcNodeDeliverFwd.cpp +++ b/src/ripple/module/app/paths/CalcNodeDeliverFwd.cpp @@ -22,14 +22,15 @@ #include namespace ripple { +namespace path { // For current offer, get input from deliver/limbo and output to next account or // deliver for next offers. // -// <-- node.saFwdDeliver: For calcNodeAccountFwd to know how much went through +// <-- node.saFwdDeliver: For nodeAccountFwd to know how much went through // --> node.saRevDeliver: Do not exceed. -TER calcNodeDeliverFwd ( +TER nodeDeliverFwd ( RippleCalc& rippleCalc, const unsigned int nodeIndex, // 0 < nodeIndex < lastNodeIndex PathState& pathState, @@ -39,11 +40,11 @@ TER calcNodeDeliverFwd ( STAmount& saInAct, // <-- Amount delivered, this invokation. STAmount& saInFees) // <-- Fees charged, this invokation. { - TER errorCode = tesSUCCESS; + TER resultCode = tesSUCCESS; - PathState::Node& previousNode = pathState.vpnNodes[nodeIndex - 1]; - PathState::Node& node = pathState.vpnNodes[nodeIndex]; - PathState::Node& nextNode = pathState.vpnNodes[nodeIndex + 1]; + auto& previousNode = pathState.nodes()[nodeIndex - 1]; + auto& node = pathState.nodes()[nodeIndex]; + auto& nextNode = pathState.nodes()[nodeIndex + 1]; const uint160& nextAccountID = nextNode.uAccountID; const uint160& uCurCurrencyID = node.uCurrencyID; @@ -73,34 +74,34 @@ TER calcNodeDeliverFwd ( // XXX Perhaps make sure do not exceed saCurDeliverMax as another way to // stop? - while (errorCode == tesSUCCESS && saInAct + saInFees < saInReq) + while (resultCode == tesSUCCESS && saInAct + saInFees < saInReq) { // Did not spend all inbound deliver funds. if (++loopCount > CALC_NODE_DELIVER_MAX_LOOPS) { WriteLog (lsWARNING, RippleCalc) - << "calcNodeDeliverFwd: max loops cndf"; + << "nodeDeliverFwd: max loops cndf"; return rippleCalc.mOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING; } // Determine values for pass to adjust saInAct, saInFees, and // saCurDeliverAct. - errorCode = calcNodeAdvance ( + resultCode = nodeAdvance ( rippleCalc, nodeIndex, pathState, bMultiQuality || saInAct == zero, false); // If needed, advance to next funded offer. - if (errorCode != tesSUCCESS) + if (resultCode != tesSUCCESS) { nothing (); } else if (!uOfferIndex) { WriteLog (lsWARNING, RippleCalc) - << "calcNodeDeliverFwd: INTERNAL ERROR: Ran out of offers."; + << "nodeDeliverFwd: INTERNAL ERROR: Ran out of offers."; return rippleCalc.mOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING; } - else if (errorCode == tesSUCCESS) + else if (resultCode == tesSUCCESS) { // Doesn't charge input. Input funds are in limbo. bool& bEntryAdvance = node.bEntryAdvance; @@ -163,7 +164,7 @@ TER calcNodeDeliverFwd ( STAmount saInPassFees; WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverFwd:" + << "nodeDeliverFwd:" << " nodeIndex=" << nodeIndex << " saOutFunded=" << saOutFunded << " saOutPassFunded=" << saOutPassFunded @@ -182,10 +183,10 @@ TER calcNodeDeliverFwd ( if (!saTakerPays || saInSum <= zero) { WriteLog (lsDEBUG, RippleCalc) - << "calcNodeDeliverFwd: Microscopic offer unfunded."; + << "nodeDeliverFwd: Microscopic offer unfunded."; // After math offer is effectively unfunded. - pathState.vUnfundedBecame.push_back (uOfferIndex); + pathState.becameUnfunded().push_back (uOfferIndex); bEntryAdvance = true; continue; } @@ -193,10 +194,10 @@ TER calcNodeDeliverFwd ( { // Previous check should catch this. WriteLog (lsWARNING, RippleCalc) - << "calcNodeDeliverFwd: UNREACHABLE REACHED"; + << "nodeDeliverFwd: UNREACHABLE REACHED"; // After math offer is effectively unfunded. - pathState.vUnfundedBecame.push_back (uOfferIndex); + pathState.becameUnfunded().push_back (uOfferIndex); bEntryAdvance = true; continue; } @@ -211,7 +212,7 @@ TER calcNodeDeliverFwd ( saInPassFees = saInPassFeesMax; WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverFwd: ? --> OFFER --> account:" + << "nodeDeliverFwd: ? --> OFFER --> account:" << " uOfrOwnerID=" << RippleAddress::createHumanAccountID (uOfrOwnerID) << " nextAccountID=" @@ -221,10 +222,10 @@ TER calcNodeDeliverFwd ( // Output: Debit offer owner, send XRP or non-XPR to next // account. - errorCode = rippleCalc.mActiveLedger.accountSend ( + resultCode = rippleCalc.mActiveLedger.accountSend ( uOfrOwnerID, nextAccountID, saOutPassAct); - if (errorCode != tesSUCCESS) + if (resultCode != tesSUCCESS) break; } else @@ -240,7 +241,7 @@ TER calcNodeDeliverFwd ( // Output fees vary as the next nodes offer owners may vary. // Therefore, immediately push through output for current offer. - errorCode = calcNodeDeliverFwd ( + resultCode = nodeDeliverFwd ( rippleCalc, nodeIndex + 1, pathState, @@ -250,7 +251,7 @@ TER calcNodeDeliverFwd ( saOutPassAct, // <-- Amount delivered. saOutPassFees); // <-- Fees charged. - if (errorCode != tesSUCCESS) + if (resultCode != tesSUCCESS) break; if (saOutPassAct == saOutPassMax) @@ -282,13 +283,13 @@ TER calcNodeDeliverFwd ( rippleCalc.mActiveLedger.accountSend (uOfrOwnerID, id, outPassTotal); WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverFwd: ? --> OFFER --> offer:" + << "nodeDeliverFwd: ? --> OFFER --> offer:" << " saOutPassAct=" << saOutPassAct << " saOutPassFees=" << saOutPassFees; } WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverFwd: " + << "nodeDeliverFwd: " << " nodeIndex=" << nodeIndex << " saTakerGets=" << saTakerGets << " saTakerPays=" << saTakerPays @@ -310,10 +311,10 @@ TER calcNodeDeliverFwd ( // same account. { auto id = !!uPrvCurrencyID ? uInAccountID : ACCOUNT_XRP; - errorCode = rippleCalc.mActiveLedger.accountSend ( + resultCode = rippleCalc.mActiveLedger.accountSend ( id, uOfrOwnerID, saInPassAct); - if (errorCode != tesSUCCESS) + if (resultCode != tesSUCCESS) break; } @@ -327,12 +328,12 @@ TER calcNodeDeliverFwd ( if (saTakerPaysNew < zero || saTakerGetsNew < zero) { WriteLog (lsWARNING, RippleCalc) - << "calcNodeDeliverFwd: NEGATIVE:" + << "nodeDeliverFwd: NEGATIVE:" << " saTakerPaysNew=" << saTakerPaysNew << " saTakerGetsNew=" << saTakerGetsNew; // If mOpenLedger, then ledger is not final, can vote no. - errorCode = rippleCalc.mOpenLedger + resultCode = rippleCalc.mOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING; break; } @@ -347,17 +348,17 @@ TER calcNodeDeliverFwd ( // Offer became unfunded. WriteLog (lsWARNING, RippleCalc) - << "calcNodeDeliverFwd: unfunded:" + << "nodeDeliverFwd: unfunded:" << " saOutPassAct=" << saOutPassAct << " saOutFunded=" << saOutFunded; - pathState.vUnfundedBecame.push_back (uOfferIndex); + pathState.becameUnfunded().push_back (uOfferIndex); bEntryAdvance = true; } else { CondLog (saOutPassAct >= saOutFunded, lsWARNING, RippleCalc) - << "calcNodeDeliverFwd: TOO MUCH:" + << "nodeDeliverFwd: TOO MUCH:" << " saOutPassAct=" << saOutPassAct << " saOutFunded=" << saOutFunded; @@ -374,12 +375,13 @@ TER calcNodeDeliverFwd ( } WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverFwd<" + << "nodeDeliverFwd<" << " nodeIndex=" << nodeIndex << " saInAct=" << saInAct << " saInFees=" << saInFees; - return errorCode; + return resultCode; } +} // path } // ripple diff --git a/src/ripple/module/app/paths/CalcNodeDeliverRev.cpp b/src/ripple/module/app/paths/CalcNodeDeliverRev.cpp index 3e7dad85ad..68b9046470 100644 --- a/src/ripple/module/app/paths/CalcNodeDeliverRev.cpp +++ b/src/ripple/module/app/paths/CalcNodeDeliverRev.cpp @@ -22,6 +22,7 @@ #include namespace ripple { +namespace path { // At the right most node of a list of consecutive offer nodes, given the amount // requested to be delivered, push toward node 0 the amount requested for @@ -33,7 +34,7 @@ namespace ripple { // spent on fees. Continue processing until the request is satisified as long // as the rate does not increase past the initial rate. -TER calcNodeDeliverRev ( +TER nodeDeliverRev ( RippleCalc& rippleCalc, const unsigned int nodeIndex, PathState& pathState, @@ -45,10 +46,10 @@ TER calcNodeDeliverRev ( STAmount& saOutAct) // <-- Funds actually delivered for an // increment. { - TER errorCode = tesSUCCESS; + TER resultCode = tesSUCCESS; - PathState::Node& previousNode = pathState.vpnNodes[nodeIndex - 1]; - PathState::Node& node = pathState.vpnNodes[nodeIndex]; + auto& previousNode = pathState.nodes()[nodeIndex - 1]; + auto& node = pathState.nodes()[nodeIndex]; const uint160& uCurIssuerID = node.uIssuerID; const uint160& uPrvAccountID = previousNode.uAccountID; @@ -71,7 +72,7 @@ TER calcNodeDeliverRev ( saOutAct.clear (saOutReq); WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev>" + << "nodeDeliverRev>" << " saOutAct=" << saOutAct << " saOutReq=" << saOutReq << " saPrvDlvReq=" << saPrvDlvReq; @@ -100,12 +101,12 @@ TER calcNodeDeliverRev ( STAmount& saTakerGets = node.saTakerGets; STAmount& saRateMax = node.saRateMax; - errorCode = calcNodeAdvance ( + resultCode = nodeAdvance ( rippleCalc, nodeIndex, pathState, bMultiQuality || saOutAct == zero, true); // If needed, advance to next funded offer. - if (errorCode != tesSUCCESS || !uOfferIndex) + if (resultCode != tesSUCCESS || !uOfferIndex) { // Error or out of offers. break; @@ -118,7 +119,7 @@ TER calcNodeDeliverRev ( : saTransferRate; // Transfer rate of issuer. WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev:" + << "nodeDeliverRev:" << " uOfrOwnerID=" << RippleAddress::createHumanAccountID (uOfrOwnerID) << " uOutAccountID=" @@ -138,7 +139,7 @@ TER calcNodeDeliverRev ( saRateMax = saOutFeeRate; WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev: Set initial rate:" + << "nodeDeliverRev: Set initial rate:" << " saRateMax=" << saRateMax << " saOutFeeRate=" << saOutFeeRate; } @@ -146,7 +147,7 @@ TER calcNodeDeliverRev ( { // Offer exceeds initial rate. WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev: Offer exceeds initial rate:" + << "nodeDeliverRev: Offer exceeds initial rate:" << " saRateMax=" << saRateMax << " saOutFeeRate=" << saOutFeeRate; @@ -167,7 +168,7 @@ TER calcNodeDeliverRev ( saRateMax = saOutFeeRate; WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev: Reducing rate:" + << "nodeDeliverRev: Reducing rate:" << " saRateMax=" << saRateMax; } @@ -190,7 +191,7 @@ TER calcNodeDeliverRev ( // Offer out with fees. WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev:" + << "nodeDeliverRev:" << " saOutReq=" << saOutReq << " saOutAct=" << saOutAct << " saTakerGets=" << saTakerGets @@ -210,7 +211,7 @@ TER calcNodeDeliverRev ( saOutPassAct = std::min (saOutPassReq, fee); WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev: Total exceeds fees:" + << "nodeDeliverRev: Total exceeds fees:" << " saOutPassAct=" << saOutPassAct << " saOutPlusFees=" << saOutPlusFees << " saOfferFunds=" << saOfferFunds; @@ -223,7 +224,7 @@ TER calcNodeDeliverRev ( STAmount saInPassAct; WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev:" + << "nodeDeliverRev:" << " outputFee=" << outputFee << " saInPassReq=" << saInPassReq << " saOfrRate=" << saOfrRate @@ -234,7 +235,7 @@ TER calcNodeDeliverRev ( { // After rounding did not want anything. WriteLog (lsDEBUG, RippleCalc) - << "calcNodeDeliverRev: micro offer is unfunded."; + << "nodeDeliverRev: micro offer is unfunded."; bEntryAdvance = true; continue; @@ -257,7 +258,7 @@ TER calcNodeDeliverRev ( saInPassAct = saInPassReq; WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev: account --> OFFER --> ? :" + << "nodeDeliverRev: account --> OFFER --> ? :" << " saInPassAct=" << saInPassAct; } else @@ -265,7 +266,7 @@ TER calcNodeDeliverRev ( // offer --> OFFER --> ? // Compute in previous offer node how much could come in. - errorCode = calcNodeDeliverRev ( + resultCode = nodeDeliverRev ( rippleCalc, nodeIndex - 1, pathState, @@ -275,11 +276,11 @@ TER calcNodeDeliverRev ( saInPassAct); WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev: offer --> OFFER --> ? :" + << "nodeDeliverRev: offer --> OFFER --> ? :" << " saInPassAct=" << saInPassAct; } - if (errorCode != tesSUCCESS) + if (resultCode != tesSUCCESS) break; if (saInPassAct < saInPassReq) @@ -293,7 +294,7 @@ TER calcNodeDeliverRev ( saOutPlusFees = std::min (saOfferFunds, outputFees); WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev: adjusted:" + << "nodeDeliverRev: adjusted:" << " saOutPassAct=" << saOutPassAct << " saOutPlusFees=" << saOutPlusFees; } @@ -313,10 +314,10 @@ TER calcNodeDeliverRev ( // visited. However, these deductions and adjustments are tenative. // // Must reset balances when going forward to perform actual transfers. - errorCode = rippleCalc.mActiveLedger.accountSend ( + resultCode = rippleCalc.mActiveLedger.accountSend ( uOfrOwnerID, uCurIssuerID, saOutPassAct); - if (errorCode != tesSUCCESS) + if (resultCode != tesSUCCESS) break; // Adjust offer @@ -326,12 +327,12 @@ TER calcNodeDeliverRev ( if (saTakerPaysNew < zero || saTakerGetsNew < zero) { WriteLog (lsWARNING, RippleCalc) - << "calcNodeDeliverRev: NEGATIVE:" + << "nodeDeliverRev: NEGATIVE:" << " saTakerPaysNew=" << saTakerPaysNew << " saTakerGetsNew=%s" << saTakerGetsNew; // If mOpenLedger then ledger is not final, can vote no. - errorCode = rippleCalc.mOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING; + resultCode = rippleCalc.mOpenLedger ? telFAILED_PROCESSING : tecFAILED_PROCESSING; break; } @@ -344,7 +345,7 @@ TER calcNodeDeliverRev ( { // Offer became unfunded. WriteLog (lsDEBUG, RippleCalc) - << "calcNodeDeliverRev: offer became unfunded."; + << "nodeDeliverRev: offer became unfunded."; bEntryAdvance = true; // XXX When don't we want to set advance? } @@ -359,24 +360,25 @@ TER calcNodeDeliverRev ( } CondLog (saOutAct > saOutReq, lsWARNING, RippleCalc) - << "calcNodeDeliverRev: TOO MUCH:" + << "nodeDeliverRev: TOO MUCH:" << " saOutAct=" << saOutAct << " saOutReq=" << saOutReq; assert (saOutAct <= saOutReq); // XXX Perhaps need to check if partial is okay to relax this? - if (errorCode == tesSUCCESS && !saOutAct) - errorCode = tecPATH_DRY; + if (resultCode == tesSUCCESS && !saOutAct) + resultCode = tecPATH_DRY; // Unable to meet request, consider path dry. WriteLog (lsTRACE, RippleCalc) - << "calcNodeDeliverRev<" + << "nodeDeliverRev<" << " saOutAct=" << saOutAct << " saOutReq=" << saOutReq << " saPrvDlvReq=" << saPrvDlvReq; - return errorCode; + return resultCode; } +} // path } // ripple diff --git a/src/ripple/module/app/paths/CalcNodeOffer.cpp b/src/ripple/module/app/paths/CalcNodeOffer.cpp index 06aef55742..06326f6027 100644 --- a/src/ripple/module/app/paths/CalcNodeOffer.cpp +++ b/src/ripple/module/app/paths/CalcNodeOffer.cpp @@ -22,6 +22,7 @@ #include namespace ripple { +namespace path { // Called to drive the from the first offer node in a chain. // @@ -31,15 +32,15 @@ namespace ripple { // - Transfer fees credited to issuer. // - Payout to issuer or limbo. // - Deliver is set without transfer fees. -TER calcNodeOfferFwd ( +TER nodeOfferFwd ( RippleCalc& rippleCalc, const unsigned int nodeIndex, PathState& pathState, const bool bMultiQuality ) { - TER errorCode; - PathState::Node& previousNode = pathState.vpnNodes [nodeIndex - 1]; + TER resultCode; + auto& previousNode = pathState.nodes() [nodeIndex - 1]; if (!!previousNode.uAccountID) { @@ -47,7 +48,7 @@ TER calcNodeOfferFwd ( STAmount saInAct; STAmount saInFees; - errorCode = calcNodeDeliverFwd ( + resultCode = nodeDeliverFwd ( rippleCalc, nodeIndex, pathState, @@ -57,30 +58,30 @@ TER calcNodeOfferFwd ( saInAct, saInFees); - assert (errorCode != tesSUCCESS || + assert (resultCode != tesSUCCESS || previousNode.saFwdDeliver == saInAct + saInFees); } else { // Previous is an offer. Deliver has already been resolved. - errorCode = tesSUCCESS; + resultCode = tesSUCCESS; } - return errorCode; + return resultCode; } // Called to drive from the last offer node in a chain. -TER calcNodeOfferRev ( +TER nodeOfferRev ( RippleCalc& rippleCalc, const unsigned int nodeIndex, PathState& pathState, const bool bMultiQuality) { - TER errorCode; + TER resultCode; - PathState::Node& node = pathState.vpnNodes [nodeIndex]; - PathState::Node& nextNode = pathState.vpnNodes [nodeIndex + 1]; + auto& node = pathState.nodes() [nodeIndex]; + auto& nextNode = pathState.nodes() [nodeIndex + 1]; if (!!nextNode.uAccountID) { @@ -88,11 +89,11 @@ TER calcNodeOfferRev ( STAmount saDeliverAct; WriteLog (lsTRACE, RippleCalc) - << "calcNodeOfferRev: OFFER --> account:" + << "nodeOfferRev: OFFER --> account:" << " nodeIndex=" << nodeIndex << " saRevDeliver=" << node.saRevDeliver; - errorCode = calcNodeDeliverRev ( + resultCode = nodeDeliverRev ( rippleCalc, nodeIndex, pathState, @@ -106,13 +107,14 @@ TER calcNodeOfferRev ( else { WriteLog (lsTRACE, RippleCalc) - << "calcNodeOfferRev: OFFER --> offer: nodeIndex=" << nodeIndex; + << "nodeOfferRev: OFFER --> offer: nodeIndex=" << nodeIndex; // Next is an offer. Deliver has already been resolved. - errorCode = tesSUCCESS; + resultCode = tesSUCCESS; } - return errorCode; + return resultCode; } -} // ripple +} // path +} // ripple diff --git a/src/ripple/module/app/paths/CalcNodeRipple.cpp b/src/ripple/module/app/paths/CalcNodeRipple.cpp index 4784a9cd11..aff0c9854e 100644 --- a/src/ripple/module/app/paths/CalcNodeRipple.cpp +++ b/src/ripple/module/app/paths/CalcNodeRipple.cpp @@ -22,6 +22,7 @@ #include namespace ripple { +namespace path { // Compute how much might flow for the node for the pass. Does not actually // adjust balances. @@ -45,7 +46,7 @@ namespace ripple { // This routine is called one or two times for a node in a pass. If called once, // it will work and set a rate. If called again, the new work must not worsen // the previous rate. -void calcNodeRipple ( +void nodeRipple ( RippleCalc& rippleCalc, const std::uint32_t uQualityIn, const std::uint32_t uQualityOut, @@ -56,7 +57,7 @@ void calcNodeRipple ( std::uint64_t& uRateMax) { WriteLog (lsTRACE, RippleCalc) - << "calcNodeRipple>" + << "nodeRipple>" << " uQualityIn=" << uQualityIn << " uQualityOut=" << uQualityOut << " saPrvReq=" << saPrvReq @@ -75,7 +76,7 @@ void calcNodeRipple ( const STAmount saCur = saCurReq - saCurAct; WriteLog (lsTRACE, RippleCalc) - << "calcNodeRipple: " + << "nodeRipple: " << " bPrvUnlimited=" << bPrvUnlimited << " saPrv=" << saPrv << " saCur=" << saCur; @@ -83,7 +84,7 @@ void calcNodeRipple ( if (uQualityIn >= uQualityOut) { // No fee. - WriteLog (lsTRACE, RippleCalc) << "calcNodeRipple: No fees"; + WriteLog (lsTRACE, RippleCalc) << "nodeRipple: No fees"; // Only process if we are not worsing previously processed. if (!uRateMax || STAmount::uRateOne <= uRateMax) @@ -109,7 +110,7 @@ void calcNodeRipple ( else { // Fee. - WriteLog (lsTRACE, RippleCalc) << "calcNodeRipple: Fee"; + WriteLog (lsTRACE, RippleCalc) << "nodeRipple: Fee"; std::uint64_t uRate = STAmount::getRate ( STAmount (uQualityOut), STAmount (uQualityIn)); @@ -127,7 +128,7 @@ void calcNodeRipple ( someFee, uQualityIn, uCurrencyID, uCurIssuerID, true); WriteLog (lsTRACE, RippleCalc) - << "calcNodeRipple:" + << "nodeRipple:" << " bPrvUnlimited=" << bPrvUnlimited << " saPrv=" << saPrv << " saCurIn=" << saCurIn; @@ -138,7 +139,7 @@ void calcNodeRipple ( saCurAct += saCur; saPrvAct += saCurIn; WriteLog (lsTRACE, RippleCalc) - << "calcNodeRipple:3c:" + << "nodeRipple:3c:" << " saCurReq=" << saCurReq << " saPrvAct=" << saPrvAct; } @@ -151,7 +152,7 @@ void calcNodeRipple ( STAmount saCurOut = STAmount::divRound ( someFee, uQualityOut, uCurrencyID, uCurIssuerID, true); WriteLog (lsTRACE, RippleCalc) - << "calcNodeRipple:4: saCurReq=" << saCurReq; + << "nodeRipple:4: saCurReq=" << saCurReq; saCurAct += saCurOut; saPrvAct = saPrvReq; @@ -163,7 +164,7 @@ void calcNodeRipple ( } WriteLog (lsTRACE, RippleCalc) - << "calcNodeRipple<" + << "nodeRipple<" << " uQualityIn=" << uQualityIn << " uQualityOut=" << uQualityOut << " saPrvReq=" << saPrvReq @@ -172,4 +173,5 @@ void calcNodeRipple ( << " saCurAct=" << saCurAct; } +} // path } // ripple diff --git a/src/ripple/module/app/paths/CalcState.h b/src/ripple/module/app/paths/CalcState.h index 5b837d288f..d3be62acbf 100644 --- a/src/ripple/module/app/paths/CalcState.h +++ b/src/ripple/module/app/paths/CalcState.h @@ -24,7 +24,8 @@ namespace ripple { typedef TER ErrorCode; -class CalcState { +class CalcState +{ public: CalcState( unsigned int nodeIndex, PathState& state, LedgerEntrySet& ledger, bool quality) @@ -43,42 +44,6 @@ class CalcState { void nextPath(LedgerEntrySet const& checkpoint) const; private: - enum NodeCursor { FIRST, PREVIOUS, CURRENT, NEXT, LAST }; - - unsigned int index(NodeCursor cursor = CURRENT) const - { - switch (cursor) { - case FIRST: - return 0; - case PREVIOUS: - return nodeIndex_ ? nodeIndex_ - 1 : 0; - case CURRENT: - return nodeIndex_; - default: - break; - } - unsigned int size = pathState_.vpnNodes.size (); - auto last = size ? size - 1 : 0; - switch (cursor) { - case NEXT: - return std::min(nodeIndex_ + 1, last); - case LAST: - return last; - default: - bassert(false); - } - } - - PathState::Node& node(NodeCursor cursor = CURRENT) - { - return pathState_.vpnNodes[index(cursor)]; - } - - CalcState state(NodeCursor cursor = CURRENT) - { - return CalcState(index(cursor), pathState_, ledger_, quality_); - } - LedgerEntrySet& ledger() { return ledger_; @@ -96,16 +61,6 @@ class CalcState { bool const quality_; }; -inline bool isAccount(PathState::Node const& node) -{ - return is_bit_set (node.uFlags, STPathElement::typeAccount); -} - -inline STAmount copyCurrencyAndIssuer(const STAmount& a) -{ - return STAmount(a.getCurrency(), a.getIssuer()); -} - } // ripple #endif diff --git a/src/ripple/module/app/paths/Calculators.h b/src/ripple/module/app/paths/Calculators.h index 5bc9703c41..2bc4505159 100644 --- a/src/ripple/module/app/paths/Calculators.h +++ b/src/ripple/module/app/paths/Calculators.h @@ -20,17 +20,29 @@ #ifndef RIPPLE_PATHS_CALCULATORS_H #define RIPPLE_PATHS_CALCULATORS_H +#include + +#include +#include +#include +#include + namespace ripple { -// TODO(vfalco) What's the difference between a RippleState versus PathState? -// -struct RippleCalc +/** RippleCalc calculates the quality of a payment path. + + Quality is the amount of input required to produce a given output along a + specified path. Most people would call this an exchange rate. +*/ +class RippleCalc { +public: LedgerEntrySet& mActiveLedger; bool mOpenLedger; + // First time working in reverse a funding source was mentioned. Source may // only be used there. - // + // Map of currency, issuer to node index. AccountCurrencyIssuerToNodeIndex mumSource; @@ -44,38 +56,42 @@ struct RippleCalc : mActiveLedger (activeLedger), mOpenLedger (bOpenLedger) { } - }; +namespace path { + void pathNext ( RippleCalc&, PathState& pathState, const bool bMultiQuality, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent); -TER calcNodeRev ( +TER nodeRev ( RippleCalc&, unsigned int nodeIndex, PathState& pathState, bool bMultiQuality); -TER calcNodeFwd ( +TER nodeFwd ( RippleCalc&, unsigned int nodeIndex, PathState& pathState, bool bMultiQuality); -TER calcNodeOfferRev ( +TER nodeOfferRev ( RippleCalc&, unsigned int nodeIndex, PathState& pathState, bool bMultiQuality); -TER calcNodeOfferFwd ( +TER nodeOfferFwd ( RippleCalc&, unsigned int nodeIndex, PathState& pathState, bool bMultiQuality); -TER calcNodeAccountRev ( +TER nodeAccountRev ( RippleCalc&, unsigned int nodeIndex, PathState& pathState, bool bMultiQuality); -TER calcNodeAccountFwd ( +TER nodeAccountFwd ( RippleCalc&, unsigned int nodeIndex, PathState& pathState, bool bMultiQuality); -TER calcNodeAdvance ( + +// To send money out of an account. +TER nodeAdvance ( RippleCalc&, unsigned int nodeIndex, PathState& pathState, bool bMultiQuality, bool bReverse); -TER calcNodeDeliverRev ( +// To deliver from an order book. +TER nodeDeliverRev ( RippleCalc&, const unsigned int nodeIndex, PathState& pathState, @@ -84,7 +100,7 @@ TER calcNodeDeliverRev ( const STAmount& saOutReq, STAmount& saOutAct); -TER calcNodeDeliverFwd ( +TER nodeDeliverFwd ( RippleCalc&, const unsigned int nodeIndex, PathState& pathState, @@ -94,16 +110,17 @@ TER calcNodeDeliverFwd ( STAmount& saInAct, STAmount& saInFees); -void calcNodeRipple ( +void nodeRipple ( RippleCalc&, - const std::uint32_t uQualityIn, const std::uint32_t uQualityOut, - const STAmount& saPrvReq, const STAmount& saCurReq, - STAmount& saPrvAct, STAmount& saCurAct, std::uint64_t& uRateMax); - -void setCanonical ( - STPathSet& spsDst, const std::vector& vpsExpanded, - bool bKeepDefault); + const std::uint32_t uQualityIn, + const std::uint32_t uQualityOut, + const STAmount& saPrvReq, + const STAmount& saCurReq, + STAmount& saPrvAct, + STAmount& saCurAct, + std::uint64_t& uRateMax); +} // path } // ripple #endif diff --git a/src/ripple/module/app/paths/Node.cpp b/src/ripple/module/app/paths/Node.cpp new file mode 100644 index 0000000000..d93e1d8f17 --- /dev/null +++ b/src/ripple/module/app/paths/Node.cpp @@ -0,0 +1,82 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +namespace ripple { +namespace path { + +// Compare the non-calculated fields. +bool Node::operator== (const Node& other) const +{ + return other.uFlags == uFlags + && other.uAccountID == uAccountID + && other.uCurrencyID == uCurrencyID + && other.uIssuerID == uIssuerID; +} + +// This is for debugging not end users. Output names can be changed without warning. +Json::Value Node::getJson () const +{ + Json::Value jvNode (Json::objectValue); + Json::Value jvFlags (Json::arrayValue); + + jvNode["type"] = uFlags; + + if (isAccount() || !!uAccountID) + jvFlags.append (!isAccount() == !!uAccountID ? "account" : "-account"); + + if (is_bit_set (uFlags, STPathElement::typeCurrency) || !!uCurrencyID) + jvFlags.append (!!is_bit_set (uFlags, STPathElement::typeCurrency) == !!uCurrencyID ? "currency" : "-currency"); + + if (is_bit_set (uFlags, STPathElement::typeIssuer) || !!uIssuerID) + jvFlags.append (!!is_bit_set (uFlags, STPathElement::typeIssuer) == !!uIssuerID ? "issuer" : "-issuer"); + + jvNode["flags"] = jvFlags; + + if (!!uAccountID) + jvNode["account"] = RippleAddress::createHumanAccountID (uAccountID); + + if (!!uCurrencyID) + jvNode["currency"] = STAmount::createHumanCurrency (uCurrencyID); + + if (!!uIssuerID) + jvNode["issuer"] = RippleAddress::createHumanAccountID (uIssuerID); + + if (saRevRedeem) + jvNode["rev_redeem"] = saRevRedeem.getFullText (); + + if (saRevIssue) + jvNode["rev_issue"] = saRevIssue.getFullText (); + + if (saRevDeliver) + jvNode["rev_deliver"] = saRevDeliver.getFullText (); + + if (saFwdRedeem) + jvNode["fwd_redeem"] = saFwdRedeem.getFullText (); + + if (saFwdIssue) + jvNode["fwd_issue"] = saFwdIssue.getFullText (); + + if (saFwdDeliver) + jvNode["fwd_deliver"] = saFwdDeliver.getFullText (); + + return jvNode; +} + +} // path +} // ripple diff --git a/src/ripple/module/app/paths/Node.h b/src/ripple/module/app/paths/Node.h new file mode 100644 index 0000000000..b86b137d19 --- /dev/null +++ b/src/ripple/module/app/paths/Node.h @@ -0,0 +1,95 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_APP_PATH_NODE_H +#define RIPPLE_APP_PATH_NODE_H + +namespace ripple { +namespace path { + +struct Node +{ + typedef std::vector List; + + inline bool isAccount() const + { + return is_bit_set (uFlags, STPathElement::typeAccount); + } + + Json::Value getJson () const; + + bool operator == (Node const&) const; + + std::uint16_t uFlags; // --> From path. + + uint160 uAccountID; // --> Accounts: Recieving/sending account. + uint160 uCurrencyID; // --> Accounts: Receive and send, Offers: send. + // --- For offer's next has currency out. + uint160 uIssuerID; // --> Currency's issuer + + STAmount saTransferRate; // Transfer rate for uIssuerID. + + // Computed by Reverse. + STAmount saRevRedeem; // <-- Amount to redeem to next. + STAmount saRevIssue; // <-- Amount to issue to next, limited by + // credit and outstanding IOUs. Issue + // isn't used by offers. + STAmount saRevDeliver; // <-- Amount to deliver to next regardless of fee. + + // Computed by forward. + STAmount saFwdRedeem; // <-- Amount node will redeem to next. + STAmount saFwdIssue; // <-- Amount node will issue to next. + // Issue isn't used by offers. + STAmount saFwdDeliver; // <-- Amount to deliver to next regardless of fee. + + // For offers: + + STAmount saRateMax; + + // The nodes are partitioned into a buckets called "directories". + // + // Each "directory" contains nodes with exactly the same "quality" (meaning + // the conversion rate between one corrency and the next). + // + // The "directories" are ordered in "increasing" "quality" value, which + // means that the first "directory" has the "best" (i.e. numerically least) + // "quality". + uint256 uDirectTip; // Current directory. + uint256 uDirectEnd; // Next order book. + bool bDirectAdvance; // Need to advance directory. + bool bDirectRestart; // Need to restart directory. + SLE::pointer sleDirectDir; + STAmount saOfrRate; // For correct ratio. + + // PaymentNode + bool bEntryAdvance; // Need to advance entry. + unsigned int uEntry; + uint256 uOfferIndex; + SLE::pointer sleOffer; + uint160 uOfrOwnerID; + bool bFundsDirty; // Need to refresh saOfferFunds, saTakerPays, & saTakerGets. + STAmount saOfferFunds; + STAmount saTakerPays; + STAmount saTakerGets; +}; + +} // path +} // ripple + +#endif diff --git a/src/ripple/module/app/paths/PathNext.cpp b/src/ripple/module/app/paths/PathNext.cpp index 5514def2ca..d752cf6329 100644 --- a/src/ripple/module/app/paths/PathNext.cpp +++ b/src/ripple/module/app/paths/PathNext.cpp @@ -23,6 +23,7 @@ #include namespace ripple { +namespace path { // Calculate the next increment of a path. // @@ -38,28 +39,19 @@ void pathNext ( { // The next state is what is available in preference order. // This is calculated when referenced accounts changed. - const unsigned int lastNodeIndex = pathState.vpnNodes.size () - 1; - pathState.bConsumed = false; - - // YYY This clearing should only be needed for nice logging. - pathState.saInPass = STAmount ( - pathState.saInReq.getCurrency (), pathState.saInReq.getIssuer ()); - pathState.saOutPass = STAmount ( - pathState.saOutReq.getCurrency (), pathState.saOutReq.getIssuer ()); - - pathState.vUnfundedBecame.clear (); - pathState.umReverse.clear (); + const unsigned int lastNodeIndex = pathState.nodes().size () - 1; + pathState.clear(); WriteLog (lsTRACE, RippleCalc) << "pathNext: Path In: " << pathState.getJson (); - assert (pathState.vpnNodes.size () >= 2); + assert (pathState.nodes().size () >= 2); lesCurrent = lesCheckpoint.duplicate (); // Restore from checkpoint. - for (unsigned int uIndex = pathState.vpnNodes.size (); uIndex--;) + for (unsigned int uIndex = pathState.nodes().size (); uIndex--;) { - auto& node = pathState.vpnNodes[uIndex]; + auto& node = pathState.nodes()[uIndex]; node.saRevRedeem.clear (); node.saRevIssue.clear (); @@ -67,40 +59,41 @@ void pathNext ( node.saFwdDeliver.clear (); } - pathState.terStatus = calcNodeRev (rippleCalc, lastNodeIndex, pathState, bMultiQuality); + pathState.setStatus(nodeRev (rippleCalc, lastNodeIndex, pathState, bMultiQuality)); WriteLog (lsTRACE, RippleCalc) << "pathNext: Path after reverse: " << pathState.getJson (); - if (tesSUCCESS == pathState.terStatus) + if (tesSUCCESS == pathState.status()) { // Do forward. lesCurrent = lesCheckpoint.duplicate (); // Restore from checkpoint. - pathState.terStatus = calcNodeFwd (rippleCalc, 0, pathState, bMultiQuality); + pathState.setStatus(nodeFwd (rippleCalc, 0, pathState, bMultiQuality)); } - if (tesSUCCESS == pathState.terStatus) + if (tesSUCCESS == pathState.status()) { - CondLog (!pathState.saInPass || !pathState.saOutPass, lsDEBUG, RippleCalc) - << "pathNext: Error calcNodeFwd reported success for nothing:" - << " saOutPass=" << pathState.saOutPass - << " saInPass=" << pathState.saInPass; + CondLog (!pathState.inPass() || !pathState.outPass(), lsDEBUG, RippleCalc) + << "pathNext: Error nodeFwd reported success for nothing:" + << " saOutPass=" << pathState.outPass() + << " inPass()=" << pathState.inPass(); - if (!pathState.saOutPass || !pathState.saInPass) + if (!pathState.outPass() || !pathState.inPass()) throw std::runtime_error ("Made no progress."); // Calculate relative quality. - pathState.uQuality = STAmount::getRate ( - pathState.saOutPass, pathState.saInPass); + pathState.setQuality(STAmount::getRate ( + pathState.outPass(), pathState.inPass())); WriteLog (lsTRACE, RippleCalc) << "pathNext: Path after forward: " << pathState.getJson (); } else { - pathState.uQuality = 0; + pathState.setQuality(0); } } +} // path } // ripple diff --git a/src/ripple/module/app/paths/PathRequest.cpp b/src/ripple/module/app/paths/PathRequest.cpp index c06418acbc..40ac7d5fcb 100644 --- a/src/ripple/module/app/paths/PathRequest.cpp +++ b/src/ripple/module/app/paths/PathRequest.cpp @@ -18,6 +18,7 @@ //============================================================================== #include +#include #include @@ -417,34 +418,34 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast) STPath extraPath; if (valid && pf.findPaths (iLevel, 4, spsPaths, extraPath)) { - LedgerEntrySet lesSandbox (cache->getLedger (), tapNONE); - std::vector vpsExpanded; - STAmount saMaxAmountAct; - STAmount saDstAmountAct; - STAmount saMaxAmount (currIssuer.first, + LedgerEntrySet lesSandbox (cache->getLedger (), tapNONE); + PathState::List pathStateList; + STAmount saMaxAmountAct; + STAmount saDstAmountAct; + STAmount saMaxAmount (currIssuer.first, currIssuer.second.isNonZero () ? currIssuer.second : (currIssuer.first.isZero () ? ACCOUNT_XRP : raSrcAccount.getAccountID ()), 1); saMaxAmount.negate (); m_journal.debug << iIdentifier << " Paths found, calling rippleCalc"; - TER errorCode = rippleCalculate (lesSandbox, saMaxAmountAct, saDstAmountAct, - vpsExpanded, saMaxAmount, saDstAmount, + TER resultCode = path::rippleCalculate (lesSandbox, saMaxAmountAct, saDstAmountAct, + pathStateList, saMaxAmount, saDstAmount, raDstAccount.getAccountID (), raSrcAccount.getAccountID (), spsPaths, false, false, false, true); - if ((extraPath.size() > 0) && ((errorCode == terNO_LINE) || (errorCode == tecPATH_PARTIAL))) + if ((extraPath.size() > 0) && ((resultCode == terNO_LINE) || (resultCode == tecPATH_PARTIAL))) { m_journal.debug << iIdentifier << " Trying with an extra path element"; spsPaths.addPath(extraPath); - vpsExpanded.clear (); - errorCode = rippleCalculate (lesSandbox, saMaxAmountAct, saDstAmountAct, - vpsExpanded, saMaxAmount, saDstAmount, + 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 (errorCode); + m_journal.debug << iIdentifier << " Extra path element gives " << transHuman (resultCode); } - if (errorCode == tesSUCCESS) + if (resultCode == tesSUCCESS) { Json::Value jvEntry (Json::objectValue); jvEntry["source_amount"] = saMaxAmountAct.getJson (0); @@ -454,7 +455,7 @@ Json::Value PathRequest::doUpdate (RippleLineCache::ref cache, bool fast) } else { - m_journal.debug << iIdentifier << " rippleCalc returns " << transHuman (errorCode); + m_journal.debug << iIdentifier << " rippleCalc returns " << transHuman (resultCode); } } else diff --git a/src/ripple/module/app/paths/PathRequest.h b/src/ripple/module/app/paths/PathRequest.h index 8520fcbab3..3c94b7e241 100644 --- a/src/ripple/module/app/paths/PathRequest.h +++ b/src/ripple/module/app/paths/PathRequest.h @@ -50,10 +50,9 @@ public: // VFALCO TODO Break the cyclic dependency on InfoSub PathRequest (std::shared_ptr const& subscriber, int id, PathRequests&, beast::Journal journal); - + ~PathRequest (); - bool isValid (RippleLineCache::ref crCache); bool isValid (); bool isNew (); bool needsUpdate (bool newOnly, LedgerIndex index); @@ -68,6 +67,7 @@ public: InfoSub::pointer getSubscriber (); private: + bool isValid (RippleLineCache::ref crCache); void setValid (); void resetLevel (int level); int parseJson (const Json::Value&, bool complete); diff --git a/src/ripple/module/app/paths/PathState.cpp b/src/ripple/module/app/paths/PathState.cpp index 5008d53606..3231e43095 100644 --- a/src/ripple/module/app/paths/PathState.cpp +++ b/src/ripple/module/app/paths/PathState.cpp @@ -19,14 +19,11 @@ namespace ripple { -// TODO: -// - Do automatic bridging via XRP. -// -// OPTIMIZE: When calculating path increment, note if increment consumes all liquidity. No need to revisit path in the future if -// all liquidity is used. +// OPTIMIZE: When calculating path increment, note if increment consumes all +// liquidity. No need to revisit path in the future if all liquidity is used. // -struct RippleCalc; // for logging +class RippleCalc; // for logging std::size_t hash_value (const AccountCurrencyIssuer& asValue) { @@ -34,68 +31,14 @@ std::size_t hash_value (const AccountCurrencyIssuer& asValue) return beast::hardened_hash{seed}(asValue); } -// Compare the non-calculated fields. -bool PathState::Node::operator== (const Node& pnOther) const -{ - return pnOther.uFlags == uFlags - && pnOther.uAccountID == uAccountID - && pnOther.uCurrencyID == uCurrencyID - && pnOther.uIssuerID == uIssuerID; +void PathState::clear() { + allLiquidityConsumed_ = false; + saInPass = zeroed (saInReq); + saOutPass = zeroed (saOutReq); + vUnfundedBecame.clear (); + umReverse.clear (); } -// This is for debugging not end users. Output names can be changed without warning. -Json::Value PathState::Node::getJson () const -{ - Json::Value jvNode (Json::objectValue); - Json::Value jvFlags (Json::arrayValue); - - jvNode["type"] = uFlags; - - if (is_bit_set (uFlags, STPathElement::typeAccount) || !!uAccountID) - jvFlags.append (!!is_bit_set (uFlags, STPathElement::typeAccount) == !!uAccountID ? "account" : "-account"); - - if (is_bit_set (uFlags, STPathElement::typeCurrency) || !!uCurrencyID) - jvFlags.append (!!is_bit_set (uFlags, STPathElement::typeCurrency) == !!uCurrencyID ? "currency" : "-currency"); - - if (is_bit_set (uFlags, STPathElement::typeIssuer) || !!uIssuerID) - jvFlags.append (!!is_bit_set (uFlags, STPathElement::typeIssuer) == !!uIssuerID ? "issuer" : "-issuer"); - - jvNode["flags"] = jvFlags; - - if (!!uAccountID) - jvNode["account"] = RippleAddress::createHumanAccountID (uAccountID); - - if (!!uCurrencyID) - jvNode["currency"] = STAmount::createHumanCurrency (uCurrencyID); - - if (!!uIssuerID) - jvNode["issuer"] = RippleAddress::createHumanAccountID (uIssuerID); - - if (saRevRedeem) - jvNode["rev_redeem"] = saRevRedeem.getFullText (); - - if (saRevIssue) - jvNode["rev_issue"] = saRevIssue.getFullText (); - - if (saRevDeliver) - jvNode["rev_deliver"] = saRevDeliver.getFullText (); - - if (saFwdRedeem) - jvNode["fwd_redeem"] = saFwdRedeem.getFullText (); - - if (saFwdIssue) - jvNode["fwd_issue"] = saFwdIssue.getFullText (); - - if (saFwdDeliver) - jvNode["fwd_deliver"] = saFwdDeliver.getFullText (); - - return jvNode; -} - -// -// PathState implementation -// - // Return true, iff lhs has less priority than rhs. bool PathState::lessPriority (PathState& lhs, PathState& rhs) { @@ -113,23 +56,28 @@ bool PathState::lessPriority (PathState& lhs, PathState& rhs) // Make sure last path node delivers to uAccountID: uCurrencyID from uIssuerID. // -// If the unadded next node as specified by arguments would not work as is, then add the necessary nodes so it would work. +// If the unadded next node as specified by arguments would not work as is, then +// add the necessary nodes so it would work. +// PRECONDITION: the PathState must be non-empty. // // Rules: // - Currencies must be converted via an offer. -// - A node names it's output. -// - A ripple nodes output issuer must be the node's account or the next node's account. -// - Offers can only go directly to another offer if the currency and issuer are an exact match. +// - A node names its output. + +// - A ripple nodes output issuer must be the node's account or the next node's +// account. +// - Offers can only go directly to another offer if the currency and issuer are +// an exact match. // - Real issuers must be specified for non-XRP. TER PathState::pushImply ( const uint160& uAccountID, // --> Delivering to this account. const uint160& uCurrencyID, // --> Delivering this currency. const uint160& uIssuerID) // --> Delivering this issuer. { - const Node& previousNode = vpnNodes.back (); - TER errorCode = tesSUCCESS; + auto const& previousNode = nodes_.back (); + TER resultCode = tesSUCCESS; - WriteLog (lsTRACE, RippleCalc) << "pushImply>" << + WriteLog (lsTRACE, RippleCalc) << "pushImply>" << " " << RippleAddress::createHumanAccountID (uAccountID) << " " << STAmount::createHumanCurrency (uCurrencyID) << " " << RippleAddress::createHumanAccountID (uIssuerID); @@ -137,8 +85,14 @@ TER PathState::pushImply ( if (previousNode.uCurrencyID != uCurrencyID) { // Currency is different, need to convert via an offer. + // Currency is different, need to convert via an offer from an order + // book. ACCOUNT_XRP does double duty as signaling "this is an order + // book". - errorCode = pushNode ( // Offer. + // Corresponds to "Implies an offer directory" in the diagram, currently + // at https://docs.google.com/a/ripple.com/document/d/1b1RC8pKIgVZqUmjf9MW4IYxvzU7cBla4-pCSBbV4u8Q/edit + + resultCode = pushNode ( // Offer. !!uCurrencyID ? STPathElement::typeCurrency | STPathElement::typeIssuer : STPathElement::typeCurrency, @@ -147,48 +101,54 @@ TER PathState::pushImply ( uIssuerID); } - const Node& pnBck = vpnNodes.back (); + auto const& pnBck = nodes_.back (); // For ripple, non-XRP, ensure the issuer is on at least one side of the transaction. - if (errorCode == tesSUCCESS + if (resultCode == tesSUCCESS && !!uCurrencyID // Not XRP. && (pnBck.uAccountID != uIssuerID // Previous is not issuing own IOUs. && uAccountID != uIssuerID)) // Current is not receiving own IOUs. { // Need to ripple through uIssuerID's account. - - errorCode = pushNode ( + // Case "Implies an another node: (pushImply)" in the document. + resultCode = pushNode ( STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer, uIssuerID, // Intermediate account is the needed issuer. uCurrencyID, uIssuerID); } - WriteLog (lsTRACE, RippleCalc) << "pushImply< : " << transToken (errorCode); + WriteLog (lsTRACE, RippleCalc) << "pushImply< : " << transToken (resultCode); - return errorCode; + return resultCode; } -// Append a node and insert before it any implied nodes. -// Offers may go back to back. -// <-- errorCode: tesSUCCESS, temBAD_PATH, terNO_ACCOUNT, terNO_AUTH, terNO_LINE, tecPATH_DRY +// Append a node, then create and insert before it any implied nodes. Order +// book nodes may go back to back. +// +// For each non-matching pair of IssuedCurrency, there's an order book. +// +// <-- resultCode: tesSUCCESS, temBAD_PATH, terNO_ACCOUNT, terNO_AUTH, terNO_LINE, tecPATH_DRY TER PathState::pushNode ( const int iType, - const uint160& uAccountID, - const uint160& uCurrencyID, - const uint160& uIssuerID) + const uint160& uAccountID, // If not specified, means an order book. + const uint160& uCurrencyID, // If not specified, default to previous. + const uint160& uIssuerID) // If not specified, default to previous. { - Node node; - const bool bFirst = vpnNodes.empty (); - const Node& previousNode = bFirst ? Node () : vpnNodes.back (); + path::Node node; + const bool bFirst = nodes_.empty (); + auto const& previousNode = bFirst ? path::Node () : nodes_.back (); + // true, iff node is a ripple account. false, iff node is an offer node. - const bool bAccount = is_bit_set (iType, STPathElement::typeAccount); - // true, iff currency supplied. - // Currency is specified for the output of the current node. - const bool bCurrency = is_bit_set (iType, STPathElement::typeCurrency); + const bool bAccount = is_bit_set (iType, STPathElement::typeAccount); + + // Is currency specified for the output of the current node? + const bool bCurrency = is_bit_set (iType, STPathElement::typeCurrency); + // Issuer is specified for the output of the current node. - const bool bIssuer = is_bit_set (iType, STPathElement::typeIssuer); - TER errorCode = tesSUCCESS; + const bool bIssuer = is_bit_set (iType, STPathElement::typeIssuer); + + TER resultCode = tesSUCCESS; WriteLog (lsTRACE, RippleCalc) << "pushNode> " << iType << @@ -196,32 +156,34 @@ TER PathState::pushNode ( " " << (bCurrency ? STAmount::createHumanCurrency (uCurrencyID) : "-") << "/" << (bIssuer ? RippleAddress::createHumanAccountID (uIssuerID) : "-"); - node.uFlags = iType; - node.uCurrencyID = bCurrency ? uCurrencyID : previousNode.uCurrencyID; + node.uFlags = iType; + node.uCurrencyID = bCurrency ? uCurrencyID : previousNode.uCurrencyID; if (iType & ~STPathElement::typeValidBits) { WriteLog (lsDEBUG, RippleCalc) << "pushNode: bad bits."; - errorCode = temBAD_PATH; + resultCode = temBAD_PATH; } else if (bIssuer && !node.uCurrencyID) { WriteLog (lsDEBUG, RippleCalc) << "pushNode: issuer specified for XRP."; - errorCode = temBAD_PATH; + resultCode = temBAD_PATH; } else if (bIssuer && !uIssuerID) { WriteLog (lsDEBUG, RippleCalc) << "pushNode: specified bad issuer."; - errorCode = temBAD_PATH; + resultCode = temBAD_PATH; } else if (!bAccount && !bCurrency && !bIssuer) { + // You can't default everything to the previous node as you would make + // no progress. WriteLog (lsDEBUG, RippleCalc) << "pushNode: offer must specify at least currency or issuer."; - errorCode = temBAD_PATH; + resultCode = temBAD_PATH; } else if (bAccount) { @@ -230,11 +192,14 @@ TER PathState::pushNode ( node.uAccountID = uAccountID; node.uIssuerID = bIssuer ? uIssuerID - : !!node.uCurrencyID + : !!node.uCurrencyID // Not XRP. ? uAccountID : ACCOUNT_XRP; + // Zero value - for accounts. node.saRevRedeem = STAmount (node.uCurrencyID, uAccountID); - node.saRevIssue = STAmount (node.uCurrencyID, uAccountID); + node.saRevIssue = node.saRevRedeem; + + // For order books only - zero currency with the issuer ID. node.saRevDeliver = STAmount (node.uCurrencyID, node.uIssuerID); node.saFwdDeliver = node.saRevDeliver; @@ -248,14 +213,14 @@ TER PathState::pushNode ( { WriteLog (lsDEBUG, RippleCalc) << "pushNode: specified bad account."; - errorCode = temBAD_PATH; + resultCode = temBAD_PATH; } else { // Add required intermediate nodes to deliver to current account. WriteLog (lsTRACE, RippleCalc) << "pushNode: imply for account."; - errorCode = pushImply ( + resultCode = pushImply ( node.uAccountID, // Current account. node.uCurrencyID, // Wanted currency. !!node.uCurrencyID ? uAccountID : ACCOUNT_XRP); // Account as wanted issuer. @@ -263,15 +228,17 @@ TER PathState::pushNode ( // Note: previousNode may no longer be the immediately previous node. } - if (errorCode == tesSUCCESS && !vpnNodes.empty ()) + if (resultCode == tesSUCCESS && !nodes_.empty ()) { - const Node& pnBck = vpnNodes.back (); - bool bBckAccount = is_bit_set (pnBck.uFlags, STPathElement::typeAccount); + auto const& pnBck = nodes_.back (); + bool bBckAccount = pnBck.isAccount(); if (bBckAccount) { SLE::pointer sleRippleState = lesEntries.entryCache (ltRIPPLE_STATE, Ledger::getRippleStateIndex (pnBck.uAccountID, node.uAccountID, pnBck.uCurrencyID)); + // A "RippleState" means a balance betweeen two accounts for a + // specific currency. if (!sleRippleState) { WriteLog (lsTRACE, RippleCalc) << "pushNode: No credit line between " @@ -284,7 +251,7 @@ TER PathState::pushNode ( WriteLog (lsTRACE, RippleCalc) << getJson (); - errorCode = terNO_LINE; + resultCode = terNO_LINE; } else { @@ -297,13 +264,14 @@ TER PathState::pushNode ( << "." ; SLE::pointer sleBck = lesEntries.entryCache (ltACCOUNT_ROOT, Ledger::getAccountRootIndex (pnBck.uAccountID)); + // Is the source account the highest numbered account ID? bool bHigh = pnBck.uAccountID > node.uAccountID; if (!sleBck) { WriteLog (lsWARNING, RippleCalc) << "pushNode: delay: can't receive IOUs from non-existent issuer: " << RippleAddress::createHumanAccountID (pnBck.uAccountID); - errorCode = terNO_ACCOUNT; + resultCode = terNO_ACCOUNT; } else if ((is_bit_set (sleBck->getFieldU32 (sfFlags), lsfRequireAuth) && !is_bit_set (sleRippleState->getFieldU32 (sfFlags), (bHigh ? lsfHighAuth : lsfLowAuth))) @@ -311,10 +279,10 @@ TER PathState::pushNode ( { WriteLog (lsWARNING, RippleCalc) << "pushNode: delay: can't receive IOUs from issuer without auth."; - errorCode = terNO_AUTH; + resultCode = terNO_AUTH; } - if (errorCode == tesSUCCESS) + if (resultCode == tesSUCCESS) { STAmount saOwed = lesEntries.rippleOwed (node.uAccountID, pnBck.uAccountID, node.uCurrencyID); STAmount saLimit; @@ -327,16 +295,16 @@ TER PathState::pushNode ( " saOwed=" << saOwed << " saLimit=" << saLimit; - errorCode = tecPATH_DRY; + resultCode = tecPATH_DRY; } } } } } - if (errorCode == tesSUCCESS) + if (resultCode == tesSUCCESS) { - vpnNodes.push_back (node); + nodes_.push_back (node); } } else @@ -354,43 +322,52 @@ TER PathState::pushNode ( node.saRevDeliver = STAmount (node.uCurrencyID, node.uIssuerID); node.saFwdDeliver = node.saRevDeliver; - if (!!node.uCurrencyID != !!node.uIssuerID) + if (node.uCurrencyID.isZero() != node.uIssuerID.isZero()) { - WriteLog (lsDEBUG, RippleCalc) << - "pushNode: currency is inconsistent with issuer."; - errorCode = temBAD_PATH; + WriteLog (lsDEBUG, RippleCalc) + << "pushNode: currency is inconsistent with issuer."; + + resultCode = temBAD_PATH; } else if (previousNode.uCurrencyID == node.uCurrencyID && - previousNode.uIssuerID == node.uIssuerID) + previousNode.uIssuerID == node.uIssuerID) { WriteLog (lsDEBUG, RippleCalc) << "pushNode: bad path: offer to same currency and issuer"; - errorCode = temBAD_PATH; - } - else - { + resultCode = temBAD_PATH; + } else { WriteLog (lsTRACE, RippleCalc) << "pushNode: imply for offer."; // Insert intermediary issuer account if needed. - errorCode = pushImply ( + resultCode = pushImply ( ACCOUNT_XRP, // Rippling, but offers don't have an account. previousNode.uCurrencyID, previousNode.uIssuerID); } - if (errorCode == tesSUCCESS) + if (resultCode == tesSUCCESS) { - vpnNodes.push_back (node); + nodes_.push_back (node); } } - WriteLog (lsTRACE, RippleCalc) << "pushNode< : " << transToken (errorCode); - - return errorCode; + WriteLog (lsTRACE, RippleCalc) << "pushNode< : " << transToken (resultCode); + return resultCode; } -// Set to an expanded path. +// Set this object to be an expanded path from spSourcePath - take the implied +// nodes and makes them explicit. It also sanitizes the path. // +// There are only two types of nodes: account nodes and order books nodes. +// +// You can infer some nodes automatically. If you're paying me bitstamp USD, +// then there must be an intermediate bitstamp node. +// +// If you have accounts A and B, and they're delivery currency issued by C, then +// there must be a node with account C in the middle. +// +// If you're paying USD and getting bitcoins, there has to be an order book in +// between. // terStatus = tesSUCCESS, temBAD_PATH, terNO_LINE, terNO_ACCOUNT, terNO_AUTH, or temBAD_PATH_LOOP void PathState::setExpanded ( const LedgerEntrySet& lesSource, @@ -492,7 +469,7 @@ void PathState::setExpanded ( } } - const Node& previousNode = vpnNodes.back (); + auto const& previousNode = nodes_.back (); if (tesSUCCESS == terStatus && !!uOutCurrencyID // Next is not XRP @@ -534,11 +511,11 @@ void PathState::setExpanded ( // Look for first mention of source in nodes and detect loops. // Note: The output is not allowed to be a source. - const unsigned int uNodes = vpnNodes.size (); + const unsigned int uNodes = nodes_.size (); for (unsigned int nodeIndex = 0; tesSUCCESS == terStatus && nodeIndex != uNodes; ++nodeIndex) { - const Node& node = vpnNodes[nodeIndex]; + const auto& node = nodes_[nodeIndex]; AccountCurrencyIssuer aci( node.uAccountID, node.uCurrencyID, node.uIssuerID); @@ -561,220 +538,6 @@ void PathState::setExpanded ( ": " << getJson (); } -// Set to a canonical path. -// - Remove extra elements -// - Assumes path is expanded. -// -// We do canonicalization to: -// - Prevent waste in the ledger. -// - Allow longer paths to be specified than would otherwise be allowed. -// -// Optimization theory: -// - Can omit elements that the expansion routine derives. -// - Can pack some elements into other elements. -// -// Rules: -// - SendMax if not specified, defaults currency to send and if not sending XRP defaults issuer to sender. -// - All paths start with the sender account. -// - Currency and issuer is from SendMax. -// - All paths end with the destination account. -// -// Optimization: -// - An XRP output implies an offer node or destination node is next. -// - A change in currency implies an offer node. -// - A change in issuer... -void PathState::setCanonical ( - const PathState& psExpanded -) -{ - assert (false); - 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 nodeIndex = 0; - - unsigned int uEnd = psExpanded.vpnNodes.size (); // The node, indexed by 0, not to include. - - uint160 uDstAccountID = psExpanded.vpnNodes[uEnd].uAccountID; // FIXME: This can't be right - - uint160 uAccountID = psExpanded.vpnNodes[0].uAccountID; - uint160 uCurrencyID = uMaxCurrencyID; - uint160 uIssuerID = uMaxIssuerID; - - // Node 0 is a composite of the sending account and saInAct. - ++nodeIndex; // 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 1 - - if (nodeIndex != uEnd && uMaxIssuerID != uAccountID) - { - // saInAct issuer is not the sender. This forces an implied node. - // WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: in diff: nodeIndex=%d uEnd=%d") % nodeIndex % uEnd); - - // skip node 1 - - uIssuerID = psExpanded.vpnNodes[nodeIndex].uIssuerID; - - ++nodeIndex; - } - -#else - - if (nodeIndex != uEnd) - { - // Have another node - bool bKeep = false; - - if (uMaxIssuerID != uAccountID) - { - } - - if (uMaxCurrencyID) // Not sending XRP. - { - // Node 1 must be an account. - - if (uMaxIssuerID != uAccountID) - { - // Node 1 is required to specify issuer. - - bKeep = true; - } - else - { - // Node 1 must be an account - } - } - else - { - // Node 1 must be an order book. - - bKeep = true; - } - - if (bKeep) - { - uCurrencyID = psExpanded.vpnNodes[nodeIndex].uCurrencyID; - uIssuerID = psExpanded.vpnNodes[nodeIndex].uIssuerID; - ++nodeIndex; // Keep it. - } - } - -#endif - - if (nodeIndex != uEnd && !!uOutCurrencyID && uOutIssuerID != uDstAccountID) - { - // WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: out diff: nodeIndex=%d uEnd=%d") % nodeIndex % uEnd); - // 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 Node& pnEnd = psExpanded.vpnNodes[uEnd]; - - if (nodeIndex != 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. - // WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: out offer: nodeIndex=%d uEnd=%d") % nodeIndex % uEnd); - - --uEnd; - } - - // Do not include uEnd. - for (; nodeIndex != uEnd; ++nodeIndex) - { - // WriteLog (lsDEBUG, RippleCalc) << boost::str(boost::format("setCanonical: loop: nodeIndex=%d uEnd=%d") % nodeIndex % uEnd); - const Node& previousNode = psExpanded.vpnNodes[nodeIndex - 1]; - const Node& node = psExpanded.vpnNodes[nodeIndex]; - const Node& nextNode = psExpanded.vpnNodes[nodeIndex + 1]; - - const bool nodeIsAccount = is_bit_set (node.uFlags, STPathElement::typeAccount); - - bool bSkip = false; - - if (nodeIsAccount) - { - // Currently at an account. - - // Output is non-XRP and issuer is account. - if (!!node.uCurrencyID && node.uIssuerID == node.uAccountID) - { - // Account issues itself. - // XXX Not good enough. Previous account must mention it. - - bSkip = true; - } - } - else - { - // Currently at an offer. - const bool bPrvAccount = is_bit_set (previousNode.uFlags, STPathElement::typeAccount); - const bool bNxtAccount = is_bit_set (nextNode.uFlags, STPathElement::typeAccount); - - if (bPrvAccount && bNxtAccount // Offer surrounded by accounts. - && previousNode.uCurrencyID != nextNode.uCurrencyID) - { - // Offer can be implied by currency change. - // XXX What about issuer? - - bSkip = true; - } - } - - if (!bSkip) - { - // Copy node - Node pnNew; - - bool bSetCurrency = (uCurrencyID != node.uCurrencyID); - // XXX What if we need the next account because we want to skip it? - bool bSetIssuer = !uCurrencyID && (uIssuerID != node.uIssuerID); - - pnNew.uFlags = (nodeIsAccount ? STPathElement::typeAccount : 0) - | (bSetCurrency ? STPathElement::typeCurrency : 0) - | (bSetIssuer ? STPathElement::typeIssuer : 0); - - if (nodeIsAccount) - pnNew.uAccountID = node.uAccountID; - - if (bSetCurrency) - { - pnNew.uCurrencyID = node.uCurrencyID; - uCurrencyID = pnNew.uCurrencyID; - } - - if (bSetIssuer) - pnNew.uIssuerID = node.uIssuerID; - - // XXX ^^^ What about setting uIssuerID? - - if (bSetCurrency && !uCurrencyID) - uIssuerID.zero (); - - vpnNodes.push_back (pnNew); - } - } - - WriteLog (lsDEBUG, RippleCalc) << "setCanonical:" << - " in=" << STAmount::createHumanCurrency (uMaxCurrencyID) << - "/" << RippleAddress::createHumanAccountID (uMaxIssuerID) << - " out=" << STAmount::createHumanCurrency (uOutCurrencyID) << - "/" << RippleAddress::createHumanAccountID (uOutIssuerID) << - ": " << getJson (); -} - /** Check if a sequence of three accounts violates the no ripple constrains [first] -> [second] -> [third] Disallowed if 'second' set no ripple on [first]->[second] and [second]->[third] @@ -813,87 +576,84 @@ void PathState::checkNoRipple ( // Check a fully-expanded path to make sure it doesn't violate no-Ripple settings void PathState::checkNoRipple (uint160 const& uDstAccountID, uint160 const& uSrcAccountID) { - // There must be at least one node for there to be two consecutive ripple lines - if (vpnNodes.size() == 0) + if (nodes_.size() == 0) return; - if (vpnNodes.size() == 1) + if (nodes_.size() == 1) { // There's just one link in the path // We only need to check source-node-dest - if (is_bit_set (vpnNodes[0].uFlags, STPathElement::typeAccount) && - (vpnNodes[0].uAccountID != uSrcAccountID) && - (vpnNodes[0].uAccountID != uDstAccountID)) + if (nodes_[0].isAccount() && + (nodes_[0].uAccountID != uSrcAccountID) && + (nodes_[0].uAccountID != uDstAccountID)) { if (saInReq.getCurrency() != saOutReq.getCurrency()) terStatus = terNO_LINE; else - checkNoRipple (uSrcAccountID, vpnNodes[0].uAccountID, uDstAccountID, - vpnNodes[0].uCurrencyID); + checkNoRipple (uSrcAccountID, nodes_[0].uAccountID, uDstAccountID, + nodes_[0].uCurrencyID); } return; } // Check source <-> first <-> second - if (is_bit_set (vpnNodes[0].uFlags, STPathElement::typeAccount) && - is_bit_set (vpnNodes[1].uFlags, STPathElement::typeAccount) && - (vpnNodes[0].uAccountID != uSrcAccountID)) + if (nodes_[0].isAccount() && + nodes_[1].isAccount() && + (nodes_[0].uAccountID != uSrcAccountID)) { - if ((vpnNodes[0].uCurrencyID != vpnNodes[1].uCurrencyID)) + if ((nodes_[0].uCurrencyID != nodes_[1].uCurrencyID)) { terStatus = terNO_LINE; return; } else { - checkNoRipple (uSrcAccountID, vpnNodes[0].uAccountID, vpnNodes[1].uAccountID, - vpnNodes[0].uCurrencyID); + checkNoRipple (uSrcAccountID, nodes_[0].uAccountID, nodes_[1].uAccountID, + nodes_[0].uCurrencyID); if (tesSUCCESS != terStatus) return; } } // Check second_from_last <-> last <-> destination - size_t s = vpnNodes.size() - 2; - if (is_bit_set (vpnNodes[s].uFlags, STPathElement::typeAccount) && - is_bit_set (vpnNodes[s+1].uFlags, STPathElement::typeAccount) && - (uDstAccountID != vpnNodes[s+1].uAccountID)) + size_t s = nodes_.size() - 2; + if (nodes_[s].isAccount() && + nodes_[s + 1].isAccount() && + (uDstAccountID != nodes_[s+1].uAccountID)) { - if ((vpnNodes[s].uCurrencyID != vpnNodes[s+1].uCurrencyID)) + if ((nodes_[s].uCurrencyID != nodes_[s+1].uCurrencyID)) { terStatus = terNO_LINE; return; } else { - checkNoRipple (vpnNodes[s].uAccountID, vpnNodes[s+1].uAccountID, uDstAccountID, - vpnNodes[s].uCurrencyID); + checkNoRipple (nodes_[s].uAccountID, nodes_[s+1].uAccountID, uDstAccountID, + nodes_[s].uCurrencyID); if (tesSUCCESS != terStatus) return; } } - // Loop through all nodes that have a prior node and successor nodes // These are the nodes whose no ripple constratints could be violated - for (int i = 1; i < (vpnNodes.size() - 1); ++i) + for (int i = 1; i < nodes_.size() - 1; ++i) { + if (nodes_[i - 1].isAccount() && + nodes_[i].isAccount() && + nodes_[i + 1].isAccount()) + { // Two consecutive account-to-account links - if (is_bit_set (vpnNodes[i-1].uFlags, STPathElement::typeAccount) && - is_bit_set (vpnNodes[i].uFlags, STPathElement::typeAccount) && - is_bit_set (vpnNodes[i+1].uFlags, STPathElement::typeAccount)) - { // two consecutive account-to-account links - - uint160 const& currencyID = vpnNodes[i].uCurrencyID; - if ((vpnNodes[i-1].uCurrencyID != currencyID) || - (vpnNodes[i+1].uCurrencyID != currencyID)) + uint160 const& currencyID = nodes_[i].uCurrencyID; + if ((nodes_[i-1].uCurrencyID != currencyID) || + (nodes_[i+1].uCurrencyID != currencyID)) { terStatus = temBAD_PATH; return; } checkNoRipple ( - vpnNodes[i-1].uAccountID, vpnNodes[i].uAccountID, vpnNodes[i+1].uAccountID, + nodes_[i-1].uAccountID, nodes_[i].uAccountID, nodes_[i+1].uAccountID, currencyID); if (terStatus != tesSUCCESS) return; @@ -908,10 +668,8 @@ Json::Value PathState::getJson () const Json::Value jvPathState (Json::objectValue); Json::Value jvNodes (Json::arrayValue); - BOOST_FOREACH (const Node & pnNode, vpnNodes) - { + for (auto const &pnNode: nodes_) jvNodes.append (pnNode.getJson ()); - } jvPathState["status"] = terStatus; jvPathState["index"] = mIndex; diff --git a/src/ripple/module/app/paths/PathState.h b/src/ripple/module/app/paths/PathState.h index ab9f764295..496d88cf16 100644 --- a/src/ripple/module/app/paths/PathState.h +++ b/src/ripple/module/app/paths/PathState.h @@ -20,110 +20,34 @@ #ifndef RIPPLE_PATHSTATE_H #define RIPPLE_PATHSTATE_H +#include +#include + namespace ripple { -// account id, currency id, issuer id :: node -typedef std::tuple AccountCurrencyIssuer; - -// Map of currency, issuer to node index. -typedef ripple::unordered_map -AccountCurrencyIssuerToNodeIndex; - -extern std::size_t hash_value (const AccountCurrencyIssuer& asValue); - // Holds a path state under incremental application. class PathState : public CountedObject { -public: + public: + typedef std::vector OfferIndexList; + typedef std::vector> List; - static char const* getCountedObjectName () { return "PathState"; } - - class Node - { - public: - bool operator == (Node const& pnOther) const; - - Json::Value getJson () const; - - public: - std::uint16_t uFlags; // --> From path. - - uint160 uAccountID; // --> Accounts: Recieving/sending account. - uint160 uCurrencyID; // --> Accounts: Receive and send, Offers: send. - // --- For offer's next has currency out. - uint160 uIssuerID; // --> Currency's issuer - - STAmount saTransferRate; // Transfer rate for uIssuerID. - - // Computed by Reverse. - STAmount saRevRedeem; // <-- Amount to redeem to next. - STAmount saRevIssue; // <-- Amount to issue to next limited by credit and outstanding IOUs. - // Issue isn't used by offers. - STAmount saRevDeliver; // <-- Amount to deliver to next regardless of fee. - - // Computed by forward. - STAmount saFwdRedeem; // <-- Amount node will redeem to next. - STAmount saFwdIssue; // <-- Amount node will issue to next. - // Issue isn't used by offers. - STAmount saFwdDeliver; // <-- Amount to deliver to next regardless of fee. - - // For offers: - - STAmount saRateMax; - - // Directory - uint256 uDirectTip; // Current directory. - uint256 uDirectEnd; // Next order book. - bool bDirectAdvance; // Need to advance directory. - bool bDirectRestart; // Need to restart directory. - SLE::pointer sleDirectDir; - STAmount saOfrRate; // For correct ratio. - - // PaymentNode - bool bEntryAdvance; // Need to advance entry. - unsigned int uEntry; - uint256 uOfferIndex; - SLE::pointer sleOffer; - uint160 uOfrOwnerID; - bool bFundsDirty; // Need to refresh saOfferFunds, saTakerPays, & saTakerGets. - STAmount saOfferFunds; - STAmount saTakerPays; - STAmount saTakerGets; - - }; - - typedef std::shared_ptr pointer; - typedef const std::shared_ptr& ref; - - PathState* setIndex (const int iIndex) - { - mIndex = iIndex; - - return this; - } - - int getIndex () - { - return mIndex; - }; - - PathState ( - const STAmount& saSend, - const STAmount& saSendMax) + PathState (const STAmount& saSend, const STAmount& saSendMax) : saInReq (saSendMax) , saOutReq (saSend) - , bConsumed (false) + , allLiquidityConsumed_ (false) { } - PathState (const PathState& psSrc, - bool bUnused) + PathState (const PathState& psSrc, bool bUnused) : saInReq (psSrc.saInReq) , saOutReq (psSrc.saOutReq) - , bConsumed (false) + , allLiquidityConsumed_ (false) { } + void clear(); + void setExpanded ( const LedgerEntrySet& lesSource, const STPath& spSourcePath, @@ -131,23 +55,53 @@ public: const uint160& uSenderID ); - void checkNoRipple (uint160 const& destinationAccountID, uint160 const& sourceAccountID); - void checkNoRipple (uint160 const&, uint160 const&, uint160 const&, uint160 const&); + path::Node::List& nodes() { return nodes_; } - void setCanonical (const PathState& psExpanded); + STAmount& inPass() { return saInPass; } + STAmount& outPass() { return saOutPass; } + const STAmount& outReq() const { return saOutReq; } + STAmount& inAct() { return saInAct; } + STAmount& outAct() { return saOutAct; } + const STAmount& inReq() const { return saInReq; } + + AccountCurrencyIssuerToNodeIndex& forward() { return umForward; } + AccountCurrencyIssuerToNodeIndex& reverse() { return umReverse; } Json::Value getJson () const; + static char const* getCountedObjectName () { return "PathState"; } + OfferIndexList& becameUnfunded() { return vUnfundedBecame; } + + void setStatus(TER status) { terStatus = status; } + TER status() const { return terStatus; } + + std::uint64_t quality() const { return uQuality; } + void setQuality (std::uint64_t q) { uQuality = q; } + + bool allLiquidityConsumed() const { return allLiquidityConsumed_; } + void consumeAllLiqudity () { allLiquidityConsumed_ = true; } + + void setIndex (int i) { mIndex = i; } + int index() const { return mIndex; } + + void checkNoRipple (uint160 const& destinationAccountID, + uint160 const& sourceAccountID); static bool lessPriority (PathState& lhs, PathState& rhs); - TER terStatus; - std::vector vpnNodes; + LedgerEntrySet& ledgerEntries() { return lesEntries; } + + private: + void checkNoRipple (uint160 const&, uint160 const&, uint160 const&, uint160 const&); + + TER terStatus; + path::Node::List nodes_; // When processing, don't want to complicate directory walking with deletion. - std::vector vUnfundedBecame; // Offers that became unfunded or were completely consumed. + // Offers that became unfunded or were completely consumed. + OfferIndexList vUnfundedBecame; - // First time scanning foward, as part of path contruction, a funding source was mentioned for accounts. Source may only be - // used there. + // First time scanning foward, as part of path construction, a funding + // source was mentioned for accounts. Source may only be used there. AccountCurrencyIssuerToNodeIndex umForward; // First time working in reverse a funding source was used. @@ -164,11 +118,17 @@ public: const STAmount& saOutReq; // --> Amount to send. STAmount saOutAct; // --> Amount actually sent so far. STAmount saOutPass; // <-- Amount actually sent. - bool bConsumed; // If true, use consumes full liquidity. False, may or may not. -private: - TER pushNode (const int iType, const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID); - TER pushImply (const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID); + // If true, all liquidity on this path has been consumed. + bool allLiquidityConsumed_; + + TER pushNode ( + const int iType, const uint160& uAccountID, const uint160& uCurrencyID, + const uint160& uIssuerID); + + TER pushImply ( + const uint160& uAccountID, const uint160& uCurrencyID, + const uint160& uIssuerID); }; } // ripple diff --git a/src/ripple/module/app/paths/Pathfinder.cpp b/src/ripple/module/app/paths/Pathfinder.cpp index 68ae41c173..6296d7b827 100644 --- a/src/ripple/module/app/paths/Pathfinder.cpp +++ b/src/ripple/module/app/paths/Pathfinder.cpp @@ -1,4 +1,3 @@ - //------------------------------------------------------------------------------ /* This file is part of rippled: https://github.com/ripple/rippled @@ -243,14 +242,14 @@ STPathSet Pathfinder::filterPaths(int iMaxPaths, STPath& extraPath) try { STAmount saMaxAmountAct, saDstAmountAct; - std::vector vpsExpanded; + PathState::List pathStateList; LedgerEntrySet lesSandbox (mLedger, tapNONE); - TER result = rippleCalculate ( + TER result = path::rippleCalculate ( lesSandbox, saMaxAmountAct, saDstAmountAct, - vpsExpanded, + pathStateList, mSrcAmount, mDstAmount, mDstAccountID, @@ -286,23 +285,23 @@ STPathSet Pathfinder::filterPaths(int iMaxPaths, STPath& extraPath) { STAmount saMaxAmountAct; STAmount saDstAmountAct; - std::vector vpsExpanded; + PathState::List pathStateList; STPathSet spsPaths; STPath& spCurrent = mCompletePaths[i]; spsPaths.addPath (spCurrent); // Just checking the current path. - TER errorCode; + TER resultCode; try { LedgerEntrySet lesSandbox (mLedger, tapNONE); - errorCode = rippleCalculate ( + resultCode = path::rippleCalculate ( lesSandbox, saMaxAmountAct, // --> computed input saDstAmountAct, // --> computed output - vpsExpanded, + pathStateList, mSrcAmount, // --> amount to send max. mDstAmount, // --> amount to deliver. mDstAccountID, @@ -317,13 +316,13 @@ STPathSet Pathfinder::filterPaths(int iMaxPaths, STPath& extraPath) { WriteLog (lsINFO, Pathfinder) << "findPaths: Caught throw: " << e.what (); - errorCode = tefEXCEPTION; + resultCode = tefEXCEPTION; } - if (errorCode != tesSUCCESS) + if (resultCode != tesSUCCESS) { WriteLog (lsDEBUG, Pathfinder) << - "findPaths: dropping: " << transToken (errorCode) << + "findPaths: dropping: " << transToken (resultCode) << ": " << spCurrent.getJson (0); } else if (saDstAmountAct < saMinDstAmount) diff --git a/src/ripple/module/app/paths/QualityConstraint.h b/src/ripple/module/app/paths/QualityConstraint.h new file mode 100644 index 0000000000..4c80b3bad9 --- /dev/null +++ b/src/ripple/module/app/paths/QualityConstraint.h @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_QUALITY_CONSTRAINT_H +#define RIPPLE_QUALITY_CONSTRAINT_H + +namespace ripple { +namespace path { + +enum class QualityConstraint { SAME_OR_BETTER, UNCONSTRAINED }; + +} // path +} // ripple + +#endif diff --git a/src/ripple/module/app/paths/RippleCalc.cpp b/src/ripple/module/app/paths/RippleCalc.cpp index 62309fb419..d98fa5f277 100644 --- a/src/ripple/module/app/paths/RippleCalc.cpp +++ b/src/ripple/module/app/paths/RippleCalc.cpp @@ -27,12 +27,18 @@ #include #include #include +#include #include namespace ripple { SETUP_LOG (RippleCalc) +namespace path { + +// OPTIMIZE: When calculating path increment, note if increment consumes all +// liquidity. No need to revisit path in the future if all liquidity is used. + // <-- TER: Only returns tepPATH_PARTIAL if !bPartialPayment. TER rippleCalculate ( // Compute paths vs this ledger entry set. Up to caller to actually apply @@ -42,7 +48,14 @@ TER rippleCalculate ( STAmount& saMaxAmountAct, // <-- The computed input amount. STAmount& saDstAmountAct, // <-- The computed output amount. - std::vector& vpsExpanded, + + // Expanded path with all the actual nodes in it. + // TODO(tom): does it put in default paths? + + // A path starts with the source account, ends with the destination account + // and goes through other acounts or order books. + PathState::List& pathStateList, + // Issuer: // XRP: ACCOUNT_XRP // non-XRP: uSrcAccountID (for any issuer) or another account with trust @@ -57,11 +70,15 @@ TER rippleCalculate ( const uint160& uDstAccountID, const uint160& uSrcAccountID, + + // A set of paths that are included in the transaction that we'll explore + // for liquidity. const STPathSet& spsPaths, const bool bPartialPayment, const bool bLimitQuality, const bool bNoRippleDirect, const bool bStandAlone, + // True, not to delete unfundeds. const bool bOpenLedger) { @@ -73,7 +90,7 @@ TER rippleCalculate ( << " saMaxAmountReq:" << saMaxAmountReq << " saDstAmountReq:" << saDstAmountReq; - TER errorCode = temUNCERTAIN; + TER resultCode = temUNCERTAIN; // YYY Might do basic checks on src and dst validity as per doPayment. @@ -96,7 +113,7 @@ TER rippleCalculate ( // nodes. // XXX Might also make a XRP bridge by default. - PathState::pointer pspDirect = std::make_shared ( + auto pspDirect = std::make_shared ( saDstAmountReq, saMaxAmountReq); if (!pspDirect) @@ -105,29 +122,27 @@ TER rippleCalculate ( pspDirect->setExpanded ( activeLedger, STPath (), uDstAccountID, uSrcAccountID); - if (tesSUCCESS == pspDirect->terStatus) + if (tesSUCCESS == pspDirect->status()) pspDirect->checkNoRipple (uDstAccountID, uSrcAccountID); - pspDirect->setIndex (vpsExpanded.size ()); + pspDirect->setIndex (pathStateList.size ()); WriteLog (lsDEBUG, RippleCalc) << "rippleCalc: Build direct:" - << " status: " << transToken (pspDirect->terStatus); + << " status: " << transToken (pspDirect->status()); // Return if malformed. - if (isTemMalformed (pspDirect->terStatus)) - return pspDirect->terStatus; + if (isTemMalformed (pspDirect->status())) + return pspDirect->status(); - if (tesSUCCESS == pspDirect->terStatus) + if (tesSUCCESS == pspDirect->status()) { - // Had a success. - errorCode = tesSUCCESS; - - vpsExpanded.push_back (pspDirect); + resultCode = tesSUCCESS; + pathStateList.push_back (pspDirect); } - else if (terNO_LINE != pspDirect->terStatus) + else if (terNO_LINE != pspDirect->status()) { - errorCode = pspDirect->terStatus; + resultCode = pspDirect->status(); } } @@ -137,7 +152,7 @@ TER rippleCalculate ( int iIndex = 0; for (auto const& spPath: spsPaths) { - PathState::pointer pspExpanded = std::make_shared ( + auto pspExpanded = std::make_shared ( saDstAmountReq, saMaxAmountReq); if (!pspExpanded) @@ -155,43 +170,38 @@ TER rippleCalculate ( pspExpanded->setExpanded ( activeLedger, spPath, uDstAccountID, uSrcAccountID); - if (tesSUCCESS == pspExpanded->terStatus) + if (tesSUCCESS == pspExpanded->status()) pspExpanded->checkNoRipple (uDstAccountID, uSrcAccountID); WriteLog (lsDEBUG, RippleCalc) << "rippleCalc:" << " Build path:" << ++iIndex - << " status: " << transToken (pspExpanded->terStatus); + << " status: " << transToken (pspExpanded->status()); // Return, if the path specification was malformed. - if (isTemMalformed (pspExpanded->terStatus)) - return pspExpanded->terStatus; + if (isTemMalformed (pspExpanded->status())) + return pspExpanded->status(); - if (tesSUCCESS == pspExpanded->terStatus) + if (tesSUCCESS == pspExpanded->status()) { - errorCode = tesSUCCESS; // Had a success. + resultCode = tesSUCCESS; // Had a success. - pspExpanded->setIndex (vpsExpanded.size ()); - vpsExpanded.push_back (pspExpanded); + pspExpanded->setIndex (pathStateList.size ()); + pathStateList.push_back (pspExpanded); } - else if (terNO_LINE != pspExpanded->terStatus) + else if (terNO_LINE != pspExpanded->status()) { - errorCode = pspExpanded->terStatus; + resultCode = pspExpanded->status(); } } - if (errorCode != tesSUCCESS) - return errorCode == temUNCERTAIN ? terNO_LINE : errorCode; + if (resultCode != tesSUCCESS) + return resultCode == temUNCERTAIN ? terNO_LINE : resultCode; else - errorCode = temUNCERTAIN; + resultCode = temUNCERTAIN; - saMaxAmountAct = STAmount ( - saMaxAmountReq.getCurrency (), saMaxAmountReq.getIssuer ()); - saDstAmountAct = STAmount ( - saDstAmountReq.getCurrency (), saDstAmountReq.getIssuer ()); - - // Checkpoint with just fees paid. - const LedgerEntrySet lesBase = activeLedger; + saMaxAmountAct = zeroed(saMaxAmountReq); + saDstAmountAct = zeroed(saDstAmountReq); // When processing, we don't want to complicate directory walking with // deletion. @@ -203,7 +213,7 @@ TER rippleCalculate ( int iPass = 0; - while (errorCode == temUNCERTAIN) + while (resultCode == temUNCERTAIN) { int iBest = -1; const LedgerEntrySet lesCheckpoint = activeLedger; @@ -213,47 +223,47 @@ TER rippleCalculate ( bool bMultiQuality = false; // Find the best path. - for (auto pspCur: vpsExpanded) + for (auto pspCur: pathStateList) { - if (pspCur->uQuality) + if (pspCur->quality()) // Only do active paths. { - bMultiQuality = 1 == vpsExpanded.size () - iDry; + bMultiQuality = 1 == pathStateList.size () - iDry; // Computing the only non-dry path, compute multi-quality. - pspCur->saInAct = saMaxAmountAct; + pspCur->inAct() = saMaxAmountAct; // Update to current amount processed. - pspCur->saOutAct = saDstAmountAct; + pspCur->outAct() = saDstAmountAct; - CondLog (pspCur->saInReq > zero - && pspCur->saInAct >= pspCur->saInReq, + CondLog (pspCur->inReq() > zero + && pspCur->inAct() >= pspCur->inReq(), lsWARNING, RippleCalc) << "rippleCalc: DONE:" - << " saInAct=" << pspCur->saInAct - << " saInReq=" << pspCur->saInReq; + << " inAct()=" << pspCur->inAct() + << " inReq()=" << pspCur->inReq(); - assert (pspCur->saInReq < zero || - pspCur->saInAct < pspCur->saInReq); // Error if done. + assert (pspCur->inReq() < zero || + pspCur->inAct() < pspCur->inReq()); // Error if done. - CondLog (pspCur->saOutAct >= pspCur->saOutReq, + CondLog (pspCur->outAct() >= pspCur->outReq(), lsWARNING, RippleCalc) << "rippleCalc: ALREADY DONE:" - << " saOutAct=" << pspCur->saOutAct - << " saOutReq=%s" << pspCur->saOutReq; + << " saOutAct=" << pspCur->outAct() + << " saOutReq=%s" << pspCur->outReq(); - assert (pspCur->saOutAct < pspCur->saOutReq); + assert (pspCur->outAct() < pspCur->outReq()); // Error if done, output met. pathNext (rc, *pspCur, bMultiQuality, lesCheckpoint, rc.mActiveLedger); // Compute increment. WriteLog (lsDEBUG, RippleCalc) << "rippleCalc: AFTER:" - << " mIndex=" << pspCur->mIndex - << " uQuality=" << pspCur->uQuality - << " rate=%s" << STAmount::saFromRate (pspCur->uQuality); + << " mIndex=" << pspCur->index() + << " uQuality=" << pspCur->quality() + << " rate=%s" << STAmount::saFromRate (pspCur->quality()); - if (!pspCur->uQuality) + if (!pspCur->quality()) { // Path was dry. @@ -261,40 +271,40 @@ TER rippleCalculate ( } else { - CondLog (!pspCur->saInPass || !pspCur->saOutPass, + CondLog (!pspCur->inPass() || !pspCur->outPass(), lsDEBUG, RippleCalc) << "rippleCalc: better:" << " uQuality=" - << STAmount::saFromRate (pspCur->uQuality) - << " saInPass=" << pspCur->saInPass - << " saOutPass=" << pspCur->saOutPass; + << STAmount::saFromRate (pspCur->quality()) + << " inPass()=" << pspCur->inPass() + << " saOutPass=" << pspCur->outPass(); - assert (!!pspCur->saInPass && !!pspCur->saOutPass); + assert (!!pspCur->inPass() && !!pspCur->outPass()); - if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) + if ((!bLimitQuality || pspCur->quality() <= uQualityLimit) // Quality is not limited or increment has allowed // quality. && (iBest < 0 // Best is not yet set. - || PathState::lessPriority (*vpsExpanded[iBest], + || PathState::lessPriority (*pathStateList[iBest], *pspCur))) // Current is better than set. { WriteLog (lsDEBUG, RippleCalc) << "rippleCalc: better:" - << " mIndex=" << pspCur->mIndex - << " uQuality=" << pspCur->uQuality + << " mIndex=" << pspCur->index() + << " uQuality=" << pspCur->quality() << " rate=" - << STAmount::saFromRate (pspCur->uQuality) - << " saInPass=" << pspCur->saInPass - << " saOutPass=" << pspCur->saOutPass; + << STAmount::saFromRate (pspCur->quality()) + << " inPass()=" << pspCur->inPass() + << " saOutPass=" << pspCur->outPass(); assert (activeLedger.isValid ()); - activeLedger.swapWith (pspCur->lesEntries); + activeLedger.swapWith (pspCur->ledgerEntries()); // For the path, save ledger state. activeLedger.invalidate (); - iBest = pspCur->getIndex (); + iBest = pspCur->index (); } } } @@ -306,58 +316,58 @@ TER rippleCalculate ( << "rippleCalc: Summary:" << " Pass: " << ++iPass << " Dry: " << iDry - << " Paths: " << vpsExpanded.size (); - for (auto pspCur: vpsExpanded) + << " Paths: " << pathStateList.size (); + for (auto pspCur: pathStateList) { WriteLog (lsDEBUG, RippleCalc) << "rippleCalc: " - << "Summary: " << pspCur->mIndex + << "Summary: " << pspCur->index() << " rate: " - << STAmount::saFromRate (pspCur->uQuality) - << " quality:" << pspCur->uQuality - << " best: " << (iBest == pspCur->getIndex ()); + << STAmount::saFromRate (pspCur->quality()) + << " quality:" << pspCur->quality() + << " best: " << (iBest == pspCur->index ()); } } if (iBest >= 0) { // Apply best path. - PathState::pointer pspBest = vpsExpanded[iBest]; + auto pspBest = pathStateList[iBest]; WriteLog (lsDEBUG, RippleCalc) << "rippleCalc: best:" << " uQuality=" - << STAmount::saFromRate (pspBest->uQuality) - << " saInPass=" << pspBest->saInPass - << " saOutPass=" << pspBest->saOutPass; + << STAmount::saFromRate (pspBest->quality()) + << " inPass()=" << pspBest->inPass() + << " saOutPass=" << pspBest->outPass(); // Record best pass' offers that became unfunded for deletion on // success. vuUnfundedBecame.insert ( vuUnfundedBecame.end (), - pspBest->vUnfundedBecame.begin (), - pspBest->vUnfundedBecame.end ()); + pspBest->becameUnfunded().begin (), + pspBest->becameUnfunded().end ()); // Record best pass' LedgerEntrySet to build off of and potentially // return. - assert (pspBest->lesEntries.isValid ()); - activeLedger.swapWith (pspBest->lesEntries); - pspBest->lesEntries.invalidate (); + assert (pspBest->ledgerEntries().isValid ()); + activeLedger.swapWith (pspBest->ledgerEntries()); + pspBest->ledgerEntries().invalidate (); - saMaxAmountAct += pspBest->saInPass; - saDstAmountAct += pspBest->saOutPass; + saMaxAmountAct += pspBest->inPass(); + saDstAmountAct += pspBest->outPass(); - if (pspBest->bConsumed || bMultiQuality) + if (pspBest->allLiquidityConsumed() || bMultiQuality) { ++iDry; - pspBest->uQuality = 0; + pspBest->setQuality(0); } if (saDstAmountAct == saDstAmountReq) { // Done. Delivered requested amount. - errorCode = tesSUCCESS; + resultCode = tesSUCCESS; } else if (saDstAmountAct > saDstAmountReq) { @@ -370,59 +380,59 @@ TER rippleCalculate ( assert (false); } else if (saMaxAmountAct != saMaxAmountReq && - iDry != vpsExpanded.size ()) + iDry != pathStateList.size ()) { // Have not met requested amount or max send, try to do // more. Prepare for next pass. // // Merge best pass' umReverse. rc.mumSource.insert ( - pspBest->umReverse.begin (), pspBest->umReverse.end ()); + pspBest->reverse().begin (), pspBest->reverse().end ()); } else if (!bPartialPayment) { // Have sent maximum allowed. Partial payment not allowed. - errorCode = tecPATH_PARTIAL; + resultCode = tecPATH_PARTIAL; } else { // Have sent maximum allowed. Partial payment allowed. Success. - errorCode = tesSUCCESS; + resultCode = tesSUCCESS; } } // Not done and ran out of paths. else if (!bPartialPayment) { // Partial payment not allowed. - errorCode = tecPATH_PARTIAL; + resultCode = tecPATH_PARTIAL; } // Partial payment ok. else if (!saDstAmountAct) { // No payment at all. - errorCode = tecPATH_DRY; + resultCode = tecPATH_DRY; } else { - errorCode = tesSUCCESS; + resultCode = tesSUCCESS; } } if (!bStandAlone) { - if (errorCode == tesSUCCESS) + if (resultCode == tesSUCCESS) { // Delete became unfunded offers. for (auto const& uOfferIndex: vuUnfundedBecame) { - if (errorCode == tesSUCCESS) + if (resultCode == tesSUCCESS) { WriteLog (lsDEBUG, RippleCalc) << "Became unfunded " << to_string (uOfferIndex); - errorCode = activeLedger.offerDelete (uOfferIndex); + resultCode = activeLedger.offerDelete (uOfferIndex); } } } @@ -430,16 +440,17 @@ TER rippleCalculate ( // Delete found unfunded offers. for (auto const& uOfferIndex: rc.mUnfundedOffers) { - if (errorCode == tesSUCCESS) + if (resultCode == tesSUCCESS) { WriteLog (lsDEBUG, RippleCalc) << "Delete unfunded " << to_string (uOfferIndex); - errorCode = activeLedger.offerDelete (uOfferIndex); + resultCode = activeLedger.offerDelete (uOfferIndex); } } } - return errorCode; + return resultCode; } +} // path } // ripple diff --git a/src/ripple/module/app/paths/RippleCalc.h b/src/ripple/module/app/paths/RippleCalc.h index e80e342d27..c03849747e 100644 --- a/src/ripple/module/app/paths/RippleCalc.h +++ b/src/ripple/module/app/paths/RippleCalc.h @@ -21,6 +21,7 @@ #define RIPPLE_RIPPLECALC_H namespace ripple { +namespace path { /** Calculate the quality of a payment path. @@ -32,7 +33,7 @@ TER rippleCalculate ( LedgerEntrySet& lesActive, STAmount& saMaxAmountAct, STAmount& saDstAmountAct, - std::vector& vpsExpanded, + PathState::List& pathStateList, const STAmount& saDstAmountReq, const STAmount& saMaxAmountReq, const uint160& uDstAccountID, @@ -47,6 +48,7 @@ TER rippleCalculate ( const bool bOpenLedger = true ); +} // path } // ripple #endif diff --git a/src/ripple/module/app/paths/Types.h b/src/ripple/module/app/paths/Types.h new file mode 100644 index 0000000000..2005ce06d1 --- /dev/null +++ b/src/ripple/module/app/paths/Types.h @@ -0,0 +1,43 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_TYPES_H +#define RIPPLE_TYPES_H + +namespace ripple { + +// account id, currency id, issuer id. +typedef std::tuple AccountCurrencyIssuer; + +std::size_t hash_value (const AccountCurrencyIssuer& asValue); + +// Map of account, currency, issuer to node index. +typedef ripple::unordered_map +AccountCurrencyIssuerToNodeIndex; + +/** Returns a copy of an STAmount with the same currency and issuer but the + amount set to zero. */ +inline STAmount zeroed(const STAmount& a) +{ + return STAmount(a.getCurrency(), a.getIssuer()); +} + +} // ripple + +#endif diff --git a/src/ripple/module/app/transactors/Payment.cpp b/src/ripple/module/app/transactors/Payment.cpp index 6cdfc1bccf..62d7c86e46 100644 --- a/src/ripple/module/app/transactors/Payment.cpp +++ b/src/ripple/module/app/transactors/Payment.cpp @@ -232,7 +232,7 @@ TER Payment::doApply () // Copy paths into an editable class. STPathSet spsPaths = mTxn.getFieldPathSet (sfPaths); - std::vector vpsExpanded; + PathState::List pathStateList; STAmount maxSourceAmountAct; STAmount saDstAmountAct; @@ -243,11 +243,11 @@ TER Payment::doApply () terResult = openLedger && tooManyPaths ? telBAD_PATH_COUNT // Too many paths for proposed ledger. - : rippleCalculate ( + : path::rippleCalculate ( mEngine->view (), maxSourceAmountAct, saDstAmountAct, - vpsExpanded, // Vector for saving expanded path. + pathStateList, // Vector for saving expanded path. maxSourceAmount, saDstAmount, uDstAccountID, diff --git a/src/ripple/module/rpc/handlers/RipplePathFind.cpp b/src/ripple/module/rpc/handlers/RipplePathFind.cpp index 4e0f86f8af..f6e2bec158 100644 --- a/src/ripple/module/rpc/handlers/RipplePathFind.cpp +++ b/src/ripple/module/rpc/handlers/RipplePathFind.cpp @@ -203,10 +203,10 @@ Json::Value RPCHandler::doRipplePathFind ( } else { - std::vector vpsExpanded; - STAmount saMaxAmountAct; - STAmount saDstAmountAct; - STAmount saMaxAmount ( + PathState::List pathStateList; + STAmount saMaxAmountAct; + STAmount saDstAmountAct; + STAmount saMaxAmount ( uSrcCurrencyID, !!uSrcIssuerID ? uSrcIssuerID // Use specifed issuer. @@ -219,11 +219,11 @@ Json::Value RPCHandler::doRipplePathFind ( LedgerEntrySet lesSandbox (lpLedger, tapNONE); TER terResult = - rippleCalculate ( + path::rippleCalculate ( lesSandbox, saMaxAmountAct, // <-- saDstAmountAct, // <-- - vpsExpanded, // <-- + pathStateList, // <-- saMaxAmount, // --> Amount to send is unlimited to get an estimate. saDstAmount, // --> Amount to deliver. raDst.getAccountID (), // --> Account to deliver to. @@ -236,7 +236,7 @@ Json::Value RPCHandler::doRipplePathFind ( true); // --> Stand alone mode, no point in deleting unfundeds. // WriteLog (lsDEBUG, RPCHandler) << "ripple_path_find: PATHS IN: " << spsComputed.size() << " : " << spsComputed.getJson(0); - // WriteLog (lsDEBUG, RPCHandler) << "ripple_path_find: PATHS EXP: " << vpsExpanded.size(); + // WriteLog (lsDEBUG, RPCHandler) << "ripple_path_find: PATHS EXP: " << pathStateList.size(); WriteLog (lsWARNING, RPCHandler) << boost::str (boost::format ("ripple_path_find: saMaxAmount=%s saDstAmount=%s saMaxAmountAct=%s saDstAmountAct=%s") @@ -249,10 +249,10 @@ Json::Value RPCHandler::doRipplePathFind ( { WriteLog (lsDEBUG, PathRequest) << "Trying with an extra path element"; spsComputed.addPath(extraPath); - vpsExpanded.clear (); + pathStateList.clear (); lesSandbox.clear (); - terResult = rippleCalculate (lesSandbox, saMaxAmountAct, saDstAmountAct, - vpsExpanded, saMaxAmount, saDstAmount, + terResult = path::rippleCalculate (lesSandbox, saMaxAmountAct, saDstAmountAct, + pathStateList, saMaxAmount, saDstAmount, raDst.getAccountID (), raSrc.getAccountID (), spsComputed, false, false, false, true); WriteLog (lsDEBUG, PathRequest) << "Extra path element gives " << transHuman (terResult); @@ -266,10 +266,9 @@ Json::Value RPCHandler::doRipplePathFind ( // Reuse the expanded as it would need to be calcuated anyway to produce the canonical. // (At least unless we make a direct canonical.) - // RippleCalc::setCanonical(spsCanonical, vpsExpanded, false); jvEntry["source_amount"] = saMaxAmountAct.getJson (0); - // jvEntry["paths_expanded"] = vpsExpanded.getJson(0); + // jvEntry["paths_expanded"] = pathStateList.getJson(0); jvEntry["paths_canonical"] = Json::arrayValue; // spsCanonical.getJson(0); jvEntry["paths_computed"] = spsComputed.getJson (0);