Files
rippled/src/TransactionEngine.h

282 lines
11 KiB
C++

#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>
#include "Ledger.h"
#include "SerializedTransaction.h"
#include "SerializedLedger.h"
#include "LedgerEntrySet.h"
#include "TransactionErr.h"
// A TransactionEngine applies serialized transactions to a ledger
// It can also, verify signatures, verify fees, and give rejection reasons
enum TransactionEngineParams
{
tapNONE = 0x00,
tapNO_CHECK_SIGN = 0x01, // Signature already checked
tapOPEN_LEDGER = 0x10, // Transaction is running against an open ledger
// true = failures are not forwarded, check transaction fee
// false = debit ledger for consumed funds
tapRETRY = 0x20, // This is not the transaction's last pass
// 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
{
private:
LedgerEntrySet mNodes;
TER setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator);
TER takeOffers(
bool bPassive,
const uint256& uBookBase,
const uint160& uTakerAccountID,
const SLE::pointer& sleTakerAccount,
const STAmount& saTakerPays,
const STAmount& saTakerGets,
STAmount& saTakerPaid,
STAmount& saTakerGot);
protected:
Ledger::pointer mLedger;
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);
TER doClaim(const SerializedTransaction& txn);
TER doCreditSet(const SerializedTransaction& txn);
TER doInvoice(const SerializedTransaction& txn);
TER doOfferCreate(const SerializedTransaction& txn);
TER doOfferCancel(const SerializedTransaction& txn);
TER doNicknameSet(const SerializedTransaction& txn);
TER doPasswordFund(const SerializedTransaction& txn);
TER doPasswordSet(const SerializedTransaction& txn);
TER doPayment(const SerializedTransaction& txn);
TER doWalletAdd(const SerializedTransaction& txn);
TER doContractAdd(const SerializedTransaction& txn);
TER doContractRemove(const SerializedTransaction& txn);
public:
TransactionEngine() { ; }
TransactionEngine(Ledger::ref ledger) : mLedger(ledger) { assert(mLedger); }
Ledger::pointer getLedger() { return mLedger; }
void setLedger(Ledger::ref ledger) { assert(ledger); mLedger = ledger; }
TER applyTransaction(const SerializedTransaction&, TransactionEngineParams);
};
inline TransactionEngineParams operator|(const TransactionEngineParams& l1, const TransactionEngineParams& l2)
{
return static_cast<TransactionEngineParams>(static_cast<int>(l1) | static_cast<int>(l2));
}
inline TransactionEngineParams operator&(const TransactionEngineParams& l1, const TransactionEngineParams& l2)
{
return static_cast<TransactionEngineParams>(static_cast<int>(l1) & static_cast<int>(l2));
}
#endif
// vim:ts=4