diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 1a5bdd3bf9..df263827e3 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -318,13 +318,13 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) return new STPathSet(name, paths); } } - else if (iType & STPathElement::typeStrayBits) + else if (iType & ~STPathElement::typeValidBits) { throw std::runtime_error("bad path element"); } else { - bool bAccount = !!(iType & STPathElement::typeAccount); + bool bAccount = !!(iType & STPathElement::typeAccount); bool bCurrency = !!(iType & STPathElement::typeCurrency); bool bIssuer = !!(iType & STPathElement::typeIssuer); diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 392966fcbb..48a7069da1 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -526,7 +526,7 @@ public: typeCurrency = 0x10, // Currency follows. typeIssuer = 0x20, // Issuer follows. typeBoundary = 0xFF, // Boundary between alternate paths. - typeStrayBits = 0xC0, // Bits that must be zero. + typeValidBits = 0x3E, // Bits that may be non-zero. }; protected: diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 25a0cef547..f2b4575b99 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -22,7 +22,8 @@ #define RIPPLE_PATHS_MAX 3 #define QUALITY_ONE 100000000 // 10e9 -#define CURRENCY_ONE uint160(1) +#define CURRENCY_ONE uint160(1) // Used as a place holder +#define ACCOUNT_ONE uint160(1) // Used as a place holder // static STAmount saOne(CURRENCY_ONE, 1, 0); @@ -2510,6 +2511,85 @@ bool PathState::less(const PathState::pointer& lhs, const PathState::pointer& rh return lhs->mIndex > rhs->mIndex; // Bigger is worse. } +// <-- bValid: true, if node is valid. +bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) +{ + paymentNode pnCur; + bool bFirst = vpnNodes.empty(); + const paymentNode& pnPrv = bFirst ? paymentNode() : vpnNodes.back(); + bool bAccount = !!(iType & STPathElement::typeAccount); + bool bCurrency = !!(iType & STPathElement::typeCurrency); + bool bIssuer = !!(iType & STPathElement::typeIssuer); + bool bRedeem = !!(iType & STPathElement::typeRedeem); + bool bIssue = !!(iType & STPathElement::typeIssue); + bool bValid = true; + + pnCur.uFlags = iType; + + if (iType & ~STPathElement::typeValidBits) + { + bValid = false; + } + else if (bAccount) + { + if (bRedeem || bIssue) + { + // Account link + + pnCur.uAccountID = uAccountID; + pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; + pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; + + // An intermediate node may be implied. + + // An offer may be implied + if (uCurrencyID != pnPrv.uCurrencyID) + { + // Implied preceeding offer. + + bValid = pushNode( + 0, + ACCOUNT_ONE, + CURRENCY_ONE, // Inherit from previous + ACCOUNT_ONE); // Inherit from previous + } + else if (uIssuerID != pnPrv.uIssuerID) + { + // Implied preceeding account. + + bValid = pushNode( + STPathElement::typeAccount + | STPathElement::typeRedeem + | STPathElement::typeIssue, + uIssuerID, + CURRENCY_ONE, // Inherit from previous + ACCOUNT_ONE); // Default same as account. + } + } + else + { + bValid = false; + } + } + else + { + // Offer link + if (bRedeem || bIssue) + { + bValid = false; + } + else + { + pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; + pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; + } + } + + vpnNodes.push_back(pnCur); + + return bValid; +} + PathState::PathState( int iIndex, const LedgerEntrySet& lesSource, @@ -2527,17 +2607,14 @@ PathState::PathState( saOutReq = saSend; saInReq = saSendMax; - paymentNode pnFirst; - paymentNode pnLast; + pushNode(STPathElement::typeAccount, uSenderID, saSendMax.getCurrency(), saSendMax.getIssuer()); - pnLast.uAccountID = uReceiverID; - pnLast.uCurrencyID = saOutReq.getCurrency(); + BOOST_FOREACH(const STPathElement& speElement, spSourcePath) + { + pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID()); + } - pnFirst.uAccountID = uSenderID; - pnFirst.uCurrencyID = saSendMax.getCurrency(); - - vpnNodes.push_back(pnFirst); - vpnNodes.push_back(pnLast); + pushNode(STPathElement::typeAccount, uReceiverID, saOutReq.getCurrency(), saOutReq.getIssuer()); } // Calculate the next increment of a path. diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index e246895cc0..0f3aed7671 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -101,10 +101,12 @@ enum TransactionEngineParams }; typedef struct { - uint16 uFlags; // --> from path + uint16 uFlags; // --> From path. - uint160 uAccountID; // --> recieving/sending account - uint160 uCurrencyID; // --> currency to recieve + uint160 uAccountID; // --> Recieving/sending account. + uint160 uCurrencyID; // --> Currency to recieve. + // --- For offer's next has currency out. + uint160 uIssuerID; // --> Currency's issuer // Computed by Reverse. STAmount saRevRedeem; // <-- Amount to redeem to next. @@ -119,10 +121,12 @@ typedef struct { // Hold a path state under incremental application. class PathState { +protected: + bool pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID); + public: typedef boost::shared_ptr pointer; - std::vector vpnNodes; LedgerEntrySet lesEntries;