diff --git a/src/cpp/ripple/Amount.cpp b/src/cpp/ripple/Amount.cpp index 40639d164..52ff6f8d3 100644 --- a/src/cpp/ripple/Amount.cpp +++ b/src/cpp/ripple/Amount.cpp @@ -383,7 +383,7 @@ bool STAmount::setFullValue(const std::string& sAmount, const std::string& sCurr // Stamps not must have an issuer. if (mIsNative && !mIssuer.isZero()) { - Log(lsINFO) << "Issuer specified for stamps: " << sIssuer; + Log(lsINFO) << "Issuer specified for XRP: " << sIssuer; return false; } diff --git a/src/cpp/ripple/Ledger.cpp b/src/cpp/ripple/Ledger.cpp index 94754a931..03e0a48d1 100644 --- a/src/cpp/ripple/Ledger.cpp +++ b/src/cpp/ripple/Ledger.cpp @@ -944,7 +944,7 @@ uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uT % RippleAddress::createHumanAccountID(uTakerGetsIssuerID) % uBaseIndex.ToString()); - assert(!bInNative || !bOutNative); // Stamps to stamps not allowed. + assert(!bInNative || !bOutNative); // XRP to XRP not allowed. assert(bInNative == uTakerPaysIssuerID.isZero()); // Make sure issuer is specified as needed. assert(bOutNative == uTakerGetsIssuerID.isZero()); // Make sure issuer is specified as needed. assert(uTakerPaysCurrency != uTakerGetsCurrency || uTakerPaysIssuerID != uTakerGetsIssuerID); // Currencies or accounts must differ. diff --git a/src/cpp/ripple/RippleCalc.cpp b/src/cpp/ripple/RippleCalc.cpp index 738d07d71..568449eb0 100644 --- a/src/cpp/ripple/RippleCalc.cpp +++ b/src/cpp/ripple/RippleCalc.cpp @@ -1472,26 +1472,27 @@ TER PathState::pushImply( { // Currency is different, need to convert via an offer. - terResult = pushNode( - STPathElement::typeCurrency // Offer. - | STPathElement::typeIssuer, - ACCOUNT_ONE, // Placeholder for offers. + terResult = pushNode( // Offer. + !!uCurrencyID + ? STPathElement::typeCurrency | STPathElement::typeIssuer + : STPathElement::typeCurrency, + ACCOUNT_XRP, // Placeholder for offers. uCurrencyID, // The offer's output is what is now wanted. uIssuerID); } const PaymentNode& pnBck = vpnNodes.back(); - // For ripple, non-stamps, ensure the issuer is on at least one side of the transaction. + // For ripple, non-XRP, ensure the issuer is on at least one side of the transaction. if (tesSUCCESS == terResult - && !!uCurrencyID // Not stamps. + && !!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. terResult = pushNode( - STPathElement::typeAccount, + STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer, uIssuerID, // Intermediate account is the needed issuer. uCurrencyID, uIssuerID); @@ -1511,10 +1512,6 @@ TER PathState::pushNode( const uint160& uCurrencyID, const uint160& uIssuerID) { - cLog(lsINFO) << "pushNode> " - << RippleAddress::createHumanAccountID(uAccountID) - << " " << STAmount::createHumanCurrency(uCurrencyID) - << "/" << RippleAddress::createHumanAccountID(uIssuerID); PaymentNode pnCur; const bool bFirst = vpnNodes.empty(); const PaymentNode& pnPrv = bFirst ? PaymentNode() : vpnNodes.back(); @@ -1527,11 +1524,30 @@ TER PathState::pushNode( const bool bIssuer = isSetBit(iType, STPathElement::typeIssuer); TER terResult = tesSUCCESS; + cLog(lsDEBUG) << "pushNode> " + << iType + << ": " << (bAccount ? RippleAddress::createHumanAccountID(uAccountID) : "-") + << " " << (bCurrency ? STAmount::createHumanCurrency(uCurrencyID) : "-") + << "/" << (bIssuer ? RippleAddress::createHumanAccountID(uIssuerID) : "-"); + pnCur.uFlags = iType; + pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; if (iType & ~STPathElement::typeValidBits) { - cLog(lsINFO) << "pushNode: bad bits."; + cLog(lsDEBUG) << "pushNode: bad bits."; + + terResult = temBAD_PATH; + } + else if (bIssuer && !pnCur.uCurrencyID) + { + cLog(lsDEBUG) << "pushNode: issuer specified for XRP."; + + terResult = temBAD_PATH; + } + else if (bIssuer && !uIssuerID) + { + cLog(lsDEBUG) << "pushNode: specified bad issuer."; terResult = temBAD_PATH; } @@ -1540,8 +1556,11 @@ TER PathState::pushNode( // Account link pnCur.uAccountID = uAccountID; - pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; - pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; + pnCur.uIssuerID = bIssuer + ? uIssuerID + : !!pnCur.uCurrencyID + ? uAccountID + : ACCOUNT_XRP; pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID); pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID); @@ -1551,6 +1570,12 @@ TER PathState::pushNode( nothing(); } + else if (!uAccountID) + { + cLog(lsDEBUG) << "pushNode: specified bad account."; + + terResult = temBAD_PATH; + } else { // Add required intermediate nodes to deliver to current account. @@ -1612,19 +1637,28 @@ TER PathState::pushNode( { // Offer link // Offers bridge a change in currency & issuer or just a change in issuer. - pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; - pnCur.uIssuerID = bIssuer ? uIssuerID : pnCur.uAccountID; + pnCur.uIssuerID = bIssuer + ? uIssuerID + : !!pnCur.uCurrencyID + ? !!pnPrv.uIssuerID + ? pnPrv.uIssuerID // Default to previous issuer + : pnPrv.uAccountID // Or previous account if no previous issuer. + : ACCOUNT_XRP; pnCur.saRateMax = saZero; - if (!!pnPrv.uAccountID) + if (!!pnCur.uCurrencyID != !!pnCur.uIssuerID) + { + cLog(lsDEBUG) << "pushNode: currency is inconsistent with issuer."; + + terResult = temBAD_PATH; + } + else if (!!pnPrv.uAccountID) { // Previous is an account. // Insert intermediary issuer account if needed. terResult = pushImply( - !!pnPrv.uCurrencyID - ? ACCOUNT_ONE // Rippling, but offer's don't have an account. - : ACCOUNT_XRP, + ACCOUNT_XRP, // Rippling, but offer's don't have an account. pnPrv.uCurrencyID, pnPrv.uIssuerID); } @@ -1655,30 +1689,37 @@ PathState::PathState( saInReq(saSendMax), saOutReq(saSend) { - const uint160 uInCurrencyID = saSendMax.getCurrency(); + const uint160 uMaxCurrencyID = saSendMax.getCurrency(); + const uint160 uMaxIssuerID = saSendMax.getIssuer(); + const uint160 uOutCurrencyID = saSend.getCurrency(); - const uint160 uInIssuerID = !!uInCurrencyID ? saSendMax.getIssuer() : ACCOUNT_XRP; - const uint160 uOutIssuerID = !!uOutCurrencyID ? saSend.getIssuer() : ACCOUNT_XRP; + const uint160 uOutIssuerID = saSend.getIssuer(); + const uint160 uSenderIssuerID = !!uMaxCurrencyID ? uSenderID : ACCOUNT_XRP; // Sender is always issuer for non-XRP. lesEntries = lesSource.duplicate(); + terStatus = tesSUCCESS; + + if ((!uMaxCurrencyID && !!uMaxIssuerID) || (!uOutCurrencyID && !!uOutIssuerID)) + terStatus = temBAD_PATH; + // Push sending node. - terStatus = pushNode( - STPathElement::typeAccount - | STPathElement::typeCurrency - | STPathElement::typeIssuer, - uSenderID, - uInCurrencyID, - uSenderID); + if (tesSUCCESS == terStatus) + terStatus = pushNode( + !!uMaxCurrencyID + ? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer + : STPathElement::typeAccount | STPathElement::typeCurrency, + uSenderID, + uMaxCurrencyID, // Max specifes the currency. + uSenderIssuerID); cLog(lsDEBUG) << boost::str(boost::format("PathState: pushed: account=%s currency=%s issuer=%s") % RippleAddress::createHumanAccountID(uSenderID) - % STAmount::createHumanCurrency(uInCurrencyID) - % RippleAddress::createHumanAccountID(uSenderID)); + % STAmount::createHumanCurrency(uMaxCurrencyID) + % RippleAddress::createHumanAccountID(uSenderIssuerID)); if (tesSUCCESS == terStatus - && !!uInCurrencyID // First was not XRC - && uInIssuerID != uSenderID) { // Issuer was not same as sender + && uMaxIssuerID != uSenderIssuerID) { // Issuer was not same as sender // May have an implied node. // Figure out next node properties for implied node. @@ -1698,22 +1739,22 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: implied check: uNxtCurrenc % RippleAddress::createHumanAccountID(uNxtAccountID)); // 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 + if (!uNxtCurrencyID // Next is XRP - will have offer next + || uMaxCurrencyID != uNxtCurrencyID // Next is different current - will have offer next + || uMaxIssuerID != uNxtAccountID) // Next is not implied issuer { -cLog(lsDEBUG) << boost::str(boost::format("PathState: implied: account=%s currency=%s issuer=%s") - % RippleAddress::createHumanAccountID(uInIssuerID) - % RippleAddress::createHumanAccountID(uInCurrencyID) - % RippleAddress::createHumanAccountID(uInIssuerID)); - // Add implied account. +cLog(lsDEBUG) << boost::str(boost::format("PathState: sender implied: account=%s currency=%s issuer=%s") + % RippleAddress::createHumanAccountID(uMaxIssuerID) + % RippleAddress::createHumanAccountID(uMaxCurrencyID) + % RippleAddress::createHumanAccountID(uMaxIssuerID)); + // Add account implied by SendMax. terStatus = pushNode( - STPathElement::typeAccount - | STPathElement::typeCurrency - | STPathElement::typeIssuer, - uInIssuerID, - uInCurrencyID, - uInIssuerID); + !!uMaxCurrencyID + ? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer + : STPathElement::typeAccount | STPathElement::typeCurrency, + uMaxIssuerID, + uMaxCurrencyID, + uMaxIssuerID); } } @@ -1726,32 +1767,37 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: implied: account=%s curren const PaymentNode& pnPrv = vpnNodes.back(); if (tesSUCCESS == terStatus - && !!uOutCurrencyID // Next is not XRC + && !!uOutCurrencyID // Next is not XRP && 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. +cLog(lsDEBUG) << boost::str(boost::format("PathState: receiver implied: account=%s currency=%s issuer=%s") + % RippleAddress::createHumanAccountID(uOutIssuerID) + % RippleAddress::createHumanAccountID(uOutCurrencyID) + % RippleAddress::createHumanAccountID(uOutIssuerID)); terStatus = pushNode( - STPathElement::typeAccount - | STPathElement::typeCurrency - | STPathElement::typeIssuer, + !!uOutCurrencyID + ? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer + : STPathElement::typeAccount | STPathElement::typeCurrency, uOutIssuerID, - uInCurrencyID, + uOutCurrencyID, uOutIssuerID); } if (tesSUCCESS == terStatus) { // Create receiver node. + // Last node is always an account. terStatus = pushNode( - STPathElement::typeAccount // Last node is always an account. - | STPathElement::typeCurrency - | STPathElement::typeIssuer, + !!uOutCurrencyID + ? STPathElement::typeAccount | STPathElement::typeCurrency | STPathElement::typeIssuer + : STPathElement::typeAccount | STPathElement::typeCurrency, uReceiverID, // Receive to output uOutCurrencyID, // Desired currency - !!uOutCurrencyID ? uReceiverID : ACCOUNT_XRP); + uReceiverID); } if (tesSUCCESS == terStatus) @@ -1773,7 +1819,7 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: implied: account=%s curren else if (!umForward.insert(std::make_pair(boost::make_tuple(pnCur.uAccountID, pnCur.uCurrencyID, pnCur.uIssuerID), uNode)).second) { // Failed to insert. Have a loop. - cLog(lsINFO) << boost::str(boost::format("PathState: loop detected: %s") + cLog(lsDEBUG) << boost::str(boost::format("PathState: loop detected: %s") % getJson()); terStatus = temBAD_PATH_LOOP; @@ -1782,8 +1828,8 @@ cLog(lsDEBUG) << boost::str(boost::format("PathState: implied: account=%s curren } cLog(lsINFO) << boost::str(boost::format("PathState: in=%s/%s out=%s/%s %s") - % STAmount::createHumanCurrency(uInCurrencyID) - % RippleAddress::createHumanAccountID(uInIssuerID) + % STAmount::createHumanCurrency(uMaxCurrencyID) + % RippleAddress::createHumanAccountID(uMaxIssuerID) % STAmount::createHumanCurrency(uOutCurrencyID) % RippleAddress::createHumanAccountID(uOutIssuerID) % getJson()); @@ -2024,7 +2070,7 @@ TER RippleCalc::rippleCalc( if (!bNoRippleDirect) { // Direct path. - // XXX Might also make a stamp bridge by default. + // XXX Might also make a XRP bridge by default. PathState::pointer pspDirect = PathState::createPathState( vpsPaths.size(), @@ -2274,7 +2320,7 @@ TER calcOfferFill(PaymentNode& pnSrc, PaymentNode& pnDst, bool bAllowPartial) if (pnDst.saWanted.isNative()) { - // Transfer stamps. + // Transfer XRP. STAmount saSrcFunds = pnSrc.saAccount->accountHolds(pnSrc.saAccount, uint160(0), uint160(0)); @@ -2366,7 +2412,7 @@ void TransactionEngine::calcOfferBridgeNext( if (saOfferPays.isNative()) { - // No additional fees for stamps. + // No additional fees for XRP. nothing(); } @@ -2427,7 +2473,7 @@ void TransactionEngine::calcOfferBridgeNext( #endif #if 0 -// If either currency is not stamps, then also calculates vs stamp bridge. +// If either currency is not XRP, then also calculates vs XRP bridge. // --> saWanted: Limit of how much is wanted out. // <-- saPay: How much to pay into the offer. // <-- saGot: How much to the offer pays out. Never more than saWanted.