Merge branch 'master' of github.com:jedmccaleb/NewCoin

This commit is contained in:
JoelKatz
2012-08-31 14:47:55 -07:00
5 changed files with 318 additions and 175 deletions

View File

@@ -5,6 +5,7 @@
#include <boost/lexical_cast.hpp>
#include <fstream>
#include <iostream>
#include <algorithm>
#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<int>(strTemp));
PEER_SCAN_INTERVAL_MIN = std::max(60, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_PEER_START_MAX, strTemp))
PEER_START_MAX = MAX(1, boost::lexical_cast<int>(strTemp));
PEER_START_MAX = std::max(1, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_PEER_CONNECT_LOW_WATER, strTemp))
PEER_CONNECT_LOW_WATER = MAX(1, boost::lexical_cast<int>(strTemp));
PEER_CONNECT_LOW_WATER = std::max(1, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_NETWORK_QUORUM, strTemp))
NETWORK_QUORUM = MAX(0, boost::lexical_cast<int>(strTemp));
NETWORK_QUORUM = std::max(0, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_VALIDATION_QUORUM, strTemp))
VALIDATION_QUORUM = MAX(0, boost::lexical_cast<int>(strTemp));
VALIDATION_QUORUM = std::max(0, boost::lexical_cast<int>(strTemp));
if (sectionSingleB(secConfig, SECTION_FEE_ACCOUNT_CREATE, strTemp))
FEE_ACCOUNT_CREATE = boost::lexical_cast<int>(strTemp);

View File

@@ -6,6 +6,7 @@
#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <boost/algorithm/string.hpp>
#include <algorithm>
#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);

View File

@@ -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<uint160, STAmount> 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<uint160, STAmount>::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();

View File

@@ -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<paymentNode> vpnNodes;
// When processing, don't want to complicate directory walking with deletion.
std::vector<uint256> vUnfundedBecame; // Offers that became unfunded.
std::vector<uint256> 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,

View File

@@ -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