Fix ripple bugs.

- Default send max inherits source account as issuer.
- Add end point implications for node expansion.
- Fix rippling through accounts.
This commit is contained in:
Arthur Britto
2012-11-03 04:16:48 -07:00
parent 4adb0e07a2
commit 7c595bf23b
3 changed files with 101 additions and 53 deletions

View File

@@ -799,7 +799,11 @@ void RippleCalc::calcNodeRipple(
} }
// Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver from saCur... // Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver from saCur...
// No account adjustments in reverse as we don't know how much is going to actually be pushed through yet. // Based on required deliverable, propagate redeem, issue, and deliver requests to the previous node.
// Inflate amount requested by required fees.
// Reedems are limited based on IOUs previous has on hand.
// Issues are limited based on credit limits and amount owed.
// No account balance adjustments as we don't know how much is going to actually be pushed through yet.
// <-- tesSUCCESS or tepPATH_DRY // <-- tesSUCCESS or tepPATH_DRY
TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality) TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref pspCur, const bool bMultiQuality)
{ {
@@ -1135,7 +1139,9 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, PathState::ref psp
return terResult; return terResult;
} }
// When moving forward, we know the actual amount to push through so adjust balances. // The reverse pass has been narrowing by credit available and inflating by fees as it worked backwards.
// Now, push through the actual amount to each node and adjust balances.
//
// Perform balance adjustments between previous and current node. // Perform balance adjustments between previous and current node.
// - The previous node: specifies what to push through to current. // - The previous node: specifies what to push through to current.
// - All of previous output is consumed. // - All of previous output is consumed.
@@ -1204,46 +1210,39 @@ TER RippleCalc::calcNodeAccountFwd(
if (bPrvAccount && bNxtAccount) if (bPrvAccount && bNxtAccount)
{ {
// Next is an account, must be rippling.
if (!uIndex) if (!uIndex)
{ {
// ^ --> ACCOUNT --> account // ^ --> ACCOUNT --> account
// First node, calculate amount to send. // First node, calculate amount to ripple based on what is available.
// XXX Limit by stamp/ripple balance
const STAmount& saCurSendMaxReq = pspCur->saInReq.isNegative() // Limit by sendmax.
? pspCur->saInReq // Negative for no limit, doing a calculation. const STAmount saCurSendMaxReq = pspCur->saInReq.isNegative()
? pspCur->saInReq // Negative for no limit, doing a calculation.
: pspCur->saInReq-pspCur->saInAct; // request - done. : pspCur->saInReq-pspCur->saInAct; // request - done.
STAmount& saCurSendMaxPass = pspCur->saInPass; // Report how much pass sends. STAmount& saCurSendMaxPass = pspCur->saInPass; // Report how much pass sends.
if (saCurRedeemReq) saCurRedeemAct = saCurRedeemReq
{ // Redeem requested.
// Redeem requested. ? saCurRedeemReq.isNegative()
saCurRedeemAct = saCurRedeemReq.isNegative() ? saCurRedeemReq
? saCurRedeemReq : std::min(saCurRedeemReq, saCurSendMaxReq)
: std::min(saCurRedeemReq, saCurSendMaxReq); // No redeeming.
} : saCurRedeemReq;
else
{
// No redeeming.
saCurRedeemAct = saCurRedeemReq;
}
saCurSendMaxPass = saCurRedeemAct; saCurSendMaxPass = saCurRedeemAct;
if (saCurIssueReq && (saCurSendMaxReq.isNegative() || saCurSendMaxPass != saCurSendMaxReq)) saCurIssueAct = (saCurIssueReq // Issue wanted.
{ && (saCurSendMaxReq.isNegative() // No limit.
// Issue requested and pass does not meet max. || saCurSendMaxPass != saCurSendMaxReq)) // Not yet satisfied.
saCurIssueAct = saCurSendMaxReq.isNegative() // Issue requested and pass does not meet max.
? saCurIssueReq ? saCurSendMaxReq.isNegative()
: std::min(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); ? saCurIssueReq
} : std::min(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq)
else // No issuing.
{ : STAmount(saCurIssueReq);
// No issuing.
saCurIssueAct = STAmount(saCurIssueReq);
}
saCurSendMaxPass += saCurIssueAct; saCurSendMaxPass += saCurIssueAct;
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saInReq=%s saInAct=%s saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s saCurSendMaxPass=%s") cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saInReq=%s saInAct=%s saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s saCurSendMaxPass=%s")
@@ -1287,7 +1286,7 @@ TER RippleCalc::calcNodeAccountFwd(
saCurIssueAct.zero(saCurIssueReq); saCurIssueAct.zero(saCurIssueReq);
// Previous redeem part 1: redeem -> redeem // Previous redeem part 1: redeem -> redeem
if (saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. if (saPrvRedeemReq && saCurRedeemReq) // Previous wants to redeem.
{ {
// Rate : 1.0 : quality out // Rate : 1.0 : quality out
calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax); calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax);
@@ -1302,25 +1301,23 @@ TER RippleCalc::calcNodeAccountFwd(
} }
// Previous redeem part 2: redeem -> issue. // Previous redeem part 2: redeem -> issue.
// wants to redeem and current would and can issue.
// If redeeming cur to next is done, this implies can issue.
if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem. if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem.
&& saCurRedeemReq == saCurRedeemAct // Current has no more to redeem to next. && saCurRedeemReq == saCurRedeemAct // Current redeeming is done can issue.
&& saCurIssueReq) && saCurIssueReq) // Current wants to issue.
{ {
// Rate : 1.0 : transfer_rate // Rate : 1.0 : transfer_rate
calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax); calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax);
} }
// Previous issue part 2 : issue -> issue // Previous issue part 2 : issue -> issue
if (saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. if (saPrvIssueReq != saPrvIssueAct // Previous wants to issue.
&& saCurRedeemReq == saCurRedeemAct) // Current redeeming is done can issue.
{ {
// Rate: quality in : 1.0 // Rate: quality in : 1.0
calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax); calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax);
} }
// Adjust prv --> cur balance : take all inbound // Adjust prv --> cur balance : take all inbound
// XXX Currency must be in amount.
lesActive.rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false); lesActive.rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false);
} }
} }
@@ -1429,7 +1426,7 @@ bool PathState::lessPriority(PathState::ref lhs, PathState::ref rhs)
return lhs->mIndex > rhs->mIndex; // Bigger is worse. return lhs->mIndex > rhs->mIndex; // Bigger is worse.
} }
// Make sure the path delivers to uAccountID: uCurrencyID from uIssuerID. // 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.
// //
@@ -1651,7 +1648,40 @@ PathState::PathState(
| STPathElement::typeIssuer, | STPathElement::typeIssuer,
uSenderID, uSenderID,
uInCurrencyID, uInCurrencyID,
uInIssuerID); uSenderID);
if (tesSUCCESS == terStatus
&& !!uInCurrencyID // First was not XRC
&& uInIssuerID != uSenderID) { // Issuer was not same as sender
// May have an implied node.
// Figure out next node properties for implied node.
const uint160 uNxtCurrencyID = spSourcePath.getElementCount()
? spSourcePath.getElement(0).getCurrency()
: uOutCurrencyID;
const uint160 uNxtAccountID = spSourcePath.getElementCount()
? spSourcePath.getElement(0).getAccountID()
: !!uOutCurrencyID
? uOutIssuerID == uReceiverID
? uReceiverID
: uOutIssuerID
: ACCOUNT_XNS;
// Can't just use push implied, because it can't compensate for next account.
if (!uNxtCurrencyID // Next is XRC - will have offer next
|| uInCurrencyID != uNxtCurrencyID // Next is different current - will have offer next
|| uInIssuerID != uNxtAccountID) // Next is not implied issuer
{
// Add implied account.
terStatus = pushNode(
STPathElement::typeAccount
| STPathElement::typeCurrency
| STPathElement::typeIssuer,
uInIssuerID,
uInCurrencyID,
uInIssuerID);
}
}
BOOST_FOREACH(const STPathElement& speElement, spSourcePath) BOOST_FOREACH(const STPathElement& speElement, spSourcePath)
{ {
@@ -1659,21 +1689,35 @@ PathState::PathState(
terStatus = pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID()); terStatus = pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID());
} }
const PaymentNode& pnPrv = vpnNodes.back();
if (tesSUCCESS == terStatus
&& !!uOutCurrencyID // Next is not XRC
&& uOutIssuerID != uReceiverID // Out issuer is not reciever
&& (pnPrv.uCurrencyID != uOutCurrencyID // Previous will be an offer.
|| pnPrv.uAccountID != uOutIssuerID)) // Need the implied issuer.
{
// Add implied account.
terStatus = pushNode(
STPathElement::typeAccount
| STPathElement::typeCurrency
| STPathElement::typeIssuer,
uOutIssuerID,
uInCurrencyID,
uOutIssuerID);
}
if (tesSUCCESS == terStatus) if (tesSUCCESS == terStatus)
{ {
// Create receiver node. // Create receiver node.
terStatus = pushImply(uReceiverID, uOutCurrencyID, uOutIssuerID); terStatus = pushNode(
if (tesSUCCESS == terStatus) STPathElement::typeAccount // Last node is always an account.
{ | STPathElement::typeCurrency
terStatus = pushNode( | STPathElement::typeIssuer,
STPathElement::typeAccount // Last node is always an account. uReceiverID, // Receive to output
| STPathElement::typeCurrency uOutCurrencyID, // Desired currency
| STPathElement::typeIssuer, !!uOutCurrencyID ? uReceiverID : ACCOUNT_XNS);
uReceiverID, // Receive to output
uOutCurrencyID, // Desired currency
uOutIssuerID);
}
} }
if (tesSUCCESS == terStatus) if (tesSUCCESS == terStatus)

View File

@@ -603,7 +603,7 @@ public:
int getElementCount() const { return mPath.size(); } int getElementCount() const { return mPath.size(); }
bool isEmpty() const { return mPath.empty(); } bool isEmpty() const { return mPath.empty(); }
const STPathElement& getElement(int offset) const { return mPath[offset]; } const STPathElement& getElement(int offset) const { return mPath[offset]; }
const STPathElement& getElemet(int offset) { return mPath[offset]; } const STPathElement& getElement(int offset) { return mPath[offset]; }
void addElement(const STPathElement &e) { mPath.push_back(e); } void addElement(const STPathElement &e) { mPath.push_back(e); }
void clear() { mPath.clear(); } void clear() { mPath.clear(); }
bool hasSeen(const uint160 &acct); bool hasSeen(const uint160 &acct);

View File

@@ -462,7 +462,11 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac
const bool bMax = txn.isFieldPresent(sfSendMax); const bool bMax = txn.isFieldPresent(sfSendMax);
const uint160 uDstAccountID = txn.getFieldAccount160(sfDestination); const uint160 uDstAccountID = txn.getFieldAccount160(sfDestination);
const STAmount saDstAmount = txn.getFieldAmount(sfAmount); const STAmount saDstAmount = txn.getFieldAmount(sfAmount);
const STAmount saMaxAmount = bMax ? txn.getFieldAmount(sfSendMax) : saDstAmount; const STAmount saMaxAmount = bMax
? txn.getFieldAmount(sfSendMax)
: saDstAmount.isNative()
? saDstAmount
: STAmount(saDstAmount.getCurrency(), mTxnAccountID, saDstAmount.getMantissa(), saDstAmount.getExponent(), saDstAmount.isNegative());
const uint160 uSrcCurrency = saMaxAmount.getCurrency(); const uint160 uSrcCurrency = saMaxAmount.getCurrency();
const uint160 uDstCurrency = saDstAmount.getCurrency(); const uint160 uDstCurrency = saDstAmount.getCurrency();