mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
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().
This commit is contained in:
committed by
Vinnie Falco
parent
bf116308d4
commit
27620af1bf
@@ -2233,6 +2233,11 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\Calculators.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\app\paths\Node.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\Node.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\app\paths\PathNext.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
@@ -2256,6 +2261,8 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\Pathfinder.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\QualityConstraint.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\app\paths\RippleCalc.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
@@ -2273,6 +2280,8 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\Tuning.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\Types.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\peers\ClusterNodeStatus.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\app\peers\PeerSet.cpp">
|
||||
@@ -2932,6 +2941,9 @@
|
||||
<ClCompile Include="..\..\src\ripple\module\rpc\handlers\LedgerHeader.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\module\rpc\handlers\LedgerRequest.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\module\rpc\handlers\LogLevel.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
@@ -3068,9 +3080,6 @@
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\module\rpc\impl\GetMasterGenerator.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\rpc\impl\Handlers.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\module\rpc\impl\LegacyPathFind.cpp">
|
||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
|
||||
@@ -3279,6 +3279,12 @@
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\Calculators.h">
|
||||
<Filter>ripple\module\app\paths</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\app\paths\Node.cpp">
|
||||
<Filter>ripple\module\app\paths</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\Node.h">
|
||||
<Filter>ripple\module\app\paths</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\app\paths\PathNext.cpp">
|
||||
<Filter>ripple\module\app\paths</Filter>
|
||||
</ClCompile>
|
||||
@@ -3306,6 +3312,9 @@
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\Pathfinder.h">
|
||||
<Filter>ripple\module\app\paths</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\QualityConstraint.h">
|
||||
<Filter>ripple\module\app\paths</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\app\paths\RippleCalc.cpp">
|
||||
<Filter>ripple\module\app\paths</Filter>
|
||||
</ClCompile>
|
||||
@@ -3327,6 +3336,9 @@
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\Tuning.h">
|
||||
<Filter>ripple\module\app\paths</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\paths\Types.h">
|
||||
<Filter>ripple\module\app\paths</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\module\app\peers\ClusterNodeStatus.h">
|
||||
<Filter>ripple\module\app\peers</Filter>
|
||||
</ClInclude>
|
||||
@@ -4119,6 +4131,9 @@
|
||||
<ClCompile Include="..\..\src\ripple\module\rpc\handlers\LedgerHeader.cpp">
|
||||
<Filter>ripple\module\rpc\handlers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\module\rpc\handlers\LedgerRequest.cpp">
|
||||
<Filter>ripple\module\rpc\handlers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\module\rpc\handlers\LogLevel.cpp">
|
||||
<Filter>ripple\module\rpc\handlers</Filter>
|
||||
</ClCompile>
|
||||
@@ -4260,9 +4275,6 @@
|
||||
<ClInclude Include="..\..\src\ripple\module\rpc\impl\GetMasterGenerator.h">
|
||||
<Filter>ripple\module\rpc\impl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\module\rpc\impl\Handlers.cpp">
|
||||
<Filter>ripple\module\rpc\impl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\module\rpc\impl\LegacyPathFind.cpp">
|
||||
<Filter>ripple\module\rpc\impl</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -25,34 +25,35 @@
|
||||
#include <ripple/module/app/paths/Tuning.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <ripple/module/app/paths/Tuning.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <ripple/module/app/paths/Tuning.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <ripple/module/app/paths/Tuning.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -22,14 +22,15 @@
|
||||
#include <ripple/module/app/paths/Tuning.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <ripple/module/app/paths/Tuning.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <ripple/module/app/paths/Tuning.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <ripple/module/app/paths/Tuning.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -20,17 +20,29 @@
|
||||
#ifndef RIPPLE_PATHS_CALCULATORS_H
|
||||
#define RIPPLE_PATHS_CALCULATORS_H
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <ripple/module/app/paths/CalcState.h>
|
||||
#include <ripple/module/app/paths/QualityConstraint.h>
|
||||
#include <ripple/module/app/paths/RippleCalc.h>
|
||||
#include <ripple/module/app/paths/Tuning.h>
|
||||
|
||||
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<PathState::pointer>& 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
|
||||
|
||||
82
src/ripple/module/app/paths/Node.cpp
Normal file
82
src/ripple/module/app/paths/Node.cpp
Normal file
@@ -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
|
||||
95
src/ripple/module/app/paths/Node.h
Normal file
95
src/ripple/module/app/paths/Node.h
Normal file
@@ -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<Node> 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
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/module/app/paths/Tuning.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <tuple>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <ripple/module/app/paths/Calculators.h>
|
||||
|
||||
@@ -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<PathState::pointer> 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
|
||||
|
||||
@@ -50,10 +50,9 @@ public:
|
||||
// VFALCO TODO Break the cyclic dependency on InfoSub
|
||||
PathRequest (std::shared_ptr <InfoSub> 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);
|
||||
|
||||
@@ -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<AccountCurrencyIssuer>{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;
|
||||
|
||||
@@ -20,110 +20,34 @@
|
||||
#ifndef RIPPLE_PATHSTATE_H
|
||||
#define RIPPLE_PATHSTATE_H
|
||||
|
||||
#include <ripple/module/app/paths/Node.h>
|
||||
#include <ripple/module/app/paths/Types.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
// account id, currency id, issuer id :: node
|
||||
typedef std::tuple <uint160, uint160, uint160> AccountCurrencyIssuer;
|
||||
|
||||
// Map of currency, issuer to node index.
|
||||
typedef ripple::unordered_map <AccountCurrencyIssuer, unsigned int>
|
||||
AccountCurrencyIssuerToNodeIndex;
|
||||
|
||||
extern std::size_t hash_value (const AccountCurrencyIssuer& asValue);
|
||||
|
||||
// Holds a path state under incremental application.
|
||||
class PathState : public CountedObject <PathState>
|
||||
{
|
||||
public:
|
||||
public:
|
||||
typedef std::vector<uint256> OfferIndexList;
|
||||
typedef std::vector<std::shared_ptr<PathState>> 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<PathState> pointer;
|
||||
typedef const std::shared_ptr<PathState>& 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<Node> 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<uint256> 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
|
||||
|
||||
@@ -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<PathState::pointer> 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<PathState::pointer> 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)
|
||||
|
||||
31
src/ripple/module/app/paths/QualityConstraint.h
Normal file
31
src/ripple/module/app/paths/QualityConstraint.h
Normal file
@@ -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
|
||||
@@ -27,12 +27,18 @@
|
||||
#include <ripple/module/app/paths/CalcNodeDeliverRev.cpp>
|
||||
#include <ripple/module/app/paths/CalcNodeOffer.cpp>
|
||||
#include <ripple/module/app/paths/CalcNodeRipple.cpp>
|
||||
#include <ripple/module/app/paths/Node.cpp>
|
||||
#include <ripple/module/app/paths/PathNext.cpp>
|
||||
|
||||
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<PathState::pointer>& 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<PathState> (
|
||||
auto pspDirect = std::make_shared<PathState> (
|
||||
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<PathState> (
|
||||
auto pspExpanded = std::make_shared<PathState> (
|
||||
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
|
||||
|
||||
@@ -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<PathState::pointer>& 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
|
||||
|
||||
43
src/ripple/module/app/paths/Types.h
Normal file
43
src/ripple/module/app/paths/Types.h
Normal file
@@ -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 <uint160, uint160, uint160> AccountCurrencyIssuer;
|
||||
|
||||
std::size_t hash_value (const AccountCurrencyIssuer& asValue);
|
||||
|
||||
// Map of account, currency, issuer to node index.
|
||||
typedef ripple::unordered_map <AccountCurrencyIssuer, unsigned int>
|
||||
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
|
||||
@@ -232,7 +232,7 @@ TER Payment::doApply ()
|
||||
|
||||
// Copy paths into an editable class.
|
||||
STPathSet spsPaths = mTxn.getFieldPathSet (sfPaths);
|
||||
std::vector<PathState::pointer> 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,
|
||||
|
||||
@@ -203,10 +203,10 @@ Json::Value RPCHandler::doRipplePathFind (
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<PathState::pointer> 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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user