mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 11:05:54 +00:00
Split up TransactionEngine, part 1.
This commit is contained in:
@@ -756,4 +756,366 @@ Log(lsINFO) << boost::str(boost::format("dirNext: uDirEntry=%d uEntryIndex=%s")
|
||||
return true;
|
||||
}
|
||||
|
||||
TER LedgerEntrySet::offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID)
|
||||
{
|
||||
uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode);
|
||||
TER terResult = dirDelete(false, uOwnerNode, Ledger::getOwnerDirIndex(uOwnerID), uOfferIndex, false);
|
||||
|
||||
if (tesSUCCESS == terResult)
|
||||
{
|
||||
uint256 uDirectory = sleOffer->getIFieldH256(sfBookDirectory);
|
||||
uint64 uBookNode = sleOffer->getIFieldU64(sfBookNode);
|
||||
|
||||
terResult = dirDelete(false, uBookNode, uDirectory, uOfferIndex, true);
|
||||
}
|
||||
|
||||
entryDelete(sleOffer);
|
||||
|
||||
return terResult;
|
||||
}
|
||||
|
||||
TER LedgerEntrySet::offerDelete(const uint256& uOfferIndex)
|
||||
{
|
||||
SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex);
|
||||
const uint160 uOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID();
|
||||
|
||||
return offerDelete(sleOffer, uOfferIndex, uOwnerID);
|
||||
}
|
||||
|
||||
// Returns amount owed by uToAccountID to uFromAccountID.
|
||||
// <-- $owed/uCurrencyID/uToAccountID: positive: uFromAccountID holds IOUs., negative: uFromAccountID owes IOUs.
|
||||
STAmount LedgerEntrySet::rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)
|
||||
{
|
||||
STAmount saBalance;
|
||||
SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID));
|
||||
|
||||
if (sleRippleState)
|
||||
{
|
||||
saBalance = sleRippleState->getIValueFieldAmount(sfBalance);
|
||||
if (uToAccountID < uFromAccountID)
|
||||
saBalance.negate();
|
||||
saBalance.setIssuer(uToAccountID);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log(lsINFO) << "rippleOwed: No credit line between "
|
||||
<< NewcoinAddress::createHumanAccountID(uFromAccountID)
|
||||
<< " and "
|
||||
<< NewcoinAddress::createHumanAccountID(uToAccountID)
|
||||
<< " for "
|
||||
<< STAmount::createHumanCurrency(uCurrencyID)
|
||||
<< "." ;
|
||||
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return saBalance;
|
||||
}
|
||||
|
||||
// Maximum amount of IOUs uToAccountID will hold from uFromAccountID.
|
||||
// <-- $amount/uCurrencyID/uToAccountID.
|
||||
STAmount LedgerEntrySet::rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)
|
||||
{
|
||||
STAmount saLimit;
|
||||
SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID));
|
||||
|
||||
assert(sleRippleState);
|
||||
if (sleRippleState)
|
||||
{
|
||||
saLimit = sleRippleState->getIValueFieldAmount(uToAccountID < uFromAccountID ? sfLowLimit : sfHighLimit);
|
||||
saLimit.setIssuer(uToAccountID);
|
||||
}
|
||||
|
||||
return saLimit;
|
||||
|
||||
}
|
||||
|
||||
uint32 LedgerEntrySet::rippleTransferRate(const uint160& uIssuerID)
|
||||
{
|
||||
SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uIssuerID));
|
||||
|
||||
uint32 uQuality = sleAccount && sleAccount->getIFieldPresent(sfTransferRate)
|
||||
? sleAccount->getIFieldU32(sfTransferRate)
|
||||
: QUALITY_ONE;
|
||||
|
||||
Log(lsINFO) << boost::str(boost::format("rippleTransferRate: uIssuerID=%s account_exists=%d transfer_rate=%f")
|
||||
% NewcoinAddress::createHumanAccountID(uIssuerID)
|
||||
% !!sleAccount
|
||||
% (uQuality/1000000000.0));
|
||||
|
||||
assert(sleAccount);
|
||||
|
||||
return uQuality;
|
||||
}
|
||||
|
||||
// XXX Might not need this, might store in nodes on calc reverse.
|
||||
uint32 LedgerEntrySet::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, const SOE_Field sfLow, const SOE_Field sfHigh)
|
||||
{
|
||||
uint32 uQuality = QUALITY_ONE;
|
||||
SLE::pointer sleRippleState;
|
||||
|
||||
if (uToAccountID == uFromAccountID)
|
||||
{
|
||||
nothing();
|
||||
}
|
||||
else
|
||||
{
|
||||
sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID));
|
||||
|
||||
if (sleRippleState)
|
||||
{
|
||||
SOE_Field sfField = uToAccountID < uFromAccountID ? sfLow: sfHigh;
|
||||
|
||||
uQuality = sleRippleState->getIFieldPresent(sfField)
|
||||
? sleRippleState->getIFieldU32(sfField)
|
||||
: QUALITY_ONE;
|
||||
|
||||
if (!uQuality)
|
||||
uQuality = 1; // Avoid divide by zero.
|
||||
}
|
||||
}
|
||||
|
||||
Log(lsINFO) << boost::str(boost::format("rippleQuality: %s uToAccountID=%s uFromAccountID=%s uCurrencyID=%s bLine=%d uQuality=%f")
|
||||
% (sfLow == sfLowQualityIn ? "in" : "out")
|
||||
% NewcoinAddress::createHumanAccountID(uToAccountID)
|
||||
% NewcoinAddress::createHumanAccountID(uFromAccountID)
|
||||
% STAmount::createHumanCurrency(uCurrencyID)
|
||||
% !!sleRippleState
|
||||
% (uQuality/1000000000.0));
|
||||
|
||||
assert(uToAccountID == uFromAccountID || !!sleRippleState);
|
||||
|
||||
return uQuality;
|
||||
}
|
||||
|
||||
// Return how much of uIssuerID's uCurrencyID IOUs that uAccountID holds. May be negative.
|
||||
// <-- IOU's uAccountID has of uIssuerID
|
||||
STAmount LedgerEntrySet::rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID)
|
||||
{
|
||||
STAmount saBalance;
|
||||
SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uAccountID, uIssuerID, uCurrencyID));
|
||||
|
||||
if (sleRippleState)
|
||||
{
|
||||
saBalance = sleRippleState->getIValueFieldAmount(sfBalance);
|
||||
|
||||
if (uAccountID > uIssuerID)
|
||||
saBalance.negate(); // Put balance in uAccountID terms.
|
||||
}
|
||||
|
||||
return saBalance;
|
||||
}
|
||||
|
||||
// <-- saAmount: amount of uCurrencyID held by uAccountID. May be negative.
|
||||
STAmount LedgerEntrySet::accountHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID)
|
||||
{
|
||||
STAmount saAmount;
|
||||
|
||||
if (!uCurrencyID)
|
||||
{
|
||||
SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uAccountID));
|
||||
|
||||
saAmount = sleAccount->getIValueFieldAmount(sfBalance);
|
||||
|
||||
Log(lsINFO) << "accountHolds: stamps: " << saAmount.getText();
|
||||
}
|
||||
else
|
||||
{
|
||||
saAmount = rippleHolds(uAccountID, uCurrencyID, uIssuerID);
|
||||
|
||||
Log(lsINFO) << "accountHolds: "
|
||||
<< saAmount.getFullText()
|
||||
<< " : "
|
||||
<< STAmount::createHumanCurrency(uCurrencyID)
|
||||
<< "/"
|
||||
<< NewcoinAddress::createHumanAccountID(uIssuerID);
|
||||
}
|
||||
|
||||
return saAmount;
|
||||
}
|
||||
|
||||
// Returns the funds available for uAccountID for a currency/issuer.
|
||||
// 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, funds are unlimited, use result is saDefault.
|
||||
STAmount LedgerEntrySet::accountFunds(const uint160& uAccountID, const STAmount& saDefault)
|
||||
{
|
||||
STAmount saFunds;
|
||||
|
||||
Log(lsINFO) << "accountFunds: uAccountID="
|
||||
<< NewcoinAddress::createHumanAccountID(uAccountID);
|
||||
Log(lsINFO) << "accountFunds: saDefault.isNative()=" << saDefault.isNative();
|
||||
Log(lsINFO) << "accountFunds: saDefault.getIssuer()="
|
||||
<< NewcoinAddress::createHumanAccountID(saDefault.getIssuer());
|
||||
|
||||
if (!saDefault.isNative() && saDefault.getIssuer() == uAccountID)
|
||||
{
|
||||
saFunds = saDefault;
|
||||
|
||||
Log(lsINFO) << "accountFunds: offer funds: ripple self-funded: " << saFunds.getText();
|
||||
}
|
||||
else
|
||||
{
|
||||
saFunds = accountHolds(uAccountID, saDefault.getCurrency(), saDefault.getIssuer());
|
||||
|
||||
Log(lsINFO) << "accountFunds: offer funds: uAccountID ="
|
||||
<< NewcoinAddress::createHumanAccountID(uAccountID)
|
||||
<< " : "
|
||||
<< saFunds.getText()
|
||||
<< "/"
|
||||
<< saDefault.getHumanCurrency()
|
||||
<< "/"
|
||||
<< NewcoinAddress::createHumanAccountID(saDefault.getIssuer());
|
||||
}
|
||||
|
||||
return saFunds;
|
||||
}
|
||||
|
||||
// Calculate transit fee.
|
||||
STAmount LedgerEntrySet::rippleTransferFee(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount)
|
||||
{
|
||||
STAmount saTransitFee;
|
||||
|
||||
if (uSenderID != uIssuerID && uReceiverID != uIssuerID)
|
||||
{
|
||||
uint32 uTransitRate = rippleTransferRate(uIssuerID);
|
||||
|
||||
if (QUALITY_ONE != uTransitRate)
|
||||
{
|
||||
STAmount saTransitRate(CURRENCY_ONE, uTransitRate, -9);
|
||||
|
||||
saTransitFee = STAmount::multiply(saAmount, saTransitRate, saAmount.getCurrency(), saAmount.getIssuer());
|
||||
}
|
||||
}
|
||||
|
||||
return saTransitFee;
|
||||
}
|
||||
|
||||
// Direct send w/o fees: redeeming IOUs and/or sending own IOUs.
|
||||
void LedgerEntrySet::rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount, bool bCheckIssuer)
|
||||
{
|
||||
uint160 uIssuerID = saAmount.getIssuer();
|
||||
|
||||
assert(!bCheckIssuer || uSenderID == uIssuerID || uReceiverID == uIssuerID);
|
||||
|
||||
bool bFlipped = uSenderID > uReceiverID;
|
||||
uint256 uIndex = Ledger::getRippleStateIndex(uSenderID, uReceiverID, saAmount.getCurrency());
|
||||
SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, uIndex);
|
||||
|
||||
if (!sleRippleState)
|
||||
{
|
||||
Log(lsINFO) << "rippleCredit: Creating ripple line: " << uIndex.ToString();
|
||||
|
||||
STAmount saBalance = saAmount;
|
||||
|
||||
sleRippleState = entryCreate(ltRIPPLE_STATE, uIndex);
|
||||
|
||||
if (!bFlipped)
|
||||
saBalance.negate();
|
||||
|
||||
sleRippleState->setIFieldAmount(sfBalance, saBalance);
|
||||
sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, uSenderID);
|
||||
sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uReceiverID);
|
||||
}
|
||||
else
|
||||
{
|
||||
STAmount saBalance = sleRippleState->getIValueFieldAmount(sfBalance);
|
||||
|
||||
if (!bFlipped)
|
||||
saBalance.negate(); // Put balance in low terms.
|
||||
|
||||
saBalance += saAmount;
|
||||
|
||||
if (!bFlipped)
|
||||
saBalance.negate();
|
||||
|
||||
sleRippleState->setIFieldAmount(sfBalance, saBalance);
|
||||
|
||||
entryModify(sleRippleState);
|
||||
}
|
||||
}
|
||||
|
||||
// Send regardless of limits.
|
||||
// --> saAmount: Amount/currency/issuer for receiver to get.
|
||||
// <-- saActual: Amount actually sent. Sender pay's fees.
|
||||
STAmount LedgerEntrySet::rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount)
|
||||
{
|
||||
STAmount saActual;
|
||||
const uint160 uIssuerID = saAmount.getIssuer();
|
||||
|
||||
assert(!!uSenderID && !!uReceiverID);
|
||||
|
||||
if (uSenderID == uIssuerID || uReceiverID == uIssuerID)
|
||||
{
|
||||
// Direct send: redeeming IOUs and/or sending own IOUs.
|
||||
rippleCredit(uSenderID, uReceiverID, saAmount);
|
||||
|
||||
saActual = saAmount;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sending 3rd party IOUs: transit.
|
||||
|
||||
STAmount saTransitFee = rippleTransferFee(uSenderID, uReceiverID, uIssuerID, saAmount);
|
||||
|
||||
saActual = !saTransitFee ? saAmount : saAmount+saTransitFee;
|
||||
|
||||
saActual.setIssuer(uIssuerID); // XXX Make sure this done in + above.
|
||||
|
||||
rippleCredit(uIssuerID, uReceiverID, saAmount);
|
||||
rippleCredit(uSenderID, uIssuerID, saActual);
|
||||
}
|
||||
|
||||
return saActual;
|
||||
}
|
||||
|
||||
void LedgerEntrySet::accountSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount)
|
||||
{
|
||||
assert(!saAmount.isNegative());
|
||||
|
||||
if (!saAmount)
|
||||
{
|
||||
nothing();
|
||||
}
|
||||
else if (saAmount.isNative())
|
||||
{
|
||||
SLE::pointer sleSender = !!uSenderID
|
||||
? entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uSenderID))
|
||||
: SLE::pointer();
|
||||
SLE::pointer sleReceiver = !!uReceiverID
|
||||
? entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uReceiverID))
|
||||
: SLE::pointer();
|
||||
|
||||
Log(lsINFO) << boost::str(boost::format("accountSend> %s (%s) -> %s (%s) : %s")
|
||||
% NewcoinAddress::createHumanAccountID(uSenderID)
|
||||
% (sleSender ? (sleSender->getIValueFieldAmount(sfBalance)).getFullText() : "-")
|
||||
% NewcoinAddress::createHumanAccountID(uReceiverID)
|
||||
% (sleReceiver ? (sleReceiver->getIValueFieldAmount(sfBalance)).getFullText() : "-")
|
||||
% saAmount.getFullText());
|
||||
|
||||
if (sleSender)
|
||||
{
|
||||
sleSender->setIFieldAmount(sfBalance, sleSender->getIValueFieldAmount(sfBalance) - saAmount);
|
||||
entryModify(sleSender);
|
||||
}
|
||||
|
||||
if (sleReceiver)
|
||||
{
|
||||
sleReceiver->setIFieldAmount(sfBalance, sleReceiver->getIValueFieldAmount(sfBalance) + saAmount);
|
||||
entryModify(sleReceiver);
|
||||
}
|
||||
|
||||
Log(lsINFO) << boost::str(boost::format("accountSend< %s (%s) -> %s (%s) : %s")
|
||||
% NewcoinAddress::createHumanAccountID(uSenderID)
|
||||
% (sleSender ? (sleSender->getIValueFieldAmount(sfBalance)).getFullText() : "-")
|
||||
% NewcoinAddress::createHumanAccountID(uReceiverID)
|
||||
% (sleReceiver ? (sleReceiver->getIValueFieldAmount(sfBalance)).getFullText() : "-")
|
||||
% saAmount.getFullText());
|
||||
}
|
||||
else
|
||||
{
|
||||
rippleSend(uSenderID, uReceiverID, saAmount);
|
||||
}
|
||||
}
|
||||
// vim:ts=4
|
||||
|
||||
@@ -17,7 +17,6 @@ enum LedgerEntryAction
|
||||
taaCREATE, // Newly created.
|
||||
};
|
||||
|
||||
|
||||
class LedgerEntrySetEntry
|
||||
{
|
||||
public:
|
||||
@@ -68,6 +67,9 @@ public:
|
||||
void init(Ledger::ref ledger, const uint256& transactionID, uint32 ledgerID);
|
||||
void clear();
|
||||
|
||||
Ledger::pointer& getLedger() { return mLedger; }
|
||||
const Ledger::pointer& getLedgerRef() const { return mLedger; }
|
||||
|
||||
// basic entry functions
|
||||
SLE::pointer getEntry(const uint256& index, LedgerEntryAction&);
|
||||
LedgerEntryAction hasEntry(const uint256& index) const;
|
||||
@@ -80,7 +82,7 @@ public:
|
||||
SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex);
|
||||
SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex);
|
||||
|
||||
// Utility entry functions.
|
||||
// Directory functions.
|
||||
TER dirAdd(
|
||||
uint64& uNodeDir, // Node of entry.
|
||||
const uint256& uRootIndex,
|
||||
@@ -96,6 +98,26 @@ public:
|
||||
bool dirFirst(const uint256& uRootIndex, SLE::pointer& sleNode, unsigned int& uDirEntry, uint256& uEntryIndex);
|
||||
bool dirNext(const uint256& uRootIndex, SLE::pointer& sleNode, unsigned int& uDirEntry, uint256& uEntryIndex);
|
||||
|
||||
// Offer functions.
|
||||
TER offerDelete(const uint256& uOfferIndex);
|
||||
TER offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID);
|
||||
|
||||
// Balance functions.
|
||||
uint32 rippleTransferRate(const uint160& uIssuerID);
|
||||
STAmount rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
|
||||
STAmount rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
|
||||
uint32 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, const SOE_Field sfLow=sfLowQualityIn, const SOE_Field sfHigh=sfHighQualityIn);
|
||||
uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)
|
||||
{ return rippleQualityIn(uToAccountID, uFromAccountID, uCurrencyID, sfLowQualityOut, sfHighQualityOut); }
|
||||
|
||||
STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
|
||||
STAmount rippleTransferFee(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount);
|
||||
void rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount, bool bCheckIssuer=true);
|
||||
STAmount rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount);
|
||||
|
||||
STAmount accountHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
|
||||
void accountSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount);
|
||||
STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault);
|
||||
|
||||
Json::Value getJson(int) const;
|
||||
void calcRawMeta(Serializer&, Ledger::ref originalLedger);
|
||||
|
||||
2400
src/RippleCalc.cpp
Normal file
2400
src/RippleCalc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
190
src/RippleCalc.h
Normal file
190
src/RippleCalc.h
Normal file
@@ -0,0 +1,190 @@
|
||||
#ifndef __RIPPLE_CALC__
|
||||
#define __RIPPLE_CALC__
|
||||
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#include "LedgerEntrySet.h"
|
||||
|
||||
class PaymentNode {
|
||||
protected:
|
||||
friend class RippleCalc;
|
||||
friend class PathState;
|
||||
|
||||
uint16 uFlags; // --> From path.
|
||||
|
||||
uint160 uAccountID; // --> Accounts: Recieving/sending account.
|
||||
uint160 uCurrencyID; // --> Accounts: Receive and send, Offers: send.
|
||||
// --- For offer's next has currency out.
|
||||
uint160 uIssuerID; // --> Currency's issuer
|
||||
|
||||
STAmount saTransferRate; // Transfer rate for uIssuerID.
|
||||
|
||||
// Computed by Reverse.
|
||||
STAmount saRevRedeem; // <-- Amount to redeem to next.
|
||||
STAmount saRevIssue; // <-- Amount to issue to next limited by credit and outstanding IOUs.
|
||||
// Issue isn't used by offers.
|
||||
STAmount saRevDeliver; // <-- Amount to deliver to next regardless of fee.
|
||||
|
||||
// Computed by forward.
|
||||
STAmount saFwdRedeem; // <-- Amount node will redeem to next.
|
||||
STAmount saFwdIssue; // <-- Amount node will issue to next.
|
||||
// Issue isn't used by offers.
|
||||
STAmount saFwdDeliver; // <-- Amount to deliver to next regardless of fee.
|
||||
|
||||
// For offers:
|
||||
|
||||
STAmount saRateMax; // XXX Should rate be sticky for forward too?
|
||||
|
||||
// Directory
|
||||
uint256 uDirectTip; // Current directory.
|
||||
uint256 uDirectEnd; // Next order book.
|
||||
bool bDirectAdvance; // Need to advance directory.
|
||||
SLE::pointer sleDirectDir;
|
||||
STAmount saOfrRate; // For correct ratio.
|
||||
|
||||
// Node
|
||||
bool bEntryAdvance; // Need to advance entry.
|
||||
unsigned int uEntry;
|
||||
uint256 uOfferIndex;
|
||||
SLE::pointer sleOffer;
|
||||
uint160 uOfrOwnerID;
|
||||
bool bFundsDirty; // Need to refresh saOfferFunds, saTakerPays, & saTakerGets.
|
||||
STAmount saOfferFunds;
|
||||
STAmount saTakerPays;
|
||||
STAmount saTakerGets;
|
||||
};
|
||||
|
||||
// account id, currency id, issuer id :: node
|
||||
typedef boost::tuple<uint160, uint160, uint160> aciSource;
|
||||
typedef boost::unordered_map<aciSource, unsigned int> curIssuerNode; // Map of currency, issuer to node index.
|
||||
typedef boost::unordered_map<aciSource, unsigned int>::const_iterator curIssuerNodeConstIterator;
|
||||
|
||||
extern std::size_t hash_value(const aciSource& asValue);
|
||||
|
||||
// Holds a path state under incremental application.
|
||||
class PathState
|
||||
{
|
||||
protected:
|
||||
const Ledger::pointer& mLedger;
|
||||
|
||||
TER pushNode(const int iType, const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
|
||||
TER pushImply(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
|
||||
|
||||
public:
|
||||
typedef boost::shared_ptr<PathState> pointer;
|
||||
|
||||
TER terStatus;
|
||||
std::vector<PaymentNode> vpnNodes;
|
||||
|
||||
// When processing, don't want to complicate directory walking with deletion.
|
||||
std::vector<uint256> vUnfundedBecame; // Offers that became unfunded or were completely consumed.
|
||||
|
||||
// First time scanning foward, as part of path contruction, a funding source was mentioned for accounts. Source may only be
|
||||
// used there.
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
PathState(
|
||||
const int iIndex,
|
||||
const LedgerEntrySet& lesSource,
|
||||
const STPath& spSourcePath,
|
||||
const uint160& uReceiverID,
|
||||
const uint160& uSenderID,
|
||||
const STAmount& saSend,
|
||||
const STAmount& saSendMax
|
||||
);
|
||||
|
||||
Json::Value getJson() const;
|
||||
|
||||
static PathState::pointer createPathState(
|
||||
const int iIndex,
|
||||
const LedgerEntrySet& lesSource,
|
||||
const STPath& spSourcePath,
|
||||
const uint160& uReceiverID,
|
||||
const uint160& uSenderID,
|
||||
const STAmount& saSend,
|
||||
const STAmount& saSendMax
|
||||
)
|
||||
{
|
||||
return boost::make_shared<PathState>(iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax);
|
||||
}
|
||||
|
||||
static bool lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs);
|
||||
};
|
||||
|
||||
class RippleCalc
|
||||
{
|
||||
protected:
|
||||
LedgerEntrySet& lesActive;
|
||||
|
||||
public:
|
||||
// First time working in reverse a funding source was mentioned. Source may only be used there.
|
||||
curIssuerNode mumSource; // Map of currency, issuer to node index.
|
||||
|
||||
// If the transaction fails to meet some constraint, still need to delete unfunded offers.
|
||||
boost::unordered_set<uint256> musUnfundedFound; // Offers that were found unfunded.
|
||||
|
||||
PathState::pointer pathCreate(const STPath& spPath);
|
||||
void pathNext(const PathState::pointer& pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent);
|
||||
TER calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeOfferRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeOfferFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAccountFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAdvance(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality, const bool bReverse);
|
||||
TER calcNodeDeliverRev(
|
||||
const unsigned int uIndex,
|
||||
const PathState::pointer& pspCur,
|
||||
const bool bMultiQuality,
|
||||
const uint160& uOutAccountID,
|
||||
const STAmount& saOutReq,
|
||||
STAmount& saOutAct);
|
||||
|
||||
TER calcNodeDeliverFwd(
|
||||
const unsigned int uIndex,
|
||||
const PathState::pointer& pspCur,
|
||||
const bool bMultiQuality,
|
||||
const uint160& uInAccountID,
|
||||
const STAmount& saInFunds,
|
||||
const STAmount& saInReq,
|
||||
STAmount& saInAct,
|
||||
STAmount& saInFees);
|
||||
|
||||
void calcNodeRipple(const uint32 uQualityIn, const uint32 uQualityOut,
|
||||
const STAmount& saPrvReq, const STAmount& saCurReq,
|
||||
STAmount& saPrvAct, STAmount& saCurAct,
|
||||
uint64& uRateMax);
|
||||
|
||||
RippleCalc(LedgerEntrySet& lesNodes) : lesActive(lesNodes) { ; }
|
||||
|
||||
static TER rippleCalc(
|
||||
LedgerEntrySet& lesActive,
|
||||
STAmount& saMaxAmountAct,
|
||||
STAmount& saDstAmountAct,
|
||||
const STAmount& saDstAmountReq,
|
||||
const STAmount& saMaxAmountReq,
|
||||
const uint160& uDstAccountID,
|
||||
const uint160& uSrcAccountID,
|
||||
const STPathSet& spsPaths,
|
||||
const bool bPartialPayment,
|
||||
const bool bLimitQuality,
|
||||
const bool bNoRippleDirect
|
||||
);
|
||||
};
|
||||
|
||||
#endif
|
||||
// vim:ts=4
|
||||
@@ -9,6 +9,9 @@
|
||||
#include "NewcoinAddress.h"
|
||||
#include "utils.h"
|
||||
|
||||
STAmount saZero(CURRENCY_ONE, ACCOUNT_ONE, 0);
|
||||
STAmount saOne(CURRENCY_ONE, ACCOUNT_ONE, 1);
|
||||
|
||||
std::string SerializedType::getFullText() const
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
@@ -395,6 +395,9 @@ public:
|
||||
Json::Value getJson(int) const;
|
||||
};
|
||||
|
||||
extern STAmount saZero;
|
||||
extern STAmount saOne;
|
||||
|
||||
class STHash128 : public SerializedType
|
||||
{
|
||||
protected:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,6 @@
|
||||
#ifndef __TRANSACTIONENGINE__
|
||||
#define __TRANSACTIONENGINE__
|
||||
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/tuple/tuple_comparison.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
@@ -29,127 +27,6 @@ enum TransactionEngineParams
|
||||
// Transaction can be retried, soft failures allowed
|
||||
};
|
||||
|
||||
class PaymentNode {
|
||||
protected:
|
||||
friend class TransactionEngine;
|
||||
friend class PathState;
|
||||
|
||||
uint16 uFlags; // --> From path.
|
||||
|
||||
uint160 uAccountID; // --> Accounts: Recieving/sending account.
|
||||
uint160 uCurrencyID; // --> Accounts: Receive and send, Offers: send.
|
||||
// --- For offer's next has currency out.
|
||||
uint160 uIssuerID; // --> Currency's issuer
|
||||
|
||||
STAmount saTransferRate; // Transfer rate for uIssuerID.
|
||||
|
||||
// Computed by Reverse.
|
||||
STAmount saRevRedeem; // <-- Amount to redeem to next.
|
||||
STAmount saRevIssue; // <-- Amount to issue to next limited by credit and outstanding IOUs.
|
||||
// Issue isn't used by offers.
|
||||
STAmount saRevDeliver; // <-- Amount to deliver to next regardless of fee.
|
||||
|
||||
// Computed by forward.
|
||||
STAmount saFwdRedeem; // <-- Amount node will redeem to next.
|
||||
STAmount saFwdIssue; // <-- Amount node will issue to next.
|
||||
// Issue isn't used by offers.
|
||||
STAmount saFwdDeliver; // <-- Amount to deliver to next regardless of fee.
|
||||
|
||||
// For offers:
|
||||
|
||||
STAmount saRateMax; // XXX Should rate be sticky for forward too?
|
||||
|
||||
// Directory
|
||||
uint256 uDirectTip; // Current directory.
|
||||
uint256 uDirectEnd; // Next order book.
|
||||
bool bDirectAdvance; // Need to advance directory.
|
||||
SLE::pointer sleDirectDir;
|
||||
STAmount saOfrRate; // For correct ratio.
|
||||
|
||||
// Node
|
||||
bool bEntryAdvance; // Need to advance entry.
|
||||
unsigned int uEntry;
|
||||
uint256 uOfferIndex;
|
||||
SLE::pointer sleOffer;
|
||||
uint160 uOfrOwnerID;
|
||||
bool bFundsDirty; // Need to refresh saOfferFunds, saTakerPays, & saTakerGets.
|
||||
STAmount saOfferFunds;
|
||||
STAmount saTakerPays;
|
||||
STAmount saTakerGets;
|
||||
};
|
||||
|
||||
// account id, currency id, issuer id :: node
|
||||
typedef boost::tuple<uint160, uint160, uint160> aciSource;
|
||||
typedef boost::unordered_map<aciSource, unsigned int> curIssuerNode; // Map of currency, issuer to node index.
|
||||
typedef boost::unordered_map<aciSource, unsigned int>::const_iterator curIssuerNodeConstIterator;
|
||||
|
||||
extern std::size_t hash_value(const aciSource& asValue);
|
||||
|
||||
// Holds a path state under incremental application.
|
||||
class PathState
|
||||
{
|
||||
protected:
|
||||
Ledger::pointer mLedger;
|
||||
|
||||
TER pushNode(const int iType, const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
|
||||
TER pushImply(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
|
||||
|
||||
public:
|
||||
typedef boost::shared_ptr<PathState> pointer;
|
||||
|
||||
TER terStatus;
|
||||
std::vector<PaymentNode> vpnNodes;
|
||||
|
||||
// When processing, don't want to complicate directory walking with deletion.
|
||||
std::vector<uint256> vUnfundedBecame; // Offers that became unfunded or were completely consumed.
|
||||
|
||||
// First time scanning foward, as part of path contruction, a funding source was mentioned for accounts. Source may only be
|
||||
// used there.
|
||||
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.
|
||||
|
||||
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).
|
||||
|
||||
PathState(
|
||||
Ledger::ref lpLedger,
|
||||
const int iIndex,
|
||||
const LedgerEntrySet& lesSource,
|
||||
const STPath& spSourcePath,
|
||||
const uint160& uReceiverID,
|
||||
const uint160& uSenderID,
|
||||
const STAmount& saSend,
|
||||
const STAmount& saSendMax
|
||||
);
|
||||
|
||||
Json::Value getJson() const;
|
||||
|
||||
static PathState::pointer createPathState(
|
||||
Ledger::ref lpLedger,
|
||||
const int iIndex,
|
||||
const LedgerEntrySet& lesSource,
|
||||
const STPath& spSourcePath,
|
||||
const uint160& uReceiverID,
|
||||
const uint160& uSenderID,
|
||||
const STAmount& saSend,
|
||||
const STAmount& saSendMax
|
||||
)
|
||||
{
|
||||
return boost::make_shared<PathState>(lpLedger, iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax);
|
||||
}
|
||||
|
||||
static bool lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs);
|
||||
};
|
||||
|
||||
// One instance per ledger.
|
||||
// Only one transaction applied at a time.
|
||||
class TransactionEngine
|
||||
@@ -175,72 +52,11 @@ protected:
|
||||
uint160 mTxnAccountID;
|
||||
SLE::pointer mTxnAccount;
|
||||
|
||||
// First time working in reverse a funding source was mentioned. Source may only be used there.
|
||||
curIssuerNode mumSource; // Map of currency, issuer to node index.
|
||||
|
||||
// When processing, don't want to complicate directory walking with deletion.
|
||||
std::vector<uint256> mvUnfundedBecame; // Offers that became unfunded.
|
||||
|
||||
// If the transaction fails to meet some constraint, still need to delete unfunded offers.
|
||||
boost::unordered_set<uint256> musUnfundedFound; // Offers that were found unfunded.
|
||||
|
||||
SLE::pointer entryCreate(LedgerEntryType type, const uint256& index) { return mNodes.entryCreate(type, index); }
|
||||
SLE::pointer entryCache(LedgerEntryType type, const uint256& index) { return mNodes.entryCache(type, index); }
|
||||
void entryDelete(SLE::ref sleEntry) { mNodes.entryDelete(sleEntry); }
|
||||
void entryModify(SLE::ref sleEntry) { mNodes.entryModify(sleEntry); }
|
||||
|
||||
TER offerDelete(const uint256& uOfferIndex);
|
||||
TER offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID);
|
||||
|
||||
uint32 rippleTransferRate(const uint160& uIssuerID);
|
||||
STAmount rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
|
||||
STAmount rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID);
|
||||
uint32 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, const SOE_Field sfLow=sfLowQualityIn, const SOE_Field sfHigh=sfHighQualityIn);
|
||||
uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID)
|
||||
{ return rippleQualityIn(uToAccountID, uFromAccountID, uCurrencyID, sfLowQualityOut, sfHighQualityOut); }
|
||||
|
||||
STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
|
||||
STAmount rippleTransferFee(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount);
|
||||
void rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount, bool bCheckIssuer=true);
|
||||
STAmount rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount);
|
||||
|
||||
STAmount accountHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID);
|
||||
void accountSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount);
|
||||
STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault);
|
||||
|
||||
PathState::pointer pathCreate(const STPath& spPath);
|
||||
void pathNext(const PathState::pointer& pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint);
|
||||
TER calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeOfferRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeOfferFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAccountFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality);
|
||||
TER calcNodeAdvance(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality, const bool bReverse);
|
||||
TER calcNodeDeliverRev(
|
||||
const unsigned int uIndex,
|
||||
const PathState::pointer& pspCur,
|
||||
const bool bMultiQuality,
|
||||
const uint160& uOutAccountID,
|
||||
const STAmount& saOutReq,
|
||||
STAmount& saOutAct);
|
||||
|
||||
TER calcNodeDeliverFwd(
|
||||
const unsigned int uIndex,
|
||||
const PathState::pointer& pspCur,
|
||||
const bool bMultiQuality,
|
||||
const uint160& uInAccountID,
|
||||
const STAmount& saInFunds,
|
||||
const STAmount& saInReq,
|
||||
STAmount& saInAct,
|
||||
STAmount& saInFees);
|
||||
|
||||
void calcNodeRipple(const uint32 uQualityIn, const uint32 uQualityOut,
|
||||
const STAmount& saPrvReq, const STAmount& saCurReq,
|
||||
STAmount& saPrvAct, STAmount& saCurAct,
|
||||
uint64& uRateMax);
|
||||
|
||||
void txnWrite();
|
||||
|
||||
TER doAccountSet(const SerializedTransaction& txn);
|
||||
@@ -252,7 +68,7 @@ protected:
|
||||
TER doNicknameSet(const SerializedTransaction& txn);
|
||||
TER doPasswordFund(const SerializedTransaction& txn);
|
||||
TER doPasswordSet(const SerializedTransaction& txn);
|
||||
TER doPayment(const SerializedTransaction& txn);
|
||||
TER doPayment(const SerializedTransaction& txn, const TransactionEngineParams params);
|
||||
TER doWalletAdd(const SerializedTransaction& txn);
|
||||
TER doContractAdd(const SerializedTransaction& txn);
|
||||
TER doContractRemove(const SerializedTransaction& txn);
|
||||
|
||||
Reference in New Issue
Block a user