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

Conflicts:
	test/config.js
This commit is contained in:
jed
2012-11-16 09:08:37 -08:00
9 changed files with 282 additions and 84 deletions

View File

@@ -275,7 +275,10 @@ SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::ref ledger,
if (it != mEntries.end())
{
if (it->second.mAction == taaDELETE)
{
cLog(lsFATAL) << "Trying to thread to deleted node";
return SLE::pointer();
}
if (it->second.mAction == taaCACHED)
it->second.mAction = taaMODIFY;
if (it->second.mSeq != mSeq)
@@ -288,7 +291,10 @@ SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::ref ledger,
boost::unordered_map<uint256, SLE::pointer>::iterator me = newMods.find(node);
if (me != newMods.end())
{
assert(me->second);
return me->second;
}
SLE::pointer ret = ledger->getSLE(node);
if (ret)
@@ -306,6 +312,7 @@ bool LedgerEntrySet::threadTx(const RippleAddress& threadTo, Ledger::ref ledger,
SLE::pointer sle = getForMod(Ledger::getAccountRootIndex(threadTo.getAccountID()), ledger, newMods);
if (!sle)
{
cLog(lsFATAL) << "Threading to non-existent account: " << threadTo.humanAccountID();
assert(false);
return false;
}

View File

@@ -471,15 +471,13 @@ TER RippleCalc::calcNodeDeliverRev(
return terResult;
}
// Deliver maximum amount of funds from previous node.
// Goal: Make progress consuming the offer.
// For current offer, get input from deliver/limbo and output to next account or deliver for next offers.
TER RippleCalc::calcNodeDeliverFwd(
const unsigned int uNode, // 0 < uNode < uLast
PathState::ref pspCur,
const bool bMultiQuality,
const uint160& uInAccountID, // --> Input owner's account.
const STAmount& saInFunds, // --> Funds available for delivery and fees.
const STAmount& saInReq, // --> Limit to deliver.
const STAmount& saInReq, // --> Amount to deliver.
STAmount& saInAct, // <-- Amount delivered.
STAmount& saInFees) // <-- Fees charged.
{
@@ -490,7 +488,9 @@ TER RippleCalc::calcNodeDeliverFwd(
PaymentNode& pnNxt = pspCur->vpnNodes[uNode+1];
const uint160& uNxtAccountID = pnNxt.uAccountID;
const uint160& uCurCurrencyID = pnCur.uCurrencyID;
const uint160& uCurIssuerID = pnCur.uIssuerID;
const uint160& uPrvCurrencyID = pnPrv.uCurrencyID;
const uint160& uPrvIssuerID = pnPrv.uIssuerID;
const STAmount& saTransferRate = pnPrv.saTransferRate;
@@ -498,19 +498,20 @@ TER RippleCalc::calcNodeDeliverFwd(
uint256& uDirectTip = pnCur.uDirectTip;
uDirectTip = 0; // Restart book searching.
uDirectTip = 0; // Restart book searching.
saInAct.zero(saInFunds);
saInFees.zero(saInFunds);
saInAct.zero(saInReq);
saInFees.zero(saInReq);
saCurDeliverAct.zero(uCurCurrencyID, uCurIssuerID);
while (tesSUCCESS == terResult
&& saInAct != saInReq // Did not deliver limit.
&& saInAct + saInFees != saInFunds) // Did not deliver all funds.
&& saInAct + saInFees != saInReq) // Did not deliver all funds.
{
terResult = calcNodeAdvance(uNode, pspCur, bMultiQuality, false); // If needed, advance to next funded offer.
if (tesSUCCESS == terResult)
{
// Doesn't charge input. Input funds are in limbo.
bool& bEntryAdvance = pnCur.bEntryAdvance;
STAmount& saOfrRate = pnCur.saOfrRate;
uint256& uOfferIndex = pnCur.uOfferIndex;
@@ -521,9 +522,11 @@ TER RippleCalc::calcNodeDeliverFwd(
STAmount& saTakerPays = pnCur.saTakerPays;
STAmount& saTakerGets = pnCur.saTakerGets;
const STAmount saInFeeRate = uInAccountID == uPrvIssuerID || uOfrOwnerID == uPrvIssuerID // Issuer receiving or sending.
? saOne // No fee.
: saTransferRate; // Transfer rate of issuer.
const STAmount saInFeeRate = !!uPrvCurrencyID
? uInAccountID == uPrvIssuerID || uOfrOwnerID == uPrvIssuerID // Issuer receiving or sending.
? saOne // No fee.
: saTransferRate // Transfer rate of issuer.
: saOne;
//
// First calculate assuming no output fees.
@@ -532,11 +535,11 @@ TER RippleCalc::calcNodeDeliverFwd(
STAmount saOutFunded = std::max(saOfferFunds, saTakerGets); // Offer maximum out - There are no out fees.
STAmount saInFunded = STAmount::multiply(saOutFunded, saOfrRate, saInReq); // Offer maximum in - Limited by by payout.
STAmount saInTotal = STAmount::multiply(saInFunded, saTransferRate); // Offer maximum in with fees.
STAmount saInSum = std::min(saInTotal, saInFunds-saInAct-saInFees); // In limited by saInFunds.
STAmount saInSum = std::min(saInTotal, saInReq-saInAct-saInFees); // In limited by saInReq.
STAmount saInPassAct = STAmount::divide(saInSum, saInFeeRate); // In without fees.
STAmount saOutPassMax = STAmount::divide(saInPassAct, saOfrRate, saOutFunded); // Out.
STAmount saInPassFees(saInFunds.getCurrency(), saInFunds.getIssuer());
STAmount saInPassFees(saInReq.getCurrency(), saInReq.getIssuer());
STAmount saOutPassAct(saOfferFunds.getCurrency(), saOfferFunds.getIssuer());
cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: saOutFunded=%s saInFunded=%s saInTotal=%s saInSum=%s saInPassAct=%s saOutPassMax=%s")
@@ -551,22 +554,21 @@ TER RippleCalc::calcNodeDeliverFwd(
{
// ? --> OFFER --> account
// Input fees: vary based upon the consumed offer's owner.
// Output fees: none as the destination account is the issuer.
// XXX This doesn't claim input.
// XXX Assumes input is in limbo. XXX Check.
// Debit offer owner.
lesActive.accountSend(uOfrOwnerID, uCurIssuerID, saOutPassMax);
// Output fees: none as XRP or the destination account is the issuer.
saOutPassAct = saOutPassMax;
// Debit offer owner, send XRP or non-XPR to next account.
lesActive.accountSend(uOfrOwnerID, uNxtAccountID, saOutPassAct);
cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: ? --> OFFER --> account: saOutPassAct=%s")
% saOutPassAct);
}
else
{
// ? --> OFFER --> offer
// Offer to offer means current order book's output currency and issuer match next order book's input current and
// issuer.
STAmount saOutPassFees;
terResult = RippleCalc::calcNodeDeliverFwd(
@@ -575,16 +577,22 @@ TER RippleCalc::calcNodeDeliverFwd(
bMultiQuality,
uOfrOwnerID,
saOutPassMax,
saOutPassMax,
saOutPassAct, // <-- Amount delivered.
saOutPassFees); // <-- Fees charged.
if (tesSUCCESS != terResult)
break;
// Offer maximum in limited by next payout.
// Offer maximum in split into fees by next payout.
saInPassAct = STAmount::multiply(saOutPassAct, saOfrRate);
saInPassFees = STAmount::multiply(saInFunded, saInFeeRate)-saInPassAct;
// Do outbound debiting.
// Send to issuer/limbo total amount (no fees to issuer).
lesActive.accountSend(uOfrOwnerID, !!uCurCurrencyID ? uCurIssuerID : ACCOUNT_XRP, saOutPassAct);
cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: ? --> OFFER --> offer: saOutPassAct=%s")
% saOutPassAct);
}
cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: saTakerGets=%s saTakerPays=%s saInPassAct=%s saOutPassAct=%s")
@@ -596,13 +604,12 @@ TER RippleCalc::calcNodeDeliverFwd(
// Funds were spent.
bFundsDirty = true;
// Credit issuer transfer fees.
lesActive.accountSend(uInAccountID, uOfrOwnerID, saInPassFees);
// Credit offer owner from offer.
lesActive.accountSend(uInAccountID, uOfrOwnerID, saInPassAct);
// Do inbound crediting.
// Credit offer owner from in issuer/limbo (don't take transfer fees).
lesActive.accountSend(!!uPrvCurrencyID ? uInAccountID : ACCOUNT_XRP, uOfrOwnerID, saInPassAct);
// Adjust offer
// Fees are considered paid from a seperate budget and are not named in the offer.
sleOffer->setFieldAmount(sfTakerGets, saTakerGets - saOutPassAct);
sleOffer->setFieldAmount(sfTakerPays, saTakerPays - saInPassAct);
@@ -661,7 +668,7 @@ TER RippleCalc::calcNodeOfferRev(
}
// Called to drive the from the first offer node in a chain.
// - Offer input is limbo.
// - Offer input is in issuer/limbo.
// - Current offers consumed.
// - Current offer owners debited.
// - Transfer fees credited to issuer.
@@ -688,7 +695,6 @@ TER RippleCalc::calcNodeOfferFwd(
bMultiQuality,
pnPrv.uAccountID,
pnPrv.saFwdDeliver,
pnPrv.saFwdDeliver,
saInAct,
saInFees);
@@ -843,6 +849,7 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState::ref pspC
const uint160& uCurrencyID = pnCur.uCurrencyID;
// XXX Don't look up quality for XRP
const uint32 uQualityIn = uNode ? lesActive.rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE;
const uint32 uQualityOut = uNode != uLast ? lesActive.rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE;
@@ -908,15 +915,16 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState::ref pspC
|| !saNxtOwed.isNegative() // saNxtOwed >= 0: Sender not holding next IOUs, saNxtOwed < 0: Sender holding next IOUs.
|| -saNxtOwed == saCurRedeemReq); // If issue req, then redeem req must consume all owed.
if (bPrvAccount && bNxtAccount)
if (!uNode)
{
if (!uNode)
{
// ^ --> ACCOUNT --> account|offer
// Nothing to do, there is no previous to adjust.
nothing();
}
else if (uNode == uLast)
// ^ --> ACCOUNT --> account|offer
// Nothing to do, there is no previous to adjust.
nothing();
}
else if (bPrvAccount && bNxtAccount)
{
if (uNode == uLast)
{
// account --> ACCOUNT --> $
// Overall deliverable.
@@ -1157,7 +1165,7 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState::ref pspC
}
// 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.
// Now, for the current account node, take the actual amount from previous and adjust forward balances.
//
// Perform balance adjustments between previous and current node.
// - The previous node: specifies what to push through to current.
@@ -1165,6 +1173,8 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState::ref pspC
// Then, compute current node's output for next node.
// - Current node: specify what to push through to next.
// - Output to next node is computed as input minus quality or transfer fee.
// - If next node is an offer and output is non-XRP then we are the issuer and do not need to push funds.
// - If next node is an offer and output is XRP then we need to deliver funds to limbo.
TER RippleCalc::calcNodeAccountFwd(
const unsigned int uNode, // 0 <= uNode <= uLast
PathState::ref pspCur,
@@ -1186,6 +1196,8 @@ TER RippleCalc::calcNodeAccountFwd(
const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID;
const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue.
const uint160& uCurIssuerID = pnCur.uIssuerID;
const uint160& uCurrencyID = pnCur.uCurrencyID;
uint32 uQualityIn = uNode ? lesActive.rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE;
@@ -1216,6 +1228,9 @@ TER RippleCalc::calcNodeAccountFwd(
const STAmount& saCurDeliverReq = pnCur.saRevDeliver;
STAmount& saCurDeliverAct = pnCur.saFwdDeliver;
// For !uNode
STAmount& saCurSendMaxPass = pspCur->saInPass; // Report how much pass sends.
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uNode=%d/%d saPrvRedeemReq=%s saPrvIssueReq=%s saPrvDeliverReq=%s saCurRedeemReq=%s saCurIssueReq=%s saCurDeliverReq=%s")
% uNode
% uLast
@@ -1242,7 +1257,6 @@ TER RippleCalc::calcNodeAccountFwd(
const STAmount saCurSendMaxReq = pspCur->saInReq.isNegative()
? pspCur->saInReq // Negative for no limit, doing a calculation.
: pspCur->saInReq-pspCur->saInAct; // request - done.
STAmount& saCurSendMaxPass = pspCur->saInPass; // Report how much pass sends.
saCurRedeemAct = saCurRedeemReq
// Redeem requested.
@@ -1343,31 +1357,71 @@ TER RippleCalc::calcNodeAccountFwd(
}
else if (bPrvAccount && !bNxtAccount)
{
// account --> ACCOUNT --> offer
cLog(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> offer"));
saCurDeliverAct.zero(saCurDeliverReq);
// redeem -> issue.
// wants to redeem and current would and can issue.
// If redeeming cur to next is done, this implies can issue.
if (saPrvRedeemReq) // Previous wants to redeem.
if (uNode)
{
// Rate : 1.0 : transfer_rate
calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct, uRateMax);
}
// Non-XRP, current node is the issuer.
cLog(lsDEBUG) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> offer"));
// issue -> issue
if (saPrvRedeemReq == saPrvRedeemAct // Previous done redeeming: Previous has no IOUs.
&& saPrvIssueReq) // Previous wants to issue. To next must be ok.
saCurDeliverAct.zero(saCurDeliverReq);
// redeem -> issue/deliver.
// Previous wants to redeem.
// Current is issuing to an offer so leave funds in account as "limbo".
if (saPrvRedeemReq) // Previous wants to redeem.
{
// Rate : 1.0 : transfer_rate
// XXX Is having the transfer rate here correct?
calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct, uRateMax);
}
// issue -> issue/deliver
if (saPrvRedeemReq == saPrvRedeemAct // Previous done redeeming: Previous has no IOUs.
&& saPrvIssueReq) // Previous wants to issue. To next must be ok.
{
// Rate: quality in : 1.0
calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurDeliverReq, saPrvIssueAct, saCurDeliverAct, uRateMax);
}
// Adjust prv --> cur balance : take all inbound
lesActive.rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false);
}
else
{
// Rate: quality in : 1.0
calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurDeliverReq, saPrvIssueAct, saCurDeliverAct, uRateMax);
}
// Delivering amount requested from downstream.
saCurDeliverAct = saCurDeliverReq;
// Adjust prv --> cur balance : take all inbound
// XXX Currency must be in amount.
lesActive.rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false);
// If limited, then limit by send max and available.
if (!pspCur->saInReq.isNegative())
{
saCurDeliverAct = pspCur->saInReq-pspCur->saInAct;
// Limit XRP by available. No limit for non-XRP as issuer.
if (!uCurAccountID)
saCurDeliverAct = std::min(saCurDeliverAct, lesActive.accountHolds(uCurAccountID, CURRENCY_XRP, ACCOUNT_XRP));
}
saCurSendMaxPass = saCurDeliverAct; // Record amount sent for pass.
if (!!uCurrencyID)
{
// Non-XRP, current node is the issuer.
// We could be delivering to multiple accounts, so we don't know which ripple balance will be adjusted. Assume
// just issuing.
cLog(lsDEBUG) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT -- !XRP --> offer"));
// As the issuer, would only issue.
// Don't need to actually deliver. As from delivering leave in the issuer as limbo.
nothing();
}
else
{
cLog(lsDEBUG) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT -- XRP --> offer"));
// Deliver XRP to limbo.
lesActive.accountSend(uCurAccountID, ACCOUNT_XRP, saCurDeliverAct);
}
}
}
else if (!bPrvAccount && bNxtAccount)
{

View File

@@ -163,7 +163,6 @@ public:
PathState::ref pspCur,
const bool bMultiQuality,
const uint160& uInAccountID,
const STAmount& saInFunds,
const STAmount& saInReq,
STAmount& saInAct,
STAmount& saInFees);

View File

@@ -189,6 +189,36 @@ int ValidationCollection::getLoadRatio(bool overLoaded)
return (goodNodes * 100) / (goodNodes + badNodes);
}
std::list<SerializedValidation::pointer> ValidationCollection::getCurrentTrustedValidations()
{
uint32 cutoff = theApp->getOPs().getNetworkTimeNC() - LEDGER_VAL_INTERVAL;
std::list<SerializedValidation::pointer> ret;
boost::mutex::scoped_lock sl(mValidationLock);
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin();
while (it != mCurrentValidations.end())
{
if (!it->second) // contains no record
it = mCurrentValidations.erase(it);
else if (it->second->getSignTime() < cutoff)
{ // contains a stale record
mStaleValidations.push_back(it->second);
it->second.reset();
condWrite();
it = mCurrentValidations.erase(it);
}
else
{ // contains a live record
if (it->second->isTrusted())
ret.push_back(it->second);
++it;
}
}
return ret;
}
boost::unordered_map<uint256, currentValidationCount>
ValidationCollection::getCurrentValidations(uint256 currentLedger)
{

View File

@@ -46,6 +46,7 @@ public:
int getLoadRatio(bool overLoaded);
boost::unordered_map<uint256, currentValidationCount> getCurrentValidations(uint256 currentLedger);
std::list<SerializedValidation::pointer> getCurrentTrustedValidations();
void flush();
void sweep() { mValidations.sweep(); }