From 4d6c37857e9014dc3e72120416194c6795c7db84 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 24 Jul 2012 19:45:47 -0700 Subject: [PATCH] Work in progress on ripple. --- src/TransactionEngine.cpp | 116 ++++++++++++++++++++++++++++++-------- src/TransactionEngine.h | 26 +++++++++ src/TransactionFormats.h | 15 +++-- 3 files changed, 129 insertions(+), 28 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index fca01e7996..72b852f23a 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "../json/writer.h" @@ -17,7 +18,8 @@ #include "utils.h" // Small for testing, should likely be 32 or 64. -#define DIR_NODE_MAX 2 +#define DIR_NODE_MAX 2 +#define RIPPLE_PATHS_MAX 3 bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std::string& strHuman) { @@ -33,6 +35,7 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { tenBAD_GEN_AUTH, "tenBAD_GEN_AUTH", "Not authorized to claim generator." }, { tenBAD_ISSUER, "tenBAD_ISSUER", "Malformed." }, { tenBAD_OFFER, "tenBAD_OFFER", "Malformed." }, + { tenBAD_PATH_COUNT, "tenBAD_PATH_COUNT", "Malformed: too many paths." }, { tenBAD_RIPPLE, "tenBAD_RIPPLE", "Ledger prevents ripple from succeeding." }, { tenBAD_SET_ID, "tenBAD_SET_ID", "Malformed." }, { tenCLAIMED, "tenCLAIMED", "Can not claim a previously claimed account." }, @@ -72,6 +75,8 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { terOVER_LIMIT, "terOVER_LIMIT", "Over limit." }, { terPAST_LEDGER, "terPAST_LEDGER", "The transaction expired and can't be applied" }, { terPAST_SEQ, "terPAST_SEQ", "This sequence number has already past" }, + { terPATH_EMPTY, "terPATH_EMPTY", "Path could not send partial amount." }, + { terPATH_PARTIAL, "terPATH_PARTIAL", "Path could not send full amount." }, { terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction" }, { terSET_MISSING_DST, "terSET_MISSING_DST", "Can't set password, destination missing." }, { terSUCCESS, "terSUCCESS", "The transaction was applied" }, @@ -2126,6 +2131,44 @@ bool calcPaymentForward(std::vector& pnNodes) } #endif +// Ensure sort order is complelely deterministic. +class PathStateCompare +{ +public: + bool operator()(const PathState::pointer& lhs, const PathState::pointer& rhs) + { + // Return true, iff lhs has less priority than rhs. + + if (lhs->uQuality != rhs->uQuality) + return lhs->uQuality > rhs->uQuality; // Bigger is worse. + + // Best quanity is second rank. + if (lhs->saOut != rhs->saOut) + return lhs->saOut < rhs->saOut; // Smaller is worse. + + // Path index is third rank. + return lhs->mIndex > rhs->mIndex; // Bigger is worse. + } +}; + +PathState::pointer TransactionEngine::pathCreate(const STPath& spPath) +{ + return PathState::pointer(); +} + +// Calcuate the next increment of a path. +void TransactionEngine::pathNext(PathState::pointer pspCur) +{ + +} + +// Apply an increment of the path, then calculate the next increment. +void TransactionEngine::pathApply(PathState::pointer pspCur) +{ + + pathNext(pspCur); +} + // XXX Need to audit for things like setting accountID not having memory. TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn) { @@ -2313,47 +2356,72 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); // XXX If we are parsing for determing forwarding check maximum path count. - if (!spsPaths.getPathCount()) + if (!spsPaths.isEmpty()) { Log(lsINFO) << "doPayment: Invalid transaction: No paths."; return tenRIPPLE_EMPTY; } -#if 0 - // 1) Calc payment in reverse: do not modify sles. - // 2) Calc payment forward: do modify sles. - std::vector spPath; - - BOOST_FOREACH(std::vector& spPath, spsPaths) + else if (spsPaths.getPathCount() > RIPPLE_PATHS_MAX) { + return tenBAD_PATH_COUNT; + } - Log(lsINFO) << "doPayment: Implementation error: Not implemented."; + // Incrementally search paths. + std::priority_queue, PathStateCompare> pqPaths; +#if 0 + BOOST_FOREACH(std::vector::const_iterator::value_type spPath, spsPaths) + { + PathState::pointer pspCur = pathCreate(spPath); - return tenUNKNOWN; + pqPaths.push(pspCur); } #endif + TransactionEngineResult terResult; + STAmount saPaid; + STAmount saWanted; + uint32 uFlags = txn.getFlags(); // XXX Redundant. -#if 0 -// XXX Or additionally queue unfundeds for removal on failure. - if (terSUCCESS == terResult) + terResult = tenUNKNOWN; + while (tenUNKNOWN == terResult) { - // Transaction failed. Process possible unfunded offers. - entryReset(txn); - - BOOST_FOREACH(const uint256& uOfferIndex, mUnfunded) + if (!pqPaths.empty()) { - SLE::pointer sleOffer = mLedger->getOffer(uOfferIndex); - uint160 uOfferID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); - STAmount saOfferFunds = sleOffer->getIValueFieldAmount(sfTakerGets); + // Have a path to contribute. + PathState::pointer pspCur = pqPaths.top(); - if (!accountFunds(uOfferID, saOfferFunds).isPositive()) + pqPaths.pop(); + + pathApply(pspCur); + + if (tenUNKNOWN == terResult && saPaid == saWanted) { - offerDelete(sleOffer, uOfferIndex, uOfferID); - bWrite = true; + terResult = terSUCCESS; + } + + if (tenUNKNOWN == terResult && pspCur->uQuality) + { + // Current path still has something to contribute. + pqPaths.push(pspCur); } } + // Ran out of paths. + else if ((!uFlags & tfPartialPayment)) + { + // Partial payment not allowed. + terResult = terPATH_PARTIAL; // XXX No effect, except unfunded and charge fee. + } + else if (saPaid.isZero()) + { + // Nothing claimed. + terResult = terPATH_EMPTY; // XXX No effect except unfundeds and charge fee. + // XXX + } + else + { + terResult = terSUCCESS; + } } -#endif Log(lsINFO) << "doPayment: Delay transaction: No ripple paths could be satisfied."; diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index c51dcdeed9..a02d5009f5 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -26,6 +26,7 @@ enum TransactionEngineResult tenBAD_GEN_AUTH, tenBAD_ISSUER, tenBAD_OFFER, + tenBAD_PATH_COUNT, tenBAD_SET_ID, tenCREATEXNS, tenDST_IS_SRC, @@ -78,6 +79,11 @@ enum TransactionEngineResult terSET_MISSING_DST, terUNCLAIMED, terUNFUNDED, + + // Might succeed in different order. + // XXX claim fee and try to delete unfunded. + terPATH_EMPTY, + terPATH_PARTIAL, }; bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std::string& strHuman); @@ -102,6 +108,22 @@ enum TransactionAccountAction typedef std::pair AffectedAccount; +// Hold a path state under incremental application. +class PathState +{ +public: + typedef boost::shared_ptr pointer; + + int mIndex; + uint64 uQuality; // 0 = none. + STAmount saIn; + STAmount saOut; + + PathState(int iIndex) : mIndex(iIndex) { ; }; + + static PathState::pointer createPathState(int iIndex) { return boost::make_shared(iIndex); }; +}; + // One instance per ledger. // Only one transaction applied at a time. class TransactionEngine @@ -190,6 +212,10 @@ protected: STAmount 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 pathApply(PathState::pointer pspCur); + void pathNext(PathState::pointer pspCur); + void txnWrite(); TransactionEngineResult offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID); diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index 7994fdee84..1fd9d9e142 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -35,15 +35,22 @@ const int TransactionIFee = 4; const int TransactionMinLen = 32; const int TransactionMaxLen = 1048576; +// // Transaction flags. -const uint32 tfCreateAccount = 0x00010000; -const uint32 tfNoRippleDirect = 0x00020000; - -const uint32 tfPassive = 0x00010000; +// +// AccountSet flags: const uint32 tfUnsetEmailHash = 0x00010000; const uint32 tfUnsetWalletLocator = 0x00020000; +// OfferCreate flags: +const uint32 tfPassive = 0x00010000; + +// Payment flags: +const uint32 tfCreateAccount = 0x00010000; +const uint32 tfPartialPayment = 0x00020000; +const uint32 tfNoRippleDirect = 0x00040000; + extern TransactionFormat InnerTxnFormats[]; extern TransactionFormat* getTxnFormat(TransactionType t); #endif