diff --git a/src/Config.cpp b/src/Config.cpp index 4e36f39a1b..a419ae0aae 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #define SECTION_ACCOUNT_PROBE_MAX "account_probe_max" #define SECTION_DEBUG_LOGFILE "debug_logfile" @@ -232,19 +233,19 @@ void Config::load() if (sectionSingleB(secConfig, SECTION_PEER_SCAN_INTERVAL_MIN, strTemp)) // Minimum for min is 60 seconds. - PEER_SCAN_INTERVAL_MIN = MAX(60, boost::lexical_cast(strTemp)); + PEER_SCAN_INTERVAL_MIN = std::max(60, boost::lexical_cast(strTemp)); if (sectionSingleB(secConfig, SECTION_PEER_START_MAX, strTemp)) - PEER_START_MAX = MAX(1, boost::lexical_cast(strTemp)); + PEER_START_MAX = std::max(1, boost::lexical_cast(strTemp)); if (sectionSingleB(secConfig, SECTION_PEER_CONNECT_LOW_WATER, strTemp)) - PEER_CONNECT_LOW_WATER = MAX(1, boost::lexical_cast(strTemp)); + PEER_CONNECT_LOW_WATER = std::max(1, boost::lexical_cast(strTemp)); if (sectionSingleB(secConfig, SECTION_NETWORK_QUORUM, strTemp)) - NETWORK_QUORUM = MAX(0, boost::lexical_cast(strTemp)); + NETWORK_QUORUM = std::max(0, boost::lexical_cast(strTemp)); if (sectionSingleB(secConfig, SECTION_VALIDATION_QUORUM, strTemp)) - VALIDATION_QUORUM = MAX(0, boost::lexical_cast(strTemp)); + VALIDATION_QUORUM = std::max(0, boost::lexical_cast(strTemp)); if (sectionSingleB(secConfig, SECTION_FEE_ACCOUNT_CREATE, strTemp)) FEE_ACCOUNT_CREATE = boost::lexical_cast(strTemp); diff --git a/src/ConnectionPool.cpp b/src/ConnectionPool.cpp index 14e5604841..acceef4887 100644 --- a/src/ConnectionPool.cpp +++ b/src/ConnectionPool.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "Config.h" #include "Peer.h" @@ -645,7 +646,7 @@ void ConnectionPool::scanRefresh() (void) mScanTimer.cancel(); - iInterval = MAX(iInterval, theConfig.PEER_SCAN_INTERVAL_MIN); + iInterval = std::max(iInterval, theConfig.PEER_SCAN_INTERVAL_MIN); tpNext = tpNow + boost::posix_time::seconds(iInterval); diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 1fbb473c26..a99b4088fa 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -266,7 +266,7 @@ STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint16 // Use when you need a default for rippling uAccountID's currency. // --> saDefault/currency/issuer // <-- saFunds: Funds available. May be negative. -// If the issuer is the same as uAccountID, result is Default. +// If the issuer is the same as uAccountID, funds are unlimited, use result is saDefault. STAmount TransactionEngine::accountFunds(const uint160& uAccountID, const STAmount& saDefault) { STAmount saFunds; @@ -861,7 +861,9 @@ SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint25 mNodes.entryCache(sleEntry); } else if (action == taaDELETE) + { assert(false); + } } return sleEntry; @@ -1321,13 +1323,13 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Log(lsINFO) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman; - if (terResult >= tepPATH_PARTIAL && isSetBit(params, tapRETRY)) + if (isTepPartial(terResult) && isSetBit(params, tapRETRY)) { // Partial result and allowed to retry, reclassify as a retry. terResult = terRETRY; } - if (tesSUCCESS == terResult || terResult >= tepPATH_PARTIAL) + if (tesSUCCESS == terResult || isTepPartial(terResult)) { // Transaction succeeded fully or (retries are not allowed and the transaction succeeded partially). txnWrite(); @@ -1348,8 +1350,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, musUnfundedFound.clear(); if (!isSetBit(params, tapOPEN_LEDGER) - && ((terResult >= temMALFORMED && terResult <= tefFAILURE) - || ((terResult >= tefFAILURE && terResult <= terRETRY)))) + && (isTemMalformed(terResult) || isTefFailure(terResult))) { // XXX Malformed or failed transaction in closed ledger must bow out. } @@ -1968,8 +1969,7 @@ TER TransactionEngine::calcNodeOfferRev( Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString()); - while (!!uDirectTip // Have a quality. - && saCurDlvAct != saCurDlvReq) + while (!!uDirectTip && saCurDlvAct != saCurDlvReq) // Have a quality and not done. { // Get next quality. if (bAdvance) @@ -2033,7 +2033,7 @@ TER TransactionEngine::calcNodeOfferRev( curIssuerNodeConstIterator itSourcePast = mumSource.find(asLine); bool bFoundPast = itSourcePast != mumSource.end(); - if (!saCurOfrFunds) + if (!saCurOfrFunds.isPositive()) { // Offer is unfunded. Log(lsINFO) << "calcNodeOfferRev: encountered unfunded offer"; @@ -2048,11 +2048,6 @@ TER TransactionEngine::calcNodeOfferRev( // Never mentioned before: found unfunded. musUnfundedFound.insert(uOfferIndex); // Mark offer for always deletion. } - else - { - // Mentioned before: source became unfunded. - pspCur->vUnfundedBecame.push_back(uOfferIndex); // Mark offer for deletion on use of current path state. - } continue; } @@ -2069,8 +2064,8 @@ TER TransactionEngine::calcNodeOfferRev( : saTransferRate; bool bFee = saFeeRate != saOne; - STAmount saOutBase = MIN(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed. - STAmount saOutCost = MIN( + STAmount saOutBase = std::min(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed. + STAmount saOutCost = std::min( bFee ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, @@ -2113,7 +2108,7 @@ TER TransactionEngine::calcNodeOfferRev( // Although the fee varies based upon the next offer it does not matter as the offer maker knows in // advance that they are obligated to pay a transfer fee of necessary. The owner of next offer has no // expectation of a quality in being applied. - SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); + SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); // ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip), uCurCurrencyID); // For correct ratio unsigned int uEntry = 0; uint256 uNxtIndex; @@ -2149,9 +2144,9 @@ TER TransactionEngine::calcNodeOfferRev( : saTransferRate; bool bFee = saFeeRate != saOne; - STAmount saOutBase = MIN(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed. - saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. - STAmount saOutCost = MIN( + STAmount saOutBase = std::min(saCurOfrOutReq, saCurDlvReq-saCurDlvAct);// Limit offer out by needed. + saOutBase = std::min(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. + STAmount saOutCost = std::min( bFee ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, @@ -2204,6 +2199,12 @@ TER TransactionEngine::calcNodeOfferRev( return terResult; } +// - Offer input is limbo. +// - Current offers consumed. +// - Current offer owners debited. +// - Transfer fees credited to issuer. +// - Payout to issuer or limbo. +// - Deliver is set without transfer fees. TER TransactionEngine::calcNodeOfferFwd( const unsigned int uIndex, // 0 < uIndex < uLast const PathState::pointer& pspCur, @@ -2211,7 +2212,7 @@ TER TransactionEngine::calcNodeOfferFwd( ) { TER terResult = tepPATH_DRY; - +#if 0 paymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; paymentNode& pnCur = pspCur->vpnNodes[uIndex]; paymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; @@ -2223,7 +2224,7 @@ TER TransactionEngine::calcNodeOfferFwd( const uint160& uNxtCurrencyID = pnNxt.uCurrencyID; const uint160& uNxtIssuerID = pnNxt.uIssuerID; -// const uint160& uPrvAccountID = pnPrv.uAccountID; + const uint160& uPrvAccountID = pnPrv.uAccountID; const uint160& uNxtAccountID = pnNxt.uAccountID; const STAmount saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID)); @@ -2234,15 +2235,42 @@ TER TransactionEngine::calcNodeOfferFwd( const STAmount& saPrvDlvReq = pnPrv.saFwdDeliver; // Forward driver. STAmount saPrvDlvAct; - STAmount& saCurDlvReq = pnCur.saFwdDeliver; - STAmount saCurDlvAct; + STAmount& saCurDlvAct = pnCur.saFwdDeliver; // How much current node will deliver. + saCurDlvAct = 0; - while (!!uDirectTip // Have a quality. - && saPrvDlvAct != saPrvDlvReq) + bool bNxtOffer = !uNxtAccountID; + uint256 uNxtTip; + uint256 uNxtEnd; + SLE::pointer sleNxtDir; + bool bNxtDirAdvance; + bool bNxtEntryDirty; + bool bNxtEntryAdvance; + unsigned int uNxtEntry; // Next nodes index. + uint256 uNxtIndex; // Next offer. + boost::unordered_map umNxtBalance; // Account valances. + STAmount saNxtOfrFunds; + STAmount saNxtOfrIn; + STAmount saNxtOfrOut; + SLE::pointer sleNxtOfr; + uint160 uNxtOfrAccountID; + STAmount saNxtFeeRate; + bool bNxtFee; + + if (bNxtOffer) + { + uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); + uNxtEnd = Ledger::getQualityNext(uNxtTip); + sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); + bNxtDirAdvance = !sleNxtDir; + uNxtEntry = 0; + bNxtEntryAdvance = true; + } + + while (!!uDirectTip && saPrvDlvAct != saPrvDlvReq) // Have a quality and not done. { - // Get next quality. if (bAdvance) { + // Get next quality. uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd); } else @@ -2278,8 +2306,8 @@ TER TransactionEngine::calcNodeOfferFwd( } // Allowed to access source from this node? - curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine); - bool bFoundForward = itAllow != pspCur->umForward.end(); + curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine); + const bool bFoundForward = itAllow != pspCur->umForward.end(); if (bFoundForward || itAllow->second != uIndex) { @@ -2290,13 +2318,11 @@ TER TransactionEngine::calcNodeOfferFwd( continue; } - const STAmount& saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets); - const STAmount& saCurOfrInReq = sleOffer->getIValueFieldAmount(sfTakerPays); - STAmount saCurOfrInAct; + const STAmount saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets); STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. - STAmount saCurOfrInMax = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); + STAmount saCurOfrSpent; - if (!saCurOfrFunds) + if (!saCurOfrFunds.isPositive()) { // Offer is unfunded. Log(lsINFO) << "calcNodeOfferFwd: unfunded offer"; @@ -2306,6 +2332,11 @@ TER TransactionEngine::calcNodeOfferFwd( continue; } + const STAmount saCurOfrInReq = sleOffer->getIValueFieldAmount(sfTakerPays); + STAmount saCurOfrInMax = std::min(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); + STAmount saCurOfrInAct; + STAmount saCurOfrOutAct; + if (!!uNxtAccountID) { // Next is an account node. @@ -2320,103 +2351,188 @@ TER TransactionEngine::calcNodeOfferFwd( const bool bFee = saFeeRate != saOne; const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID, uCurIssuerID); - const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. + const STAmount saOutBase = std::min(saCurOfrOutReq, saOutPass); // Limit offer out by needed. const STAmount saOutCostRaw= bFee ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase; - const STAmount saOutCost = MIN(saOutCostRaw, saCurOfrFunds); // Limit cost by fees & funds. - const STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; // Out amount after fees. + const STAmount saOutCost = std::min(saOutCostRaw, saCurOfrFunds); // Limit cost by fees & funds. + + saCurOfrSpent = saOutCost; // XXX Check. + saCurOfrOutAct = bFee + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) + : saOutCost; // Out amount after fees. + // Compute input w/o fees required. - const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uPrvIssuerID); + saCurOfrInAct = STAmount::multiply(saCurOfrOutAct, saOfrRate, uPrvCurrencyID, uPrvIssuerID); // Deliver to output. - accountSend(uCurOfrAccountID, uNxtAccountID, saOutDlvAct); - - saCurDlvAct += saOutDlvAct; // Portion of driver served. + accountSend(uCurOfrAccountID, uNxtAccountID, saCurOfrOutAct); } else { // Next is an offer node. // Need to step through next offer's nodes to figure out fees. + STAmount saNxtOfrRate; + bool bDirectoryFirst = true; - uint256 uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); - const uint256 uNxtEnd = Ledger::getQualityNext(uNxtTip); - bool bNxtAdvance = !entryCache(ltDIR_NODE, uNxtTip); - - while (!!uNxtTip // Have a quality. - && saPrvDlvAct != saPrvDlvReq) // Have more to do. + while (!!uNxtTip && saCurOfrInAct != saCurOfrInMax) // A next offer may be available and have more to do. { - if (bNxtAdvance) + if (!bNxtDirAdvance) { - uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd); + // Current directory is fine. + nothing(); + } + else if (bDirectoryFirst || bMultiQuality) + { + if (bDirectoryFirst) + bDirectoryFirst = false; + + uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd); + if (!!uNxtTip) + { + saNxtOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip)); // For correct ratio + sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); + + assert(!!sleNxtDir); + + bNxtDirAdvance = false; + uNxtEntry = 0; + bNxtEntryAdvance = true; + } + else + { + // No more next offers. Should be done rather than fall off end of book. + Log(lsINFO) << "Unreachable."; + assert(false); + } } else { - bNxtAdvance = true; + // Don't do another directory. + break; } - if (!!uNxtTip) + if (!bNxtEntryAdvance) { - // Do a directory. - // - Drive on computing saCurDlvAct to derive saPrvDlvAct. - SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); -// ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip)); // For correct ratio - unsigned int uEntry = 0; - uint256 uNxtIndex; - - while (saPrvDlvReq != saPrvDlvAct // Have not met request. - && dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex)) - { - // YYY This could combine offers with the same fee before doing math. - SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex); - const uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); - const STAmount& saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); - - const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID - ? saOne - : saTransferRate; - const bool bFee = saFeeRate != saOne; - -// XXX Skip expireds and unfundeds. - const STAmount saInBase = saCurOfrInMax-saCurOfrInAct; - const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID); - STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. - saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. - const STAmount saOutCost = MIN( - bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutBase, - saCurOfrFunds); // Limit cost by fees & funds. - const STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; // Out amount after fees. - const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required. - - saCurOfrInAct += saOutDlvAct; // Portion of driver served. - saPrvDlvAct += saOutDlvAct; // Portion needed in previous. - saCurDlvAct += saInDlvAct; // Portion of driver served. - } + // Current next directory is fine. + nothing(); + } + else if (dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex)) + { + // Found a next uNxtIndex. + bNxtEntryAdvance = false; + bNxtEntryDirty = true; + } + else + { + // No more offers in nxt directory. + bNxtDirAdvance = true; + continue; } - // Do another nxt directory iff bMultiQuality - if (!bMultiQuality) - uNxtTip = 0; + if (bNxtEntryDirty) + { + sleNxtOfr = entryCache(ltOFFER, uNxtIndex); + + if (sleNxtOfr->getIFieldPresent(sfExpiration) + && sleNxtOfr->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + { + // Offer is expired. + bNxtEntryAdvance = true; + continue; + } + + uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); + + saNxtFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID + ? saOne + : saTransferRate; + + bNxtFee = saNxtFeeRate != saOne; + + boost::unordered_map::const_iterator itNxtBalance = umNxtBalance.find(uNxtOfrAccountID); + saNxtOfrFunds = itNxtBalance == umNxtBalance.end() + ? accountFunds(uNxtOfrAccountID, saNxtOfrOut) + : it->second; + + saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); + saNxtOfrOut = sleNxtOfr->getIValueFieldAmount(sfTakerGets); + + // Cost (payout + fees) to next offer owner if offer is fully redeem. + STAmount saNxtOutCost = STAmount::multiply(saNxtOfrOut, saNxtFeeRate, saNxtOfrOut.getCurrency(), saNxtOfrOut.getIssuer()); + + if (saNxtOfrOut > saNxtOfrFunds) + { + // Limit offer by funds available. + STAmount saNxtOutMax = STAmount::divide(saNxtOfrOut, saNxtFeeRate, uCurCurrencyID, uCurIssuerID); + + } + + bNxtEntryDirty = false; + } + + if (!saNxtOfrFunds.isPositive()) + { + // Offer is unfunded. + bNxtEntryAdvance = true; + continue; + } + + STAmount saNxtOutAvail = + // Driving amount of input. + const STAmount saInBase = saCurOfrInMax-saCurOfrInAct; + + // Desired amount of output not including fees. + const STAmount saOutReq = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID); + STAmount saOutBase = std::min( + std::min(saCurOfrOutReq, saOutReq), // Limit offer out by needed. + saNxtOfrIn); // Limit offer out by supplying offer. + // Limit cost by fees & funds. + const STAmount saOutCost = std::min( + bNxtFee + ? STAmount::multiply(saOutBase, saNxtFeeRate, uCurCurrencyID, uCurIssuerID) + : saOutBase, + saCurOfrFunds); + // Compute output minus fees. Fees are offer's obligation and not passed to input. + const STAmount saOutDlvPass= bNxtFee + ? STAmount::divide(saOutCost, saNxtFeeRate, uCurCurrencyID, uCurIssuerID) + : saOutCost; + // Compute input based on output minus fees. + const STAmount saInDlvPass = STAmount::multiply(saOutDlvPass, saOfrRate, uPrvCurrencyID, uCurIssuerID); + + // XXX Check fees. + sleNxtOfr->setIFieldAmount(sfTakerGets, saNxtOfrIn - saInDlvPass); + sleNxtOfr->setIFieldAmount(sfTakerPays, saNxtOfrOut - saOutDlvPass); + + if (saNxtOfrOut == saOutDlvPass) { + // Consumed all of offer. + // XXX Move to outside. + Log(lsINFO) << "calcNodeOfferFwd: offer consumed"; + + pspCur->vUnfundedBecame.push_back(uNxtIndex); // Mark offer for deletion on use of current path state. + + bNxtEntryAdvance = true; + } + + umNxtBalance[uNxtOfrAccountID] = saNxtOfrFunds; + + saCurOfrSpent += saOutDlvPass; // XXX Check. + + saCurOfrInAct += saInDlvPass; // Add to input handled. + + saCurOfrOutAct += saOutDlvPass; // Add to output handled. } -#if 0 + // Deliver output to limbo or currency issuer. accountSend( - uCurOfrAccountID, // Offer owner pays. + uCurOfrAccountID, // Offer owner pays. !!uCurIssuerID ? uCurIssuerID // Output is non-XNS send to issuer. : ACCOUNT_XNS, // Output is XNS send to limbo (ACCOUNT_XNS). - saOutDlvAct); -#endif + saCurOfrOutAct); } // Deliver input to offer owner. -#if 0 accountSend( !!uPrvAccountID ? uPrvAccountID // Previous is an account. Source is previous account. @@ -2424,10 +2540,16 @@ TER TransactionEngine::calcNodeOfferFwd( ? ACCOUNT_XNS // Previous is offer outputing XNS, source is limbo (ACCOUNT_XNS). : uPrvIssuerID, // Previous is offer outputing non-XNS, source is input issuer. uCurOfrAccountID, // Offer owner receives. - saInDlvAct); + saCurOfrInAct); - saPrvDlvAct += saInDlvAct; // Portion needed in previous. -#endif + if (saCurOfrFunds == saCurOfrSpent) + { + // Offer became unfunded. + pspCur->vUnfundedBecame.push_back(uOfferIndex); // Mark offer for deletion on use of current path state. + } + + saPrvDlvAct += saCurOfrInAct; // Portion needed in previous. + saCurDlvAct += saCurOfrOutAct; // Portion of driver served. } } @@ -2436,13 +2558,10 @@ TER TransactionEngine::calcNodeOfferFwd( uDirectTip = 0; } - if (saCurDlvAct) - { - saCurDlvReq = saCurDlvAct; // Adjust request. - terResult = tesSUCCESS; - } - + return !!saCurDlvAct ? tesSUCCESS : terResult; +#else return terResult; +#endif } #if 0 @@ -2716,7 +2835,7 @@ void TransactionEngine::calcNodeRipple( // No fee. Log(lsINFO) << boost::str(boost::format("calcNodeRipple: No fees")); - STAmount saTransfer = bPrvUnlimited ? saCur : MIN(saPrv, saCur); + STAmount saTransfer = bPrvUnlimited ? saCur : std::min(saPrv, saCur); saPrvAct += saTransfer; saCurAct += saTransfer; @@ -2771,12 +2890,12 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS paymentNode& pnCur = pspCur->vpnNodes[uIndex]; paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - const bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem); - const bool bPrvRedeem = !!(pnPrv.uFlags & STPathElement::typeRedeem); - const bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue); - const bool bPrvIssue = !!(pnPrv.uFlags & STPathElement::typeIssue); - const bool bPrvAccount = !uIndex || !!(pnPrv.uFlags & STPathElement::typeAccount); - const bool bNxtAccount = uIndex == uLast || !!(pnNxt.uFlags & STPathElement::typeAccount); + const bool bRedeem = isSetBit(pnCur.uFlags, STPathElement::typeRedeem); + const bool bPrvRedeem = isSetBit(pnPrv.uFlags, STPathElement::typeRedeem); + const bool bIssue = isSetBit(pnCur.uFlags, STPathElement::typeIssue); + const bool bPrvIssue = isSetBit(pnPrv.uFlags, STPathElement::typeIssue); + const bool bPrvAccount = !uIndex || isSetBit(pnPrv.uFlags, STPathElement::typeAccount); + const bool bNxtAccount = uIndex == uLast || isSetBit(pnNxt.uFlags, STPathElement::typeAccount); const uint160& uCurAccountID = pnCur.uAccountID; const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; @@ -2850,8 +2969,8 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS // account --> ACCOUNT --> $ // Overall deliverable. const STAmount& saCurWantedReq = bPrvAccount - ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. - : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + ? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $ : saCurWantedReq=%s") @@ -2864,7 +2983,7 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS // Redeem at 1:1 Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Redeem at 1:1")); - saCurWantedAct = MIN(saPrvRedeemReq, saCurWantedReq); + saCurWantedAct = std::min(saPrvRedeemReq, saCurWantedReq); saPrvRedeemAct = saCurWantedAct; } @@ -3005,7 +3124,7 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS { // offer --> ACCOUNT --> $ const STAmount& saCurWantedReq = bPrvAccount - ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + ? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); @@ -3099,10 +3218,10 @@ TER TransactionEngine::calcNodeAccountFwd( paymentNode& pnCur = pspCur->vpnNodes[uIndex]; paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - const bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem); - const bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue); - const bool bPrvAccount = !!(pnPrv.uFlags & STPathElement::typeAccount); - const bool bNxtAccount = !!(pnNxt.uFlags & STPathElement::typeAccount); + const bool bRedeem = isSetBit(pnCur.uFlags, STPathElement::typeRedeem); + const bool bIssue = isSetBit(pnCur.uFlags, STPathElement::typeIssue); + const bool bPrvAccount = isSetBit(pnPrv.uFlags, STPathElement::typeAccount); + const bool bNxtAccount = isSetBit(pnNxt.uFlags, STPathElement::typeAccount); const uint160& uCurAccountID = pnCur.uAccountID; const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; @@ -3172,7 +3291,7 @@ TER TransactionEngine::calcNodeAccountFwd( // Redeem requested. saCurRedeemAct = saCurRedeemReq.isNegative() ? saCurRedeemReq - : MIN(saCurRedeemReq, saCurSendMaxReq); + : std::min(saCurRedeemReq, saCurSendMaxReq); } else { @@ -3185,7 +3304,7 @@ TER TransactionEngine::calcNodeAccountFwd( // Issue requested and not over budget. saCurIssueAct = saCurSendMaxReq.isNegative() ? saCurIssueReq - : MIN(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); + : std::min(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); } else { @@ -3433,15 +3552,15 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint const bool bFirst = vpnNodes.empty(); const paymentNode& pnPrv = bFirst ? paymentNode() : vpnNodes.back(); // true, iff node is a ripple account. false, iff node is an offer node. - const bool bAccount = !!(iType & STPathElement::typeAccount); + const bool bAccount = isSetBit(iType, STPathElement::typeAccount); // true, iff currency supplied. // Currency is specified for the output of the current node. - const bool bCurrency = !!(iType & STPathElement::typeCurrency); + const bool bCurrency = isSetBit(iType, STPathElement::typeCurrency); // Issuer is specified for the output of the current node. - const bool bIssuer = !!(iType & STPathElement::typeIssuer); + const bool bIssuer = isSetBit(iType, STPathElement::typeIssuer); // true, iff account is allowed to redeem it's IOUs to next node. - const bool bRedeem = !!(iType & STPathElement::typeRedeem); - const bool bIssue = !!(iType & STPathElement::typeIssue); + const bool bRedeem = isSetBit(iType, STPathElement::typeRedeem); + const bool bIssue = isSetBit(iType, STPathElement::typeIssue); TER terResult = tesSUCCESS; pnCur.uFlags = iType; @@ -3476,7 +3595,7 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint if (tesSUCCESS == terResult && !vpnNodes.empty()) { const paymentNode& pnBck = vpnNodes.back(); - bool bBckAccount = !!(pnBck.uFlags & STPathElement::typeAccount); + bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); if (bBckAccount) { @@ -3551,8 +3670,8 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint { // Verify that previous account is allowed to issue. const paymentNode& pnBck = vpnNodes.back(); - bool bBckAccount = !!(pnBck.uFlags & STPathElement::typeAccount); - bool bBckIssue = !!(pnBck.uFlags & STPathElement::typeIssue); + bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); + bool bBckIssue = isSetBit(pnBck.uFlags, STPathElement::typeIssue); if (bBckAccount && !bBckIssue) { @@ -3751,15 +3870,15 @@ Json::Value PathState::getJson() const TER TransactionEngine::calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) { const paymentNode& pnCur = pspCur->vpnNodes[uIndex]; - const bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount); + const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); TER terResult; Log(lsINFO) << boost::str(boost::format("calcNode> uIndex=%d") % uIndex); // Do current node reverse. terResult = bCurAccount - ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) - : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); + ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) + : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); // Do previous. if (tesSUCCESS == terResult && uIndex) @@ -3771,8 +3890,8 @@ TER TransactionEngine::calcNode(const unsigned int uIndex, const PathState::poin if (tesSUCCESS == terResult) { terResult = bCurAccount - ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) - : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); + ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) + : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); } Log(lsINFO) << boost::str(boost::format("calcNode< uIndex=%d terResult=%d") % uIndex % terResult); @@ -3816,9 +3935,9 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) { // Ripple if source or destination is non-native or if there are paths. const uint32 uTxFlags = txn.getFlags(); - const bool bCreate = !!(uTxFlags & tfCreateAccount); - const bool bNoRippleDirect = !!(uTxFlags & tfNoRippleDirect); - const bool bPartialPayment = !!(uTxFlags & tfPartialPayment); + const bool bCreate = isSetBit(uTxFlags, tfCreateAccount); + const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect); + const bool bPartialPayment = isSetBit(uTxFlags, tfPartialPayment); const bool bPaths = txn.getITFieldPresent(sfPaths); const bool bMax = txn.getITFieldPresent(sfSendMax); const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); @@ -4414,7 +4533,7 @@ TER TransactionEngine::doOfferCreate(const SerializedTransaction& txn) { Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); const uint32 txFlags = txn.getFlags(); - const bool bPassive = !!(txFlags & tfPassive); + const bool bPassive = isSetBit(txFlags, tfPassive); STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText(); diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 115e4e68a2..149c6289b7 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -19,14 +19,22 @@ enum TER // aka TransactionEngineResult // Note: Range is stable. Exact numbers are currently unstable. Use tokens. // -399 .. -300: L Local error (transaction fee inadequate, exceeds local limit) - // Not forwarded, no fee. Only valid during non-consensus processing + // Only valid during non-consensus processing. + // Implications: + // - Not forwarded + // - No fee check telLOCAL_ERROR = -399, telBAD_PATH_COUNT, telINSUF_FEE_P, // -299 .. -200: M Malformed (bad signature) - // Transaction corrupt, not forwarded, cannot charge fee, reject - // Never can succeed in any ledger + // Causes: + // - Transaction corrupt. + // Implications: + // - Not applied + // - Not forwarded + // - Reject + // - Can not succeed in any imagined ledger. temMALFORMED = -299, temBAD_AMOUNT, temBAD_AUTH_MASTER, @@ -48,8 +56,14 @@ enum TER // aka TransactionEngineResult temUNKNOWN, // -199 .. -100: F Failure (sequence number previously used) - // Transaction cannot succeed because of ledger state, unexpected ledger state, C++ exception, not forwarded, cannot be - // applied, Could succeed in an imaginary ledger. + // Causes: + // - Transaction cannot succeed because of ledger state. + // - Unexpected ledger state. + // - C++ exception. + // Implications: + // - Not applied + // - Not forwarded + // - Could succeed in an imaginared ledger. tefFAILURE = -199, tefALREADY, tefBAD_ADD_AUTH, @@ -64,7 +78,13 @@ enum TER // aka TransactionEngineResult tefPAST_SEQ, // -99 .. -1: R Retry (sequence too high, no funds for txn fee, originating account non-existent) - // Transaction cannot be applied, not forwarded, might succeed later, hold + // Causes: + // - Priror application of another, possibly non-existant, transaction could allow this transaction to succeed. + // Implications: + // - Not applied + // - Not forwarded + // - Might succeed later + // - Hold terRETRY = -99, terDIR_FULL, terFUNDS_SPENT, @@ -79,19 +99,29 @@ enum TER // aka TransactionEngineResult terUNFUNDED, // 0: S Success (success) - // Transaction succeeds, can be applied, can charge fee, forwarded - // applyTransaction: addTransaction and destroyCoins + // Causes: + // - Success. + // Implications: + // - Applied + // - Forwarded tesSUCCESS = 0, // 100 .. P Partial success (SR) (ripple transaction with no good paths, pay to non-existent account) - // Transaction can be applied, forwarded, but does not achieve optimal result. - // Only allowed as a return code of appliedTransaction when !tapRetry. - // applyTransaction: addTransaction and destroyCoins + // Causes: + // - Success, but does not achieve optimal result. + // Implications: + // - Applied + // - Forwarded + // Only allowed as a return code of appliedTransaction when !tapRetry. Otherwise, treated as terRETRY. tepPARTIAL = 100, tepPATH_DRY, tepPATH_PARTIAL, }; +#define isTemMalformed(x) ((x) >= temMALFORMED && (x) < tefFAILURE) +#define isTefFailure(x) ((x) >= tefFAILURE && (x) < terRETRY) +#define isTepPartial(x) ((x) >= tepPATH_PARTIAL) + bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman); enum TransactionEngineParams @@ -153,23 +183,23 @@ public: std::vector vpnNodes; // When processing, don't want to complicate directory walking with deletion. - std::vector vUnfundedBecame; // Offers that became unfunded. + std::vector vUnfundedBecame; // Offers that became unfunded or were completely consumed. // First time working foward a funding source was mentioned for accounts. Source may only be used there. - curIssuerNode umForward; // Map of currency, issuer to node index. + curIssuerNode umForward; // Map of currency, issuer to node index. // First time working in reverse a funding source was used. // Source may only be used there if not mentioned by an account. - curIssuerNode umReverse; // Map of currency, issuer to node index. + curIssuerNode umReverse; // Map of currency, issuer to node index. LedgerEntrySet lesEntries; int mIndex; - uint64 uQuality; // 0 = none. - STAmount saInReq; // Max amount to spend by sender - STAmount saInAct; // Amount spent by sender (calc output) - STAmount saOutReq; // Amount to send (calc input) - STAmount saOutAct; // Amount actually sent (calc output). + uint64 uQuality; // 0 = none. + STAmount saInReq; // Max amount to spend by sender + STAmount saInAct; // Amount spent by sender (calc output) + STAmount saOutReq; // Amount to send (calc input) + STAmount saOutAct; // Amount actually sent (calc output). PathState( const Ledger::pointer& lpLedger, diff --git a/src/utils.h b/src/utils.h index f11b82a1b7..91c5ff9b36 100644 --- a/src/utils.h +++ b/src/utils.h @@ -16,14 +16,6 @@ #define ADDRESS(p) strHex(uint64( ((char*) p) - ((char*) 0))) #define ADDRESS_SHARED(p) strHex(uint64( ((char*) (p).get()) - ((char*) 0))) -#ifndef MAX -#define MAX(x,y) ((x) < (y) ? (y) : (x)) -#endif - -#ifndef MIN -#define MIN(x,y) ((x) > (y) ? (y) : (x)) -#endif - #define isSetBit(x,y) (!!((x) & (y))) #ifdef WIN32