mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-26 14:05:51 +00:00
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:
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user