From fde853d3884d0097282098ad95f92f1a0e65a6bf Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 28 Jul 2012 17:35:51 -0700 Subject: [PATCH 001/426] Revise STPathSet. --- src/SerializedTypes.cpp | 122 ++++++++++++++++++++++++---------------- src/SerializedTypes.h | 83 +++++++++++++++++++++------ 2 files changed, 142 insertions(+), 63 deletions(-) diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index bd76f5c843..fbd861c440 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -294,34 +294,54 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) { std::vector paths; std::vector path; + do { - switch(s.get8()) + int iType = s.get8(); + + if (iType == STPathElement::typeEnd || iType == STPathElement::typeBoundary) { - case STPathElement::typeEnd: - if (path.empty()) - { - if (!paths.empty()) - throw std::runtime_error("empty last path"); - } - else paths.push_back(path); + if (path.empty()) + throw std::runtime_error("empty path"); + + paths.push_back(path); + path.clear(); + + if (iType == STPathElement::typeEnd) + { return new STPathSet(name, paths); + } + } + else if (iType & STPathElement::typeStrayBits) + { + throw std::runtime_error("bad path element"); + } + else + { + bool bAccount = !!(iType & STPathElement::typeAccount); + bool bOffer = !!(iType & STPathElement::typeOffer); + bool bCurrency = !!(iType & STPathElement::typeCurrency); + bool bIssuer = !!(iType & STPathElement::typeIssuer); - case STPathElement::typeBoundary: - if (path.empty()) - throw std::runtime_error("empty path"); - paths.push_back(path); - path.clear(); + if (!bAccount && !bOffer) + { + throw std::runtime_error("bad path element"); + } - case STPathElement::typeAccount: - path.push_back(STPathElement(STPathElement::typeAccount, s.get160())); - break; + uint160 uAccountID; + uint160 uCurrency; + uint160 uIssuerID; - case STPathElement::typeOffer: - path.push_back(STPathElement(STPathElement::typeOffer, s.get160())); - break; + if (bAccount) + uAccountID = s.get160(); - default: throw std::runtime_error("Unknown path element"); + if (bCurrency) + uCurrency = s.get160(); + + if (bIssuer) + uIssuerID = s.get160(); + + path.push_back(STPathElement(uAccountID, uCurrency, uIssuerID)); } } while(1); } @@ -329,8 +349,10 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) int STPathSet::getLength() const { int ret = 0; + for (std::vector::const_iterator it = value.begin(), end = value.end(); it != end; ++it) ret += it->getSerializeSize(); + return (ret != 0) ? ret : (ret + 1); } @@ -340,30 +362,22 @@ Json::Value STPath::getJson(int) const BOOST_FOREACH(std::vector::const_iterator::value_type it, mPath) { - switch (it.getNodeType()) - { - case STPathElement::typeAccount: - { - Json::Value elem(Json::objectValue); + Json::Value elem(Json::objectValue); + int iType = it.getNodeType(); - elem["account"] = NewcoinAddress::createHumanAccountID(it.getNode()); + elem["type"] = it.getNodeType(); + elem["type_hex"] = strHex(it.getNodeType()); - ret.append(elem); - break; - } + if (iType & STPathElement::typeAccount) + elem["account"] = NewcoinAddress::createHumanAccountID(it.getAccountID()); - case STPathElement::typeOffer: - { - Json::Value elem(Json::objectValue); + if (iType & STPathElement::typeCurrency) + elem["currency"] = STAmount::createHumanCurrency(it.getCurrency()); - elem["offer"] = it.getNode().GetHex(); + if (iType & STPathElement::typeIssuer) + elem["issuer"] = NewcoinAddress::createHumanAccountID(it.getIssuerID()); - ret.append(elem); - break; - } - - default: throw std::runtime_error("Unknown path element"); - } + ret.append(elem); } return ret; @@ -379,12 +393,13 @@ Json::Value STPathSet::getJson(int options) const return ret; } +#if 0 std::string STPath::getText() const { std::string ret("["); bool first = true; - BOOST_FOREACH(std::vector::const_iterator::value_type it, mPath) + BOOST_FOREACH(const STPathElement& it, mPath) { if (!first) ret += ", "; switch (it.getNodeType()) @@ -410,7 +425,9 @@ std::string STPath::getText() const return ret + "]"; } +#endif +#if 0 std::string STPathSet::getText() const { std::string ret("{"); @@ -427,23 +444,34 @@ std::string STPathSet::getText() const } return ret + "}"; } +#endif void STPathSet::add(Serializer& s) const { - bool firstPath = true; + bool bFirst = true; - BOOST_FOREACH(std::vector::const_iterator::value_type pit, value) + BOOST_FOREACH(const STPath& spPath, value) { - if (!firstPath) + if (!bFirst) { s.add8(STPathElement::typeBoundary); - firstPath = false; + bFirst = false; } - for (std::vector::const_iterator eit = pit.begin(), eend = pit.end(); eit != eend; ++eit) + BOOST_FOREACH(const STPathElement& speElement, spPath) { - s.add8(eit->getNodeType()); - s.add160(eit->getNode()); + int iType = speElement.getNodeType(); + + s.add8(iType); + + if (iType && STPathElement::typeAccount) + s.add160(speElement.getAccountID()); + + if (iType && STPathElement::typeCurrency) + s.add160(speElement.getCurrency()); + + if (iType && STPathElement::typeIssuer) + s.add160(speElement.getIssuerID()); } } s.add8(STPathElement::typeEnd); diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index b1ce80eedb..89c3a89dd7 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -518,26 +518,40 @@ public: class STPathElement { public: - static const int typeEnd = 0x00; - static const int typeAccount = 0x01; // Rippling through an account - static const int typeOffer = 0x02; // Claiming an offer - static const int typeBoundary = 0xFF; // boundary between alternate paths + enum { + typeEnd = 0x00, + typeAccount = 0x01, // Rippling through an account + typeOffer = 0x02, // Claiming an offer + typeCurrency = 0x10, // Currency follows + typeIssuer = 0x20, // Issuer follows + typeBoundary = 0xFF, // boundary between alternate paths + typeStrayBits = 0xCC, // Bits that must be zero. + }; protected: - int mType; - uint160 mNode; + int mType; + uint160 mAccountID; + uint160 mCurrency; + uint160 mIssuerID; public: - STPathElement(int type, const uint160& node) : mType(type), mNode(node) { ; } - int getNodeType() const { return mType; } - bool isAccount() const { return mType == typeAccount; } - bool isOffer() const { return mType == typeOffer; } + STPathElement(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID) + : mAccountID(uAccountID), mCurrency(uCurrency), mIssuerID(uIssuerID) + { + mType = + (uAccountID.isZero() ? STPathElement::typeOffer : STPathElement::typeAccount) + | (uCurrency.isZero() ? 0 : STPathElement::typeCurrency) + | (uIssuerID.isZero() ? 0 : STPathElement::typeIssuer); + } + + int getNodeType() const { return mType; } + bool isOffer() const { return mAccountID.isZero(); } + bool isAccount() const { return !isOffer(); } // Nodes are either an account ID or a offer prefix. Offer prefixs denote a class of offers. - const uint160& getNode() const { return mNode; } - - void setType(int type) { mType = type; } - void setNode(const uint160& n) { mNode = n; } + const uint160& getAccountID() const { return mAccountID; } + const uint160& getCurrency() const { return mCurrency; } + const uint160& getIssuerID() const { return mIssuerID; } }; class STPath @@ -556,12 +570,49 @@ public: void addElement(const STPathElement& e) { mPath.push_back(e); } void clear() { mPath.clear(); } int getSerializeSize() const { return 1 + mPath.size() * 21; } - std::string getText() const; +// std::string getText() const; Json::Value getJson(int) const; + + std::vector::iterator begin() { return mPath.begin(); } + std::vector::iterator end() { return mPath.end(); } std::vector::const_iterator begin() const { return mPath.begin(); } std::vector::const_iterator end() const { return mPath.end(); } }; +inline std::vector::iterator range_begin(STPath & x) +{ + return x.begin(); +} + +inline std::vector::iterator range_end(STPath & x) +{ + return x.end(); +} + +inline std::vector::const_iterator range_begin(const STPath& x) +{ + return x.begin(); +} + +inline std::vector::const_iterator range_end(const STPath& x) +{ + return x.end(); +} + +namespace boost +{ + template<> + struct range_mutable_iterator< STPath > + { + typedef std::vector::iterator type; + }; + + template<> + struct range_const_iterator< STPath > + { + typedef std::vector::const_iterator type; + }; +} class STPathSet : public SerializedType { // A set of zero or more payment paths protected: @@ -580,7 +631,7 @@ public: { return std::auto_ptr(construct(sit, name)); } int getLength() const; - std::string getText() const; +// std::string getText() const; void add(Serializer& s) const; virtual Json::Value getJson(int) const; From 4f8ada17c710ee812cb53e180f7527dfb0bbdb0a Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 28 Jul 2012 17:36:08 -0700 Subject: [PATCH 002/426] Work towards ripple. --- src/LedgerEntrySet.cpp | 7 +- src/LedgerEntrySet.h | 6 +- src/SerializedTypes.cpp | 6 +- src/TransactionEngine.cpp | 144 +++++++++++++++++++++++++------------- src/TransactionEngine.h | 77 +++++++++++++------- 5 files changed, 162 insertions(+), 78 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index e325b47dee..ad65ddd9f4 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -15,7 +15,7 @@ void LedgerEntrySet::clear() mSet.clear(); } -LedgerEntrySet LedgerEntrySet::duplicate() +LedgerEntrySet LedgerEntrySet::duplicate() const { return LedgerEntrySet(mEntries, mSet, mSeq + 1); } @@ -180,4 +180,9 @@ void LedgerEntrySet::entryDelete(SLE::pointer& sle) } } +bool LedgerEntrySet::intersect(const LedgerEntrySet& lesLeft, const LedgerEntrySet& lesRight) +{ + return true; // XXX Needs implementation +} + // vim:ts=4 diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 01312e0b52..885281a01f 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -34,14 +34,14 @@ protected: TransactionMetaSet mSet; int mSeq; - LedgerEntrySet(const boost::unordered_map &e, TransactionMetaSet& s, int m) : + LedgerEntrySet(const boost::unordered_map &e, const TransactionMetaSet& s, int m) : mEntries(e), mSet(s), mSeq(m) { ; } public: LedgerEntrySet() : mSeq(0) { ; } // set functions - LedgerEntrySet duplicate(); // Make a duplicate of this set + LedgerEntrySet duplicate() const; // Make a duplicate of this set void setTo(LedgerEntrySet&); // Set this set to have the same contents as another void swapWith(LedgerEntrySet&); // Swap the contents of two sets @@ -64,6 +64,8 @@ public: boost::unordered_map::const_iterator end() const { return mEntries.end(); } boost::unordered_map::iterator begin() { return mEntries.begin(); } boost::unordered_map::iterator end() { return mEntries.end(); } + + static bool intersect(const LedgerEntrySet& lesLeft, const LedgerEntrySet& lesRight); }; #endif diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index fbd861c440..a341225d19 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -464,13 +464,13 @@ void STPathSet::add(Serializer& s) const s.add8(iType); - if (iType && STPathElement::typeAccount) + if (iType & STPathElement::typeAccount) s.add160(speElement.getAccountID()); - if (iType && STPathElement::typeCurrency) + if (iType & STPathElement::typeCurrency) s.add160(speElement.getCurrency()); - if (iType && STPathElement::typeIssuer) + if (iType & STPathElement::typeIssuer) s.add160(speElement.getIssuerID()); } } diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 69dde7cb91..5fb1fc94d4 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -2161,51 +2161,67 @@ bool calcPaymentForward(std::vector& pnNodes) } #endif -// Ensure sort order is complelely deterministic. -class PathStateCompare +bool PathState::less(const PathState::pointer& lhs, const PathState::pointer& rhs) { -public: - bool operator()(const PathState::pointer& lhs, const PathState::pointer& rhs) - { - // Return true, iff lhs has less priority than rhs. + // Return true, iff lhs has less priority than rhs. - if (lhs->uQuality != rhs->uQuality) - return lhs->uQuality > rhs->uQuality; // Bigger is worse. + 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. + // 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(); + // Path index is third rank. + return lhs->mIndex > rhs->mIndex; // Bigger is worse. } -// Calcuate the next increment of a path. +PathState::PathState( + int iIndex, + const LedgerEntrySet& lesSource, + const STPath& spSourcePath, + uint160 uReceiverID, + uint160 uSenderID, + STAmount saSend, + STAmount saSendMax, + bool bPartialPayment + ) + : mIndex(iIndex), uQuality(0), bDirty(true) +{ + lesEntries = lesSource.duplicate(); + + paymentNode pnFirst; + paymentNode pnLast; + + pnLast.bPartialPayment = bPartialPayment; + pnLast.uAccount = uReceiverID; + pnLast.saWanted = saSend; + + pnFirst.uAccount = uSenderID; + pnFirst.saWanted = saSendMax; + + vpnNodes.push_back(pnFirst); + vpnNodes.push_back(pnLast); +} + +// Calculate 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) { // Ripple if source or destination is non-native or if there are paths. - uint32 txFlags = txn.getFlags(); - bool bCreate = !!(txFlags & tfCreateAccount); - bool bNoRippleDirect = !!(txFlags & tfNoRippleDirect); + uint32 uTxFlags = txn.getFlags(); + bool bCreate = !!(uTxFlags & tfCreateAccount); + bool bNoRippleDirect = !!(uTxFlags & tfNoRippleDirect); + bool bPartialPayment = !!(uTxFlags & tfPartialPayment); bool bPaths = txn.getITFieldPresent(sfPaths); bool bMax = txn.getITFieldPresent(sfSendMax); uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); @@ -2385,7 +2401,6 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); - // XXX If we are parsing for determing forwarding check maximum path count. if (!spsPaths.isEmpty()) { Log(lsINFO) << "doPayment: Invalid transaction: No paths."; @@ -2398,45 +2413,80 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction } // 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); + std::vector vpsPaths; - pqPaths.push(pspCur); + BOOST_FOREACH(const STPath& spPath, spsPaths) + { + vpsPaths.push_back(PathState::createPathState( + vpsPaths.size(), + mNodes, + spPath, + uDstAccountID, + mTxnAccountID, + saDstAmount, + saMaxAmount, + bPartialPayment + )); } -#endif + TransactionEngineResult terResult; STAmount saPaid; STAmount saWanted; - uint32 uFlags = txn.getFlags(); // XXX Redundant. terResult = tenUNKNOWN; while (tenUNKNOWN == terResult) { - if (!pqPaths.empty()) + PathState::pointer pspBest; + + // Find the best path. + BOOST_FOREACH(PathState::pointer pspCur, vpsPaths) { - // Have a path to contribute. - PathState::pointer pspCur = pqPaths.top(); + if (pspCur->bDirty) + { + pspCur->bDirty = false; + pspCur->lesEntries = mNodes.duplicate(); - pqPaths.pop(); + // XXX Compute increment + pathNext(pspCur); + } - pathApply(pspCur); + if (!pspBest || (pspCur->uQuality && PathState::less(pspBest, pspCur))) + pspBest = pspCur; + } + if (!pspBest) + { + // + // Apply path. + // + + // Install changes for path. + mNodes.swapWith(pspBest->lesEntries); + + // Mark that path as dirty. + pspBest->bDirty = true; + + // Mark as dirty any other path that intersected. + BOOST_FOREACH(PathState::pointer& pspOther, vpsPaths) + { + // Look for intersection of best and the others. + // - Will forget the intersection applied. + // - Anything left will not interfere with it. + // - Will remember the non-intersection non-applied for future consideration. + if (!pspOther->bDirty + && pspOther->uQuality + && LedgerEntrySet::intersect(pspBest->lesEntries, pspOther->lesEntries)) + pspOther->bDirty = true; + } + + // Figure out if done. if (tenUNKNOWN == terResult && saPaid == saWanted) { 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)) + else if (!bPartialPayment) { // Partial payment not allowed. terResult = terPATH_PARTIAL; // XXX No effect, except unfunded and charge fee. diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 82a651181b..f470e98ab4 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -105,14 +105,60 @@ class PathState public: typedef boost::shared_ptr pointer; - int mIndex; - uint64 uQuality; // 0 = none. - STAmount saIn; - STAmount saOut; + typedef struct { + bool bPartialPayment; // --> + uint16 uFlags; // --> from path - PathState(int iIndex) : mIndex(iIndex) { ; }; + uint160 uAccount; // --> recieving/sending account - static PathState::pointer createPathState(int iIndex) { return boost::make_shared(iIndex); }; + STAmount saWanted; // --> What this node wants from upstream. + + // Maybe this should just be a bool: + // STAmount saIOURedeemMax; // --> Max amount of IOUs to redeem downstream. + // Maybe this should just be a bool: + // STAmount saIOUIssueMax; // --> Max Amount of IOUs to issue downstream. + + STAmount saIOURedeem; // <-- What this node will redeem downstream. + STAmount saIOUIssue; // <-- What this node will issue downstream. + STAmount saSend; // <-- Stamps this node will send downstream. + + STAmount saRecieve; // Amount stamps to receive. + + } paymentNode; + + std::vector vpnNodes; + LedgerEntrySet lesEntries; + + int mIndex; + uint64 uQuality; // 0 = none. + STAmount saIn; + STAmount saOut; + bool bDirty; // Path not computed. + + PathState( + int iIndex, + const LedgerEntrySet& lesSource, + const STPath& spSourcePath, + uint160 uReceiverID, + uint160 uSenderID, + STAmount saSend, + STAmount saSendMax, + bool bPartialPayment + ); + + static PathState::pointer createPathState( + int iIndex, + const LedgerEntrySet& lesSource, + const STPath& spSourcePath, + uint160 uReceiverID, + uint160 uSenderID, + STAmount saSend, + STAmount saSendMax, + bool bPartialPayment + ) + { return boost::make_shared(iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax, bPartialPayment); }; + + static bool less(const PathState::pointer& lhs, const PathState::pointer& rhs); }; // One instance per ledger. @@ -137,25 +183,6 @@ private: bool dirNext(const uint256& uRootIndex, SLE::pointer& sleNode, unsigned int& uDirEntry, uint256& uEntryIndex); #ifdef WORK_IN_PROGRESS - typedef struct { - uint16 uFlags; // --> from path - - STAccount saAccount; // --> recieving/sending account - - STAmount saWanted; // --> What this node wants from upstream. - - // Maybe this should just be a bool: - STAmount saIOURedeemMax; // --> Max amount of IOUs to redeem downstream. - // Maybe this should just be a bool: - STAmount saIOUIssueMax; // --> Max Amount of IOUs to issue downstream. - - STAmount saIOURedeem; // <-- What this node will redeem downstream. - STAmount saIOUIssue; // <-- What this node will issue downstream. - STAmount saSend; // <-- Stamps this node will send downstream. - - STAmount saRecieve; // Amount stamps to receive. - - } paymentNode; typedef struct { std::vector vpnNodes; From 794fe66008d0e15d394e1457258b449ac1d3cd88 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 1 Aug 2012 12:44:22 -0700 Subject: [PATCH 003/426] Work towards ripple. --- src/SerializedTypes.cpp | 8 +- src/SerializedTypes.h | 15 +- src/TransactionEngine.cpp | 287 ++++++++++++++++++++++++++++++-------- src/TransactionEngine.h | 46 +++--- 4 files changed, 261 insertions(+), 95 deletions(-) diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index a341225d19..311f004edb 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -318,16 +318,10 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) } else { - bool bAccount = !!(iType & STPathElement::typeAccount); - bool bOffer = !!(iType & STPathElement::typeOffer); + bool bAccount = !!(iType & STPathElement::typeAccount); bool bCurrency = !!(iType & STPathElement::typeCurrency); bool bIssuer = !!(iType & STPathElement::typeIssuer); - if (!bAccount && !bOffer) - { - throw std::runtime_error("bad path element"); - } - uint160 uAccountID; uint160 uCurrency; uint160 uIssuerID; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 89c3a89dd7..c3ba0f0471 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -520,12 +520,13 @@ class STPathElement public: enum { typeEnd = 0x00, - typeAccount = 0x01, // Rippling through an account - typeOffer = 0x02, // Claiming an offer - typeCurrency = 0x10, // Currency follows - typeIssuer = 0x20, // Issuer follows - typeBoundary = 0xFF, // boundary between alternate paths - typeStrayBits = 0xCC, // Bits that must be zero. + typeAccount = 0x01, // Rippling through an account (vs taking an offer). + typeRedeem = 0x04, // Redeem IOUs. + typeIssue = 0x08, // Issue IOUs. + typeCurrency = 0x10, // Currency follows. + typeIssuer = 0x20, // Issuer follows. + typeBoundary = 0xFF, // Boundary between alternate paths. + typeStrayBits = 0xC0, // Bits that must be zero. }; protected: @@ -539,7 +540,7 @@ public: : mAccountID(uAccountID), mCurrency(uCurrency), mIssuerID(uIssuerID) { mType = - (uAccountID.isZero() ? STPathElement::typeOffer : STPathElement::typeAccount) + (uAccountID.isZero() ? 0 : STPathElement::typeAccount) | (uCurrency.isZero() ? 0 : STPathElement::typeCurrency) | (uIssuerID.isZero() ? 0 : STPathElement::typeIssuer); } diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 5fb1fc94d4..dd3d3a8c8c 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -2017,6 +2017,7 @@ void TransactionEngine::calcNodeOfferReverse( } } } +#endif // From the destination work towards the source calculating how much must be asked for. // --> bAllowPartial: If false, fail if can't meet requirements. @@ -2028,64 +2029,31 @@ void TransactionEngine::calcNodeOfferReverse( // <-> [0]saWanted.mAmount : --> limit, <-- actual // XXX Disallow looping. // XXX With multiple path and due to offers, must consider consumed. -bool calcPaymentReverse(std::vector& pnNodes, bool bAllowPartial) +bool TransactionEngine::calcPathReverse(PathState::pointer pspCur) { + bool bSent = true; +#if 0 TransactionEngineResult terResult = tenUNKNOWN; - uIndex = pnNodes.size(); + unsigned int uIndex = pspCur->vpnNodes.size() - 1; - while (tenUNKNOWN == terResult && uIndex--) + while (bSent && tenUNKNOWN == terResult && uIndex--) { // Calculate (1) sending by fullfilling next wants and (2) setting current wants. + paymentNode& prvPN = uIndex ? pnNodes[uIndex-1] : pnNodes[0]; paymentNode& curPN = pnNodes[uIndex]; - paymentNode& prvPN = pnNodes[uIndex-1]; paymentNode& nxtPN = pnNodes[uIndex+1]; + bool bRedeem = !!(curPN.uFlags & STPathElement::typeRedeem); + bool bIssue = !!(curPN.uFlags & STPathElement::typeIssue); + bool bOffer = !!(curPN.uFlags & STPathElement::typeOffer); - if (!(uFlags & (PF_REDEEM|PF_ISSUE))) - { - // Redeem IOUs - terResult = tenBAD_PATH; - } - else if (curPN.saWanted.isZero()) + if (curPN.saWanted.isZero()) { // Must want something. terResult = tenBAD_AMOUNT; } - else if (curPN->uFlags & PF_ACCOUNT) - { - // Account node. - // Rippling through this accounts balances. - // No currency change. - // Issuer change possible. - - SLE::pointer sleRippleCur = ; - SLE::pointer sleRippleNxt = ; - STAmount saBalanceCur = ; - - if ((uFlags & PF_REDEEM) && saBalanceCur.isPositive()) - { - // Redeem IOUs - - // XXX - curPN.saWanted += ___; - - bSent = true; - } - - if ((uFlags & PF_ISSUE) // Allowed to issue. - && !saWantedNxt.isZero() // Need to issue. - && !saBalanceCur.isPositive()) // Can issue. - { - // Issue IOUs - - // XXX - curPN.saWanted += ___; - bSent = true; - } - - } - else if (curPN->uFlags & PF_OFFER) + else if (bOffer) { // Offer node. // Ripple or transfering from previous node through this offer to next node. @@ -2125,13 +2093,91 @@ bool calcPaymentReverse(std::vector& pnNodes, bool bAllowPartial) // Save sent amount } } + // Account node. + else if (!bIssue && !bOffer) + { + terResult = tenBAD_PATH; + } else { - assert(false); - } + // Rippling through this accounts balances. + // No currency change. + // Issuer change possible. + // Figuring out want current account should redeem and send. - if (tenUNKNOWN == terResult == curPN.saWanted.isZero()) - terResult = terZERO; // Path contributes nothing. + SLE::pointer sleRippleCur = ; + SLE::pointer sleRippleNxt = ; + STAmount saBalance = peekBalance(curPN.uAccountID, nxtPN.uAccountID); + STAmount saLimit = peekLimit(curPN.uAccountID, nxtPN.uAccountID); + STAmount saWanted = nxtPN.saWanted; + + curPN.saWanted.zero(); + + if (bRedeem && saBalance.isPositive()) + { + // Allowed to redeem and have IOUs. + curPN.saIOURedeem = min(saBalance, saWanted); + curPN.saWanted = curPN.saIOURedeem; // XXX Assumes we want 1::1 + saWanted -= curPN.saIOURedeem; + } + else + { + curPN.saIOURedeem.zero(); + } + + if (bIssue // Allowed to issue. + && !saWanted.isZero() // Need to issue. + && !saBalance.isPositive()) // Can issue. (Can't if must redeem). + { + curPN.saIOUIssue = min(saLimit+saBalance, saWanted); + curPN.saWanted += curPN.saIOUIssue; // XXX Assumes we want 1::1 + } + else + { + curPN.saIOUIssue.zero(); + } + + bSent = !curPN.saIOURedeem.isZero() || !curPN.saIOUIssue.isZero(); + } + } +#endif + return bSent; +} + +// Cur is the driver and will be filled exactly. +void TransactionEngine::calcNodeFwd(const uint32 uQualityIn, const uint32 uQualityOut, + const STAmount& saPrvReq, const STAmount& saCurReq, + STAmount& saPrvAct, STAmount& saCurAct) +{ + if (uQualityIn >= uQualityOut) + { + // No fee. + STAmount saTransfer = MIN(saPrvReq-saPrvAct, saCurReq-saCurAct); + + saPrvAct += saTransfer; + saCurAct += saTransfer; + } + else + { + // Fee. + STAmount saPrv = saPrvReq-saPrvAct; + STAmount saCur = saCurReq-saCurAct; + STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityIn, uint160(1)), uQualityOut, uint160(1)); + + if (saCurIn >= saPrv) + { + // All of cur. Some amount of prv. + saCurAct = saCurReq; + saPrvAct += saCurIn; + } + else + { + // A part of cur. All of prv. + STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityOut, uint160(1)), uQualityIn, uint160(1)); + + saCurAct += saCurOut; + saPrvAct = saPrvReq; + } } } @@ -2142,24 +2188,130 @@ bool calcPaymentReverse(std::vector& pnNodes, bool bAllowPartial) // --> [all]saWanted.IOURedeem // --> [all]saWanted.IOUIssue // --> [all]saAccount -bool calcPaymentForward(std::vector& pnNodes) +// XXX This path becomes dirty if saSendMaxFirst must be changed. +void TransactionEngine::calcPathForward(PathState::pointer pspCur) { - cur = src; +#if 0 + TransactionEngineResult terResult = tenUNKNOWN; + unsigned int uIndex = 0; - if (!cur->saSend.isZero()) - { - // Sending stamps - always final step. - assert(!cur->next); - nxt->saReceive = cur->saSend; - bDone = true; - } - else - { - // Rippling. + unsigned int uEnd = pspCur->vpnNodes.size(); + unsigned int uLast = uEnd - 1; + while (tenUNKNOWN == terResult && uIndex != uEnd) + { + // Calculate (1) sending by fullfilling next wants and (2) setting current wants. + + paymentNode& prvPN = uIndex ? pnNodes[uIndex-1] : pnNodes[0]; + paymentNode& curPN = pnNodes[uIndex]; + + // XXX Assume rippling. + + if (!uIndex) + { + // First node, calculate amount to send. + STAmount& saCurRedeemReq = curPN.saRevRedeem; + STAmount& saCurRedeemAct = curPN.saFwdRedeem; + STAmount& saCurIssueReq = curPN.saRevIssue; + STAmount& saCurIssueAct = curPN.saFwdIssue; + + STAmount& saCurSendMaxReq = curPN.saSendMax; + STAmount saCurSendMaxAct; + + if (saCurRedeemReq) + { + // Redeem requested. + saCurRedeemAct = MIN(saCurRedeemAct, saCurSendMaxReq); + saCurSendMaxAct = saCurRedeemAct; + } + + if (saCurIssueReq && saCurSendMaxReq != saCurRedeemAct) + { + // Issue requested and not over budget. + saCurIssueAct = MIN(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); + // saCurSendMaxAct += saCurIssueReq; // Not needed. + } + } + else if (uIndex == uLast) + { + // Last node. Accept all funds. Calculate amount actually to credit. + uint32 uQualityIn = peekQualityIn(curPN.uAccountID, prvPN.uAccountID); + STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; + STAmount& saPrvIssueReq = prvPN.saFwdIssue; + STAmount saPrvIssueAct = uQualityIn >= QUALITY_ONE + ? saPrvIssueReq // No fee. + : multiply(saPrvIssueReq, uQualityIn, _); // Fee. + STAmount& saCurReceive = curPN.saReceive; + + // Amount to credit. + saCurReceive = saPrvRedeemReq+saPrvIssueAct; + + // Actually receive. + rippleCredit(curPN.uAccountID, prvPN.uAccountID, saPrvRedeemReq + saPrvIssueReq); + } + else + { + // Handle middle node. + // The previous nodes tells want it wants to push through to current. + // The current node know what it woud push through next. + // Determine for the current node: + // - Output to next node minus fees. + // Perform balance adjustment with previous. + // All of previous output is consumed. + + STAmount saSrcRedeem; // To start, redeeming none. + STAmount saSrcIssue; // To start, issuing none. + STAmount saDstRedeem; + + // Have funds in previous node to transfer. + uint32 uQualityIn = peekQualityIn(curPN.uAccountID, prvPN.uAccountID); + uint32 uQualityOut = peekQualityOut(curPN.uAccountID, nxtPN.uAccountID); + + STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; + STAmount saPrvRedeemAct; + STAmount& saCurRedeemReq = curPN.saRevRedeem; + STAmount& saCurRedeemAct = curPN.saFwdRedeem; + STAmount& saPrvIssueReq = prvPN.saFwdIssue; + STAmount saPrvIssueAct; + + // Previous redeem part 1: redeem -> redeem + if (saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. + { + // Rate : 1.0 : quality out + calcNodeFwd(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); + } + + // Previous redeem part 2: redeem -> issue. + // wants to redeem and current would and can issue. + // If redeeming cur to next is done, this implies can issue. + if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem. + && saCurRedeemReq == saCurRedeemAct) // Current has more to redeem to next. + { + // Rate : 1.0 : 1.0 + transfer_rate + calcNodeFwd(QUALITY_ONE, QUALITY_ONE+peekTransfer(curPN.uAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + } + + // Previous issue part 1: issue -> redeem + if (saPrvIssueReq != saPrvIssueAct // Previous wants to issue. + && saCurRedeemReq == saCurRedeemAct) // Current has more to redeem to next. + { + // Rate: quality in : quality out + calcNodeFwd(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); + } + + // Previous issue part 2 : issue -> issue + if (saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. + { + // Rate: quality in : 1.0 + calcNodeFwd(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); + } + + // Adjust prv --> cur balance : take all inbound + rippleCredit(cur, prv, saPrvRedeemReq + saPrvIssueReq); + } } -} #endif +} bool PathState::less(const PathState::pointer& lhs, const PathState::pointer& rhs) { @@ -2207,6 +2359,19 @@ PathState::PathState( // Calculate the next increment of a path. void TransactionEngine::pathNext(PathState::pointer pspCur) { + // The next state is what is available in preference order. + // This is calculated when referenced accounts changed. + + if (calcPathReverse(pspCur)) + { + calcPathForward(pspCur); + } + else + { + // Mark path as inactive. + pspCur->uQuality = 0; + pspCur->bDirty = false; + } } // Apply an increment of the path, then calculate the next increment. diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index f470e98ab4..144dc79883 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -99,32 +99,33 @@ enum TransactionEngineParams tepMETADATA = 5, // put metadata in tree, not transaction }; +typedef struct { + bool bPartialPayment; // --> + uint16 uFlags; // --> from path + + uint160 uAccount; // --> recieving/sending account + + STAmount saSendMax; // --> First node: most to send. + STAmount saRecieve; // <-- Last node: Value received (minus fees) from upstream. + + STAmount saRevRedeem; // <-- Computed amount node needs at most redeem. + STAmount saRevIssue; // <-- Computed amount node ____ + STAmount saCurRedeem; // <-- Amount node will redeem to next. + STAmount saCurIssue; // <-- Amount node will issue to next. + + STAmount saWanted; // <-- What this node wants from upstream. + + STAmount saSend; // <-- Stamps this node will send downstream. + + STAmount saXNSRecieve; // Amount stamps to receive. +} paymentNode; + // Hold a path state under incremental application. class PathState { public: typedef boost::shared_ptr pointer; - typedef struct { - bool bPartialPayment; // --> - uint16 uFlags; // --> from path - - uint160 uAccount; // --> recieving/sending account - - STAmount saWanted; // --> What this node wants from upstream. - - // Maybe this should just be a bool: - // STAmount saIOURedeemMax; // --> Max amount of IOUs to redeem downstream. - // Maybe this should just be a bool: - // STAmount saIOUIssueMax; // --> Max Amount of IOUs to issue downstream. - - STAmount saIOURedeem; // <-- What this node will redeem downstream. - STAmount saIOUIssue; // <-- What this node will issue downstream. - STAmount saSend; // <-- Stamps this node will send downstream. - - STAmount saRecieve; // Amount stamps to receive. - - } paymentNode; std::vector vpnNodes; LedgerEntrySet lesEntries; @@ -229,6 +230,11 @@ protected: PathState::pointer pathCreate(const STPath& spPath); void pathApply(PathState::pointer pspCur); void pathNext(PathState::pointer pspCur); + void calcNodeFwd(const uint32 uQualityIn, const uint32 uQualityOut, + const STAmount& saPrvReq, const STAmount& saCurReq, + STAmount& saPrvAct, STAmount& saCurAct); + bool calcPathReverse(PathState::pointer pspCur); + void calcPathForward(PathState::pointer pspCur); void txnWrite(); From 42bd29c212f6869992387ade887e0ea401aef8ee Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 2 Aug 2012 19:16:24 -0700 Subject: [PATCH 004/426] Work towards ripple. --- src/SerializedTypes.h | 1 + src/TransactionEngine.cpp | 491 ++++++++++++++++++++++++++------------ src/TransactionEngine.h | 71 +++--- 3 files changed, 375 insertions(+), 188 deletions(-) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 21a3ca8f6b..392966fcbb 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -614,6 +614,7 @@ namespace boost typedef std::vector::const_iterator type; }; } + class STPathSet : public SerializedType { // A set of zero or more payment paths protected: diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 50d70ea75d..25a0cef547 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -21,6 +21,11 @@ #define DIR_NODE_MAX 2 #define RIPPLE_PATHS_MAX 3 +#define QUALITY_ONE 100000000 // 10e9 +#define CURRENCY_ONE uint160(1) + +// static STAmount saOne(CURRENCY_ONE, 1, 0); + bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std::string& strHuman) { static struct { @@ -35,6 +40,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, "tenBAD_PATH", "Malformed: path." }, { tenBAD_PATH_COUNT, "tenBAD_PATH_COUNT", "Malformed: too many paths." }, { tenBAD_PUBLISH, "tenBAD_PUBLISH", "Malformed: bad publish." }, { tenBAD_RIPPLE, "tenBAD_RIPPLE", "Ledger prevents ripple from succeeding." }, @@ -99,12 +105,92 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std return iIndex >= 0; } -// Return how much of uIssuerID's uCurrency IOUs that uAccountID holds. May be negative. +STAmount TransactionEngine::rippleBalance(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) +{ + STAmount saBalance; + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); + + assert(sleRippleState); + if (sleRippleState) + { + saBalance = sleRippleState->getIValueFieldAmount(sfBalance); + if (uToAccountID < uFromAccountID) + saBalance.negate(); + } + + return saBalance; + +} + +STAmount TransactionEngine::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); + } + + return saLimit; + +} + +uint32 TransactionEngine::rippleTransfer(const uint160& uIssuerID) +{ + SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uIssuerID)); + + return sleAccount->getIFieldPresent(sfTransferRate) + ? sleAccount->getIFieldU32(sfTransferRate) + : QUALITY_ONE; +} + +// XXX Might not need this, might store in nodes on calc reverse. +uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) +{ + uint32 uQualityIn; + + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); + + if (sleRippleState) + { + uQualityIn = sleRippleState->getIFieldU32(uToAccountID < uFromAccountID ? sfLowQualityIn : sfHighQualityIn); + } + else + { + assert(false); + uQualityIn = QUALITY_ONE; + } + + return uQualityIn; +} + +uint32 TransactionEngine::rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) +{ + uint32 uQualityOut; + + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); + + if (sleRippleState) + { + uQualityOut = sleRippleState->getIFieldU32(uToAccountID < uFromAccountID ? sfLowQualityOut : sfHighQualityOut); + } + else + { + assert(false); + uQualityOut = QUALITY_ONE; + } + + return uQualityOut; +} + +// Return how much of uIssuerID's uCurrencyID IOUs that uAccountID holds. May be negative. // <-- IOU's uAccountID has of uIssuerID -STAmount TransactionEngine::rippleHolds(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID) +STAmount TransactionEngine::rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID) { STAmount saBalance; - SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uAccountID, uIssuerID, uCurrency)); + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uAccountID, uIssuerID, uCurrencyID)); if (sleRippleState) { @@ -117,12 +203,12 @@ STAmount TransactionEngine::rippleHolds(const uint160& uAccountID, const uint160 return saBalance; } -// <-- saAmount: amount of uCurrency held by uAccountID. May be negative. -STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID) +// <-- saAmount: amount of uCurrencyID held by uAccountID. May be negative. +STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID) { STAmount saAmount; - if (uCurrency.isZero()) + if (uCurrencyID.isZero()) { SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uAccountID)); @@ -132,12 +218,12 @@ STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint16 } else { - saAmount = rippleHolds(uAccountID, uCurrency, uIssuerID); + saAmount = rippleHolds(uAccountID, uCurrencyID, uIssuerID); Log(lsINFO) << "accountHolds: " << saAmount.getFullText() << " : " - << STAmount::createHumanCurrency(uCurrency) + << STAmount::createHumanCurrency(uCurrencyID) << "/" << NewcoinAddress::createHumanAccountID(uIssuerID); } @@ -190,16 +276,11 @@ STAmount TransactionEngine::rippleTransit(const uint160& uSenderID, const uint16 if (uSenderID != uIssuerID && uReceiverID != uIssuerID) { - SLE::pointer sleIssuerAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uIssuerID)); - uint32 uTransitRate; + uint32 uTransitRate = rippleTransfer(uIssuerID); - if (sleIssuerAccount->getIFieldPresent(sfTransferRate)) - uTransitRate = sleIssuerAccount->getIFieldU32(sfTransferRate); - - if (uTransitRate) + if (QUALITY_ONE != uTransitRate) { - - STAmount saTransitRate(uint160(1), uTransitRate, -9); + STAmount saTransitRate(CURRENCY_ONE, uTransitRate, -9); saTransitFee = STAmount::multiply(saAmount, saTransitRate, saAmount.getCurrency()); } @@ -208,6 +289,50 @@ STAmount TransactionEngine::rippleTransit(const uint160& uSenderID, const uint16 return saTransitFee; } +// Direct send w/o fees: redeeming IOUs and/or sending own IOUs. +void TransactionEngine::rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount) +{ + uint160 uIssuerID = saAmount.getIssuer(); + + assert(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. @@ -219,42 +344,7 @@ STAmount TransactionEngine::rippleSend(const uint160& uSenderID, const uint160& if (uSenderID == uIssuerID || uReceiverID == uIssuerID) { // Direct send: redeeming IOUs and/or sending own IOUs. - - bool bFlipped = uSenderID > uReceiverID; - uint256 uIndex = Ledger::getRippleStateIndex(uSenderID, uReceiverID, saAmount.getCurrency()); - SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, uIndex); - - if (!sleRippleState) - { - Log(lsINFO) << "rippleSend: 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); - } + rippleCredit(uSenderID, uReceiverID, saAmount); saActual = saAmount; } @@ -268,8 +358,8 @@ STAmount TransactionEngine::rippleSend(const uint160& uSenderID, const uint160& saActual.setIssuer(uIssuerID); // XXX Make sure this done in + above. - rippleSend(uIssuerID, uReceiverID, saAmount); - rippleSend(uSenderID, uIssuerID, saActual); + rippleCredit(uIssuerID, uReceiverID, saAmount); + rippleCredit(uSenderID, uIssuerID, saActual); } return saActual; @@ -1405,12 +1495,12 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti uint32 uQualityIn = bQualityIn ? txn.getITFieldU32(sfQualityIn) : 0; bool bQualityOut = txn.getITFieldPresent(sfQualityOut); uint32 uQualityOut = bQualityIn ? txn.getITFieldU32(sfQualityOut) : 0; - uint160 uCurrency = saLimitAmount.getCurrency(); - STAmount saBalance(uCurrency); + uint160 uCurrencyID = saLimitAmount.getCurrency(); + STAmount saBalance(uCurrencyID); bool bAddIndex = false; bool bDelIndex = false; - SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrency)); + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); if (sleRippleState) { // A line exists in one or more directions. @@ -1489,10 +1579,10 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti else { // Create a new ripple line. - STAmount saZero(uCurrency); + STAmount saZero(uCurrencyID); bAddIndex = true; - sleRippleState = entryCreate(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrency)); + sleRippleState = entryCreate(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString(); @@ -2024,7 +2114,7 @@ void TransactionEngine::calcNodeOfferReverse( // From the destination work towards the source calculating how much must be asked for. // --> bAllowPartial: If false, fail if can't meet requirements. -// <-- bSuccess: true=success, false=insufficient funds. +// <-- bSuccess: true=success, false=insufficient funds / liqudity. // <-> pnNodes: // --> [end]saWanted.mAmount // --> [all]saWanted.mCurrency @@ -2034,29 +2124,70 @@ void TransactionEngine::calcNodeOfferReverse( // XXX With multiple path and due to offers, must consider consumed. bool TransactionEngine::calcPathReverse(PathState::pointer pspCur) { - bool bSent = true; -#if 0 TransactionEngineResult terResult = tenUNKNOWN; - unsigned int uIndex = pspCur->vpnNodes.size() - 1; + unsigned int uLast = pspCur->vpnNodes.size() - 1; + unsigned int uIndex = pspCur->vpnNodes.size(); - while (bSent && tenUNKNOWN == terResult && uIndex--) + while (tenUNKNOWN == terResult && uIndex--) { - // Calculate (1) sending by fullfilling next wants and (2) setting current wants. + // Calculate: + // (1) saPrvRedeem & saPrvIssue from saCurRevRedeem & saCurRevIssue. + // (2) saCurWanted by summing saRevRedeem & saRevIssue. <-- XXX might not need this as it can be infered. + // XXX We might not need to do 0. - paymentNode& prvPN = uIndex ? pnNodes[uIndex-1] : pnNodes[0]; - paymentNode& curPN = pnNodes[uIndex]; - paymentNode& nxtPN = pnNodes[uIndex+1]; - bool bRedeem = !!(curPN.uFlags & STPathElement::typeRedeem); - bool bIssue = !!(curPN.uFlags & STPathElement::typeIssue); - bool bOffer = !!(curPN.uFlags & STPathElement::typeOffer); + paymentNode& prvPN = uIndex ? pspCur->vpnNodes[uIndex-1] : pspCur->vpnNodes[0]; + paymentNode& curPN = pspCur->vpnNodes[uIndex]; + paymentNode& nxtPN = uIndex == uLast ? pspCur->vpnNodes[uLast] : pspCur->vpnNodes[uIndex+1]; + bool bAccount = !!(curPN.uFlags & STPathElement::typeAccount); + bool bRedeem = !!(curPN.uFlags & STPathElement::typeRedeem); + bool bIssue = !!(curPN.uFlags & STPathElement::typeIssue); + uint160& uPrvAccountID = prvPN.uAccountID; + uint160& uCurAccountID = curPN.uAccountID; + uint160& uNxtAccountID = nxtPN.uAccountID; + uint160& uCurrencyID = curPN.uCurrencyID; - if (curPN.saWanted.isZero()) + if (uIndex == uLast) { - // Must want something. - terResult = tenBAD_AMOUNT; + // saCurWanted set by caller. + uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); + STAmount saPrvBalance = rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID); + STAmount saPrvLimit = rippleLimit(uCurAccountID, uPrvAccountID, uCurAccountID); + + STAmount saPrvRedeemReq = saPrvBalance.isNative() ? -saPrvBalance : STAmount(uCurrencyID, 0); + STAmount& saPrvRedeemAct = prvPN.saRevRedeem; // What previous should redeem with cur. + + STAmount& saPrvIssueAct = prvPN.saRevIssue; + STAmount saPrvIssueReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; + + STAmount saCurWantedReq = pspCur->saOutReq; + STAmount saCurWantedAct; + + // Calculate redeem + if (bRedeem + && saPrvRedeemReq) // Previous has IOUs to redeem. + { + // Redeem at 1:1 + saCurWantedAct = MIN(saPrvRedeemReq, saCurWantedReq); + saPrvRedeemAct = saCurWantedAct; + } + + // Calculate issuing. + if (bIssue + && saCurWantedReq != saCurWantedAct // Need more. + && saPrvIssueReq) // Will accept IOUs. + { + // Rate: quality in : 1.0 + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurWantedReq, saPrvIssueAct, saCurWantedAct); + } + + if (!saCurWantedAct) + { + // Must have processed something. + terResult = tenBAD_AMOUNT; + } } - else if (bOffer) + else if (!bAccount) { // Offer node. // Ripple or transfering from previous node through this offer to next node. @@ -2065,12 +2196,12 @@ bool TransactionEngine::calcPathReverse(PathState::pointer pspCur) // We limit what this node sends by this nodes redeem and issue max. // This allows path lists to be strictly redeem. // XXX Make sure offer book was not previously mentioned. - - uint160 uPrvCurrency = curPN->uFlags & PF_WANTED_CURRENCY +#if 0 + uint160 uPrvCurrency = curPN.uFlags & PF_WANTED_CURRENCY ? curPN->saWanted.getCurrency() : saSendMax.getCurrency(); - uint160 uPrvIssuer = curPN->uFlags & PF_WANTED_ISSUER + uint160 uPrvIssuer = curPN.uFlags & PF_WANTED_ISSUER ? curPN->saWanted.getIssuer() : saSendMax.getIssuer(); @@ -2095,67 +2226,114 @@ bool TransactionEngine::calcPathReverse(PathState::pointer pspCur) // Save sent amount } +#endif } - // Account node. - else if (!bIssue && !bOffer) + // Ripple through account. + else if (!bIssue && !bRedeem) { - terResult = tenBAD_PATH; + // XXX This might be checked sooner. + terResult = tenBAD_PATH; // Must be able to redeem and issue. + } + else if (!uIndex) + { + // Done. No previous. We know what we would like to redeem and issue. + nothing(); } else { // Rippling through this accounts balances. // No currency change. - // Issuer change possible. - // Figuring out want current account should redeem and send. + // Given saCurRedeem & saCurIssue figure out saPrvRedeem & saPrvIssue. - SLE::pointer sleRippleCur = ; - SLE::pointer sleRippleNxt = ; - STAmount saBalance = peekBalance(curPN.uAccountID, nxtPN.uAccountID); - STAmount saLimit = peekLimit(curPN.uAccountID, nxtPN.uAccountID); - STAmount saWanted = nxtPN.saWanted; + uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); + uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); + STAmount saPrvBalance = rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID); + STAmount saPrvLimit = rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID); - curPN.saWanted.zero(); + STAmount saPrvRedeemReq = saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); + STAmount& saPrvRedeemAct = prvPN.saRevRedeem; - if (bRedeem && saBalance.isPositive()) + STAmount saPrvIssueReq = saPrvLimit - saPrvBalance; + STAmount& saPrvIssueAct = prvPN.saRevIssue; + + const STAmount& saCurRedeemReq = curPN.saRevRedeem; + STAmount saCurRedeemAct; + + const STAmount& saCurIssueReq = curPN.saRevIssue; + STAmount saCurIssueAct; // Track progess. + + + // Previous redeem part 1: redeem -> redeem + if (bRedeem + && saCurRedeemReq // Next wants us to redeem. + && saPrvBalance.isNegative()) // Previous has IOUs to redeem. { - // Allowed to redeem and have IOUs. - curPN.saIOURedeem = min(saBalance, saWanted); - curPN.saWanted = curPN.saIOURedeem; // XXX Assumes we want 1::1 - saWanted -= curPN.saIOURedeem; - } - else - { - curPN.saIOURedeem.zero(); + // Rate : 1.0 : quality out + + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); } - if (bIssue // Allowed to issue. - && !saWanted.isZero() // Need to issue. - && !saBalance.isPositive()) // Can issue. (Can't if must redeem). + // Previous redeem part 2: redeem -> issue. + if (bIssue + && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. + && saPrvBalance.isNegative() // Previous still has IOUs. + && saCurIssueReq) // Need some issued. { - curPN.saIOUIssue = min(saLimit+saBalance, saWanted); - curPN.saWanted += curPN.saIOUIssue; // XXX Assumes we want 1::1 - } - else - { - curPN.saIOUIssue.zero(); + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); } - bSent = !curPN.saIOURedeem.isZero() || !curPN.saIOUIssue.isZero(); + // Previous issue part 1: issue -> redeem + if (bRedeem + && saCurRedeemReq != saCurRedeemAct // Can only redeem if more to be redeemed. + && !saPrvBalance.isNegative()) // Previous has no IOUs. + { + // Rate: quality in : quality out + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); + } + + // Previous issue part 2 : issue -> issue + if (bIssue + && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. + && !saPrvBalance.isNegative() // Previous has no IOUs. + && saCurIssueReq != saCurIssueAct) // Need some issued. + { + // Rate: quality in : 1.0 + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); + } + + if (!saCurRedeemAct && !saCurIssueAct) + { + // Must want something. + terResult = tenBAD_AMOUNT; + } } } -#endif - return bSent; + + return tenUNKNOWN == terResult; } // Cur is the driver and will be filled exactly. -void TransactionEngine::calcNodeFwd(const uint32 uQualityIn, const uint32 uQualityOut, - const STAmount& saPrvReq, const STAmount& saCurReq, - STAmount& saPrvAct, STAmount& saCurAct) +// uQualityIn -> uQualityOut +// saPrvReq -> saCurReq +// sqPrvAct -> saCurAct +// This routine works backwards as it calculates previous wants based on previous credit limits and current wants. +// This routine works forwards as it calculates current deliver based on previous delivery limits and current wants. +void TransactionEngine::calcNodeRipple( + const uint32 uQualityIn, + const uint32 uQualityOut, + const STAmount& saPrvReq, // --> in limit including fees + const STAmount& saCurReq, // --> out limit (driver) + STAmount& saPrvAct, // <-> in limit including achieved + STAmount& saCurAct) // <-> out limit achieved. { + STAmount saPrv = saPrvReq-saPrvAct; + STAmount saCur = saCurReq-saCurAct; + if (uQualityIn >= uQualityOut) { // No fee. - STAmount saTransfer = MIN(saPrvReq-saPrvAct, saCurReq-saCurAct); + STAmount saTransfer = MIN(saPrv, saCur); saPrvAct += saTransfer; saCurAct += saTransfer; @@ -2163,9 +2341,7 @@ void TransactionEngine::calcNodeFwd(const uint32 uQualityIn, const uint32 uQuali else { // Fee. - STAmount saPrv = saPrvReq-saPrvAct; - STAmount saCur = saCurReq-saCurAct; - STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityIn, uint160(1)), uQualityOut, uint160(1)); + STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, CURRENCY_ONE), uQualityIn, CURRENCY_ONE); if (saCurIn >= saPrv) { @@ -2175,8 +2351,8 @@ void TransactionEngine::calcNodeFwd(const uint32 uQualityIn, const uint32 uQuali } else { - // A part of cur. All of prv. - STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityOut, uint160(1)), uQualityIn, uint160(1)); + // A part of cur. All of prv. (cur as driver) + STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, CURRENCY_ONE), uQualityOut, CURRENCY_ONE); saCurAct += saCurOut; saPrvAct = saPrvReq; @@ -2191,22 +2367,20 @@ void TransactionEngine::calcNodeFwd(const uint32 uQualityIn, const uint32 uQuali // --> [all]saWanted.IOURedeem // --> [all]saWanted.IOUIssue // --> [all]saAccount -// XXX This path becomes dirty if saSendMaxFirst must be changed. void TransactionEngine::calcPathForward(PathState::pointer pspCur) { -#if 0 - TransactionEngineResult terResult = tenUNKNOWN; unsigned int uIndex = 0; unsigned int uEnd = pspCur->vpnNodes.size(); unsigned int uLast = uEnd - 1; - while (tenUNKNOWN == terResult && uIndex != uEnd) + while (uIndex != uEnd) { // Calculate (1) sending by fullfilling next wants and (2) setting current wants. - paymentNode& prvPN = uIndex ? pnNodes[uIndex-1] : pnNodes[0]; - paymentNode& curPN = pnNodes[uIndex]; + paymentNode& prvPN = uIndex ? pspCur->vpnNodes[uIndex-1] : pspCur->vpnNodes[0]; + paymentNode& curPN = pspCur->vpnNodes[uIndex]; + paymentNode& nxtPN = uIndex == uLast ? pspCur->vpnNodes[uLast] : pspCur->vpnNodes[uIndex+1]; // XXX Assume rippling. @@ -2218,8 +2392,8 @@ void TransactionEngine::calcPathForward(PathState::pointer pspCur) STAmount& saCurIssueReq = curPN.saRevIssue; STAmount& saCurIssueAct = curPN.saFwdIssue; - STAmount& saCurSendMaxReq = curPN.saSendMax; - STAmount saCurSendMaxAct; + STAmount& saCurSendMaxReq = pspCur->saInReq; + STAmount& saCurSendMaxAct = pspCur->saInAct; if (saCurRedeemReq) { @@ -2238,50 +2412,55 @@ void TransactionEngine::calcPathForward(PathState::pointer pspCur) else if (uIndex == uLast) { // Last node. Accept all funds. Calculate amount actually to credit. - uint32 uQualityIn = peekQualityIn(curPN.uAccountID, prvPN.uAccountID); + uint32 uQualityIn = rippleQualityIn(curPN.uAccountID, prvPN.uAccountID, curPN.uCurrencyID); STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; STAmount& saPrvIssueReq = prvPN.saFwdIssue; STAmount saPrvIssueAct = uQualityIn >= QUALITY_ONE - ? saPrvIssueReq // No fee. - : multiply(saPrvIssueReq, uQualityIn, _); // Fee. - STAmount& saCurReceive = curPN.saReceive; + ? saPrvIssueReq // No fee. + : STAmount::multiply(saPrvIssueReq, uQualityIn, curPN.uCurrencyID); // Fee. + STAmount& saCurReceive = pspCur->saOutAct; // Amount to credit. saCurReceive = saPrvRedeemReq+saPrvIssueAct; // Actually receive. - rippleCredit(curPN.uAccountID, prvPN.uAccountID, saPrvRedeemReq + saPrvIssueReq); + rippleCredit(curPN.uAccountID, prvPN.uAccountID, saCurReceive); } else { // Handle middle node. // The previous nodes tells want it wants to push through to current. - // The current node know what it woud push through next. + // The current node know what it would push through next. // Determine for the current node: // - Output to next node minus fees. // Perform balance adjustment with previous. // All of previous output is consumed. - STAmount saSrcRedeem; // To start, redeeming none. - STAmount saSrcIssue; // To start, issuing none. - STAmount saDstRedeem; + uint160& uCurrencyID = curPN.uCurrencyID; - // Have funds in previous node to transfer. - uint32 uQualityIn = peekQualityIn(curPN.uAccountID, prvPN.uAccountID); - uint32 uQualityOut = peekQualityOut(curPN.uAccountID, nxtPN.uAccountID); + uint160& uPrvAccountID = prvPN.uAccountID; + uint160& uCurAccountID = curPN.uAccountID; + uint160& uNxtAccountID = nxtPN.uAccountID; STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; STAmount saPrvRedeemAct; - STAmount& saCurRedeemReq = curPN.saRevRedeem; - STAmount& saCurRedeemAct = curPN.saFwdRedeem; STAmount& saPrvIssueReq = prvPN.saFwdIssue; STAmount saPrvIssueAct; + STAmount& saCurRedeemReq = curPN.saRevRedeem; + STAmount& saCurRedeemAct = curPN.saFwdRedeem; + STAmount& saCurIssueReq = curPN.saRevIssue; + STAmount& saCurIssueAct = curPN.saFwdIssue; + + // Have funds in previous node to transfer. + uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); + uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); + // Previous redeem part 1: redeem -> redeem if (saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. { // Rate : 1.0 : quality out - calcNodeFwd(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); } // Previous redeem part 2: redeem -> issue. @@ -2290,8 +2469,8 @@ void TransactionEngine::calcPathForward(PathState::pointer pspCur) if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem. && saCurRedeemReq == saCurRedeemAct) // Current has more to redeem to next. { - // Rate : 1.0 : 1.0 + transfer_rate - calcNodeFwd(QUALITY_ONE, QUALITY_ONE+peekTransfer(curPN.uAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); } // Previous issue part 1: issue -> redeem @@ -2299,21 +2478,21 @@ void TransactionEngine::calcPathForward(PathState::pointer pspCur) && saCurRedeemReq == saCurRedeemAct) // Current has more to redeem to next. { // Rate: quality in : quality out - calcNodeFwd(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); } // Previous issue part 2 : issue -> issue if (saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. { // Rate: quality in : 1.0 - calcNodeFwd(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); } // Adjust prv --> cur balance : take all inbound - rippleCredit(cur, prv, saPrvRedeemReq + saPrvIssueReq); + // XXX Currency must be in amount. + rippleCredit(uCurAccountID, uPrvAccountID, saPrvRedeemReq + saPrvIssueReq); } } -#endif } bool PathState::less(const PathState::pointer& lhs, const PathState::pointer& rhs) @@ -2324,8 +2503,8 @@ bool PathState::less(const PathState::pointer& lhs, const PathState::pointer& rh 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. + if (lhs->saOutAct != rhs->saOutAct) + return lhs->saOutAct < rhs->saOutAct; // Smaller is worse. // Path index is third rank. return lhs->mIndex > rhs->mIndex; // Bigger is worse. @@ -2345,15 +2524,17 @@ PathState::PathState( { lesEntries = lesSource.duplicate(); + saOutReq = saSend; + saInReq = saSendMax; + paymentNode pnFirst; paymentNode pnLast; - pnLast.bPartialPayment = bPartialPayment; - pnLast.uAccount = uReceiverID; - pnLast.saWanted = saSend; + pnLast.uAccountID = uReceiverID; + pnLast.uCurrencyID = saOutReq.getCurrency(); - pnFirst.uAccount = uSenderID; - pnFirst.saWanted = saSendMax; + pnFirst.uAccountID = uSenderID; + pnFirst.uCurrencyID = saSendMax.getCurrency(); vpnNodes.push_back(pnFirst); vpnNodes.push_back(pnLast); diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 6143468d10..e246895cc0 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -27,6 +27,7 @@ enum TransactionEngineResult tenBAD_GEN_AUTH, tenBAD_ISSUER, tenBAD_OFFER, + tenBAD_PATH, tenBAD_PATH_COUNT, tenBAD_PUBLISH, tenBAD_SET_ID, @@ -100,24 +101,19 @@ enum TransactionEngineParams }; typedef struct { - bool bPartialPayment; // --> uint16 uFlags; // --> from path - uint160 uAccount; // --> recieving/sending account + uint160 uAccountID; // --> recieving/sending account + uint160 uCurrencyID; // --> currency to recieve - STAmount saSendMax; // --> First node: most to send. - STAmount saRecieve; // <-- Last node: Value received (minus fees) from upstream. + // Computed by Reverse. + STAmount saRevRedeem; // <-- Amount to redeem to next. + STAmount saRevIssue; // <-- Amount to issue to next limited by credit and outstanding IOUs. + // ? STAmount saSend; // <-- Stamps this node will send downstream. - STAmount saRevRedeem; // <-- Computed amount node needs at most redeem. - STAmount saRevIssue; // <-- Computed amount node ____ - STAmount saCurRedeem; // <-- Amount node will redeem to next. - STAmount saCurIssue; // <-- Amount node will issue to next. - - STAmount saWanted; // <-- What this node wants from upstream. - - STAmount saSend; // <-- Stamps this node will send downstream. - - STAmount saXNSRecieve; // Amount stamps to receive. + // Computed by forward. + STAmount saFwdRedeem; // <-- Amount node will redeem to next. + STAmount saFwdIssue; // <-- Amount node will issue to next. } paymentNode; // Hold a path state under incremental application. @@ -132,8 +128,10 @@ public: int mIndex; uint64 uQuality; // 0 = none. - STAmount saIn; - STAmount saOut; + 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). bool bDirty; // Path not computed. PathState( @@ -204,39 +202,46 @@ private: STAmount& saTakerGot); protected: - Ledger::pointer mLedger; - uint64 mLedgerParentCloseTime; + Ledger::pointer mLedger; + uint64 mLedgerParentCloseTime; - uint160 mTxnAccountID; - SLE::pointer mTxnAccount; + uint160 mTxnAccountID; + SLE::pointer mTxnAccount; boost::unordered_set mUnfunded; // Indexes that were found unfunded. - SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex); - SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex); - void entryDelete(SLE::pointer sleEntry, bool unfunded = false); - void entryModify(SLE::pointer sleEntry); + SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex); + SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex); + void entryDelete(SLE::pointer sleEntry, bool unfunded = false); + void entryModify(SLE::pointer sleEntry); - void entryReset(); + void entryReset(); - STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID); - STAmount rippleTransit(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount); - STAmount rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); + uint32 rippleTransfer(const uint160& uIssuerID); + STAmount rippleBalance(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); + uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); - STAmount accountHolds(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID); - STAmount accountSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); - STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault); + STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID); + STAmount rippleTransit(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount); + void rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); + STAmount rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); + + STAmount accountHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID); + 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 calcNodeFwd(const uint32 uQualityIn, const uint32 uQualityOut, + void calcNodeRipple(const uint32 uQualityIn, const uint32 uQualityOut, const STAmount& saPrvReq, const STAmount& saCurReq, STAmount& saPrvAct, STAmount& saCurAct); bool calcPathReverse(PathState::pointer pspCur); void calcPathForward(PathState::pointer pspCur); - void txnWrite(); + void txnWrite(); TransactionEngineResult offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID); From 1a6a6231cc040c8ee372156530796aff80830ac0 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 3 Aug 2012 14:57:52 -0700 Subject: [PATCH 005/426] Add path expansion to transaction engine. --- src/SerializedTypes.cpp | 4 +- src/SerializedTypes.h | 2 +- src/TransactionEngine.cpp | 97 +++++++++++++++++++++++++++++++++++---- src/TransactionEngine.h | 12 +++-- 4 files changed, 98 insertions(+), 17 deletions(-) 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; From f80b884e8131c51f42324a78d6147fab79b411d5 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 7 Aug 2012 01:30:39 -0700 Subject: [PATCH 006/426] Fix a consensus close time bug. --- src/LedgerConsensus.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 3b0d9b41e9..6902ab6599 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -872,13 +872,15 @@ void LedgerConsensus::accept(SHAMap::pointer set) applyTransactions(set, newLCL, newLCL, failedTransactions, true); newLCL->setClosed(); - uint32 closeTime = mOurPosition->getCloseTime(); + uint32 closeTime = mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() & mCloseResolution); bool closeTimeCorrect = true; if (closeTime == 0) - { // we didn't agree + { // we agreed to disagree closeTimeCorrect = false; closeTime = mPreviousLedger->getCloseTimeNC() + 1; + Log(lsINFO) << "Consensus close time (good) " << closeTime; } + else Log(lsINFO) << "Consensus close time (bad) " << closeTime; newLCL->setAccepted(closeTime, mCloseResolution, closeTimeCorrect); newLCL->updateHash(); From 03e8104f6249dc8a50dd46af3df55ec66cb9e1d7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 7 Aug 2012 01:39:34 -0700 Subject: [PATCH 007/426] Small close time consensus fix. --- src/LedgerConsensus.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 6902ab6599..0d53af7b83 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -527,7 +527,15 @@ void LedgerConsensus::updateOurPositions() neededWeight = AV_MID_CONSENSUS_PCT; else neededWeight = AV_LATE_CONSENSUS_PCT; + uint32 closeTime = 0; + mHaveCloseTimeConsensus = false; + int thresh = mPeerPositions.size(); + if (thresh == 0) + { // no other times + mHaveCloseTimeConsensus = true; + closeTime = mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution); + } if (mProposing) { ++closeTimes[mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)]; @@ -535,8 +543,6 @@ void LedgerConsensus::updateOurPositions() } thresh = thresh * neededWeight / 100; - uint32 closeTime = 0; - mHaveCloseTimeConsensus = false; for (std::map::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it) { Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << " out of " << thresh; From 86b9597ddd61404f475f954036dd9f78f7bc16d2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 7 Aug 2012 03:32:58 -0700 Subject: [PATCH 008/426] Reduce log chattiness. Acquire transaction and state trees in parallel. --- src/HashedObject.cpp | 1 - src/LedgerAcquire.cpp | 60 ++++++++++++++--------------------------- src/LedgerConsensus.cpp | 15 +++++------ src/SNTPClient.cpp | 24 +++++++++++------ 4 files changed, 43 insertions(+), 57 deletions(-) diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp index 8c9ef0ac7c..9dc7e6e92c 100644 --- a/src/HashedObject.cpp +++ b/src/HashedObject.cpp @@ -37,7 +37,6 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index, t.detach(); } } - Log(lsTRACE) << "HOS: " << hash.GetHex() << " store: deferred"; return true; } diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 16cc1abe4f..bc065606ef 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -147,27 +147,22 @@ void LedgerAcquire::trigger(Peer::pointer peer) #ifdef LA_DEBUG if(peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex() << " from " << peer->getIP(); else Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex(); - Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed; - Log(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState; + if (mComplete || mFailed) + Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed; + else + Log(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState; #endif if (!mHaveBase) { -#ifdef LA_DEBUG - Log(lsTRACE) << "need base"; -#endif newcoin::TMGetLedger tmGL; tmGL.set_ledgerhash(mHash.begin(), mHash.size()); tmGL.set_itype(newcoin::liBASE); *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); - if (peer) - { - sendRequest(tmGL, peer); - return; - } - else sendRequest(tmGL); + sendRequest(tmGL, peer); + return; // Cannot go on without base } - if (mHaveBase && !mHaveTransactions) + if (!mHaveTransactions) { #ifdef LA_DEBUG Log(lsTRACE) << "need tx"; @@ -180,12 +175,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) tmGL.set_ledgerseq(mLedger->getLedgerSeq()); tmGL.set_itype(newcoin::liTX_NODE); *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); - if (peer) - { - sendRequest(tmGL, peer); - return; - } - sendRequest(tmGL); + sendRequest(tmGL, peer); } else { @@ -199,7 +189,8 @@ void LedgerAcquire::trigger(Peer::pointer peer) else { mHaveTransactions = true; - if (mHaveState) mComplete = true; + if (mHaveState) + mComplete = true; } } else @@ -210,17 +201,12 @@ void LedgerAcquire::trigger(Peer::pointer peer) tmGL.set_itype(newcoin::liTX_NODE); for (std::vector::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it) *(tmGL.add_nodeids()) = it->getRawString(); - if (peer) - { - sendRequest(tmGL, peer); - return; - } - sendRequest(tmGL); + sendRequest(tmGL, peer); } } } - if (mHaveBase && !mHaveState) + if (!mHaveState) { #ifdef LA_DEBUG Log(lsTRACE) << "need as"; @@ -233,12 +219,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) tmGL.set_ledgerseq(mLedger->getLedgerSeq()); tmGL.set_itype(newcoin::liAS_NODE); *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); - if (peer) - { - sendRequest(tmGL, peer); - return; - } - sendRequest(tmGL); + sendRequest(tmGL, peer); } else { @@ -252,7 +233,8 @@ void LedgerAcquire::trigger(Peer::pointer peer) else { mHaveState = true; - if (mHaveTransactions) mComplete = true; + if (mHaveTransactions) + mComplete = true; } } else @@ -263,12 +245,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) tmGL.set_itype(newcoin::liAS_NODE); for (std::vector::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it) *(tmGL.add_nodeids()) = it->getRawString(); - if (peer) - { - sendRequest(tmGL, peer); - return; - } - sendRequest(tmGL); + sendRequest(tmGL, peer); } } } @@ -281,7 +258,10 @@ void LedgerAcquire::trigger(Peer::pointer peer) void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL, Peer::pointer peer) { - peer->sendPacket(boost::make_shared(tmGL, newcoin::mtGET_LEDGER)); + if (!peer) + sendRequest(tmGL); + else + peer->sendPacket(boost::make_shared(tmGL, newcoin::mtGET_LEDGER)); } void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 0d53af7b83..440be88eeb 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -427,9 +427,10 @@ void LedgerConsensus::stateEstablish() updateOurPositions(); if (!mHaveCloseTimeConsensus) { - Log(lsINFO) << "No close time consensus"; + if (haveConsensus()) + Log(lsINFO) << "We have TX consensus but not CT consensus"; } - else if (haveConsensus()) + if (haveConsensus()) { Log(lsINFO) << "Converge cutoff"; mState = lcsFINISHED; @@ -455,11 +456,10 @@ void LedgerConsensus::timerEntry() if (!mHaveCorrectLCL) { checkLCL(); - Log(lsINFO) << "Checking for consensus ledger " << mPrevLedgerHash.GetHex(); Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(mPrevLedgerHash); if (consensus) { - Log(lsINFO) << "We have acquired the consensus ledger"; + Log(lsINFO) << "Acquired the consensus ledger " << mPrevLedgerHash.GetHex(); if (theApp->getMasterLedger().getClosedLedger()->getHash() != mPrevLedgerHash) theApp->getOPs().switchLastClosedLedger(consensus, true); mPreviousLedger = consensus; @@ -468,7 +468,8 @@ void LedgerConsensus::timerEntry() mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(), mPreviousLedger->getLedgerSeq() + 1); } - else Log(lsINFO) << "We still don't have it"; + else + Log(lsINFO) << "Need consensus ledger " << mPrevLedgerHash.GetHex(); } mCurrentMSeconds = (mCloseTime == 0) ? 0 : @@ -487,7 +488,6 @@ void LedgerConsensus::timerEntry() void LedgerConsensus::updateOurPositions() { - Log(lsINFO) << "Updating our positions"; bool changes = false; SHAMap::pointer ourPosition; std::vector addedTx, removedTx; @@ -566,8 +566,7 @@ void LedgerConsensus::updateOurPositions() mOurPosition->changePosition(newHash, closeTime); if (mProposing) propose(addedTx, removedTx); mapComplete(newHash, ourPosition, false); - Log(lsINFO) << "We change our position to " << newHash.GetHex(); - Log(lsINFO) << " Close time " << closeTime; + Log(lsINFO) << "Position change: CTime " << closeTime << ", tx " << newHash.GetHex(); } } diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index d84cfa3c57..ffd2eecbe9 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -8,6 +8,8 @@ #include "utils.h" #include "Log.h" +// #define SNTP_DEBUG + static uint8_t SNTPQueryData[48] = { 0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @@ -86,21 +88,24 @@ void SNTPClient::receivePacket(const boost::system::error_code& error, std::size if (!error) { boost::mutex::scoped_lock sl(mLock); +#ifdef SNTP_DEBUG Log(lsTRACE) << "SNTP: Packet from " << mReceiveEndpoint; +#endif std::map::iterator query = mQueries.find(mReceiveEndpoint); if (query == mQueries.end()) - Log(lsDEBUG) << "SNTP: Reply found without matching query"; + Log(lsDEBUG) << "SNTP: Reply from " << mReceiveEndpoint << " found without matching query"; else if (query->second.mReceivedReply) - Log(lsDEBUG) << "SNTP: Duplicate response to query"; + Log(lsDEBUG) << "SNTP: Duplicate response from " << mReceiveEndpoint; else { query->second.mReceivedReply = true; if (time(NULL) > (query->second.mLocalTimeSent + 1)) - Log(lsWARNING) << "SNTP: Late response"; + Log(lsWARNING) << "SNTP: Late response from " << mReceiveEndpoint; else if (bytes_xferd < 48) - Log(lsWARNING) << "SNTP: Short reply (" << bytes_xferd << ") " << mReceiveBuffer.size(); + Log(lsWARNING) << "SNTP: Short reply from " << mReceiveEndpoint + << " (" << bytes_xferd << ") " << mReceiveBuffer.size(); else if (reinterpret_cast(&mReceiveBuffer[0])[NTP_OFF_ORGTS_FRAC] != query->second.mQueryNonce) - Log(lsWARNING) << "SNTP: Reply had wrong nonce"; + Log(lsWARNING) << "SNTP: Reply from " << mReceiveEndpoint << "had wrong nonce"; else processReply(); } @@ -128,12 +133,12 @@ void SNTPClient::processReply() if ((info >> 30) == 3) { - Log(lsINFO) << "SNTP: Alarm condition"; + Log(lsINFO) << "SNTP: Alarm condition " << mReceiveEndpoint; return; } if ((stratum == 0) || (stratum > 14)) { - Log(lsINFO) << "SNTP: Unreasonable stratum"; + Log(lsINFO) << "SNTP: Unreasonable stratum (" << stratum << ") from " << mReceiveEndpoint; return; } @@ -161,7 +166,8 @@ void SNTPClient::processReply() if ((mOffset == -1) || (mOffset == 1)) // small corrections likely do more harm than good mOffset = 0; - Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset; + if (timev || mOffset) + Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset; } void SNTPClient::timerEntry(const boost::system::error_code& error) @@ -234,6 +240,8 @@ bool SNTPClient::doQuery() mResolver.async_resolve(query, boost::bind(&SNTPClient::resolveComplete, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); +#ifdef SNTP_DEBUG Log(lsTRACE) << "SNTP: Resolve pending for " << best->first; +#endif return true; } From b4e63c30254769b4da03480a4e27acced7ab5fd1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 7 Aug 2012 04:11:20 -0700 Subject: [PATCH 009/426] Fix a few cases where we reset the acquire timer when we should not. --- src/LedgerAcquire.cpp | 19 +++++++++---------- src/LedgerAcquire.h | 4 ++-- src/LedgerConsensus.cpp | 6 +++--- src/LedgerConsensus.h | 6 +++--- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index bc065606ef..95c4d287e4 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -102,7 +102,7 @@ void LedgerAcquire::onTimer() setFailed(); done(); } - else trigger(Peer::pointer()); + else trigger(Peer::pointer(), true); } boost::weak_ptr LedgerAcquire::pmDowncast() @@ -140,7 +140,7 @@ void LedgerAcquire::addOnComplete(boost::function mLock.unlock(); } -void LedgerAcquire::trigger(Peer::pointer peer) +void LedgerAcquire::trigger(Peer::pointer peer, bool timer) { if (mAborted || mComplete || mFailed) return; @@ -159,10 +159,9 @@ void LedgerAcquire::trigger(Peer::pointer peer) tmGL.set_itype(newcoin::liBASE); *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); sendRequest(tmGL, peer); - return; // Cannot go on without base } - if (!mHaveTransactions) + if (mHaveBase && !mHaveTransactions) { #ifdef LA_DEBUG Log(lsTRACE) << "need tx"; @@ -206,7 +205,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) } } - if (!mHaveState) + if (mHaveBase && !mHaveState) { #ifdef LA_DEBUG Log(lsTRACE) << "need as"; @@ -252,7 +251,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) if (mComplete || mFailed) done(); - else + else if (timer) resetTimer(); } @@ -460,7 +459,7 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi return false; if (packet.nodes_size() == 1) { - ledger->trigger(peer); + ledger->trigger(peer, false); return true; } if (!ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata()))) @@ -469,12 +468,12 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi } if (packet.nodes().size() == 2) { - ledger->trigger(peer); + ledger->trigger(peer, false); return true; } if (!ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata()))) Log(lsWARNING) << "Invcluded TXbase invalid"; - ledger->trigger(peer); + ledger->trigger(peer, false); return true; } @@ -498,7 +497,7 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi else ret = ledger->takeAsNode(nodeIDs, nodeData); if (ret) - ledger->trigger(peer); + ledger->trigger(peer, false); return ret; } diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index fbcac6c7e3..1497ca41ad 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -72,7 +72,7 @@ protected: void done(); void onTimer(); - void newPeer(Peer::pointer peer) { trigger(peer); } + void newPeer(Peer::pointer peer) { trigger(peer, false); } boost::weak_ptr pmDowncast(); @@ -92,7 +92,7 @@ public: bool takeTxRootNode(const std::vector& data); bool takeAsNode(const std::list& IDs, const std::list >& data); bool takeAsRootNode(const std::vector& data); - void trigger(Peer::pointer); + void trigger(Peer::pointer, bool timer); }; class LedgerAcquireMaster diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 440be88eeb..2549ecfb85 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -36,7 +36,7 @@ boost::weak_ptr TransactionAcquire::pmDowncast() return boost::shared_polymorphic_downcast(shared_from_this()); } -void TransactionAcquire::trigger(Peer::pointer peer) +void TransactionAcquire::trigger(Peer::pointer peer, bool timer) { if (mComplete || mFailed) return; @@ -76,7 +76,7 @@ void TransactionAcquire::trigger(Peer::pointer peer) } if (mComplete || mFailed) done(); - else + else if (timer) resetTimer(); } @@ -110,7 +110,7 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, ++nodeIDit; ++nodeDatait; } - trigger(peer); + trigger(peer, false); progress(); return true; } diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 205a75cd1a..7e104a43b7 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -27,11 +27,11 @@ protected: SHAMap::pointer mMap; bool mHaveRoot; - void onTimer() { trigger(Peer::pointer()); } - void newPeer(Peer::pointer peer) { trigger(peer); } + void onTimer() { trigger(Peer::pointer(), true); } + void newPeer(Peer::pointer peer) { trigger(peer, false); } void done(); - void trigger(Peer::pointer); + void trigger(Peer::pointer, bool timer); boost::weak_ptr pmDowncast(); public: From 8e89335e2bd5d001127905fde87051347057c373 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 7 Aug 2012 19:52:09 -0700 Subject: [PATCH 010/426] Cleanups to the sha map node format code. --- src/LedgerAcquire.cpp | 14 ++++++++------ src/LedgerConsensus.cpp | 2 +- src/Peer.cpp | 8 ++++---- src/SHAMap.cpp | 4 ++-- src/SHAMap.h | 19 +++++++++++-------- src/SHAMapNodes.cpp | 20 ++++++++++---------- src/SHAMapSync.cpp | 20 ++++++++++---------- 7 files changed, 46 insertions(+), 41 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 95c4d287e4..525096872e 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -311,8 +311,10 @@ bool LedgerAcquire::takeBase(const std::string& data) theApp->getHashedObjectStore().store(LEDGER, mLedger->getLedgerSeq(), s.peekData(), mHash); progress(); - if (!mLedger->getTransHash()) mHaveTransactions = true; - if (!mLedger->getAccountHash()) mHaveState = true; + if (!mLedger->getTransHash()) + mHaveTransactions = true; + if (!mLedger->getAccountHash()) + mHaveState = true; mLedger->setAcquiring(); return true; } @@ -328,7 +330,7 @@ bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, { if (nodeIDit->isRoot()) { - if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, STN_ARF_WIRE)) + if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, snfWIRE)) return false; } else if (!mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter)) @@ -363,7 +365,7 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, { if (nodeIDit->isRoot()) { - if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), *nodeDatait, STN_ARF_WIRE)) + if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), *nodeDatait, snfWIRE)) return false; } else if (!mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter)) @@ -387,13 +389,13 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, bool LedgerAcquire::takeAsRootNode(const std::vector& data) { if (!mHaveBase) return false; - return mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, STN_ARF_WIRE); + return mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, snfWIRE); } bool LedgerAcquire::takeTxRootNode(const std::vector& data) { if (!mHaveBase) return false; - return mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, STN_ARF_WIRE); + return mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, snfWIRE); } LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 2549ecfb85..7a194d8d7d 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -101,7 +101,7 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, Log(lsWARNING) << "Got root TXS node, already have it"; return false; } - if (!mMap->addRootNode(getHash(), *nodeDatait, STN_ARF_WIRE)) + if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE)) return false; else mHaveRoot = true; } diff --git a/src/Peer.cpp b/src/Peer.cpp index 7c822dd229..991d18456b 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -1007,13 +1007,13 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) reply.add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength()); if (packet.nodeids().size() != 0) - { + { // new-style root request Log(lsINFO) << "Ledger root w/map roots request"; SHAMap::pointer map = ledger->peekAccountStateMap(); if (map) - { + { // return account state root node if possible Serializer rootNode(768); - if (map->getRootNode(rootNode, STN_ARF_WIRE)) + if (map->getRootNode(rootNode, snfWIRE)) { reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength()); if (ledger->getTransHash().isNonZero()) @@ -1022,7 +1022,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) if (map) { rootNode.resize(0); - if (map->getRootNode(rootNode, STN_ARF_WIRE)) + if (map->getRootNode(rootNode, snfWIRE)) reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength()); } } diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 738d1858ef..1221ed336d 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -641,7 +641,7 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui try { - SHAMapTreeNode::pointer ret = boost::make_shared(id, obj->getData(), mSeq, STN_ARF_PREFIXED); + SHAMapTreeNode::pointer ret = boost::make_shared(id, obj->getData(), mSeq, snfPREFIX); #ifdef DEBUG assert((ret->getNodeHash() == hash) && (id == *ret)); #endif @@ -672,7 +672,7 @@ int SHAMap::flushDirty(int maxNodes, HashedObjectType t, uint32 seq) while (it != dirtyNodes.end()) { s.erase(); - it->second->addRaw(s, STN_ARF_PREFIXED); + it->second->addRaw(s, snfPREFIX); theApp->getHashedObjectStore().store(t, seq, s.peekData(), s.getSHA512Half()); if (flushed++ >= maxNodes) return flushed; diff --git a/src/SHAMap.h b/src/SHAMap.h index 0130a624d7..4bfd7999db 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -122,6 +122,12 @@ public: virtual void dump(); }; +enum SHANodeFormat +{ + snfPREFIX = 1, // Form that hashes to its official hash + snfWIRE = 2, // Compressed form used on the wire +}; + class SHAMapTreeNode : public SHAMapNode { friend class SHAMap; @@ -156,12 +162,9 @@ public: SHAMapTreeNode(const SHAMapTreeNode& node, uint32 seq); // copy node from older tree SHAMapTreeNode(const SHAMapNode& nodeID, SHAMapItem::pointer item, TNType type, uint32 seq); -#define STN_ARF_PREFIXED 1 -#define STN_ARF_WIRE 2 - // raw node functions - SHAMapTreeNode(const SHAMapNode& id, const std::vector& contents, uint32 seq, int format); - void addRaw(Serializer &, int format); + SHAMapTreeNode(const SHAMapNode& id, const std::vector& data, uint32 seq, SHANodeFormat format); + void addRaw(Serializer &, SHANodeFormat format); virtual bool isPopulated() const { return true; } @@ -325,9 +328,9 @@ public: SHAMapSyncFilter* filter); bool getNodeFat(const SHAMapNode& node, std::vector& nodeIDs, std::list >& rawNode, bool fatLeaves); - bool getRootNode(Serializer& s, int format); - bool addRootNode(const uint256& hash, const std::vector& rootNode, int format); - bool addRootNode(const std::vector& rootNode, int format); + bool getRootNode(Serializer& s, SHANodeFormat format); + bool addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format); + bool addRootNode(const std::vector& rootNode, SHANodeFormat format); bool addKnownNode(const SHAMapNode& nodeID, const std::vector& rawNode, SHAMapSyncFilter* filter); diff --git a/src/SHAMapNodes.cpp b/src/SHAMapNodes.cpp index 95fdcb1f9d..da4ef4ebfb 100644 --- a/src/SHAMapNodes.cpp +++ b/src/SHAMapNodes.cpp @@ -189,10 +189,10 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, SHAMapItem::pointer item, updateHash(); } -SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector& rawNode, uint32 seq, int format) - : SHAMapNode(id), mSeq(seq), mType(tnERROR), mFullBelow(false) +SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector& rawNode, uint32 seq, + SHANodeFormat format) : SHAMapNode(id), mSeq(seq), mType(tnERROR), mFullBelow(false) { - if (format == STN_ARF_WIRE) + if (format == snfWIRE) { Serializer s(rawNode); int type = s.removeLastByte(); @@ -256,7 +256,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vectoraddRaw(s); @@ -400,7 +400,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format) } else if (mType == tnTRANSACTION_NM) { - if (format == STN_ARF_PREFIXED) + if (format == snfPREFIX) { s.add32(sHP_TransactionID); mItem->addRaw(s); @@ -413,7 +413,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format) } else if (mType == tnTRANSACTION_MD) { - if (format == STN_ARF_PREFIXED) + if (format == snfPREFIX) { s.add32(sHP_TransactionNode); mItem->addRaw(s); diff --git a/src/SHAMapSync.cpp b/src/SHAMapSync.cpp index ab230c79fb..25c2d019a0 100644 --- a/src/SHAMapSync.cpp +++ b/src/SHAMapSync.cpp @@ -58,7 +58,7 @@ void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vector nodeData; if (filter->haveNode(childID, childHash, nodeData)) { - d = boost::make_shared(childID, nodeData, mSeq, STN_ARF_PREFIXED); + d = boost::make_shared(childID, nodeData, mSeq, snfPREFIX); if (childHash != d->getNodeHash()) { Log(lsERROR) << "Wrong hash from cached object"; @@ -99,7 +99,7 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector& nodeI nodeIDs.push_back(*node); Serializer s; - node->addRaw(s, STN_ARF_WIRE); + node->addRaw(s, snfWIRE); rawNodes.push_back(s.peekData()); if (node->isRoot() || node->isLeaf()) // don't get a fat root, can't get a fat leaf @@ -114,7 +114,7 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector& nodeI { nodeIDs.push_back(*nextNode); Serializer s; - nextNode->addRaw(s, STN_ARF_WIRE); + nextNode->addRaw(s, snfWIRE); rawNodes.push_back(s.peekData()); } } @@ -122,14 +122,14 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector& nodeI return true; } -bool SHAMap::getRootNode(Serializer& s, int format) +bool SHAMap::getRootNode(Serializer& s, SHANodeFormat format) { boost::recursive_mutex::scoped_lock sl(mLock); root->addRaw(s, format); return true; } -bool SHAMap::addRootNode(const std::vector& rootNode, int format) +bool SHAMap::addRootNode(const std::vector& rootNode, SHANodeFormat format) { boost::recursive_mutex::scoped_lock sl(mLock); @@ -160,7 +160,7 @@ bool SHAMap::addRootNode(const std::vector& rootNode, int format) return true; } -bool SHAMap::addRootNode(const uint256& hash, const std::vector& rootNode, int format) +bool SHAMap::addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format) { boost::recursive_mutex::scoped_lock sl(mLock); @@ -236,14 +236,14 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vectorgetChildHash(branch); if (!hash) return false; - SHAMapTreeNode::pointer newNode = boost::make_shared(node, rawNode, mSeq, STN_ARF_WIRE); + SHAMapTreeNode::pointer newNode = boost::make_shared(node, rawNode, mSeq, snfWIRE); if (hash != newNode->getNodeHash()) // these aren't the droids we're looking for return false; if (filter) { Serializer s; - newNode->addRaw(s, STN_ARF_PREFIXED); + newNode->addRaw(s, snfPREFIX); filter->gotNode(node, hash, s.peekData(), newNode->isLeaf()); } @@ -399,7 +399,7 @@ std::list > SHAMap::getTrustedPath(const uint256& ind Serializer s; while (!stack.empty()) { - stack.top()->addRaw(s, STN_ARF_WIRE); + stack.top()->addRaw(s, snfWIRE); path.push_back(s.getData()); s.erase(); stack.pop(); @@ -454,7 +454,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) Log(lsFATAL) << "Didn't get root node " << gotNodes.size(); BOOST_FAIL("NodeSize"); } - if (!destination.addRootNode(*gotNodes.begin(), STN_ARF_WIRE)) + if (!destination.addRootNode(*gotNodes.begin(), snfWIRE)) { Log(lsFATAL) << "AddRootNode fails"; BOOST_FAIL("AddRootNode"); From 9fc4f469b817063f7d61e432c2d1ea6ae05f4628 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 8 Aug 2012 01:35:34 -0700 Subject: [PATCH 011/426] Add STAmount::isNonZero --- src/SerializedTypes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 9a1c34b3f8..cb719d2c15 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -290,6 +290,7 @@ public: bool isNative() const { return mIsNative; } bool isZero() const { return mValue == 0; } + bool isNonZero() const { return mValue != 0; } bool isNegative() const { return mIsNegative && !isZero(); } bool isPositive() const { return !mIsNegative && !isZero(); } bool isGEZero() const { return !mIsNegative; } From 3a4762c60985da6f5492ce562a811da0991c041c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 8 Aug 2012 01:35:44 -0700 Subject: [PATCH 012/426] Don't try to calculate close time offsets if a ledger closed due to being idle. --- src/LedgerConsensus.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 7a194d8d7d..1a9eda60d2 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -937,7 +937,8 @@ void LedgerConsensus::accept(SHAMap::pointer set) mState = lcsACCEPTED; sl.unlock(); - { + if (mValidating && mOurPosition->getCurrentHash().isNonZero()) + { // see how close our close time is to other node's close time reports Log(lsINFO) << "We closed at " << boost::lexical_cast(mCloseTime); uint64 closeTotal = mCloseTime; int closeCount = 1; From 7fd327ee38ea197c74b3506c759b0c51ead44172 Mon Sep 17 00:00:00 2001 From: jed Date: Wed, 8 Aug 2012 10:22:54 -0700 Subject: [PATCH 013/426] compile on windows --- newcoin.vcxproj | 5 +---- newcoin.vcxproj.filters | 7 +++---- src/LedgerAcquire.cpp | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/newcoin.vcxproj b/newcoin.vcxproj index c053c90f59..d6c37b34c1 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -146,6 +146,7 @@ + @@ -248,17 +249,13 @@ Designer - - - Document ..\protoc-2.4.1-win32\protoc -I=..\newcoin\src --cpp_out=..\newcoin\obj\src ..\newcoin\src\newcoin.proto obj\src\newcoin.pb.h - diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index b8c3acee1e..2116e89379 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -273,6 +273,9 @@ Source Files + + Source Files + @@ -506,16 +509,12 @@ - html - - - diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 525096872e..2407616bd6 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -129,7 +129,7 @@ void LedgerAcquire::done() if (mLedger) theApp->getMasterLedger().storeLedger(mLedger); - for (int i = 0; i < triggers.size(); ++i) + for (unsigned int i = 0; i < triggers.size(); ++i) triggers[i](shared_from_this()); } From 9991c9532feb772b32224c246b87727f27cb6588 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 8 Aug 2012 13:56:31 -0700 Subject: [PATCH 014/426] Not sure why I put this in, but it's wrong. --- src/LedgerTiming.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index e3ea061640..c28fc80e02 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -101,7 +101,6 @@ bool ContinuousLedgerTiming::haveConsensus( int ContinuousLedgerTiming::getNextLedgerTimeResolution(int previousResolution, bool previousAgree, int ledgerSeq) { assert(ledgerSeq); - assert(previousAgree); // TEMPORARY if ((!previousAgree) && ((ledgerSeq % LEDGER_RES_DECREASE) == 0)) { // reduce resolution int i = 1; From be17a3866ff8abfa070cbed1fd755c75a8edaa33 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 8 Aug 2012 14:22:03 -0700 Subject: [PATCH 015/426] Fix the race condition bug Jed reported. A time jump on startup could cause an apparently overly-long (or even negative) ledger interval. The fix is to start up time synch earlier and to tolerate slight negative ledger intervals. --- src/Application.cpp | 10 ++++++++-- src/Application.h | 2 +- src/LedgerTiming.cpp | 10 ++-------- src/SNTPClient.cpp | 2 ++ 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 89fe9d2ddc..daac98dd54 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -38,7 +38,7 @@ DatabaseCon::~DatabaseCon() Application::Application() : mUNL(mIOService), mNetOps(mIOService, &mMasterLedger), mTempNodeCache(16384, 90), mHashedObjectStore(16384, 300), - mSNTPClient(mIOService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), + mSNTPClient(mAuxService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL) { @@ -51,6 +51,7 @@ extern int RpcDBCount, TxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount void Application::stop() { + mAuxService.stop(); mIOService.stop(); mHashedObjectStore.bulkWrite(); mValidations.flush(); @@ -69,6 +70,11 @@ void Application::run() if (!theConfig.DEBUG_LOGFILE.empty()) Log::setLogFile(theConfig.DEBUG_LOGFILE); + mSNTPClient.init(theConfig.SNTP_SERVERS); + + boost::thread auxThread(boost::bind(&boost::asio::io_service::run, &mAuxService)); + auxThread.detach(); + // // Construct databases. // @@ -91,6 +97,7 @@ void Application::run() // getUNL().nodeBootstrap(); + // // Allow peer connections. // @@ -147,7 +154,6 @@ void Application::run() mNetOps.setLastCloseNetTime(secondLedger->getCloseTimeNC()); } - mSNTPClient.init(theConfig.SNTP_SERVERS); mNetOps.setStateTimer(); diff --git a/src/Application.h b/src/Application.h index 9efbc89fc1..79ffb8cf34 100644 --- a/src/Application.h +++ b/src/Application.h @@ -39,7 +39,7 @@ public: class Application { - boost::asio::io_service mIOService; + boost::asio::io_service mIOService, mAuxService; Wallet mWallet; UniqueNodeList mUNL; diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index c28fc80e02..0585abd47a 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -19,8 +19,8 @@ int ContinuousLedgerTiming::shouldClose( int previousMSeconds, // seconds the previous ledger took to reach consensus int currentMSeconds) // seconds since the previous ledger closed { - assert((previousMSeconds > 0) && (previousMSeconds < 600000)); - assert((currentMSeconds >= 0) && (currentMSeconds < 600000)); + assert((previousMSeconds > -1000) && (previousMSeconds < 600000)); + assert((currentMSeconds >= -1000) && (currentMSeconds < 600000)); #if 0 Log(lsTRACE) << boost::str(boost::format("CLC::shouldClose Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") % @@ -44,12 +44,6 @@ int ContinuousLedgerTiming::shouldClose( return LEDGER_IDLE_INTERVAL * 1000; // normal idle } - if (previousMSeconds == (1000 * LEDGER_IDLE_INTERVAL)) // coming out of idle, close now - { - Log(lsTRACE) << "leaving idle, close now"; - return currentMSeconds; - } - Log(lsTRACE) << "close now"; return currentMSeconds; // this ledger should close now } diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index ffd2eecbe9..728e6f4129 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -166,7 +166,9 @@ void SNTPClient::processReply() if ((mOffset == -1) || (mOffset == 1)) // small corrections likely do more harm than good mOffset = 0; +#ifndef SNTP_DEBUG if (timev || mOffset) +#endif Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset; } From 4e99d8d7bdb7c2acf5be7d4b0ce012df27a50dc4 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 8 Aug 2012 23:08:24 -0700 Subject: [PATCH 016/426] Cleanups. --- src/SNTPClient.cpp | 16 ++++++++-------- src/SNTPClient.h | 4 ---- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index 728e6f4129..e5cafd46e1 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -10,14 +10,15 @@ // #define SNTP_DEBUG -static uint8_t SNTPQueryData[48] = { - 0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -}; +static uint8_t SNTPQueryData[48] = +{ 0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; // NTP query frequency - 5 minutes #define NTP_QUERY_FREQUENCY (5 * 60) +// NTP minimum interval to query same servers - 3 minutes +#define NTP_MIN_QUERY (3 * 60) + // NTP sample window (should be odd) #define NTP_SAMPLE_WINDOW 9 @@ -39,8 +40,7 @@ static uint8_t SNTPQueryData[48] = { #define NTP_OFF_XMITTS_FRAC 11 -SNTPClient::SNTPClient(boost::asio::io_service& service) : - mIOService(service), mSocket(service), mTimer(service), mResolver(service), +SNTPClient::SNTPClient(boost::asio::io_service& service) : mSocket(service), mTimer(service), mResolver(service), mOffset(0), mLastOffsetUpdate((time_t) -1), mReceiveBuffer(256) { mSocket.open(boost::asio::ip::udp::v4()); @@ -67,7 +67,7 @@ void SNTPClient::resolveComplete(const boost::system::error_code& error, boost:: SNTPQuery& query = mQueries[*sel]; time_t now = time(NULL); if ((query.mLocalTimeSent == now) || ((query.mLocalTimeSent + 1) == now)) - { + { // This can happen if the same IP address is reached through multiple names Log(lsTRACE) << "SNTP: Redundant query suppressed"; return; } @@ -231,7 +231,7 @@ bool SNTPClient::doQuery() return false; } time_t now = time(NULL); - if ((best->second == now) || (best->second == (now - 1))) + if ((best->second != (time_t) -1) && ((best->second + NTP_MIN_QUERY) >= now)) { Log(lsTRACE) << "SNTP: All servers recently queried"; return false; diff --git a/src/SNTPClient.h b/src/SNTPClient.h index ea7b0e7c8a..51adf3ceb2 100644 --- a/src/SNTPClient.h +++ b/src/SNTPClient.h @@ -21,14 +21,10 @@ public: class SNTPClient { -public: - typedef boost::shared_ptr pointer; - protected: std::map mQueries; boost::mutex mLock; - boost::asio::io_service& mIOService; boost::asio::ip::udp::socket mSocket; boost::asio::deadline_timer mTimer; boost::asio::ip::udp::resolver mResolver; From 1aa15c62e10951e15c3ff9bdb5911a5874eed5be Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 9 Aug 2012 16:03:00 -0700 Subject: [PATCH 017/426] Implement STAmount::getRate. --- src/Amount.cpp | 32 +++++++++++++++++++++++--------- src/SerializedTypes.h | 1 + 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 7d95eeffca..4ada7054cc 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -446,7 +446,7 @@ bool STAmount::operator==(const STAmount& a) const bool STAmount::operator!=(const STAmount& a) const { - return (mOffset != a.mOffset) || (mValue != a.mValue) || (mIsNegative!= a.mIsNegative) || !isComparable(a); + return (mOffset != a.mOffset) || (mValue != a.mValue) || (mIsNegative != a.mIsNegative) || !isComparable(a); } bool STAmount::operator<(const STAmount& a) const @@ -762,6 +762,14 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn) return (ret << (64 - 8)) | r.getMantissa(); } +STAmount STAmount::setRate(uint64 rate, const uint160& currencyOut) +{ + uint64 mantissa = rate & ~(255ull << (64 - 8)); + int exponent = static_cast(rate >> (64 - 8)) - 100; + + return STAmount(currencyOut, mantissa, exponent); +} + // Taker gets all taker can pay for with saTakerFunds, limited by saOfferPays and saOfferFunds. // --> saOfferFunds: Limit for saOfferPays // --> saTakerFunds: Limit for saOfferGets : How much taker really wants. : Driver @@ -1105,6 +1113,12 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test ) if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), uint160()).getText() != "20") BOOST_FAIL("STAmount divide fail"); + STAmount a1(currency, 60), a2 (currency, 10, -1); + if(STAmount::divide(a2, a1, currency) != STAmount::setRate(STAmount::getRate(a1, a2), currency)) + BOOST_FAIL("STAmount setRate(getRate) fail"); + if(STAmount::divide(a1, a2, currency) != STAmount::setRate(STAmount::getRate(a2, a1), currency)) + BOOST_FAIL("STAmount setRate(getRate) fail"); + BOOST_TEST_MESSAGE("Amount CC Complete"); } @@ -1115,21 +1129,21 @@ BOOST_AUTO_TEST_CASE( CurrencyMulDivTests ) uint160 c(1); if (STAmount::getRate(STAmount(1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(c, 1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(c, 10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(c, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(c, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index cb719d2c15..0db5658393 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -343,6 +343,7 @@ public: // Someone is offering X for Y, what is the rate? static uint64 getRate(const STAmount& offerOut, const STAmount& offerIn); + static STAmount setRate(uint64 rate, const uint160& currencyOut); // Someone is offering X for Y, I try to pay Z, how much do I get? // And what's left of the offer? And how much do I actually pay? From d477172f65514a21f8e896e095657b718d6ea0b2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 9 Aug 2012 19:20:53 -0700 Subject: [PATCH 018/426] Cleanups and whitespace fixes. --- src/Amount.cpp | 4 +-- src/LedgerConsensus.cpp | 17 +++++------ src/PubKeyCache.cpp | 1 - src/SHAMap.cpp | 66 ++++++++++++++++++++++------------------- src/SHAMapNodes.cpp | 36 +++++++++++----------- src/SNTPClient.cpp | 2 +- src/SerializedTypes.h | 2 +- src/TransactionMeta.cpp | 2 +- 8 files changed, 66 insertions(+), 64 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 4ada7054cc..1e2db3124c 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -1114,9 +1114,9 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test ) BOOST_FAIL("STAmount divide fail"); STAmount a1(currency, 60), a2 (currency, 10, -1); - if(STAmount::divide(a2, a1, currency) != STAmount::setRate(STAmount::getRate(a1, a2), currency)) + if (STAmount::divide(a2, a1, currency) != STAmount::setRate(STAmount::getRate(a1, a2), currency)) BOOST_FAIL("STAmount setRate(getRate) fail"); - if(STAmount::divide(a1, a2, currency) != STAmount::setRate(STAmount::getRate(a2, a1), currency)) + if (STAmount::divide(a1, a2, currency) != STAmount::setRate(STAmount::getRate(a2, a1), currency)) BOOST_FAIL("STAmount setRate(getRate) fail"); BOOST_TEST_MESSAGE("Amount CC Complete"); diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 1a9eda60d2..b9bd543450 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -146,7 +146,7 @@ void LCTransaction::setVote(const uint160& peer, bool votesYes) ++mYays; res.first->second = true; } - else if(!votesYes && res.first->second) + else if (!votesYes && res.first->second) { // changes vote to no Log(lsTRACE) << "Peer " << peer.GetHex() << " now votes NO on " << mTransactionID.GetHex(); ++mNays; @@ -270,7 +270,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) // if any peers have taken a contrary position, process disputes boost::unordered_set found; - for(boost::unordered_map::iterator it = mPeerPositions.begin(), + for (boost::unordered_map::iterator it = mPeerPositions.begin(), end = mPeerPositions.end(); it != end; ++it) { uint256 set = it->second->getCurrentHash(); @@ -296,14 +296,14 @@ void LedgerConsensus::createDisputes(SHAMap::pointer m1, SHAMap::pointer m2) { SHAMap::SHAMapDiff differences; m1->compare(m2, differences, 16384); - for(SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos) + for (SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos) { // create disputed transactions (from the ledger that has them) if (pos->second.first) { assert(!pos->second.second); addDisputedTransaction(pos->first, pos->second.first->peekData()); } - else if(pos->second.second) + else if (pos->second.second) { assert(!pos->second.first); addDisputedTransaction(pos->first, pos->second.second->peekData()); @@ -371,7 +371,7 @@ void LedgerConsensus::adjustCount(SHAMap::pointer map, const std::vectorhasItem(it->second->getTransactionID()); - for(std::vector::const_iterator pit = peers.begin(), pend = peers.end(); pit != pend; ++pit) + for (std::vector::const_iterator pit = peers.begin(), pend = peers.end(); pit != pend; ++pit) it->second->setVote(*pit, setHas); } } @@ -492,7 +492,7 @@ void LedgerConsensus::updateOurPositions() SHAMap::pointer ourPosition; std::vector addedTx, removedTx; - for(boost::unordered_map::iterator it = mDisputes.begin(), + for (boost::unordered_map::iterator it = mDisputes.begin(), end = mDisputes.end(); it != end; ++it) { if (it->second->updatePosition(mClosePercent, mProposing)) @@ -942,7 +942,7 @@ void LedgerConsensus::accept(SHAMap::pointer set) Log(lsINFO) << "We closed at " << boost::lexical_cast(mCloseTime); uint64 closeTotal = mCloseTime; int closeCount = 1; - for(std::map::iterator it = mCloseTimes.begin(), end = mCloseTimes.end(); it != end; ++it) + for (std::map::iterator it = mCloseTimes.begin(), end = mCloseTimes.end(); it != end; ++it) { Log(lsINFO) << boost::lexical_cast(it->second) << " time votes for " << boost::lexical_cast(it->first); @@ -956,9 +956,8 @@ void LedgerConsensus::accept(SHAMap::pointer set) } #ifdef DEBUG - Json::StyledStreamWriter ssw; - if (1) { + Json::StyledStreamWriter ssw; Log(lsTRACE) << "newLCL"; Json::Value p; newLCL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE); diff --git a/src/PubKeyCache.cpp b/src/PubKeyCache.cpp index 0119969544..f6a4096d38 100644 --- a/src/PubKeyCache.cpp +++ b/src/PubKeyCache.cpp @@ -6,7 +6,6 @@ CKey::pointer PubKeyCache::locate(const NewcoinAddress& id) { - if(1) { // is it in cache boost::mutex::scoped_lock sl(mLock); std::map::iterator it(mCache.find(id)); diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 1221ed336d..b360908f2d 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -262,7 +262,7 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node) break; } if (!foundNode) return SHAMapItem::pointer(); - } while (1); + } while (true); } SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node) @@ -284,7 +284,7 @@ SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node) break; } if (!foundNode) return SHAMapItem::pointer(); - } while (1); + } while (true); } SHAMapItem::pointer SHAMap::onlyBelow(SHAMapTreeNode* node) @@ -359,22 +359,23 @@ SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id) boost::recursive_mutex::scoped_lock sl(mLock); std::stack stack = getStack(id, true, false); - while(!stack.empty()) + while (!stack.empty()) { SHAMapTreeNode::pointer node = stack.top(); stack.pop(); - if(node->isLeaf()) + if (node->isLeaf()) { - if(node->peekItem()->getTag()>id) + if (node->peekItem()->getTag() > id) return node->peekItem(); } - else for(int i = node->selectBranch(id) + 1; i < 16; ++i) - if(!node->isEmptyBranch(i)) + else for (int i = node->selectBranch(id) + 1; i < 16; ++i) + if (!node->isEmptyBranch(i)) { node = getNode(node->getChildNodeID(i), node->getChildHash(i), false); SHAMapItem::pointer item = firstBelow(node.get()); - if (!item) throw std::runtime_error("missing node"); + if (!item) + throw std::runtime_error("missing node"); return item; } } @@ -392,17 +393,18 @@ SHAMapItem::pointer SHAMap::peekPrevItem(const uint256& id) SHAMapTreeNode::pointer node = stack.top(); stack.pop(); - if(node->isLeaf()) + if (node->isLeaf()) { - if(node->peekItem()->getTag()peekItem()->getTag() < id) return node->peekItem(); } - else for(int i = node->selectBranch(id) - 1; i >= 0; --i) - if(!node->isEmptyBranch(i)) + else for (int i = node->selectBranch(id) - 1; i >= 0; --i) + if (!node->isEmptyBranch(i)) { node = getNode(node->getChildNodeID(i), node->getChildHash(i), false); SHAMapItem::pointer item = firstBelow(node.get()); - if (!item) throw std::runtime_error("missing node"); + if (!item) + throw std::runtime_error("missing node"); return item; } } @@ -414,7 +416,8 @@ SHAMapItem::pointer SHAMap::peekItem(const uint256& id) { boost::recursive_mutex::scoped_lock sl(mLock); SHAMapTreeNode* leaf = walkToPointer(id); - if (!leaf) return SHAMapItem::pointer(); + if (!leaf) + return SHAMapItem::pointer(); return leaf->peekItem(); } @@ -432,7 +435,7 @@ bool SHAMap::delItem(const uint256& id) assert(mState != Immutable); std::stack stack = getStack(id, true, false); - if(stack.empty()) + if (stack.empty()) throw std::runtime_error("missing node"); SHAMapTreeNode::pointer leaf=stack.top(); @@ -442,7 +445,7 @@ bool SHAMap::delItem(const uint256& id) SHAMapTreeNode::TNType type=leaf->getType(); returnNode(leaf, true); - if(mTNByID.erase(*leaf)==0) + if (mTNByID.erase(*leaf) == 0) assert(false); uint256 prevHash; @@ -460,8 +463,8 @@ bool SHAMap::delItem(const uint256& id) } if (!node->isRoot()) { // we may have made this a node with 1 or 0 children - int bc=node->getBranchCount(); - if(bc==0) + int bc = node->getBranchCount(); + if (bc == 0) { #ifdef DEBUG std::cerr << "delItem makes empty node" << std::endl; @@ -470,10 +473,10 @@ bool SHAMap::delItem(const uint256& id) if (!mTNByID.erase(*node)) assert(false); } - else if(bc==1) + else if (bc == 1) { // pull up on the thread SHAMapItem::pointer item = onlyBelow(node.get()); - if(item) + if (item) { eraseChildren(node); #ifdef ST_DEBUG @@ -521,7 +524,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM uint256 prevHash; returnNode(node, true); - if(node->isInner()) + if (node->isInner()) { // easy case, we end on an inner node #ifdef ST_DEBUG std::cerr << "aGI inner " << node->getString() << std::endl; @@ -530,7 +533,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM assert(node->isEmptyBranch(branch)); SHAMapTreeNode::pointer newNode = boost::make_shared(node->getChildNodeID(branch), item, type, mSeq); - if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) + if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) { std::cerr << "Node: " << node->getString() << std::endl; std::cerr << "NewNode: " << newNode->getString() << std::endl; @@ -562,7 +565,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM SHAMapTreeNode::pointer newNode = boost::make_shared(mSeq, node->getChildNodeID(b1)); newNode->makeInner(); - if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) + if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) assert(false); stack.push(node); node = newNode; @@ -579,7 +582,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM newNode = boost::make_shared(node->getChildNodeID(b2), otherItem, type, mSeq); assert(newNode->isValid() && newNode->isLeaf()); - if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) + if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) assert(false); node->setChildHash(b2, newNode->getNodeHash()); } @@ -635,7 +638,7 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui throw SHAMapMissingNode(id, hash); HashedObject::pointer obj(theApp->getHashedObjectStore().retrieve(hash)); - if(!obj) + if (!obj) throw SHAMapMissingNode(id, hash); assert(Serializer::getSHA512Half(obj->getData()) == hash); @@ -665,7 +668,7 @@ int SHAMap::flushDirty(int maxNodes, HashedObjectType t, uint32 seq) int flushed = 0; Serializer s; - if(mDirtyNodes) + if (mDirtyNodes) { boost::unordered_map& dirtyNodes = *mDirtyNodes; boost::unordered_map::iterator it = dirtyNodes.begin(); @@ -714,10 +717,10 @@ void SHAMap::dump(bool hash) #if 0 std::cerr << "SHAMap::dump" << std::endl; SHAMapItem::pointer i=peekFirstItem(); - while(i) + while (i) { std::cerr << "Item: id=" << i->getTag().GetHex() << std::endl; - i=peekNextItem(i->getTag()); + i = peekNextItem(i->getTag()); } std::cerr << "SHAMap::dump done" << std::endl; #endif @@ -728,7 +731,8 @@ void SHAMap::dump(bool hash) it != mTNByID.end(); ++it) { std::cerr << it->second->getString() << std::endl; - if(hash) std::cerr << " " << it->second->getNodeHash().GetHex() << std::endl; + if (hash) + std::cerr << " " << it->second->getNodeHash().GetHex() << std::endl; } } @@ -756,8 +760,8 @@ BOOST_AUTO_TEST_CASE( SHAMap_test ) SHAMap sMap; SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)), i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5)); - if(!sMap.addItem(i2, true, false)) BOOST_FAIL("no add"); - if(!sMap.addItem(i1, true, false)) BOOST_FAIL("no add"); + if (!sMap.addItem(i2, true, false)) BOOST_FAIL("no add"); + if (!sMap.addItem(i1, true, false)) BOOST_FAIL("no add"); SHAMapItem::pointer i; diff --git a/src/SHAMapNodes.cpp b/src/SHAMapNodes.cpp index da4ef4ebfb..689745995c 100644 --- a/src/SHAMapNodes.cpp +++ b/src/SHAMapNodes.cpp @@ -27,50 +27,50 @@ uint256 SHAMapNode::smMasks[65]; bool SHAMapNode::operator<(const SHAMapNode &s) const { - if(s.mDepthmDepth) return false; - return mNodeID mDepth) return false; + return mNodeID < s.mNodeID; } bool SHAMapNode::operator>(const SHAMapNode &s) const { - if(s.mDepthmDepth) return true; - return mNodeID>s.mNodeID; + if (s.mDepth < mDepth) return false; + if (s.mDepth > mDepth) return true; + return mNodeID > s.mNodeID; } bool SHAMapNode::operator<=(const SHAMapNode &s) const { - if(s.mDepthmDepth) return false; - return mNodeID<=s.mNodeID; + if (s.mDepth < mDepth) return true; + if (s.mDepth > mDepth) return false; + return mNodeID <= s.mNodeID; } bool SHAMapNode::operator>=(const SHAMapNode &s) const { - if(s.mDepthmDepth) return true; - return mNodeID>=s.mNodeID; + if (s.mDepth < mDepth) return false; + if (s.mDepth > mDepth) return true; + return mNodeID >= s.mNodeID; } bool SHAMapNode::operator==(const SHAMapNode &s) const { - return (s.mDepth==mDepth) && (s.mNodeID==mNodeID); + return (s.mDepth == mDepth) && (s.mNodeID == mNodeID); } bool SHAMapNode::operator!=(const SHAMapNode &s) const { - return (s.mDepth!=mDepth) || (s.mNodeID!=mNodeID); + return (s.mDepth != mDepth) || (s.mNodeID != mNodeID); } bool SHAMapNode::operator==(const uint256 &s) const { - return s==mNodeID; + return s == mNodeID; } bool SHAMapNode::operator!=(const uint256 &s) const { - return s!=mNodeID; + return s != mNodeID; } static bool j = SHAMapNode::ClassInit(); @@ -78,7 +78,7 @@ static bool j = SHAMapNode::ClassInit(); bool SHAMapNode::ClassInit() { // set up the depth masks uint256 selector; - for(int i = 0; i < 64; i += 2) + for (int i = 0; i < 64; i += 2) { smMasks[i] = selector; *(selector.begin() + (i / 2)) = 0xF0; @@ -476,7 +476,7 @@ std::string SHAMapTreeNode::getString() const ret += ")"; if (isInner()) { - for(int i = 0; i < 16; ++i) + for (int i = 0; i < 16; ++i) if (!isEmptyBranch(i)) { ret += "\nb"; diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index e5cafd46e1..444b7b6c73 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -204,7 +204,7 @@ void SNTPClient::init(const std::vector& servers) void SNTPClient::queryAll() { - while(doQuery()) + while (doQuery()) nothing(); } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 0db5658393..6372ec66c3 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -655,7 +655,7 @@ public: int getLength() const; SerializedTypeID getSType() const { return STI_TL; } std::string getText() const; - void add(Serializer& s) const { if(s.addTaggedList(value)<0) throw(0); } + void add(Serializer& s) const { if (s.addTaggedList(value) < 0) throw(0); } const std::vector& peekValue() const { return value; } std::vector& peekValue() { return value; } diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index 0476b94200..0ab28f391e 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -205,7 +205,7 @@ TransactionMetaSet::TransactionMetaSet(uint32 ledger, const std::vector Date: Thu, 9 Aug 2012 19:21:08 -0700 Subject: [PATCH 019/426] More LedgerEntrySet code. Retrieve as Json. Finalize before serializing. --- src/LedgerEntrySet.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++ src/LedgerEntrySet.h | 3 +++ 2 files changed, 63 insertions(+) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index fb4903ff4c..cf2e0234bb 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -189,4 +189,64 @@ void LedgerEntrySet::entryDelete(SLE::pointer& sle, bool unfunded) } } +Json::Value LedgerEntrySet::getJson(int) const +{ + Json::Value ret(Json::objectValue); + + Json::Value nodes(Json::arrayValue); + for (boost::unordered_map::const_iterator it = mEntries.begin(), + end = mEntries.end(); it != end; ++it) + { + Json::Value entry(Json::objectValue); + entry["node"] = it->first.GetHex(); + switch (it->second.mEntry->getType()) + { + case ltINVALID: entry["type"] = "invalid"; break; + case ltACCOUNT_ROOT: entry["type"] = "acccount_root"; break; + case ltDIR_NODE: entry["type"] = "dir_node"; break; + case ltGENERATOR_MAP: entry["type"] = "generator_map"; break; + case ltRIPPLE_STATE: entry["type"] = "ripple_state"; break; + case ltNICKNAME: entry["type"] = "nickname"; break; + case ltOFFER: entry["type"] = "offer"; break; + default: assert(false); + } + switch (it->second.mAction) + { + case taaCACHED: entry["action"] = "cache"; break; + case taaMODIFY: entry["action"] = "modify"; break; + case taaDELETE: entry["action"] = "delete"; break; + case taaCREATE: entry["action"] = "create"; break; + default: assert(false); + } + nodes.append(entry); + } + ret["nodes" ] = nodes; + + return ret; +} + +void LedgerEntrySet::addRawMeta(Serializer& s) +{ + for (boost::unordered_map::const_iterator it = mEntries.begin(), + end = mEntries.end(); it != end; ++it) + { + switch (it->second.mAction) + { + case taaMODIFY: + // WRITEME + break; + case taaDELETE: + // WRITEME + break; + case taaCREATE: + // WRITEME + break; + default: + // ignore these + break; + } + } + mSet.addRaw(s); +} + // vim:ts=4 diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index e600060f33..11843f060c 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -58,6 +58,9 @@ public: void entryDelete(SLE::pointer&, bool unfunded); void entryModify(SLE::pointer&); // This entry will be modified + Json::Value getJson(int) const; + void addRawMeta(Serializer&); + // iterator functions bool isEmpty() const { return mEntries.empty(); } boost::unordered_map::const_iterator begin() const { return mEntries.begin(); } From 5b431ea4f629a702a0bb145f023c043357fc24b5 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 10 Aug 2012 10:51:35 -0700 Subject: [PATCH 020/426] Fix the bug Jed reported where our second closed ledger has a close time in the past which crashes the CLC timing code. --- src/Ledger.cpp | 2 +- src/LedgerTiming.cpp | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index e94c6dc5b1..131e7d3b91 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -71,7 +71,7 @@ Ledger::Ledger(bool dummy, Ledger& prevLedger) : prevLedger.getCloseAgree(), mLedgerSeq); if (prevLedger.mCloseTime == 0) { - mCloseTime = theApp->getOPs().getCloseTimeNC(); + mCloseTime = theApp->getOPs().getCloseTimeNC() - mCloseResolution; mCloseTime -= (mCloseTime % mCloseResolution); } else diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index 0585abd47a..ecff1f441a 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -19,13 +19,15 @@ int ContinuousLedgerTiming::shouldClose( int previousMSeconds, // seconds the previous ledger took to reach consensus int currentMSeconds) // seconds since the previous ledger closed { - assert((previousMSeconds > -1000) && (previousMSeconds < 600000)); - assert((currentMSeconds >= -1000) && (currentMSeconds < 600000)); - -#if 0 - Log(lsTRACE) << boost::str(boost::format("CLC::shouldClose Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") % - (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentMSeconds % previousMSeconds); -#endif + if ((previousMSeconds < -1000) || (previousMSeconds > 600000) || + (currentMSeconds < -1000) || (currentMSeconds > 600000)) + { + Log(lsFATAL) << + boost::str(boost::format("CLC::shouldClose range error Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") + % (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed + % currentMSeconds % previousMSeconds); + return currentMSeconds; + } if (!anyTransactions) { // no transactions so far this interval From 622066f7e362992324b3a6bbddc3a59f14ac9840 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 10 Aug 2012 12:58:59 -0700 Subject: [PATCH 021/426] Work towards ripple backend. --- src/TransactionEngine.cpp | 1361 +++++++++++++++++++++++-------------- src/TransactionEngine.h | 18 +- 2 files changed, 881 insertions(+), 498 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index f2b4575b99..0f22432f14 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -22,10 +22,12 @@ #define RIPPLE_PATHS_MAX 3 #define QUALITY_ONE 100000000 // 10e9 +#define CURRENCY_XNS uint160(0) #define CURRENCY_ONE uint160(1) // Used as a place holder +#define ACCOUNT_XNS uint160(0) #define ACCOUNT_ONE uint160(1) // Used as a place holder -// static STAmount saOne(CURRENCY_ONE, 1, 0); +static STAmount saOne(CURRENCY_ONE, 1, 0); bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std::string& strHuman) { @@ -271,7 +273,7 @@ STAmount TransactionEngine::accountFunds(const uint160& uAccountID, const STAmou } // Calculate transit fee. -STAmount TransactionEngine::rippleTransit(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount) +STAmount TransactionEngine::rippleTransfer(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount) { STAmount saTransitFee; @@ -353,7 +355,7 @@ STAmount TransactionEngine::rippleSend(const uint160& uSenderID, const uint160& { // Sending 3rd party IOUs: transit. - STAmount saTransitFee = rippleTransit(uSenderID, uReceiverID, uIssuerID, saAmount); + STAmount saTransitFee = rippleTransfer(uSenderID, uReceiverID, uIssuerID, saAmount); saActual = saTransitFee.isZero() ? saAmount : saAmount+saTransitFee; @@ -684,10 +686,11 @@ TransactionEngineResult TransactionEngine::dirDelete( return terSUCCESS; } +// Return the first entry and advance uDirEntry. // <-- true, if had a next entry. bool TransactionEngine::dirFirst( const uint256& uRootIndex, // --> Root of directory. - SLE::pointer& sleNode, // <-> current node + SLE::pointer& sleNode, // <-- current node unsigned int& uDirEntry, // <-- next entry uint256& uEntryIndex) // <-- The entry, if available. Otherwise, zero. { @@ -699,6 +702,7 @@ bool TransactionEngine::dirFirst( return TransactionEngine::dirNext(uRootIndex, sleNode, uDirEntry, uEntryIndex); } +// Return the current entry and advance uDirEntry. // <-- true, if had a next entry. bool TransactionEngine::dirNext( const uint256& uRootIndex, // --> Root of directory @@ -1712,7 +1716,7 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac return terResult; } -#ifdef WORK_IN_PROGRESS +#if 0 // XXX Need to adjust for fees. // Find offers to satisfy pnDst. // - Does not adjust any balances as there is at least a forward pass to come. @@ -1748,8 +1752,7 @@ TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bo else { // Ripple funds. - { - prv->saSend = min(prv->account->saBalance(), cur->saWanted); + // Redeem to limit. terResult = calcOfferFill( accountHolds(pnSrc.saAccount, pnDst.saWanted.getCurrency(), pnDst.saWanted.getIssuer()), @@ -1778,7 +1781,9 @@ TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bo return terResult; } +#endif +#if 0 // Get the next offer limited by funding. // - Stop when becomes unfunded. void TransactionEngine::calcOfferBridgeNext( @@ -1859,7 +1864,7 @@ void TransactionEngine::calcOfferBridgeNext( // Offer fully funded. // Account transfering funds in to offer always pays inbound fees. - // + saOfferIn = saOfferGets; // XXX Add in fees? saOfferOut = saOfferPays; @@ -1886,15 +1891,413 @@ void TransactionEngine::calcOfferBridgeNext( } while (bNext); } +#endif +// <-- bSuccess: false= no transfer +bool TransactionEngine::calcNodeOfferRev( + unsigned int uIndex, // 0 < uIndex < uLast-1 + PathState::pointer pspCur, + bool bMultiQuality + ) +{ + bool bSuccess = false; + + paymentNode& prvPN = pspCur->vpnNodes[uIndex-1]; + paymentNode& curPN = pspCur->vpnNodes[uIndex]; + paymentNode& nxtPN = pspCur->vpnNodes[uIndex+1]; + + uint160& uPrvCurrencyID = prvPN.uCurrencyID; + uint160& uPrvIssuerID = prvPN.uIssuerID; + uint160& uCurCurrencyID = curPN.uCurrencyID; + uint160& uCurIssuerID = curPN.uIssuerID; + uint160& uNxtCurrencyID = nxtPN.uCurrencyID; + uint160& uNxtIssuerID = nxtPN.uIssuerID; + uint160& uNxtAccountID = nxtPN.uAccountID; + + STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransfer(uCurIssuerID), -9); + + uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); + uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); + bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); + + STAmount& saPrvDlvReq = prvPN.saRevDeliver; + STAmount saPrvDlvAct; + + STAmount& saCurDlvReq = curPN.saRevDeliver; // Reverse driver. + STAmount saCurDlvAct; + + while (!!uDirectTip // Have a quality. + && saCurDlvAct != saCurDlvReq) + { + // Get next quality. + if (bAdvance) + { + uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd); + } + else + { + bAdvance = true; + } + + if (!!uDirectTip) + { + // Do a directory. + // - Drive on computing saCurDlvAct to derive saPrvDlvAct. + SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); + STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio + unsigned int uEntry = 0; + uint256 uCurIndex; + + while (saCurDlvReq != saCurDlvAct // Have not met request. + && dirNext(uDirectTip, sleDirectDir, uEntry, uCurIndex)) + { + SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex); + uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); + STAmount saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); + STAmount saCurOfrIn = sleCurOfr->getIValueFieldAmount(sfTakerPays); + // XXX Move issuer into STAmount + if (sleCurOfr->getIFieldPresent(sfGetsIssuer)) + saCurOfrOutReq.setIssuer(sleCurOfr->getIValueFieldAccount(sfGetsIssuer).getAccountID()); + + if (sleCurOfr->getIFieldPresent(sfPaysIssuer)) + saCurOfrIn.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID()); + + STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. + + // XXX Offer is also unfunded if funding source previously mentioned. + if (!saCurOfrFunds) + { + // Offer is unfunded. + Log(lsINFO) << "calcNodeOffer: encountered unfunded offer"; + + // XXX Mark unfunded. + } + else if (sleCurOfr->getIFieldPresent(sfExpiration) && sleCurOfr->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + { + // Offer is expired. + Log(lsINFO) << "calcNodeOffer: encountered expired offer"; + + // XXX Mark unfunded. + } + else if (!!uNxtAccountID) + { + // Next is an account. + + STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtAccountID == uCurIssuerID + ? saOne + : saTransferRate; + bool bFee = saFeeRate != saOne; + + STAmount saOutBase = MIN(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed. + STAmount saOutCost = MIN( + bFee + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + : saOutBase, + saCurOfrFunds); // Limit cost by fees & funds. + STAmount saOutDlvAct = bFee + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + : saOutCost; // Out amount after fees. + STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required. + + saCurDlvAct += saOutDlvAct; // Portion of driver served. + saPrvDlvAct += saInDlvAct; // Portion needed in previous. + } + else + { + // Next is an offer. + + uint256 uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); + uint256 uNxtEnd = Ledger::getQualityNext(uNxtTip); + bool bNxtAdvance = !entryCache(ltDIR_NODE, uNxtTip); + + while (!!uNxtTip // Have a quality. + && saCurDlvAct != saCurDlvReq) // Have more to do. + { + if (bNxtAdvance) + { + uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd); + } + else + { + bNxtAdvance = true; + } + + if (!!uNxtTip) + { + // Do a directory. + // - Drive on computing saCurDlvAct to derive saPrvDlvAct. + SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); +// ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip)); // For correct ratio + unsigned int uEntry = 0; + uint256 uNxtIndex; + + while (saCurDlvReq != saCurDlvAct // Have not met request. + && dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex)) + { + // YYY This could combine offers with the same fee before doing math. + SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex); + uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); + STAmount saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); + // XXX Move issuer into STAmount + if (sleNxtOfr->getIFieldPresent(sfPaysIssuer)) + saNxtOfrIn.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID()); + + STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID + ? saOne + : saTransferRate; + bool bFee = saFeeRate != saOne; + + STAmount saOutBase = MIN(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed. + saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. + STAmount saOutCost = MIN( + bFee + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + : saOutBase, + saCurOfrFunds); // Limit cost by fees & funds. + STAmount saOutDlvAct = bFee + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + : saOutCost; // Out amount after fees. + STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required. + + saCurDlvAct += saOutDlvAct; // Portion of driver served. + saPrvDlvAct += saInDlvAct; // Portion needed in previous. + } + } + + // Do another nxt directory iff bMultiQuality + if (!bMultiQuality) + uNxtTip = 0; + } + } + } + } + + // Do another cur directory iff bMultiQuality + if (!bMultiQuality) + uDirectTip = 0; + } + + if (saPrvDlvAct) + { + saPrvDlvReq = saPrvDlvAct; // Adjust request. + bSuccess = true; + } + + return bSuccess; +} + +bool TransactionEngine::calcNodeOfferFwd( + unsigned int uIndex, // 0 < uIndex < uLast-1 + PathState::pointer pspCur, + bool bMultiQuality + ) +{ + bool bSuccess = false; + + paymentNode& prvPN = pspCur->vpnNodes[uIndex-1]; + paymentNode& curPN = pspCur->vpnNodes[uIndex]; + paymentNode& nxtPN = pspCur->vpnNodes[uIndex+1]; + + uint160& uPrvCurrencyID = prvPN.uCurrencyID; + uint160& uPrvIssuerID = prvPN.uIssuerID; + uint160& uCurCurrencyID = curPN.uCurrencyID; + uint160& uCurIssuerID = curPN.uIssuerID; + uint160& uNxtCurrencyID = nxtPN.uCurrencyID; + uint160& uNxtIssuerID = nxtPN.uIssuerID; + + uint160& uNxtAccountID = nxtPN.uAccountID; + STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransfer(uCurIssuerID), -9); + + uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); + uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); + bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); + + STAmount& saPrvDlvReq = prvPN.saFwdDeliver; // Forward driver. + STAmount saPrvDlvAct; + + STAmount& saCurDlvReq = curPN.saFwdDeliver; + STAmount saCurDlvAct; + + while (!!uDirectTip // Have a quality. + && saPrvDlvAct != saPrvDlvReq) + { + // Get next quality. + if (bAdvance) + { + uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd); + } + else + { + bAdvance = true; + } + + if (!!uDirectTip) + { + // Do a directory. + // - Drive on computing saPrvDlvAct to derive saCurDlvAct. + SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); + STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio + unsigned int uEntry = 0; + uint256 uCurIndex; + + while (saPrvDlvReq != saPrvDlvAct // Have not met request. + && dirNext(uDirectTip, sleDirectDir, uEntry, uCurIndex)) + { + SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex); + uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); + STAmount saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); + STAmount saCurOfrInReq = sleCurOfr->getIValueFieldAmount(sfTakerPays); + // XXX Move issuer into STAmount + if (sleCurOfr->getIFieldPresent(sfGetsIssuer)) + saCurOfrOutReq.setIssuer(sleCurOfr->getIValueFieldAccount(sfGetsIssuer).getAccountID()); + + if (sleCurOfr->getIFieldPresent(sfPaysIssuer)) + saCurOfrInReq.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID()); + STAmount saCurOfrInAct; + STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. + + saCurOfrInReq = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); + + if (!!uNxtAccountID) + { + // Next is an account. + + STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtAccountID == uCurIssuerID + ? saOne + : saTransferRate; + bool bFee = saFeeRate != saOne; + + STAmount saOutPass = STAmount::divide(saCurOfrInReq, saOfrRate, uCurCurrencyID); + STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. + STAmount saOutCost = MIN( + bFee + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + : saOutBase, + saCurOfrFunds); // Limit cost by fees & funds. + STAmount saOutDlvAct = bFee + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + : saOutCost; // Out amount after fees. + STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID); // Compute input w/o fees required. + + saCurDlvAct += saOutDlvAct; // Portion of driver served. + saPrvDlvAct += saInDlvAct; // Portion needed in previous. + } + else + { + // Next is an offer. + + uint256 uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); + uint256 uNxtEnd = Ledger::getQualityNext(uNxtTip); + bool bNxtAdvance = !entryCache(ltDIR_NODE, uNxtTip); + + while (!!uNxtTip // Have a quality. + && saPrvDlvAct != saPrvDlvReq) // Have more to do. + { + if (bNxtAdvance) + { + uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd); + } + else + { + bNxtAdvance = true; + } + + if (!!uNxtTip) + { + // Do a directory. + // - Drive on computing saCurDlvAct to derive saPrvDlvAct. + SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); +// ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip)); // For correct ratio + unsigned int uEntry = 0; + uint256 uNxtIndex; + + while (saPrvDlvReq != saPrvDlvAct // Have not met request. + && dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex)) + { + // YYY This could combine offers with the same fee before doing math. + SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex); + uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); + STAmount saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); + // XXX Move issuer into STAmount + if (sleNxtOfr->getIFieldPresent(sfPaysIssuer)) + saNxtOfrIn.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID()); + + STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID + ? saOne + : saTransferRate; + bool bFee = saFeeRate != saOne; + + STAmount saInBase = saCurOfrInReq-saCurOfrInAct; + STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID); + STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. + saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. + STAmount saOutCost = MIN( + bFee + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + : saOutBase, + saCurOfrFunds); // Limit cost by fees & funds. + STAmount saOutDlvAct = bFee + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + : saOutCost; // Out amount after fees. + STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required. + + saCurOfrInAct += saOutDlvAct; // Portion of driver served. + saPrvDlvAct += saOutDlvAct; // Portion needed in previous. + saCurDlvAct += saInDlvAct; // Portion of driver served. + } + } + + // Do another nxt directory iff bMultiQuality + if (!bMultiQuality) + uNxtTip = 0; + } + } + } + } + + // Do another cur directory iff bMultiQuality + if (!bMultiQuality) + uDirectTip = 0; + } + + if (saCurDlvAct) + { + saCurDlvReq = saCurDlvAct; // Adjust request. + bSuccess = true; + } + + return bSuccess; +} + +#if 0 // If either currency is not stamps, then also calculates vs stamp bridge. // --> saWanted: Limit of how much is wanted out. // <-- saPay: How much to pay into the offer. // <-- saGot: How much to the offer pays out. Never more than saWanted. -void TransactionEngine::calcNodeOfferReverse( - const uint160& uPayCurrency, - const uint160& uPayIssuerID, - const STAmount& saWanted, // Driver +// Given two value's enforce a minimum: +// - reverse: prv is maximum to pay in (including fee) - cur is what is wanted: generally, minimizing prv +// - forward: prv is actual amount to pay in (including fee) - cur is what is wanted: generally, minimizing cur +// Value in is may be rippled or credited from limbo. Value out is put in limbo. +// If next is an offer, the amount needed is in cur reedem. +// XXX What about account mentioned multiple times via offers? +void TransactionEngine::calcNodeOffer( + bool bForward, + bool bMultiQuality, // True, if this is the only active path: we can do multiple qualities in this pass. + const uint160& uPrvAccountID, // If 0, then funds from previous offer's limbo + const uint160& uPrvCurrencyID, + const uint160& uPrvIssuerID, + const uint160& uCurCurrencyID, + const uint160& uCurIssuerID, + + const STAmount& uPrvRedeemReq, // --> In limit. + STAmount& uPrvRedeemAct, // <-> In limit achived. + const STAmount& uCurRedeemReq, // --> Out limit. Driver when uCurIssuerID == uNxtIssuerID (offer would redeem to next) + STAmount& uCurRedeemAct, // <-> Out limit achived. + + const STAmount& uCurIssueReq, // --> In limit. + STAmount& uCurIssueAct, // <-> In limit achived. + const STAmount& uCurIssueReq, // --> Out limit. Driver when uCurIssueReq != uNxtIssuerID (offer would effectively issue or transfer to next) + STAmount& uCurIssueAct, // <-> Out limit achived. STAmount& saPay, STAmount& saGot @@ -1902,11 +2305,13 @@ void TransactionEngine::calcNodeOfferReverse( { TransactionEngineResult terResult = tenUNKNOWN; + // Direct: not bridging via XNS bool bDirectNext = true; // True, if need to load. uint256 uDirectQuality; uint256 uDirectTip = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); + // Bridging: bridging via XNS bool bBridge = true; // True, if bridging active. False, missing an offer. uint256 uBridgeQuality; STAmount saBridgeIn; // Amount available. @@ -1927,397 +2332,177 @@ void TransactionEngine::calcNodeOfferReverse( unsigned int uOutEntry; saPay.zero(); - saPay.setCurrency(uPayCurrency); - saPay.setIssuer(uPayIssuerID); + saPay.setCurrency(uPrvCurrencyID); + saPay.setIssuer(uPrvIssuerID); saNeed = saWanted; - if (!saWanted.isNative() && !uTakerCurrency.isZero()) + if (!uCurCurrencyID && !uPrvCurrencyID) { - // Bridging - uInTip = Ledger::getBookBase(uPayCurrency, uPayIssuerID, uint160(0), uint160(0)); + // Bridging: Neither currency is XNS. + uInTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, CURRENCY_XNS, ACCOUNT_XNS); uInEnd = Ledger::getQualityNext(uInTip); - uOutTip = Ledger::getBookBase(uint160(0), uint160(0), saWanted.getCurrency(), saWanted.getIssuer()); + uOutTip = Ledger::getBookBase(CURRENCY_XNS, ACCOUNT_XNS, uCurCurrencyID, uCurIssuerID); uOutEnd = Ledger::getQualityNext(uInTip); } - while (tenUNKNOWN == terResult) + // Find our head offer. + + bool bRedeeming = false; + bool bIssuing = false; + + // The price varies as we change between issuing and transfering, so unless bMultiQuality, we must stick with a mode once it + // is determined. + + if (bBridge && (bInNext || bOutNext)) { - if (saNeed == saWanted) + // Bridging and need to calculate next bridge rate. + // A bridge can consist of multiple offers. As offer's are consumed, the effective rate changes. + + if (bInNext) { - // Got all. - saGot = saWanted; - terResult = terSUCCESS; - } - else - { - // Calculate next tips, if needed. - - if (bDirectNext) - { - // Find next direct offer. - uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd); - if (!!uDirectTip) - { - sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); - - // XXX Need to calculate the real quality: including fees. - uDirectQuality = STAmount::getQualityNext(uDirectTip); - } - - bDirectNext = false; - } - - if (bBridge && (bInNext || bOutNext)) - { - // Bridging and need to calculate next bridge rate. - // A bridge can consist of multiple offers. As offer's are consumed, the effective rate changes. - - if (bInNext) - { // sleInDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uInIndex, uInEnd)); - // Get the next funded offer. - offerBridgeNext(uInIndex, uInEnd, uInEntry, saInIn, saInOut); // Get offer limited by funding. - bInNext = false; - } + // Get the next funded offer. + offerBridgeNext(uInIndex, uInEnd, uInEntry, saInIn, saInOut); // Get offer limited by funding. + bInNext = false; + } - if (bOutNext) - { + if (bOutNext) + { // sleOutDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uOutIndex, uOutEnd)); - offerNext(uOutIndex, uOutEnd, uOutEntry, saOutIn, saOutOut); - bOutNext = false; - } - - if (!uInIndex || !uOutIndex) - { - bBridge = false; // No more offers to bridge. - } - else - { - // Have bridge in and out entries. - // Calculate bridge rate. Out offer pay ripple fee. In offer fee is added to in cost. - - saBridgeOut.zero(); - - if (saInOut < saOutIn) - { - // Limit by in. - - // XXX Need to include fees in saBridgeIn. - saBridgeIn = saInIn; // All of in - // Limit bridge out: saInOut/saBridgeOut = saOutIn/saOutOut - // Round such that we would take all of in offer, otherwise would have leftovers. - saBridgeOut = (saInOut * saOutOut) / saOutIn; - } - else if (saInOut > saOutIn) - { - // Limit by out, if at all. - - // XXX Need to include fees in saBridgeIn. - // Limit bridge in:saInIn/saInOuts = aBridgeIn/saOutIn - // Round such that would take all of out offer. - saBridgeIn = (saInIn * saOutIn) / saInOuts; - saBridgeOut = saOutOut; // All of out. - } - else - { - // Entries match, - - // XXX Need to include fees in saBridgeIn. - saBridgeIn = saInIn; // All of in - saBridgeOut = saOutOut; // All of out. - } - - uBridgeQuality = STAmount::getRate(saBridgeIn, saBridgeOut); // Inclusive of fees. - } - } - - if (bBridge) - { - bUseBridge = !uDirectTip || (uBridgeQuality < uDirectQuality) - } - else if (!!uDirectTip) - { - bUseBridge = false - } - else - { - // No more offers. Declare success, even if none returned. - saGot = saWanted-saNeed; - terResult = terSUCCESS; - } - - if (terSUCCESS != terResult) - { - STAmount& saAvailIn = bUseBridge ? saBridgeIn : saDirectIn; - STAmount& saAvailOut = bUseBridge ? saBridgeOut : saDirectOut; - - if (saAvailOut > saNeed) - { - // Consume part of offer. Done. - - saNeed = 0; - saPay += (saNeed*saAvailIn)/saAvailOut; // Round up, prefer to pay more. - } - else - { - // Consume entire offer. - - saNeed -= saAvailOut; - saPay += saAvailIn; - - if (bUseBridge) - { - // Consume bridge out. - if (saOutOut == saAvailOut) - { - // Consume all. - saOutOut = 0; - saOutIn = 0; - bOutNext = true; - } - else - { - // Consume portion of bridge out, must be consuming all of bridge in. - // saOutIn/saOutOut = saSpent/saAvailOut - // Round? - saOutIn -= (saOutIn*saAvailOut)/saOutOut; - saOutOut -= saAvailOut; - } - - // Consume bridge in. - if (saOutIn == saAvailIn) - { - // Consume all. - saInOut = 0; - saInIn = 0; - bInNext = true; - } - else - { - // Consume portion of bridge in, must be consuming all of bridge out. - // saInIn/saInOut = saAvailIn/saPay - // Round? - saInOut -= (saInOut*saAvailIn)/saInIn; - saInIn -= saAvailIn; - } - } - else - { - bDirectNext = true; - } - } - } + offerNext(uOutIndex, uOutEnd, uOutEntry, saOutIn, saOutOut); + bOutNext = false; } - } -} -#endif -// From the destination work towards the source calculating how much must be asked for. -// --> bAllowPartial: If false, fail if can't meet requirements. -// <-- bSuccess: true=success, false=insufficient funds / liqudity. -// <-> pnNodes: -// --> [end]saWanted.mAmount -// --> [all]saWanted.mCurrency -// --> [all]saAccount -// <-> [0]saWanted.mAmount : --> limit, <-- actual -// XXX Disallow looping. -// XXX With multiple path and due to offers, must consider consumed. -bool TransactionEngine::calcPathReverse(PathState::pointer pspCur) -{ - TransactionEngineResult terResult = tenUNKNOWN; - - unsigned int uLast = pspCur->vpnNodes.size() - 1; - unsigned int uIndex = pspCur->vpnNodes.size(); - - while (tenUNKNOWN == terResult && uIndex--) - { - // Calculate: - // (1) saPrvRedeem & saPrvIssue from saCurRevRedeem & saCurRevIssue. - // (2) saCurWanted by summing saRevRedeem & saRevIssue. <-- XXX might not need this as it can be infered. - // XXX We might not need to do 0. - - paymentNode& prvPN = uIndex ? pspCur->vpnNodes[uIndex-1] : pspCur->vpnNodes[0]; - paymentNode& curPN = pspCur->vpnNodes[uIndex]; - paymentNode& nxtPN = uIndex == uLast ? pspCur->vpnNodes[uLast] : pspCur->vpnNodes[uIndex+1]; - bool bAccount = !!(curPN.uFlags & STPathElement::typeAccount); - bool bRedeem = !!(curPN.uFlags & STPathElement::typeRedeem); - bool bIssue = !!(curPN.uFlags & STPathElement::typeIssue); - uint160& uPrvAccountID = prvPN.uAccountID; - uint160& uCurAccountID = curPN.uAccountID; - uint160& uNxtAccountID = nxtPN.uAccountID; - uint160& uCurrencyID = curPN.uCurrencyID; - - if (uIndex == uLast) + if (!uInIndex || !uOutIndex) { - // saCurWanted set by caller. - uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); - STAmount saPrvBalance = rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID); - STAmount saPrvLimit = rippleLimit(uCurAccountID, uPrvAccountID, uCurAccountID); - - STAmount saPrvRedeemReq = saPrvBalance.isNative() ? -saPrvBalance : STAmount(uCurrencyID, 0); - STAmount& saPrvRedeemAct = prvPN.saRevRedeem; // What previous should redeem with cur. - - STAmount& saPrvIssueAct = prvPN.saRevIssue; - STAmount saPrvIssueReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; - - STAmount saCurWantedReq = pspCur->saOutReq; - STAmount saCurWantedAct; - - // Calculate redeem - if (bRedeem - && saPrvRedeemReq) // Previous has IOUs to redeem. - { - // Redeem at 1:1 - saCurWantedAct = MIN(saPrvRedeemReq, saCurWantedReq); - saPrvRedeemAct = saCurWantedAct; - } - - // Calculate issuing. - if (bIssue - && saCurWantedReq != saCurWantedAct // Need more. - && saPrvIssueReq) // Will accept IOUs. - { - // Rate: quality in : 1.0 - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurWantedReq, saPrvIssueAct, saCurWantedAct); - } - - if (!saCurWantedAct) - { - // Must have processed something. - terResult = tenBAD_AMOUNT; - } - } - else if (!bAccount) - { - // Offer node. - // Ripple or transfering from previous node through this offer to next node. - // Current node has a credit line with next node. - // Next node will receive either its own IOUs or this nodes IOUs. - // We limit what this node sends by this nodes redeem and issue max. - // This allows path lists to be strictly redeem. - // XXX Make sure offer book was not previously mentioned. -#if 0 - uint160 uPrvCurrency = curPN.uFlags & PF_WANTED_CURRENCY - ? curPN->saWanted.getCurrency() - : saSendMax.getCurrency(); - - uint160 uPrvIssuer = curPN.uFlags & PF_WANTED_ISSUER - ? curPN->saWanted.getIssuer() - : saSendMax.getIssuer(); - - calcNodeOfferReverse( - uTakerCurrency, - uTakerIssuer, - nxtPN->saWanted, // Driver. - - uTakerPaid, - uTakerGot, - uOwnerPaid, - uOwnerGot, - ); - - if (uOwnerPaid.isZero()) - { - terResult = terZERO; // Path contributes nothing. - } - else - { - // Update wanted. - - // Save sent amount - } -#endif - } - // Ripple through account. - else if (!bIssue && !bRedeem) - { - // XXX This might be checked sooner. - terResult = tenBAD_PATH; // Must be able to redeem and issue. - } - else if (!uIndex) - { - // Done. No previous. We know what we would like to redeem and issue. - nothing(); + bBridge = false; // No more offers to bridge. } else { - // Rippling through this accounts balances. - // No currency change. - // Given saCurRedeem & saCurIssue figure out saPrvRedeem & saPrvIssue. + // Have bridge in and out entries. + // Calculate bridge rate. Out offer pay ripple fee. In offer fee is added to in cost. - uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); - uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); - STAmount saPrvBalance = rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID); - STAmount saPrvLimit = rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID); + saBridgeOut.zero(); - STAmount saPrvRedeemReq = saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); - STAmount& saPrvRedeemAct = prvPN.saRevRedeem; - - STAmount saPrvIssueReq = saPrvLimit - saPrvBalance; - STAmount& saPrvIssueAct = prvPN.saRevIssue; - - const STAmount& saCurRedeemReq = curPN.saRevRedeem; - STAmount saCurRedeemAct; - - const STAmount& saCurIssueReq = curPN.saRevIssue; - STAmount saCurIssueAct; // Track progess. - - - // Previous redeem part 1: redeem -> redeem - if (bRedeem - && saCurRedeemReq // Next wants us to redeem. - && saPrvBalance.isNegative()) // Previous has IOUs to redeem. + if (saInOut < saOutIn) { - // Rate : 1.0 : quality out + // Limit by in. - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); + // XXX Need to include fees in saBridgeIn. + saBridgeIn = saInIn; // All of in + // Limit bridge out: saInOut/saBridgeOut = saOutIn/saOutOut + // Round such that we would take all of in offer, otherwise would have leftovers. + saBridgeOut = (saInOut * saOutOut) / saOutIn; + } + else if (saInOut > saOutIn) + { + // Limit by out, if at all. + + // XXX Need to include fees in saBridgeIn. + // Limit bridge in:saInIn/saInOuts = aBridgeIn/saOutIn + // Round such that would take all of out offer. + saBridgeIn = (saInIn * saOutIn) / saInOuts; + saBridgeOut = saOutOut; // All of out. + } + else + { + // Entries match, + + // XXX Need to include fees in saBridgeIn. + saBridgeIn = saInIn; // All of in + saBridgeOut = saOutOut; // All of out. } - // Previous redeem part 2: redeem -> issue. - if (bIssue - && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. - && saPrvBalance.isNegative() // Previous still has IOUs. - && saCurIssueReq) // Need some issued. - { - // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); - } - - // Previous issue part 1: issue -> redeem - if (bRedeem - && saCurRedeemReq != saCurRedeemAct // Can only redeem if more to be redeemed. - && !saPrvBalance.isNegative()) // Previous has no IOUs. - { - // Rate: quality in : quality out - calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); - } - - // Previous issue part 2 : issue -> issue - if (bIssue - && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. - && !saPrvBalance.isNegative() // Previous has no IOUs. - && saCurIssueReq != saCurIssueAct) // Need some issued. - { - // Rate: quality in : 1.0 - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); - } - - if (!saCurRedeemAct && !saCurIssueAct) - { - // Must want something. - terResult = tenBAD_AMOUNT; - } + uBridgeQuality = STAmount::getRate(saBridgeIn, saBridgeOut); // Inclusive of fees. } } - return tenUNKNOWN == terResult; + if (bBridge) + { + bUseBridge = !uDirectTip || (uBridgeQuality < uDirectQuality) + } + else if (!!uDirectTip) + { + bUseBridge = false + } + else + { + // No more offers. Declare success, even if none returned. + saGot = saWanted-saNeed; + terResult = terSUCCESS; + } + + if (terSUCCESS != terResult) + { + STAmount& saAvailIn = bUseBridge ? saBridgeIn : saDirectIn; + STAmount& saAvailOut = bUseBridge ? saBridgeOut : saDirectOut; + + if (saAvailOut > saNeed) + { + // Consume part of offer. Done. + + saNeed = 0; + saPay += (saNeed*saAvailIn)/saAvailOut; // Round up, prefer to pay more. + } + else + { + // Consume entire offer. + + saNeed -= saAvailOut; + saPay += saAvailIn; + + if (bUseBridge) + { + // Consume bridge out. + if (saOutOut == saAvailOut) + { + // Consume all. + saOutOut = 0; + saOutIn = 0; + bOutNext = true; + } + else + { + // Consume portion of bridge out, must be consuming all of bridge in. + // saOutIn/saOutOut = saSpent/saAvailOut + // Round? + saOutIn -= (saOutIn*saAvailOut)/saOutOut; + saOutOut -= saAvailOut; + } + + // Consume bridge in. + if (saOutIn == saAvailIn) + { + // Consume all. + saInOut = 0; + saInIn = 0; + bInNext = true; + } + else + { + // Consume portion of bridge in, must be consuming all of bridge out. + // saInIn/saInOut = saAvailIn/saPay + // Round? + saInOut -= (saInOut*saAvailIn)/saInIn; + saInIn -= saAvailIn; + } + } + else + { + bDirectNext = true; + } + } + } } +#endif // Cur is the driver and will be filled exactly. // uQualityIn -> uQualityOut // saPrvReq -> saCurReq // sqPrvAct -> saCurAct +// This is a minimizing routine: moving in reverse it propagates the send limit to the sender, moving forward it propagates the +// actual send toward the reciver. // This routine works backwards as it calculates previous wants based on previous credit limits and current wants. // This routine works forwards as it calculates current deliver based on previous delivery limits and current wants. void TransactionEngine::calcNodeRipple( @@ -2361,145 +2546,301 @@ void TransactionEngine::calcNodeRipple( } } -// From the source work toward the destination calculate how much is transfered at each step and finally. -// <-> pnNodes: -// --> [0]saWanted.mAmount -// --> [all]saWanted.saSend -// --> [all]saWanted.IOURedeem -// --> [all]saWanted.IOUIssue -// --> [all]saAccount -void TransactionEngine::calcPathForward(PathState::pointer pspCur) +// Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver; +bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) { - unsigned int uIndex = 0; + bool bSuccess = true; + unsigned int uLast = pspCur->vpnNodes.size() - 1; - unsigned int uEnd = pspCur->vpnNodes.size(); - unsigned int uLast = uEnd - 1; + paymentNode& prvPN = uIndex ? pspCur->vpnNodes[uIndex-1] : pspCur->vpnNodes[0]; + paymentNode& curPN = pspCur->vpnNodes[uIndex]; + paymentNode& nxtPN = uIndex == uLast ? pspCur->vpnNodes[uLast] : pspCur->vpnNodes[uIndex+1]; - while (uIndex != uEnd) + bool bRedeem = !!(curPN.uFlags & STPathElement::typeRedeem); + bool bIssue = !!(curPN.uFlags & STPathElement::typeIssue); + bool bPrvAccount = !!(prvPN.uFlags & STPathElement::typeAccount); + + uint160& uPrvAccountID = prvPN.uAccountID; + uint160& uCurAccountID = curPN.uAccountID; + uint160& uNxtAccountID = nxtPN.uAccountID; + + uint160& uCurIssuerID = curPN.uIssuerID; + + uint160& uCurrencyID = curPN.uCurrencyID; + + if (uIndex == uLast) { - // Calculate (1) sending by fullfilling next wants and (2) setting current wants. + STAmount saCurWantedReq = pspCur->saOutReq; + STAmount saCurWantedAct; - paymentNode& prvPN = uIndex ? pspCur->vpnNodes[uIndex-1] : pspCur->vpnNodes[0]; - paymentNode& curPN = pspCur->vpnNodes[uIndex]; - paymentNode& nxtPN = uIndex == uLast ? pspCur->vpnNodes[uLast] : pspCur->vpnNodes[uIndex+1]; - - // XXX Assume rippling. - - if (!uIndex) + // Calculate deliver + if (bPrvAccount) { - // First node, calculate amount to send. - STAmount& saCurRedeemReq = curPN.saRevRedeem; - STAmount& saCurRedeemAct = curPN.saFwdRedeem; - STAmount& saCurIssueReq = curPN.saRevIssue; - STAmount& saCurIssueAct = curPN.saFwdIssue; + // Previous is an account node. + uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); + STAmount saPrvBalance = rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID); + STAmount saPrvLimit = rippleLimit(uCurAccountID, uPrvAccountID, uCurAccountID); - STAmount& saCurSendMaxReq = pspCur->saInReq; - STAmount& saCurSendMaxAct = pspCur->saInAct; + STAmount saPrvRedeemReq = saPrvBalance.isNative() ? -saPrvBalance : STAmount(uCurrencyID, 0); + STAmount& saPrvRedeemAct = prvPN.saRevRedeem; // What previous should redeem with cur. - if (saCurRedeemReq) + STAmount saPrvIssueReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; + STAmount& saPrvIssueAct = prvPN.saRevIssue; + + // Calculate redeem + if (bRedeem + && saPrvRedeemReq) // Previous has IOUs to redeem. { - // Redeem requested. - saCurRedeemAct = MIN(saCurRedeemAct, saCurSendMaxReq); - saCurSendMaxAct = saCurRedeemAct; + // Redeem at 1:1 + saCurWantedAct = MIN(saPrvRedeemReq, saCurWantedReq); + saPrvRedeemAct = saCurWantedAct; } - if (saCurIssueReq && saCurSendMaxReq != saCurRedeemAct) + // Calculate issuing. + if (bIssue + && saCurWantedReq != saCurWantedAct // Need more. + && saPrvIssueReq) // Will accept IOUs. { - // Issue requested and not over budget. - saCurIssueAct = MIN(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); - // saCurSendMaxAct += saCurIssueReq; // Not needed. + // Rate: quality in : 1.0 + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurWantedReq, saPrvIssueAct, saCurWantedAct); } - } - else if (uIndex == uLast) - { - // Last node. Accept all funds. Calculate amount actually to credit. - uint32 uQualityIn = rippleQualityIn(curPN.uAccountID, prvPN.uAccountID, curPN.uCurrencyID); - STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; - STAmount& saPrvIssueReq = prvPN.saFwdIssue; - STAmount saPrvIssueAct = uQualityIn >= QUALITY_ONE - ? saPrvIssueReq // No fee. - : STAmount::multiply(saPrvIssueReq, uQualityIn, curPN.uCurrencyID); // Fee. - STAmount& saCurReceive = pspCur->saOutAct; - // Amount to credit. - saCurReceive = saPrvRedeemReq+saPrvIssueAct; - - // Actually receive. - rippleCredit(curPN.uAccountID, prvPN.uAccountID, saCurReceive); + if (!saCurWantedAct) + { + // Must have processed something. + // terResult = tenBAD_AMOUNT; + bSuccess = false; + } } else { - // Handle middle node. - // The previous nodes tells want it wants to push through to current. - // The current node know what it would push through next. - // Determine for the current node: - // - Output to next node minus fees. - // Perform balance adjustment with previous. - // All of previous output is consumed. + // Previous is an offer node. + // Rate: quality in : 1.0 + uint32 uQualityIn = rippleQualityIn(uCurAccountID, uCurIssuerID, uCurrencyID); + STAmount saPrvBalance = rippleBalance(uCurAccountID, uCurIssuerID, uCurrencyID); + STAmount saPrvLimit = rippleLimit(uCurAccountID, uCurIssuerID, uCurAccountID); + STAmount saPrvDeliverReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; + STAmount& saPrvDeliverAct = prvPN.saRevDeliver; - uint160& uCurrencyID = curPN.uCurrencyID; + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct); + } - uint160& uPrvAccountID = prvPN.uAccountID; - uint160& uCurAccountID = curPN.uAccountID; - uint160& uNxtAccountID = nxtPN.uAccountID; - - STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; - STAmount saPrvRedeemAct; - STAmount& saPrvIssueReq = prvPN.saFwdIssue; - STAmount saPrvIssueAct; - - STAmount& saCurRedeemReq = curPN.saRevRedeem; - STAmount& saCurRedeemAct = curPN.saFwdRedeem; - STAmount& saCurIssueReq = curPN.saRevIssue; - STAmount& saCurIssueAct = curPN.saFwdIssue; - - // Have funds in previous node to transfer. - uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); - uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); - - // Previous redeem part 1: redeem -> redeem - if (saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. - { - // Rate : 1.0 : quality out - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); - } - - // Previous redeem part 2: redeem -> issue. - // wants to redeem and current would and can issue. - // If redeeming cur to next is done, this implies can issue. - if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem. - && saCurRedeemReq == saCurRedeemAct) // Current has more to redeem to next. - { - // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); - } - - // Previous issue part 1: issue -> redeem - if (saPrvIssueReq != saPrvIssueAct // Previous wants to issue. - && saCurRedeemReq == saCurRedeemAct) // Current has more to redeem to next. - { - // Rate: quality in : quality out - calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); - } - - // Previous issue part 2 : issue -> issue - if (saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. - { - // Rate: quality in : 1.0 - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); - } - - // Adjust prv --> cur balance : take all inbound - // XXX Currency must be in amount. - rippleCredit(uCurAccountID, uPrvAccountID, saPrvRedeemReq + saPrvIssueReq); + if (!saCurWantedAct) + { + // Must have processed something. + // terResult = tenBAD_AMOUNT; + bSuccess = false; } } + else if (bPrvAccount) + { + // Rippling through this accounts balances. + // No currency change. + // Given saCurRedeem & saCurIssue figure out saPrvRedeem & saPrvIssue. + + uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); + uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); + STAmount saPrvBalance = rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID); + STAmount saPrvLimit = rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID); + + STAmount saPrvRedeemReq = saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); + STAmount& saPrvRedeemAct = prvPN.saRevRedeem; + + STAmount saPrvIssueReq = saPrvLimit - saPrvBalance; + STAmount& saPrvIssueAct = prvPN.saRevIssue; + + const STAmount& saCurRedeemReq = curPN.saRevRedeem; + STAmount saCurRedeemAct; + + const STAmount& saCurIssueReq = curPN.saRevIssue; + STAmount saCurIssueAct; // Track progess. + + + // Previous redeem part 1: redeem -> redeem + if (bRedeem // Allowed to redeem. + && saCurRedeemReq // Next wants us to redeem. + && saPrvBalance.isNegative()) // Previous has IOUs to redeem. + { + // Rate : 1.0 : quality out + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); + } + + // Previous redeem part 2: redeem -> issue. + if (bIssue // Allowed to issue. + && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. + && saPrvBalance.isNegative() // Previous still has IOUs. + && saCurIssueReq) // Need some issued. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + } + + // Previous issue part 1: issue -> redeem + if (bRedeem // Allowed to redeem. + && saCurRedeemReq != saCurRedeemAct // Can only redeem if more to be redeemed. + && !saPrvBalance.isNegative()) // Previous has no IOUs. + { + // Rate: quality in : quality out + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); + } + + // Previous issue part 2 : issue -> issue + if (bIssue // Allowed to issue. + && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. + && !saPrvBalance.isNegative() // Previous has no IOUs. + && saCurIssueReq != saCurIssueAct) // Need some issued. + { + // Rate: quality in : 1.0 + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); + } + + if (!saCurRedeemAct && !saCurIssueAct) + { + // Must want something. + // terResult = tenBAD_AMOUNT; + bSuccess = false; + } + } + else + { + // Previous is a offer. + + } + + return bSuccess; } -bool PathState::less(const PathState::pointer& lhs, const PathState::pointer& rhs) +bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) { - // Return true, iff lhs has less priority than rhs. + bool bSuccess = true; + unsigned int uLast = pspCur->vpnNodes.size() - 1; + // Ripple through account. + if (!uIndex) + { + // First node, calculate amount to send. + // XXX Use stamp/ripple balance + paymentNode& curPN = pspCur->vpnNodes[uIndex]; + + STAmount& saCurRedeemReq = curPN.saRevRedeem; + STAmount& saCurRedeemAct = curPN.saFwdRedeem; + STAmount& saCurIssueReq = curPN.saRevIssue; + STAmount& saCurIssueAct = curPN.saFwdIssue; + + STAmount& saCurSendMaxReq = pspCur->saInReq; + STAmount& saCurSendMaxAct = pspCur->saInAct; + + if (saCurRedeemReq) + { + // Redeem requested. + saCurRedeemAct = MIN(saCurRedeemAct, saCurSendMaxReq); + saCurSendMaxAct = saCurRedeemAct; + } + + if (saCurIssueReq && saCurSendMaxReq != saCurRedeemAct) + { + // Issue requested and not over budget. + saCurIssueAct = MIN(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); + // saCurSendMaxAct += saCurIssueReq; // Not needed. + } + } + else if (uIndex == uLast) + { + // Last node. Accept all funds. Calculate amount actually to credit. + paymentNode& prvPN = pspCur->vpnNodes[uIndex-1]; + paymentNode& curPN = pspCur->vpnNodes[uIndex]; + + uint32 uQualityIn = rippleQualityIn(curPN.uAccountID, prvPN.uAccountID, curPN.uCurrencyID); + STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; + STAmount& saPrvIssueReq = prvPN.saFwdIssue; + STAmount saPrvIssueAct = uQualityIn >= QUALITY_ONE + ? saPrvIssueReq // No fee. + : STAmount::multiply(saPrvIssueReq, uQualityIn, curPN.uCurrencyID); // Fee. + STAmount& saCurReceive = pspCur->saOutAct; + + // Amount to credit. + saCurReceive = saPrvRedeemReq+saPrvIssueAct; + + // Actually receive. + rippleCredit(curPN.uAccountID, prvPN.uAccountID, saCurReceive); + } + else + { + // Handle middle node. + // The previous nodes tells want it wants to push through to current. + // The current node know what it would push through next. + // Determine for the current node: + // - Output to next node minus fees. + // Perform balance adjustment with previous. + // All of previous output is consumed. + + paymentNode& prvPN = pspCur->vpnNodes[uIndex-1]; + paymentNode& curPN = pspCur->vpnNodes[uIndex]; + paymentNode& nxtPN = pspCur->vpnNodes[uIndex+1]; + + uint160& uCurrencyID = curPN.uCurrencyID; + + uint160& uPrvAccountID = prvPN.uAccountID; + uint160& uCurAccountID = curPN.uAccountID; + uint160& uNxtAccountID = nxtPN.uAccountID; + + STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; + STAmount saPrvRedeemAct; + STAmount& saPrvIssueReq = prvPN.saFwdIssue; + STAmount saPrvIssueAct; + + STAmount& saCurRedeemReq = curPN.saRevRedeem; + STAmount& saCurRedeemAct = curPN.saFwdRedeem; + STAmount& saCurIssueReq = curPN.saRevIssue; + STAmount& saCurIssueAct = curPN.saFwdIssue; + + // Have funds in previous node to transfer. + uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); + uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); + + // Previous redeem part 1: redeem -> redeem + if (saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. + { + // Rate : 1.0 : quality out + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); + } + + // Previous redeem part 2: redeem -> issue. + // wants to redeem and current would and can issue. + // If redeeming cur to next is done, this implies can issue. + if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem. + && saCurRedeemReq == saCurRedeemAct) // Current has more to redeem to next. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + } + + // Previous issue part 1: issue -> redeem + if (saPrvIssueReq != saPrvIssueAct // Previous wants to issue. + && saCurRedeemReq == saCurRedeemAct) // Current has more to redeem to next. + { + // Rate: quality in : quality out + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); + } + + // Previous issue part 2 : issue -> issue + if (saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. + { + // Rate: quality in : 1.0 + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); + } + + // Adjust prv --> cur balance : take all inbound + // XXX Currency must be in amount. + rippleCredit(uCurAccountID, uPrvAccountID, saPrvRedeemReq + saPrvIssueReq); + } + + return bSuccess; +} + +// Return true, iff lhs has less priority than rhs. +bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs) +{ if (lhs->uQuality != rhs->uQuality) return lhs->uQuality > rhs->uQuality; // Bigger is worse. @@ -2590,6 +2931,7 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin return bValid; } +// XXX Disallow loops in ripple paths PathState::PathState( int iIndex, const LedgerEntrySet& lesSource, @@ -2617,17 +2959,53 @@ PathState::PathState( pushNode(STPathElement::typeAccount, uReceiverID, saOutReq.getCurrency(), saOutReq.getIssuer()); } +// Calculate a node and its previous nodes. +// From the destination work towards the source calculating how much must be asked for. +// --> bAllowPartial: If false, fail if can't meet requirements. +// <-- bSuccess: true=success, false=insufficient funds / liqudity. +// <-> pnNodes: +// --> [end]saWanted.mAmount +// --> [all]saWanted.mCurrency +// --> [all]saAccount +// <-> [0]saWanted.mAmount : --> limit, <-- actual +// XXX Disallow looping. +bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) +{ + paymentNode& curPN = pspCur->vpnNodes[uIndex]; + bool bCurAccount = !!(curPN.uFlags & STPathElement::typeAccount); + bool bSuccess; + + // Do current node reverse. + bSuccess = bCurAccount + ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) + : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); + + // Do previous. + if (bSuccess && uIndex) + { + bSuccess = calcNode(uIndex-1, pspCur, bMultiQuality); + } + + // Do current node forward. + if (bSuccess) + { + bSuccess = bCurAccount + ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) + : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); + } + + return bSuccess; +} + // Calculate the next increment of a path. -void TransactionEngine::pathNext(PathState::pointer pspCur) +void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) { // The next state is what is available in preference order. // This is calculated when referenced accounts changed. - if (calcPathReverse(pspCur)) - { - calcPathForward(pspCur); - } - else + unsigned int uLast = pspCur->vpnNodes.size() - 1; + + if (!calcNode(uLast, pspCur, iPaths == 1)) { // Mark path as inactive. pspCur->uQuality = 0; @@ -2740,7 +3118,6 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // // Ripple payment // - // XXX Disallow loops in ripple paths // Try direct ripple first. if (!bNoRippleDirect && mTxnAccountID != uDstAccountID && uSrcCurrency == uDstCurrency) @@ -2873,10 +3250,10 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction pspCur->lesEntries = mNodes.duplicate(); // XXX Compute increment - pathNext(pspCur); + pathNext(pspCur, vpsPaths.size()); } - if (!pspBest || (pspCur->uQuality && PathState::less(pspBest, pspCur))) + if (!pspBest || (pspCur->uQuality && PathState::lessPriority(pspBest, pspCur))) pspBest = pspCur; } diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 0f3aed7671..832f09e5e0 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -111,11 +111,14 @@ typedef struct { // Computed by Reverse. STAmount saRevRedeem; // <-- Amount to redeem to next. STAmount saRevIssue; // <-- Amount to issue to next limited by credit and outstanding IOUs. - // ? STAmount saSend; // <-- Stamps this node will send downstream. + // 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. } paymentNode; // Hold a path state under incremental application. @@ -161,7 +164,7 @@ public: ) { return boost::make_shared(iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax, bPartialPayment); }; - static bool less(const PathState::pointer& lhs, const PathState::pointer& rhs); + static bool lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs); }; // One instance per ledger. @@ -228,7 +231,7 @@ protected: uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID); - STAmount rippleTransit(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount); + STAmount rippleTransfer(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount); void rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); STAmount rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); @@ -238,12 +241,15 @@ protected: PathState::pointer pathCreate(const STPath& spPath); void pathApply(PathState::pointer pspCur); - void pathNext(PathState::pointer pspCur); + void pathNext(PathState::pointer pspCur, int iPaths); + bool calcNode(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); + bool calcNodeOfferRev(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); + bool calcNodeOfferFwd(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); + bool calcNodeAccountRev(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); + bool calcNodeAccountFwd(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); void calcNodeRipple(const uint32 uQualityIn, const uint32 uQualityOut, const STAmount& saPrvReq, const STAmount& saCurReq, STAmount& saPrvAct, STAmount& saCurAct); - bool calcPathReverse(PathState::pointer pspCur); - void calcPathForward(PathState::pointer pspCur); void txnWrite(); From 05304cc1fcbf51f161019f89990601b4ca9240c2 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 11 Aug 2012 14:39:58 -0700 Subject: [PATCH 022/426] More work towards ripple backend. --- src/TransactionEngine.cpp | 670 +++++++++++++++++++++++++------------- 1 file changed, 447 insertions(+), 223 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 92a6ddec94..d95b0bb198 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -27,6 +27,7 @@ #define ACCOUNT_XNS uint160(0) #define ACCOUNT_ONE uint160(1) // Used as a place holder +static STAmount saZero(CURRENCY_ONE, 0, 0); static STAmount saOne(CURRENCY_ONE, 1, 0); bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std::string& strHuman) @@ -152,18 +153,24 @@ uint32 TransactionEngine::rippleTransfer(const uint160& uIssuerID) // XXX Might not need this, might store in nodes on calc reverse. uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) { - uint32 uQualityIn; + uint32 uQualityIn = QUALITY_ONE; - SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); - - if (sleRippleState) + if (uToAccountID == uFromAccountID) { - uQualityIn = sleRippleState->getIFieldU32(uToAccountID < uFromAccountID ? sfLowQualityIn : sfHighQualityIn); + nothing(); } else { - assert(false); - uQualityIn = QUALITY_ONE; + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); + + if (sleRippleState) + { + uQualityIn = sleRippleState->getIFieldU32(uToAccountID < uFromAccountID ? sfLowQualityIn : sfHighQualityIn); + } + else + { + assert(false); + } } return uQualityIn; @@ -171,18 +178,24 @@ uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uin uint32 TransactionEngine::rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) { - uint32 uQualityOut; + uint32 uQualityOut = QUALITY_ONE; - SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); - - if (sleRippleState) + if (uToAccountID == uFromAccountID) { - uQualityOut = sleRippleState->getIFieldU32(uToAccountID < uFromAccountID ? sfLowQualityOut : sfHighQualityOut); + nothing(); } else { - assert(false); - uQualityOut = QUALITY_ONE; + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); + + if (sleRippleState) + { + uQualityOut = sleRippleState->getIFieldU32(uToAccountID < uFromAccountID ? sfLowQualityOut : sfHighQualityOut); + } + else + { + assert(false); + } } return uQualityOut; @@ -1894,6 +1907,7 @@ void TransactionEngine::calcOfferBridgeNext( #endif // <-- bSuccess: false= no transfer +// XXX Make sure missing ripple path is addressed cleanly. bool TransactionEngine::calcNodeOfferRev( unsigned int uIndex, // 0 < uIndex < uLast-1 PathState::pointer pspCur, @@ -2508,18 +2522,19 @@ void TransactionEngine::calcNodeOffer( void TransactionEngine::calcNodeRipple( const uint32 uQualityIn, const uint32 uQualityOut, - const STAmount& saPrvReq, // --> in limit including fees + const STAmount& saPrvReq, // --> in limit including fees, <0 = unlimited const STAmount& saCurReq, // --> out limit (driver) STAmount& saPrvAct, // <-> in limit including achieved STAmount& saCurAct) // <-> out limit achieved. { - STAmount saPrv = saPrvReq-saPrvAct; - STAmount saCur = saCurReq-saCurAct; + bool bPrvUnlimited = saPrvReq.isNegative(); + STAmount saPrv = bPrvUnlimited ? saZero : saPrvReq-saPrvAct; + STAmount saCur = saCurReq-saCurAct; if (uQualityIn >= uQualityOut) { // No fee. - STAmount saTransfer = MIN(saPrv, saCur); + STAmount saTransfer = bPrvUnlimited ? saCur : MIN(saPrv, saCur); saPrvAct += saTransfer; saCurAct += saTransfer; @@ -2529,7 +2544,7 @@ void TransactionEngine::calcNodeRipple( // Fee. STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, CURRENCY_ONE), uQualityIn, CURRENCY_ONE); - if (saCurIn >= saPrv) + if (bPrvUnlimited || saCurIn >= saPrv) { // All of cur. Some amount of prv. saCurAct = saCurReq; @@ -2552,40 +2567,61 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point bool bSuccess = true; unsigned int uLast = pspCur->vpnNodes.size() - 1; - paymentNode& prvPN = uIndex ? pspCur->vpnNodes[uIndex-1] : pspCur->vpnNodes[0]; + paymentNode& prvPN = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; paymentNode& curPN = pspCur->vpnNodes[uIndex]; - paymentNode& nxtPN = uIndex == uLast ? pspCur->vpnNodes[uLast] : pspCur->vpnNodes[uIndex+1]; + paymentNode& nxtPN = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; bool bRedeem = !!(curPN.uFlags & STPathElement::typeRedeem); + bool bPrvRedeem = !!(prvPN.uFlags & STPathElement::typeRedeem); bool bIssue = !!(curPN.uFlags & STPathElement::typeIssue); + bool bPrvIssue = !!(prvPN.uFlags & STPathElement::typeIssue); bool bPrvAccount = !!(prvPN.uFlags & STPathElement::typeAccount); + bool bNxtAccount = !!(nxtPN.uFlags & STPathElement::typeAccount); uint160& uPrvAccountID = prvPN.uAccountID; uint160& uCurAccountID = curPN.uAccountID; - uint160& uNxtAccountID = nxtPN.uAccountID; - - uint160& uCurIssuerID = curPN.uIssuerID; + uint160& uNxtAccountID = bNxtAccount ? nxtPN.uAccountID : uCurAccountID; // Offers are always issue. uint160& uCurrencyID = curPN.uCurrencyID; - if (uIndex == uLast) + uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); + uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); + + // For bPrvAccount + STAmount saPrvBalance = bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : saZero; + STAmount saPrvLimit = bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : saZero; + + STAmount saPrvRedeemReq = bPrvRedeem && saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); + STAmount& saPrvRedeemAct = prvPN.saRevRedeem; + + STAmount saPrvIssueReq = bPrvIssue && saPrvLimit - saPrvBalance; + STAmount& saPrvIssueAct = prvPN.saRevIssue; + + // For !bPrvAccount + STAmount saPrvDeliverReq = STAmount(uCurrencyID, -1); // Unlimited. + STAmount& saPrvDeliverAct = prvPN.saRevDeliver; + + // For bNxtAccount + const STAmount& saCurRedeemReq = curPN.saRevRedeem; + STAmount saCurRedeemAct; + + const STAmount& saCurIssueReq = curPN.saRevIssue; + STAmount saCurIssueAct; // Track progress. + + // For !bNxtAccount + const STAmount& saCurDeliverReq = curPN.saRevDeliver; + STAmount saCurDeliverAct; + + // For uIndex == uLast + const STAmount& saCurWantedReq = pspCur->saOutReq; // XXX Credit limits? + // STAmount saPrvDeliverReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; + STAmount saCurWantedAct; + + if (bPrvAccount && bNxtAccount) { - STAmount saCurWantedReq = pspCur->saOutReq; - STAmount saCurWantedAct; - - // Calculate deliver - if (bPrvAccount) + if (uIndex == uLast) { - // Previous is an account node. - uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); - STAmount saPrvBalance = rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID); - STAmount saPrvLimit = rippleLimit(uCurAccountID, uPrvAccountID, uCurAccountID); - - STAmount saPrvRedeemReq = saPrvBalance.isNative() ? -saPrvBalance : STAmount(uCurrencyID, 0); - STAmount& saPrvRedeemAct = prvPN.saRevRedeem; // What previous should redeem with cur. - - STAmount saPrvIssueReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; - STAmount& saPrvIssueAct = prvPN.saRevIssue; + // account --> ACCOUNT --> $ // Calculate redeem if (bRedeem @@ -2614,225 +2650,384 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point } else { - // Previous is an offer node. - // Rate: quality in : 1.0 - uint32 uQualityIn = rippleQualityIn(uCurAccountID, uCurIssuerID, uCurrencyID); - STAmount saPrvBalance = rippleBalance(uCurAccountID, uCurIssuerID, uCurrencyID); - STAmount saPrvLimit = rippleLimit(uCurAccountID, uCurIssuerID, uCurAccountID); - STAmount saPrvDeliverReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; - STAmount& saPrvDeliverAct = prvPN.saRevDeliver; + // account --> ACCOUNT --> account - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct); - } + // redeem (part 1) -> redeem + if (bPrvRedeem + && bRedeem // Allowed to redeem. + && saCurRedeemReq // Next wants us to redeem. + && saPrvBalance.isNegative()) // Previous has IOUs to redeem. + { + // Rate : 1.0 : quality out + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); + } - if (!saCurWantedAct) - { - // Must have processed something. - // terResult = tenBAD_AMOUNT; - bSuccess = false; + // redeem (part 2) -> issue. + if (bPrvRedeem + && bIssue // Allowed to issue. + && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. + && saPrvBalance.isNegative() // Previous still has IOUs. + && saCurIssueReq) // Need some issued. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + } + + // issue (part 1)-> redeem + if (bPrvIssue + && bRedeem // Allowed to redeem. + && saCurRedeemReq != saCurRedeemAct // Can only redeem if more to be redeemed. + && !saPrvBalance.isNegative()) // Previous has no IOUs. + { + // Rate: quality in : quality out + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); + } + + // issue (part 2) -> issue + if (bPrvIssue + && bIssue // Allowed to issue. + && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. + && !saPrvBalance.isNegative() // Previous has no IOUs. + && saCurIssueReq != saCurIssueAct) // Need some issued. + { + // Rate: quality in : 1.0 + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); + } + + if (!saCurRedeemAct && !saCurIssueAct) + { + // Must want something. + // terResult = tenBAD_AMOUNT; + bSuccess = false; + } } } - else if (bPrvAccount) + else if (bPrvAccount && !bNxtAccount) { - // Rippling through this accounts balances. - // No currency change. - // Given saCurRedeem & saCurIssue figure out saPrvRedeem & saPrvIssue. + // account --> ACCOUNT --> offer + // Note: deliver is always issue as ACCOUNT is the issuer for the offer input. - uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); - uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); - STAmount saPrvBalance = rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID); - STAmount saPrvLimit = rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID); - - STAmount saPrvRedeemReq = saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); - STAmount& saPrvRedeemAct = prvPN.saRevRedeem; - - STAmount saPrvIssueReq = saPrvLimit - saPrvBalance; - STAmount& saPrvIssueAct = prvPN.saRevIssue; - - const STAmount& saCurRedeemReq = curPN.saRevRedeem; - STAmount saCurRedeemAct; - - const STAmount& saCurIssueReq = curPN.saRevIssue; - STAmount saCurIssueAct; // Track progess. - - - // Previous redeem part 1: redeem -> redeem - if (bRedeem // Allowed to redeem. - && saCurRedeemReq // Next wants us to redeem. - && saPrvBalance.isNegative()) // Previous has IOUs to redeem. - { - // Rate : 1.0 : quality out - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); - } - - // Previous redeem part 2: redeem -> issue. - if (bIssue // Allowed to issue. - && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. - && saPrvBalance.isNegative() // Previous still has IOUs. - && saCurIssueReq) // Need some issued. + // redeem -> deliver/issue. + if (bPrvRedeem + && bIssue // Allowed to issue. + && saPrvBalance.isNegative() // Previous redeeming: Previous still has IOUs. + && saCurDeliverReq) // Need some issued. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct); } - // Previous issue part 1: issue -> redeem - if (bRedeem // Allowed to redeem. - && saCurRedeemReq != saCurRedeemAct // Can only redeem if more to be redeemed. - && !saPrvBalance.isNegative()) // Previous has no IOUs. - { - // Rate: quality in : quality out - calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); - } - - // Previous issue part 2 : issue -> issue - if (bIssue // Allowed to issue. - && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. - && !saPrvBalance.isNegative() // Previous has no IOUs. - && saCurIssueReq != saCurIssueAct) // Need some issued. + // issue -> deliver/issue + if (bPrvIssue + && bIssue // Allowed to issue. + && !saPrvBalance.isNegative() // Previous issuing: Previous has no IOUs. + && saCurDeliverReq != saCurDeliverAct) // Need some issued. { // Rate: quality in : 1.0 - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurDeliverReq, saPrvIssueAct, saCurDeliverAct); } - if (!saCurRedeemAct && !saCurIssueAct) + if (!saCurDeliverAct) { // Must want something. // terResult = tenBAD_AMOUNT; bSuccess = false; } } + else if (!bPrvAccount && bNxtAccount) + { + if (uIndex == uLast) + { + // offer --> ACCOUNT --> $ + + // Rate: quality in : 1.0 + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct); + + if (!saCurWantedAct) + { + // Must have processed something. + // terResult = tenBAD_AMOUNT; + bSuccess = false; + } + } + else + { + // offer --> ACCOUNT --> account + // Note: offer is always deliver/redeeming as account is issuer. + + // deliver -> redeem + if (bRedeem // Allowed to redeem. + && saCurRedeemReq // Next wants us to redeem. + && saPrvBalance.isNegative()) // Previous has IOUs to redeem. + { + // Rate : 1.0 : quality out + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct); + } + + // deliver -> issue. + if (bIssue // Allowed to issue. + && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. + && saPrvBalance.isNegative() // Previous still has IOUs. + && saCurIssueReq) // Need some issued. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct); + } + + if (!saCurDeliverAct && !saCurIssueAct) + { + // Must want something. + // terResult = tenBAD_AMOUNT; + bSuccess = false; + } + } + } else { - // Previous is a offer. + // offer --> ACCOUNT --> offer + // deliver/redeem -> deliver/issue. + if (bIssue // Allowed to issue. + && saCurDeliverReq != saCurDeliverAct) // Can only if issue if more can not be redeemed. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct); + } + if (!saCurDeliverAct) + { + // Must want something. + // terResult = tenBAD_AMOUNT; + bSuccess = false; + } } + // XXX Need a more nuanced return: temporary fail vs perm? return bSuccess; } +// The previous node: specifies what to push through to current. +// - All of previous output is consumed. +// The current node: specify what to push through to next. +// - Output to next node minus fees. +// Perform balance adjustment with previous. bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) { - bool bSuccess = true; - unsigned int uLast = pspCur->vpnNodes.size() - 1; + bool bSuccess = true; + unsigned int uLast = pspCur->vpnNodes.size() - 1; + + paymentNode& prvPN = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; + paymentNode& curPN = pspCur->vpnNodes[uIndex]; + paymentNode& nxtPN = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; + + bool bRedeem = !!(curPN.uFlags & STPathElement::typeRedeem); + bool bIssue = !!(curPN.uFlags & STPathElement::typeIssue); + bool bPrvAccount = !!(prvPN.uFlags & STPathElement::typeAccount); + bool bNxtAccount = !!(nxtPN.uFlags & STPathElement::typeAccount); + + uint160& uPrvAccountID = prvPN.uAccountID; + uint160& uCurAccountID = curPN.uAccountID; + uint160& uNxtAccountID = bNxtAccount ? nxtPN.uAccountID : uCurAccountID; // Offers are always issue. + + uint160& uCurrencyID = curPN.uCurrencyID; + + uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); + uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); + + // For bNxtAccount + const STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; + STAmount saPrvRedeemAct; + + const STAmount& saPrvIssueReq = prvPN.saFwdIssue; + STAmount saPrvIssueAct; + + // For !bPrvAccount + const STAmount& saPrvDeliverReq = prvPN.saRevDeliver; + STAmount saPrvDeliverAct; + + // For bNxtAccount + const STAmount& saCurRedeemReq = curPN.saRevRedeem; + STAmount& saCurRedeemAct = curPN.saFwdRedeem; + + const STAmount& saCurIssueReq = curPN.saRevIssue; + STAmount& saCurIssueAct = curPN.saFwdIssue; + + // For !bNxtAccount + const STAmount& saCurDeliverReq = curPN.saRevDeliver; + STAmount& saCurDeliverAct = curPN.saFwdDeliver; + + STAmount& saCurReceive = pspCur->saOutAct; // Ripple through account. - if (!uIndex) + + if (bPrvAccount && bNxtAccount) { - // First node, calculate amount to send. - // XXX Use stamp/ripple balance - paymentNode& curPN = pspCur->vpnNodes[uIndex]; - - STAmount& saCurRedeemReq = curPN.saRevRedeem; - STAmount& saCurRedeemAct = curPN.saFwdRedeem; - STAmount& saCurIssueReq = curPN.saRevIssue; - STAmount& saCurIssueAct = curPN.saFwdIssue; - - STAmount& saCurSendMaxReq = pspCur->saInReq; - STAmount& saCurSendMaxAct = pspCur->saInAct; - - if (saCurRedeemReq) + if (!uIndex) { - // Redeem requested. - saCurRedeemAct = MIN(saCurRedeemAct, saCurSendMaxReq); - saCurSendMaxAct = saCurRedeemAct; + // ^ --> ACCOUNT --> account + + // First node, calculate amount to send. + // XXX Use stamp/ripple balance + paymentNode& curPN = pspCur->vpnNodes[uIndex]; + + STAmount& saCurRedeemReq = curPN.saRevRedeem; + STAmount& saCurRedeemAct = curPN.saFwdRedeem; + STAmount& saCurIssueReq = curPN.saRevIssue; + STAmount& saCurIssueAct = curPN.saFwdIssue; + + STAmount& saCurSendMaxReq = pspCur->saInReq; + STAmount& saCurSendMaxAct = pspCur->saInAct; + + if (saCurRedeemReq) + { + // Redeem requested. + saCurRedeemAct = MIN(saCurRedeemAct, saCurSendMaxReq); + saCurSendMaxAct = saCurRedeemAct; + } + + if (saCurIssueReq && saCurSendMaxReq != saCurRedeemAct) + { + // Issue requested and not over budget. + saCurIssueAct = MIN(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); + // saCurSendMaxAct += saCurIssueReq; // Not needed. + } } - - if (saCurIssueReq && saCurSendMaxReq != saCurRedeemAct) + else if (uIndex == uLast) { - // Issue requested and not over budget. - saCurIssueAct = MIN(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); - // saCurSendMaxAct += saCurIssueReq; // Not needed. + // account --> ACCOUNT --> $ + + // Last node. Accept all funds. Calculate amount actually to credit. + + STAmount saIssueCrd = uQualityIn >= QUALITY_ONE + ? saPrvIssueReq // No fee. + : STAmount::multiply(saPrvIssueReq, uQualityIn, uCurrencyID); // Fee. + + // Amount to credit. + saCurReceive = saPrvRedeemReq+saIssueCrd; + + // Actually receive. + rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq+saPrvIssueReq); + } + else + { + // account --> ACCOUNT --> account + + // Previous redeem part 1: redeem -> redeem + if (bRedeem // Can redeem. + && saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. + { + // Rate : 1.0 : quality out + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); + } + + // Previous redeem part 2: redeem -> issue. + // wants to redeem and current would and can issue. + // If redeeming cur to next is done, this implies can issue. + if (bIssue // Can issue. + && saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem. + && saCurRedeemReq == saCurRedeemAct // Current has no more to redeem to next. + && saCurIssueReq) + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + } + + // Previous issue part 1: issue -> redeem + if (bRedeem // Can redeem. + && saPrvIssueReq != saPrvIssueAct // Previous wants to issue. + && saCurRedeemReq != saCurRedeemAct) // Current has more to redeem to next. + { + // Rate: quality in : quality out + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); + } + + // Previous issue part 2 : issue -> issue + if (bIssue // Can issue. + && saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. + { + // Rate: quality in : 1.0 + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); + } + + // Adjust prv --> cur balance : take all inbound + // XXX Currency must be in amount. + rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq); } } - else if (uIndex == uLast) + else if (bPrvAccount && !bNxtAccount) { - // Last node. Accept all funds. Calculate amount actually to credit. - paymentNode& prvPN = pspCur->vpnNodes[uIndex-1]; - paymentNode& curPN = pspCur->vpnNodes[uIndex]; + // account --> ACCOUNT --> offer - uint32 uQualityIn = rippleQualityIn(curPN.uAccountID, prvPN.uAccountID, curPN.uCurrencyID); - STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; - STAmount& saPrvIssueReq = prvPN.saFwdIssue; - STAmount saPrvIssueAct = uQualityIn >= QUALITY_ONE - ? saPrvIssueReq // No fee. - : STAmount::multiply(saPrvIssueReq, uQualityIn, curPN.uCurrencyID); // Fee. - STAmount& saCurReceive = pspCur->saOutAct; - - // Amount to credit. - saCurReceive = saPrvRedeemReq+saPrvIssueAct; - - // Actually receive. - rippleCredit(curPN.uAccountID, prvPN.uAccountID, saCurReceive); - } - else - { - // Handle middle node. - // The previous nodes tells want it wants to push through to current. - // The current node know what it would push through next. - // Determine for the current node: - // - Output to next node minus fees. - // Perform balance adjustment with previous. - // All of previous output is consumed. - - paymentNode& prvPN = pspCur->vpnNodes[uIndex-1]; - paymentNode& curPN = pspCur->vpnNodes[uIndex]; - paymentNode& nxtPN = pspCur->vpnNodes[uIndex+1]; - - uint160& uCurrencyID = curPN.uCurrencyID; - - uint160& uPrvAccountID = prvPN.uAccountID; - uint160& uCurAccountID = curPN.uAccountID; - uint160& uNxtAccountID = nxtPN.uAccountID; - - STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; - STAmount saPrvRedeemAct; - STAmount& saPrvIssueReq = prvPN.saFwdIssue; - STAmount saPrvIssueAct; - - STAmount& saCurRedeemReq = curPN.saRevRedeem; - STAmount& saCurRedeemAct = curPN.saFwdRedeem; - STAmount& saCurIssueReq = curPN.saRevIssue; - STAmount& saCurIssueAct = curPN.saFwdIssue; - - // Have funds in previous node to transfer. - uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); - uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); - - // Previous redeem part 1: redeem -> redeem - if (saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. - { - // Rate : 1.0 : quality out - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); - } - - // Previous redeem part 2: redeem -> issue. + // redeem -> issue. // wants to redeem and current would and can issue. // If redeeming cur to next is done, this implies can issue. - if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem. - && saCurRedeemReq == saCurRedeemAct) // Current has more to redeem to next. + if (saPrvRedeemReq) // Previous wants to redeem. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct); } - // Previous issue part 1: issue -> redeem - if (saPrvIssueReq != saPrvIssueAct // Previous wants to issue. - && saCurRedeemReq == saCurRedeemAct) // Current has more to redeem to next. - { - // Rate: quality in : quality out - calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); - } - - // Previous issue part 2 : issue -> issue - if (saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. + // issue -> issue + 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, saCurIssueReq, saPrvIssueAct, saCurIssueAct); + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurDeliverReq, saPrvIssueAct, saCurDeliverAct); } // Adjust prv --> cur balance : take all inbound // XXX Currency must be in amount. - rippleCredit(uCurAccountID, uPrvAccountID, saPrvRedeemReq + saPrvIssueReq); + rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq); + } + else if (!bPrvAccount && bNxtAccount) + { + if (uIndex == uLast) + { + // offer --> ACCOUNT --> $ + + // Amount to credit. + saCurReceive = saPrvDeliverAct; + + // No income balance adjustments necessary. The paying side inside the offer paid to this account. + } + else + { + // offer --> ACCOUNT --> account + + // deliver -> redeem + if (bRedeem // Allowed to redeem. + && saPrvDeliverReq) // Previous wants to deliver. + { + // Rate : 1.0 : quality out + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct); + } + + // deliver -> issue + // Wants to redeem and current would and can issue. + if (bIssue // Allowed to issue. + && saPrvDeliverReq != saPrvDeliverAct // Previous still wants to deliver. + && saCurRedeemReq == saCurRedeemAct // Current has more to redeem to next. + && saCurIssueReq) // Current wants issue. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + } + + // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. + } + } + else + { + // offer --> ACCOUNT --> offer + // deliver/redeem -> deliver/issue. + if (bIssue // Allowed to issue. + && saPrvDeliverReq // Previous wants to deliver + && saCurIssueReq) // Current wants issue. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct); + } + + // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. } return bSuccess; @@ -2852,7 +3047,8 @@ bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::poi return lhs->mIndex > rhs->mIndex; // Bigger is worse. } -// <-- bValid: true, if node is valid. +// Add a node and insert any implied nodes. +// <-- bValid: true, if node is valid. false, if node is malformed. bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) { paymentNode pnCur; @@ -2883,29 +3079,32 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin // 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 + 0, + ACCOUNT_ONE, + CURRENCY_ONE, // Inherit from previous + ACCOUNT_ONE); // Inherit from previous } - else if (uIssuerID != pnPrv.uIssuerID) + + if (bValid && 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. + STPathElement::typeAccount + | STPathElement::typeRedeem + | STPathElement::typeIssue, + uIssuerID, + CURRENCY_ONE, // Inherit from previous + ACCOUNT_ONE); // Default same as account. } + + if (bValid) + vpnNodes.push_back(pnCur); } else { @@ -2921,13 +3120,38 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin } else { + pnCur.uAccountID = uAccountID; pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; - pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; + pnCur.uIssuerID = bIssuer ? uIssuerID : pnCur.uAccountID; + + if (!!pnPrv.uAccountID // Previous is an account. + && pnPrv.uAccountID != pnCur.uIssuerID) // Account is not issuer. + { + // Implied preceeding account. + + bValid = pushNode( + STPathElement::typeAccount + | STPathElement::typeIssue, + uIssuerID, + CURRENCY_ONE, // Inherit from previous + ACCOUNT_ONE); // Default same as account. + } + else if (bValid) + { + // Verify that previous account is allowed to issue. + const paymentNode& pnLst = vpnNodes.back(); + bool bLstAccount = !!(pnLst.uFlags & STPathElement::typeAccount); + bool bLstIssue = !!(pnLst.uFlags & STPathElement::typeIssue); + + if (bLstAccount && !bLstIssue) + bValid = false; // Malformed path. + } + + if (bValid) + vpnNodes.push_back(pnCur); } } - vpnNodes.push_back(pnCur); - return bValid; } From e0aa5f287fee435c555206c7114358e4d56cdc29 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 02:19:18 -0700 Subject: [PATCH 023/426] Some asserts to help track down a bug (that seems impossible) that Jed reported. --- src/LedgerHistory.cpp | 4 +++- src/LedgerMaster.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/LedgerHistory.cpp b/src/LedgerHistory.cpp index 8f9b1bec9e..79ff9ac615 100644 --- a/src/LedgerHistory.cpp +++ b/src/LedgerHistory.cpp @@ -32,7 +32,9 @@ void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger) uint256 h(ledger->getHash()); boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex()); mLedgersByHash.canonicalize(h, ledger); - assert(ledger && ledger->isAccepted() && ledger->isImmutable()); + assert(ledger); + assert(ledger->isAccepted()); + assert(ledger->isImmutable()); mLedgersByIndex.insert(std::make_pair(ledger->getLedgerSeq(), ledger)); boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, ledger)); thread.detach(); diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp index f5bb19646a..7350b85349 100644 --- a/src/LedgerMaster.cpp +++ b/src/LedgerMaster.cpp @@ -42,6 +42,8 @@ void LedgerMaster::pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL) if (newLCL->isAccepted()) { + assert(newLCL->isClosed()); + assert(newLCL->isImmutable()); mLedgerHistory.addAcceptedLedger(newLCL); Log(lsINFO) << "StashAccepted: " << newLCL->getHash().GetHex(); } From eaf0ffa08f06a72073de9aea1b396e6f537a3e41 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 03:10:29 -0700 Subject: [PATCH 024/426] Possible fix for a bug Jed reported. --- src/LedgerHistory.cpp | 4 ++-- src/TaggedCache.h | 52 +++++++++++++++++++++++++++---------------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/LedgerHistory.cpp b/src/LedgerHistory.cpp index 79ff9ac615..0445b268d5 100644 --- a/src/LedgerHistory.cpp +++ b/src/LedgerHistory.cpp @@ -23,7 +23,7 @@ LedgerHistory::LedgerHistory() : mLedgersByHash(CACHED_LEDGER_NUM, CACHED_LEDGER void LedgerHistory::addLedger(Ledger::pointer ledger) { - mLedgersByHash.canonicalize(ledger->getHash(), ledger); + mLedgersByHash.canonicalize(ledger->getHash(), ledger, true); } void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger) @@ -31,7 +31,7 @@ void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger) assert(ledger && ledger->isAccepted()); uint256 h(ledger->getHash()); boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex()); - mLedgersByHash.canonicalize(h, ledger); + mLedgersByHash.canonicalize(h, ledger, true); assert(ledger); assert(ledger->isAccepted()); assert(ledger->isImmutable()); diff --git a/src/TaggedCache.h b/src/TaggedCache.h index bb5dc36667..92a122d017 100644 --- a/src/TaggedCache.h +++ b/src/TaggedCache.h @@ -1,8 +1,6 @@ #ifndef __TAGGEDCACHE__ #define __TAGGEDCACHE__ -#include - #include #include #include @@ -21,18 +19,18 @@ template class TaggedCache { public: - typedef c_Key key_type; - typedef c_Data data_type; + typedef c_Key key_type; + typedef c_Data data_type; - typedef boost::weak_ptr weak_data_ptr; - typedef boost::shared_ptr data_ptr; - - typedef std::pair cache_entry; + typedef boost::weak_ptr weak_data_ptr; + typedef boost::shared_ptr data_ptr; + typedef std::pair cache_entry; protected: mutable boost::recursive_mutex mLock; int mTargetSize, mTargetAge; + boost::unordered_map mCache; // Hold strong reference to recent objects time_t mLastSweep; @@ -40,6 +38,7 @@ protected: public: TaggedCache(int size, int age) : mTargetSize(size), mTargetAge(age), mLastSweep(time(NULL)) { ; } + int getTargetSize() const; int getTargetAge() const; @@ -52,7 +51,7 @@ public: bool touch(const key_type& key); bool del(const key_type& key); - bool canonicalize(const key_type& key, boost::shared_ptr& data); + bool canonicalize(const key_type& key, boost::shared_ptr& data, bool replace = false); bool store(const key_type& key, const c_Data& data); boost::shared_ptr fetch(const key_type& key); bool retrieve(const key_type& key, c_Data& data); @@ -82,10 +81,12 @@ template void TaggedCache::sweep { boost::recursive_mutex::scoped_lock sl(mLock); - if (mCache.size() < mTargetSize) return; + if (mCache.size() < mTargetSize) + return; time_t now = time(NULL); - if ((mLastSweep + 10) < now) return; + if ((mLastSweep + 10) < now) + return; mLastSweep = now; time_t target = now - mTargetAge; @@ -99,7 +100,8 @@ template void TaggedCache::sweep typename boost::unordered_map::iterator tmp = cit++; mCache.erase(tmp); } - else ++cit; + else + ++cit; } // Pass 2, remove dead objects from map @@ -111,7 +113,8 @@ template void TaggedCache::sweep typename boost::unordered_map::iterator tmp = mit++; mMap.erase(mit); } - else ++mit; + else + ++mit; } } @@ -121,7 +124,8 @@ template bool TaggedCache::touch // Is the object in the map? typename boost::unordered_map::iterator mit = mMap.find(key); - if (mit == mMap.end()) return false; + if (mit == mMap.end()) + return false; if (mit->second.expired()) { // in map, but expired mMap.erase(mit); @@ -146,13 +150,14 @@ template bool TaggedCache::del(c boost::recursive_mutex::scoped_lock sl(mLock); typename boost::unordered_map::iterator cit = mCache.find(key); - if (cit == mCache.end()) return false; + if (cit == mCache.end()) + return false; mCache.erase(cit); return true; } template -bool TaggedCache::canonicalize(const key_type& key, boost::shared_ptr& data) +bool TaggedCache::canonicalize(const key_type& key, boost::shared_ptr& data, bool replace) { // Return canonical value, store if needed, refresh in cache // Return values: true=we had the data already boost::recursive_mutex::scoped_lock sl(mLock); @@ -172,13 +177,21 @@ bool TaggedCache::canonicalize(const key_type& key, boost::shared mCache.insert(std::make_pair(key, std::make_pair(time(NULL), data))); return false; } - - data = cachedData; + + // in map and cache, canonicalize + if (replace) + mit->second = data; + else + data = cachedData; // Valid in map, is it in cache? typename boost::unordered_map::iterator cit = mCache.find(key); if (cit != mCache.end()) + { cit->second.first = time(NULL); // Yes, refesh + if (replace) + cit->second.second = data; + } else // no, add to cache mCache.insert(std::make_pair(key, std::make_pair(time(NULL), data))); @@ -192,7 +205,8 @@ boost::shared_ptr TaggedCache::fetch(const key_type& key) // Is it in the map? typename boost::unordered_map::iterator mit = mMap.find(key); - if (mit == mMap.end()) return data_ptr(); // No, we're done + if (mit == mMap.end()) + return data_ptr(); // No, we're done boost::shared_ptr cachedData = mit->second.lock(); if (!cachedData) From c5acd0f630e6b2b186ff38f0f8b6d382868e9b6f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 03:10:43 -0700 Subject: [PATCH 025/426] Cleanups. --- src/LedgerConsensus.cpp | 53 ++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index b9bd543450..3f5fd06e11 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -536,35 +536,42 @@ void LedgerConsensus::updateOurPositions() mHaveCloseTimeConsensus = true; closeTime = mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution); } - if (mProposing) + else { - ++closeTimes[mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)]; - ++thresh; - } - thresh = thresh * neededWeight / 100; - - for (std::map::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it) - { - Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << " out of " << thresh; - if (it->second > thresh) + if (mProposing) { - Log(lsINFO) << "Close time consensus reached: " << closeTime; - mHaveCloseTimeConsensus = true; - closeTime = it->first; + ++closeTimes[mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)]; + ++thresh; + } + thresh = thresh * neededWeight / 100; + + for (std::map::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it) + { + Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << " out of " << thresh; + if (it->second > thresh) + { + Log(lsINFO) << "Close time consensus reached: " << closeTime; + mHaveCloseTimeConsensus = true; + closeTime = it->first; + } } } if (closeTime != (mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution))) { - ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); - changes = true; + if (!changes) + { + ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); + changes = true; + } } if (changes) { uint256 newHash = ourPosition->getHash(); mOurPosition->changePosition(newHash, closeTime); - if (mProposing) propose(addedTx, removedTx); + if (mProposing) + propose(addedTx, removedTx); mapComplete(newHash, ourPosition, false); Log(lsINFO) << "Position change: CTime " << closeTime << ", tx " << newHash.GetHex(); } @@ -701,30 +708,26 @@ bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition) assert(newPosition->getPeerID() == currentPosition->getPeerID()); if (newPosition->getProposeSeq() <= currentPosition->getProposeSeq()) return false; - if (newPosition->getCurrentHash() == currentPosition->getCurrentHash()) - { // we missed an intermediary change - Log(lsINFO) << "We missed an intermediary position"; - currentPosition = newPosition; - return true; - } } - else if (newPosition->getProposeSeq() == 0) + + if (newPosition->getProposeSeq() == 0) { // new initial close time estimate Log(lsTRACE) << "Peer reports close time as " << newPosition->getCloseTime(); ++mCloseTimes[newPosition->getCloseTime()]; } + Log(lsINFO) << "Processing peer proposal " << newPosition->getProposeSeq() << "/" << newPosition->getCurrentHash().GetHex(); currentPosition = newPosition; SHAMap::pointer set = getTransactionTree(newPosition->getCurrentHash(), true); if (set) { - Log(lsTRACE) << "Have that set"; for (boost::unordered_map::iterator it = mDisputes.begin(), end = mDisputes.end(); it != end; ++it) it->second->setVote(newPosition->getPeerID(), set->hasItem(it->first)); } - else Log(lsTRACE) << "Don't have that set"; + else + Log(lsTRACE) << "Don't have that tx set"; return true; } From d3daa2fc00a47df7c0b4b5556c6e0ca6350f2218 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 04:53:50 -0700 Subject: [PATCH 026/426] Extra debug to help rule out the possibility that our ledgers are diverging after we are in sync. --- src/LedgerConsensus.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 3f5fd06e11..ede0804cc4 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -869,9 +869,15 @@ void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer app void LedgerConsensus::accept(SHAMap::pointer set) { assert(set->getHash() == mOurPosition->getCurrentHash()); + + uint32 closeTime = mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() & mCloseResolution); + Log(lsINFO) << "Computing new LCL based on network consensus"; - Log(lsDEBUG) << "Consensus " << mOurPosition->getCurrentHash().GetHex(); - Log(lsDEBUG) << "Previous LCL " << mPrevLedgerHash.GetHex(); + if (mHaveCorrectLCL) + { + Log(lsINFO) << "CNF tx " << mOurPosition->getCurrentHash().GetHex() << ", close " << closeTime; + Log(lsINFO) << "CNF oldLCL " << mPrevLedgerHash.GetHex(); + } Ledger::pointer newLCL = boost::make_shared(false, boost::ref(*mPreviousLedger)); newLCL->armDirty(); @@ -880,20 +886,17 @@ void LedgerConsensus::accept(SHAMap::pointer set) applyTransactions(set, newLCL, newLCL, failedTransactions, true); newLCL->setClosed(); - uint32 closeTime = mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() & mCloseResolution); bool closeTimeCorrect = true; if (closeTime == 0) { // we agreed to disagree closeTimeCorrect = false; closeTime = mPreviousLedger->getCloseTimeNC() + 1; - Log(lsINFO) << "Consensus close time (good) " << closeTime; + Log(lsINFO) << "CNF badclose " << closeTime; } - else Log(lsINFO) << "Consensus close time (bad) " << closeTime; newLCL->setAccepted(closeTime, mCloseResolution, closeTimeCorrect); newLCL->updateHash(); uint256 newLCLHash = newLCL->getHash(); - Log(lsTRACE) << "newLCL " << newLCLHash.GetHex(); statusChange(newcoin::neACCEPTED_LEDGER, *newLCL); if (mValidating) { @@ -905,8 +908,10 @@ void LedgerConsensus::accept(SHAMap::pointer set) newcoin::TMValidation val; val.set_validation(&validation[0], validation.size()); theApp->getConnectionPool().relayMessage(NULL, boost::make_shared(val, newcoin::mtVALIDATION)); - Log(lsINFO) << "Validation sent " << newLCLHash.GetHex(); + Log(lsINFO) << "CNF Val " << newLCLHash.GetHex(); } + else + Log(lsINFO) << "CNF newLCL " << newLCLHash.GetHex(); Ledger::pointer newOL = boost::make_shared(true, boost::ref(*newLCL)); ScopedLock sl = theApp->getMasterLedger().getLock(); From d554950efe63f2239949d95dba874027aff614ec Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 14:35:47 -0700 Subject: [PATCH 027/426] One more drop of extra debug. --- src/LedgerConsensus.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index ede0804cc4..1cb3d288cf 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -876,7 +876,8 @@ void LedgerConsensus::accept(SHAMap::pointer set) if (mHaveCorrectLCL) { Log(lsINFO) << "CNF tx " << mOurPosition->getCurrentHash().GetHex() << ", close " << closeTime; - Log(lsINFO) << "CNF oldLCL " << mPrevLedgerHash.GetHex(); + Log(lsINFO) << "CNF mode " << theApp->getOPs().getOperatingMode() + << ", oldLCL " << mPrevLedgerHash.GetHex(); } Ledger::pointer newLCL = boost::make_shared(false, boost::ref(*mPreviousLedger)); From 99a3d833300c90c3a9e7e69c65bd979004179962 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 14:56:08 -0700 Subject: [PATCH 028/426] Indent fix. --- src/LedgerTiming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index ecff1f441a..ae0d65de19 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -17,7 +17,7 @@ int ContinuousLedgerTiming::shouldClose( int previousProposers, // proposers in the last closing int proposersClosed, // proposers who have currently closed this ledgers int previousMSeconds, // seconds the previous ledger took to reach consensus - int currentMSeconds) // seconds since the previous ledger closed + int currentMSeconds) // seconds since the previous ledger closed { if ((previousMSeconds < -1000) || (previousMSeconds > 600000) || (currentMSeconds < -1000) || (currentMSeconds > 600000)) From 0f51774f58612a4971cb9b4929fb234da4d87d49 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 15:10:38 -0700 Subject: [PATCH 029/426] Some paranoid extra checks. --- src/LedgerConsensus.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 1cb3d288cf..7d9f1c3d6c 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -544,6 +544,8 @@ void LedgerConsensus::updateOurPositions() ++thresh; } thresh = thresh * neededWeight / 100; + if (thresh == 0) + thresh = 1; for (std::map::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it) { @@ -553,6 +555,7 @@ void LedgerConsensus::updateOurPositions() Log(lsINFO) << "Close time consensus reached: " << closeTime; mHaveCloseTimeConsensus = true; closeTime = it->first; + thresh = it->second; } } } From 9e41cac0dad99c7d8dcaffbd51c0977027a58c39 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 13 Aug 2012 17:05:35 -0700 Subject: [PATCH 030/426] Add RPC ripple command and improve wallet_propose. --- src/RPCServer.cpp | 286 +++++++++++++++++++++++++++++++++++++--- src/RPCServer.h | 3 + src/SerializedTypes.cpp | 6 + src/SerializedTypes.h | 31 +++-- src/main.cpp | 3 +- 5 files changed, 299 insertions(+), 30 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 0ac81e6b54..46ea9eda7d 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -44,6 +44,7 @@ Json::Value RPCServer::RPCError(int iError) { rpcBAD_SEED, "badSeed", "Disallowed seed." }, { rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." }, { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." }, + { rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exists." }, { rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." }, { rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." }, { rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets ammount malformed." }, @@ -70,8 +71,8 @@ Json::Value RPCServer::RPCError(int iError) { rpcPORT_MALFORMED, "portMalformed", "Port is malformed." }, { rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed." }, { rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." }, + { rpcSRC_ACT_MISSING, "srcActMissing", "Source account does not exist." }, { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency is malformed." }, - { rpcSRC_MISSING, "srcMissing", "Source account does not exist." }, { rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." }, { rpcSUCCESS, "success", "Success." }, { rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." }, @@ -279,7 +280,7 @@ Json::Value RPCServer::authorize(const uint256& uLedger, asSrc = mNetOps->getAccountState(uLedger, naSrcAccountID); if (!asSrc) { - return RPCError(rpcSRC_MISSING); + return RPCError(rpcSRC_ACT_MISSING); } NewcoinAddress naMasterGenerator; @@ -546,7 +547,7 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) { std::string strIdent = params[0u].asString(); bool bIndex; - int iIndex = 2 == params.size()? lexical_cast_s(params[1u].asString()) : 0; + int iIndex = 2 == params.size() ? lexical_cast_s(params[1u].asString()) : 0; NewcoinAddress naAccount; Json::Value ret; @@ -1385,6 +1386,239 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) } } + +// ripple +// [noredeem] [noissue] +// + +// full|partial +// +// path: +// path + +// +// path_element: +// account [] [] [noredeem] [noissue] +// offer [] +Json::Value RPCServer::doRipple(const Json::Value ¶ms) +{ + NewcoinAddress naSeed; + STAmount saSrcAmountMax; + uint160 uSrcCurrencyID; + NewcoinAddress naSrcAccountID; + bool bSrcRedeem = true; + bool bSrcIssue = true; + bool bPartial; + bool bFull; + NewcoinAddress naDstAccountID; + STAmount saDstAmount; + uint160 uDstCurrencyID; + NewcoinAddress naDstIssuerID; + + std::vector vpnPath; + STPathSet spsPaths; + + if (!naSeed.setSeedGeneric(params[0u].asString())) // + { + return RPCError(rpcBAD_SEED); + } + else if (!naSrcAccountID.setAccountID(params[1u].asString())) // + { + return RPCError(rpcSRC_ACT_MALFORMED); + } + // + else if (!saSrcAmountMax.setFullValue(params[2u].asString(), params[3u].asString(), params[4u].asString())) + { + return RPCError(rpcSRC_AMT_MALFORMED); + } + + int iArg = 5; + + if (params[iArg].asString() == "noredeem") // [noredeem] + { + ++iArg; + bSrcRedeem = false; + } + + if (params[iArg].asString() == "noissue") // [noissue] + { + ++iArg; + bSrcIssue = false; + } + + // XXX bSrcRedeem & bSrcIssue not used. + STPath spPath; + + while (params.size() != iArg && params[iArg].asString() == "path") // path + { + Log(lsINFO) << "Path>"; + ++iArg; + + while (params.size() != iArg + && (params[iArg].asString() == "offer" || params[iArg].asString() == "account")) + { + if (params.size() >= iArg + 3 && params[iArg].asString() == "offer") // offer + { + Log(lsINFO) << "Offer>"; + uint160 uCurrencyID; + NewcoinAddress naIssuerID; + + ++iArg; + + if (!STAmount::currencyFromString(uCurrencyID, params[iArg++].asString())) // + { + return RPCError(rpcINVALID_PARAMS); + } + else if (naIssuerID.setAccountID(params[iArg].asString())) // [] + { + ++iArg; + } + + spPath.addElement(STPathElement( + uint160(0), + uCurrencyID, + naIssuerID.isValid() ? naIssuerID.getAccountID() : uint160(0))); + } + else if (params.size() >= iArg + 2 && params[iArg].asString() == "account") // account + { + Log(lsINFO) << "Account>"; + NewcoinAddress naAccountID; + uint160 uCurrencyID; + NewcoinAddress naIssuerID; + bool bRedeem = true; + bool bIssue = true; + + ++iArg; + + if (!naAccountID.setAccountID(params[iArg++].asString())) // + { + return RPCError(rpcINVALID_PARAMS); + } + + if (params.size() != iArg && STAmount::currencyFromString(uCurrencyID, params[iArg].asString())) // [] + { + ++iArg; + } + + if (params.size() != iArg && naIssuerID.setAccountID(params[iArg].asString())) // [] + { + ++iArg; + } + + if (params.size() != iArg && params[iArg].asString() == "noredeem") // [noredeem] + { + ++iArg; + bRedeem = false; + } + + if (params.size() != iArg && params[iArg].asString() == "noissue") // [noissue] + { + ++iArg; + bIssue = false; + } + + spPath.addElement(STPathElement( + naAccountID.getAccountID(), + uCurrencyID, + naIssuerID.isValid() ? naIssuerID.getAccountID() : uint160(0), + bRedeem, + bIssue)); + } + else + { + return RPCError(rpcINVALID_PARAMS); + } + } + + if (spPath.isEmpty()) + { + return RPCError(rpcINVALID_PARAMS); + } + else + { + spsPaths.addPath(spPath); + spPath.clear(); + } + } + + // full|partial + bPartial = params.size() != iArg ? params[iArg].asString() == "partial" : false; + bFull = params.size() != iArg ? params[iArg].asString() == "full" : false; + + if (!bPartial && !bFull) + { + return RPCError(rpcINVALID_PARAMS); + } + else + { + ++iArg; + } + + if (params.size() != iArg && !naDstAccountID.setAccountID(params[iArg++].asString())) // + { + return RPCError(rpcDST_ACT_MALFORMED); + } + // + else if (params.size() != iArg + 3 || !saDstAmount.setFullValue(params[iArg].asString(), params[iArg+1].asString(), params[iArg+2].asString())) + { + Log(lsINFO) << "params.size(): " << params.size(); + Log(lsINFO) << " iArg: " << iArg; + Log(lsINFO) << " Amount: " << params[iArg].asString(); + Log(lsINFO) << "Currency: " << params[iArg+1].asString(); + Log(lsINFO) << " Issuer: " << params[iArg+2].asString(); + + return RPCError(rpcDST_AMT_MALFORMED); + } + + uint256 uLedger = mNetOps->getCurrentLedger(); + AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID); + STAmount saFee = theConfig.FEE_DEFAULT; + + NewcoinAddress naVerifyGenerator; + NewcoinAddress naAccountPublic; + NewcoinAddress naAccountPrivate; + AccountState::pointer asSrc; + STAmount saSrcBalance; + Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + saSrcBalance, saFee, asSrc, naVerifyGenerator); + + if (!obj.empty()) + return obj; + + // YYY Could do some checking: source has funds or credit, dst exists and has sufficent credit limit. + // YYY Currency from same source or loops not allowed. + // YYY Limit paths length and count. + if (!asDst) + { + return RPCError(rpcDST_ACT_MISSING); + } + + Transaction::pointer trans = Transaction::sharedPayment( + naAccountPublic, naAccountPrivate, + naSrcAccountID, + asSrc->getSeq(), + saFee, + 0, // YYY No source tag + naDstAccountID, + saDstAmount, + saSrcAmountMax, + spsPaths); + + trans = mNetOps->submitTransaction(trans); + + obj["transaction"] = trans->getSTransaction()->getJson(0); + obj["status"] = trans->getStatus(); + obj["seed"] = naSeed.humanSeed(); + obj["fee"] = saFee.getText(); + obj["srcAccountID"] = naSrcAccountID.humanAccountID(); + obj["dstAccountID"] = naDstAccountID.humanAccountID(); + obj["srcAmountMax"] = saSrcAmountMax.getText(); + obj["srcISO"] = saSrcAmountMax.getHumanCurrency(); + obj["dstAmount"] = saDstAmount.getText(); + obj["dstISO"] = saDstAmount.getHumanCurrency(); + obj["paths"] = spsPaths.getText(); + + return obj; +} + // ripple_lines_get || [] Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) { @@ -1393,7 +1627,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) std::string strIdent = params[0u].asString(); bool bIndex; - int iIndex = 2 == params.size()? lexical_cast_s(params[1u].asString()) : 0; + int iIndex = 2 == params.size() ? lexical_cast_s(params[1u].asString()) : 0; NewcoinAddress naAccount; @@ -1501,11 +1735,10 @@ Json::Value RPCServer::doSend(const Json::Value& params) NewcoinAddress naSeed; NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; - STAmount saSrcAmount; + STAmount saSrcAmountMax; STAmount saDstAmount; std::string sSrcCurrency; std::string sDstCurrency; - uint256 uLedger = mNetOps->getCurrentLedger(); if (params.size() >= 5) sDstCurrency = params[4u].asString(); @@ -1529,12 +1762,13 @@ Json::Value RPCServer::doSend(const Json::Value& params) { return RPCError(rpcDST_AMT_MALFORMED); } - else if (params.size() >= 6 && !saSrcAmount.setFullValue(params[5u].asString(), sSrcCurrency)) + else if (params.size() >= 6 && !saSrcAmountMax.setFullValue(params[5u].asString(), sSrcCurrency)) { return RPCError(rpcSRC_AMT_MALFORMED); } else { + uint256 uLedger = mNetOps->getCurrentLedger(); AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID); bool bCreate = !asDst; STAmount saFee = bCreate ? theConfig.FEE_ACCOUNT_CREATE : theConfig.FEE_DEFAULT; @@ -1551,10 +1785,10 @@ Json::Value RPCServer::doSend(const Json::Value& params) return obj; if (params.size() < 6) - saSrcAmount = saDstAmount; + saSrcAmountMax = saDstAmount; // Do a few simple checks. - if (!saSrcAmount.isNative()) + if (!saSrcAmountMax.isNative()) { Log(lsINFO) << "doSend: Ripple"; @@ -1567,11 +1801,11 @@ Json::Value RPCServer::doSend(const Json::Value& params) return RPCError(rpcINSUF_FUNDS); } - else if (saDstAmount.isNative() && saSrcAmount < saDstAmount) + else if (saDstAmount.isNative() && saSrcAmountMax < saDstAmount) { // Not enough native currency. - Log(lsINFO) << "doSend: Insufficient funds: src=" << saSrcAmount.getText() << " dst=" << saDstAmount.getText(); + Log(lsINFO) << "doSend: Insufficient funds: src=" << saSrcAmountMax.getText() << " dst=" << saDstAmount.getText(); return RPCError(rpcINSUF_FUNDS); } @@ -1582,7 +1816,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) if (asDst) { // Destination exists, ordinary send. - STPathSet spPaths; + STPathSet spsPaths; trans = Transaction::sharedPayment( naAccountPublic, naAccountPrivate, @@ -1592,8 +1826,8 @@ Json::Value RPCServer::doSend(const Json::Value& params) 0, // YYY No source tag naDstAccountID, saDstAmount, - saSrcAmount, - spPaths); + saSrcAmountMax, + spsPaths); } else { @@ -1618,8 +1852,8 @@ Json::Value RPCServer::doSend(const Json::Value& params) obj["create"] = bCreate; obj["srcAccountID"] = naSrcAccountID.humanAccountID(); obj["dstAccountID"] = naDstAccountID.humanAccountID(); - obj["srcAmount"] = saSrcAmount.getText(); - obj["srcISO"] = saSrcAmount.getHumanCurrency(); + obj["srcAmountMax"] = saSrcAmountMax.getText(); + obj["srcISO"] = saSrcAmountMax.getHumanCurrency(); obj["dstAmount"] = saDstAmount.getText(); obj["dstISO"] = saDstAmount.getHumanCurrency(); @@ -2156,13 +2390,21 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) return obj; } -// wallet_propose +// wallet_propose [] +// is only for testing. Master seeds should only be generated randomly. Json::Value RPCServer::doWalletPropose(const Json::Value& params) { NewcoinAddress naSeed; NewcoinAddress naAccount; - naSeed.setSeedRandom(); + if (params.empty()) + { + naSeed.setSeedRandom(); + } + else + { + naSeed = NewcoinAddress::createSeedGeneric(params[0u].asString()); + } NewcoinAddress naGenerator = NewcoinAddress::createGeneratorPublic(naSeed); naAccount.setAccountPublic(naGenerator, 0); @@ -2332,7 +2574,8 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "password_fund", &RPCServer::doPasswordFund, 2, 3, false, optCurrent }, { "password_set", &RPCServer::doPasswordSet, 2, 3, false, optNetwork }, { "peers", &RPCServer::doPeers, 0, 0, true }, - { "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent|optClosed }, + { "ripple", &RPCServer::doRipple, 10, -1, false, optCurrent|optClosed }, + { "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent }, { "ripple_line_set", &RPCServer::doRippleLineSet, 4, 7, false, optCurrent }, { "send", &RPCServer::doSend, 3, 7, false, optCurrent }, { "server_info", &RPCServer::doServerInfo, 0, 0, true }, @@ -2354,7 +2597,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "wallet_add", &RPCServer::doWalletAdd, 3, 5, false, optCurrent }, { "wallet_claim", &RPCServer::doWalletClaim, 2, 4, false, optNetwork }, { "wallet_create", &RPCServer::doWalletCreate, 3, 4, false, optCurrent }, - { "wallet_propose", &RPCServer::doWalletPropose, 0, 0, false, }, + { "wallet_propose", &RPCServer::doWalletPropose, 0, 1, false, }, { "wallet_seed", &RPCServer::doWalletSeed, 0, 1, false, }, { "login", &RPCServer::doLogin, 2, 2, true }, @@ -2373,7 +2616,8 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { return RPCError(rpcNO_PERMISSION); } - else if (params.size() < commandsA[i].iMinParams || params.size() > commandsA[i].iMaxParams) + else if (params.size() < commandsA[i].iMinParams + || (commandsA[i].iMaxParams >= 0 && params.size() > commandsA[i].iMaxParams)) { return RPCError(rpcINVALID_PARAMS); } diff --git a/src/RPCServer.h b/src/RPCServer.h index 539dcf2e7d..eb847b2e07 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -50,6 +50,7 @@ public: rpcACT_MALFORMED, rpcBAD_SEED, rpcDST_ACT_MALFORMED, + rpcDST_ACT_MISSING, rpcDST_AMT_MALFORMED, rpcGETS_ACT_MALFORMED, rpcGETS_AMT_MALFORMED, @@ -63,6 +64,7 @@ public: rpcPORT_MALFORMED, rpcPUBLIC_MALFORMED, rpcSRC_ACT_MALFORMED, + rpcSRC_ACT_MISSING, rpcSRC_AMT_MALFORMED, // Internal error (should never happen) @@ -146,6 +148,7 @@ private: Json::Value doPasswordFund(const Json::Value& params); Json::Value doPasswordSet(const Json::Value& params); Json::Value doPeers(const Json::Value& params); + Json::Value doRipple(const Json::Value ¶ms); Json::Value doRippleLinesGet(const Json::Value ¶ms); Json::Value doRippleLineSet(const Json::Value& params); Json::Value doSend(const Json::Value& params); diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index df263827e3..cd759e1ee2 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -346,6 +346,12 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) } while(1); } +bool STPathSet::isEquivalent(const SerializedType& t) const +{ + const STPathSet* v = dynamic_cast(&t); + return v && (value == v->value); +} + int STPathSet::getLength() const { int ret = 0; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index fc5e80d0dd..41bcafc33d 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -290,7 +290,7 @@ public: bool isNative() const { return mIsNative; } bool isZero() const { return mValue == 0; } - bool isNonZero() const { return mValue != 0; } + bool isNonZero() const { return mValue != 0; } bool isNegative() const { return mIsNegative && !isZero(); } bool isPositive() const { return !mIsNegative && !isZero(); } bool isGEZero() const { return !mIsNegative; } @@ -528,23 +528,31 @@ public: typeCurrency = 0x10, // Currency follows. typeIssuer = 0x20, // Issuer follows. typeBoundary = 0xFF, // Boundary between alternate paths. - typeValidBits = 0x3E, // Bits that may be non-zero. + typeValidBits = ( + typeAccount + | typeRedeem + | typeIssue + | typeCurrency + | typeIssuer + ), // Bits that may be non-zero. }; protected: int mType; uint160 mAccountID; - uint160 mCurrency; + uint160 mCurrencyID; uint160 mIssuerID; public: - STPathElement(const uint160& uAccountID, const uint160& uCurrency, const uint160& uIssuerID) - : mAccountID(uAccountID), mCurrency(uCurrency), mIssuerID(uIssuerID) + STPathElement(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID, bool bRedeem=false, bool bIssue=false) + : mAccountID(uAccountID), mCurrencyID(uCurrencyID), mIssuerID(uIssuerID) { mType = (uAccountID.isZero() ? 0 : STPathElement::typeAccount) - | (uCurrency.isZero() ? 0 : STPathElement::typeCurrency) - | (uIssuerID.isZero() ? 0 : STPathElement::typeIssuer); + | (uCurrencyID.isZero() ? 0 : STPathElement::typeCurrency) + | (uIssuerID.isZero() ? 0 : STPathElement::typeIssuer) + | (bRedeem ? STPathElement::typeRedeem : 0) + | (bIssue ? STPathElement::typeIssue : 0); } int getNodeType() const { return mType; } @@ -553,8 +561,11 @@ public: // Nodes are either an account ID or a offer prefix. Offer prefixs denote a class of offers. const uint160& getAccountID() const { return mAccountID; } - const uint160& getCurrency() const { return mCurrency; } + const uint160& getCurrency() const { return mCurrencyID; } const uint160& getIssuerID() const { return mIssuerID; } + + bool operator==(const STPathElement& t) const + { return mType == t.mType && mAccountID == t.mAccountID && mCurrencyID == t.mCurrencyID && mIssuerID == mIssuerID; } }; class STPath @@ -580,6 +591,8 @@ public: std::vector::iterator end() { return mPath.end(); } std::vector::const_iterator begin() const { return mPath.begin(); } std::vector::const_iterator end() const { return mPath.end(); } + + bool operator==(const STPath& t) const { return mPath == t.mPath; } }; inline std::vector::iterator range_begin(STPath & x) @@ -647,6 +660,8 @@ public: void clear() { value.clear(); } void addPath(const STPath& e) { value.push_back(e); } + virtual bool isEquivalent(const SerializedType& t) const; + std::vector::iterator begin() { return value.begin(); } std::vector::iterator end() { return value.end(); } std::vector::const_iterator begin() const { return value.begin(); } diff --git a/src/main.cpp b/src/main.cpp index 49d23edf31..155408170a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -58,6 +58,7 @@ void printHelp(const po::options_description& desc) cout << " password_fund []" << endl; cout << " password_set []" << endl; cout << " peers" << endl; + cout << " ripple ..." << endl; cout << " ripple_lines_get || []" << endl; cout << " ripple_line_set [] []" << endl; cout << " send [] [] []" << endl; @@ -75,7 +76,7 @@ void printHelp(const po::options_description& desc) cout << " wallet_accounts " << endl; cout << " wallet_claim [] []" << endl; cout << " wallet_seed [||]" << endl; - cout << " wallet_propose" << endl; + cout << " wallet_propose []" << endl; } int main(int argc, char* argv[]) From 88e938ec50bb0d05a45f01b8375c74587b89c4bd Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:10:51 -0700 Subject: [PATCH 031/426] Change TXS acquire timeout. --- src/LedgerAcquire.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 2407616bd6..6e13a883c8 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -11,7 +11,7 @@ #include "HashPrefixes.h" // #define LA_DEBUG -#define LEDGER_ACQUIRE_TIMEOUT 2 +#define LEDGER_ACQUIRE_TIMEOUT 1 #define TRUST_NETWORK PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterval(interval), mTimeouts(0), From a7f192c989b0062ac07e659c006e593d8e74081c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:11:00 -0700 Subject: [PATCH 032/426] Cleanups. --- src/LedgerConsensus.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 7d9f1c3d6c..b47a19ee67 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -26,7 +26,10 @@ TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, 1), void TransactionAcquire::done() { if (mFailed) + { + Log(lsWARNING) << "Failed to acqiure TXs " << mHash.GetHex(); theApp->getOPs().mapComplete(mHash, SHAMap::pointer()); + } else theApp->getOPs().mapComplete(mHash, mMap); } @@ -48,7 +51,7 @@ void TransactionAcquire::trigger(Peer::pointer peer, bool timer) *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); sendRequest(tmGL, peer); } - if (mHaveRoot) + else { std::vector nodeIDs; std::vector nodeHashes; ConsensusTransSetSF sf; @@ -67,10 +70,7 @@ void TransactionAcquire::trigger(Peer::pointer peer, bool timer) tmGL.set_itype(newcoin::liTS_CANDIDATE); for (std::vector::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it) *(tmGL.add_nodeids()) = it->getRawString(); - if (peer) - sendRequest(tmGL, peer); - else - sendRequest(tmGL); + sendRequest(tmGL, peer); return; } } From 4aea8c8dfb7efa8eed6ecfac7ed202e330d416df Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:11:15 -0700 Subject: [PATCH 033/426] Use fat root semantics when acquire transaction sets. This might save a pass. --- src/Peer.cpp | 8 +++++--- src/SHAMap.h | 2 +- src/SHAMapSync.cpp | 11 ++++++----- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index 991d18456b..28b79d5024 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -928,7 +928,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) { SHAMap::pointer map; newcoin::TMLedgerData reply; - bool fatLeaves = true; + bool fatLeaves = true, fatRoot = false; if (packet.itype() == newcoin::liTS_CANDIDATE) { // Request is for a transaction candidate set @@ -952,6 +952,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) reply.set_ledgerhash(txHash.begin(), txHash.size()); reply.set_type(newcoin::liTS_CANDIDATE); fatLeaves = false; // We'll already have most transactions + fatRoot = true; // Save a pass } else { // Figure out what ledger they want @@ -1057,7 +1058,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) } std::vector nodeIDs; std::list< std::vector > rawNodes; - if(map->getNodeFat(mn, nodeIDs, rawNodes, fatLeaves)) + if(map->getNodeFat(mn, nodeIDs, rawNodes, fatRoot, fatLeaves)) { std::vector::iterator nodeIDIterator; std::list< std::vector >::iterator rawNodeIterator; @@ -1074,7 +1075,8 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) } } } - if (packet.has_requestcookie()) reply.set_requestcookie(packet.requestcookie()); + if (packet.has_requestcookie()) + reply.set_requestcookie(packet.requestcookie()); PackedMessage::pointer oPacket = boost::make_shared(reply, newcoin::mtLEDGER_DATA); sendPacket(oPacket); } diff --git a/src/SHAMap.h b/src/SHAMap.h index 4bfd7999db..2f9e73d529 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -327,7 +327,7 @@ public: void getMissingNodes(std::vector& nodeIDs, std::vector& hashes, int max, SHAMapSyncFilter* filter); bool getNodeFat(const SHAMapNode& node, std::vector& nodeIDs, - std::list >& rawNode, bool fatLeaves); + std::list >& rawNode, bool fatRoot, bool fatLeaves); bool getRootNode(Serializer& s, SHANodeFormat format); bool addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format); bool addRootNode(const std::vector& rootNode, SHANodeFormat format); diff --git a/src/SHAMapSync.cpp b/src/SHAMapSync.cpp index 25c2d019a0..ed76558906 100644 --- a/src/SHAMapSync.cpp +++ b/src/SHAMapSync.cpp @@ -86,7 +86,7 @@ void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vector& nodeIDs, - std::list >& rawNodes, bool fatLeaves) + std::list >& rawNodes, bool fatRoot, bool fatLeaves) { // Gets a node and some of its children boost::recursive_mutex::scoped_lock sl(mLock); @@ -102,7 +102,7 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector& nodeI node->addRaw(s, snfWIRE); rawNodes.push_back(s.peekData()); - if (node->isRoot() || node->isLeaf()) // don't get a fat root, can't get a fat leaf + if ((!fatRoot && node->isRoot()) || node->isLeaf()) // don't get a fat root, can't get a fat leaf return true; for (int i = 0; i < 16; ++i) @@ -141,7 +141,8 @@ bool SHAMap::addRootNode(const std::vector& rootNode, SHANodeForm } SHAMapTreeNode::pointer node = boost::make_shared(SHAMapNode(), rootNode, 0, format); - if (!node) return false; + if (!node) + return false; #ifdef DEBUG node->dump(); @@ -444,7 +445,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) destination.setSynching(); - if (!source.getNodeFat(SHAMapNode(), nodeIDs, gotNodes, (rand() % 2) == 0)) + if (!source.getNodeFat(SHAMapNode(), nodeIDs, gotNodes, (rand() % 2) == 0, (rand() % 2) == 0)) { Log(lsFATAL) << "GetNodeFat(root) fails"; BOOST_FAIL("GetNodeFat"); @@ -481,7 +482,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) // get as many nodes as possible based on this information for (nodeIDIterator = nodeIDs.begin(); nodeIDIterator != nodeIDs.end(); ++nodeIDIterator) { - if (!source.getNodeFat(*nodeIDIterator, gotNodeIDs, gotNodes, (rand() % 2) == 0)) + if (!source.getNodeFat(*nodeIDIterator, gotNodeIDs, gotNodes, (rand() % 2) == 0, (rand() % 2) == 0)) { Log(lsFATAL) << "GetNodeFat fails"; BOOST_FAIL("GetNodeFat"); From e3b6ec5080f5d73bbeba136f136f9376a145ce33 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:18:58 -0700 Subject: [PATCH 034/426] Don't call newLCL more than once. --- src/LedgerConsensus.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index b47a19ee67..a2888f190a 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -441,9 +441,7 @@ void LedgerConsensus::stateEstablish() void LedgerConsensus::stateFinished() { // we are processing the finished ledger // logic of calculating next ledger advances us out of this state - - // CHECKME: Should we count proposers that didn't converge to our consensus set? - theApp->getOPs().newLCL(mPeerPositions.size(), mCurrentMSeconds, mNewLedgerHash); + // nothing to do } void LedgerConsensus::stateAccepted() @@ -770,6 +768,7 @@ void LedgerConsensus::beginAccept() return; } + theApp->getOPs().newLCL(mPeerPositions.size(), mCurrentMSeconds, mNewLedgerHash); boost::thread thread(boost::bind(&LedgerConsensus::Saccept, shared_from_this(), consensusSet)); thread.detach(); } From 524e89f4e1ce0452fea0d40b6e4a949c910a75a4 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:35:20 -0700 Subject: [PATCH 035/426] Timing cleanups. --- src/LedgerTiming.h | 9 +++++++-- src/ValidationCollection.cpp | 11 ++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/LedgerTiming.h b/src/LedgerTiming.h index 41e85762a1..9f5cfa903f 100644 --- a/src/LedgerTiming.h +++ b/src/LedgerTiming.h @@ -4,8 +4,13 @@ // The number of seconds a ledger may remain idle before closing # define LEDGER_IDLE_INTERVAL 15 -// The number of seconds a validation remains current -# define LEDGER_MAX_INTERVAL (LEDGER_IDLE_INTERVAL * 4) +// The number of seconds a validation remains current after its ledger's close time +// This is a safety to protect against very old validations +# define LEDGER_MAX_INTERVAL (LEDGER_IDLE_INTERVAL * 32) + +// The number of seconds before a close time that we consider a validation acceptable +// This protects against extreme clock errors +# define LEDGER_EARLY_INTERVAL 240 // The number of milliseconds we wait minimum to ensure participation # define LEDGER_MIN_CONSENSUS 2000 diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 466b3d7f2e..68c54fc86e 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -14,7 +14,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) val->setTrusted(); uint32 now = theApp->getOPs().getCloseTimeNC(); uint32 valClose = val->getCloseTime(); - if ((now > (valClose - 4)) && (now < (valClose + LEDGER_MAX_INTERVAL))) + if ((now > (valClose - LEDGER_EARLY_INTERVAL)) && (now < (valClose + LEDGER_MAX_INTERVAL))) isCurrent = true; else Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose; @@ -81,7 +81,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren if (isTrusted && currentOnly) { uint32 closeTime = vit->second->getCloseTime(); - if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_MAX_INTERVAL))) + if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_MAX_INTERVAL))) isTrusted = false; } if (isTrusted) @@ -129,7 +129,6 @@ boost::unordered_map ValidationCollection::getCurrentValidations() { boost::mutex::scoped_lock sl(mValidationLock); boost::unordered_map::iterator it = mCurrentValidations.begin(); - bool anyNew = false; while (it != mCurrentValidations.end()) { ValidationPair& pair = it->second; @@ -138,13 +137,13 @@ boost::unordered_map ValidationCollection::getCurrentValidations() { mStaleValidations.push_back(pair.oldest); pair.oldest = SerializedValidation::pointer(); - anyNew = true; + condWrite(); } if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_MAX_INTERVAL))) { mStaleValidations.push_back(pair.newest); pair.newest = SerializedValidation::pointer(); - anyNew = true; + condWrite(); } if (!pair.newest && !pair.oldest) it = mCurrentValidations.erase(it); @@ -165,8 +164,6 @@ boost::unordered_map ValidationCollection::getCurrentValidations() ++it; } } - if (anyNew) - condWrite(); } return ret; From d1547998d71d7aa5640d248adc1754924b616fe0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 17:55:55 -0700 Subject: [PATCH 036/426] Change LEDGER_MAX_INTERVAL to LEDGER_VAL_INTERVAL to more accurately reflect what it now does. Turn this interval way up to ensure we can't lose synch (due to validations seeming too old) if time resolution drops drastically. --- src/LedgerTiming.h | 5 +++-- src/ValidationCollection.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/LedgerTiming.h b/src/LedgerTiming.h index 9f5cfa903f..eb8f2d56c8 100644 --- a/src/LedgerTiming.h +++ b/src/LedgerTiming.h @@ -5,8 +5,9 @@ # define LEDGER_IDLE_INTERVAL 15 // The number of seconds a validation remains current after its ledger's close time -// This is a safety to protect against very old validations -# define LEDGER_MAX_INTERVAL (LEDGER_IDLE_INTERVAL * 32) +// This is a safety to protect against very old validations and the time it takes to adjust +// the close time accuracy window +# define LEDGER_VAL_INTERVAL 600 // The number of seconds before a close time that we consider a validation acceptable // This protects against extreme clock errors diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 68c54fc86e..41c772f819 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -14,7 +14,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) val->setTrusted(); uint32 now = theApp->getOPs().getCloseTimeNC(); uint32 valClose = val->getCloseTime(); - if ((now > (valClose - LEDGER_EARLY_INTERVAL)) && (now < (valClose + LEDGER_MAX_INTERVAL))) + if ((now > (valClose - LEDGER_EARLY_INTERVAL)) && (now < (valClose + LEDGER_VAL_INTERVAL))) isCurrent = true; else Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose; @@ -81,7 +81,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren if (isTrusted && currentOnly) { uint32 closeTime = vit->second->getCloseTime(); - if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_MAX_INTERVAL))) + if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_VAL_INTERVAL))) isTrusted = false; } if (isTrusted) @@ -133,13 +133,13 @@ boost::unordered_map ValidationCollection::getCurrentValidations() { ValidationPair& pair = it->second; - if (pair.oldest && (now > (pair.oldest->getCloseTime() + LEDGER_MAX_INTERVAL))) + if (pair.oldest && (now > (pair.oldest->getCloseTime() + LEDGER_VAL_INTERVAL))) { mStaleValidations.push_back(pair.oldest); pair.oldest = SerializedValidation::pointer(); condWrite(); } - if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_MAX_INTERVAL))) + if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_VAL_INTERVAL))) { mStaleValidations.push_back(pair.newest); pair.newest = SerializedValidation::pointer(); From ba6e65214b6f7b789130be3f2cbe8916071e443e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 19:23:49 -0700 Subject: [PATCH 037/426] Log whether a ledger is alive or dead when considering it as LCL. --- src/NetworkOPs.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 875834a1e5..355318844c 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -458,9 +458,10 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis for (boost::unordered_map::iterator it = ledgers.begin(), end = ledgers.end(); it != end; ++it) { - Log(lsTRACE) << "L: " << it->first.GetHex() << + bool isDead = theApp->getValidations().isDeadLedger(it->first); + Log(lsTRACE) << "L: " << it->first.GetHex() << ((isDead) ? " dead" : " live") << " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; - if ((it->second > bestVC) && !theApp->getValidations().isDeadLedger(it->first)) + if ((it->second > bestVC) && !isDead) { bestVC = it->second; closedLedger = it->first; From 8068e5fbb9b699a300cf4b8898cb840af8c11143 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 22:27:20 -0700 Subject: [PATCH 038/426] Remove chatty debug. --- src/ValidationCollection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 41c772f819..2f29327140 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -151,13 +151,13 @@ boost::unordered_map ValidationCollection::getCurrentValidations() { if (pair.oldest) { - Log(lsTRACE) << "OLD " << pair.oldest->getLedgerHash().GetHex() << " " << +// Log(lsTRACE) << "OLD " << pair.oldest->getLedgerHash().GetHex() << " " << boost::lexical_cast(pair.oldest->getCloseTime()); ++ret[pair.oldest->getLedgerHash()]; } if (pair.newest) { - Log(lsTRACE) << "NEW " << pair.newest->getLedgerHash().GetHex() << " " << +// Log(lsTRACE) << "NEW " << pair.newest->getLedgerHash().GetHex() << " " << boost::lexical_cast(pair.newest->getCloseTime()); ++ret[pair.newest->getLedgerHash()]; } From 22237e58ab15a02b257f072c854101dc9f32b9ca Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 22:27:29 -0700 Subject: [PATCH 039/426] Check for network condition during idle time. Switch LCL if needed. --- src/LedgerConsensus.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index a2888f190a..6b56b66402 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -224,7 +224,7 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer pre } else { - Log(lsINFO) << "Entering consensus process, proposing"; + Log(lsINFO) << "Entering consensus process, watching"; mHaveCorrectLCL = true; mProposing = mValidating = false; } @@ -249,6 +249,9 @@ void LedgerConsensus::checkLCL() mPrevLedgerHash = netLgr; mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash); std::vector peerList = theApp->getConnectionPool().getPeerVector(); + mHaveCorrectLCL = false; + mProposing = false; + mValidating = false; bool found = false; for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) if ((*it)->hasLedger(mPrevLedgerHash)) @@ -418,6 +421,8 @@ void LedgerConsensus::statePreClose() statusChange(newcoin::neCLOSING_LEDGER, *mPreviousLedger); takeInitialPosition(*theApp->getMasterLedger().closeLedger()); } + else + checkLCL(); } void LedgerConsensus::stateEstablish() From 6788105b2c72d8b154441e3d0b5b7e90fcebb791 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 23:13:01 -0700 Subject: [PATCH 040/426] Chatty debug. --- src/HashedObject.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp index 9dc7e6e92c..71730bfb19 100644 --- a/src/HashedObject.cpp +++ b/src/HashedObject.cpp @@ -21,7 +21,9 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index, if (!theApp->getHashNodeDB()) return true; if (mCache.touch(hash)) { +#ifdef HS_DEBUG Log(lsTRACE) << "HOS: " << hash.GetHex() << " store: incache"; +#endif return false; } From 5eca52497f680377e90a7c5c28cc8942fab35b7e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 23:13:12 -0700 Subject: [PATCH 041/426] Improve close time synch with no transactions --- src/LedgerConsensus.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 6b56b66402..aba77ea75f 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -408,7 +408,12 @@ void LedgerConsensus::statePreClose() int proposersClosed = mPeerPositions.size(); // This ledger is open. This computes how long since the last ledger closed - int sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - theApp->getOPs().getLastCloseNetTime()); + int lastCloseTime; + if (!anyTransactions && mPreviousLedger->getCloseAgree()) + lastCloseTime = mPreviousLedger->getCloseTimeNC(); + else + lastCloseTime = theApp->getOPs().getLastCloseNetTime(); + int sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - lastCloseTime); if (sinceClose >= ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed, mPreviousMSeconds, sinceClose)) @@ -911,12 +916,12 @@ void LedgerConsensus::accept(SHAMap::pointer set) SerializedValidation::pointer v = boost::make_shared (newLCLHash, newLCL->getCloseTimeNC(), mValSeed, mProposing); v->setTrusted(); + Log(lsINFO) << "CNF Val " << newLCLHash.GetHex(); theApp->getValidations().addValidation(v); std::vector validation = v->getSigned(); newcoin::TMValidation val; val.set_validation(&validation[0], validation.size()); theApp->getConnectionPool().relayMessage(NULL, boost::make_shared(val, newcoin::mtVALIDATION)); - Log(lsINFO) << "CNF Val " << newLCLHash.GetHex(); } else Log(lsINFO) << "CNF newLCL " << newLCLHash.GetHex(); From 227754496e0b995b9920fd80bffa5baff9b0b8b2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 23:14:39 -0700 Subject: [PATCH 042/426] Fix what is probably *the* bug. We aren't usually in our own UNL, so we specially mark our validations trusted. But that wasn't properly taken into account in one case where we decide if a validation is current. This causes two nodes to each not recognize their own validations, so they tend to exchange ledgers. Cleanups, extra logging. --- src/ValidationCollection.cpp | 34 +++++++++++++++++++++++++++------- src/ValidationCollection.h | 2 +- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 2f29327140..1502e4b52d 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -5,11 +5,13 @@ #include "LedgerTiming.h" #include "Log.h" -bool ValidationCollection::addValidation(SerializedValidation::pointer val) +// #define VC_DEBUG + +bool ValidationCollection::addValidation(SerializedValidation::pointer& val) { NewcoinAddress signer = val->getSignerPublic(); bool isCurrent = false; - if (theApp->getUNL().nodeInUNL(signer)) + if (theApp->getUNL().nodeInUNL(signer) || val->isTrusted()) { val->setTrusted(); uint32 now = theApp->getOPs().getCloseTimeNC(); @@ -51,7 +53,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) } Log(lsINFO) << "Val for " << hash.GetHex() << " from " << signer.humanNodePublic() - << " added " << (val->isTrusted() ? "trusted" : "UNtrusted"); + << " added " << (val->isTrusted() ? "trusted/" : "UNtrusted/") << (isCurrent ? "current" : "stale"); return isCurrent; } @@ -83,6 +85,12 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren uint32 closeTime = vit->second->getCloseTime(); if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_VAL_INTERVAL))) isTrusted = false; + else + { +#ifdef VC_DEBUG + Log(lsINFO) << "VC: Untrusted due to time " << ledger.GetHex(); +#endif + } } if (isTrusted) ++trusted; @@ -90,6 +98,9 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren ++untrusted; } } +#ifdef VC_DEBUG + Log(lsINFO) << "VC: " << ledger.GetHex() << "t:" << trusted << " u:" << untrusted; +#endif } int ValidationCollection::getTrustedValidationCount(const uint256& ledger) @@ -135,12 +146,18 @@ boost::unordered_map ValidationCollection::getCurrentValidations() if (pair.oldest && (now > (pair.oldest->getCloseTime() + LEDGER_VAL_INTERVAL))) { +#ifdef VC_DEBUG + Log(lsINFO) << "VC: " << it->first.GetHex() << " removeOldestStale"; +#endif mStaleValidations.push_back(pair.oldest); pair.oldest = SerializedValidation::pointer(); condWrite(); } if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_VAL_INTERVAL))) { +#ifdef VC_DEBUG + Log(lsINFO) << "VC: " << it->first.GetHex() << " removeNewestStale"; +#endif mStaleValidations.push_back(pair.newest); pair.newest = SerializedValidation::pointer(); condWrite(); @@ -151,14 +168,18 @@ boost::unordered_map ValidationCollection::getCurrentValidations() { if (pair.oldest) { -// Log(lsTRACE) << "OLD " << pair.oldest->getLedgerHash().GetHex() << " " << +#ifdef VC_DEBUG + Log(lsTRACE) << "VC: OLD " << pair.oldest->getLedgerHash().GetHex() << " " << boost::lexical_cast(pair.oldest->getCloseTime()); +#endif ++ret[pair.oldest->getLedgerHash()]; } if (pair.newest) { -// Log(lsTRACE) << "NEW " << pair.newest->getLedgerHash().GetHex() << " " << +#ifdef VC_DEBUG + Log(lsTRACE) << "VC: NEW " << pair.newest->getLedgerHash().GetHex() << " " << boost::lexical_cast(pair.newest->getCloseTime()); +#endif ++ret[pair.newest->getLedgerHash()]; } ++it; @@ -224,8 +245,7 @@ void ValidationCollection::condWrite() void ValidationCollection::doWrite() { static boost::format insVal("INSERT INTO LedgerValidations " - "(LedgerHash,NodePubKey,Flags,CloseTime,Signature) VALUES " - "('%s','%s','%u','%u',%s);"); + "(LedgerHash,NodePubKey,Flags,CloseTime,Signature) VALUES ('%s','%s','%u','%u',%s);"); boost::mutex::scoped_lock sl(mValidationLock); assert(mWriting); diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index 2198a967fe..1ed522dc54 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -38,7 +38,7 @@ protected: public: ValidationCollection() : mWriting(false) { ; } - bool addValidation(SerializedValidation::pointer); + bool addValidation(SerializedValidation::pointer&); ValidationSet getValidations(const uint256& ledger); void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted); From 04427b4ad024bc2de694b6555a66a1095c5414ee Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 13 Aug 2012 23:15:50 -0700 Subject: [PATCH 043/426] Cleanups. --- src/NetworkOPs.cpp | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 355318844c..afbf87e32a 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -322,8 +322,11 @@ public: { if (trustedValidations > v.trustedValidations) return true; if (trustedValidations < v.trustedValidations) return false; - if (nodesUsing > v.nodesUsing) return true; - if (nodesUsing < v.nodesUsing) return false; + if (trustedValidations == 0) + { + if (nodesUsing > v.nodesUsing) return true; + if (nodesUsing < v.nodesUsing) return false; + } return highNode > v.highNode; } }; @@ -332,6 +335,7 @@ void NetworkOPs::checkState(const boost::system::error_code& result) { // Network state machine if (result == boost::asio::error::operation_aborted) return; + setStateTimer(); std::vector peerList = theApp->getConnectionPool().getPeerVector(); @@ -344,7 +348,6 @@ void NetworkOPs::checkState(const boost::system::error_code& result) Log(lsWARNING) << "Node count (" << peerList.size() << ") has fallen below quorum (" << theConfig.NETWORK_QUORUM << ")."; } - setStateTimer(); return; } if (mMode == omDISCONNECTED) @@ -356,7 +359,6 @@ void NetworkOPs::checkState(const boost::system::error_code& result) if (mConsensus) { mConsensus->timerEntry(); - setStateTimer(); return; } @@ -383,15 +385,13 @@ void NetworkOPs::checkState(const boost::system::error_code& result) // check if the ledger is good enough to go to omFULL // Note: Do not go to omFULL if we don't have the previous ledger // check if the ledger is bad enough to go to omCONNECTED -- TODO - if (theApp->getOPs().getNetworkTimeNC() < - (theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC() + 4)) + if (theApp->getOPs().getNetworkTimeNC() < theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC()) setMode(omFULL); - else - Log(lsINFO) << "Will try to go to FULL in consensus window"; } if (mMode == omFULL) { + // WRITEME // check if the ledger is bad enough to go to omTRACKING } @@ -399,7 +399,6 @@ void NetworkOPs::checkState(const boost::system::error_code& result) beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger()); if (mConsensus) mConsensus->timerEntry(); - setStateTimer(); } bool NetworkOPs::checkLastClosedLedger(const std::vector& peerList, uint256& networkClosed) @@ -460,7 +459,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis { bool isDead = theApp->getValidations().isDeadLedger(it->first); Log(lsTRACE) << "L: " << it->first.GetHex() << ((isDead) ? " dead" : " live") << - " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; + " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; if ((it->second > bestVC) && !isDead) { bestVC = it->second; @@ -633,20 +632,23 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash) { - if (!mConsensus) return SHAMap::pointer(); + if (!mConsensus) + return SHAMap::pointer(); return mConsensus->getTransactionTree(hash, false); } bool NetworkOPs::gotTXData(boost::shared_ptr peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { - if (!mConsensus) return false; + if (!mConsensus) + return false; return mConsensus->peerGaveNodes(peer, hash, nodeIDs, nodeData); } bool NetworkOPs::hasTXSet(boost::shared_ptr peer, const uint256& set, newcoin::TxSetStatus status) { - if (!mConsensus) return false; + if (!mConsensus) + return false; return mConsensus->peerHasSet(peer, set, status); } @@ -677,10 +679,14 @@ void NetworkOPs::setMode(OperatingMode om) if ((om >= omCONNECTED) && (mMode == omDISCONNECTED)) mConnectTime = boost::posix_time::second_clock::universal_time(); Log l((om < mMode) ? lsWARNING : lsINFO); - if (om == omDISCONNECTED) l << "STATE->Disonnected"; - else if (om == omCONNECTED) l << "STATE->Connected"; - else if (om == omTRACKING) l << "STATE->Tracking"; - else l << "STATE->Full"; + if (om == omDISCONNECTED) + l << "STATE->Disonnected"; + else if (om == omCONNECTED) + l << "STATE->Connected"; + else if (om == omTRACKING) + l << "STATE->Tracking"; + else + l << "STATE->Full"; mMode = om; } From 3dcdc3b94a449c7b506b02d917a706e5df2b0508 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 14 Aug 2012 01:51:17 -0700 Subject: [PATCH 044/426] Fire up the aux thread earlier. --- src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index daac98dd54..af3b17f9a0 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -70,11 +70,11 @@ void Application::run() if (!theConfig.DEBUG_LOGFILE.empty()) Log::setLogFile(theConfig.DEBUG_LOGFILE); - mSNTPClient.init(theConfig.SNTP_SERVERS); - boost::thread auxThread(boost::bind(&boost::asio::io_service::run, &mAuxService)); auxThread.detach(); + mSNTPClient.init(theConfig.SNTP_SERVERS); + // // Construct databases. // From 046c539d49f0e8cb0b262c08d337cdd1f80040f2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 14 Aug 2012 01:51:35 -0700 Subject: [PATCH 045/426] Mark a parameter as unused. --- src/Ledger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 131e7d3b91..0cd6e2346d 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -57,7 +57,7 @@ Ledger::Ledger(Ledger& ledger, bool isMutable) : mTotCoins(ledger.mTotCoins), mL } -Ledger::Ledger(bool dummy, Ledger& prevLedger) : +Ledger::Ledger(bool /* dummy */, Ledger& prevLedger) : mTotCoins(prevLedger.mTotCoins), mLedgerSeq(prevLedger.mLedgerSeq + 1), mParentCloseTime(prevLedger.mCloseTime), mCloseResolution(prevLedger.mCloseResolution), mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false), From 4b2ae556bd29fc31988ed595b8667b530ffbc96f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 14 Aug 2012 01:51:46 -0700 Subject: [PATCH 046/426] Downgrade a timing issue from fatal to warning. --- src/LedgerTiming.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index ae0d65de19..9243dd6ce0 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -22,8 +22,8 @@ int ContinuousLedgerTiming::shouldClose( if ((previousMSeconds < -1000) || (previousMSeconds > 600000) || (currentMSeconds < -1000) || (currentMSeconds > 600000)) { - Log(lsFATAL) << - boost::str(boost::format("CLC::shouldClose range error Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") + Log(lsWARNING) << + boost::str(boost::format("CLC::shouldClose range Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") % (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentMSeconds % previousMSeconds); return currentMSeconds; From 11f02ba79822158a0edd4859dcd226918c64eca1 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 14 Aug 2012 13:17:59 -0700 Subject: [PATCH 047/426] Ignore create flag on payments if account already created. --- src/TransactionEngine.cpp | 9 --------- src/TransactionEngine.h | 1 - 2 files changed, 10 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index d95b0bb198..197c6c9472 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -70,7 +70,6 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { terBAD_LEDGER, "terBAD_LEDGER", "Ledger in unexpected state." }, { terBAD_RIPPLE, "terBAD_RIPPLE", "No ripple path can be satisfied." }, { terBAD_SEQ, "terBAD_SEQ", "This sequence number should be zero for prepaid transactions." }, - { terCREATED, "terCREATED", "Can not create a previously created account." }, { terDIR_FULL, "terDIR_FULL", "Can not add entry to full dir." }, { terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." }, { terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee" }, @@ -3305,14 +3304,6 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction sleDst->setIFieldAccount(sfAccount, uDstAccountID); sleDst->setIFieldU32(sfSequence, 1); } - // Destination exists. - else if (bCreate) - { - // Retryable: if account created this ledger, reordering might allow account to be made by this transaction. - Log(lsINFO) << "doPayment: Invalid transaction: Account already created."; - - return terCREATED; - } else { entryModify(sleDst); diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 832f09e5e0..02e8dfb762 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -41,7 +41,6 @@ enum TransactionEngineResult // Invalid: Ledger won't allow. tenCLAIMED = -200, tenBAD_RIPPLE, - tenCREATED, tenEXPIRED, tenMSG_SET, terALREADY, From 07f5bf26129e1c0bd9f02d1ab10c2ecb9cd08431 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 14 Aug 2012 13:31:46 -0700 Subject: [PATCH 048/426] Enforce SendMax restrictions in transaction engine. --- src/Transaction.cpp | 2 +- src/TransactionEngine.cpp | 9 +++++++++ src/TransactionEngine.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Transaction.cpp b/src/Transaction.cpp index d600bfefae..da778890c3 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -500,7 +500,7 @@ Transaction::pointer Transaction::setPayment( mTransaction->setITFieldAccount(sfDestination, naDstAccountID); mTransaction->setITFieldAmount(sfAmount, saAmount); - if (saAmount != saSendMax) + if (saAmount != saSendMax || saAmount.getCurrency() != saSendMax.getCurrency()) { mTransaction->setITFieldAmount(sfSendMax, saSendMax); } diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 197c6c9472..598af8b3aa 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -3279,6 +3279,14 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction return tenREDUNDANT; } + else if (bMax + && ((saMaxAmount == saDstAmount && saMaxAmount.getCurrency() == saDstAmount.getCurrency()) + || (saDstAmount.isNative() && saMaxAmount.isNative()))) + { + Log(lsINFO) << "doPayment: Invalid transaction: bad SendMax."; + + return tenINVALID; + } SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); if (!sleDst) @@ -3309,6 +3317,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction entryModify(sleDst); } + // XXX Should bMax be sufficient to imply ripple? bool bRipple = bPaths || bMax || !saDstAmount.isNative(); if (!bRipple) diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 02e8dfb762..832f09e5e0 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -41,6 +41,7 @@ enum TransactionEngineResult // Invalid: Ledger won't allow. tenCLAIMED = -200, tenBAD_RIPPLE, + tenCREATED, tenEXPIRED, tenMSG_SET, terALREADY, From 6044e49994878a376779623f067243141a047bd0 Mon Sep 17 00:00:00 2001 From: jed Date: Tue, 14 Aug 2012 14:19:44 -0700 Subject: [PATCH 049/426] . --- src/Peer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index 991d18456b..99abf149f3 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -1212,7 +1212,8 @@ Json::Value Peer::getJson() //ret["this"] = ADDRESS(this); ret["public_key"] = mNodePublic.ToString(); ret["ip"] = mIpPortConnect.first; - ret["port"] = mIpPortConnect.second; + //ret["port"] = mIpPortConnect.second; + ret["port"] = mIpPort.second; if (mHello.has_fullversion()) ret["version"] = mHello.fullversion(); From e473ce84248a4cfc3edfd38ad53910744c023593 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 14 Aug 2012 15:35:30 -0700 Subject: [PATCH 050/426] Support "standalone" mode (-a or --standalone) in which we do not connect to the network and do not close ledgers. This mode makes it much easier to test transactions as they are only applied once to the open ledger. --- src/Application.cpp | 17 +++++++++++++---- src/Config.cpp | 5 +++++ src/Config.h | 2 ++ src/ConnectionPool.cpp | 5 +++++ src/LedgerMaster.h | 2 ++ src/NetworkOPs.cpp | 4 ++-- src/RPCServer.cpp | 3 +++ src/main.cpp | 7 +++++++ 8 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index af3b17f9a0..2fe18c161f 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -95,13 +95,14 @@ void Application::run() // // Set up UNL. // - getUNL().nodeBootstrap(); + if (!theConfig.RUN_STANDALONE) + getUNL().nodeBootstrap(); // // Allow peer connections. // - if (!theConfig.PEER_IP.empty() && theConfig.PEER_PORT) + if (!theConfig.RUN_STANDALONE && !theConfig.PEER_IP.empty() && theConfig.PEER_PORT) { mPeerDoor = new PeerDoor(mIOService); } @@ -127,7 +128,8 @@ void Application::run() // // Begin connecting to network. // - mConnectionPool.start(); + if (!theConfig.RUN_STANDALONE) + mConnectionPool.start(); // New stuff. NewcoinAddress rootSeedMaster = NewcoinAddress::createSeedGeneric("masterpassphrase"); @@ -155,7 +157,14 @@ void Application::run() } - mNetOps.setStateTimer(); + if (theConfig.RUN_STANDALONE) + { + Log(lsWARNING) << "Running in standalone mode"; + mNetOps.setStandAlone(); + mMasterLedger.runStandAlone(); + } + else + mNetOps.setStateTimer(); mIOService.run(); // This blocks diff --git a/src/Config.cpp b/src/Config.cpp index cf9c135bfe..ef79cae52a 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -40,6 +40,11 @@ Config theConfig; +void Config::init() +{ + RUN_STANDALONE = false; +} + void Config::setup(const std::string& strConf) { boost::system::error_code ec; diff --git a/src/Config.h b/src/Config.h index 585980b92b..a7828da7b6 100644 --- a/src/Config.h +++ b/src/Config.h @@ -63,6 +63,7 @@ public: int LEDGER_PROPOSAL_DELAY_SECONDS; int LEDGER_AVALANCHE_SECONDS; bool LEDGER_CREATOR; // should be false unless we are starting a new ledger + bool RUN_STANDALONE; // Note: The following parameters do not relate to the UNL or trust at all unsigned int NETWORK_QUORUM; // Minimum number of nodes to consider the network present @@ -100,6 +101,7 @@ public: // Client behavior int ACCOUNT_PROBE_MAX; // How far to scan for accounts. + void init(); void setup(const std::string& strConf); void load(); }; diff --git a/src/ConnectionPool.cpp b/src/ConnectionPool.cpp index 2a7f38bb7e..3d79fbc2ad 100644 --- a/src/ConnectionPool.cpp +++ b/src/ConnectionPool.cpp @@ -42,6 +42,9 @@ ConnectionPool::ConnectionPool(boost::asio::io_service& io_service) : void ConnectionPool::start() { + if (theConfig.RUN_STANDALONE) + return; + // Start running policy. policyEnforce(); @@ -243,6 +246,8 @@ void ConnectionPool::relayMessage(Peer* fromPeer, PackedMessage::pointer msg) // Requires sane IP and port. void ConnectionPool::connectTo(const std::string& strIp, int iPort) { + if (theConfig.RUN_STANDALONE) + return; { Database* db = theApp->getWalletDB()->getDB(); ScopedLock sl(theApp->getWalletDB()->getDBLock()); diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h index 9f9603f1bc..187aaeec13 100644 --- a/src/LedgerMaster.h +++ b/src/LedgerMaster.h @@ -43,6 +43,8 @@ public: // The finalized ledger is the last closed/accepted ledger Ledger::pointer getClosedLedger() { return mFinalizedLedger; } + void runStandAlone() { mFinalizedLedger = mCurrentLedger; } + TransactionEngineResult doTransaction(const SerializedTransaction& txn, uint32 targetLedger, TransactionEngineParams params); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index afbf87e32a..d7180a6ae9 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -333,7 +333,7 @@ public: void NetworkOPs::checkState(const boost::system::error_code& result) { // Network state machine - if (result == boost::asio::error::operation_aborted) + if ((result == boost::asio::error::operation_aborted) || theConfig.RUN_STANDALONE) return; setStateTimer(); @@ -680,7 +680,7 @@ void NetworkOPs::setMode(OperatingMode om) mConnectTime = boost::posix_time::second_clock::universal_time(); Log l((om < mMode) ? lsWARNING : lsINFO); if (om == omDISCONNECTED) - l << "STATE->Disonnected"; + l << "STATE->Disconnected"; else if (om == omCONNECTED) l << "STATE->Connected"; else if (om == omTRACKING) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 46ea9eda7d..9bf863a356 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -832,6 +832,9 @@ Json::Value RPCServer::doAccountWalletSet(const Json::Value& params) { Json::Value RPCServer::doConnect(const Json::Value& params) { + if (theConfig.RUN_STANDALONE) + return "cannot connect in standalone mode"; + // connect [port] std::string strIp; int iPort = -1; diff --git a/src/main.cpp b/src/main.cpp index 155408170a..c78da1e246 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -84,6 +84,7 @@ int main(int argc, char* argv[]) int iResult = 0; po::variables_map vm; // Map of options. bool bTest = false; + theConfig.init(); // // Set up option parsing. @@ -93,6 +94,7 @@ int main(int argc, char* argv[]) ("help,h", "Display this message.") ("conf", po::value(), "Specify the configuration file.") ("rpc", "Perform rpc command (default).") + ("standalone,a", "Run with no peers.") ("test,t", "Perform unit tests.") ("parameters", po::value< vector >(), "Specify comma separated parameters.") ("verbose,v", "Increase log level") @@ -142,6 +144,11 @@ int main(int argc, char* argv[]) Log::setMinSeverity(lsTRACE); } + if (vm.count("standalone")) + { + theConfig.RUN_STANDALONE = true; + } + if (!iResult) { theConfig.setup(vm.count("conf") ? vm["conf"].as() : ""); From 89c7c26c2f409ec9a62542dfc9887604f4a2847a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 14 Aug 2012 15:36:50 -0700 Subject: [PATCH 051/426] Oops. --- src/NetworkOPs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 8e8e45c24c..44eebc0ae4 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -188,6 +188,7 @@ public: bool checkLastClosedLedger(const std::vector&, uint256& networkClosed); int beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger); void endConsensus(bool correctLCL); + void setStandAlone() { setMode(omFULL); } void setStateTimer(); void newLCL(int proposers, int convergeTime, const uint256& ledgerHash); int getPreviousProposers() { return mLastCloseProposers; } From 5ddbf968bfd5e7f7c110894dcd356286dbdb75c3 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 14 Aug 2012 15:50:35 -0700 Subject: [PATCH 052/426] Remove Account field from AccountRootNode. --- src/LedgerFormats.cpp | 1 - src/TransactionEngine.cpp | 60 ++++++++++++++++++--------------------- src/TransactionEngine.h | 1 - 3 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 8cc358b58c..5b031ffc99 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -7,7 +7,6 @@ LedgerEntryFormat LedgerFormats[]= { { "AccountRoot", ltACCOUNT_ROOT, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(LastReceive), STI_UINT32, SOE_REQUIRED, 0 }, diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 598af8b3aa..ae32693fe6 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -818,7 +818,7 @@ SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint25 mOrigNodes.entryCache(sleEntry); // So the metadata code can compare to the original } } - else if(action == taaDELETE) + else if (action == taaDELETE) assert(false); } @@ -3165,7 +3165,7 @@ PathState::PathState( STAmount saSendMax, bool bPartialPayment ) - : mIndex(iIndex), uQuality(0), bDirty(true) + : mIndex(iIndex), uQuality(0) { lesEntries = lesSource.duplicate(); @@ -3228,11 +3228,12 @@ void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) unsigned int uLast = pspCur->vpnNodes.size() - 1; + pspCur->lesEntries = mNodes.duplicate(); // Checkpoint state? + if (!calcNode(uLast, pspCur, iPaths == 1)) { // Mark path as inactive. pspCur->uQuality = 0; - pspCur->bDirty = false; } } @@ -3309,7 +3310,6 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // Create the account. sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - sleDst->setIFieldAccount(sfAccount, uDstAccountID); sleDst->setIFieldU32(sfSequence, 1); } else @@ -3343,9 +3343,12 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // Ripple payment // +#if 0 +// Disabled to make sure full ripple code is correct. // Try direct ripple first. if (!bNoRippleDirect && mTxnAccountID != uDstAccountID && uSrcCurrency == uDstCurrency) { + // XXX Does not handle quality. SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uDstCurrency)); if (sleRippleState) @@ -3425,16 +3428,18 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction return terSUCCESS; } } +#endif STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); - if (!spsPaths.isEmpty()) + if (!bNoRippleDirect && spsPaths.isEmpty()) { - Log(lsINFO) << "doPayment: Invalid transaction: No paths."; + Log(lsINFO) << "doPayment: Invalid transaction: No paths and direct ripple not allowed."; return tenRIPPLE_EMPTY; } - else if (spsPaths.getPathCount() > RIPPLE_PATHS_MAX) + + if (spsPaths.getPathCount() > RIPPLE_PATHS_MAX) { return tenBAD_PATH_COUNT; } @@ -3442,6 +3447,21 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // Incrementally search paths. std::vector vpsPaths; + if (!bNoRippleDirect) + { + // Direct path. + vpsPaths.push_back(PathState::createPathState( + vpsPaths.size(), + mNodes, + STPath(), + uDstAccountID, + mTxnAccountID, + saDstAmount, + saMaxAmount, + bPartialPayment + )); + } + BOOST_FOREACH(const STPath& spPath, spsPaths) { vpsPaths.push_back(PathState::createPathState( @@ -3468,14 +3488,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // Find the best path. BOOST_FOREACH(PathState::pointer pspCur, vpsPaths) { - if (pspCur->bDirty) - { - pspCur->bDirty = false; - pspCur->lesEntries = mNodes.duplicate(); - - // XXX Compute increment - pathNext(pspCur, vpsPaths.size()); - } + pathNext(pspCur, vpsPaths.size()); // Compute increment if (!pspBest || (pspCur->uQuality && PathState::lessPriority(pspBest, pspCur))) pspBest = pspCur; @@ -3490,22 +3503,6 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // Install changes for path. mNodes.swapWith(pspBest->lesEntries); - // Mark that path as dirty. - pspBest->bDirty = true; - - // Mark as dirty any other path that intersected. - BOOST_FOREACH(PathState::pointer& pspOther, vpsPaths) - { - // Look for intersection of best and the others. - // - Will forget the intersection applied. - // - Anything left will not interfere with it. - // - Will remember the non-intersection non-applied for future consideration. - if (!pspOther->bDirty - && pspOther->uQuality - && LedgerEntrySet::intersect(pspBest->lesEntries, pspOther->lesEntries)) - pspOther->bDirty = true; - } - // Figure out if done. if (tenUNKNOWN == terResult && saPaid == saWanted) { @@ -3581,7 +3578,6 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti // Create the account. sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - sleDst->setIFieldAccount(sfAccount, uDstAccountID); sleDst->setIFieldU32(sfSequence, 1); sleDst->setIFieldAmount(sfBalance, saAmount); sleDst->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 832f09e5e0..5e1d76c767 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -139,7 +139,6 @@ public: STAmount saInAct; // Amount spent by sender (calc output) STAmount saOutReq; // Amount to send (calc input) STAmount saOutAct; // Amount actually sent (calc output). - bool bDirty; // Path not computed. PathState( int iIndex, From 36fb085114deadc96ec4aa9f72b7994267fc8601 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 14 Aug 2012 15:59:25 -0700 Subject: [PATCH 053/426] Make this more readable. --- src/NetworkOPs.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index d7180a6ae9..f5458b48d5 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -678,15 +678,15 @@ void NetworkOPs::setMode(OperatingMode om) if (mMode == om) return; if ((om >= omCONNECTED) && (mMode == omDISCONNECTED)) mConnectTime = boost::posix_time::second_clock::universal_time(); - Log l((om < mMode) ? lsWARNING : lsINFO); + Log lg((om < mMode) ? lsWARNING : lsINFO); if (om == omDISCONNECTED) - l << "STATE->Disconnected"; + lg << "STATE->Disconnected"; else if (om == omCONNECTED) - l << "STATE->Connected"; + lg << "STATE->Connected"; else if (om == omTRACKING) - l << "STATE->Tracking"; + lg << "STATE->Tracking"; else - l << "STATE->Full"; + lg << "STATE->Full"; mMode = om; } From d3bce70e862c9f8a997aa36f0d1874542a8cf1fb Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 14 Aug 2012 16:00:03 -0700 Subject: [PATCH 054/426] Remove Config::init. It's not needed. --- src/Config.cpp | 7 ++----- src/Config.h | 1 - src/main.cpp | 11 +++++------ 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/Config.cpp b/src/Config.cpp index ef79cae52a..4e36f39a1b 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -40,11 +40,6 @@ Config theConfig; -void Config::init() -{ - RUN_STANDALONE = false; -} - void Config::setup(const std::string& strConf) { boost::system::error_code ec; @@ -155,6 +150,8 @@ void Config::setup(const std::string& strConf) VALIDATORS_SITE = DEFAULT_VALIDATORS_SITE; + RUN_STANDALONE = false; + load(); } diff --git a/src/Config.h b/src/Config.h index a7828da7b6..89fb60b3de 100644 --- a/src/Config.h +++ b/src/Config.h @@ -101,7 +101,6 @@ public: // Client behavior int ACCOUNT_PROBE_MAX; // How far to scan for accounts. - void init(); void setup(const std::string& strConf); void load(); }; diff --git a/src/main.cpp b/src/main.cpp index c78da1e246..4499a2c588 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -84,7 +84,6 @@ int main(int argc, char* argv[]) int iResult = 0; po::variables_map vm; // Map of options. bool bTest = false; - theConfig.init(); // // Set up option parsing. @@ -144,16 +143,16 @@ int main(int argc, char* argv[]) Log::setMinSeverity(lsTRACE); } - if (vm.count("standalone")) - { - theConfig.RUN_STANDALONE = true; - } - if (!iResult) { theConfig.setup(vm.count("conf") ? vm["conf"].as() : ""); } + if (vm.count("standalone")) + { + theConfig.RUN_STANDALONE = true; + } + if (iResult) { nothing(); From 64d6f160681c0f01c5332d55138e2ae014fc73f4 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 14 Aug 2012 16:04:39 -0700 Subject: [PATCH 055/426] Minor cleanup. --- src/main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 4499a2c588..444231ba3a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -146,11 +146,11 @@ int main(int argc, char* argv[]) if (!iResult) { theConfig.setup(vm.count("conf") ? vm["conf"].as() : ""); - } - if (vm.count("standalone")) - { - theConfig.RUN_STANDALONE = true; + if (vm.count("standalone")) + { + theConfig.RUN_STANDALONE = true; + } } if (iResult) From 872314f933751bef03ea30322a00cbe30ce64375 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 14 Aug 2012 17:16:39 -0700 Subject: [PATCH 056/426] Remove more Account from AccountStateNode and LedgerEntrySet revision. --- src/AccountState.cpp | 9 ++++----- src/AccountState.h | 2 -- src/LedgerEntrySet.cpp | 2 +- src/LedgerEntrySet.h | 2 +- src/SerializedTypes.h | 1 + src/TransactionEngine.cpp | 34 +++++++++++++++++++--------------- src/TransactionEngine.h | 1 - 7 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/AccountState.cpp b/src/AccountState.cpp index 5e56bd9965..1f84c9dce9 100644 --- a/src/AccountState.cpp +++ b/src/AccountState.cpp @@ -10,12 +10,12 @@ #include "Ledger.h" #include "Serializer.h" -AccountState::AccountState(const NewcoinAddress& id) : mAccountID(id), mValid(false) +AccountState::AccountState(const NewcoinAddress& id) : mValid(false) { if (!id.isValid()) return; mLedgerEntry = boost::make_shared(ltACCOUNT_ROOT); mLedgerEntry->setIndex(Ledger::getAccountRootIndex(id)); - mLedgerEntry->setIFieldAccount(sfAccount, id); + mValid = true; } @@ -23,9 +23,8 @@ AccountState::AccountState(SerializedLedgerEntry::pointer ledgerEntry) : mLedger { if (!mLedgerEntry) return; if (mLedgerEntry->getType() != ltACCOUNT_ROOT) return; - mAccountID = mLedgerEntry->getIValueFieldAccount(sfAccount); - if (mAccountID.isValid()) - mValid = true; + + mValid = true; } std::string AccountState::createGravatarUrl(uint128 uEmailHash) diff --git a/src/AccountState.h b/src/AccountState.h index d51898e5dd..b2e5a0c95a 100644 --- a/src/AccountState.h +++ b/src/AccountState.h @@ -21,7 +21,6 @@ public: typedef boost::shared_ptr pointer; private: - NewcoinAddress mAccountID; NewcoinAddress mAuthorizedKey; SerializedLedgerEntry::pointer mLedgerEntry; @@ -41,7 +40,6 @@ public: return mLedgerEntry->getIValueFieldAccount(sfAuthorizedKey); } - const NewcoinAddress& getAccountID() const { return mAccountID; } STAmount getBalance() const { return mLedgerEntry->getIValueFieldAmount(sfBalance); } uint32 getSeq() const { return mLedgerEntry->getIFieldU32(sfSequence); } diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index a43ea72bf3..9dc3bb157c 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -20,7 +20,7 @@ LedgerEntrySet LedgerEntrySet::duplicate() const return LedgerEntrySet(mEntries, mSet, mSeq + 1); } -void LedgerEntrySet::setTo(LedgerEntrySet& e) +void LedgerEntrySet::setTo(const LedgerEntrySet& e) { mEntries = e.mEntries; mSet = e.mSet; diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index a6784d946d..02c09c559c 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -42,7 +42,7 @@ public: // set functions LedgerEntrySet duplicate() const; // Make a duplicate of this set - void setTo(LedgerEntrySet&); // Set this set to have the same contents as another + void setTo(const LedgerEntrySet&); // Set this set to have the same contents as another void swapWith(LedgerEntrySet&); // Swap the contents of two sets int getSeq() const { return mSeq; } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 41bcafc33d..63977102ca 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -342,6 +342,7 @@ public: static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut); // Someone is offering X for Y, what is the rate? + // Rate: smaller is better, the taker wants the most out: in/out static uint64 getRate(const STAmount& offerOut, const STAmount& offerIn); static STAmount setRate(uint64 rate, const uint160& currencyOut); diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index ae32693fe6..5cb0f5a4f5 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -3221,6 +3221,8 @@ bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur, } // Calculate the next increment of a path. +// The increment is what can satisfy a portion or all of the requested output at the best quality. +// <-- pspCur->uQuality void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) { // The next state is what is available in preference order. @@ -3228,20 +3230,18 @@ void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) unsigned int uLast = pspCur->vpnNodes.size() - 1; - pspCur->lesEntries = mNodes.duplicate(); // Checkpoint state? - - if (!calcNode(uLast, pspCur, iPaths == 1)) + if (calcNode(uLast, pspCur, iPaths == 1)) + { + // Calculate relative quality. + pspCur->uQuality = STAmount::getRate(pspCur->saOutAct, pspCur->saInAct); + } + else { // Mark path as inactive. pspCur->uQuality = 0; } } -// Apply an increment of the path, then calculate the next increment. -void TransactionEngine::pathApply(PathState::pointer pspCur) -{ -} - // XXX Need to audit for things like setting accountID not having memory. TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn) { @@ -3484,23 +3484,28 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction while (tenUNKNOWN == terResult) { PathState::pointer pspBest; + LedgerEntrySet lesCheckpoint; + + mNodes.swapWith(lesCheckpoint); // Checkpoint ledger prior to path application. // Find the best path. BOOST_FOREACH(PathState::pointer pspCur, vpsPaths) { + mNodes.setTo(lesCheckpoint.duplicate()); // Vary ledger from checkpoint. + pathNext(pspCur, vpsPaths.size()); // Compute increment + mNodes.swapWith(pspCur->lesEntries); // For the path, save ledger state. + if (!pspBest || (pspCur->uQuality && PathState::lessPriority(pspBest, pspCur))) pspBest = pspCur; } - if (!pspBest) + if (pspBest) { - // - // Apply path. - // + // Apply best path. - // Install changes for path. + // Install ledger for best past. mNodes.swapWith(pspBest->lesEntries); // Figure out if done. @@ -3518,8 +3523,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction else if (saPaid.isZero()) { // Nothing claimed. - terResult = terPATH_EMPTY; // XXX No effect except unfundeds and charge fee. - // XXX + terResult = terPATH_EMPTY; // XXX No effect except unfundeds and charge fee. } else { diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 5e1d76c767..16e105b57a 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -239,7 +239,6 @@ protected: STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault); PathState::pointer pathCreate(const STPath& spPath); - void pathApply(PathState::pointer pspCur); void pathNext(PathState::pointer pspCur, int iPaths); bool calcNode(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); bool calcNodeOfferRev(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); From 8ef27615dcd6cb7e82559d6ff48cc04994dfad0f Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 14 Aug 2012 18:18:15 -0700 Subject: [PATCH 057/426] Add getJson to PathState. --- src/TransactionEngine.cpp | 74 +++++++++++++++++++++++++++++++++------ src/TransactionEngine.h | 10 ++---- 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 5cb0f5a4f5..70695407b8 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -3182,6 +3182,59 @@ PathState::PathState( pushNode(STPathElement::typeAccount, uReceiverID, saOutReq.getCurrency(), saOutReq.getIssuer()); } +Json::Value PathState::getJson() const +{ + Json::Value jvPathState(Json::arrayValue); + Json::Value jvNodes(Json::arrayValue); + + BOOST_FOREACH(const paymentNode& pnNode, vpnNodes) + { + Json::Value jvNode(Json::objectValue); + + Json::Value jvFlags(Json::objectValue); + + if (pnNode.uFlags & STPathElement::typeRedeem) + jvFlags["redeem"] = 1; + + if (pnNode.uFlags & STPathElement::typeIssue) + jvFlags["issue"] = 1; + + jvNode["flags"] = jvFlags; + + if (pnNode.uFlags & STPathElement::typeAccount) + jvNode["account"] = NewcoinAddress::createHumanAccountID(pnNode.uAccountID); + + if (!!pnNode.uCurrencyID) + jvNode["currency"] = STAmount::createHumanCurrency(pnNode.uCurrencyID); + + if (!!pnNode.uIssuerID) + jvNode["issuer"] = NewcoinAddress::createHumanAccountID(pnNode.uIssuerID); + + jvNodes.append(jvNode); + } + + jvPathState["nodes"] = jvNodes; + + jvPathState["index"] = mIndex; + + if (!!saInReq) + jvPathState["in_req"] = saInReq.getJson(0); + + if (!!saOutReq) + jvPathState["in_act"] = saInAct.getJson(0); + + if (!!saOutReq) + jvPathState["out_req"] = saOutReq.getJson(0); + + if (!!saOutAct) + jvPathState["out_act"] = saOutAct.getJson(0); + + if (uQuality) + jvPathState["uQuality"] = Json::Value::UInt(uQuality); + + return jvNodes; +} + // Calculate a node and its previous nodes. // From the destination work towards the source calculating how much must be asked for. // --> bAllowPartial: If false, fail if can't meet requirements. @@ -3230,16 +3283,15 @@ void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) unsigned int uLast = pspCur->vpnNodes.size() - 1; - if (calcNode(uLast, pspCur, iPaths == 1)) - { - // Calculate relative quality. - pspCur->uQuality = STAmount::getRate(pspCur->saOutAct, pspCur->saInAct); - } - else - { - // Mark path as inactive. - pspCur->uQuality = 0; - } + Log(lsINFO) << "Path In: " << pspCur->getJson(); + + bool bZero = !calcNode(uLast, pspCur, iPaths == 1); + + pspCur->uQuality = bZero + ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. + : 0; // Mark path as inactive. + + Log(lsINFO) << "Path Out: " << pspCur->getJson(); } // XXX Need to audit for things like setting accountID not having memory. @@ -3432,7 +3484,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); - if (!bNoRippleDirect && spsPaths.isEmpty()) + if (bNoRippleDirect && spsPaths.isEmpty()) { Log(lsINFO) << "doPayment: Invalid transaction: No paths and direct ripple not allowed."; diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 16e105b57a..7bb68509e0 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -151,6 +151,8 @@ public: bool bPartialPayment ); + Json::Value getJson() const; + static PathState::pointer createPathState( int iIndex, const LedgerEntrySet& lesSource, @@ -187,14 +189,6 @@ private: 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); -#ifdef WORK_IN_PROGRESS - - typedef struct { - std::vector vpnNodes; - bool bAllowPartial; - } paymentGroup; -#endif - TransactionEngineResult setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator); TransactionEngineResult takeOffers( From 11f7012d09d5963c7bd69e496752eed6b8f67125 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 15 Aug 2012 01:20:14 -0700 Subject: [PATCH 058/426] Fix a bug where tx set acquire timeouts never occured. Run acquire timeouts in milliseconds rather than seconds. --- src/LedgerAcquire.cpp | 8 +++++--- src/LedgerConsensus.cpp | 5 ++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 6e13a883c8..1a7e6e8edf 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -11,12 +11,14 @@ #include "HashPrefixes.h" // #define LA_DEBUG -#define LEDGER_ACQUIRE_TIMEOUT 1 +#define LEDGER_ACQUIRE_TIMEOUT 750 #define TRUST_NETWORK PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterval(interval), mTimeouts(0), mComplete(false), mFailed(false), mProgress(true), mTimer(theApp->getIOService()) -{ ; } +{ + assert((mTimerInterval > 10) && (mTimerInterval < 30000)); +} void PeerSet::peerHas(Peer::pointer ptr) { @@ -61,7 +63,7 @@ void PeerSet::badPeer(Peer::pointer ptr) void PeerSet::resetTimer() { - mTimer.expires_from_now(boost::posix_time::seconds(mTimerInterval)); + mTimer.expires_from_now(boost::posix_time::milliseconds(mTimerInterval)); mTimer.async_wait(boost::bind(&PeerSet::TimerEntry, pmDowncast(), boost::asio::placeholders::error)); } diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index aba77ea75f..5f34c7c344 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -13,11 +13,13 @@ #include "Log.h" #include "SHAMapSync.h" +#define TX_ACQUIRE_TIMEOUT 250 + #define TRUST_NETWORK // #define LC_DEBUG -TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, 1), mHaveRoot(false) +TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false) { mMap = boost::make_shared(); mMap->setSynching(); @@ -664,6 +666,7 @@ void LedgerConsensus::startAcquiring(TransactionAcquire::pointer acquire) } } } + acquire->resetTimer(); } void LedgerConsensus::propose(const std::vector& added, const std::vector& removed) From abf41dd4def1c9735ef44d5a485ad1fb50a348b4 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 15 Aug 2012 04:01:22 -0700 Subject: [PATCH 059/426] Fix a large number of cases where we copy construct a shared_ptr just to destroy it. --- src/LedgerAcquire.cpp | 8 ++++---- src/LedgerAcquire.h | 12 ++++++------ src/LedgerConsensus.cpp | 2 +- src/LedgerConsensus.h | 6 +++--- src/LedgerEntrySet.cpp | 8 ++++---- src/LedgerEntrySet.h | 10 +++++----- src/Peer.cpp | 4 ++-- src/Peer.h | 31 +++++++++++++------------------ src/ValidationCollection.cpp | 2 +- src/ValidationCollection.h | 4 ++-- 10 files changed, 41 insertions(+), 46 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 1a7e6e8edf..d2189e693f 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -20,7 +20,7 @@ PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterva assert((mTimerInterval > 10) && (mTimerInterval < 30000)); } -void PeerSet::peerHas(Peer::pointer ptr) +void PeerSet::peerHas(const Peer::pointer& ptr) { boost::recursive_mutex::scoped_lock sl(mLock); std::vector< boost::weak_ptr >::iterator it = mPeers.begin(); @@ -40,7 +40,7 @@ void PeerSet::peerHas(Peer::pointer ptr) newPeer(ptr); } -void PeerSet::badPeer(Peer::pointer ptr) +void PeerSet::badPeer(const Peer::pointer& ptr) { boost::recursive_mutex::scoped_lock sl(mLock); std::vector< boost::weak_ptr >::iterator it = mPeers.begin(); @@ -142,7 +142,7 @@ void LedgerAcquire::addOnComplete(boost::function mLock.unlock(); } -void LedgerAcquire::trigger(Peer::pointer peer, bool timer) +void LedgerAcquire::trigger(const Peer::pointer& peer, bool timer) { if (mAborted || mComplete || mFailed) return; @@ -435,7 +435,7 @@ void LedgerAcquireMaster::dropLedger(const uint256& hash) mLedgers.erase(hash); } -bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::pointer peer) +bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, const Peer::pointer& peer) { #ifdef LA_DEBUG Log(lsTRACE) << "got data for acquiring ledger "; diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index 1497ca41ad..3ea334bd10 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -41,12 +41,12 @@ public: void progress() { mProgress = true; } - void peerHas(Peer::pointer); - void badPeer(Peer::pointer); + void peerHas(const Peer::pointer&); + void badPeer(const Peer::pointer&); void resetTimer(); protected: - virtual void newPeer(Peer::pointer) = 0; + virtual void newPeer(const Peer::pointer&) = 0; virtual void onTimer(void) = 0; virtual boost::weak_ptr pmDowncast() = 0; @@ -72,7 +72,7 @@ protected: void done(); void onTimer(); - void newPeer(Peer::pointer peer) { trigger(peer, false); } + void newPeer(const Peer::pointer& peer) { trigger(peer, false); } boost::weak_ptr pmDowncast(); @@ -92,7 +92,7 @@ public: bool takeTxRootNode(const std::vector& data); bool takeAsNode(const std::list& IDs, const std::list >& data); bool takeAsRootNode(const std::vector& data); - void trigger(Peer::pointer, bool timer); + void trigger(const Peer::pointer&, bool timer); }; class LedgerAcquireMaster @@ -108,7 +108,7 @@ public: LedgerAcquire::pointer find(const uint256& hash); bool hasLedger(const uint256& ledgerHash); void dropLedger(const uint256& ledgerHash); - bool gotLedgerData(newcoin::TMLedgerData& packet, Peer::pointer); + bool gotLedgerData(newcoin::TMLedgerData& packet, const Peer::pointer&); }; #endif diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 5f34c7c344..2b45f3b8c4 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -41,7 +41,7 @@ boost::weak_ptr TransactionAcquire::pmDowncast() return boost::shared_polymorphic_downcast(shared_from_this()); } -void TransactionAcquire::trigger(Peer::pointer peer, bool timer) +void TransactionAcquire::trigger(const Peer::pointer& peer, bool timer) { if (mComplete || mFailed) return; diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 7e104a43b7..cadfb23acd 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -27,11 +27,11 @@ protected: SHAMap::pointer mMap; bool mHaveRoot; - void onTimer() { trigger(Peer::pointer(), true); } - void newPeer(Peer::pointer peer) { trigger(peer, false); } + void onTimer() { trigger(Peer::pointer(), true); } + void newPeer(const Peer::pointer& peer) { trigger(peer, false); } void done(); - void trigger(Peer::pointer, bool timer); + void trigger(const Peer::pointer&, bool timer); boost::weak_ptr pmDowncast(); public: diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 9dc3bb157c..390cec2301 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -61,7 +61,7 @@ LedgerEntryAction LedgerEntrySet::hasEntry(const uint256& index) const return it->second.mAction; } -void LedgerEntrySet::entryCache(SLE::pointer& sle) +void LedgerEntrySet::entryCache(const SLE::pointer& sle) { boost::unordered_map::iterator it = mEntries.find(sle->getIndex()); if (it == mEntries.end()) @@ -82,7 +82,7 @@ void LedgerEntrySet::entryCache(SLE::pointer& sle) } } -void LedgerEntrySet::entryCreate(SLE::pointer& sle) +void LedgerEntrySet::entryCreate(const SLE::pointer& sle) { boost::unordered_map::iterator it = mEntries.find(sle->getIndex()); if (it == mEntries.end()) @@ -112,7 +112,7 @@ void LedgerEntrySet::entryCreate(SLE::pointer& sle) } } -void LedgerEntrySet::entryModify(SLE::pointer& sle) +void LedgerEntrySet::entryModify(const SLE::pointer& sle) { boost::unordered_map::iterator it = mEntries.find(sle->getIndex()); if (it == mEntries.end()) @@ -147,7 +147,7 @@ void LedgerEntrySet::entryModify(SLE::pointer& sle) } } -void LedgerEntrySet::entryDelete(SLE::pointer& sle, bool unfunded) +void LedgerEntrySet::entryDelete(const SLE::pointer& sle, bool unfunded) { boost::unordered_map::iterator it = mEntries.find(sle->getIndex()); if (it == mEntries.end()) diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 02c09c559c..0980d094b3 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -23,7 +23,7 @@ public: LedgerEntryAction mAction; int mSeq; - LedgerEntrySetEntry(SLE::pointer e, LedgerEntryAction a, int s) : mEntry(e), mAction(a), mSeq(s) { ; } + LedgerEntrySetEntry(const SLE::pointer& e, LedgerEntryAction a, int s) : mEntry(e), mAction(a), mSeq(s) { ; } }; @@ -53,10 +53,10 @@ public: // basic entry functions SLE::pointer getEntry(const uint256& index, LedgerEntryAction&); LedgerEntryAction hasEntry(const uint256& index) const; - void entryCache(SLE::pointer&); // Add this entry to the cache - void entryCreate(SLE::pointer&); // This entry will be created - void entryDelete(SLE::pointer&, bool unfunded); - void entryModify(SLE::pointer&); // This entry will be modified + void entryCache(const SLE::pointer&); // Add this entry to the cache + void entryCreate(const SLE::pointer&); // This entry will be created + void entryDelete(const SLE::pointer&, bool unfunded); + void entryModify(const SLE::pointer&); // This entry will be modified Json::Value getJson(int) const; void addRawMeta(Serializer&); diff --git a/src/Peer.cpp b/src/Peer.cpp index 28b79d5024..d589cb9496 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -260,7 +260,7 @@ void Peer::connected(const boost::system::error_code& error) } } -void Peer::sendPacketForce(PackedMessage::pointer packet) +void Peer::sendPacketForce(const PackedMessage::pointer& packet) { if (!mDetaching) { @@ -273,7 +273,7 @@ void Peer::sendPacketForce(PackedMessage::pointer packet) } } -void Peer::sendPacket(PackedMessage::pointer packet) +void Peer::sendPacket(const PackedMessage::pointer& packet) { if (packet) { diff --git a/src/Peer.h b/src/Peer.h index 13cf6b79bc..01c5863714 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -30,7 +30,7 @@ public: static const int psbNoLedgers = 4, psbNoTransactions = 5, psbDownLevel = 6; void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it); - static void sHandleConnect(Peer::pointer ptr, const boost::system::error_code& error, + static void sHandleConnect(const Peer::pointer& ptr, const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it) { ptr->handleConnect(error, it); } @@ -52,11 +52,11 @@ private: boost::asio::deadline_timer mVerifyTimer; void handleStart(const boost::system::error_code& ecResult); - static void sHandleStart(Peer::pointer ptr, const boost::system::error_code& ecResult) + static void sHandleStart(const Peer::pointer& ptr, const boost::system::error_code& ecResult) { ptr->handleStart(ecResult); } void handleVerifyTimer(const boost::system::error_code& ecResult); - static void sHandleVerifyTimer(Peer::pointer ptr, const boost::system::error_code& ecResult) + static void sHandleVerifyTimer(const Peer::pointer& ptr, const boost::system::error_code& ecResult) { ptr->handleVerifyTimer(ecResult); } protected: @@ -70,26 +70,26 @@ protected: Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx); void handleShutdown(const boost::system::error_code& error) { ; } - static void sHandleShutdown(Peer::pointer ptr, const boost::system::error_code& error) + static void sHandleShutdown(const Peer::pointer& ptr, const boost::system::error_code& error) { ptr->handleShutdown(error); } void handle_write(const boost::system::error_code& error, size_t bytes_transferred); - static void sHandle_write(Peer::pointer ptr, const boost::system::error_code& error, size_t bytes_transferred) + static void sHandle_write(const Peer::pointer& ptr, const boost::system::error_code& error, size_t bytes_transferred) { ptr->handle_write(error, bytes_transferred); } void handle_read_header(const boost::system::error_code& error); - static void sHandle_read_header(Peer::pointer ptr, const boost::system::error_code& error) + static void sHandle_read_header(const Peer::pointer& ptr, const boost::system::error_code& error) { ptr->handle_read_header(error); } void handle_read_body(const boost::system::error_code& error); - static void sHandle_read_body(Peer::pointer ptr, const boost::system::error_code& error) + static void sHandle_read_body(const Peer::pointer& ptr, const boost::system::error_code& error) { ptr->handle_read_body(error); } void processReadBuffer(); void start_read_header(); void start_read_body(unsigned msg_len); - void sendPacketForce(PackedMessage::pointer packet); + void sendPacketForce(const PackedMessage::pointer& packet); void sendHello(); @@ -139,12 +139,12 @@ public: void connect(const std::string strIp, int iPort); void connected(const boost::system::error_code& error); void detach(const char *); - bool samePeer(Peer::pointer p) { return samePeer(*p); } - bool samePeer(const Peer& p) { return this == &p; } + bool samePeer(const Peer::pointer& p) { return samePeer(*p); } + bool samePeer(const Peer& p) { return this == &p; } - void sendPacket(PackedMessage::pointer packet); - void sendLedgerProposal(Ledger::pointer ledger); - void sendFullLedger(Ledger::pointer ledger); + void sendPacket(const PackedMessage::pointer& packet); + void sendLedgerProposal(const Ledger::pointer& ledger); + void sendFullLedger(const Ledger::pointer& ledger); void sendGetFullLedger(uint256& hash); void sendGetPeers(); @@ -153,11 +153,6 @@ public: Json::Value getJson(); bool isConnected() const { return mHelloed && !mDetaching; } - //static PackedMessage::pointer createFullLedger(Ledger::pointer ledger); - static PackedMessage::pointer createLedgerProposal(Ledger::pointer ledger); - static PackedMessage::pointer createValidation(Ledger::pointer ledger); - static PackedMessage::pointer createGetFullLedger(uint256& hash); - uint256 getClosedLedgerHash() const { return mClosedLedgerHash; } bool hasLedger(const uint256& hash) const; NewcoinAddress getNodePublic() const { return mNodePublic; } diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 1502e4b52d..1bb971c576 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -7,7 +7,7 @@ // #define VC_DEBUG -bool ValidationCollection::addValidation(SerializedValidation::pointer& val) +bool ValidationCollection::addValidation(const SerializedValidation::pointer& val) { NewcoinAddress signer = val->getSignerPublic(); bool isCurrent = false; diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index 1ed522dc54..bdd224a040 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -17,7 +17,7 @@ class ValidationPair public: SerializedValidation::pointer oldest, newest; - ValidationPair(SerializedValidation::pointer v) : newest(v) { ; } + ValidationPair(const SerializedValidation::pointer& v) : newest(v) { ; } }; class ValidationCollection @@ -38,7 +38,7 @@ protected: public: ValidationCollection() : mWriting(false) { ; } - bool addValidation(SerializedValidation::pointer&); + bool addValidation(const SerializedValidation::pointer&); ValidationSet getValidations(const uint256& ledger); void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted); From 4f285dc603318f9f41c682068e3971669f6bc670 Mon Sep 17 00:00:00 2001 From: jed Date: Wed, 15 Aug 2012 10:35:12 -0700 Subject: [PATCH 060/426] add RippleLines --- newcoin.vcxproj | 12 +++++++ newcoin.vcxproj.filters | 12 +++++++ src/Ledger.h | 2 +- src/NetworkOPs.cpp | 9 ----- src/NetworkOPs.h | 16 +-------- src/RPCServer.cpp | 74 +++++++++-------------------------------- src/RippleLines.cpp | 48 ++++++++++++++++++++++++++ src/RippleLines.h | 19 +++++++++++ src/RippleState.cpp | 4 +-- src/RippleState.h | 2 +- 10 files changed, 112 insertions(+), 86 deletions(-) create mode 100644 src/RippleLines.cpp create mode 100644 src/RippleLines.h diff --git a/newcoin.vcxproj b/newcoin.vcxproj index d6c37b34c1..65bbd332c4 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -50,6 +50,7 @@ Disabled BOOST_TEST_ALTERNATIVE_INIT_API;BOOST_TEST_NO_MAIN;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0501;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) ..\OpenSSL\include;..\boost_1_47_0;..\protobuf-2.4.1\src\ + ProgramDatabase Console @@ -125,12 +126,14 @@ + + @@ -210,11 +213,13 @@ + + @@ -259,6 +264,13 @@ + + + + + + + diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index 2116e89379..b636aa2606 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -276,6 +276,12 @@ Source Files + + Source Files + + + Source Files + @@ -506,6 +512,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/src/Ledger.h b/src/Ledger.h index f830124e22..b90d440895 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -260,7 +260,7 @@ public: // Ripple functions : credit lines // - // Index of node which is the ripple state between to accounts for a currency. + // Index of node which is the ripple state between two accounts for a currency. static uint256 getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency); static uint256 getRippleStateIndex(const uint160& uiA, const uint160& uiB, const uint160& uCurrency) { return getRippleStateIndex(NewcoinAddress::createAccountID(uiA), NewcoinAddress::createAccountID(uiB), uCurrency); } diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index afbf87e32a..c09d427e55 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -292,15 +292,6 @@ Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddr return jvObjects; } -// -// Ripple functions -// - -RippleState::pointer NetworkOPs::accessRippleState(const uint256& uLedger, const uint256& uIndex) -{ - return mLedgerMaster->getLedgerByHash(uLedger)->accessRippleState(uIndex); -} - // // Other // diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 8e8e45c24c..e631685bc0 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -145,21 +145,7 @@ public: Json::Value getOwnerInfo(const uint256& uLedger, const NewcoinAddress& naAccount); Json::Value getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddress& naAccount); - // - // Ripple functions - // - - bool getDirLineInfo(const uint256& uLedger, const NewcoinAddress& naAccount, uint256& uRootIndex) - { - LedgerStateParms lspNode = lepNONE; - - uRootIndex = Ledger::getRippleDirIndex(naAccount.getAccountID()); - - return !!mLedgerMaster->getLedgerByHash(uLedger)->getDirNode(lspNode, uRootIndex); - } - - RippleState::pointer accessRippleState(const uint256& uLedger, const uint256& uIndex); - + // raw object operations bool findRawLedger(const uint256& ledgerHash, std::vector& rawLedger); bool findRawTransaction(const uint256& transactionHash, std::vector& rawTransaction); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 46ea9eda7d..db22f72683 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -12,6 +12,7 @@ #include "NicknameState.h" #include "utils.h" #include "Log.h" +#include "RippleLines.h" #include @@ -1654,70 +1655,27 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) // XXX This is wrong, we do access the current ledger and do need to worry about changes. // We access a committed ledger and need not worry about changes. - uint256 uRootIndex; - if (mNetOps->getDirLineInfo(uCurrent, naAccount, uRootIndex)) + RippleLines rippleLines(naAccount.getAccountID()); + BOOST_FOREACH(RippleState::pointer line,rippleLines.getLines()) { - Log(lsINFO) << "doRippleLinesGet: dir root index: " << uRootIndex.ToString(); - bool bDone = false; + STAmount saBalance = line->getBalance(); + STAmount saLimit = line->getLimit(); + STAmount saLimitPeer = line->getLimitPeer(); - while (!bDone) - { - uint64 uNodePrevious; - uint64 uNodeNext; - STVector256 svRippleNodes = mNetOps->getDirNodeInfo(uCurrent, uRootIndex, uNodePrevious, uNodeNext); + Json::Value jPeer = Json::Value(Json::objectValue); - Log(lsINFO) << "doRippleLinesGet: previous: " << strHex(uNodePrevious); - Log(lsINFO) << "doRippleLinesGet: next: " << strHex(uNodeNext); - Log(lsINFO) << "doRippleLinesGet: lines: " << svRippleNodes.peekValue().size(); + //jPeer["node"] = uNode.ToString(); - BOOST_FOREACH(uint256& uNode, svRippleNodes.peekValue()) - { - Log(lsINFO) << "doRippleLinesGet: line index: " << uNode.ToString(); + jPeer["account"] = line->getAccountIDPeer().humanAccountID(); + // Amount reported is positive if current account holds other account's IOUs. + // Amount reported is negative if other account holds current account's IOUs. + jPeer["balance"] = saBalance.getText(); + jPeer["currency"] = saBalance.getHumanCurrency(); + jPeer["limit"] = saLimit.getText(); + jPeer["limit_peer"] = saLimitPeer.getText(); - RippleState::pointer rsLine = mNetOps->accessRippleState(uCurrent, uNode); - - if (rsLine) - { - rsLine->setViewAccount(naAccount); - - STAmount saBalance = rsLine->getBalance(); - STAmount saLimit = rsLine->getLimit(); - STAmount saLimitPeer = rsLine->getLimitPeer(); - - Json::Value jPeer = Json::Value(Json::objectValue); - - jPeer["node"] = uNode.ToString(); - - jPeer["account"] = rsLine->getAccountIDPeer().humanAccountID(); - // Amount reported is positive if current account hold's other account's IOUs. - // Amount reported is negative if other account hold's current account's IOUs. - jPeer["balance"] = saBalance.getText(); - jPeer["currency"] = saBalance.getHumanCurrency(); - jPeer["limit"] = saLimit.getText(); - jPeer["limit_peer"] = saLimitPeer.getText(); - - jsonLines.append(jPeer); - } - else - { - Log(lsWARNING) << "doRippleLinesGet: Bad index: " << uNode.ToString(); - } - } - - if (uNodeNext) - { - uCurrent = Ledger::getDirNodeIndex(uRootIndex, uNodeNext); - } - else - { - bDone = true; - } - } - } - else - { - Log(lsINFO) << "doRippleLinesGet: no directory: " << uRootIndex.ToString(); + jsonLines.append(jPeer); } ret["lines"] = jsonLines; } diff --git a/src/RippleLines.cpp b/src/RippleLines.cpp new file mode 100644 index 0000000000..26e9fa827b --- /dev/null +++ b/src/RippleLines.cpp @@ -0,0 +1,48 @@ +#include "RippleLines.h" +#include "Application.h" +#include "Log.h" +#include + +RippleLines::RippleLines(const uint160& accountID, Ledger::pointer ledger) +{ + fillLines(accountID,ledger); +} + +RippleLines::RippleLines(const uint160& accountID ) +{ + fillLines(accountID,theApp->getMasterLedger().getCurrentLedger()); +} + +void RippleLines::fillLines(const uint160& accountID, Ledger::pointer ledger) +{ + uint256 rootIndex = Ledger::getRippleDirIndex(accountID); + uint256 currentIndex=rootIndex; + + LedgerStateParms lspNode = lepNONE; + + while(1) + { + SerializedLedgerEntry::pointer rippleDir=ledger->getDirNode(lspNode,currentIndex); + if(!rippleDir) return; + + STVector256 svRippleNodes = rippleDir->getIFieldV256(sfIndexes); + BOOST_FOREACH(uint256& uNode, svRippleNodes.peekValue()) + { + RippleState::pointer rsLine = ledger->accessRippleState(uNode); + if (rsLine) + { + rsLine->setViewAccount(accountID); + mLines.push_back(rsLine); + } + else + { + Log(lsWARNING) << "doRippleLinesGet: Bad index: " << uNode.ToString(); + } + } + + uint64 uNodeNext = rippleDir->getIFieldU64(sfIndexNext); + if(!uNodeNext) return; + + currentIndex = Ledger::getDirNodeIndex(rootIndex, uNodeNext); + } +} diff --git a/src/RippleLines.h b/src/RippleLines.h new file mode 100644 index 0000000000..13ea7f5dc4 --- /dev/null +++ b/src/RippleLines.h @@ -0,0 +1,19 @@ +#include "Ledger.h" +#include "RippleState.h" + +/* +This pulls all the ripple lines of a given account out of the ledger. +It provides a vector so you to easily iterate through them +*/ + +class RippleLines +{ + std::vector mLines; + void fillLines(const uint160& accountID, Ledger::pointer ledger); +public: + + RippleLines(const uint160& accountID, Ledger::pointer ledger); + RippleLines(const uint160& accountID ); // looks in the current ledger + + std::vector& getLines(){ return(mLines); } +}; \ No newline at end of file diff --git a/src/RippleState.cpp b/src/RippleState.cpp index 0b319faab7..b4a4712d57 100644 --- a/src/RippleState.cpp +++ b/src/RippleState.cpp @@ -18,9 +18,9 @@ RippleState::RippleState(SerializedLedgerEntry::pointer ledgerEntry) : mValid = true; } -void RippleState::setViewAccount(const NewcoinAddress& naView) +void RippleState::setViewAccount(const uint160& accountID) { - bool bViewLowestNew = mLowID.getAccountID() == naView.getAccountID(); + bool bViewLowestNew = mLowID.getAccountID() == accountID; if (bViewLowestNew != mViewLowest) { diff --git a/src/RippleState.h b/src/RippleState.h index 8efbae945f..e4b34eab41 100644 --- a/src/RippleState.h +++ b/src/RippleState.h @@ -32,7 +32,7 @@ private: public: RippleState(SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger - void setViewAccount(const NewcoinAddress& naView); + void setViewAccount(const uint160& accountID); const NewcoinAddress getAccountID() const { return mViewLowest ? mLowID : mHighID; } const NewcoinAddress getAccountIDPeer() const { return mViewLowest ? mHighID : mLowID; } From f4714736cbd1cb43ae9b74226c09b6b8a4860ffa Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 15 Aug 2012 14:59:55 -0700 Subject: [PATCH 061/426] Fixes for path checkpointing and expansion. --- src/TransactionEngine.cpp | 198 ++++++++++++++++++++++++++++---------- src/TransactionEngine.h | 2 + 2 files changed, 151 insertions(+), 49 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 70695407b8..c0c32519c5 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -836,7 +836,6 @@ SLE::pointer TransactionEngine::entryCreate(LedgerEntryType letType, const uint2 return sleNew; } - void TransactionEngine::entryDelete(SLE::pointer sleEntry, bool unfunded) { mNodes.entryDelete(sleEntry, unfunded); @@ -3046,16 +3045,86 @@ bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::poi return lhs->mIndex > rhs->mIndex; // Bigger is worse. } -// Add a node and insert any implied nodes. +// Make sure the path delivers to uAccountID: uCurrencyID from uIssuerID. +bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) +{ + const paymentNode& pnPrv = vpnNodes.back(); + bool bValid = true; + + Log(lsINFO) << "pushImply> " + << NewcoinAddress::createHumanAccountID(uAccountID) + << " " << STAmount::createHumanCurrency(uCurrencyID) + << " " << NewcoinAddress::createHumanAccountID(uIssuerID); + + if (pnPrv.uCurrencyID != uCurrencyID) + { + // Need to convert via an offer. +#if 0 +// XXX Don't know if need this. + bool bPrvAccount = !!pnPrv.uAccountID; + + if (!bPrvAccount) // Previous is an offer. + { + // Direct offer --> offer is not allowed for non-stamps. + // Need to ripple through uIssuerID's account. + + bValid = pushNode( + STPathElement::typeAccount + | STPathElement::typeIssue, + pnPrv.uIssuerID, // Intermediate account is the needed issuer. + CURRENCY_ONE, // Inherit from previous. + ACCOUNT_ONE); // Default same as account. + } +#endif + + bValid = pushNode( + 0, // Offer + ACCOUNT_ONE, // Placeholder for offers. + uCurrencyID, // The offer's output is what is now wanted. + uIssuerID); + + } + + if (bValid + && !!uCurrencyID // Not stamps. + && (pnPrv.uAccountID != uIssuerID // Previous is not issuing own IOUs. + && uAccountID != uIssuerID)) // Current is not receiving own IOUs. + { + // Need to ripple through uIssuerID's account. + + bValid = pushNode( + STPathElement::typeAccount + | STPathElement::typeRedeem + | STPathElement::typeIssue, + uIssuerID, // Intermediate account is the needed issuer. + uCurrencyID, + uIssuerID); + } + + Log(lsINFO) << "pushImply< " << bValid; + + return bValid; +} + +// Append a node and insert before it any implied nodes. // <-- bValid: true, if node is valid. false, if node is malformed. bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) { + Log(lsINFO) << "pushNode> " + << NewcoinAddress::createHumanAccountID(uAccountID) + << " " << STAmount::createHumanCurrency(uCurrencyID) + << " " << NewcoinAddress::createHumanAccountID(uIssuerID); paymentNode pnCur; bool bFirst = vpnNodes.empty(); const paymentNode& pnPrv = bFirst ? paymentNode() : vpnNodes.back(); + // true, iff node is a ripple account. false, iff node is an offer node. bool bAccount = !!(iType & STPathElement::typeAccount); + // true, iff currency supplied. + // Currency is specified for the output of the current node. bool bCurrency = !!(iType & STPathElement::typeCurrency); + // Issuer is specified for the output of the current node. bool bIssuer = !!(iType & STPathElement::typeIssuer); + // true, iff account is allowed to redeem it's IOUs to next node. bool bRedeem = !!(iType & STPathElement::typeRedeem); bool bIssue = !!(iType & STPathElement::typeIssue); bool bValid = true; @@ -3064,6 +3133,8 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin if (iType & ~STPathElement::typeValidBits) { + Log(lsINFO) << "pushNode: bad bits."; + bValid = false; } else if (bAccount) @@ -3076,30 +3147,13 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; - // An intermediate node may be implied. - - if (uCurrencyID != pnPrv.uCurrencyID) + if (!bFirst) { - // Implied preceeding offer. - - bValid = pushNode( - 0, - ACCOUNT_ONE, - CURRENCY_ONE, // Inherit from previous - ACCOUNT_ONE); // Inherit from previous - } - - if (bValid && 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. + // Add required intermediate nodes to deliver to current account. + bValid = pushImply( + pnCur.uAccountID, // Current account. + pnCur.uCurrencyID, // Wanted currency. + !!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as issuer. } if (bValid) @@ -3107,6 +3161,8 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin } else { + Log(lsINFO) << "pushNode: Account must redeem and/or issue."; + bValid = false; } } @@ -3119,23 +3175,28 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin } else { - pnCur.uAccountID = uAccountID; + // Offers bridge a change in currency & issuer or just a change in issuer. pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; pnCur.uIssuerID = bIssuer ? uIssuerID : pnCur.uAccountID; - if (!!pnPrv.uAccountID // Previous is an account. - && pnPrv.uAccountID != pnCur.uIssuerID) // Account is not issuer. + if (!!pnPrv.uAccountID) { - // Implied preceeding account. + // Previous is an account. - bValid = pushNode( - STPathElement::typeAccount - | STPathElement::typeIssue, - uIssuerID, - CURRENCY_ONE, // Inherit from previous - ACCOUNT_ONE); // Default same as account. + // Insert intermediary account if needed. + bValid = pushImply( + !!pnPrv.uCurrencyID ? ACCOUNT_ONE : ACCOUNT_XNS, + pnPrv.uCurrencyID, + pnPrv.uIssuerID); } - else if (bValid) + else + { + // Previous is an offer. + // XXX Need code if we don't do offer to offer. + nothing(); + } + + if (bValid) { // Verify that previous account is allowed to issue. const paymentNode& pnLst = vpnNodes.back(); @@ -3143,13 +3204,18 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin bool bLstIssue = !!(pnLst.uFlags & STPathElement::typeIssue); if (bLstAccount && !bLstIssue) + { + Log(lsINFO) << "pushNode: previous account must be allowed to issue."; + bValid = false; // Malformed path. + } } if (bValid) vpnNodes.push_back(pnCur); } } + Log(lsINFO) << "pushNode< " << bValid; return bValid; } @@ -3167,24 +3233,55 @@ PathState::PathState( ) : mIndex(iIndex), uQuality(0) { + uint160 uInCurrencyID = saSendMax.getCurrency(); + uint160 uOutCurrencyID = saSend.getCurrency(); + uint160 uInIssuerID = !!uInCurrencyID ? uSenderID : ACCOUNT_XNS; + uint160 uOutIssuerID = !!uOutCurrencyID ? uReceiverID : ACCOUNT_XNS; + lesEntries = lesSource.duplicate(); - saOutReq = saSend; saInReq = saSendMax; + saOutReq = saSend; - pushNode(STPathElement::typeAccount, uSenderID, saSendMax.getCurrency(), saSendMax.getIssuer()); + bValid = pushNode( + STPathElement::typeAccount + | STPathElement::typeRedeem + | STPathElement::typeIssue + | STPathElement::typeCurrency + | STPathElement::typeIssuer, + uSenderID, + uInCurrencyID, + uInIssuerID); BOOST_FOREACH(const STPathElement& speElement, spSourcePath) { - pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID()); + if (bValid) + bValid = pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID()); } - pushNode(STPathElement::typeAccount, uReceiverID, saOutReq.getCurrency(), saOutReq.getIssuer()); + if (bValid) + { + // Create receiver node. + + bValid = pushImply(uReceiverID, uOutCurrencyID, uOutIssuerID); + if (bValid) + { + bValid = pushNode( + STPathElement::typeAccount // Last node is always an account. + | STPathElement::typeRedeem // Does not matter just pass error check. + | STPathElement::typeIssue, // Does not matter just pass error check. + uReceiverID, // Receive to output + uOutCurrencyID, // Desired currency + uOutIssuerID); + } + } + + Log(lsINFO) << "PathState: " << getJson(); } Json::Value PathState::getJson() const { - Json::Value jvPathState(Json::arrayValue); + Json::Value jvPathState(Json::objectValue); Json::Value jvNodes(Json::arrayValue); BOOST_FOREACH(const paymentNode& pnNode, vpnNodes) @@ -3213,14 +3310,14 @@ Json::Value PathState::getJson() const jvNodes.append(jvNode); } - jvPathState["nodes"] = jvNodes; - + jvPathState["valid"] = bValid; jvPathState["index"] = mIndex; + jvPathState["nodes"] = jvNodes; if (!!saInReq) jvPathState["in_req"] = saInReq.getJson(0); - if (!!saOutReq) + if (!!saInAct) jvPathState["in_act"] = saInAct.getJson(0); if (!!saOutReq) @@ -3232,7 +3329,7 @@ Json::Value PathState::getJson() const if (uQuality) jvPathState["uQuality"] = Json::Value::UInt(uQuality); - return jvNodes; + return jvPathState; } // Calculate a node and its previous nodes. @@ -3285,6 +3382,8 @@ void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) Log(lsINFO) << "Path In: " << pspCur->getJson(); + assert(pspCur->vpnNodes.size() >= 2); + bool bZero = !calcNode(uLast, pspCur, iPaths == 1); pspCur->uQuality = bZero @@ -3502,6 +3601,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction if (!bNoRippleDirect) { // Direct path. + Log(lsINFO) << "doPayment: Build direct:"; vpsPaths.push_back(PathState::createPathState( vpsPaths.size(), mNodes, @@ -3516,6 +3616,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction BOOST_FOREACH(const STPath& spPath, spsPaths) { + Log(lsINFO) << "doPayment: Build path:"; vpsPaths.push_back(PathState::createPathState( vpsPaths.size(), mNodes, @@ -3536,14 +3637,13 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction while (tenUNKNOWN == terResult) { PathState::pointer pspBest; - LedgerEntrySet lesCheckpoint; - - mNodes.swapWith(lesCheckpoint); // Checkpoint ledger prior to path application. + LedgerEntrySet lesCheckpoint = mNodes; // Find the best path. BOOST_FOREACH(PathState::pointer pspCur, vpsPaths) { - mNodes.setTo(lesCheckpoint.duplicate()); // Vary ledger from checkpoint. + mNodes = lesCheckpoint; // Restore from checkpoint. + mNodes.bumpSeq(); // Begin ledger varance. pathNext(pspCur, vpsPaths.size()); // Compute increment diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 7bb68509e0..f6e054e4cd 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -126,10 +126,12 @@ class PathState { protected: bool pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID); + bool pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID); public: typedef boost::shared_ptr pointer; + bool bValid; std::vector vpnNodes; LedgerEntrySet lesEntries; From 5a8a4ebbfcb16d9d02a630b5ca061ad94b960996 Mon Sep 17 00:00:00 2001 From: jed Date: Wed, 15 Aug 2012 15:16:32 -0700 Subject: [PATCH 062/426] . --- src/RippleLines.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/RippleLines.cpp b/src/RippleLines.cpp index 26e9fa827b..fce03685f2 100644 --- a/src/RippleLines.cpp +++ b/src/RippleLines.cpp @@ -15,13 +15,12 @@ RippleLines::RippleLines(const uint160& accountID ) void RippleLines::fillLines(const uint160& accountID, Ledger::pointer ledger) { - uint256 rootIndex = Ledger::getRippleDirIndex(accountID); + uint256 rootIndex = Ledger::getRippleDirIndex(accountID); uint256 currentIndex=rootIndex; - LedgerStateParms lspNode = lepNONE; - while(1) { + LedgerStateParms lspNode=lepNONE; SerializedLedgerEntry::pointer rippleDir=ledger->getDirNode(lspNode,currentIndex); if(!rippleDir) return; From 916cdf527920a7421794495eb417b0fcd36faa0d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 15 Aug 2012 15:33:03 -0700 Subject: [PATCH 063/426] Remove mOrigNodes. --- src/TransactionEngine.cpp | 12 ------------ src/TransactionEngine.h | 4 +--- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index c0c32519c5..45f1e5a113 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -813,10 +813,7 @@ SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint25 { sleEntry = mLedger->getSLE(uIndex); if (sleEntry) - { mNodes.entryCache(sleEntry); - mOrigNodes.entryCache(sleEntry); // So the metadata code can compare to the original - } } else if (action == taaDELETE) assert(false); @@ -893,13 +890,6 @@ void TransactionEngine::txnWrite() } } -// This is for when a transaction fails from the issuer's point of view and the current changes need to be cleared so other -// actions can be applied to the ledger. -void TransactionEngine::entryReset() -{ - mNodes.setTo(mOrigNodes); -} - TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn, TransactionEngineParams params) { @@ -1220,7 +1210,6 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran if (terSUCCESS == terResult) { entryModify(mTxnAccount); - mOrigNodes = mNodes.duplicate(); switch (txn.getTxnType()) { @@ -1305,7 +1294,6 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran mTxnAccount = SLE::pointer(); mNodes.clear(); - mOrigNodes.clear(); mUnfunded.clear(); return terResult; diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index f6e054e4cd..546287c03e 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -175,7 +175,7 @@ public: class TransactionEngine { private: - LedgerEntrySet mNodes, mOrigNodes; + LedgerEntrySet mNodes; TransactionEngineResult dirAdd( uint64& uNodeDir, // Node of entry. @@ -217,8 +217,6 @@ protected: void entryDelete(SLE::pointer sleEntry, bool unfunded = false); void entryModify(SLE::pointer sleEntry); - void entryReset(); - uint32 rippleTransfer(const uint160& uIssuerID); STAmount rippleBalance(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); STAmount rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); From 28c31e797be81532fed07b7a7c729fdbf7505069 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 16 Aug 2012 14:05:21 -0700 Subject: [PATCH 064/426] Disable SNTPClient in standalone mode. --- src/Application.cpp | 3 ++- src/SNTPClient.cpp | 3 ++- src/SNTPClient.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 2fe18c161f..dd94fb43b9 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -73,7 +73,8 @@ void Application::run() boost::thread auxThread(boost::bind(&boost::asio::io_service::run, &mAuxService)); auxThread.detach(); - mSNTPClient.init(theConfig.SNTP_SERVERS); + if (!theConfig.RUN_STANDALONE) + mSNTPClient.init(theConfig.SNTP_SERVERS); // // Construct databases. diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index 444b7b6c73..11a7915fae 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -47,7 +47,7 @@ SNTPClient::SNTPClient(boost::asio::io_service& service) : mSocket(service), mTi mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint, boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); - + mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY)); mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error)); } @@ -247,3 +247,4 @@ bool SNTPClient::doQuery() #endif return true; } +// vim:ts=4 diff --git a/src/SNTPClient.h b/src/SNTPClient.h index 51adf3ceb2..c2bf75ec63 100644 --- a/src/SNTPClient.h +++ b/src/SNTPClient.h @@ -56,3 +56,4 @@ public: }; #endif +// vim:ts=4 From 9c66ae8ef0da6045a2c2c08b981b63512678c47d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 16 Aug 2012 14:06:06 -0700 Subject: [PATCH 065/426] Fixes for ripple path expansion. --- src/TransactionEngine.cpp | 144 +++++++++++++++++++++++++++++--------- src/TransactionEngine.h | 6 +- 2 files changed, 116 insertions(+), 34 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index c0c32519c5..a2ebca5f4c 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -113,13 +113,24 @@ STAmount TransactionEngine::rippleBalance(const uint160& uToAccountID, const uin STAmount saBalance; SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); - assert(sleRippleState); if (sleRippleState) { saBalance = sleRippleState->getIValueFieldAmount(sfBalance); if (uToAccountID < uFromAccountID) saBalance.negate(); } + else + { + Log(lsINFO) << "rippleBalance: No credit line between " + << NewcoinAddress::createHumanAccountID(uFromAccountID) + << " and " + << NewcoinAddress::createHumanAccountID(uToAccountID) + << " for " + << STAmount::createHumanCurrency(uCurrencyID) + << "." ; + + assert(false); + } return saBalance; @@ -164,7 +175,13 @@ uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uin if (sleRippleState) { - uQualityIn = sleRippleState->getIFieldU32(uToAccountID < uFromAccountID ? sfLowQualityIn : sfHighQualityIn); + SOE_Field sfField = uToAccountID < uFromAccountID ? sfLowQualityIn : sfHighQualityIn; + + uQualityIn = sleRippleState->getIFieldPresent(sfField) + ? sleRippleState->getIFieldU32(sfField) + : QUALITY_ONE; + if (!uQualityIn) + uQualityIn = 1; } else { @@ -190,6 +207,8 @@ uint32 TransactionEngine::rippleQualityOut(const uint160& uToAccountID, const ui if (sleRippleState) { uQualityOut = sleRippleState->getIFieldU32(uToAccountID < uFromAccountID ? sfLowQualityOut : sfHighQualityOut); + if (!uQualityOut) + uQualityOut = 1; } else { @@ -2517,6 +2536,7 @@ void TransactionEngine::calcNodeOffer( // actual send toward the reciver. // This routine works backwards as it calculates previous wants based on previous credit limits and current wants. // This routine works forwards as it calculates current deliver based on previous delivery limits and current wants. +// XXX Deal with uQualityIn or uQualityOut = 0 void TransactionEngine::calcNodeRipple( const uint32 uQualityIn, const uint32 uQualityOut, @@ -2525,8 +2545,18 @@ void TransactionEngine::calcNodeRipple( STAmount& saPrvAct, // <-> in limit including achieved STAmount& saCurAct) // <-> out limit achieved. { + Log(lsINFO) << str(boost::format("calcNodeRipple> uQualityIn=%d uQualityOut=%d saPrvReq=%s/%s saCurReq=%s/%s") + % uQualityIn + % uQualityOut + % saPrvReq.getText() + % saPrvReq.getHumanCurrency() + % saCurReq.getText() + % saCurReq.getHumanCurrency()); + + assert(saPrvReq.getCurrency() == saCurReq.getCurrency()); + bool bPrvUnlimited = saPrvReq.isNegative(); - STAmount saPrv = bPrvUnlimited ? saZero : saPrvReq-saPrvAct; + STAmount saPrv = bPrvUnlimited ? STAmount(saPrvReq) : saPrvReq-saPrvAct; STAmount saCur = saCurReq-saCurAct; if (uQualityIn >= uQualityOut) @@ -2573,8 +2603,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point bool bPrvRedeem = !!(prvPN.uFlags & STPathElement::typeRedeem); bool bIssue = !!(curPN.uFlags & STPathElement::typeIssue); bool bPrvIssue = !!(prvPN.uFlags & STPathElement::typeIssue); - bool bPrvAccount = !!(prvPN.uFlags & STPathElement::typeAccount); - bool bNxtAccount = !!(nxtPN.uFlags & STPathElement::typeAccount); + bool bPrvAccount = uIndex && !!(prvPN.uFlags & STPathElement::typeAccount); + bool bNxtAccount = uIndex != uLast && !!(nxtPN.uFlags & STPathElement::typeAccount); uint160& uPrvAccountID = prvPN.uAccountID; uint160& uCurAccountID = curPN.uAccountID; @@ -2582,17 +2612,17 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point uint160& uCurrencyID = curPN.uCurrencyID; - uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); - uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); + uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : 0; + uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : 0; // For bPrvAccount - STAmount saPrvBalance = bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : saZero; - STAmount saPrvLimit = bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : saZero; + STAmount saPrvBalance = bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); + STAmount saPrvLimit = bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); STAmount saPrvRedeemReq = bPrvRedeem && saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); STAmount& saPrvRedeemAct = prvPN.saRevRedeem; - STAmount saPrvIssueReq = bPrvIssue && saPrvLimit - saPrvBalance; + STAmount saPrvIssueReq = bPrvIssue ? saPrvLimit - saPrvBalance : STAmount(uCurrencyID); STAmount& saPrvIssueAct = prvPN.saRevIssue; // For !bPrvAccount @@ -2601,19 +2631,25 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // For bNxtAccount const STAmount& saCurRedeemReq = curPN.saRevRedeem; - STAmount saCurRedeemAct; + STAmount saCurRedeemAct(saCurRedeemReq.getCurrency()); const STAmount& saCurIssueReq = curPN.saRevIssue; - STAmount saCurIssueAct; // Track progress. + STAmount saCurIssueAct(saCurIssueReq.getCurrency()); // Track progress. // For !bNxtAccount const STAmount& saCurDeliverReq = curPN.saRevDeliver; - STAmount saCurDeliverAct; + STAmount saCurDeliverAct(saCurDeliverReq.getCurrency()); // For uIndex == uLast const STAmount& saCurWantedReq = pspCur->saOutReq; // XXX Credit limits? // STAmount saPrvDeliverReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; - STAmount saCurWantedAct; + STAmount saCurWantedAct(saCurWantedReq.getCurrency()); + + Log(lsINFO) << str(boost::format("calcNodeAccountRev> saPrvRedeemReq=%s/%s saCurWantedAct=%s/%s") + % saPrvRedeemReq.getText() + % saPrvRedeemReq.getHumanCurrency() + % saCurWantedAct.getText() + % saCurWantedAct.getHumanCurrency()); if (bPrvAccount && bNxtAccount) { @@ -3156,6 +3192,40 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin !!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as issuer. } + if (bValid && !vpnNodes.empty()) + { + const paymentNode& pnBck = vpnNodes.back(); + bool bBckAccount = !!(pnBck.uFlags & STPathElement::typeAccount); + + if (bBckAccount) + { + SLE::pointer sleRippleState = mLedger->getSLE(Ledger::getRippleStateIndex(pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID)); + + if (!sleRippleState) + { + Log(lsINFO) << "pushNode: No credit line between " + << NewcoinAddress::createHumanAccountID(pnBck.uAccountID) + << " and " + << NewcoinAddress::createHumanAccountID(pnCur.uAccountID) + << " for " + << STAmount::createHumanCurrency(pnPrv.uCurrencyID) + << "." ; + + bValid = false; + } + else + { + Log(lsINFO) << "pushNode: Credit line found between " + << NewcoinAddress::createHumanAccountID(pnBck.uAccountID) + << " and " + << NewcoinAddress::createHumanAccountID(pnCur.uAccountID) + << " for " + << STAmount::createHumanCurrency(pnPrv.uCurrencyID) + << "." ; + } + } + } + if (bValid) vpnNodes.push_back(pnCur); } @@ -3199,11 +3269,11 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin if (bValid) { // Verify that previous account is allowed to issue. - const paymentNode& pnLst = vpnNodes.back(); - bool bLstAccount = !!(pnLst.uFlags & STPathElement::typeAccount); - bool bLstIssue = !!(pnLst.uFlags & STPathElement::typeIssue); + const paymentNode& pnBck = vpnNodes.back(); + bool bBckAccount = !!(pnBck.uFlags & STPathElement::typeAccount); + bool bBckIssue = !!(pnBck.uFlags & STPathElement::typeIssue); - if (bLstAccount && !bLstIssue) + if (bBckAccount && !bBckIssue) { Log(lsINFO) << "pushNode: previous account must be allowed to issue."; @@ -3222,6 +3292,7 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin // XXX Disallow loops in ripple paths PathState::PathState( + Ledger::pointer lpLedger, int iIndex, const LedgerEntrySet& lesSource, const STPath& spSourcePath, @@ -3231,7 +3302,7 @@ PathState::PathState( STAmount saSendMax, bool bPartialPayment ) - : mIndex(iIndex), uQuality(0) + : mLedger(lpLedger), mIndex(iIndex), uQuality(0) { uint160 uInCurrencyID = saSendMax.getCurrency(); uint160 uOutCurrencyID = saSend.getCurrency(); @@ -3335,7 +3406,7 @@ Json::Value PathState::getJson() const // Calculate a node and its previous nodes. // From the destination work towards the source calculating how much must be asked for. // --> bAllowPartial: If false, fail if can't meet requirements. -// <-- bSuccess: true=success, false=insufficient funds / liqudity. +// <-- bValid: true=success, false=insufficient funds / liqudity. // <-> pnNodes: // --> [end]saWanted.mAmount // --> [all]saWanted.mCurrency @@ -3346,28 +3417,28 @@ bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur, { paymentNode& curPN = pspCur->vpnNodes[uIndex]; bool bCurAccount = !!(curPN.uFlags & STPathElement::typeAccount); - bool bSuccess; + bool bValid; // Do current node reverse. - bSuccess = bCurAccount - ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) - : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); + bValid = bCurAccount + ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) + : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); // Do previous. - if (bSuccess && uIndex) + if (bValid && uIndex) { - bSuccess = calcNode(uIndex-1, pspCur, bMultiQuality); + bValid = calcNode(uIndex-1, pspCur, bMultiQuality); } // Do current node forward. - if (bSuccess) + if (bValid) { - bSuccess = bCurAccount - ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) - : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); + bValid = bCurAccount + ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) + : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); } - return bSuccess; + return bValid; } // Calculate the next increment of a path. @@ -3384,9 +3455,14 @@ void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) assert(pspCur->vpnNodes.size() >= 2); - bool bZero = !calcNode(uLast, pspCur, iPaths == 1); + bool bValid = calcNode(uLast, pspCur, iPaths == 1); - pspCur->uQuality = bZero + Log(lsINFO) << "pathNext: bValid=" + << bValid + << " saOutAct=" << pspCur->saOutAct.getText() + << " saInAct=" << pspCur->saInAct.getText(); + + pspCur->uQuality = bValid ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. : 0; // Mark path as inactive. @@ -3603,6 +3679,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // Direct path. Log(lsINFO) << "doPayment: Build direct:"; vpsPaths.push_back(PathState::createPathState( + mLedger, vpsPaths.size(), mNodes, STPath(), @@ -3618,6 +3695,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction { Log(lsINFO) << "doPayment: Build path:"; vpsPaths.push_back(PathState::createPathState( + mLedger, vpsPaths.size(), mNodes, spPath, diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index f6e054e4cd..3d54952d5a 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -125,6 +125,8 @@ typedef struct { class PathState { protected: + Ledger::pointer mLedger; + bool pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID); bool pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID); @@ -143,6 +145,7 @@ public: STAmount saOutAct; // Amount actually sent (calc output). PathState( + Ledger::pointer lpLedger, int iIndex, const LedgerEntrySet& lesSource, const STPath& spSourcePath, @@ -156,6 +159,7 @@ public: Json::Value getJson() const; static PathState::pointer createPathState( + Ledger::pointer lpLedger, int iIndex, const LedgerEntrySet& lesSource, const STPath& spSourcePath, @@ -165,7 +169,7 @@ public: STAmount saSendMax, bool bPartialPayment ) - { return boost::make_shared(iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax, bPartialPayment); }; + { return boost::make_shared(lpLedger, iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax, bPartialPayment); }; static bool lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs); }; From 27f4a2ce30dfd742d87e6bedc8fddaf457ed1f10 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 16 Aug 2012 14:13:59 -0700 Subject: [PATCH 066/426] Disable SNTPClient in standalone mode, try 2. --- src/Application.cpp | 3 +-- src/SNTPClient.cpp | 16 ++++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index dd94fb43b9..2fe18c161f 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -73,8 +73,7 @@ void Application::run() boost::thread auxThread(boost::bind(&boost::asio::io_service::run, &mAuxService)); auxThread.detach(); - if (!theConfig.RUN_STANDALONE) - mSNTPClient.init(theConfig.SNTP_SERVERS); + mSNTPClient.init(theConfig.SNTP_SERVERS); // // Construct databases. diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index 11a7915fae..d204b6a8ec 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -6,6 +6,7 @@ #include #include "utils.h" +#include "Config.h" #include "Log.h" // #define SNTP_DEBUG @@ -43,13 +44,16 @@ static uint8_t SNTPQueryData[48] = SNTPClient::SNTPClient(boost::asio::io_service& service) : mSocket(service), mTimer(service), mResolver(service), mOffset(0), mLastOffsetUpdate((time_t) -1), mReceiveBuffer(256) { - mSocket.open(boost::asio::ip::udp::v4()); - mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint, - boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + if (!theConfig.RUN_STANDALONE) + { + mSocket.open(boost::asio::ip::udp::v4()); + mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint, + boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); - mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY)); - mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error)); + mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY)); + mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error)); + } } void SNTPClient::resolveComplete(const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator it) From b789154c0818127c589a6be7a2f9a34ed2b910a9 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 16 Aug 2012 15:59:27 -0700 Subject: [PATCH 067/426] SLE support for threading through transactions. --- src/LedgerFormats.cpp | 2 +- src/SerializedLedger.cpp | 30 ++++++++++++++++++++++++++++++ src/SerializedLedger.h | 6 ++++++ src/SerializedObject.h | 3 ++- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 5b031ffc99..58507b6d9d 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -10,7 +10,7 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(LastReceive), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(LastTxn), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_IFFLAG, 1 }, { S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 2 }, { S_FIELD(WalletLocator), STI_HASH256, SOE_IFFLAG, 4 }, diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 372e9cd730..33d42d46c1 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -73,4 +73,34 @@ bool SerializedLedgerEntry::isEquivalent(const SerializedType& t) const if (mObject != v->mObject) return false; return true; } + +bool SerializedLedgerEntry::isThreadedType() +{ + return getIFieldIndex(sfLastTxnID) != -1; +} + +bool SerializedLedgerEntry::isThreaded() +{ + return getIFieldPresent(sfLastTxnID); +} + +uint256 SerializedLedgerEntry::getThreadedTransaction() +{ + return getIFieldH256(sfLastTxnID); +} + +uint32 SerializedLedgerEntry::getThreadedLedger() +{ + return getIFieldU32(sfLastTxnSeq); +} + +void SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID) +{ + prevTxID = getIFieldH256(sfLastTxnID); + prevLedgerID = getIFieldU32(sfLastTxnID); + assert(prevTxID != txID); + setIFieldH256(sfLastTxnID, txID); + setIFieldU32(sfLastTxnSeq, ledgerSeq); +} + // vim:ts=4 diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index 6df79d7e88..c629ddbbce 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -62,6 +62,12 @@ public: STAmount getIValueFieldAmount(SOE_Field field) const { return mObject.getValueFieldAmount(field); } STVector256 getIFieldV256(SOE_Field field) { return mObject.getValueFieldV256(field); } + bool isThreadedType(); // is this a ledger entry that can be threaded + bool isThreaded(); // is this ledger entry actually threaded + uint256 getThreadedTransaction(); + uint32 getThreadedLedger(); + void thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID); + void setIFieldU8(SOE_Field field, unsigned char v) { return mObject.setValueFieldU8(field, v); } void setIFieldU16(SOE_Field field, uint16 v) { return mObject.setValueFieldU16(field, v); } void setIFieldU32(SOE_Field field, uint32 v) { return mObject.setValueFieldU32(field, v); } diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 0480266bee..e8df6729f4 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -64,7 +64,8 @@ enum SOE_Field sfInvoiceID, sfLastNode, sfLastReceive, - sfLastTxn, + sfLastTxnID, + sfLastTxnSeq, sfLedgerHash, sfLimitAmount, sfLowID, From 50777639fb93df9adbca0a895e474298f1888ef9 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 16 Aug 2012 16:00:18 -0700 Subject: [PATCH 068/426] Set the tolerated clock offset to 20 seconds for now. --- src/Peer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index 7ef797a98a..0a258c477e 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -572,8 +572,8 @@ void Peer::recvHello(newcoin::TMHello& packet) (void) mVerifyTimer.cancel(); uint32 ourTime = theApp->getOPs().getNetworkTimeNC(); - uint32 minTime = ourTime - 10; - uint32 maxTime = ourTime + 10; + uint32 minTime = ourTime - 20; + uint32 maxTime = ourTime + 20; #ifdef DEBUG if (packet.has_nettime()) From 6bf10b1082f1829b68ede66ad351ba14f51a1e85 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 17 Aug 2012 16:18:22 -0700 Subject: [PATCH 069/426] Threading support for node deletion. --- src/SerializedLedger.cpp | 28 ++++++++++++++++++++++++++++ src/SerializedLedger.h | 2 ++ src/SerializedObject.cpp | 26 +++++++++++++++++++------- src/SerializedObject.h | 2 +- 4 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 33d42d46c1..3cc5c70dc0 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -2,6 +2,8 @@ #include +#include "Ledger.h" + SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint256& index) : SerializedType("LedgerEntry"), mIndex(index) { @@ -103,4 +105,30 @@ void SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint25 setIFieldU32(sfLastTxnSeq, ledgerSeq); } +std::vector SerializedLedgerEntry::getOwners() +{ + std::vector owners; + uint160 account; + + for (int i = 0, fields = getIFieldCount(); i < fields; ++i) + { + switch (getIFieldSType(i)) + { + case sfAccount: + case sfLowID: + case sfHighID: + { + const STAccount* entry = dynamic_cast(mObject.peekAtPIndex(i)); + if ((entry != NULL) && entry->getValueH160(account)) + owners.push_back(Ledger::getAccountRootIndex(account)); + } + + default: + nothing(); + } + } + + return owners; +} + // vim:ts=4 diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index c629ddbbce..c8ac2d96e5 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -47,6 +47,7 @@ public: int getIFieldCount() const { return mObject.getCount(); } const SerializedType& peekIField(SOE_Field field) const { return mObject.peekAtField(field); } SerializedType& getIField(SOE_Field field) { return mObject.getField(field); } + SOE_Field getIFieldSType(int index) { return mObject.getFieldSType(index); } std::string getIFieldString(SOE_Field field) const { return mObject.getFieldString(field); } unsigned char getIFieldU8(SOE_Field field) const { return mObject.getValueFieldU8(field); } @@ -67,6 +68,7 @@ public: uint256 getThreadedTransaction(); uint32 getThreadedLedger(); void thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID); + std::vector getOwners(); // nodes notified if this node is deleted void setIFieldU8(SOE_Field field, unsigned char v) { return mObject.setValueFieldU8(field, v); } void setIFieldU16(SOE_Field field, uint16 v) { return mObject.setValueFieldU16(field, v); } diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 6fbd45e63f..0f9af758e5 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -257,35 +257,45 @@ int STObject::getFieldIndex(SOE_Field field) const const SerializedType& STObject::peekAtField(SOE_Field field) const { int index = getFieldIndex(field); - if (index == -1) throw std::runtime_error("Field not found"); + if (index == -1) + throw std::runtime_error("Field not found"); return peekAtIndex(index); } SerializedType& STObject::getField(SOE_Field field) { int index = getFieldIndex(field); - if (index==-1) throw std::runtime_error("Field not found"); + if (index == -1) + throw std::runtime_error("Field not found"); return getIndex(index); } +SOE_Field STObject::getFieldSType(int index) const +{ + return mType[index]->e_field; +} + const SerializedType* STObject::peekAtPField(SOE_Field field) const { int index = getFieldIndex(field); - if (index == -1) return NULL; + if (index == -1) + return NULL; return peekAtPIndex(index); } SerializedType* STObject::getPField(SOE_Field field) { int index = getFieldIndex(field); - if (index == -1) return NULL; + if (index == -1) + return NULL; return getPIndex(index); } bool STObject::isFieldPresent(SOE_Field field) const { int index = getFieldIndex(field); - if (index == -1) return false; + if (index == -1) + return false; return peekAtIndex(index).getSType() != STI_NOTPRESENT; } @@ -318,7 +328,8 @@ uint32 STObject::getFlags(void) const SerializedType* STObject::makeFieldPresent(SOE_Field field) { int index = getFieldIndex(field); - if (index == -1) throw std::runtime_error("Field not found"); + if (index == -1) + throw std::runtime_error("Field not found"); if ((mType[index]->e_type != SOE_IFFLAG) && (mType[index]->e_type != SOE_IFNFLAG)) throw std::runtime_error("field is not optional"); @@ -338,7 +349,8 @@ SerializedType* STObject::makeFieldPresent(SOE_Field field) void STObject::makeFieldAbsent(SOE_Field field) { int index = getFieldIndex(field); - if (index == -1) throw std::runtime_error("Field not found"); + if (index == -1) + throw std::runtime_error("Field not found"); if ((mType[index]->e_type != SOE_IFFLAG) && (mType[index]->e_type != SOE_IFNFLAG)) throw std::runtime_error("field is not optional"); diff --git a/src/SerializedObject.h b/src/SerializedObject.h index e8df6729f4..5453a987b7 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -28,7 +28,6 @@ enum SOE_Field sfAcceptRate, sfAcceptStart, sfAccount, - sfAccountID, sfAmount, sfAuthorizedKey, sfBalance, @@ -162,6 +161,7 @@ public: SerializedType* getPIndex(int offset) { return &(mData[offset]); } int getFieldIndex(SOE_Field field) const; + SOE_Field getFieldSType(int index) const; const SerializedType& peekAtField(SOE_Field field) const; SerializedType& getField(SOE_Field field); From f2902ca0148d3e6fdd28c9f2bee3f9c1e63b124e Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 17 Aug 2012 17:08:23 -0700 Subject: [PATCH 070/426] Make json full text for STAccount more legible. --- src/Amount.cpp | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 1e2db3124c..e6616a9c35 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -880,6 +880,30 @@ STAmount STAmount::deserialize(SerializerIterator& it) } std::string STAmount::getFullText() const +{ + if (mIsNative) + { + return str(boost::format("%s/" SYSTEM_CURRENCY_CODE) % getText()); + } + else if (!mIssuer) + { + return str(boost::format("%s/%s/0") % getText() % getHumanCurrency()); + } + else if (mIssuer == ACCOUNT_ONE) + { + return str(boost::format("%s/%s/1") % getText() % getHumanCurrency()); + } + else + { + return str(boost::format("%s/%s/%s") + % getText() + % getHumanCurrency() + % NewcoinAddress::createHumanAccountID(mIssuer)); + } +} + +#if 0 +std::string STAmount::getExtendedText() const { if (mIsNative) { @@ -887,7 +911,7 @@ std::string STAmount::getFullText() const } else { - return str(boost::format("%s %s/%s %dE%d" ) + return str(boost::format("%s/%s/%s %dE%d" ) % getText() % getHumanCurrency() % NewcoinAddress::createHumanAccountID(mIssuer) @@ -895,6 +919,7 @@ std::string STAmount::getFullText() const % getExponent()); } } +#endif Json::Value STAmount::getJson(int) const { From 99d1451c29a9c65d637b0faac16683d975104b47 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 17 Aug 2012 17:11:13 -0700 Subject: [PATCH 071/426] Fixes for direct ripple with quality to work. --- src/SerializedTypes.h | 6 + src/TransactionEngine.cpp | 234 +++++++++++++++++++++++++++++--------- src/TransactionEngine.h | 4 +- 3 files changed, 190 insertions(+), 54 deletions(-) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 63977102ca..b1a264cde4 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -50,6 +50,12 @@ enum PathFlags PF_ISSUE = 0x80, }; +#define QUALITY_ONE 100000000 // 10e9 +#define CURRENCY_XNS uint160(0) +#define CURRENCY_ONE uint160(1) // Used as a place holder +#define ACCOUNT_XNS uint160(0) +#define ACCOUNT_ONE uint160(1) // Used as a place holder + class SerializedType { protected: diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index a2ebca5f4c..1170fd00ae 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -21,12 +21,6 @@ #define DIR_NODE_MAX 2 #define RIPPLE_PATHS_MAX 3 -#define QUALITY_ONE 100000000 // 10e9 -#define CURRENCY_XNS uint160(0) -#define CURRENCY_ONE uint160(1) // Used as a place holder -#define ACCOUNT_XNS uint160(0) -#define ACCOUNT_ONE uint160(1) // Used as a place holder - static STAmount saZero(CURRENCY_ONE, 0, 0); static STAmount saOne(CURRENCY_ONE, 1, 0); @@ -324,11 +318,11 @@ STAmount TransactionEngine::rippleTransfer(const uint160& uSenderID, const uint1 } // Direct send w/o fees: redeeming IOUs and/or sending own IOUs. -void TransactionEngine::rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount) +void TransactionEngine::rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount, bool bCheckIssuer) { uint160 uIssuerID = saAmount.getIssuer(); - assert(uSenderID == uIssuerID || uReceiverID == uIssuerID); + assert(!bCheckIssuer || uSenderID == uIssuerID || uReceiverID == uIssuerID); bool bFlipped = uSenderID > uReceiverID; uint256 uIndex = Ledger::getRippleStateIndex(uSenderID, uReceiverID, saAmount.getCurrency()); @@ -2545,13 +2539,13 @@ void TransactionEngine::calcNodeRipple( STAmount& saPrvAct, // <-> in limit including achieved STAmount& saCurAct) // <-> out limit achieved. { - Log(lsINFO) << str(boost::format("calcNodeRipple> uQualityIn=%d uQualityOut=%d saPrvReq=%s/%s saCurReq=%s/%s") + Log(lsINFO) << str(boost::format("calcNodeRipple> uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s") % uQualityIn % uQualityOut - % saPrvReq.getText() - % saPrvReq.getHumanCurrency() - % saCurReq.getText() - % saCurReq.getHumanCurrency()); + % saPrvReq.getFullText() + % saCurReq.getFullText() + % saPrvAct.getFullText() + % saCurAct.getFullText()); assert(saPrvReq.getCurrency() == saCurReq.getCurrency()); @@ -2559,6 +2553,15 @@ void TransactionEngine::calcNodeRipple( STAmount saPrv = bPrvUnlimited ? STAmount(saPrvReq) : saPrvReq-saPrvAct; STAmount saCur = saCurReq-saCurAct; + Log(lsINFO) << str(boost::format("calcNodeRipple:1: saCurReq=%s") % saCurReq.getFullText()); + +#if 0 + Log(lsINFO) << str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCur=%s") + % bPrvUnlimited + % saPrv.getFullText() + % saCur.getFullText()); +#endif + if (uQualityIn >= uQualityOut) { // No fee. @@ -2570,23 +2573,37 @@ void TransactionEngine::calcNodeRipple( else { // Fee. - STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, CURRENCY_ONE), uQualityIn, CURRENCY_ONE); + uint160 uCurrencyID = saCur.getCurrency(); + STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID), uQualityIn, uCurrencyID); +Log(lsINFO) << str(boost::format("calcNodeRipple:2: saCurReq=%s") % saCurReq.getFullText()); if (bPrvUnlimited || saCurIn >= saPrv) { // All of cur. Some amount of prv. +Log(lsINFO) << str(boost::format("calcNodeRipple:3a: saCurReq=%s") % saCurReq.getFullText()); saCurAct = saCurReq; saPrvAct += saCurIn; +Log(lsINFO) << str(boost::format("calcNodeRipple:3c: saCurReq=%s saPrvAct=%s") % saCurReq.getFullText() % saPrvAct.getFullText()); } else { // A part of cur. All of prv. (cur as driver) - STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, CURRENCY_ONE), uQualityOut, CURRENCY_ONE); + uint160 uCurrencyID = saPrv.getCurrency(); + STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID), uQualityOut, uCurrencyID); +Log(lsINFO) << str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.getFullText()); saCurAct += saCurOut; saPrvAct = saPrvReq; } } + + Log(lsINFO) << str(boost::format("calcNodeRipple< uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s") + % uQualityIn + % uQualityOut + % saPrvReq.getFullText() + % saCurReq.getFullText() + % saPrvAct.getFullText() + % saCurAct.getFullText()); } // Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver; @@ -2603,30 +2620,30 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point bool bPrvRedeem = !!(prvPN.uFlags & STPathElement::typeRedeem); bool bIssue = !!(curPN.uFlags & STPathElement::typeIssue); bool bPrvIssue = !!(prvPN.uFlags & STPathElement::typeIssue); - bool bPrvAccount = uIndex && !!(prvPN.uFlags & STPathElement::typeAccount); - bool bNxtAccount = uIndex != uLast && !!(nxtPN.uFlags & STPathElement::typeAccount); + bool bPrvAccount = !uIndex || !!(prvPN.uFlags & STPathElement::typeAccount); + bool bNxtAccount = uIndex == uLast || !!(nxtPN.uFlags & STPathElement::typeAccount); - uint160& uPrvAccountID = prvPN.uAccountID; - uint160& uCurAccountID = curPN.uAccountID; - uint160& uNxtAccountID = bNxtAccount ? nxtPN.uAccountID : uCurAccountID; // Offers are always issue. + const uint160& uPrvAccountID = prvPN.uAccountID; + const uint160& uCurAccountID = curPN.uAccountID; + const uint160& uNxtAccountID = bNxtAccount ? nxtPN.uAccountID : uCurAccountID; // Offers are always issue. - uint160& uCurrencyID = curPN.uCurrencyID; + const uint160& uCurrencyID = curPN.uCurrencyID; - uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : 0; - uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : 0; + const uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : 1; + const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : 1; // For bPrvAccount - STAmount saPrvBalance = bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); - STAmount saPrvLimit = bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); + const STAmount saPrvBalance = uIndex && bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); + const STAmount saPrvLimit = uIndex && bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); - STAmount saPrvRedeemReq = bPrvRedeem && saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); + const STAmount saPrvRedeemReq = bPrvRedeem && saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); STAmount& saPrvRedeemAct = prvPN.saRevRedeem; - STAmount saPrvIssueReq = bPrvIssue ? saPrvLimit - saPrvBalance : STAmount(uCurrencyID); + const STAmount saPrvIssueReq = bPrvIssue ? saPrvLimit - saPrvBalance : STAmount(uCurrencyID); STAmount& saPrvIssueAct = prvPN.saRevIssue; // For !bPrvAccount - STAmount saPrvDeliverReq = STAmount(uCurrencyID, -1); // Unlimited. + const STAmount saPrvDeliverReq = STAmount(uCurrencyID, -1); // Unlimited. STAmount& saPrvDeliverAct = prvPN.saRevDeliver; // For bNxtAccount @@ -2645,23 +2662,38 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // STAmount saPrvDeliverReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; STAmount saCurWantedAct(saCurWantedReq.getCurrency()); - Log(lsINFO) << str(boost::format("calcNodeAccountRev> saPrvRedeemReq=%s/%s saCurWantedAct=%s/%s") + Log(lsINFO) << str(boost::format("calcNodeAccountRev> uIndex=%d/%d saPrvRedeemReq=%s/%s saPrvIssueReq=%s/%s saCurWantedReq=%s/%s") + % uIndex + % uLast % saPrvRedeemReq.getText() % saPrvRedeemReq.getHumanCurrency() - % saCurWantedAct.getText() - % saCurWantedAct.getHumanCurrency()); + % saPrvIssueReq.getText() + % saPrvIssueReq.getHumanCurrency() + % saCurWantedReq.getText() + % saCurWantedReq.getHumanCurrency()); + + Log(lsINFO) << pspCur->getJson(); if (bPrvAccount && bNxtAccount) { - if (uIndex == uLast) + if (!uIndex) + { + // ^ --> ACCOUNT --> account|offer + // Nothing to do, there is no previous to adjust. + nothing(); + } + else if (uIndex == uLast) { // account --> ACCOUNT --> $ + Log(lsINFO) << str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $")); // Calculate redeem if (bRedeem && saPrvRedeemReq) // Previous has IOUs to redeem. { // Redeem at 1:1 + Log(lsINFO) << str(boost::format("calcNodeAccountRev: Redeem at 1:1")); + saCurWantedAct = MIN(saPrvRedeemReq, saCurWantedReq); saPrvRedeemAct = saCurWantedAct; } @@ -2672,6 +2704,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && saPrvIssueReq) // Will accept IOUs. { // Rate: quality in : 1.0 + Log(lsINFO) << str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurWantedReq, saPrvIssueAct, saCurWantedAct); } @@ -2684,7 +2718,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point } else { - // account --> ACCOUNT --> account + // ^|account --> ACCOUNT --> account // redeem (part 1) -> redeem if (bPrvRedeem @@ -2693,6 +2727,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && saPrvBalance.isNegative()) // Previous has IOUs to redeem. { // Rate : 1.0 : quality out + Log(lsINFO) << str(boost::format("calcNodeAccountRev: Rate : 1.0 : quality out")); + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); } @@ -2704,6 +2740,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && saCurIssueReq) // Need some issued. { // Rate : 1.0 : transfer_rate + Log(lsINFO) << str(boost::format("calcNodeAccountRev: Rate : 1.0 : transfer_rate")); + calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); } @@ -2714,17 +2752,21 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && !saPrvBalance.isNegative()) // Previous has no IOUs. { // Rate: quality in : quality out + Log(lsINFO) << str(boost::format("calcNodeAccountRev: Rate: quality in : quality out")); + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); } // issue (part 2) -> issue if (bPrvIssue && bIssue // Allowed to issue. - && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. + && saCurRedeemReq == saCurRedeemAct // Can only if issue if more can not be redeemed. && !saPrvBalance.isNegative() // Previous has no IOUs. && saCurIssueReq != saCurIssueAct) // Need some issued. { // Rate: quality in : 1.0 + Log(lsINFO) << str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); } @@ -2734,12 +2776,23 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // terResult = tenBAD_AMOUNT; bSuccess = false; } + Log(lsINFO) << str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurRedeemReq=%s saCurIssueReq=%s saPrvBalance=%s saCurRedeemAct=%s saCurIssueAct=%s") + % bPrvRedeem + % bPrvIssue + % bRedeem + % bIssue + % saCurRedeemReq.getFullText() + % saCurIssueReq.getFullText() + % saPrvBalance.getFullText() + % saCurRedeemAct.getFullText() + % saCurIssueAct.getFullText()); } } else if (bPrvAccount && !bNxtAccount) { // account --> ACCOUNT --> offer // Note: deliver is always issue as ACCOUNT is the issuer for the offer input. + Log(lsINFO) << str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> offer")); // redeem -> deliver/issue. if (bPrvRedeem @@ -2773,6 +2826,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (uIndex == uLast) { // offer --> ACCOUNT --> $ + Log(lsINFO) << str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $")); // Rate: quality in : 1.0 calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct); @@ -2788,6 +2842,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point { // offer --> ACCOUNT --> account // Note: offer is always deliver/redeeming as account is issuer. + Log(lsINFO) << str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> account")); // deliver -> redeem if (bRedeem // Allowed to redeem. @@ -2820,6 +2875,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point { // offer --> ACCOUNT --> offer // deliver/redeem -> deliver/issue. + Log(lsINFO) << str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> offer")); + if (bIssue // Allowed to issue. && saCurDeliverReq != saCurDeliverAct) // Can only if issue if more can not be redeemed. { @@ -2869,14 +2926,14 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point // For bNxtAccount const STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; - STAmount saPrvRedeemAct; + STAmount saPrvRedeemAct(saPrvRedeemReq.getCurrency()); const STAmount& saPrvIssueReq = prvPN.saFwdIssue; - STAmount saPrvIssueAct; + STAmount saPrvIssueAct(saPrvIssueReq.getCurrency()); // For !bPrvAccount const STAmount& saPrvDeliverReq = prvPN.saRevDeliver; - STAmount saPrvDeliverAct; + STAmount saPrvDeliverAct(saPrvDeliverReq.getCurrency()); // For bNxtAccount const STAmount& saCurRedeemReq = curPN.saRevRedeem; @@ -2891,6 +2948,16 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point STAmount& saCurReceive = pspCur->saOutAct; + Log(lsINFO) << str(boost::format("calcNodeAccountFwd> uIndex=%d/%d saCurRedeemReq=%s/%s saCurIssueReq=%s/%s saCurDeliverReq=%s/%s") + % uIndex + % uLast + % saCurRedeemReq.getText() + % saCurRedeemReq.getHumanCurrency() + % saCurIssueReq.getText() + % saCurIssueReq.getHumanCurrency() + % saCurDeliverReq.getText() + % saCurDeliverReq.getHumanCurrency()); + // Ripple through account. if (bPrvAccount && bNxtAccount) @@ -2908,26 +2975,49 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point STAmount& saCurIssueReq = curPN.saRevIssue; STAmount& saCurIssueAct = curPN.saFwdIssue; - STAmount& saCurSendMaxReq = pspCur->saInReq; - STAmount& saCurSendMaxAct = pspCur->saInAct; + STAmount& saCurSendMaxReq = pspCur->saInReq; // Negative for no limit, doing a calculation. + STAmount& saCurSendMaxAct = pspCur->saInAct; // Report to user how much this sends. if (saCurRedeemReq) { // Redeem requested. - saCurRedeemAct = MIN(saCurRedeemAct, saCurSendMaxReq); - saCurSendMaxAct = saCurRedeemAct; + saCurRedeemAct = saCurRedeemReq.isNegative() + ? saCurRedeemReq + : MIN(saCurRedeemReq, saCurSendMaxReq); } + else + { + saCurRedeemAct = STAmount(saCurRedeemReq); + } + saCurSendMaxAct = saCurRedeemAct; - if (saCurIssueReq && saCurSendMaxReq != saCurRedeemAct) + if (saCurIssueReq && (saCurSendMaxReq.isNegative() || saCurSendMaxReq != saCurRedeemAct)) { // Issue requested and not over budget. - saCurIssueAct = MIN(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); - // saCurSendMaxAct += saCurIssueReq; // Not needed. + saCurIssueAct = saCurSendMaxReq.isNegative() + ? saCurIssueReq + : MIN(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); } + else + { + saCurIssueAct = STAmount(saCurIssueReq); + } + saCurSendMaxAct += saCurIssueAct; + + Log(lsINFO) << str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s") + % saCurSendMaxReq.getFullText() + % saCurRedeemAct.getFullText() + % saCurIssueReq.getFullText() + % saCurIssueAct.getFullText()); } else if (uIndex == uLast) { // account --> ACCOUNT --> $ + Log(lsINFO) << str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> $ : uPrvAccountID=%s uCurAccountID=%s saPrvRedeemReq=%s saPrvIssueReq=%s") + % NewcoinAddress::createHumanAccountID(uPrvAccountID) + % NewcoinAddress::createHumanAccountID(uCurAccountID) + % saPrvRedeemReq.getFullText() + % saPrvIssueReq.getFullText()); // Last node. Accept all funds. Calculate amount actually to credit. @@ -2939,11 +3029,12 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point saCurReceive = saPrvRedeemReq+saIssueCrd; // Actually receive. - rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq+saPrvIssueReq); + rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq+saPrvIssueReq, false); } else { // account --> ACCOUNT --> account + Log(lsINFO) << str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> account")); // Previous redeem part 1: redeem -> redeem if (bRedeem // Can redeem. @@ -2984,12 +3075,13 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point // Adjust prv --> cur balance : take all inbound // XXX Currency must be in amount. - rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq); + rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false); } } else if (bPrvAccount && !bNxtAccount) { // account --> ACCOUNT --> offer + Log(lsINFO) << str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> offer")); // redeem -> issue. // wants to redeem and current would and can issue. @@ -3010,13 +3102,14 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point // Adjust prv --> cur balance : take all inbound // XXX Currency must be in amount. - rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq); + rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false); } else if (!bPrvAccount && bNxtAccount) { if (uIndex == uLast) { // offer --> ACCOUNT --> $ + Log(lsINFO) << str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $")); // Amount to credit. saCurReceive = saPrvDeliverAct; @@ -3026,6 +3119,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point else { // offer --> ACCOUNT --> account + Log(lsINFO) << str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> account")); // deliver -> redeem if (bRedeem // Allowed to redeem. @@ -3053,6 +3147,8 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point { // offer --> ACCOUNT --> offer // deliver/redeem -> deliver/issue. + Log(lsINFO) << str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> offer")); + if (bIssue // Allowed to issue. && saPrvDeliverReq // Previous wants to deliver && saCurIssueReq) // Current wants issue. @@ -3182,6 +3278,8 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin pnCur.uAccountID = uAccountID; pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; + pnCur.saRevRedeem = STAmount(uCurrencyID); + pnCur.saRevIssue = STAmount(uCurrencyID); if (!bFirst) { @@ -3314,6 +3412,7 @@ PathState::PathState( saInReq = saSendMax; saOutReq = saSend; + // Push sending node. bValid = pushNode( STPathElement::typeAccount | STPathElement::typeRedeem @@ -3359,13 +3458,16 @@ Json::Value PathState::getJson() const { Json::Value jvNode(Json::objectValue); - Json::Value jvFlags(Json::objectValue); + Json::Value jvFlags(Json::arrayValue); + + if (pnNode.uFlags & STPathElement::typeAccount) + jvFlags.append("account"); if (pnNode.uFlags & STPathElement::typeRedeem) - jvFlags["redeem"] = 1; + jvFlags.append("redeem"); if (pnNode.uFlags & STPathElement::typeIssue) - jvFlags["issue"] = 1; + jvFlags.append("issue"); jvNode["flags"] = jvFlags; @@ -3378,6 +3480,24 @@ Json::Value PathState::getJson() const if (!!pnNode.uIssuerID) jvNode["issuer"] = NewcoinAddress::createHumanAccountID(pnNode.uIssuerID); + // if (!!pnNode.saRevRedeem) + jvNode["rev_redeem"] = pnNode.saRevRedeem.getFullText(); + + // if (!!pnNode.saRevIssue) + jvNode["rev_issue"] = pnNode.saRevIssue.getFullText(); + + // if (!!pnNode.saRevDeliver) + jvNode["rev_deliver"] = pnNode.saRevDeliver.getFullText(); + + // if (!!pnNode.saFwdRedeem) + jvNode["fwd_redeem"] = pnNode.saFwdRedeem.getFullText(); + + // if (!!pnNode.saFwdIssue) + jvNode["fwd_issue"] = pnNode.saFwdIssue.getFullText(); + + // if (!!pnNode.saFwdDeliver) + jvNode["fwd_deliver"] = pnNode.saFwdDeliver.getFullText(); + jvNodes.append(jvNode); } @@ -3761,9 +3881,19 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction } } - Log(lsINFO) << "doPayment: Delay transaction: No ripple paths could be satisfied."; + std::string strToken; + std::string strHuman; - return terBAD_RIPPLE; + if (transResultInfo(terResult, strToken, strHuman)) + { + Log(lsINFO) << str(boost::format("doPayment: %s: %s") % strToken % strHuman); + } + else + { + assert(false); + } + + return terResult; } TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransaction& txn) diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 3d54952d5a..35d9f23baa 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -104,7 +104,7 @@ typedef struct { uint16 uFlags; // --> From path. uint160 uAccountID; // --> Recieving/sending account. - uint160 uCurrencyID; // --> Currency to recieve. + uint160 uCurrencyID; // --> Accounts: receive and send, Offers: send. // --- For offer's next has currency out. uint160 uIssuerID; // --> Currency's issuer @@ -231,7 +231,7 @@ protected: STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID); STAmount rippleTransfer(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount); - void rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, 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); From ffbd7195080b873d81fbc9e186ec494b8f4a7410 Mon Sep 17 00:00:00 2001 From: jed Date: Fri, 17 Aug 2012 21:35:56 -0700 Subject: [PATCH 072/426] . --- newcoin.vcxproj | 4 ++++ newcoin.vcxproj.filters | 12 ++++++++++++ src/Ledger.h | 2 +- src/SerializedTypes.h | 1 + 4 files changed, 18 insertions(+), 1 deletion(-) diff --git a/newcoin.vcxproj b/newcoin.vcxproj index 65bbd332c4..2beb907c7c 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -124,6 +124,8 @@ + + @@ -211,6 +213,8 @@ + + diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index b636aa2606..d18959032e 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -282,6 +282,12 @@ Source Files + + Source Files + + + Source Files + @@ -518,6 +524,12 @@ Header Files + + Header Files + + + Header Files + diff --git a/src/Ledger.h b/src/Ledger.h index b90d440895..3de26d5e06 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -115,7 +115,7 @@ public: void disarmDirty() { mTransactionMap->disarmDirty(); mAccountStateMap->disarmDirty(); } // This ledger has closed, will never be accepted, and is accepting - // new transactions to be re-repocessed when do accept a new last-closed ledger + // new transactions to be re-reprocessed when do accept a new last-closed ledger void bumpSeq() { mClosed = true; mLedgerSeq++; } // ledger signature operations diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 63977102ca..ca283c3dea 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -281,6 +281,7 @@ public: int getExponent() const { return mOffset; } uint64 getMantissa() const { return mValue; } + // When the currency is XNS, the value in raw units. S=signed uint64 getNValue() const { if (!mIsNative) throw std::runtime_error("not native"); return mValue; } void setNValue(uint64 v) { if (!mIsNative) throw std::runtime_error("not native"); mValue = v; } int64 getSNValue() const; From d5734cd6ce12c5698b79397b2348e099e10321a7 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 18 Aug 2012 12:41:58 -0700 Subject: [PATCH 073/426] Merge ripple dirs with owner dirs and RPC fixes for setting quality. --- src/Ledger.h | 3 -- src/LedgerFormats.h | 5 ---- src/LedgerIndex.cpp | 10 ------- src/NetworkOPs.cpp | 32 +++++++++++++++++---- src/RPCServer.cpp | 30 ++++++++------------ src/RippleLines.cpp | 40 +++++++++++++++------------ src/RippleState.cpp | 14 +++++++--- src/RippleState.h | 8 ++++++ src/Transaction.cpp | 4 +-- src/TransactionEngine.cpp | 58 ++++++++++++++++----------------------- src/TransactionEngine.h | 4 +-- 11 files changed, 107 insertions(+), 101 deletions(-) diff --git a/src/Ledger.h b/src/Ledger.h index b90d440895..53dbe4dfbb 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -265,9 +265,6 @@ public: static uint256 getRippleStateIndex(const uint160& uiA, const uint160& uiB, const uint160& uCurrency) { return getRippleStateIndex(NewcoinAddress::createAccountID(uiA), NewcoinAddress::createAccountID(uiB), uCurrency); } - // Directory of lines indexed by an account (not all lines are indexed) - static uint256 getRippleDirIndex(const uint160& uAccountID); - RippleState::pointer accessRippleState(const uint256& uNode); SLE::pointer getRippleState(LedgerStateParms& parms, const uint256& uNode); diff --git a/src/LedgerFormats.h b/src/LedgerFormats.h index 230e557c48..22ae55ebf2 100644 --- a/src/LedgerFormats.h +++ b/src/LedgerFormats.h @@ -23,7 +23,6 @@ enum LedgerNameSpace spaceGenerator = 'g', spaceNickname = 'n', spaceRipple = 'r', - spaceRippleDir = 'R', spaceOffer = 'o', // Entry for an offer. spaceOwnerDir = 'O', // Directory of things owned by an account. spaceBookDir = 'B', // Directory of order books. @@ -38,10 +37,6 @@ enum LedgerSpecificFlags // ltOFFER lsfPassive = 0x00010000, - - // ltRIPPLE_STATE - lsfLowIndexed = 0x00010000, - lsfHighIndexed = 0x00020000, }; struct LedgerEntryFormat diff --git a/src/LedgerIndex.cpp b/src/LedgerIndex.cpp index 8a27e7938b..b519a9e0e8 100644 --- a/src/LedgerIndex.cpp +++ b/src/LedgerIndex.cpp @@ -126,16 +126,6 @@ uint256 Ledger::getOwnerDirIndex(const uint160& uAccountID) return s.getSHA512Half(); } -uint256 Ledger::getRippleDirIndex(const uint160& uAccountID) -{ - Serializer s(22); - - s.add16(spaceRippleDir); // 2 - s.add160(uAccountID); // 20 - - return s.getSHA512Half(); -} - uint256 Ledger::getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency) { uint160 uAID = naA.getAccountID(); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 35ae4c4063..a0e7811425 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -254,7 +254,7 @@ Json::Value NetworkOPs::getOwnerInfo(const uint256& uLedger, const NewcoinAddres Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddress& naAccount) { - Json::Value jvObjects(Json::arrayValue); + Json::Value jvObjects(Json::objectValue); uint256 uRootIndex = lpLedger->getOwnerDirIndex(naAccount.getAccountID()); @@ -267,15 +267,37 @@ Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddr do { - STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes); + STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes); const std::vector& vuiIndexes = svIndexes.peekValue(); BOOST_FOREACH(const uint256& uDirEntry, vuiIndexes) { - LedgerStateParms lspOffer = lepNONE; - SLE::pointer sleOffer = lpLedger->getOffer(lspOffer, uDirEntry); + SLE::pointer sleCur = lpLedger->getSLE(uDirEntry); - jvObjects.append(sleOffer->getJson(0)); + switch (sleCur->getType()) + { + case ltOFFER: + if (!jvObjects.isMember("offers")) + jvObjects["offers"] = Json::Value(Json::arrayValue); + + jvObjects["offers"].append(sleCur->getJson(0)); + break; + + case ltRIPPLE_STATE: + if (!jvObjects.isMember("ripple_lines")) + jvObjects["ripple_lines"] = Json::Value(Json::arrayValue); + + jvObjects["ripple_lines"].append(sleCur->getJson(0)); + break; + + case ltACCOUNT_ROOT: + case ltDIR_NODE: + case ltGENERATOR_MAP: + case ltNICKNAME: + default: + assert(false); + break; + } } uNodeDir = sleNode->getIFieldU64(sfIndexNext); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index d2ce4c0127..3f58015a47 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1151,22 +1151,12 @@ Json::Value RPCServer::doOwnerInfo(const Json::Value& params) uint256 uAccepted = mNetOps->getClosedLedger(); Json::Value jAccepted = accountFromString(uAccepted, naAccount, bIndex, strIdent, iIndex); - if (jAccepted.empty()) - { - jAccepted["offers"] = mNetOps->getOwnerInfo(uAccepted, naAccount); - } - - ret["accepted"] = jAccepted; + ret["accepted"] = jAccepted.empty() ? mNetOps->getOwnerInfo(uAccepted, naAccount) : jAccepted; uint256 uCurrent = mNetOps->getCurrentLedger(); Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); - if (jCurrent.empty()) - { - jCurrent["offers"] = mNetOps->getOwnerInfo(uCurrent, naAccount); - } - - ret["current"] = jCurrent; + ret["current"] = jCurrent.empty() ? mNetOps->getOwnerInfo(uCurrent, naAccount) : jCurrent; return ret; } @@ -1660,7 +1650,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) // We access a committed ledger and need not worry about changes. RippleLines rippleLines(naAccount.getAccountID()); - BOOST_FOREACH(RippleState::pointer line,rippleLines.getLines()) + BOOST_FOREACH(RippleState::pointer line, rippleLines.getLines()) { STAmount saBalance = line->getBalance(); STAmount saLimit = line->getLimit(); @@ -1668,15 +1658,17 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) Json::Value jPeer = Json::Value(Json::objectValue); - //jPeer["node"] = uNode.ToString(); + //jPeer["node"] = uNode.ToString(); - jPeer["account"] = line->getAccountIDPeer().humanAccountID(); + jPeer["account"] = line->getAccountIDPeer().humanAccountID(); // Amount reported is positive if current account holds other account's IOUs. // Amount reported is negative if other account holds current account's IOUs. - jPeer["balance"] = saBalance.getText(); - jPeer["currency"] = saBalance.getHumanCurrency(); - jPeer["limit"] = saLimit.getText(); - jPeer["limit_peer"] = saLimitPeer.getText(); + jPeer["balance"] = saBalance.getText(); + jPeer["currency"] = saBalance.getHumanCurrency(); + jPeer["limit"] = saLimit.getText(); + jPeer["limit_peer"] = saLimitPeer.getText(); + jPeer["quality_in"] = static_cast(line->getQualityIn()); + jPeer["quality_out"] = static_cast(line->getQualityOut()); jsonLines.append(jPeer); } diff --git a/src/RippleLines.cpp b/src/RippleLines.cpp index 26e9fa827b..391d38c02d 100644 --- a/src/RippleLines.cpp +++ b/src/RippleLines.cpp @@ -15,34 +15,40 @@ RippleLines::RippleLines(const uint160& accountID ) void RippleLines::fillLines(const uint160& accountID, Ledger::pointer ledger) { - uint256 rootIndex = Ledger::getRippleDirIndex(accountID); - uint256 currentIndex=rootIndex; + uint256 rootIndex = Ledger::getOwnerDirIndex(accountID); + uint256 currentIndex = rootIndex; LedgerStateParms lspNode = lepNONE; - while(1) + while (1) { - SerializedLedgerEntry::pointer rippleDir=ledger->getDirNode(lspNode,currentIndex); - if(!rippleDir) return; + SLE::pointer rippleDir=ledger->getDirNode(lspNode, currentIndex); + if (!rippleDir) return; - STVector256 svRippleNodes = rippleDir->getIFieldV256(sfIndexes); - BOOST_FOREACH(uint256& uNode, svRippleNodes.peekValue()) + STVector256 svOwnerNodes = rippleDir->getIFieldV256(sfIndexes); + BOOST_FOREACH(uint256& uNode, svOwnerNodes.peekValue()) { - RippleState::pointer rsLine = ledger->accessRippleState(uNode); - if (rsLine) + SLE::pointer sleCur = ledger->getSLE(uNode); + + if (ltRIPPLE_STATE == sleCur->getType()) { - rsLine->setViewAccount(accountID); - mLines.push_back(rsLine); - } - else - { - Log(lsWARNING) << "doRippleLinesGet: Bad index: " << uNode.ToString(); + RippleState::pointer rsLine = ledger->accessRippleState(uNode); + if (rsLine) + { + rsLine->setViewAccount(accountID); + mLines.push_back(rsLine); + } + else + { + Log(lsWARNING) << "doRippleLinesGet: Bad index: " << uNode.ToString(); + } } } - uint64 uNodeNext = rippleDir->getIFieldU64(sfIndexNext); - if(!uNodeNext) return; + uint64 uNodeNext = rippleDir->getIFieldU64(sfIndexNext); + if (!uNodeNext) return; currentIndex = Ledger::getDirNodeIndex(rootIndex, uNodeNext); } } +// vim:ts=4 diff --git a/src/RippleState.cpp b/src/RippleState.cpp index b4a4712d57..26a5bb7072 100644 --- a/src/RippleState.cpp +++ b/src/RippleState.cpp @@ -7,11 +7,17 @@ RippleState::RippleState(SerializedLedgerEntry::pointer ledgerEntry) : { if (!mLedgerEntry || mLedgerEntry->getType() != ltRIPPLE_STATE) return; - mLowID = mLedgerEntry->getIValueFieldAccount(sfLowID); - mHighID = mLedgerEntry->getIValueFieldAccount(sfHighID); + mLowID = mLedgerEntry->getIValueFieldAccount(sfLowID); + mHighID = mLedgerEntry->getIValueFieldAccount(sfHighID); - mLowLimit = mLedgerEntry->getIValueFieldAmount(sfLowLimit); - mHighLimit = mLedgerEntry->getIValueFieldAmount(sfHighLimit); + mLowLimit = mLedgerEntry->getIValueFieldAmount(sfLowLimit); + mHighLimit = mLedgerEntry->getIValueFieldAmount(sfHighLimit); + + mLowQualityIn = mLedgerEntry->getIFieldU32(sfLowQualityIn); + mLowQualityOut = mLedgerEntry->getIFieldU32(sfLowQualityOut); + + mHighQualityIn = mLedgerEntry->getIFieldU32(sfHighQualityIn); + mHighQualityOut = mLedgerEntry->getIFieldU32(sfHighQualityOut); mBalance = mLedgerEntry->getIValueFieldAmount(sfBalance); diff --git a/src/RippleState.h b/src/RippleState.h index e4b34eab41..c83e6b364d 100644 --- a/src/RippleState.h +++ b/src/RippleState.h @@ -24,6 +24,11 @@ private: STAmount mLowLimit; STAmount mHighLimit; + uint64 mLowQualityIn; + uint64 mLowQualityOut; + uint64 mHighQualityIn; + uint64 mHighQualityOut; + STAmount mBalance; bool mValid; @@ -42,6 +47,9 @@ public: STAmount getLimit() const { return mViewLowest ? mLowLimit : mHighLimit; } STAmount getLimitPeer() const { return mViewLowest ? mHighLimit : mLowLimit; } + uint32 getQualityIn() const { return mViewLowest ? mLowQualityIn : mHighQualityIn; } + uint32 getQualityOut() const { return mViewLowest ? mLowQualityOut : mHighQualityOut; } + SerializedLedgerEntry::pointer getSLE() { return mLedgerEntry; } const SerializedLedgerEntry& peekSLE() const { return *mLedgerEntry; } SerializedLedgerEntry& peekSLE() { return *mLedgerEntry; } diff --git a/src/Transaction.cpp b/src/Transaction.cpp index da778890c3..3f01d43f0f 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -270,10 +270,10 @@ Transaction::pointer Transaction::setCreditSet( mTransaction->setITFieldAmount(sfLimitAmount, saLimitAmount); if (bQualityIn) - mTransaction->setITFieldU32(sfAcceptRate, uQualityIn); + mTransaction->setITFieldU32(sfQualityIn, uQualityIn); if (bQualityOut) - mTransaction->setITFieldU32(sfAcceptRate, uQualityOut); + mTransaction->setITFieldU32(sfQualityOut, uQualityOut); sign(naPrivateKey); diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 17299b346b..12886c4398 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -145,7 +145,7 @@ STAmount TransactionEngine::rippleLimit(const uint160& uToAccountID, const uint1 } -uint32 TransactionEngine::rippleTransfer(const uint160& uIssuerID) +uint32 TransactionEngine::rippleTransferRate(const uint160& uIssuerID) { SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uIssuerID)); @@ -298,13 +298,13 @@ STAmount TransactionEngine::accountFunds(const uint160& uAccountID, const STAmou } // Calculate transit fee. -STAmount TransactionEngine::rippleTransfer(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount) +STAmount TransactionEngine::rippleTransferFee(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount) { STAmount saTransitFee; if (uSenderID != uIssuerID && uReceiverID != uIssuerID) { - uint32 uTransitRate = rippleTransfer(uIssuerID); + uint32 uTransitRate = rippleTransferRate(uIssuerID); if (QUALITY_ONE != uTransitRate) { @@ -380,7 +380,7 @@ STAmount TransactionEngine::rippleSend(const uint160& uSenderID, const uint160& { // Sending 3rd party IOUs: transit. - STAmount saTransitFee = rippleTransfer(uSenderID, uReceiverID, uIssuerID, saAmount); + STAmount saTransitFee = rippleTransferFee(uSenderID, uReceiverID, uIssuerID, saAmount); saActual = saTransitFee.isZero() ? saAmount : saAmount+saTransitFee; @@ -1505,7 +1505,6 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti } bool bFlipped = mTxnAccountID > uDstAccountID; - uint32 uFlags = bFlipped ? lsfLowIndexed : lsfHighIndexed; bool bLimitAmount = txn.getITFieldPresent(sfLimitAmount); STAmount saLimitAmount = bLimitAmount ? txn.getITFieldAmount(sfLimitAmount) : STAmount(); bool bQualityIn = txn.getITFieldPresent(sfQualityIn); @@ -1514,7 +1513,6 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti uint32 uQualityOut = bQualityIn ? txn.getITFieldU32(sfQualityOut) : 0; uint160 uCurrencyID = saLimitAmount.getCurrency(); STAmount saBalance(uCurrencyID); - bool bAddIndex = false; bool bDelIndex = false; SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); @@ -1540,7 +1538,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti // Zero balance and eliminating last limit. bDelIndex = true; - terResult = dirDelete(false, uSrcRef, Ledger::getRippleDirIndex(mTxnAccountID), sleRippleState->getIndex()); + terResult = dirDelete(false, uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex()); } } #endif @@ -1576,15 +1574,10 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti sleRippleState->makeIFieldAbsent(bFlipped ? sfLowQualityOut : sfHighQualityOut); } - bAddIndex = !(sleRippleState->getFlags() & uFlags); - - if (bAddIndex) - sleRippleState->setFlag(uFlags); - entryModify(sleRippleState); } - Log(lsINFO) << "doCreditSet: Modifying ripple line: bAddIndex=" << bAddIndex << " bDelIndex=" << bDelIndex; + Log(lsINFO) << "doCreditSet: Modifying ripple line: bDelIndex=" << bDelIndex; } // Line does not exist. else if (saLimitAmount.isZero()) @@ -1598,12 +1591,10 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti // Create a new ripple line. STAmount saZero(uCurrencyID); - bAddIndex = true; sleRippleState = entryCreate(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString(); - sleRippleState->setFlag(uFlags); sleRippleState->setIFieldAmount(sfBalance, saZero); // Zero balance in currency. sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAmount); sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, saZero); @@ -1613,14 +1604,13 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti sleRippleState->setIFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn); if (uQualityOut) sleRippleState->setIFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut); - } - if (bAddIndex) - { - uint64 uSrcRef; // Ignored, ripple_state dirs never delete. + uint64 uSrcRef; // Ignored, dirs never delete. - // XXX Make dirAdd more flexiable to take vector. - terResult = dirAdd(uSrcRef, Ledger::getRippleDirIndex(mTxnAccountID), sleRippleState->getIndex()); + terResult = dirAdd(uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex()); + + if (terSUCCESS == terResult) + terResult = dirAdd(uSrcRef, Ledger::getOwnerDirIndex(uDstAccountID), sleRippleState->getIndex()); } Log(lsINFO) << "doCreditSet<"; @@ -1927,16 +1917,16 @@ bool TransactionEngine::calcNodeOfferRev( uint160& uNxtIssuerID = nxtPN.uIssuerID; uint160& uNxtAccountID = nxtPN.uAccountID; - STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransfer(uCurIssuerID), -9); + STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9); uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); - STAmount& saPrvDlvReq = prvPN.saRevDeliver; + STAmount& saPrvDlvReq = prvPN.saRevDeliver; // To be adjusted. STAmount saPrvDlvAct; - STAmount& saCurDlvReq = curPN.saRevDeliver; // Reverse driver. + const STAmount& saCurDlvReq = curPN.saRevDeliver; // Reverse driver. STAmount saCurDlvAct; while (!!uDirectTip // Have a quality. @@ -2119,7 +2109,7 @@ bool TransactionEngine::calcNodeOfferFwd( uint160& uNxtIssuerID = nxtPN.uIssuerID; uint160& uNxtAccountID = nxtPN.uAccountID; - STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransfer(uCurIssuerID), -9); + STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9); uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); @@ -2730,7 +2720,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // Rate : 1.0 : transfer_rate Log(lsINFO) << str(boost::format("calcNodeAccountRev: Rate : 1.0 : transfer_rate")); - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); } // issue (part 1)-> redeem @@ -2789,7 +2779,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && saCurDeliverReq) // Need some issued. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct); } // issue -> deliver/issue @@ -2848,7 +2838,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && saCurIssueReq) // Need some issued. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct); } if (!saCurDeliverAct && !saCurIssueAct) @@ -2869,7 +2859,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && saCurDeliverReq != saCurDeliverAct) // Can only if issue if more can not be redeemed. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct); } if (!saCurDeliverAct) @@ -3041,7 +3031,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point && saCurIssueReq) { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); } // Previous issue part 1: issue -> redeem @@ -3077,7 +3067,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point if (saPrvRedeemReq) // Previous wants to redeem. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct); } // issue -> issue @@ -3125,7 +3115,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point && saCurIssueReq) // Current wants issue. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); } // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. @@ -3142,7 +3132,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point && saCurIssueReq) // Current wants issue. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransfer(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct); } // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. @@ -3742,7 +3732,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction terResult = dirAdd( uSrcRef, - Ledger::getRippleDirIndex(mTxnAccountID), // The source ended up owing. + Ledger::getOwnerDirIndex(mTxnAccountID), // The source ended up owing. sleRippleState->getIndex()); // Adding current entry. if (terSUCCESS != terResult) diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 717074194b..5df286d743 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -221,14 +221,14 @@ protected: void entryDelete(SLE::pointer sleEntry, bool unfunded = false); void entryModify(SLE::pointer sleEntry); - uint32 rippleTransfer(const uint160& uIssuerID); + uint32 rippleTransferRate(const uint160& uIssuerID); STAmount rippleBalance(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); uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); STAmount rippleHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID); - STAmount rippleTransfer(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID, const STAmount& saAmount); + 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); From 3530988e9cfe06fbdb7ff796ac52d4718047315e Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 18 Aug 2012 13:16:26 -0700 Subject: [PATCH 074/426] Cosmetic. --- src/RPCServer.cpp | 133 +++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 67 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 3f58015a47..93d800c3f1 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1314,73 +1314,6 @@ Json::Value RPCServer::doPeers(const Json::Value& params) return obj; } -// ripple_line_set [] [] [] -Json::Value RPCServer::doRippleLineSet(const Json::Value& params) -{ - NewcoinAddress naSeed; - NewcoinAddress naSrcAccountID; - NewcoinAddress naDstAccountID; - STAmount saLimitAmount; - uint256 uLedger = mNetOps->getCurrentLedger(); - bool bLimitAmount = true; - bool bQualityIn = params.size() >= 6; - bool bQualityOut = params.size() >= 7; - uint32 uQualityIn = bQualityIn ? lexical_cast_s(params[5u].asString()) : 0; - uint32 uQualityOut = bQualityOut ? lexical_cast_s(params[6u].asString()) : 0; - - if (!naSeed.setSeedGeneric(params[0u].asString())) - { - return RPCError(rpcBAD_SEED); - } - else if (!naSrcAccountID.setAccountID(params[1u].asString())) - { - return RPCError(rpcSRC_ACT_MALFORMED); - } - else if (!naDstAccountID.setAccountID(params[2u].asString())) - { - return RPCError(rpcDST_ACT_MALFORMED); - } - else if (!saLimitAmount.setFullValue(params[3u].asString(), params.size() >= 5 ? params[4u].asString() : "")) - { - return RPCError(rpcSRC_AMT_MALFORMED); - } - else - { - NewcoinAddress naMasterGenerator; - NewcoinAddress naAccountPublic; - NewcoinAddress naAccountPrivate; - AccountState::pointer asSrc; - STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, - saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); - - if (!obj.empty()) - return obj; - - Transaction::pointer trans = Transaction::sharedCreditSet( - naAccountPublic, naAccountPrivate, - naSrcAccountID, - asSrc->getSeq(), - theConfig.FEE_DEFAULT, - 0, // YYY No source tag - naDstAccountID, - bLimitAmount, saLimitAmount, - bQualityIn, uQualityIn, - bQualityOut, uQualityOut); - - trans = mNetOps->submitTransaction(trans); - - obj["transaction"] = trans->getSTransaction()->getJson(0); - obj["status"] = trans->getStatus(); - obj["seed"] = naSeed.humanSeed(); - obj["srcAccountID"] = naSrcAccountID.humanAccountID(); - obj["dstAccountID"] = naDstAccountID.humanAccountID(); - - return obj; - } -} - - // ripple // [noredeem] [noissue] // + @@ -1613,6 +1546,72 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) return obj; } +// ripple_line_set [] [] [] +Json::Value RPCServer::doRippleLineSet(const Json::Value& params) +{ + NewcoinAddress naSeed; + NewcoinAddress naSrcAccountID; + NewcoinAddress naDstAccountID; + STAmount saLimitAmount; + uint256 uLedger = mNetOps->getCurrentLedger(); + bool bLimitAmount = true; + bool bQualityIn = params.size() >= 6; + bool bQualityOut = params.size() >= 7; + uint32 uQualityIn = bQualityIn ? lexical_cast_s(params[5u].asString()) : 0; + uint32 uQualityOut = bQualityOut ? lexical_cast_s(params[6u].asString()) : 0; + + if (!naSeed.setSeedGeneric(params[0u].asString())) + { + return RPCError(rpcBAD_SEED); + } + else if (!naSrcAccountID.setAccountID(params[1u].asString())) + { + return RPCError(rpcSRC_ACT_MALFORMED); + } + else if (!naDstAccountID.setAccountID(params[2u].asString())) + { + return RPCError(rpcDST_ACT_MALFORMED); + } + else if (!saLimitAmount.setFullValue(params[3u].asString(), params.size() >= 5 ? params[4u].asString() : "")) + { + return RPCError(rpcSRC_AMT_MALFORMED); + } + else + { + NewcoinAddress naMasterGenerator; + NewcoinAddress naAccountPublic; + NewcoinAddress naAccountPrivate; + AccountState::pointer asSrc; + STAmount saSrcBalance; + Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); + + if (!obj.empty()) + return obj; + + Transaction::pointer trans = Transaction::sharedCreditSet( + naAccountPublic, naAccountPrivate, + naSrcAccountID, + asSrc->getSeq(), + theConfig.FEE_DEFAULT, + 0, // YYY No source tag + naDstAccountID, + bLimitAmount, saLimitAmount, + bQualityIn, uQualityIn, + bQualityOut, uQualityOut); + + trans = mNetOps->submitTransaction(trans); + + obj["transaction"] = trans->getSTransaction()->getJson(0); + obj["status"] = trans->getStatus(); + obj["seed"] = naSeed.humanSeed(); + obj["srcAccountID"] = naSrcAccountID.humanAccountID(); + obj["dstAccountID"] = naDstAccountID.humanAccountID(); + + return obj; + } +} + // ripple_lines_get || [] Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) { From 64b3afad28b009a7de9b893710c6fd2b1bf04dde Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 18 Aug 2012 13:16:58 -0700 Subject: [PATCH 075/426] Fixes for quality. --- src/SerializedTypes.h | 2 +- src/TransactionEngine.cpp | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index b1a264cde4..1ba0793ad3 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -50,7 +50,7 @@ enum PathFlags PF_ISSUE = 0x80, }; -#define QUALITY_ONE 100000000 // 10e9 +#define QUALITY_ONE 1000000000 // 10e9 #define CURRENCY_XNS uint160(0) #define CURRENCY_ONE uint160(1) // Used as a place holder #define ACCOUNT_XNS uint160(0) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 12886c4398..ad1c4c63d7 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1504,7 +1504,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti return terNO_DST; } - bool bFlipped = mTxnAccountID > uDstAccountID; + bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest. bool bLimitAmount = txn.getITFieldPresent(sfLimitAmount); STAmount saLimitAmount = bLimitAmount ? txn.getITFieldAmount(sfLimitAmount) : STAmount(); bool bQualityIn = txn.getITFieldPresent(sfQualityIn); @@ -1589,21 +1589,19 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti else { // Create a new ripple line. - STAmount saZero(uCurrencyID); - sleRippleState = entryCreate(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString(); - sleRippleState->setIFieldAmount(sfBalance, saZero); // Zero balance in currency. + sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID)); // Zero balance in currency. sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAmount); - sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, saZero); + sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID)); sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, mTxnAccountID); sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uDstAccountID); if (uQualityIn) - sleRippleState->setIFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn); + sleRippleState->setIFieldU32(bFlipped ? sfHighQualityIn : sfLowQualityIn, uQualityIn); if (uQualityOut) - sleRippleState->setIFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut); + sleRippleState->setIFieldU32(bFlipped ? sfHighQualityOut : sfLowQualityOut, uQualityOut); uint64 uSrcRef; // Ignored, dirs never delete. @@ -2531,8 +2529,6 @@ void TransactionEngine::calcNodeRipple( STAmount saPrv = bPrvUnlimited ? STAmount(saPrvReq) : saPrvReq-saPrvAct; STAmount saCur = saCurReq-saCurAct; - Log(lsINFO) << str(boost::format("calcNodeRipple:1: saCurReq=%s") % saCurReq.getFullText()); - #if 0 Log(lsINFO) << str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCur=%s") % bPrvUnlimited @@ -2543,6 +2539,8 @@ void TransactionEngine::calcNodeRipple( if (uQualityIn >= uQualityOut) { // No fee. + Log(lsINFO) << str(boost::format("calcNodeRipple: No fees")); + STAmount saTransfer = bPrvUnlimited ? saCur : MIN(saPrv, saCur); saPrvAct += saTransfer; @@ -2551,15 +2549,16 @@ void TransactionEngine::calcNodeRipple( else { // Fee. + Log(lsINFO) << str(boost::format("calcNodeRipple: Fee")); + uint160 uCurrencyID = saCur.getCurrency(); STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID), uQualityIn, uCurrencyID); -Log(lsINFO) << str(boost::format("calcNodeRipple:2: saCurReq=%s") % saCurReq.getFullText()); - if (bPrvUnlimited || saCurIn >= saPrv) +Log(lsINFO) << str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCurIn=%s") % bPrvUnlimited % saPrv.getFullText() % saCurIn.getFullText()); + if (bPrvUnlimited || saCurIn <= saPrv) { // All of cur. Some amount of prv. -Log(lsINFO) << str(boost::format("calcNodeRipple:3a: saCurReq=%s") % saCurReq.getFullText()); - saCurAct = saCurReq; + saCurAct += saCur; saPrvAct += saCurIn; Log(lsINFO) << str(boost::format("calcNodeRipple:3c: saCurReq=%s saPrvAct=%s") % saCurReq.getFullText() % saPrvAct.getFullText()); } From 6aa725768a69567d4c000ab37b6929aba2250536 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 19 Aug 2012 01:41:07 -0700 Subject: [PATCH 076/426] Cosmetic. --- src/TransactionEngine.cpp | 141 +++++++++++++++++++------------------- 1 file changed, 71 insertions(+), 70 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index ad1c4c63d7..65e9cda809 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1903,17 +1903,17 @@ bool TransactionEngine::calcNodeOfferRev( { bool bSuccess = false; - paymentNode& prvPN = pspCur->vpnNodes[uIndex-1]; - paymentNode& curPN = pspCur->vpnNodes[uIndex]; - paymentNode& nxtPN = pspCur->vpnNodes[uIndex+1]; + paymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; + paymentNode& pnCur = pspCur->vpnNodes[uIndex]; + paymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; - uint160& uPrvCurrencyID = prvPN.uCurrencyID; - uint160& uPrvIssuerID = prvPN.uIssuerID; - uint160& uCurCurrencyID = curPN.uCurrencyID; - uint160& uCurIssuerID = curPN.uIssuerID; - uint160& uNxtCurrencyID = nxtPN.uCurrencyID; - uint160& uNxtIssuerID = nxtPN.uIssuerID; - uint160& uNxtAccountID = nxtPN.uAccountID; + uint160& uPrvCurrencyID = pnPrv.uCurrencyID; + uint160& uPrvIssuerID = pnPrv.uIssuerID; + uint160& uCurCurrencyID = pnCur.uCurrencyID; + uint160& uCurIssuerID = pnCur.uIssuerID; + uint160& uNxtCurrencyID = pnNxt.uCurrencyID; + uint160& uNxtIssuerID = pnNxt.uIssuerID; + uint160& uNxtAccountID = pnNxt.uAccountID; STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9); @@ -1921,10 +1921,10 @@ bool TransactionEngine::calcNodeOfferRev( uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); - STAmount& saPrvDlvReq = prvPN.saRevDeliver; // To be adjusted. + STAmount& saPrvDlvReq = pnPrv.saRevDeliver; // To be adjusted. STAmount saPrvDlvAct; - const STAmount& saCurDlvReq = curPN.saRevDeliver; // Reverse driver. + const STAmount& saCurDlvReq = pnCur.saRevDeliver; // Reverse driver. STAmount saCurDlvAct; while (!!uDirectTip // Have a quality. @@ -1944,6 +1944,7 @@ bool TransactionEngine::calcNodeOfferRev( { // Do a directory. // - Drive on computing saCurDlvAct to derive saPrvDlvAct. + // XXX Behave well, if entry type is wrong (someone beat us to using the hash) SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip), uCurCurrencyID); // For correct ratio unsigned int uEntry = 0; @@ -2095,28 +2096,28 @@ bool TransactionEngine::calcNodeOfferFwd( { bool bSuccess = false; - paymentNode& prvPN = pspCur->vpnNodes[uIndex-1]; - paymentNode& curPN = pspCur->vpnNodes[uIndex]; - paymentNode& nxtPN = pspCur->vpnNodes[uIndex+1]; + paymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; + paymentNode& pnCur = pspCur->vpnNodes[uIndex]; + paymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; - uint160& uPrvCurrencyID = prvPN.uCurrencyID; - uint160& uPrvIssuerID = prvPN.uIssuerID; - uint160& uCurCurrencyID = curPN.uCurrencyID; - uint160& uCurIssuerID = curPN.uIssuerID; - uint160& uNxtCurrencyID = nxtPN.uCurrencyID; - uint160& uNxtIssuerID = nxtPN.uIssuerID; + uint160& uPrvCurrencyID = pnPrv.uCurrencyID; + uint160& uPrvIssuerID = pnPrv.uIssuerID; + uint160& uCurCurrencyID = pnCur.uCurrencyID; + uint160& uCurIssuerID = pnCur.uIssuerID; + uint160& uNxtCurrencyID = pnNxt.uCurrencyID; + uint160& uNxtIssuerID = pnNxt.uIssuerID; - uint160& uNxtAccountID = nxtPN.uAccountID; + uint160& uNxtAccountID = pnNxt.uAccountID; STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9); uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); - STAmount& saPrvDlvReq = prvPN.saFwdDeliver; // Forward driver. + STAmount& saPrvDlvReq = pnPrv.saFwdDeliver; // Forward driver. STAmount saPrvDlvAct; - STAmount& saCurDlvReq = curPN.saFwdDeliver; + STAmount& saCurDlvReq = pnCur.saFwdDeliver; STAmount saCurDlvAct; while (!!uDirectTip // Have a quality. @@ -2589,22 +2590,22 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point bool bSuccess = true; unsigned int uLast = pspCur->vpnNodes.size() - 1; - paymentNode& prvPN = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; - paymentNode& curPN = pspCur->vpnNodes[uIndex]; - paymentNode& nxtPN = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; + paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; + paymentNode& pnCur = pspCur->vpnNodes[uIndex]; + paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - bool bRedeem = !!(curPN.uFlags & STPathElement::typeRedeem); - bool bPrvRedeem = !!(prvPN.uFlags & STPathElement::typeRedeem); - bool bIssue = !!(curPN.uFlags & STPathElement::typeIssue); - bool bPrvIssue = !!(prvPN.uFlags & STPathElement::typeIssue); - bool bPrvAccount = !uIndex || !!(prvPN.uFlags & STPathElement::typeAccount); - bool bNxtAccount = uIndex == uLast || !!(nxtPN.uFlags & STPathElement::typeAccount); + bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem); + bool bPrvRedeem = !!(pnPrv.uFlags & STPathElement::typeRedeem); + bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue); + bool bPrvIssue = !!(pnPrv.uFlags & STPathElement::typeIssue); + bool bPrvAccount = !uIndex || !!(pnPrv.uFlags & STPathElement::typeAccount); + bool bNxtAccount = uIndex == uLast || !!(pnNxt.uFlags & STPathElement::typeAccount); - const uint160& uPrvAccountID = prvPN.uAccountID; - const uint160& uCurAccountID = curPN.uAccountID; - const uint160& uNxtAccountID = bNxtAccount ? nxtPN.uAccountID : uCurAccountID; // Offers are always issue. + const uint160& uPrvAccountID = pnPrv.uAccountID; + const uint160& uCurAccountID = pnCur.uAccountID; + const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. - const uint160& uCurrencyID = curPN.uCurrencyID; + const uint160& uCurrencyID = pnCur.uCurrencyID; const uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : 1; const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : 1; @@ -2614,24 +2615,24 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point const STAmount saPrvLimit = uIndex && bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); const STAmount saPrvRedeemReq = bPrvRedeem && saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); - STAmount& saPrvRedeemAct = prvPN.saRevRedeem; + STAmount& saPrvRedeemAct = pnPrv.saRevRedeem; const STAmount saPrvIssueReq = bPrvIssue ? saPrvLimit - saPrvBalance : STAmount(uCurrencyID); - STAmount& saPrvIssueAct = prvPN.saRevIssue; + STAmount& saPrvIssueAct = pnPrv.saRevIssue; // For !bPrvAccount const STAmount saPrvDeliverReq = STAmount(uCurrencyID, -1); // Unlimited. - STAmount& saPrvDeliverAct = prvPN.saRevDeliver; + STAmount& saPrvDeliverAct = pnPrv.saRevDeliver; // For bNxtAccount - const STAmount& saCurRedeemReq = curPN.saRevRedeem; + const STAmount& saCurRedeemReq = pnCur.saRevRedeem; STAmount saCurRedeemAct(saCurRedeemReq.getCurrency()); - const STAmount& saCurIssueReq = curPN.saRevIssue; + const STAmount& saCurIssueReq = pnCur.saRevIssue; STAmount saCurIssueAct(saCurIssueReq.getCurrency()); // Track progress. // For !bNxtAccount - const STAmount& saCurDeliverReq = curPN.saRevDeliver; + const STAmount& saCurDeliverReq = pnCur.saRevDeliver; STAmount saCurDeliverAct(saCurDeliverReq.getCurrency()); // For uIndex == uLast @@ -2883,45 +2884,45 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point bool bSuccess = true; unsigned int uLast = pspCur->vpnNodes.size() - 1; - paymentNode& prvPN = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; - paymentNode& curPN = pspCur->vpnNodes[uIndex]; - paymentNode& nxtPN = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; + paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; + paymentNode& pnCur = pspCur->vpnNodes[uIndex]; + paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - bool bRedeem = !!(curPN.uFlags & STPathElement::typeRedeem); - bool bIssue = !!(curPN.uFlags & STPathElement::typeIssue); - bool bPrvAccount = !!(prvPN.uFlags & STPathElement::typeAccount); - bool bNxtAccount = !!(nxtPN.uFlags & STPathElement::typeAccount); + bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem); + bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue); + bool bPrvAccount = !!(pnPrv.uFlags & STPathElement::typeAccount); + bool bNxtAccount = !!(pnNxt.uFlags & STPathElement::typeAccount); - uint160& uPrvAccountID = prvPN.uAccountID; - uint160& uCurAccountID = curPN.uAccountID; - uint160& uNxtAccountID = bNxtAccount ? nxtPN.uAccountID : uCurAccountID; // Offers are always issue. + uint160& uPrvAccountID = pnPrv.uAccountID; + uint160& uCurAccountID = pnCur.uAccountID; + uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. - uint160& uCurrencyID = curPN.uCurrencyID; + uint160& uCurrencyID = pnCur.uCurrencyID; uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); // For bNxtAccount - const STAmount& saPrvRedeemReq = prvPN.saFwdRedeem; + const STAmount& saPrvRedeemReq = pnPrv.saFwdRedeem; STAmount saPrvRedeemAct(saPrvRedeemReq.getCurrency()); - const STAmount& saPrvIssueReq = prvPN.saFwdIssue; + const STAmount& saPrvIssueReq = pnPrv.saFwdIssue; STAmount saPrvIssueAct(saPrvIssueReq.getCurrency()); // For !bPrvAccount - const STAmount& saPrvDeliverReq = prvPN.saRevDeliver; + const STAmount& saPrvDeliverReq = pnPrv.saRevDeliver; STAmount saPrvDeliverAct(saPrvDeliverReq.getCurrency()); // For bNxtAccount - const STAmount& saCurRedeemReq = curPN.saRevRedeem; - STAmount& saCurRedeemAct = curPN.saFwdRedeem; + const STAmount& saCurRedeemReq = pnCur.saRevRedeem; + STAmount& saCurRedeemAct = pnCur.saFwdRedeem; - const STAmount& saCurIssueReq = curPN.saRevIssue; - STAmount& saCurIssueAct = curPN.saFwdIssue; + const STAmount& saCurIssueReq = pnCur.saRevIssue; + STAmount& saCurIssueAct = pnCur.saFwdIssue; // For !bNxtAccount - const STAmount& saCurDeliverReq = curPN.saRevDeliver; - STAmount& saCurDeliverAct = curPN.saFwdDeliver; + const STAmount& saCurDeliverReq = pnCur.saRevDeliver; + STAmount& saCurDeliverAct = pnCur.saFwdDeliver; STAmount& saCurReceive = pspCur->saOutAct; @@ -2945,12 +2946,12 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point // First node, calculate amount to send. // XXX Use stamp/ripple balance - paymentNode& curPN = pspCur->vpnNodes[uIndex]; + paymentNode& pnCur = pspCur->vpnNodes[uIndex]; - STAmount& saCurRedeemReq = curPN.saRevRedeem; - STAmount& saCurRedeemAct = curPN.saFwdRedeem; - STAmount& saCurIssueReq = curPN.saRevIssue; - STAmount& saCurIssueAct = curPN.saFwdIssue; + STAmount& saCurRedeemReq = pnCur.saRevRedeem; + STAmount& saCurRedeemAct = pnCur.saFwdRedeem; + STAmount& saCurIssueReq = pnCur.saRevIssue; + STAmount& saCurIssueAct = pnCur.saFwdIssue; STAmount& saCurSendMaxReq = pspCur->saInReq; // Negative for no limit, doing a calculation. STAmount& saCurSendMaxAct = pspCur->saInAct; // Report to user how much this sends. @@ -3512,8 +3513,8 @@ Json::Value PathState::getJson() const // XXX Disallow looping. bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) { - paymentNode& curPN = pspCur->vpnNodes[uIndex]; - bool bCurAccount = !!(curPN.uFlags & STPathElement::typeAccount); + paymentNode& pnCur = pspCur->vpnNodes[uIndex]; + bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount); bool bValid; // Do current node reverse. From 053e030e70e9cf7b5e69377849f507c99a1e169a Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 19 Aug 2012 02:32:09 -0700 Subject: [PATCH 077/426] Constify TransactionEngine. --- src/TransactionEngine.cpp | 289 +++++++++++++++++++------------------- 1 file changed, 144 insertions(+), 145 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 65e9cda809..af7f9a53a2 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -366,8 +366,8 @@ void TransactionEngine::rippleCredit(const uint160& uSenderID, const uint160& uR // <-- saActual: Amount actually sent. Sender pay's fees. STAmount TransactionEngine::rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount) { - STAmount saActual; - uint160 uIssuerID = saAmount.getIssuer(); + STAmount saActual; + const uint160 uIssuerID = saAmount.getIssuer(); if (uSenderID == uIssuerID || uReceiverID == uIssuerID) { @@ -1504,15 +1504,14 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti return terNO_DST; } - bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest. - bool bLimitAmount = txn.getITFieldPresent(sfLimitAmount); - STAmount saLimitAmount = bLimitAmount ? txn.getITFieldAmount(sfLimitAmount) : STAmount(); - bool bQualityIn = txn.getITFieldPresent(sfQualityIn); - uint32 uQualityIn = bQualityIn ? txn.getITFieldU32(sfQualityIn) : 0; - bool bQualityOut = txn.getITFieldPresent(sfQualityOut); - uint32 uQualityOut = bQualityIn ? txn.getITFieldU32(sfQualityOut) : 0; - uint160 uCurrencyID = saLimitAmount.getCurrency(); - STAmount saBalance(uCurrencyID); + const bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest. + const bool bLimitAmount = txn.getITFieldPresent(sfLimitAmount); + const STAmount saLimitAmount = bLimitAmount ? txn.getITFieldAmount(sfLimitAmount) : STAmount(); + const bool bQualityIn = txn.getITFieldPresent(sfQualityIn); + const uint32 uQualityIn = bQualityIn ? txn.getITFieldU32(sfQualityIn) : 0; + const bool bQualityOut = txn.getITFieldPresent(sfQualityOut); + const uint32 uQualityOut = bQualityIn ? txn.getITFieldU32(sfQualityOut) : 0; + const uint160 uCurrencyID = saLimitAmount.getCurrency(); bool bDelIndex = false; SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); @@ -1620,9 +1619,9 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac { std::cerr << "doNicknameSet>" << std::endl; - uint256 uNickname = txn.getITFieldH256(sfNickname); - bool bMinOffer = txn.getITFieldPresent(sfMinimumOffer); - STAmount saMinOffer = bMinOffer ? txn.getITFieldAmount(sfAmount) : STAmount(); + const uint256 uNickname = txn.getITFieldH256(sfNickname); + const bool bMinOffer = txn.getITFieldPresent(sfMinimumOffer); + const STAmount saMinOffer = bMinOffer ? txn.getITFieldAmount(sfAmount) : STAmount(); SLE::pointer sleNickname = entryCache(ltNICKNAME, uNickname); @@ -1631,7 +1630,7 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac // Edit old entry. sleNickname->setIFieldAccount(sfAccount, mTxnAccountID); - if (bMinOffer && !saMinOffer.isZero()) + if (bMinOffer && !!saMinOffer) { sleNickname->setIFieldAmount(sfMinimumOffer, saMinOffer); } @@ -1653,7 +1652,7 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac sleNickname->setIFieldAccount(sfAccount, mTxnAccountID); - if (bMinOffer && !saMinOffer.isZero()) + if (bMinOffer && !!saMinOffer) sleNickname->setIFieldAmount(sfMinimumOffer, saMinOffer); } @@ -1666,7 +1665,7 @@ TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransa { std::cerr << "doPasswordFund>" << std::endl; - uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); + const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); SLE::pointer sleDst = mTxnAccountID == uDstAccountID ? mTxnAccount : entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); @@ -1907,18 +1906,18 @@ bool TransactionEngine::calcNodeOfferRev( paymentNode& pnCur = pspCur->vpnNodes[uIndex]; paymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; - uint160& uPrvCurrencyID = pnPrv.uCurrencyID; - uint160& uPrvIssuerID = pnPrv.uIssuerID; - uint160& uCurCurrencyID = pnCur.uCurrencyID; - uint160& uCurIssuerID = pnCur.uIssuerID; - uint160& uNxtCurrencyID = pnNxt.uCurrencyID; - uint160& uNxtIssuerID = pnNxt.uIssuerID; - uint160& uNxtAccountID = pnNxt.uAccountID; + const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; + const uint160& uPrvIssuerID = pnPrv.uIssuerID; + const uint160& uCurCurrencyID = pnCur.uCurrencyID; + const uint160& uCurIssuerID = pnCur.uIssuerID; + const uint160& uNxtCurrencyID = pnNxt.uCurrencyID; + const uint160& uNxtIssuerID = pnNxt.uIssuerID; + const uint160& uNxtAccountID = pnNxt.uAccountID; - STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9); + const STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9); uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); - uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); + const uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); STAmount& saPrvDlvReq = pnPrv.saRevDeliver; // To be adjusted. @@ -2100,21 +2099,21 @@ bool TransactionEngine::calcNodeOfferFwd( paymentNode& pnCur = pspCur->vpnNodes[uIndex]; paymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; - uint160& uPrvCurrencyID = pnPrv.uCurrencyID; - uint160& uPrvIssuerID = pnPrv.uIssuerID; - uint160& uCurCurrencyID = pnCur.uCurrencyID; - uint160& uCurIssuerID = pnCur.uIssuerID; - uint160& uNxtCurrencyID = pnNxt.uCurrencyID; - uint160& uNxtIssuerID = pnNxt.uIssuerID; + const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; + const uint160& uPrvIssuerID = pnPrv.uIssuerID; + const uint160& uCurCurrencyID = pnCur.uCurrencyID; + const uint160& uCurIssuerID = pnCur.uIssuerID; + const uint160& uNxtCurrencyID = pnNxt.uCurrencyID; + const uint160& uNxtIssuerID = pnNxt.uIssuerID; - uint160& uNxtAccountID = pnNxt.uAccountID; - STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9); + const uint160& uNxtAccountID = pnNxt.uAccountID; + const STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9); uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); - uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); + const uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); - STAmount& saPrvDlvReq = pnPrv.saFwdDeliver; // Forward driver. + const STAmount& saPrvDlvReq = pnPrv.saFwdDeliver; // Forward driver. STAmount saPrvDlvAct; STAmount& saCurDlvReq = pnCur.saFwdDeliver; @@ -2164,22 +2163,22 @@ bool TransactionEngine::calcNodeOfferFwd( { // Next is an account. - STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtAccountID == uCurIssuerID - ? saOne - : saTransferRate; - bool bFee = saFeeRate != saOne; + const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtAccountID == uCurIssuerID + ? saOne + : saTransferRate; + const bool bFee = saFeeRate != saOne; - STAmount saOutPass = STAmount::divide(saCurOfrInReq, saOfrRate, uCurCurrencyID); - STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. - STAmount saOutCost = MIN( - bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) - : saOutBase, - saCurOfrFunds); // Limit cost by fees & funds. - STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) - : saOutCost; // Out amount after fees. - STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID); // Compute input w/o fees required. + const STAmount saOutPass = STAmount::divide(saCurOfrInReq, saOfrRate, uCurCurrencyID); + const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. + const STAmount saOutCost = MIN( + bFee + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + : saOutBase, + saCurOfrFunds); // Limit cost by fees & funds. + const STAmount saOutDlvAct = bFee + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + : saOutCost; // Out amount after fees. + const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID); // Compute input w/o fees required. saCurDlvAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saInDlvAct; // Portion needed in previous. @@ -2189,7 +2188,7 @@ bool TransactionEngine::calcNodeOfferFwd( // Next is an offer. uint256 uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); - uint256 uNxtEnd = Ledger::getQualityNext(uNxtTip); + const uint256 uNxtEnd = Ledger::getQualityNext(uNxtTip); bool bNxtAdvance = !entryCache(ltDIR_NODE, uNxtTip); while (!!uNxtTip // Have a quality. @@ -2218,30 +2217,30 @@ bool TransactionEngine::calcNodeOfferFwd( { // YYY This could combine offers with the same fee before doing math. SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex); - uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); + const uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); STAmount saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); // XXX Move issuer into STAmount if (sleNxtOfr->getIFieldPresent(sfPaysIssuer)) saNxtOfrIn.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID()); - STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID - ? saOne - : saTransferRate; - bool bFee = saFeeRate != saOne; + const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID + ? saOne + : saTransferRate; + const bool bFee = saFeeRate != saOne; - STAmount saInBase = saCurOfrInReq-saCurOfrInAct; - STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID); - STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. - saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. - STAmount saOutCost = MIN( + const STAmount saInBase = saCurOfrInReq-saCurOfrInAct; + const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID); + STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. + saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. + const STAmount saOutCost = MIN( bFee ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) : saOutBase, saCurOfrFunds); // Limit cost by fees & funds. - STAmount saOutDlvAct = bFee + const STAmount saOutDlvAct = bFee ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) : saOutCost; // Out amount after fees. - STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required. + const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required. saCurOfrInAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saOutDlvAct; // Portion needed in previous. @@ -2526,9 +2525,9 @@ void TransactionEngine::calcNodeRipple( assert(saPrvReq.getCurrency() == saCurReq.getCurrency()); - bool bPrvUnlimited = saPrvReq.isNegative(); - STAmount saPrv = bPrvUnlimited ? STAmount(saPrvReq) : saPrvReq-saPrvAct; - STAmount saCur = saCurReq-saCurAct; + const bool bPrvUnlimited = saPrvReq.isNegative(); + const STAmount saPrv = bPrvUnlimited ? STAmount(saPrvReq) : saPrvReq-saPrvAct; + const STAmount saCur = saCurReq-saCurAct; #if 0 Log(lsINFO) << str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCur=%s") @@ -2588,18 +2587,18 @@ Log(lsINFO) << str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.get bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) { bool bSuccess = true; - unsigned int uLast = pspCur->vpnNodes.size() - 1; + const unsigned int uLast = pspCur->vpnNodes.size() - 1; paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; paymentNode& pnCur = pspCur->vpnNodes[uIndex]; paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem); - bool bPrvRedeem = !!(pnPrv.uFlags & STPathElement::typeRedeem); - bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue); - bool bPrvIssue = !!(pnPrv.uFlags & STPathElement::typeIssue); - bool bPrvAccount = !uIndex || !!(pnPrv.uFlags & STPathElement::typeAccount); - bool bNxtAccount = uIndex == uLast || !!(pnNxt.uFlags & STPathElement::typeAccount); + const bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem); + const bool bPrvRedeem = !!(pnPrv.uFlags & STPathElement::typeRedeem); + const bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue); + const bool bPrvIssue = !!(pnPrv.uFlags & STPathElement::typeIssue); + const bool bPrvAccount = !uIndex || !!(pnPrv.uFlags & STPathElement::typeAccount); + const bool bNxtAccount = uIndex == uLast || !!(pnNxt.uFlags & STPathElement::typeAccount); const uint160& uPrvAccountID = pnPrv.uAccountID; const uint160& uCurAccountID = pnCur.uAccountID; @@ -2882,22 +2881,22 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) { bool bSuccess = true; - unsigned int uLast = pspCur->vpnNodes.size() - 1; + const unsigned int uLast = pspCur->vpnNodes.size() - 1; paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; paymentNode& pnCur = pspCur->vpnNodes[uIndex]; paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem); - bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue); - bool bPrvAccount = !!(pnPrv.uFlags & STPathElement::typeAccount); - bool bNxtAccount = !!(pnNxt.uFlags & STPathElement::typeAccount); + const bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem); + const bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue); + const bool bPrvAccount = !!(pnPrv.uFlags & STPathElement::typeAccount); + const bool bNxtAccount = !!(pnNxt.uFlags & STPathElement::typeAccount); - uint160& uPrvAccountID = pnPrv.uAccountID; - uint160& uCurAccountID = pnCur.uAccountID; - uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. + const uint160& uPrvAccountID = pnPrv.uAccountID; + const uint160& uCurAccountID = pnCur.uAccountID; + const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. - uint160& uCurrencyID = pnCur.uCurrencyID; + const uint160& uCurrencyID = pnCur.uCurrencyID; uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); @@ -2948,12 +2947,12 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point // XXX Use stamp/ripple balance paymentNode& pnCur = pspCur->vpnNodes[uIndex]; - STAmount& saCurRedeemReq = pnCur.saRevRedeem; + const STAmount& saCurRedeemReq = pnCur.saRevRedeem; STAmount& saCurRedeemAct = pnCur.saFwdRedeem; - STAmount& saCurIssueReq = pnCur.saRevIssue; + const STAmount& saCurIssueReq = pnCur.saRevIssue; STAmount& saCurIssueAct = pnCur.saFwdIssue; - STAmount& saCurSendMaxReq = pspCur->saInReq; // Negative for no limit, doing a calculation. + const STAmount& saCurSendMaxReq = pspCur->saInReq; // Negative for no limit, doing a calculation. STAmount& saCurSendMaxAct = pspCur->saInAct; // Report to user how much this sends. if (saCurRedeemReq) @@ -3224,20 +3223,20 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin << NewcoinAddress::createHumanAccountID(uAccountID) << " " << STAmount::createHumanCurrency(uCurrencyID) << " " << NewcoinAddress::createHumanAccountID(uIssuerID); - paymentNode pnCur; - bool bFirst = vpnNodes.empty(); - const paymentNode& pnPrv = bFirst ? paymentNode() : vpnNodes.back(); - // true, iff node is a ripple account. false, iff node is an offer node. - bool bAccount = !!(iType & STPathElement::typeAccount); - // true, iff currency supplied. - // Currency is specified for the output of the current node. - bool bCurrency = !!(iType & STPathElement::typeCurrency); - // Issuer is specified for the output of the current node. - bool bIssuer = !!(iType & STPathElement::typeIssuer); - // true, iff account is allowed to redeem it's IOUs to next node. - bool bRedeem = !!(iType & STPathElement::typeRedeem); - bool bIssue = !!(iType & STPathElement::typeIssue); - bool bValid = true; + paymentNode pnCur; + const bool bFirst = vpnNodes.empty(); + const paymentNode& pnPrv = bFirst ? paymentNode() : vpnNodes.back(); + // true, iff node is a ripple account. false, iff node is an offer node. + const bool bAccount = !!(iType & STPathElement::typeAccount); + // true, iff currency supplied. + // Currency is specified for the output of the current node. + const bool bCurrency = !!(iType & STPathElement::typeCurrency); + // Issuer is specified for the output of the current node. + const bool bIssuer = !!(iType & STPathElement::typeIssuer); + // true, iff account is allowed to redeem it's IOUs to next node. + const bool bRedeem = !!(iType & STPathElement::typeRedeem); + const bool bIssue = !!(iType & STPathElement::typeIssue); + bool bValid = true; pnCur.uFlags = iType; @@ -3380,10 +3379,10 @@ PathState::PathState( ) : mLedger(lpLedger), mIndex(iIndex), uQuality(0) { - uint160 uInCurrencyID = saSendMax.getCurrency(); - uint160 uOutCurrencyID = saSend.getCurrency(); - uint160 uInIssuerID = !!uInCurrencyID ? uSenderID : ACCOUNT_XNS; - uint160 uOutIssuerID = !!uOutCurrencyID ? uReceiverID : ACCOUNT_XNS; + const uint160 uInCurrencyID = saSendMax.getCurrency(); + const uint160 uOutCurrencyID = saSend.getCurrency(); + const uint160 uInIssuerID = !!uInCurrencyID ? uSenderID : ACCOUNT_XNS; + const uint160 uOutIssuerID = !!uOutCurrencyID ? uReceiverID : ACCOUNT_XNS; lesEntries = lesSource.duplicate(); @@ -3513,9 +3512,9 @@ Json::Value PathState::getJson() const // XXX Disallow looping. bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) { - paymentNode& pnCur = pspCur->vpnNodes[uIndex]; - bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount); - bool bValid; + const paymentNode& pnCur = pspCur->vpnNodes[uIndex]; + const bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount); + bool bValid; // Do current node reverse. bValid = bCurAccount @@ -3571,17 +3570,17 @@ void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn) { // Ripple if source or destination is non-native or if there are paths. - uint32 uTxFlags = txn.getFlags(); - bool bCreate = !!(uTxFlags & tfCreateAccount); - bool bNoRippleDirect = !!(uTxFlags & tfNoRippleDirect); - bool bPartialPayment = !!(uTxFlags & tfPartialPayment); - bool bPaths = txn.getITFieldPresent(sfPaths); - bool bMax = txn.getITFieldPresent(sfSendMax); - uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); - STAmount saDstAmount = txn.getITFieldAmount(sfAmount); - STAmount saMaxAmount = bMax ? txn.getITFieldAmount(sfSendMax) : saDstAmount; - uint160 uSrcCurrency = saMaxAmount.getCurrency(); - uint160 uDstCurrency = saDstAmount.getCurrency(); + const uint32 uTxFlags = txn.getFlags(); + const bool bCreate = !!(uTxFlags & tfCreateAccount); + const bool bNoRippleDirect = !!(uTxFlags & tfNoRippleDirect); + const bool bPartialPayment = !!(uTxFlags & tfPartialPayment); + const bool bPaths = txn.getITFieldPresent(sfPaths); + const bool bMax = txn.getITFieldPresent(sfSendMax); + const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); + const STAmount saDstAmount = txn.getITFieldAmount(sfAmount); + const STAmount saMaxAmount = bMax ? txn.getITFieldAmount(sfSendMax) : saDstAmount; + const uint160 uSrcCurrency = saMaxAmount.getCurrency(); + const uint160 uDstCurrency = saDstAmount.getCurrency(); if (!uDstAccountID) { @@ -3878,11 +3877,11 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti { std::cerr << "WalletAdd>" << std::endl; - std::vector vucPubKey = txn.getITFieldVL(sfPubKey); - std::vector vucSignature = txn.getITFieldVL(sfSignature); - uint160 uAuthKeyID = txn.getITFieldAccount(sfAuthorizedKey); - NewcoinAddress naMasterPubKey = NewcoinAddress::createAccountPublic(vucPubKey); - uint160 uDstAccountID = naMasterPubKey.getAccountID(); + const std::vector vucPubKey = txn.getITFieldVL(sfPubKey); + const std::vector vucSignature = txn.getITFieldVL(sfSignature); + const uint160 uAuthKeyID = txn.getITFieldAccount(sfAuthorizedKey); + const NewcoinAddress naMasterPubKey = NewcoinAddress::createAccountPublic(vucPubKey); + const uint160 uDstAccountID = naMasterPubKey.getAccountID(); if (!naMasterPubKey.accountPublicVerify(Serializer::getSHA512Half(uAuthKeyID.begin(), uAuthKeyID.size()), vucSignature)) { @@ -3958,12 +3957,12 @@ TransactionEngineResult TransactionEngine::takeOffers( Log(lsINFO) << "takeOffers: against book: " << uBookBase.ToString(); uint256 uTipIndex = uBookBase; - uint256 uBookEnd = Ledger::getQualityNext(uBookBase); - uint64 uTakeQuality = STAmount::getRate(saTakerGets, saTakerPays); - uint160 uTakerPaysAccountID = saTakerPays.getIssuer(); - uint160 uTakerPaysCurrency = saTakerPays.getCurrency(); - uint160 uTakerGetsAccountID = saTakerGets.getIssuer(); - uint160 uTakerGetsCurrency = saTakerGets.getCurrency(); + const uint256 uBookEnd = Ledger::getQualityNext(uBookBase); + const uint64 uTakeQuality = STAmount::getRate(saTakerGets, saTakerPays); + const uint160 uTakerPaysAccountID = saTakerPays.getIssuer(); + const uint160 uTakerPaysCurrency = saTakerPays.getCurrency(); + const uint160 uTakerGetsAccountID = saTakerGets.getIssuer(); + const uint160 uTakerGetsCurrency = saTakerGets.getCurrency(); TransactionEngineResult terResult = tenUNKNOWN; saTakerPaid = 0; @@ -4018,7 +4017,7 @@ TransactionEngineResult TransactionEngine::takeOffers( Log(lsINFO) << "takeOffers: considering offer : " << sleOffer->getJson(0); - uint160 uOfferOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + const uint160 uOfferOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); @@ -4139,28 +4138,28 @@ TransactionEngineResult TransactionEngine::takeOffers( TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransaction& txn) { Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); - uint32 txFlags = txn.getFlags(); - bool bPassive = !!(txFlags & tfPassive); - uint160 uPaysIssuerID = txn.getITFieldAccount(sfPaysIssuer); - uint160 uGetsIssuerID = txn.getITFieldAccount(sfGetsIssuer); - STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); + const uint32 txFlags = txn.getFlags(); + const bool bPassive = !!(txFlags & tfPassive); + const uint160 uPaysIssuerID = txn.getITFieldAccount(sfPaysIssuer); + const uint160 uGetsIssuerID = txn.getITFieldAccount(sfGetsIssuer); + STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); saTakerPays.setIssuer(uPaysIssuerID); Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText(); STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); saTakerGets.setIssuer(uGetsIssuerID); Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); - uint32 uExpiration = txn.getITFieldU32(sfExpiration); - bool bHaveExpiration = txn.getITFieldPresent(sfExpiration); - uint32 uSequence = txn.getSequence(); + const uint32 uExpiration = txn.getITFieldU32(sfExpiration); + const bool bHaveExpiration = txn.getITFieldPresent(sfExpiration); + const uint32 uSequence = txn.getSequence(); - uint256 uLedgerIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); + const uint256 uLedgerIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); SLE::pointer sleOffer = entryCreate(ltOFFER, uLedgerIndex); Log(lsINFO) << "doOfferCreate: Creating offer node: " << uLedgerIndex.ToString() << " uSequence=" << uSequence; - uint160 uPaysCurrency = saTakerPays.getCurrency(); - uint160 uGetsCurrency = saTakerGets.getCurrency(); - uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays); + const uint160 uPaysCurrency = saTakerPays.getCurrency(); + const uint160 uGetsCurrency = saTakerGets.getCurrency(); + const uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays); TransactionEngineResult terResult = terSUCCESS; uint256 uDirectory; // Delete hints. @@ -4226,7 +4225,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); { STAmount saOfferPaid; STAmount saOfferGot; - uint256 uTakeBookBase = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); + const uint256 uTakeBookBase = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); Log(lsINFO) << str(boost::format("doOfferCreate: take against book: %s : %s/%s -> %s/%s") % uTakeBookBase.ToString() @@ -4333,8 +4332,8 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); TransactionEngineResult TransactionEngine::doOfferCancel(const SerializedTransaction& txn) { TransactionEngineResult terResult; - uint32 uSequence = txn.getITFieldU32(sfOfferSequence); - uint256 uOfferIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); + const uint32 uSequence = txn.getITFieldU32(sfOfferSequence); + const uint256 uOfferIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); if (sleOffer) From fbd67bda89ab8966e94d5bbbbb00229f8aea0455 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 19 Aug 2012 18:54:26 -0700 Subject: [PATCH 078/426] Let issuer be defaulted for RPC ripple command. --- src/RPCServer.cpp | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 93d800c3f1..11545daf7e 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1315,9 +1315,9 @@ Json::Value RPCServer::doPeers(const Json::Value& params) } // ripple -// [noredeem] [noissue] +// [] // XXX [noredeem] [noissue] // + -// full|partial +// full|partial [] // // path: // path + @@ -1331,6 +1331,7 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) STAmount saSrcAmountMax; uint160 uSrcCurrencyID; NewcoinAddress naSrcAccountID; + NewcoinAddress naSrcIssuerID; bool bSrcRedeem = true; bool bSrcIssue = true; bool bPartial; @@ -1338,11 +1339,12 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) NewcoinAddress naDstAccountID; STAmount saDstAmount; uint160 uDstCurrencyID; - NewcoinAddress naDstIssuerID; std::vector vpnPath; STPathSet spsPaths; + naSrcIssuerID.setAccountID(params[4u].asString()); // + if (!naSeed.setSeedGeneric(params[0u].asString())) // { return RPCError(rpcBAD_SEED); @@ -1351,13 +1353,18 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) { return RPCError(rpcSRC_ACT_MALFORMED); } - // - else if (!saSrcAmountMax.setFullValue(params[2u].asString(), params[3u].asString(), params[4u].asString())) + // [] + else if (!saSrcAmountMax.setFullValue(params[2u].asString(), params[3u].asString(), params[naSrcIssuerID.isValid() ? 4u : 1u].asString())) { + // Log(lsINFO) << "naSrcIssuerID.isValid(): " << naSrcIssuerID.isValid(); + // Log(lsINFO) << "source_max: " << params[2u].asString(); + // Log(lsINFO) << "source_currency: " << params[3u].asString(); + // Log(lsINFO) << "source_issuer: " << params[naSrcIssuerID.isValid() ? 4u : 2u].asString(); + return RPCError(rpcSRC_AMT_MALFORMED); } - int iArg = 5; + int iArg = 4 + naSrcIssuerID.isValid(); if (params[iArg].asString() == "noredeem") // [noredeem] { @@ -1483,14 +1490,21 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) { return RPCError(rpcDST_ACT_MALFORMED); } + + const unsigned int uDstIssuer = params.size() == iArg + 3 ? iArg+2 : iArg-1; + // - else if (params.size() != iArg + 3 || !saDstAmount.setFullValue(params[iArg].asString(), params[iArg+1].asString(), params[iArg+2].asString())) + if (params.size() != iArg + 2 && params.size() != iArg + 3) { - Log(lsINFO) << "params.size(): " << params.size(); - Log(lsINFO) << " iArg: " << iArg; - Log(lsINFO) << " Amount: " << params[iArg].asString(); - Log(lsINFO) << "Currency: " << params[iArg+1].asString(); - Log(lsINFO) << " Issuer: " << params[iArg+2].asString(); + // Log(lsINFO) << "params.size(): " << params.size(); + + return RPCError(rpcDST_AMT_MALFORMED); + } + else if (!saDstAmount.setFullValue(params[iArg].asString(), params[iArg+1].asString(), params[uDstIssuer].asString())) + { + // Log(lsINFO) << " Amount: " << params[iArg].asString(); + // Log(lsINFO) << "Currency: " << params[iArg+1].asString(); + // Log(lsINFO) << " Issuer: " << params[uDstIssuer].asString(); return RPCError(rpcDST_AMT_MALFORMED); } @@ -1515,6 +1529,8 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) // YYY Limit paths length and count. if (!asDst) { + Log(lsINFO) << "naDstAccountID: " << naDstAccountID.humanAccountID(); + return RPCError(rpcDST_ACT_MISSING); } @@ -2526,7 +2542,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "password_fund", &RPCServer::doPasswordFund, 2, 3, false, optCurrent }, { "password_set", &RPCServer::doPasswordSet, 2, 3, false, optNetwork }, { "peers", &RPCServer::doPeers, 0, 0, true }, - { "ripple", &RPCServer::doRipple, 10, -1, false, optCurrent|optClosed }, + { "ripple", &RPCServer::doRipple, 8, -1, false, optCurrent|optClosed }, { "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent }, { "ripple_line_set", &RPCServer::doRippleLineSet, 4, 7, false, optCurrent }, { "send", &RPCServer::doSend, 3, 7, false, optCurrent }, From e825db5db98bb588f7ad2a41836fb7d4e600b627 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 19 Aug 2012 19:03:33 -0700 Subject: [PATCH 079/426] Don't report a failure if we got a fat root. --- src/SHAMapSync.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SHAMapSync.cpp b/src/SHAMapSync.cpp index ed76558906..ee3bb0e1d5 100644 --- a/src/SHAMapSync.cpp +++ b/src/SHAMapSync.cpp @@ -450,7 +450,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) Log(lsFATAL) << "GetNodeFat(root) fails"; BOOST_FAIL("GetNodeFat"); } - if (gotNodes.size() != 1) + if (gotNodes.size() < 1) { Log(lsFATAL) << "Didn't get root node " << gotNodes.size(); BOOST_FAIL("NodeSize"); From 84ee39b1474ec21009ddc3b6a1d5257f2734ba45 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 19 Aug 2012 19:04:18 -0700 Subject: [PATCH 080/426] Fix a few more cases where we create a new shared pointer just to immediately throw it away, resulting in a wasted allocate/increment/decrement/free. --- src/CanonicalTXSet.cpp | 2 +- src/CanonicalTXSet.h | 2 +- src/ConnectionPool.cpp | 11 ++++++----- src/ConnectionPool.h | 15 +++++---------- src/Ledger.cpp | 4 ++-- src/Ledger.h | 6 +++--- src/LedgerNode.cpp | 2 +- src/SHAMap.cpp | 4 ++-- src/SHAMap.h | 10 +++++----- src/SHAMapDiff.cpp | 2 +- src/SHAMapNodes.cpp | 4 ++-- src/Transaction.cpp | 4 ++-- src/Transaction.h | 4 ++-- 13 files changed, 33 insertions(+), 37 deletions(-) diff --git a/src/CanonicalTXSet.cpp b/src/CanonicalTXSet.cpp index c46c089374..e3af1e4870 100644 --- a/src/CanonicalTXSet.cpp +++ b/src/CanonicalTXSet.cpp @@ -37,7 +37,7 @@ bool CanonicalTXKey::operator>=(const CanonicalTXKey& key)const return mTXid >= key.mTXid; } -void CanonicalTXSet::push_back(SerializedTransaction::pointer txn) +void CanonicalTXSet::push_back(const SerializedTransaction::pointer& txn) { uint256 effectiveAccount = mSetHash; effectiveAccount ^= txn->getSourceAccount().getAccountID().to256(); diff --git a/src/CanonicalTXSet.h b/src/CanonicalTXSet.h index 6978859af7..3315625a3e 100644 --- a/src/CanonicalTXSet.h +++ b/src/CanonicalTXSet.h @@ -38,7 +38,7 @@ protected: public: CanonicalTXSet(const uint256& lclHash) : mSetHash(lclHash) { ; } - void push_back(SerializedTransaction::pointer txn); + void push_back(const SerializedTransaction::pointer& txn); iterator erase(const iterator& it); iterator begin() { return mMap.begin(); } diff --git a/src/ConnectionPool.cpp b/src/ConnectionPool.cpp index 3d79fbc2ad..14e5604841 100644 --- a/src/ConnectionPool.cpp +++ b/src/ConnectionPool.cpp @@ -226,7 +226,7 @@ void ConnectionPool::policyHandler(const boost::system::error_code& ecResult) // YYY: Should probably do this in the background. // YYY: Might end up sending to disconnected peer? -void ConnectionPool::relayMessage(Peer* fromPeer, PackedMessage::pointer msg) +void ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg) { boost::mutex::scoped_lock sl(mPeerLock); @@ -339,7 +339,8 @@ std::vector ConnectionPool::getPeerVector() // Now know peer's node public key. Determine if we want to stay connected. // <-- bNew: false = redundant -bool ConnectionPool::peerConnected(Peer::pointer peer, const NewcoinAddress& naPeer, const std::string& strIP, int iPort) +bool ConnectionPool::peerConnected(const Peer::pointer& peer, const NewcoinAddress& naPeer, + const std::string& strIP, int iPort) { bool bNew = false; @@ -397,7 +398,7 @@ bool ConnectionPool::peerConnected(Peer::pointer peer, const NewcoinAddress& naP } // We maintain a map of public key to peer for connected and verified peers. Maintain it. -void ConnectionPool::peerDisconnected(Peer::pointer peer, const NewcoinAddress& naPeer) +void ConnectionPool::peerDisconnected(const Peer::pointer& peer, const NewcoinAddress& naPeer) { if (naPeer.isValid()) { @@ -484,7 +485,7 @@ bool ConnectionPool::peerScanSet(const std::string& strIp, int iPort) } // --> strIp: not empty -void ConnectionPool::peerClosed(Peer::pointer peer, const std::string& strIp, int iPort) +void ConnectionPool::peerClosed(const Peer::pointer& peer, const std::string& strIp, int iPort) { ipPort ipPeer = make_pair(strIp, iPort); bool bScanRefresh = false; @@ -539,7 +540,7 @@ void ConnectionPool::peerClosed(Peer::pointer peer, const std::string& strIp, in scanRefresh(); } -void ConnectionPool::peerVerified(Peer::pointer peer) +void ConnectionPool::peerVerified(const Peer::pointer& peer) { if (mScanning && mScanning == peer) { diff --git a/src/ConnectionPool.h b/src/ConnectionPool.h index c71c59fef6..b7983b751b 100644 --- a/src/ConnectionPool.h +++ b/src/ConnectionPool.h @@ -58,7 +58,7 @@ public: void start(); // Send message to network. - void relayMessage(Peer* fromPeer, PackedMessage::pointer msg); + void relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg); // Manual connection request. // Queue for immediate scanning. @@ -72,16 +72,16 @@ public: // We know peers node public key. // <-- bool: false=reject - bool peerConnected(Peer::pointer peer, const NewcoinAddress& naPeer, const std::string& strIP, int iPort); + bool peerConnected(const Peer::pointer& peer, const NewcoinAddress& naPeer, const std::string& strIP, int iPort); // No longer connected. - void peerDisconnected(Peer::pointer peer, const NewcoinAddress& naPeer); + void peerDisconnected(const Peer::pointer& peer, const NewcoinAddress& naPeer); // As client accepted. - void peerVerified(Peer::pointer peer); + void peerVerified(const Peer::pointer& peer); // As client failed connect and be accepted. - void peerClosed(Peer::pointer peer, const std::string& strIp, int iPort); + void peerClosed(const Peer::pointer& peer, const std::string& strIp, int iPort); Json::Value getPeersJson(); std::vector getPeerVector(); @@ -98,11 +98,6 @@ public: void policyLowWater(); void policyEnforce(); -#if 0 - //std::vector > mBroadcastMessages; - - bool isMessageKnown(PackedMessage::pointer msg); -#endif }; extern void splitIpPort(const std::string& strIpPort, std::string& strIp, int& iPort); diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 0cd6e2346d..7b150d69c7 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -210,7 +210,7 @@ RippleState::pointer Ledger::accessRippleState(const uint256& uNode) return boost::make_shared(sle); } -bool Ledger::addTransaction(Transaction::pointer trans) +bool Ledger::addTransaction(const Transaction::pointer& trans) { // low-level - just add to table assert(!mAccepted); assert(trans->getID().isNonZero()); @@ -257,7 +257,7 @@ uint256 Ledger::getHash() return(mHash); } -void Ledger::saveAcceptedLedger(Ledger::pointer ledger) +void Ledger::saveAcceptedLedger(const Ledger::pointer& ledger) { static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers where LedgerSeq = %d;"); static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %d;"); diff --git a/src/Ledger.h b/src/Ledger.h index 53dbe4dfbb..7f60fcbc8f 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -81,7 +81,7 @@ private: protected: - bool addTransaction(Transaction::pointer); + bool addTransaction(const Transaction::pointer&); bool addTransaction(const uint256& id, const Serializer& txn); static Ledger::pointer getSQL(const std::string& sqlStatement); @@ -156,12 +156,12 @@ public: // high-level functions AccountState::pointer getAccountState(const NewcoinAddress& acctID); - LedgerStateParms writeBack(LedgerStateParms parms, SLE::pointer); + LedgerStateParms writeBack(LedgerStateParms parms, const SLE::pointer&); SLE::pointer getAccountRoot(const uint160& accountID); SLE::pointer getAccountRoot(const NewcoinAddress& naAccountID); // database functions - static void saveAcceptedLedger(Ledger::pointer); + static void saveAcceptedLedger(const Ledger::pointer&); static Ledger::pointer loadByIndex(uint32 ledgerIndex); static Ledger::pointer loadByHash(const uint256& ledgerHash); diff --git a/src/LedgerNode.cpp b/src/LedgerNode.cpp index bbb4b7e969..24bfc58d77 100644 --- a/src/LedgerNode.cpp +++ b/src/LedgerNode.cpp @@ -8,7 +8,7 @@ // XXX Use shared locks where possible? -LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry) +LedgerStateParms Ledger::writeBack(LedgerStateParms parms, const SLE::pointer& entry) { ScopedLock l(mAccountStateMap->Lock()); bool create = false; diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index b360908f2d..2a9b48520b 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -498,7 +498,7 @@ bool SHAMap::delItem(const uint256& id) return true; } -bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasMeta) +bool SHAMap::addGiveItem(const SHAMapItem::pointer& item, bool isTransaction, bool hasMeta) { // add the specified item, does not update #ifdef ST_DEBUG std::cerr << "aGI " << item->getTag().GetHex() << std::endl; @@ -596,7 +596,7 @@ bool SHAMap::addItem(const SHAMapItem& i, bool isTransaction, bool hasMetaData) return addGiveItem(boost::make_shared(i), isTransaction, hasMetaData); } -bool SHAMap::updateGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasMeta) +bool SHAMap::updateGiveItem(const SHAMapItem::pointer& item, bool isTransaction, bool hasMeta) { // can't change the tag but can change the hash uint256 tag = item->getTag(); diff --git a/src/SHAMap.h b/src/SHAMap.h index 2f9e73d529..2e5c0ccbc8 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -160,7 +160,7 @@ private: public: SHAMapTreeNode(uint32 seq, const SHAMapNode& nodeID); // empty node SHAMapTreeNode(const SHAMapTreeNode& node, uint32 seq); // copy node from older tree - SHAMapTreeNode(const SHAMapNode& nodeID, SHAMapItem::pointer item, TNType type, uint32 seq); + SHAMapTreeNode(const SHAMapNode& nodeID, const SHAMapItem::pointer& item, TNType type, uint32 seq); // raw node functions SHAMapTreeNode(const SHAMapNode& id, const std::vector& data, uint32 seq, SHANodeFormat format); @@ -199,7 +199,7 @@ public: bool hasItem() const { return !!mItem; } SHAMapItem::pointer peekItem() { return mItem; } SHAMapItem::pointer getItem() const; - bool setItem(SHAMapItem::pointer& i, TNType type); + bool setItem(const SHAMapItem::pointer& i, TNType type); const uint256& getTag() const { return mItem->getTag(); } const std::vector& peekData() { return mItem->peekData(); } std::vector getData() const { return mItem->getData(); } @@ -311,8 +311,8 @@ public: uint256 getHash() { return root->getNodeHash(); } // save a copy if you have a temporary anyway - bool updateGiveItem(SHAMapItem::pointer, bool isTransaction, bool hasMeta); - bool addGiveItem(SHAMapItem::pointer, bool isTransaction, bool hasMeta); + bool updateGiveItem(const SHAMapItem::pointer&, bool isTransaction, bool hasMeta); + bool addGiveItem(const SHAMapItem::pointer&, bool isTransaction, bool hasMeta); // save a copy if you only need a temporary SHAMapItem::pointer peekItem(const uint256& id); @@ -345,7 +345,7 @@ public: // caution: otherMap must be accessed only by this function // return value: true=successfully completed, false=too different - bool compare(SHAMap::pointer otherMap, SHAMapDiff& differences, int maxCount); + bool compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, int maxCount); void armDirty(); int flushDirty(int maxNodes, HashedObjectType t, uint32 seq); diff --git a/src/SHAMapDiff.cpp b/src/SHAMapDiff.cpp index d1f3a32145..4bef1f73d1 100644 --- a/src/SHAMapDiff.cpp +++ b/src/SHAMapDiff.cpp @@ -91,7 +91,7 @@ bool SHAMap::walkBranch(SHAMapTreeNode* node, SHAMapItem::pointer otherMapItem, return true; } -bool SHAMap::compare(SHAMap::pointer otherMap, SHAMapDiff& differences, int maxCount) +bool SHAMap::compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, int maxCount) { // compare two hash trees, add up to maxCount differences to the difference table // return value: true=complete table of differences given, false=too many differences // throws on corrupt tables or missing nodes diff --git a/src/SHAMapNodes.cpp b/src/SHAMapNodes.cpp index 689745995c..144ccaf993 100644 --- a/src/SHAMapNodes.cpp +++ b/src/SHAMapNodes.cpp @@ -182,7 +182,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapTreeNode& node, uint32 seq) : SHAMapN memcpy(mHashes, node.mHashes, sizeof(mHashes)); } -SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, SHAMapItem::pointer item, TNType type, uint32 seq) : +SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, const SHAMapItem::pointer& item, TNType type, uint32 seq) : SHAMapNode(node), mItem(item), mSeq(seq), mType(type), mFullBelow(true) { assert(item->peekData().size() >= 12); @@ -429,7 +429,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, SHANodeFormat format) assert(false); } -bool SHAMapTreeNode::setItem(SHAMapItem::pointer& i, TNType type) +bool SHAMapTreeNode::setItem(const SHAMapItem::pointer& i, TNType type) { uint256 hash = getNodeHash(); mType = type; diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 3f01d43f0f..bf692f6cff 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -13,7 +13,7 @@ #include "SerializedTransaction.h" #include "Log.h" -Transaction::Transaction(const SerializedTransaction::pointer sit, bool bValidate) +Transaction::Transaction(const SerializedTransaction::pointer& sit, bool bValidate) : mInLedger(0), mStatus(INVALID), mTransaction(sit) { try @@ -584,7 +584,7 @@ void Transaction::setStatus(TransStatus ts, uint32 lseq) mInLedger = lseq; } -void Transaction::saveTransaction(Transaction::pointer txn) +void Transaction::saveTransaction(const Transaction::pointer& txn) { txn->save(); } diff --git a/src/Transaction.h b/src/Transaction.h index 745dce6d93..15ae32dff5 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -126,7 +126,7 @@ private: const std::vector& vucSignature); public: - Transaction(const SerializedTransaction::pointer st, bool bValidate); + Transaction(const SerializedTransaction::pointer& st, bool bValidate); static Transaction::pointer sharedTransaction(const std::vector&vucTransaction, bool bValidate); @@ -288,7 +288,7 @@ public: void setLedger(uint32 ledger) { mInLedger = ledger; } // database functions - static void saveTransaction(Transaction::pointer); + static void saveTransaction(const Transaction::pointer&); bool save(); static Transaction::pointer load(const uint256& id); static Transaction::pointer findFrom(const NewcoinAddress& fromID, uint32 seq); From 420ee918774da63724fb5e1f08af7cc60e195afd Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 19 Aug 2012 19:23:10 -0700 Subject: [PATCH 081/426] Remove more wasteful allocate/increment/decrement/free cycles. --- src/AccountState.cpp | 3 ++- src/AccountState.h | 4 ++-- src/LedgerAcquire.cpp | 2 +- src/LedgerAcquire.h | 2 +- src/LedgerConsensus.cpp | 28 ++++++++++++++-------------- src/LedgerConsensus.h | 30 +++++++++++++++--------------- src/LedgerHistory.cpp | 3 ++- src/LedgerMaster.cpp | 10 +++++----- src/LedgerMaster.h | 14 +++++++------- src/NetworkOPs.cpp | 2 +- src/NetworkOPs.h | 2 +- 11 files changed, 51 insertions(+), 49 deletions(-) diff --git a/src/AccountState.cpp b/src/AccountState.cpp index 1f84c9dce9..e9804926c2 100644 --- a/src/AccountState.cpp +++ b/src/AccountState.cpp @@ -19,7 +19,8 @@ AccountState::AccountState(const NewcoinAddress& id) : mValid(false) mValid = true; } -AccountState::AccountState(SerializedLedgerEntry::pointer ledgerEntry) : mLedgerEntry(ledgerEntry), mValid(false) +AccountState::AccountState(const SerializedLedgerEntry::pointer& ledgerEntry) : + mLedgerEntry(ledgerEntry), mValid(false) { if (!mLedgerEntry) return; if (mLedgerEntry->getType() != ltACCOUNT_ROOT) return; diff --git a/src/AccountState.h b/src/AccountState.h index b2e5a0c95a..9069f375b0 100644 --- a/src/AccountState.h +++ b/src/AccountState.h @@ -27,8 +27,8 @@ private: bool mValid; public: - AccountState(const NewcoinAddress& AccountID); // For new accounts - AccountState(SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger + AccountState(const NewcoinAddress& AccountID); // For new accounts + AccountState(const SerializedLedgerEntry::pointer& ledgerEntry); // For accounts in a ledger bool bHaveAuthorizedKey() { diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index d2189e693f..949cc7e851 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -257,7 +257,7 @@ void LedgerAcquire::trigger(const Peer::pointer& peer, bool timer) resetTimer(); } -void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL, Peer::pointer peer) +void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL, const Peer::pointer& peer) { if (!peer) sendRequest(tmGL); diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index 3ea334bd10..ff92ad4ef8 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -31,7 +31,7 @@ protected: virtual ~PeerSet() { ; } void sendRequest(const newcoin::TMGetLedger& message); - void sendRequest(const newcoin::TMGetLedger& message, Peer::pointer peer); + void sendRequest(const newcoin::TMGetLedger& message, const Peer::pointer& peer); public: const uint256& getHash() const { return mHash; } diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 2b45f3b8c4..52e4173c1c 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -83,7 +83,7 @@ void TransactionAcquire::trigger(const Peer::pointer& peer, bool timer) } bool TransactionAcquire::takeNodes(const std::list& nodeIDs, - const std::list< std::vector >& data, Peer::pointer peer) + const std::list< std::vector >& data, const Peer::pointer& peer) { if (mComplete) return true; @@ -191,7 +191,7 @@ bool LCTransaction::updatePosition(int percentTime, bool proposing) return true; } -LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime) +LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, const Ledger::pointer& previousLedger, uint32 closeTime) : mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger), mCurrentMSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false) { @@ -297,7 +297,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) propose(std::vector(), std::vector()); } -void LedgerConsensus::createDisputes(SHAMap::pointer m1, SHAMap::pointer m2) +void LedgerConsensus::createDisputes(const SHAMap::pointer& m1, const SHAMap::pointer& m2) { SHAMap::SHAMapDiff differences; m1->compare(m2, differences, 16384); @@ -317,7 +317,7 @@ void LedgerConsensus::createDisputes(SHAMap::pointer m1, SHAMap::pointer m2) } } -void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::pointer map, bool acquired) +void LedgerConsensus::mapComplete(const uint256& hash, const SHAMap::pointer& map, bool acquired) { if (acquired) Log(lsINFO) << "We have acquired TXS " << hash.GetHex(); @@ -370,7 +370,7 @@ void LedgerConsensus::sendHaveTxSet(const uint256& hash, bool direct) theApp->getConnectionPool().relayMessage(NULL, packet); } -void LedgerConsensus::adjustCount(SHAMap::pointer map, const std::vector& peers) +void LedgerConsensus::adjustCount(const SHAMap::pointer& map, const std::vector& peers) { // Adjust the counts on all disputed transactions based on the set of peers taking this position for (boost::unordered_map::iterator it = mDisputes.begin(), end = mDisputes.end(); it != end; ++it) @@ -645,7 +645,7 @@ SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool do return it->second; } -void LedgerConsensus::startAcquiring(TransactionAcquire::pointer acquire) +void LedgerConsensus::startAcquiring(const TransactionAcquire::pointer& acquire) { boost::unordered_map< uint256, std::vector< boost::weak_ptr > >::iterator it = mPeerData.find(acquire->getHash()); @@ -713,7 +713,7 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec } } -bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition) +bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) { LedgerProposal::pointer& currentPosition = mPeerPositions[newPosition->getPeerID()]; @@ -746,7 +746,7 @@ bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition) return true; } -bool LedgerConsensus::peerHasSet(Peer::pointer peer, const uint256& hashSet, newcoin::TxSetStatus status) +bool LedgerConsensus::peerHasSet(const Peer::pointer& peer, const uint256& hashSet, newcoin::TxSetStatus status) { if (status != newcoin::tsHAVE) // Indirect requests are for future support return true; @@ -763,7 +763,7 @@ bool LedgerConsensus::peerHasSet(Peer::pointer peer, const uint256& hashSet, new return true; } -bool LedgerConsensus::peerGaveNodes(Peer::pointer peer, const uint256& setHash, +bool LedgerConsensus::peerGaveNodes(const Peer::pointer& peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { boost::unordered_map::iterator acq = mAcquiring.find(setHash); @@ -791,8 +791,8 @@ void LedgerConsensus::Saccept(boost::shared_ptr This, SHAMap::p This->accept(txSet); } -void LedgerConsensus::applyTransaction(TransactionEngine& engine, SerializedTransaction::pointer txn, - Ledger::pointer ledger, CanonicalTXSet& failedTransactions, bool final) +void LedgerConsensus::applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn, + const Ledger::pointer& ledger, CanonicalTXSet& failedTransactions, bool final) { TransactionEngineParams parms = final ? (tepNO_CHECK_FEE | tepUPDATE_TOTAL | tepMETADATA) : tepNONE; #ifndef TRUST_NETWORK @@ -824,8 +824,8 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, SerializedTran #endif } -void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer applyLedger, Ledger::pointer checkLedger, - CanonicalTXSet& failedTransactions, bool final) +void LedgerConsensus::applyTransactions(const SHAMap::pointer& set, const Ledger::pointer& applyLedger, + const Ledger::pointer& checkLedger, CanonicalTXSet& failedTransactions, bool final) { TransactionEngineParams parms = final ? (tepNO_CHECK_FEE | tepUPDATE_TOTAL) : tepNONE; TransactionEngine engine(applyLedger); @@ -881,7 +881,7 @@ void LedgerConsensus::applyTransactions(SHAMap::pointer set, Ledger::pointer app } while (successes > 0); } -void LedgerConsensus::accept(SHAMap::pointer set) +void LedgerConsensus::accept(const SHAMap::pointer& set) { assert(set->getHash() == mOurPosition->getCurrentHash()); diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index cadfb23acd..e95ed6328a 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -41,7 +41,7 @@ public: SHAMap::pointer getMap() { return mMap; } bool takeNodes(const std::list& IDs, const std::list< std::vector >& data, - Peer::pointer); + const Peer::pointer&); }; class LCTransaction @@ -113,24 +113,24 @@ protected: // final accept logic static void Saccept(boost::shared_ptr This, SHAMap::pointer txSet); - void accept(SHAMap::pointer txSet); + void accept(const SHAMap::pointer& txSet); - void weHave(const uint256& id, Peer::pointer avoidPeer); - void startAcquiring(TransactionAcquire::pointer); + void weHave(const uint256& id, const Peer::pointer& avoidPeer); + void startAcquiring(const TransactionAcquire::pointer&); SHAMap::pointer find(const uint256& hash); - void createDisputes(SHAMap::pointer, SHAMap::pointer); + void createDisputes(const SHAMap::pointer&, const SHAMap::pointer&); void addDisputedTransaction(const uint256&, const std::vector& transaction); - void adjustCount(SHAMap::pointer map, const std::vector& peers); + void adjustCount(const SHAMap::pointer& map, const std::vector& peers); void propose(const std::vector& addedTx, const std::vector& removedTx); void addPosition(LedgerProposal&, bool ours); void removePosition(LedgerProposal&, bool ours); void sendHaveTxSet(const uint256& set, bool direct); - void applyTransactions(SHAMap::pointer transactionSet, Ledger::pointer targetLedger, Ledger::pointer checkLedger, - CanonicalTXSet& failedTransactions, bool final); - void applyTransaction(TransactionEngine& engine, SerializedTransaction::pointer txn, Ledger::pointer targetLedger, - CanonicalTXSet& failedTransactions, bool final); + void applyTransactions(const SHAMap::pointer& transactionSet, const Ledger::pointer& targetLedger, + const Ledger::pointer& checkLedger, CanonicalTXSet& failedTransactions, bool final); + void applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn, + const Ledger::pointer& targetLedger, CanonicalTXSet& failedTransactions, bool final); // manipulating our own position void statusChange(newcoin::NodeEvent, Ledger& ledger); @@ -141,7 +141,7 @@ protected: void endConsensus(); public: - LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime); + LedgerConsensus(const uint256& prevLCLHash, const Ledger::pointer& previousLedger, uint32 closeTime); int startup(); Json::Value getJson(); @@ -151,7 +151,7 @@ public: SHAMap::pointer getTransactionTree(const uint256& hash, bool doAcquire); TransactionAcquire::pointer getAcquiring(const uint256& hash); - void mapComplete(const uint256& hash, SHAMap::pointer map, bool acquired); + void mapComplete(const uint256& hash, const SHAMap::pointer& map, bool acquired); void checkLCL(); void timerEntry(); @@ -165,11 +165,11 @@ public: bool haveConsensus(); - bool peerPosition(LedgerProposal::pointer); + bool peerPosition(const LedgerProposal::pointer&); - bool peerHasSet(Peer::pointer peer, const uint256& set, newcoin::TxSetStatus status); + bool peerHasSet(const Peer::pointer& peer, const uint256& set, newcoin::TxSetStatus status); - bool peerGaveNodes(Peer::pointer peer, const uint256& setHash, + bool peerGaveNodes(const Peer::pointer& peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); }; diff --git a/src/LedgerHistory.cpp b/src/LedgerHistory.cpp index 0445b268d5..6dd3a9c4a3 100644 --- a/src/LedgerHistory.cpp +++ b/src/LedgerHistory.cpp @@ -90,7 +90,8 @@ Ledger::pointer LedgerHistory::canonicalizeLedger(Ledger::pointer ledger, bool s if (!save) { // return input ledger if not in map, otherwise, return corresponding map ledger Ledger::pointer ret = mLedgersByHash.fetch(h); - if (ret) return ret; + if (ret) + return ret; return ledger; } diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp index 7350b85349..e7b571f361 100644 --- a/src/LedgerMaster.cpp +++ b/src/LedgerMaster.cpp @@ -13,13 +13,13 @@ uint32 LedgerMaster::getCurrentLedgerIndex() return mCurrentLedger->getLedgerSeq(); } -bool LedgerMaster::addHeldTransaction(Transaction::pointer transaction) +bool LedgerMaster::addHeldTransaction(const Transaction::pointer& transaction) { // returns true if transaction was added boost::recursive_mutex::scoped_lock ml(mLock); return mHeldTransactionsByID.insert(std::make_pair(transaction->getID(), transaction)).second; } -void LedgerMaster::pushLedger(Ledger::pointer newLedger) +void LedgerMaster::pushLedger(const Ledger::pointer& newLedger) { // Caller should already have properly assembled this ledger into "ready-to-close" form -- // all candidate transactions must already be appled @@ -35,7 +35,7 @@ void LedgerMaster::pushLedger(Ledger::pointer newLedger) mEngine.setLedger(newLedger); } -void LedgerMaster::pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL) +void LedgerMaster::pushLedger(const Ledger::pointer& newLCL, const Ledger::pointer& newOL) { assert(newLCL->isClosed() && newLCL->isAccepted()); assert(!newOL->isClosed() && !newOL->isAccepted()); @@ -54,7 +54,7 @@ void LedgerMaster::pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL) mEngine.setLedger(newOL); } -void LedgerMaster::switchLedgers(Ledger::pointer lastClosed, Ledger::pointer current) +void LedgerMaster::switchLedgers(const Ledger::pointer& lastClosed, const Ledger::pointer& current) { assert(lastClosed && current); mFinalizedLedger = lastClosed; @@ -66,7 +66,7 @@ void LedgerMaster::switchLedgers(Ledger::pointer lastClosed, Ledger::pointer cur mEngine.setLedger(mCurrentLedger); } -void LedgerMaster::storeLedger(Ledger::pointer ledger) +void LedgerMaster::storeLedger(const Ledger::pointer& ledger) { mLedgerHistory.addLedger(ledger); } diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h index 187aaeec13..dd51333283 100644 --- a/src/LedgerMaster.h +++ b/src/LedgerMaster.h @@ -26,8 +26,8 @@ class LedgerMaster std::map mHeldTransactionsByID; void applyFutureTransactions(uint32 ledgerIndex); - bool isValidTransaction(Transaction::pointer trans); - bool isTransactionOnFutureList(Transaction::pointer trans); + bool isValidTransaction(const Transaction::pointer& trans); + bool isTransactionOnFutureList(const Transaction::pointer& trans); public: @@ -48,11 +48,11 @@ public: TransactionEngineResult doTransaction(const SerializedTransaction& txn, uint32 targetLedger, TransactionEngineParams params); - void pushLedger(Ledger::pointer newLedger); - void pushLedger(Ledger::pointer newLCL, Ledger::pointer newOL); - void storeLedger(Ledger::pointer); + void pushLedger(const Ledger::pointer& newLedger); + void pushLedger(const Ledger::pointer& newLCL, const Ledger::pointer& newOL); + void storeLedger(const Ledger::pointer&); - void switchLedgers(Ledger::pointer lastClosed, Ledger::pointer newCurrent); + void switchLedgers(const Ledger::pointer& lastClosed, const Ledger::pointer& newCurrent); Ledger::pointer closeLedger(); @@ -74,7 +74,7 @@ public: return mLedgerHistory.getLedgerByHash(hash); } - bool addHeldTransaction(Transaction::pointer trans); + bool addHeldTransaction(const Transaction::pointer& trans); }; #endif diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index a0e7811425..4d3fd7aee2 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -52,7 +52,7 @@ uint32 NetworkOPs::getCurrentLedgerID() } // Sterilize transaction through serialization. -Transaction::pointer NetworkOPs::submitTransaction(Transaction::pointer tpTrans) +Transaction::pointer NetworkOPs::submitTransaction(const Transaction::pointer& tpTrans) { Serializer s; diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 52e1329f8d..79dc6ae138 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -108,7 +108,7 @@ public: // // Transaction operations // - Transaction::pointer submitTransaction(Transaction::pointer tpTrans); + Transaction::pointer submitTransaction(const Transaction::pointer& tpTrans); Transaction::pointer processTransaction(Transaction::pointer transaction, uint32 targetLedger = 0, Peer* source = NULL); From c036188c3cb8fe3cc318d4e4258d056512fd2a1d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 19 Aug 2012 21:01:36 -0700 Subject: [PATCH 082/426] Some more cleanups. --- src/Ledger.h | 6 ------ src/NetworkOPs.cpp | 8 ++++---- src/NetworkOPs.h | 8 ++++---- src/PubKeyCache.cpp | 12 ++++++------ src/PubKeyCache.h | 2 +- src/TransactionEngine.h | 4 ++-- 6 files changed, 17 insertions(+), 23 deletions(-) diff --git a/src/Ledger.h b/src/Ledger.h index 7f60fcbc8f..53b7980794 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -281,12 +281,6 @@ public: SLE::pointer getRippleState(const uint160& uiA, const uint160& uiB, const uint160& uCurrency) { return getRippleState(getRippleStateIndex(NewcoinAddress::createAccountID(uiA), NewcoinAddress::createAccountID(uiB), uCurrency)); } - // - // Misc - // - bool isCompatible(boost::shared_ptr other); -// bool signLedger(std::vector &signature, const LocalHanko &hanko); - void addJson(Json::Value&, int options); static bool unitTest(); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 4d3fd7aee2..75b12a813b 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -650,7 +650,7 @@ SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash) return mConsensus->getTransactionTree(hash, false); } -bool NetworkOPs::gotTXData(boost::shared_ptr peer, const uint256& hash, +bool NetworkOPs::gotTXData(const boost::shared_ptr& peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { if (!mConsensus) @@ -658,14 +658,14 @@ bool NetworkOPs::gotTXData(boost::shared_ptr peer, const uint256& hash, return mConsensus->peerGaveNodes(peer, hash, nodeIDs, nodeData); } -bool NetworkOPs::hasTXSet(boost::shared_ptr peer, const uint256& set, newcoin::TxSetStatus status) +bool NetworkOPs::hasTXSet(const boost::shared_ptr& peer, const uint256& set, newcoin::TxSetStatus status) { if (!mConsensus) return false; return mConsensus->peerHasSet(peer, set, status); } -void NetworkOPs::mapComplete(const uint256& hash, SHAMap::pointer map) +void NetworkOPs::mapComplete(const uint256& hash, const SHAMap::pointer& map) { if (mConsensus) mConsensus->mapComplete(hash, map, true); @@ -746,7 +746,7 @@ std::vector return accounts; } -bool NetworkOPs::recvValidation(SerializedValidation::pointer val) +bool NetworkOPs::recvValidation(const SerializedValidation::pointer& val) { Log(lsINFO) << "recvValidation " << val->getLedgerHash().GetHex(); return theApp->getValidations().addValidation(val); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 79dc6ae138..91ac722a05 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -161,12 +161,12 @@ public: // ledger proposal/close functions bool recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint32 closeTime, const std::string& pubKey, const std::string& signature); - bool gotTXData(boost::shared_ptr peer, const uint256& hash, + bool gotTXData(const boost::shared_ptr& peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); - bool recvValidation(SerializedValidation::pointer val); + bool recvValidation(const SerializedValidation::pointer& val); SHAMap::pointer getTXMap(const uint256& hash); - bool hasTXSet(boost::shared_ptr peer, const uint256& set, newcoin::TxSetStatus status); - void mapComplete(const uint256& hash, SHAMap::pointer map); + bool hasTXSet(const boost::shared_ptr& peer, const uint256& set, newcoin::TxSetStatus status); + void mapComplete(const uint256& hash, const SHAMap::pointer& map); // network state machine void checkState(const boost::system::error_code& result); diff --git a/src/PubKeyCache.cpp b/src/PubKeyCache.cpp index f6a4096d38..503fefc3d1 100644 --- a/src/PubKeyCache.cpp +++ b/src/PubKeyCache.cpp @@ -42,7 +42,7 @@ CKey::pointer PubKeyCache::locate(const NewcoinAddress& id) return ckp; } -CKey::pointer PubKeyCache::store(const NewcoinAddress& id, CKey::pointer key) +CKey::pointer PubKeyCache::store(const NewcoinAddress& id, const CKey::pointer& key) { // stored if needed, returns cached copy (possibly the original) { boost::mutex::scoped_lock sl(mLock); @@ -51,14 +51,14 @@ CKey::pointer PubKeyCache::store(const NewcoinAddress& id, CKey::pointer key) return pit.first->second; } - std::vector pk=key->GetPubKey(); + std::vector pk = key->GetPubKey(); std::string encodedPK; theApp->getTxnDB()->getDB()->escape(&(pk.front()), pk.size(), encodedPK); - std::string sql="INSERT INTO PubKeys (ID,PubKey) VALUES ('"; - sql+=id.humanAccountID(); - sql+="',"; - sql+=encodedPK; + std::string sql = "INSERT INTO PubKeys (ID,PubKey) VALUES ('"; + sql += id.humanAccountID(); + sql += "',"; + sql += encodedPK; sql.append(");"); ScopedLock dbl(theApp->getTxnDB()->getDBLock()); diff --git a/src/PubKeyCache.h b/src/PubKeyCache.h index bf6995875c..69c19b2be6 100644 --- a/src/PubKeyCache.h +++ b/src/PubKeyCache.h @@ -18,7 +18,7 @@ public: PubKeyCache() { ; } CKey::pointer locate(const NewcoinAddress& id); - CKey::pointer store(const NewcoinAddress& id, CKey::pointer key); + CKey::pointer store(const NewcoinAddress& id, const CKey::pointer& key); void clear(); }; diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 5df286d743..1960bde680 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -268,10 +268,10 @@ protected: public: TransactionEngine() { ; } - TransactionEngine(Ledger::pointer ledger) : mLedger(ledger) { ; } + TransactionEngine(const Ledger::pointer& ledger) : mLedger(ledger) { ; } Ledger::pointer getLedger() { return mLedger; } - void setLedger(Ledger::pointer ledger) { assert(ledger); mLedger = ledger; } + void setLedger(const Ledger::pointer& ledger) { assert(ledger); mLedger = ledger; } TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams); }; From 7e30db94b4a9e37d5910938aeca9245d86edad2b Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 19 Aug 2012 21:36:25 -0700 Subject: [PATCH 083/426] Work on ripple paths. --- src/SerializedTypes.cpp | 13 ++++++++++--- src/TransactionEngine.cpp | 27 ++++++++++++++++++--------- src/TransactionEngine.h | 6 +++++- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index cd759e1ee2..6e50c61fdb 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -5,6 +5,7 @@ #include "SerializedTypes.h" #include "SerializedObject.h" #include "TransactionFormats.h" +#include "Log.h" #include "NewcoinAddress.h" #include "utils.h" @@ -308,7 +309,11 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) if (iType == STPathElement::typeEnd || iType == STPathElement::typeBoundary) { if (path.empty()) + { + Log(lsINFO) << "STPathSet: Empty path."; + throw std::runtime_error("empty path"); + } paths.push_back(path); path.clear(); @@ -320,13 +325,15 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) } else if (iType & ~STPathElement::typeValidBits) { + Log(lsINFO) << "STPathSet: Bad path element: " << iType; + throw std::runtime_error("bad path element"); } else { - bool bAccount = !!(iType & STPathElement::typeAccount); - bool bCurrency = !!(iType & STPathElement::typeCurrency); - bool bIssuer = !!(iType & STPathElement::typeIssuer); + const bool bAccount = !!(iType & STPathElement::typeAccount); + const bool bCurrency = !!(iType & STPathElement::typeCurrency); + const bool bIssuer = !!(iType & STPathElement::typeIssuer); uint160 uAccountID; uint160 uCurrency; diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index af7f9a53a2..c322b289de 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1969,14 +1969,14 @@ bool TransactionEngine::calcNodeOfferRev( if (!saCurOfrFunds) { // Offer is unfunded. - Log(lsINFO) << "calcNodeOffer: encountered unfunded offer"; + Log(lsINFO) << "calcNodeOfferRev: encountered unfunded offer"; // XXX Mark unfunded. } else if (sleCurOfr->getIFieldPresent(sfExpiration) && sleCurOfr->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) { // Offer is expired. - Log(lsINFO) << "calcNodeOffer: encountered expired offer"; + Log(lsINFO) << "calcNodeOfferRev: encountered expired offer"; // XXX Mark unfunded. } @@ -3774,8 +3774,10 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction if (!bNoRippleDirect) { // Direct path. + // XXX Might also make a stamp bridge by default. Log(lsINFO) << "doPayment: Build direct:"; - vpsPaths.push_back(PathState::createPathState( + + PathState::pointer pspDirect = PathState::createPathState( mLedger, vpsPaths.size(), mNodes, @@ -3784,14 +3786,19 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction mTxnAccountID, saDstAmount, saMaxAmount, - bPartialPayment - )); + bPartialPayment); + + if (pspDirect) + vpsPaths.push_back(pspDirect); } + Log(lsINFO) << "doPayment: Paths: " << spsPaths.getPathCount(); + BOOST_FOREACH(const STPath& spPath, spsPaths) { Log(lsINFO) << "doPayment: Build path:"; - vpsPaths.push_back(PathState::createPathState( + + PathState::pointer pspExpanded = PathState::createPathState( mLedger, vpsPaths.size(), mNodes, @@ -3800,8 +3807,10 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction mTxnAccountID, saDstAmount, saMaxAmount, - bPartialPayment - )); + bPartialPayment); + + if (pspExpanded) + vpsPaths.push_back(pspExpanded); } TransactionEngineResult terResult; @@ -3885,7 +3894,7 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti if (!naMasterPubKey.accountPublicVerify(Serializer::getSHA512Half(uAuthKeyID.begin(), uAuthKeyID.size()), vucSignature)) { - std::cerr << "WalletAdd: unauthorized: bad signature " << std::endl; + std::cerr << "WalletAdd: unauthorized: bad signature " << std::endl; return tenBAD_ADD_AUTH; } diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 5df286d743..ecc1a4a722 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -169,7 +169,11 @@ public: STAmount saSendMax, bool bPartialPayment ) - { return boost::make_shared(lpLedger, iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax, bPartialPayment); }; + { + PathState::pointer pspNew = boost::make_shared(lpLedger, iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax, bPartialPayment); + + return pspNew && pspNew->bValid ? pspNew : PathState::pointer(); + } static bool lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs); }; From a251a1ae4e2d1ecfeecb016c125dece497e2e78d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 19 Aug 2012 22:20:58 -0700 Subject: [PATCH 084/426] Fix STPathSet deserialization. --- src/SerializedTypes.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 6e50c61fdb..2a6b0f978e 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -332,6 +332,8 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) else { const bool bAccount = !!(iType & STPathElement::typeAccount); + const bool bRedeem = !!(iType & STPathElement::typeRedeem); + const bool bIssue = !!(iType & STPathElement::typeIssue); const bool bCurrency = !!(iType & STPathElement::typeCurrency); const bool bIssuer = !!(iType & STPathElement::typeIssuer); @@ -348,7 +350,7 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) if (bIssuer) uIssuerID = s.get160(); - path.push_back(STPathElement(uAccountID, uCurrency, uIssuerID)); + path.push_back(STPathElement(uAccountID, uCurrency, uIssuerID, bRedeem, bIssue)); } } while(1); } @@ -361,6 +363,8 @@ bool STPathSet::isEquivalent(const SerializedType& t) const int STPathSet::getLength() const { + // XXX This code is broken? + assert(false); int ret = 0; for (std::vector::const_iterator it = value.begin(), end = value.end(); it != end; ++it) From 6f5eb015bfe6a165ea2609e3d1f0002827f2362d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 19 Aug 2012 22:41:30 -0700 Subject: [PATCH 085/426] Fix the bug causing 'Paths' not to have a name. The implicit 'operator=' function obliterated the name. --- src/SerializedTypes.cpp | 8 ++++++++ src/SerializedTypes.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 2a6b0f978e..da96fa5373 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -463,6 +463,14 @@ std::string STPathSet::getText() const } #endif +STPathSet& STPathSet::operator=(const STPathSet& p) +{ + if (name == NULL) + name = p.name; + value = p.value; + return *this; +} + void STPathSet::add(Serializer& s) const { bool bFirst = true; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 1ba0793ad3..7b7aa562b9 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -668,6 +668,7 @@ public: void addPath(const STPath& e) { value.push_back(e); } virtual bool isEquivalent(const SerializedType& t) const; + STPathSet& operator=(const STPathSet&); std::vector::iterator begin() { return value.begin(); } std::vector::iterator end() { return value.end(); } From aa1f923306ef7699c474691d76bf5e5e22109a94 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 19 Aug 2012 22:47:59 -0700 Subject: [PATCH 086/426] A better fix so that every type doesn't have to have its own operator=. This fixes it in one place and allows many such helpers to be removed. --- src/Amount.cpp | 12 ------------ src/SerializedTypes.cpp | 8 -------- src/SerializedTypes.h | 13 ++----------- 3 files changed, 2 insertions(+), 31 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index e6616a9c35..966eea15b6 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -491,18 +491,6 @@ STAmount STAmount::operator-(void) const return STAmount(name, mCurrency, mValue, mOffset, mIsNative, !mIsNegative); } -STAmount& STAmount::operator=(const STAmount& a) -{ - mValue = a.mValue; - mOffset = a.mOffset; - mIssuer = a.mIssuer; - mCurrency = a.mCurrency; - mIsNative = a.mIsNative; - mIsNegative = a.mIsNegative; - - return *this; -} - STAmount& STAmount::operator=(uint64 v) { // does not copy name, does not change currency type mOffset = 0; diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index da96fa5373..2a6b0f978e 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -463,14 +463,6 @@ std::string STPathSet::getText() const } #endif -STPathSet& STPathSet::operator=(const STPathSet& p) -{ - if (name == NULL) - name = p.name; - value = p.value; - return *this; -} - void STPathSet::add(Serializer& s) const { bool bFirst = true; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 7b7aa562b9..2c877b8bd1 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -91,6 +91,8 @@ public: virtual bool isEquivalent(const SerializedType& t) const { assert(getSType() == STI_NOTPRESENT); return t.getSType() == STI_NOTPRESENT; } + SerializedType& operator=(const SerializedType& t) + { name = (name == NULL) ? t.name : name; return *this; } bool operator==(const SerializedType& t) const { return (getSType() == t.getSType()) && isEquivalent(t); } bool operator!=(const SerializedType& t) const @@ -124,7 +126,6 @@ public: void setValue(unsigned char v) { value=v; } operator unsigned char() const { return value; } - STUInt8& operator=(unsigned char v) { value=v; return *this; } virtual bool isEquivalent(const SerializedType& t) const; }; @@ -152,7 +153,6 @@ public: void setValue(uint16 v) { value=v; } operator uint16() const { return value; } - STUInt16& operator=(uint16 v) { value=v; return *this; } virtual bool isEquivalent(const SerializedType& t) const; }; @@ -180,7 +180,6 @@ public: void setValue(uint32 v) { value=v; } operator uint32() const { return value; } - STUInt32& operator=(uint32 v) { value=v; return *this; } virtual bool isEquivalent(const SerializedType& t) const; }; @@ -208,7 +207,6 @@ public: void setValue(uint64 v) { value=v; } operator uint64() const { return value; } - STUInt64& operator=(uint64 v) { value=v; return *this; } virtual bool isEquivalent(const SerializedType& t) const; }; @@ -334,7 +332,6 @@ public: STAmount& operator+=(const STAmount&); STAmount& operator-=(const STAmount&); - STAmount& operator=(const STAmount&); STAmount& operator+=(uint64); STAmount& operator-=(uint64); STAmount& operator=(uint64); @@ -401,7 +398,6 @@ public: void setValue(const uint128& v) { value=v; } operator uint128() const { return value; } - STHash128& operator=(const uint128& v) { value=v; return *this; } virtual bool isEquivalent(const SerializedType& t) const; }; @@ -431,7 +427,6 @@ public: void setValue(const uint160& v) { value=v; } operator uint160() const { return value; } - STHash160& operator=(const uint160& v) { value=v; return *this; } virtual bool isEquivalent(const SerializedType& t) const; }; @@ -461,7 +456,6 @@ public: void setValue(const uint256& v) { value=v; } operator uint256() const { return value; } - STHash256& operator=(const uint256& v) { value=v; return *this; } virtual bool isEquivalent(const SerializedType& t) const; }; @@ -494,7 +488,6 @@ public: void setValue(const std::vector& v) { value=v; } operator std::vector() const { return value; } - STVariableLength& operator=(const std::vector& v) { value=v; return *this; } virtual bool isEquivalent(const SerializedType& t) const; }; @@ -668,7 +661,6 @@ public: void addPath(const STPath& e) { value.push_back(e); } virtual bool isEquivalent(const SerializedType& t) const; - STPathSet& operator=(const STPathSet&); std::vector::iterator begin() { return value.begin(); } std::vector::iterator end() { return value.end(); } @@ -747,7 +739,6 @@ public: void addItem(const TaggedListItem& v) { value.push_back(v); } operator std::vector() const { return value; } - STTaggedList& operator=(const std::vector& v) { value=v; return *this; } virtual bool isEquivalent(const SerializedType& t) const; }; From 532db8be357c881b3627dec36a9d39bd60cc007b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 19 Aug 2012 22:52:14 -0700 Subject: [PATCH 087/426] assert if the sanitized transaction differs materially from the submitted transaction. --- src/NetworkOPs.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 75b12a813b..adc8a3c7b9 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -65,6 +65,7 @@ Transaction::pointer NetworkOPs::submitTransaction(const Transaction::pointer& t Transaction::pointer tpTransNew = Transaction::sharedTransaction(s.getData(), true); assert(tpTransNew); + assert(tpTransNew->getSTransaction()->isEquivalent(*tpTrans->getSTransaction())); (void) NetworkOPs::processTransaction(tpTransNew); From 3dc0646ed8711547415f4cccd4564f5ebc1f4713 Mon Sep 17 00:00:00 2001 From: jed Date: Mon, 20 Aug 2012 09:51:10 -0700 Subject: [PATCH 088/426] moved all Ledger:: functions to the same .cpp file --- newcoin.vcxproj | 2 - newcoin.vcxproj.filters | 6 -- src/Ledger.cpp | 4 +- src/LedgerIndex.cpp | 144 ----------------------------- src/LedgerNode.cpp | 200 ---------------------------------------- src/RippleState.h | 4 +- 6 files changed, 4 insertions(+), 356 deletions(-) delete mode 100644 src/LedgerIndex.cpp delete mode 100644 src/LedgerNode.cpp diff --git a/newcoin.vcxproj b/newcoin.vcxproj index 2beb907c7c..0e7dfbd8fa 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -114,9 +114,7 @@ - - diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index d18959032e..ae7712d308 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -93,15 +93,9 @@ Source Files - - Source Files - Source Files - - Source Files - Source Files diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 64bc767cbb..99ce3986de 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -505,8 +505,7 @@ void Ledger::setCloseTime(boost::posix_time::ptime ptm) } // XXX Use shared locks where possible? - -LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::pointer entry) +LedgerStateParms Ledger::writeBack(LedgerStateParms parms, const SLE::pointer& entry) { ScopedLock l(mAccountStateMap->Lock()); bool create = false; @@ -696,4 +695,5 @@ SLE::pointer Ledger::getRippleState(LedgerStateParms& parms, const uint256& uNod } + // vim:ts=4 diff --git a/src/LedgerIndex.cpp b/src/LedgerIndex.cpp deleted file mode 100644 index b519a9e0e8..0000000000 --- a/src/LedgerIndex.cpp +++ /dev/null @@ -1,144 +0,0 @@ - -#include "Ledger.h" - -// For an entry put in the 64 bit index or quality. -uint256 Ledger::getQualityIndex(const uint256& uBase, const uint64 uNodeDir) -{ - // Indexes are stored in big endian format: they print as hex as stored. - // Most significant bytes are first. Least significant bytes represent adjacent entries. - // We place uNodeDir in the 8 right most bytes to be adjacent. - // Want uNodeDir in big endian format so ++ goes to the next entry for indexes. - uint256 uNode(uBase); - - ((uint64*) uNode.end())[-1] = htobe64(uNodeDir); - - return uNode; -} - -// Return the last 64 bits. -uint64 Ledger::getQuality(const uint256& uBase) -{ - return be64toh(((uint64*) uBase.end())[-1]); -} - -uint256 Ledger::getQualityNext(const uint256& uBase) -{ - static uint256 uNext("10000000000000000"); - - uint256 uResult = uBase; - - uResult += uNext; - - return uResult; -} - -uint256 Ledger::getAccountRootIndex(const uint160& uAccountID) -{ - Serializer s(22); - - s.add16(spaceAccount); // 2 - s.add160(uAccountID); // 20 - - return s.getSHA512Half(); -} - -uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID, - const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID) -{ - bool bInNative = uTakerPaysCurrency.isZero(); - bool bOutNative = uTakerGetsCurrency.isZero(); - - assert(!bInNative || !bOutNative); // Stamps to stamps not allowed. - assert(bInNative == uTakerPaysIssuerID.isZero()); // Make sure issuer is specified as needed. - assert(bOutNative == uTakerGetsIssuerID.isZero()); // Make sure issuer is specified as needed. - assert(uTakerPaysCurrency != uTakerGetsCurrency || uTakerPaysIssuerID != uTakerGetsIssuerID); // Currencies or accounts must differ. - - Serializer s(82); - - s.add16(spaceBookDir); // 2 - s.add160(uTakerPaysCurrency); // 20 - s.add160(uTakerGetsCurrency); // 20 - s.add160(uTakerPaysIssuerID); // 20 - s.add160(uTakerGetsIssuerID); // 20 - - return getQualityIndex(s.getSHA512Half()); // Return with quality 0. -} - -uint256 Ledger::getDirNodeIndex(const uint256& uDirRoot, const uint64 uNodeIndex) -{ - if (uNodeIndex) - { - Serializer s(42); - - s.add16(spaceDirNode); // 2 - s.add256(uDirRoot); // 32 - s.add64(uNodeIndex); // 8 - - return s.getSHA512Half(); - } - else - { - return uDirRoot; - } -} - -uint256 Ledger::getGeneratorIndex(const uint160& uGeneratorID) -{ - Serializer s(22); - - s.add16(spaceGenerator); // 2 - s.add160(uGeneratorID); // 20 - - return s.getSHA512Half(); -} - -// What is important: -// --> uNickname: is a Sha256 -// <-- SHA512/2: for consistency and speed in generating indexes. -uint256 Ledger::getNicknameIndex(const uint256& uNickname) -{ - Serializer s(34); - - s.add16(spaceNickname); // 2 - s.add256(uNickname); // 32 - - return s.getSHA512Half(); -} - -uint256 Ledger::getOfferIndex(const uint160& uAccountID, uint32 uSequence) -{ - Serializer s(26); - - s.add16(spaceOffer); // 2 - s.add160(uAccountID); // 20 - s.add32(uSequence); // 4 - - return s.getSHA512Half(); -} - -uint256 Ledger::getOwnerDirIndex(const uint160& uAccountID) -{ - Serializer s(22); - - s.add16(spaceOwnerDir); // 2 - s.add160(uAccountID); // 20 - - return s.getSHA512Half(); -} - -uint256 Ledger::getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency) -{ - uint160 uAID = naA.getAccountID(); - uint160 uBID = naB.getAccountID(); - bool bAltB = uAID < uBID; - Serializer s(62); - - s.add16(spaceRipple); // 2 - s.add160(bAltB ? uAID : uBID); // 20 - s.add160(bAltB ? uBID : uAID); // 20 - s.add160(uCurrency); // 20 - - return s.getSHA512Half(); -} - -// vim:ts=4 diff --git a/src/LedgerNode.cpp b/src/LedgerNode.cpp deleted file mode 100644 index 24bfc58d77..0000000000 --- a/src/LedgerNode.cpp +++ /dev/null @@ -1,200 +0,0 @@ - -#include "Ledger.h" - -#include - -#include "utils.h" -#include "Log.h" - -// XXX Use shared locks where possible? - -LedgerStateParms Ledger::writeBack(LedgerStateParms parms, const SLE::pointer& entry) -{ - ScopedLock l(mAccountStateMap->Lock()); - bool create = false; - - if (!mAccountStateMap->hasItem(entry->getIndex())) - { - if ((parms & lepCREATE) == 0) - { - Log(lsERROR) << "WriteBack non-existent node without create"; - return lepMISSING; - } - create = true; - } - - SHAMapItem::pointer item = boost::make_shared(entry->getIndex()); - entry->add(item->peekSerializer()); - - if (create) - { - assert(!mAccountStateMap->hasItem(entry->getIndex())); - if(!mAccountStateMap->addGiveItem(item, false, false)) // FIXME: TX metadata - { - assert(false); - return lepERROR; - } - return lepCREATED; - } - - if (!mAccountStateMap->updateGiveItem(item, false, false)) // FIXME: TX metadata - { - assert(false); - return lepERROR; - } - return lepOKAY; -} - -SLE::pointer Ledger::getSLE(const uint256& uHash) -{ - SHAMapItem::pointer node = mAccountStateMap->peekItem(uHash); - if (!node) - return SLE::pointer(); - return boost::make_shared(node->peekSerializer(), node->getTag()); -} - -uint256 Ledger::getFirstLedgerIndex() -{ - SHAMapItem::pointer node = mAccountStateMap->peekFirstItem(); - return node ? node->getTag() : uint256(); -} - -uint256 Ledger::getLastLedgerIndex() -{ - SHAMapItem::pointer node = mAccountStateMap->peekLastItem(); - return node ? node->getTag() : uint256(); -} - -uint256 Ledger::getNextLedgerIndex(const uint256& uHash) -{ - SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash); - return node ? node->getTag() : uint256(); -} - -uint256 Ledger::getNextLedgerIndex(const uint256& uHash, const uint256& uEnd) -{ - SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash); - if ((!node) || (node->getTag() > uEnd)) - return uint256(); - return node->getTag(); -} - -uint256 Ledger::getPrevLedgerIndex(const uint256& uHash) -{ - SHAMapItem::pointer node = mAccountStateMap->peekPrevItem(uHash); - return node ? node->getTag() : uint256(); -} - -uint256 Ledger::getPrevLedgerIndex(const uint256& uHash, const uint256& uBegin) -{ - SHAMapItem::pointer node = mAccountStateMap->peekNextItem(uHash); - if ((!node) || (node->getTag() < uBegin)) - return uint256(); - return node->getTag(); -} - -SLE::pointer Ledger::getASNode(LedgerStateParms& parms, const uint256& nodeID, - LedgerEntryType let ) -{ - SHAMapItem::pointer account = mAccountStateMap->peekItem(nodeID); - - if (!account) - { - if ( (parms & lepCREATE) == 0 ) - { - parms = lepMISSING; - return SLE::pointer(); - } - - parms = parms | lepCREATED | lepOKAY; - SLE::pointer sle=boost::make_shared(let); - sle->setIndex(nodeID); - - return sle; - } - - SLE::pointer sle = - boost::make_shared(account->peekSerializer(), nodeID); - - if (sle->getType() != let) - { // maybe it's a currency or something - parms = parms | lepWRONGTYPE; - return SLE::pointer(); - } - - parms = parms | lepOKAY; - - return sle; -} - -SLE::pointer Ledger::getAccountRoot(const uint160& accountID) -{ - LedgerStateParms qry = lepNONE; - - return getASNode(qry, getAccountRootIndex(accountID), ltACCOUNT_ROOT); -} - -SLE::pointer Ledger::getAccountRoot(const NewcoinAddress& naAccountID) -{ - LedgerStateParms qry = lepNONE; - - return getASNode(qry, getAccountRootIndex(naAccountID.getAccountID()), ltACCOUNT_ROOT); -} - -// -// Directory -// - -SLE::pointer Ledger::getDirNode(LedgerStateParms& parms, const uint256& uNodeIndex) -{ - ScopedLock l(mAccountStateMap->Lock()); - - return getASNode(parms, uNodeIndex, ltDIR_NODE); -} - -// -// Generator Map -// - -SLE::pointer Ledger::getGenerator(LedgerStateParms& parms, const uint160& uGeneratorID) -{ - ScopedLock l(mAccountStateMap->Lock()); - - return getASNode(parms, getGeneratorIndex(uGeneratorID), ltGENERATOR_MAP); -} - -// -// Nickname -// - -SLE::pointer Ledger::getNickname(LedgerStateParms& parms, const uint256& uNickname) -{ - ScopedLock l(mAccountStateMap->Lock()); - - return getASNode(parms, uNickname, ltNICKNAME); -} - -// -// Offer -// - - -SLE::pointer Ledger::getOffer(LedgerStateParms& parms, const uint256& uIndex) -{ - ScopedLock l(mAccountStateMap->Lock()); - - return getASNode(parms, uIndex, ltOFFER); -} - -// -// Ripple State -// - -SLE::pointer Ledger::getRippleState(LedgerStateParms& parms, const uint256& uNode) -{ - ScopedLock l(mAccountStateMap->Lock()); - - return getASNode(parms, uNode, ltRIPPLE_STATE); -} - -// vim:ts=4 diff --git a/src/RippleState.h b/src/RippleState.h index c83e6b364d..f17daf31ca 100644 --- a/src/RippleState.h +++ b/src/RippleState.h @@ -47,8 +47,8 @@ public: STAmount getLimit() const { return mViewLowest ? mLowLimit : mHighLimit; } STAmount getLimitPeer() const { return mViewLowest ? mHighLimit : mLowLimit; } - uint32 getQualityIn() const { return mViewLowest ? mLowQualityIn : mHighQualityIn; } - uint32 getQualityOut() const { return mViewLowest ? mLowQualityOut : mHighQualityOut; } + uint32 getQualityIn() const { return((uint32) (mViewLowest ? mLowQualityIn : mHighQualityIn)); } + uint32 getQualityOut() const { return((uint32) (mViewLowest ? mLowQualityOut : mHighQualityOut)); } SerializedLedgerEntry::pointer getSLE() { return mLedgerEntry; } const SerializedLedgerEntry& peekSLE() const { return *mLedgerEntry; } From 1c5481bad7b168b142a1d89fc9b19412a9db8ed5 Mon Sep 17 00:00:00 2001 From: jed Date: Mon, 20 Aug 2012 11:53:43 -0700 Subject: [PATCH 089/426] forgot some functions --- src/Ledger.cpp | 140 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 99ce3986de..739947d933 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -694,6 +694,146 @@ SLE::pointer Ledger::getRippleState(LedgerStateParms& parms, const uint256& uNod return getASNode(parms, uNode, ltRIPPLE_STATE); } +// For an entry put in the 64 bit index or quality. +uint256 Ledger::getQualityIndex(const uint256& uBase, const uint64 uNodeDir) +{ + // Indexes are stored in big endian format: they print as hex as stored. + // Most significant bytes are first. Least significant bytes represent adjacent entries. + // We place uNodeDir in the 8 right most bytes to be adjacent. + // Want uNodeDir in big endian format so ++ goes to the next entry for indexes. + uint256 uNode(uBase); + + ((uint64*) uNode.end())[-1] = htobe64(uNodeDir); + + return uNode; +} + +// Return the last 64 bits. +uint64 Ledger::getQuality(const uint256& uBase) +{ + return be64toh(((uint64*) uBase.end())[-1]); +} + +uint256 Ledger::getQualityNext(const uint256& uBase) +{ + static uint256 uNext("10000000000000000"); + + uint256 uResult = uBase; + + uResult += uNext; + + return uResult; +} + +uint256 Ledger::getAccountRootIndex(const uint160& uAccountID) +{ + Serializer s(22); + + s.add16(spaceAccount); // 2 + s.add160(uAccountID); // 20 + + return s.getSHA512Half(); +} + +uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID, + const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID) +{ + bool bInNative = uTakerPaysCurrency.isZero(); + bool bOutNative = uTakerGetsCurrency.isZero(); + + assert(!bInNative || !bOutNative); // Stamps to stamps not allowed. + assert(bInNative == uTakerPaysIssuerID.isZero()); // Make sure issuer is specified as needed. + assert(bOutNative == uTakerGetsIssuerID.isZero()); // Make sure issuer is specified as needed. + assert(uTakerPaysCurrency != uTakerGetsCurrency || uTakerPaysIssuerID != uTakerGetsIssuerID); // Currencies or accounts must differ. + + Serializer s(82); + + s.add16(spaceBookDir); // 2 + s.add160(uTakerPaysCurrency); // 20 + s.add160(uTakerGetsCurrency); // 20 + s.add160(uTakerPaysIssuerID); // 20 + s.add160(uTakerGetsIssuerID); // 20 + + return getQualityIndex(s.getSHA512Half()); // Return with quality 0. +} + +uint256 Ledger::getDirNodeIndex(const uint256& uDirRoot, const uint64 uNodeIndex) +{ + if (uNodeIndex) + { + Serializer s(42); + + s.add16(spaceDirNode); // 2 + s.add256(uDirRoot); // 32 + s.add64(uNodeIndex); // 8 + + return s.getSHA512Half(); + } + else + { + return uDirRoot; + } +} + +uint256 Ledger::getGeneratorIndex(const uint160& uGeneratorID) +{ + Serializer s(22); + + s.add16(spaceGenerator); // 2 + s.add160(uGeneratorID); // 20 + + return s.getSHA512Half(); +} + +// What is important: +// --> uNickname: is a Sha256 +// <-- SHA512/2: for consistency and speed in generating indexes. +uint256 Ledger::getNicknameIndex(const uint256& uNickname) +{ + Serializer s(34); + + s.add16(spaceNickname); // 2 + s.add256(uNickname); // 32 + + return s.getSHA512Half(); +} + +uint256 Ledger::getOfferIndex(const uint160& uAccountID, uint32 uSequence) +{ + Serializer s(26); + + s.add16(spaceOffer); // 2 + s.add160(uAccountID); // 20 + s.add32(uSequence); // 4 + + return s.getSHA512Half(); +} + +uint256 Ledger::getOwnerDirIndex(const uint160& uAccountID) +{ + Serializer s(22); + + s.add16(spaceOwnerDir); // 2 + s.add160(uAccountID); // 20 + + return s.getSHA512Half(); +} + +uint256 Ledger::getRippleStateIndex(const NewcoinAddress& naA, const NewcoinAddress& naB, const uint160& uCurrency) +{ + uint160 uAID = naA.getAccountID(); + uint160 uBID = naB.getAccountID(); + bool bAltB = uAID < uBID; + Serializer s(62); + + s.add16(spaceRipple); // 2 + s.add160(bAltB ? uAID : uBID); // 20 + s.add160(bAltB ? uBID : uAID); // 20 + s.add160(uCurrency); // 20 + + return s.getSHA512Half(); +} + // vim:ts=4 From 2522c4625f0508c3254385337f500ec3c9bd3539 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 20 Aug 2012 12:37:36 -0700 Subject: [PATCH 090/426] Fixes for paths. --- src/SerializedTypes.cpp | 37 +++++++++++++++++++++++++++++++------ src/SerializedTypes.h | 2 +- src/Transaction.cpp | 10 +++++----- src/Transaction.h | 4 ++-- 4 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 2a6b0f978e..16572e5d78 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -361,16 +361,41 @@ bool STPathSet::isEquivalent(const SerializedType& t) const return v && (value == v->value); } +int STPath::getSerializeSize() const +{ + int iBytes = 0; + + BOOST_FOREACH(const STPathElement& speElement, mPath) + { + int iType = speElement.getNodeType(); + + iBytes += 1; // mType + + if (iType & STPathElement::typeAccount) + iBytes += 160/8; + + if (iType & STPathElement::typeCurrency) + iBytes += 160/8; + + if (iType & STPathElement::typeIssuer) + iBytes += 160/8; + } + + iBytes += 1; // typeBoundary | typeEnd + + return iBytes; +} + int STPathSet::getLength() const { - // XXX This code is broken? - assert(false); - int ret = 0; + int iBytes = 0; - for (std::vector::const_iterator it = value.begin(), end = value.end(); it != end; ++it) - ret += it->getSerializeSize(); + BOOST_FOREACH(const STPath& spPath, value) + { + iBytes += spPath.getSerializeSize(); + } - return (ret != 0) ? ret : (ret + 1); + return iBytes ? iBytes : 1; } Json::Value STPath::getJson(int) const diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index a582f7fd0f..78fb9a5393 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -584,7 +584,7 @@ public: const STPathElement& getElemet(int offset) { return mPath[offset]; } void addElement(const STPathElement& e) { mPath.push_back(e); } void clear() { mPath.clear(); } - int getSerializeSize() const { return 1 + mPath.size() * 21; } + int getSerializeSize() const; // std::string getText() const; Json::Value getJson(int) const; diff --git a/src/Transaction.cpp b/src/Transaction.cpp index bf692f6cff..224c65d4d6 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -495,7 +495,7 @@ Transaction::pointer Transaction::setPayment( const NewcoinAddress& naDstAccountID, const STAmount& saAmount, const STAmount& saSendMax, - const STPathSet& spPaths) + const STPathSet& spsPaths) { mTransaction->setITFieldAccount(sfDestination, naDstAccountID); mTransaction->setITFieldAmount(sfAmount, saAmount); @@ -505,9 +505,9 @@ Transaction::pointer Transaction::setPayment( mTransaction->setITFieldAmount(sfSendMax, saSendMax); } - if (spPaths.getPathCount()) + if (spsPaths.getPathCount()) { - mTransaction->setITFieldPathSet(sfPaths, spPaths); + mTransaction->setITFieldPathSet(sfPaths, spsPaths); } sign(naPrivateKey); @@ -524,11 +524,11 @@ Transaction::pointer Transaction::sharedPayment( const NewcoinAddress& naDstAccountID, const STAmount& saAmount, const STAmount& saSendMax, - const STPathSet& saPaths) + const STPathSet& spsPaths) { pointer tResult = boost::make_shared(ttPAYMENT, naPublicKey, naSourceAccount, uSeq, saFee, uSourceTag); - return tResult->setPayment(naPrivateKey, naDstAccountID, saAmount, saSendMax, saPaths); + return tResult->setPayment(naPrivateKey, naDstAccountID, saAmount, saSendMax, spsPaths); } // diff --git a/src/Transaction.h b/src/Transaction.h index 15ae32dff5..7198ef04ea 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -116,7 +116,7 @@ private: const NewcoinAddress& naDstAccountID, const STAmount& saAmount, const STAmount& saSendMax, - const STPathSet& spPaths); + const STPathSet& spsPaths); Transaction::pointer setWalletAdd( const NewcoinAddress& naPrivateKey, @@ -231,7 +231,7 @@ public: const NewcoinAddress& naDstAccountID, const STAmount& saAmount, const STAmount& saSendMax, - const STPathSet& saPaths); + const STPathSet& spsPaths); // Place an offer. static Transaction::pointer sharedOfferCreate( From a99f814c20e25b0ea365c8f040c9507cfa70590f Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 20 Aug 2012 13:19:43 -0700 Subject: [PATCH 091/426] Allow qualities to be specified as a float for RPC. --- src/RPCServer.cpp | 15 ++++++++++++--- src/RPCServer.h | 1 + src/SerializedTypes.h | 1 - src/utils.cpp | 19 +++++++++++++++++++ src/utils.h | 3 +++ 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 11545daf7e..33b0639b99 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -44,8 +44,8 @@ Json::Value RPCServer::RPCError(int iError) { rpcACT_NOT_FOUND, "actNotFound", "Account not found." }, { rpcBAD_SEED, "badSeed", "Disallowed seed." }, { rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." }, - { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." }, { rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exists." }, + { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." }, { rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." }, { rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." }, { rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets ammount malformed." }, @@ -71,6 +71,7 @@ Json::Value RPCServer::RPCError(int iError) { rpcPAYS_AMT_MALFORMED, "paysAmtMalformed", "Pays amount malformed." }, { rpcPORT_MALFORMED, "portMalformed", "Port is malformed." }, { rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed." }, + { rpcQUALITY_MALFORMED, "qualityMalformed", "Quality malformed." }, { rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." }, { rpcSRC_ACT_MISSING, "srcActMissing", "Source account does not exist." }, { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency is malformed." }, @@ -1573,8 +1574,8 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) bool bLimitAmount = true; bool bQualityIn = params.size() >= 6; bool bQualityOut = params.size() >= 7; - uint32 uQualityIn = bQualityIn ? lexical_cast_s(params[5u].asString()) : 0; - uint32 uQualityOut = bQualityOut ? lexical_cast_s(params[6u].asString()) : 0; + uint32 uQualityIn = 0; + uint32 uQualityOut = 0; if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -1592,6 +1593,14 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) { return RPCError(rpcSRC_AMT_MALFORMED); } + else if (bQualityIn && !parseQuality(params[5u].asString(), uQualityIn)) + { + return RPCError(rpcQUALITY_MALFORMED); + } + else if (bQualityOut && !parseQuality(params[6u].asString(), uQualityOut)) + { + return RPCError(rpcQUALITY_MALFORMED); + } else { NewcoinAddress naMasterGenerator; diff --git a/src/RPCServer.h b/src/RPCServer.h index eb847b2e07..33f9699b03 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -48,6 +48,7 @@ public: // Bad parameter rpcACT_MALFORMED, + rpcQUALITY_MALFORMED, rpcBAD_SEED, rpcDST_ACT_MALFORMED, rpcDST_ACT_MISSING, diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 78fb9a5393..f076af8708 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -50,7 +50,6 @@ enum PathFlags PF_ISSUE = 0x80, }; -#define QUALITY_ONE 1000000000 // 10e9 #define CURRENCY_XNS uint160(0) #define CURRENCY_ONE uint160(1) // Used as a place holder #define ACCOUNT_XNS uint160(0) diff --git a/src/utils.cpp b/src/utils.cpp index f61a0df304..55c312cb42 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -156,6 +156,25 @@ bool parseIpPort(const std::string& strSource, std::string& strIP, int& iPort) return bValid; } +// +// Quality parsing +// - integers as is. +// - floats multiplied by a billion +bool parseQuality(const std::string& strSource, uint32& uQuality) +{ + uQuality = lexical_cast_s(strSource); + + if (!uQuality) + { + float fQuality = lexical_cast_s(strSource); + + if (fQuality) + uQuality = QUALITY_ONE*fQuality; + } + + return !!uQuality; +} + /* void intIPtoStr(int ip,std::string& retStr) { diff --git a/src/utils.h b/src/utils.h index 4a09e26307..9da1b76aba 100644 --- a/src/utils.h +++ b/src/utils.h @@ -8,6 +8,8 @@ #include "types.h" +#define QUALITY_ONE 1000000000 // 10e9 + #define nothing() do {} while (0) #define fallthru() do {} while (0) #define NUMBER(x) (sizeof(x)/sizeof((x)[0])) @@ -153,6 +155,7 @@ std::vector strCopy(const std::string& strSrc); std::string strCopy(const std::vector& vucSrc); bool parseIpPort(const std::string& strSource, std::string& strIP, int& iPort); +bool parseQuality(const std::string& strSource, uint32& uQuality); DH* DH_der_load(const std::string& strDer); std::string DH_der_gen(int iKeyLength); From 68b044dddea22d3ad613eafa530192f11b896881 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 20 Aug 2012 13:45:58 -0700 Subject: [PATCH 092/426] Changes to support threading through account roots, offers, and ripple state nodes. Fix tracking the last transaction signed by an account. --- src/LedgerFormats.cpp | 6 ++++++ src/SerializedLedger.cpp | 8 ++++++-- src/SerializedLedger.h | 2 +- src/SerializedObject.h | 1 + src/TransactionEngine.cpp | 1 + src/Version.h | 4 ++-- 6 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 58507b6d9d..c7383016b2 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -10,6 +10,8 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(LastReceive), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(LastSignedSeq), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_IFFLAG, 1 }, { S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 2 }, @@ -52,6 +54,8 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(BookDirectory), STI_HASH256, SOE_REQUIRED, 0 }, { S_FIELD(BookNode), STI_UINT64, SOE_REQUIRED, 0 }, { S_FIELD(OwnerNode), STI_UINT64, SOE_REQUIRED, 0 }, + { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, + { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(PaysIssuer), STI_ACCOUNT, SOE_IFFLAG, 1 }, { S_FIELD(GetsIssuer), STI_ACCOUNT, SOE_IFFLAG, 2 }, { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 4 }, @@ -65,6 +69,8 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(LowLimit), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(HighID), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(HighLimit), STI_AMOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, + { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(LowQualityIn), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(LowQualityOut), STI_UINT32, SOE_IFFLAG, 2 }, { S_FIELD(HighQualityIn), STI_UINT32, SOE_IFFLAG, 4 }, diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 3cc5c70dc0..e79b19c1b7 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -96,13 +96,17 @@ uint32 SerializedLedgerEntry::getThreadedLedger() return getIFieldU32(sfLastTxnSeq); } -void SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID) +bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID) { - prevTxID = getIFieldH256(sfLastTxnID); + uint256 oldPrevTxID = getIFieldH256(sfLastTxnID); + if (oldPrevTxID == txID) + return false; + prevTxID = oldPrevTxID; prevLedgerID = getIFieldU32(sfLastTxnID); assert(prevTxID != txID); setIFieldH256(sfLastTxnID, txID); setIFieldU32(sfLastTxnSeq, ledgerSeq); + return true; } std::vector SerializedLedgerEntry::getOwners() diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index c8ac2d96e5..5f66a765dc 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -67,7 +67,7 @@ public: bool isThreaded(); // is this ledger entry actually threaded uint256 getThreadedTransaction(); uint32 getThreadedLedger(); - void thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID); + bool thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID); std::vector getOwners(); // nodes notified if this node is deleted void setIFieldU8(SOE_Field field, unsigned char v) { return mObject.setValueFieldU8(field, v); } diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 5453a987b7..8ee7a6b4c8 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -63,6 +63,7 @@ enum SOE_Field sfInvoiceID, sfLastNode, sfLastReceive, + sfLastSignedSeq, sfLastTxnID, sfLastTxnSeq, sfLedgerHash, diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 583f287653..d877c0ffd4 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1219,6 +1219,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran terResult = terPAST_SEQ; } } + mTxnAccount->setIFieldU32(sfLastSignedSeq, mLedger->getLedgerSeq()); if (terSUCCESS == terResult) { diff --git a/src/Version.h b/src/Version.h index 51603753c5..957327c2a0 100644 --- a/src/Version.h +++ b/src/Version.h @@ -16,11 +16,11 @@ // Version we prefer to speak: #define PROTO_VERSION_MAJOR 0 -#define PROTO_VERSION_MINOR 4 +#define PROTO_VERSION_MINOR 5 // Version we wil speak to: #define MIN_PROTO_MAJOR 0 -#define MIN_PROTO_MINOR 4 +#define MIN_PROTO_MINOR 5 #define MAKE_VERSION_INT(maj,min) ((maj << 16) | min) #define GET_VERSION_MAJOR(ver) (ver >> 16) From 58644fc806b89c59c2d90080926dfff11e540a58 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 20 Aug 2012 16:23:23 -0700 Subject: [PATCH 093/426] Fix transaction engine sense of ripple balances. --- src/Amount.cpp | 14 ++++++++++++++ src/RPCServer.cpp | 2 +- src/TransactionEngine.cpp | 6 +++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 966eea15b6..60a4792fa4 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -105,7 +105,11 @@ bool STAmount::setFullValue(const std::string& sAmount, const std::string& sCurr // Figure out the currency. // if (!currencyFromString(mCurrency, sCurrency)) + { + Log(lsINFO) << "Currency malformed: " << sCurrency; + return false; + } mIsNative = !mCurrency; @@ -116,13 +120,21 @@ bool STAmount::setFullValue(const std::string& sAmount, const std::string& sCurr // Issuer must be "" or a valid account string. if (!naIssuerID.setAccountID(sIssuer)) + { + Log(lsINFO) << "Issuer malformed: " << sIssuer; + return false; + } mIssuer = naIssuerID.getAccountID(); // Stamps not must have an issuer. if (mIsNative && !mIssuer.isZero()) + { + Log(lsINFO) << "Issuer specified for stamps: " << sIssuer; + return false; + } uint64 uValue; int iOffset; @@ -137,6 +149,8 @@ bool STAmount::setFullValue(const std::string& sAmount, const std::string& sCurr } catch (...) { + Log(lsINFO) << "Bad integer amount: " << sAmount; + return false; } iOffset = 0; diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 33b0639b99..8cd2a27f14 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -48,7 +48,7 @@ Json::Value RPCServer::RPCError(int iError) { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." }, { rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." }, { rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." }, - { rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets ammount malformed." }, + { rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets amount malformed." }, { rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed." }, { rpcINSUF_FUNDS, "insufFunds", "Insufficient funds." }, { rpcINTERNAL, "internal", "Internal error." }, diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 583f287653..ad11f8d6f9 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -224,8 +224,8 @@ STAmount TransactionEngine::rippleHolds(const uint160& uAccountID, const uint160 { saBalance = sleRippleState->getIValueFieldAmount(sfBalance); - if (uAccountID < uIssuerID) - saBalance.negate(); // Put balance in low terms. + if (uAccountID > uIssuerID) + saBalance.negate(); // Put balance in uAccountID terms. } return saBalance; @@ -4213,7 +4213,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); } else if (!accountFunds(mTxnAccountID, saTakerGets).isPositive()) { - Log(lsWARNING) << "doOfferCreate: delay: offers must be funded"; + Log(lsWARNING) << "doOfferCreate: delay: Offers must be at least partially funded."; terResult = terUNFUNDED; } From c16fe1e725db2a0793815a5f35b15366fa11bd76 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 20 Aug 2012 16:45:30 -0700 Subject: [PATCH 094/426] Add AccountID to json output for AccountState. --- src/AccountState.cpp | 20 ++++++++++++++------ src/AccountState.h | 3 ++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/AccountState.cpp b/src/AccountState.cpp index e9804926c2..b9cea5936b 100644 --- a/src/AccountState.cpp +++ b/src/AccountState.cpp @@ -10,11 +10,12 @@ #include "Ledger.h" #include "Serializer.h" -AccountState::AccountState(const NewcoinAddress& id) : mValid(false) +AccountState::AccountState(const NewcoinAddress& naAccountID) : mAccountID(naAccountID), mValid(false) { - if (!id.isValid()) return; + if (!naAccountID.isValid()) return; + mLedgerEntry = boost::make_shared(ltACCOUNT_ROOT); - mLedgerEntry->setIndex(Ledger::getAccountRootIndex(id)); + mLedgerEntry->setIndex(Ledger::getAccountRootIndex(naAccountID)); mValid = true; } @@ -41,10 +42,17 @@ void AccountState::addJson(Json::Value& val) { val = mLedgerEntry->getJson(0); - if (!mValid) val["Invalid"] = true; + if (mValid) + { + val["AccountID"] = mAccountID.humanAccountID(); - if (mLedgerEntry->getIFieldPresent(sfEmailHash)) - val["UrlGravatar"] = createGravatarUrl(mLedgerEntry->getIFieldH128(sfEmailHash)); + if (mLedgerEntry->getIFieldPresent(sfEmailHash)) + val["UrlGravatar"] = createGravatarUrl(mLedgerEntry->getIFieldH128(sfEmailHash)); + } + else + { + val["Invalid"] = true; + } } void AccountState::dump() diff --git a/src/AccountState.h b/src/AccountState.h index 9069f375b0..bd7503cb11 100644 --- a/src/AccountState.h +++ b/src/AccountState.h @@ -21,13 +21,14 @@ public: typedef boost::shared_ptr pointer; private: + NewcoinAddress mAccountID; NewcoinAddress mAuthorizedKey; SerializedLedgerEntry::pointer mLedgerEntry; bool mValid; public: - AccountState(const NewcoinAddress& AccountID); // For new accounts + AccountState(const NewcoinAddress& naAccountID); // For new accounts AccountState(const SerializedLedgerEntry::pointer& ledgerEntry); // For accounts in a ledger bool bHaveAuthorizedKey() From 6694372af721680cd3706c7dbfe4fe08afd61542 Mon Sep 17 00:00:00 2001 From: jed Date: Mon, 20 Aug 2012 17:01:53 -0700 Subject: [PATCH 095/426] . --- src/AccountState.cpp | 6 +++--- src/AccountState.h | 2 +- src/Ledger.cpp | 2 +- src/utils.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/AccountState.cpp b/src/AccountState.cpp index b9cea5936b..235616dfb8 100644 --- a/src/AccountState.cpp +++ b/src/AccountState.cpp @@ -20,8 +20,8 @@ AccountState::AccountState(const NewcoinAddress& naAccountID) : mAccountID(naAcc mValid = true; } -AccountState::AccountState(const SerializedLedgerEntry::pointer& ledgerEntry) : - mLedgerEntry(ledgerEntry), mValid(false) +AccountState::AccountState(const SerializedLedgerEntry::pointer& ledgerEntry,const NewcoinAddress& naAccountID) : + mLedgerEntry(ledgerEntry), mValid(false), mAccountID(naAccountID) { if (!mLedgerEntry) return; if (mLedgerEntry->getType() != ltACCOUNT_ROOT) return; @@ -44,7 +44,7 @@ void AccountState::addJson(Json::Value& val) if (mValid) { - val["AccountID"] = mAccountID.humanAccountID(); + val["Account"] = mAccountID.humanAccountID(); if (mLedgerEntry->getIFieldPresent(sfEmailHash)) val["UrlGravatar"] = createGravatarUrl(mLedgerEntry->getIFieldH128(sfEmailHash)); diff --git a/src/AccountState.h b/src/AccountState.h index bd7503cb11..1a3de87095 100644 --- a/src/AccountState.h +++ b/src/AccountState.h @@ -29,7 +29,7 @@ private: public: AccountState(const NewcoinAddress& naAccountID); // For new accounts - AccountState(const SerializedLedgerEntry::pointer& ledgerEntry); // For accounts in a ledger + AccountState(const SerializedLedgerEntry::pointer& ledgerEntry,const NewcoinAddress& naAccountI); // For accounts in a ledger bool bHaveAuthorizedKey() { diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 739947d933..6239115cc4 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -178,7 +178,7 @@ AccountState::pointer Ledger::getAccountState(const NewcoinAddress& accountID) SerializedLedgerEntry::pointer sle = boost::make_shared(item->peekSerializer(), item->getTag()); if (sle->getType() != ltACCOUNT_ROOT) return AccountState::pointer(); - return boost::make_shared(sle); + return boost::make_shared(sle,accountID); } NicknameState::pointer Ledger::getNicknameState(const uint256& uNickname) diff --git a/src/utils.cpp b/src/utils.cpp index 55c312cb42..944a281139 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -169,7 +169,7 @@ bool parseQuality(const std::string& strSource, uint32& uQuality) float fQuality = lexical_cast_s(strSource); if (fQuality) - uQuality = QUALITY_ONE*fQuality; + uQuality = (uint32)(QUALITY_ONE*fQuality); } return !!uQuality; From f9e1ee033b2609afa20c639df4c39a80f7ed0106 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 21 Aug 2012 08:16:10 -0700 Subject: [PATCH 096/426] TxMeta rewrite. --- src/TransactionMeta.cpp | 193 +++++++++++++++++++++------------------- src/TransactionMeta.h | 104 ++++++++++++---------- 2 files changed, 159 insertions(+), 138 deletions(-) diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index 0ab28f391e..41bd565405 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -33,114 +33,119 @@ bool TransactionMetaNodeEntry::operator>=(const TransactionMetaNodeEntry& e) con return compare(e) >= 0; } -TMNEBalance::TMNEBalance(SerializerIterator& sit) : TransactionMetaNodeEntry(TMNChangedBalance) +TMNEThread::TMNEThread(SerializerIterator& sit) : TransactionMetaNodeEntry(TMSThread) { - mFlags = sit.get32(); - mFirstAmount = * dynamic_cast(STAmount::deserialize(sit, "FirstAmount").get()); - if ((mFlags & TMBTwoAmounts) != 0) - mSecondAmount = * dynamic_cast(STAmount::deserialize(sit, "SecondAmount").get()); + mPrevTxID = sit.get256(); + mPrevLgrSeq = sit.get32(); } -void TMNEBalance::addRaw(Serializer& sit) const +void TMNEThread::addRaw(Serializer& sit) const { sit.add8(mType); - sit.add32(mFlags); - mFirstAmount.add(sit); - if ((mFlags & TMBTwoAmounts) != 0) - mSecondAmount.add(sit); + sit.add256(mPrevTxID); + sit.add32(mPrevLgrSeq); } -void TMNEBalance::adjustFirstAmount(const STAmount& a) +int TMNEThread::compare(const TransactionMetaNodeEntry&) const { - mFirstAmount += a; -} - -void TMNEBalance::adjustSecondAmount(const STAmount& a) -{ - mSecondAmount += a; - mFlags |= TMBTwoAmounts; -} - -int TMNEBalance::compare(const TransactionMetaNodeEntry&) const -{ - assert(false); // should never be two TMNEBalance entries for the same node (as of now) + assert(false); // should never be two entries for the same node (as of now) return 0; } -Json::Value TMNEBalance::getJson(int p) const +Json::Value TMNEThread::getJson(int) const { - Json::Value ret(Json::objectValue); + Json::Value inner(Json::objectValue); + inner["prev_transaction"] = mPrevTxID.GetHex(); + inner["prev_ledger_seq"] = mPrevLgrSeq; - if ((mFlags & TMBDestroyed) != 0) - ret["destroyed"] = "true"; - if ((mFlags & TMBPaidFee) != 0) - ret["transaction_fee"] = "true"; - - if ((mFlags & TMBRipple) != 0) - ret["type"] = "ripple"; - else if ((mFlags & TMBOffer) != 0) - ret["type"] = "offer"; - else - ret["type"] = "account"; - - if (!mFirstAmount.isZero()) - ret["amount"] = mFirstAmount.getJson(p); - if (!mSecondAmount.isZero()) - ret["second_amount"] = mSecondAmount.getJson(p); - - return ret; + Json::Value outer(Json::objectValue); + outer["thread"] = inner; + return outer; } -void TMNEUnfunded::addRaw(Serializer& sit) const +TMNEAmount::TMNEAmount(int type, SerializerIterator& sit) : TransactionMetaNodeEntry(type) { - sit.add8(mType); + mPrevAmount = *dynamic_cast(STAmount::deserialize(sit, NULL).get()); // Ouch } -Json::Value TMNEUnfunded::getJson(int) const +void TMNEAmount::addRaw(Serializer& s) const { - return Json::Value("delete_unfunded"); + s.add8(mType); + mPrevAmount.add(s); } -void TMNEUnfunded::setBalances(const STAmount& first, const STAmount& second) +Json::Value TMNEAmount::getJson(int v) const { - firstAmount = first; - secondAmount = second; -} - -int TMNEUnfunded::compare(const TransactionMetaNodeEntry&) const -{ - assert(false); // Can't be two deletes for same node - return 0; -} - -TransactionMetaNode::TransactionMetaNode(const uint256& node, SerializerIterator& sit) : mNode(node) -{ - mNode = sit.get256(); - mPreviousTransaction = sit.get256(); - mPreviousLedger = sit.get32(); - int type; - do + Json::Value outer(Json::objectValue); + switch (mType) { - type = sit.get8(); - if (type == TransactionMetaNodeEntry::TMNChangedBalance) - mEntries.push_back(new TMNEBalance(sit)); - if (type == TransactionMetaNodeEntry::TMNDeleteUnfunded) - mEntries.push_back(new TMNEUnfunded()); - else if (type != TransactionMetaNodeEntry::TMNEndOfMetadata) - throw std::runtime_error("Unparseable metadata"); - } while (type != TransactionMetaNodeEntry::TMNEndOfMetadata); + case TMSPrevBalance: outer["prev_balance"] = mPrevAmount.getJson(v); break; + case TMSPrevTakerPays: outer["prev_taker_pays"] = mPrevAmount.getJson(v); break; + case TMSPrevTakerGets: outer["prev_taker_gets"] = mPrevAmount.getJson(v); break; + case TMSFinalTakerPays: outer["final_taker_pays"] = mPrevAmount.getJson(v); break; + case TMSFinalTakerGets: outer["final_taker_gets"] = mPrevAmount.getJson(v); break; + default: assert(false); + } + return outer; +} + +void TMNEAccount::addRaw(Serializer& sit) const +{ + sit.add8(mType); + sit.add256(mPrevAccount); +} + +Json::Value TMNEAccount::getJson(int) const +{ + Json::Value outer(Json::objectValue); + outer["prev_account"] = mPrevAccount.GetHex(); + return outer; +} + +int TMNEAccount::compare(const TransactionMetaNodeEntry&) const +{ + assert(false); // Can't be two modified accounts of same type for same node + return 0; +} + +TransactionMetaNode::TransactionMetaNode(int type, const uint256& node, SerializerIterator& sit) + : mType(type), mNode(node) +{ + while (1) + { + int nType = sit.get8(); + switch (nType) + { + case TMSEndOfNode: + return; + + case TMSThread: + mEntries.push_back(new TMNEThread(sit)); + break; + + // Nodes that contain an amount + case TMSPrevBalance: + case TMSPrevTakerPays: + case TMSPrevTakerGets: + case TMSFinalTakerPays: + case TMSFinalTakerGets: + mEntries.push_back(new TMNEAmount(nType, sit)); + + case TMSPrevAccount: + mEntries.push_back(new TMNEAccount(nType, sit)); + } + } } void TransactionMetaNode::addRaw(Serializer& s) { + s.add8(mType); s.add256(mNode); - s.add256(mPreviousTransaction); - s.add32(mPreviousLedger); mEntries.sort(); for (boost::ptr_vector::const_iterator it = mEntries.begin(), end = mEntries.end(); it != end; ++it) it->addRaw(s); - s.add8(TransactionMetaNodeEntry::TMNEndOfMetadata); + s.add8(TMSEndOfNode); } TransactionMetaNodeEntry* TransactionMetaNode::findEntry(int nodeType) @@ -152,13 +157,13 @@ TransactionMetaNodeEntry* TransactionMetaNode::findEntry(int nodeType) return NULL; } -TMNEBalance* TransactionMetaNode::findBalance() +TMNEAmount* TransactionMetaNode::findAmount(int nType) { for (boost::ptr_vector::iterator it = mEntries.begin(), end = mEntries.end(); it != end; ++it) - if (it->getType() == TransactionMetaNodeEntry::TMNChangedBalance) - return dynamic_cast(&*it); - TMNEBalance* node = new TMNEBalance(); + if (it->getType() == nType) + return dynamic_cast(&*it); + TMNEAmount* node = new TMNEAmount(nType); mEntries.push_back(node); return node; } @@ -170,18 +175,23 @@ void TransactionMetaNode::addNode(TransactionMetaNodeEntry* node) void TransactionMetaNode::thread(const uint256& prevTx, uint32 prevLgr) { - assert((mPreviousLedger == 0) || (mPreviousLedger == prevLgr)); - assert(mPreviousTransaction.isZero() || (mPreviousTransaction == prevTx)); - mPreviousTransaction = prevTx; - mPreviousLedger = prevLgr; + // WRITEME } Json::Value TransactionMetaNode::getJson(int v) const { Json::Value ret = Json::objectValue; + + switch (mType) + { + case TMNCreatedNode: ret["action"] = "create"; break; + case TMNDeletedNode: ret["action"] = "delete"; break; + case TMNModifiedNode: ret["action"] = "modify"; break; + default: + assert(false); + } + ret["node"] = mNode.GetHex(); - ret["previous_transaction"] = mPreviousTransaction.GetHex(); - ret["previous_ledger"] = mPreviousLedger; Json::Value e = Json::arrayValue; for (boost::ptr_vector::const_iterator it = mEntries.begin(), end = mEntries.end(); @@ -199,13 +209,12 @@ TransactionMetaSet::TransactionMetaSet(uint32 ledger, const std::vector::iterator it = mNodes.begin(), end = mNodes.end(); it != end; ++it) it->second.addRaw(s); - s.add256(uint256()); + s.add8(TMNEndOfMetadata); } Json::Value TransactionMetaSet::getJson(int v) const diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index d863ccb701..8fe20948bd 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -12,18 +12,36 @@ #include "Serializer.h" #include "SerializedTypes.h" +// master record types +static const int TMNEndOfMetadata = 0x00; +static const int TMNCreatedNode = 0x10; // This transaction created this node +static const int TMNDeletedNode = 0x11; +static const int TMNModifiedNode = 0x12; + +// sub record types - special +static const int TMSEndOfNode = 0x00; +static const int TMSThread = 0x01; // Holds previous TxID and LgrSeq for threading + +// sub record types - containing an amount +static const int TMSPrevBalance = 0x11; // Balances prior to the transaction +static const int TMSPrevTakerPays = 0x12; +static const int TMSPrevTakerGets = 0x13; +static const int TMSFinalTakerPays = 0x14; // Balances at node deletion time +static const int TMSFinalTakerGets = 0x15; + +// sub record types - containing an account (for example, for when a nickname is transferred) +static const int TMSPrevAccount = 0x20; + class TransactionMetaNodeEntry { // a way that a transaction has affected a node public: - typedef boost::shared_ptr pointer; - static const int TMNEndOfMetadata = 0; - static const int TMNChangedBalance = 1; - static const int TMNDeleteUnfunded = 2; - +protected: int mType; + +public: TransactionMetaNodeEntry(int type) : mType(type) { ; } int getType() const { return mType; } @@ -43,52 +61,53 @@ protected: virtual TransactionMetaNodeEntry* duplicate(void) const = 0; }; -class TMNEBalance : public TransactionMetaNodeEntry -{ // a transaction affected the balance of a node -public: - - static const int TMBTwoAmounts = 0x001; - static const int TMBDestroyed = 0x010; - static const int TMBPaidFee = 0x020; - static const int TMBRipple = 0x100; - static const int TMBOffer = 0x200; - +class TMNEThread : public TransactionMetaNodeEntry +{ protected: - unsigned mFlags; - STAmount mFirstAmount, mSecondAmount; + uint256 mPrevTxID; + uint32 mPrevLgrSeq; public: - TMNEBalance() : TransactionMetaNodeEntry(TMNChangedBalance), mFlags(0) { ; } + TMNEThread() : TransactionMetaNodeEntry(TMSThread) { ; } + TMNEThread(SerializerIterator&); - TMNEBalance(SerializerIterator&); virtual void addRaw(Serializer&) const; - - unsigned getFlags() const { return mFlags; } - const STAmount& getFirstAmount() const { return mFirstAmount; } - const STAmount& getSecondAmount() const { return mSecondAmount; } - - void adjustFirstAmount(const STAmount&); - void adjustSecondAmount(const STAmount&); - void setFlags(unsigned flags); - virtual Json::Value getJson(int) const; virtual int compare(const TransactionMetaNodeEntry&) const; - virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEBalance(*this); } + virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEThread(*this); } }; -class TMNEUnfunded : public TransactionMetaNodeEntry +class TMNEAmount : public TransactionMetaNodeEntry +{ // a transaction affected the balance of a node +protected: + STAmount mPrevAmount; + +public: + TMNEAmount(int type) : TransactionMetaNodeEntry(type) { ; } + + TMNEAmount(int type, SerializerIterator&); + virtual void addRaw(Serializer&) const; + + const STAmount& getAmount() const { return mPrevAmount; } + void setAmount(const STAmount& a) { mPrevAmount = a; } + + virtual Json::Value getJson(int) const; + virtual int compare(const TransactionMetaNodeEntry&) const; + virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEAmount(*this); } +}; + +class TMNEAccount : public TransactionMetaNodeEntry { // node was deleted because it was unfunded protected: - STAmount firstAmount, secondAmount; // Amounts left when declared unfunded + uint256 mPrevAccount; + public: - TMNEUnfunded() : TransactionMetaNodeEntry(TMNDeleteUnfunded) { ; } - TMNEUnfunded(const STAmount& f, const STAmount& s) : - TransactionMetaNodeEntry(TMNDeleteUnfunded), firstAmount(f), secondAmount(s) { ; } - void setBalances(const STAmount& firstBalance, const STAmount& secondBalance); + TMNEAccount(int type, uint256 prev) : TransactionMetaNodeEntry(type), mPrevAccount(prev) { ; } + TMNEAccount(int type, SerializerIterator&); virtual void addRaw(Serializer&) const; virtual Json::Value getJson(int) const; virtual int compare(const TransactionMetaNodeEntry&) const; - virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEUnfunded(*this); } + virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEAccount(*this); } }; inline TransactionMetaNodeEntry* new_clone(const TransactionMetaNodeEntry& s) { return s.clone().release(); } @@ -100,21 +119,17 @@ public: typedef boost::shared_ptr pointer; protected: + int mType; uint256 mNode; - uint256 mPreviousTransaction; - uint32 mPreviousLedger; boost::ptr_vector mEntries; public: TransactionMetaNode(const uint256 &node) : mNode(node) { ; } const uint256& getNode() const { return mNode; } - const uint256& getPreviousTransaction() const { return mPreviousTransaction; } - uint32 getPreviousLedger() const { return mPreviousLedger; } const boost::ptr_vector& peekEntries() const { return mEntries; } TransactionMetaNodeEntry* findEntry(int nodeType); - TMNEBalance* findBalance(); void addNode(TransactionMetaNodeEntry*); bool operator<(const TransactionMetaNode& n) const { return mNode < n.mNode; } @@ -124,14 +139,11 @@ public: void thread(const uint256& prevTx, uint32 prevLgr); - TransactionMetaNode(const uint256&node, SerializerIterator&); + TransactionMetaNode(int type, const uint256& node, SerializerIterator&); void addRaw(Serializer&); Json::Value getJson(int) const; - void threadNode(const uint256& previousTransaction, uint32 previousLedger); - void deleteUnfunded(const STAmount& firstBalance, const STAmount& secondBalance); - void adjustBalance(unsigned flags, const STAmount &amount, bool signedBy); - void adjustBalances(unsigned flags, const STAmount &firstAmt, const STAmount &secondAmt); + TMNEAmount* findAmount(int nodeType); }; From a3e3318943882834de62fef1eb58a17694a6a74a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 22 Aug 2012 04:55:01 -0700 Subject: [PATCH 097/426] Silence a warning. --- src/AccountState.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/AccountState.cpp b/src/AccountState.cpp index 235616dfb8..ab8fcac229 100644 --- a/src/AccountState.cpp +++ b/src/AccountState.cpp @@ -21,10 +21,12 @@ AccountState::AccountState(const NewcoinAddress& naAccountID) : mAccountID(naAcc } AccountState::AccountState(const SerializedLedgerEntry::pointer& ledgerEntry,const NewcoinAddress& naAccountID) : - mLedgerEntry(ledgerEntry), mValid(false), mAccountID(naAccountID) + mAccountID(naAccountID), mLedgerEntry(ledgerEntry), mValid(false) { - if (!mLedgerEntry) return; - if (mLedgerEntry->getType() != ltACCOUNT_ROOT) return; + if (!mLedgerEntry) + return; + if (mLedgerEntry->getType() != ltACCOUNT_ROOT) + return; mValid = true; } From a8316fac265f65c0ff16f64aa0b876d5b149f05f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 22 Aug 2012 04:55:10 -0700 Subject: [PATCH 098/426] Missing from previous commits. --- src/TransactionMeta.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index 41bd565405..60dc768c59 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -89,6 +89,17 @@ Json::Value TMNEAmount::getJson(int v) const return outer; } +int TMNEAmount::compare(const TransactionMetaNodeEntry& e) const +{ + assert(getType() != e.getType()); + return getType() - e.getType(); +} + +TMNEAccount::TMNEAccount(int type, SerializerIterator& sit) : TransactionMetaNodeEntry(type) +{ + mPrevAccount = sit.get256(); +} + void TMNEAccount::addRaw(Serializer& sit) const { sit.add8(mType); From c2a3d5b468fad5723134c4785d6575426f33c19e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 22 Aug 2012 05:17:10 -0700 Subject: [PATCH 099/426] compare and duplicate should both be private. --- src/TransactionMeta.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index 8fe20948bd..a6650a7b28 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -47,7 +47,6 @@ public: int getType() const { return mType; } virtual Json::Value getJson(int) const = 0; virtual void addRaw(Serializer&) const = 0; - virtual int compare(const TransactionMetaNodeEntry&) const = 0; bool operator<(const TransactionMetaNodeEntry&) const; bool operator<=(const TransactionMetaNodeEntry&) const; @@ -58,6 +57,7 @@ public: { return std::auto_ptr(duplicate()); } protected: + virtual int compare(const TransactionMetaNodeEntry&) const = 0; virtual TransactionMetaNodeEntry* duplicate(void) const = 0; }; @@ -73,8 +73,10 @@ public: virtual void addRaw(Serializer&) const; virtual Json::Value getJson(int) const; - virtual int compare(const TransactionMetaNodeEntry&) const; + +protected: virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEThread(*this); } + virtual int compare(const TransactionMetaNodeEntry&) const; }; class TMNEAmount : public TransactionMetaNodeEntry @@ -92,8 +94,10 @@ public: void setAmount(const STAmount& a) { mPrevAmount = a; } virtual Json::Value getJson(int) const; - virtual int compare(const TransactionMetaNodeEntry&) const; + +protected: virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEAmount(*this); } + virtual int compare(const TransactionMetaNodeEntry&) const; }; class TMNEAccount : public TransactionMetaNodeEntry @@ -106,8 +110,10 @@ public: TMNEAccount(int type, SerializerIterator&); virtual void addRaw(Serializer&) const; virtual Json::Value getJson(int) const; - virtual int compare(const TransactionMetaNodeEntry&) const; + +protected: virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEAccount(*this); } + virtual int compare(const TransactionMetaNodeEntry&) const; }; inline TransactionMetaNodeEntry* new_clone(const TransactionMetaNodeEntry& s) { return s.clone().release(); } From 962e9f0180b66df2edf3a3f5f0909e8fb5b10c2f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 22 Aug 2012 05:17:23 -0700 Subject: [PATCH 100/426] Type comparison is handled in higher-level code and not needed at the bottom. --- src/TransactionMeta.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index 60dc768c59..93f89652ef 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -91,8 +91,8 @@ Json::Value TMNEAmount::getJson(int v) const int TMNEAmount::compare(const TransactionMetaNodeEntry& e) const { - assert(getType() != e.getType()); - return getType() - e.getType(); + assert(false); // can't be two changed amounts of same type + return 0; } TMNEAccount::TMNEAccount(int type, SerializerIterator& sit) : TransactionMetaNodeEntry(type) From c120a4cada3ea92d449f8bbeba0ddc0c1bff90f9 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 22 Aug 2012 08:03:29 -0700 Subject: [PATCH 101/426] Fix thread. New constructor. --- src/TransactionMeta.cpp | 16 ++++++++++------ src/TransactionMeta.h | 5 ++++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index 93f89652ef..b193afb48a 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -95,10 +95,9 @@ int TMNEAmount::compare(const TransactionMetaNodeEntry& e) const return 0; } -TMNEAccount::TMNEAccount(int type, SerializerIterator& sit) : TransactionMetaNodeEntry(type) -{ - mPrevAccount = sit.get256(); -} +TMNEAccount::TMNEAccount(int type, SerializerIterator& sit) + : TransactionMetaNodeEntry(type), mPrevAccount(sit.get256()) +{ ; } void TMNEAccount::addRaw(Serializer& sit) const { @@ -184,9 +183,14 @@ void TransactionMetaNode::addNode(TransactionMetaNodeEntry* node) mEntries.push_back(node); } -void TransactionMetaNode::thread(const uint256& prevTx, uint32 prevLgr) +bool TransactionMetaNode::thread(const uint256& prevTx, uint32 prevLgr) { - // WRITEME + for (boost::ptr_vector::iterator it = mEntries.begin(), end = mEntries.end(); + it != end; ++it) + if (it->getType() == TMSThread) + return false; + addNode(new TMNEThread(prevTx, prevLgr)); + return true; } Json::Value TransactionMetaNode::getJson(int v) const diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index a6650a7b28..e3a5f359eb 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -69,6 +69,9 @@ protected: public: TMNEThread() : TransactionMetaNodeEntry(TMSThread) { ; } + TMNEThread(uint256 prevTx, uint32 prevLgrSeq) + : TransactionMetaNodeEntry(TMSThread), mPrevTxID(prevTx), mPrevLgrSeq(prevLgrSeq) + { ; } TMNEThread(SerializerIterator&); virtual void addRaw(Serializer&) const; @@ -143,7 +146,7 @@ public: bool operator>(const TransactionMetaNode& n) const { return mNode > n.mNode; } bool operator>=(const TransactionMetaNode& n) const { return mNode >= n.mNode; } - void thread(const uint256& prevTx, uint32 prevLgr); + bool thread(const uint256& prevTx, uint32 prevLgr); TransactionMetaNode(int type, const uint256& node, SerializerIterator&); void addRaw(Serializer&); From e00426a3bed5921669a1cd2a48555f59fd5131e0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 22 Aug 2012 14:56:01 -0700 Subject: [PATCH 102/426] Finalizing of metadata building. --- src/LedgerEntrySet.cpp | 18 ++++++++++++++---- src/LedgerEntrySet.h | 5 +++-- src/TransactionMeta.h | 2 +- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 390cec2301..ac110df3c3 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -230,26 +230,36 @@ Json::Value LedgerEntrySet::getJson(int) const return ret; } -void LedgerEntrySet::addRawMeta(Serializer& s) +void LedgerEntrySet::addRawMeta(Serializer& s, Ledger::pointer origLedger) { for (boost::unordered_map::const_iterator it = mEntries.begin(), end = mEntries.end(); it != end; ++it) { + int nType = TMNEndOfMetadata; + switch (it->second.mAction) { case taaMODIFY: - // WRITEME + nType = TMNModifiedNode; break; case taaDELETE: - // WRITEME + nType = TMNDeletedNode; break; case taaCREATE: - // WRITEME + nType = TMNCreatedNode; break; default: // ignore these break; } + if (nType != TMNEndOfMetadata) + { + SLE::pointer origNode = origLedger->getSLE(it->first); + SLE::pointer curNode = it->second.mEntry; + + // FINISH + + } } mSet.addRaw(s); } diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 0980d094b3..cf4ee9b281 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -5,6 +5,7 @@ #include "SerializedLedger.h" #include "TransactionMeta.h" +#include "Ledger.h" enum LedgerEntryAction { @@ -42,7 +43,7 @@ public: // set functions LedgerEntrySet duplicate() const; // Make a duplicate of this set - void setTo(const LedgerEntrySet&); // Set this set to have the same contents as another + void setTo(const LedgerEntrySet&); // Set this set to have the same contents as another void swapWith(LedgerEntrySet&); // Swap the contents of two sets int getSeq() const { return mSeq; } @@ -59,7 +60,7 @@ public: void entryModify(const SLE::pointer&); // This entry will be modified Json::Value getJson(int) const; - void addRawMeta(Serializer&); + void addRawMeta(Serializer&, Ledger::pointer originalLedger); // iterator functions bool isEmpty() const { return mEntries.empty(); } diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index e3a5f359eb..4060353221 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -175,7 +175,7 @@ public: void swap(TransactionMetaSet&); bool isNodeAffected(const uint256&) const; - TransactionMetaNode& getAffectedNode(const uint256&); + TransactionMetaNode& getAffectedNode(const uint256&, int type); const TransactionMetaNode& peekAffectedNode(const uint256&) const; Json::Value getJson(int) const; From cedb9d08fabf9d6fc89742c1545855de643d861b Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 22 Aug 2012 16:24:05 -0700 Subject: [PATCH 103/426] Add Account field back to AccountRoot nodes. --- src/AccountState.cpp | 5 ++--- src/LedgerFormats.cpp | 1 + src/TransactionEngine.cpp | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/AccountState.cpp b/src/AccountState.cpp index ab8fcac229..b48bcbd131 100644 --- a/src/AccountState.cpp +++ b/src/AccountState.cpp @@ -16,11 +16,12 @@ AccountState::AccountState(const NewcoinAddress& naAccountID) : mAccountID(naAcc mLedgerEntry = boost::make_shared(ltACCOUNT_ROOT); mLedgerEntry->setIndex(Ledger::getAccountRootIndex(naAccountID)); + mLedgerEntry->setIFieldAccount(sfAccount, naAccountID.getAccountID()); mValid = true; } -AccountState::AccountState(const SerializedLedgerEntry::pointer& ledgerEntry,const NewcoinAddress& naAccountID) : +AccountState::AccountState(const SerializedLedgerEntry::pointer& ledgerEntry, const NewcoinAddress& naAccountID) : mAccountID(naAccountID), mLedgerEntry(ledgerEntry), mValid(false) { if (!mLedgerEntry) @@ -46,8 +47,6 @@ void AccountState::addJson(Json::Value& val) if (mValid) { - val["Account"] = mAccountID.humanAccountID(); - if (mLedgerEntry->getIFieldPresent(sfEmailHash)) val["UrlGravatar"] = createGravatarUrl(mLedgerEntry->getIFieldH128(sfEmailHash)); } diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index c7383016b2..a0f0271d78 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -7,6 +7,7 @@ LedgerEntryFormat LedgerFormats[]= { { "AccountRoot", ltACCOUNT_ROOT, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, + { S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(LastReceive), STI_UINT32, SOE_REQUIRED, 0 }, diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 579fa47b53..31816e1174 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -3635,6 +3635,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // Create the account. sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); + sleDst->setIFieldAccount(sfAccount, uDstAccountID); sleDst->setIFieldU32(sfSequence, 1); } else @@ -3929,6 +3930,7 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti // Create the account. sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); + sleDst->setIFieldAccount(sfAccount, uDstAccountID); sleDst->setIFieldU32(sfSequence, 1); sleDst->setIFieldAmount(sfBalance, saAmount); sleDst->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); From acb4502a045787ef65af7463c6bcf6c1981b8333 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 23 Aug 2012 13:26:53 -0700 Subject: [PATCH 104/426] Work toward rippling through offers. --- src/Ledger.cpp | 11 +++- src/SerializedTypes.h | 14 ++++- src/TransactionEngine.cpp | 110 +++++++++++++++++++++++++++++--------- 3 files changed, 106 insertions(+), 29 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 6239115cc4..b6b7eedb0c 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -754,7 +754,16 @@ uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uT s.add160(uTakerPaysIssuerID); // 20 s.add160(uTakerGetsIssuerID); // 20 - return getQualityIndex(s.getSHA512Half()); // Return with quality 0. + uint256 uBaseIndex = getQualityIndex(s.getSHA512Half()); // Return with quality 0. + + Log(lsINFO) << str(boost::format("getBookBase(%s,%s,%s,%s) = %s") + % STAmount::createHumanCurrency(uTakerPaysCurrency) + % NewcoinAddress::createHumanAccountID(uTakerPaysIssuerID) + % STAmount::createHumanCurrency(uTakerGetsCurrency) + % NewcoinAddress::createHumanAccountID(uTakerGetsIssuerID) + % uBaseIndex.ToString()); + + return uBaseIndex; } uint256 Ledger::getDirNodeIndex(const uint256& uDirRoot, const uint64 uNodeIndex) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index f076af8708..46439587a4 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -261,8 +261,8 @@ public: : SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false) { ; } - STAmount(const uint160& currency, uint64 v = 0, int off = 0) - : mCurrency(currency), mValue(v), mOffset(off), mIsNegative(false) + STAmount(const uint160& uCurrency, uint64 uV=0, int iOff=0, bool bNegative=false) + : mCurrency(uCurrency), mValue(uV), mOffset(iOff), mIsNegative(bNegative) { canonicalize(); } STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0, bool isNeg = false) : @@ -274,6 +274,16 @@ public: static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) { return std::auto_ptr(construct(sit, name)); } + static STAmount saFromRate(uint64 uV = 0) + { + return STAmount(CURRENCY_ONE, uV, -9, false); + } + + static STAmount saFromSigned(const uint160& uCurrency, int64 iV=0, int iOff=0) + { + return STAmount(uCurrency, iV < 0 ? -iV : iV, iOff, iV < 0); + } + int getLength() const { return mIsNative ? 8 : 28; } SerializedTypeID getSType() const { return STI_AMOUNT; } std::string getText() const; diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 31816e1174..b1d18ff3bb 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -149,15 +149,25 @@ uint32 TransactionEngine::rippleTransferRate(const uint160& uIssuerID) { SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uIssuerID)); - return sleAccount->getIFieldPresent(sfTransferRate) - ? sleAccount->getIFieldU32(sfTransferRate) - : QUALITY_ONE; + uint32 uQuality = sleAccount && sleAccount->getIFieldPresent(sfTransferRate) + ? sleAccount->getIFieldU32(sfTransferRate) + : QUALITY_ONE; + + Log(lsINFO) << 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 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) { - uint32 uQualityIn = QUALITY_ONE; + uint32 uQualityIn = QUALITY_ONE; + SLE::pointer sleRippleState; if (uToAccountID == uFromAccountID) { @@ -165,7 +175,7 @@ uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uin } else { - SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); + sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); if (sleRippleState) { @@ -177,12 +187,17 @@ uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uin if (!uQualityIn) uQualityIn = 1; } - else - { - assert(false); - } } + Log(lsINFO) << str(boost::format("rippleQualityIn: uToAccountID=%s uFromAccountID=%s uCurrencyID=%s bLine=%d uQualityIn=%f") + % NewcoinAddress::createHumanAccountID(uToAccountID) + % NewcoinAddress::createHumanAccountID(uFromAccountID) + % STAmount::createHumanCurrency(uCurrencyID) + % !!sleRippleState + % (uQualityIn/1000000000.0)); + + assert(uToAccountID == uFromAccountID || !!sleRippleState); + return uQualityIn; } @@ -1915,18 +1930,30 @@ bool TransactionEngine::calcNodeOfferRev( const uint160& uNxtIssuerID = pnNxt.uIssuerID; const uint160& uNxtAccountID = pnNxt.uAccountID; - const STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9); + const STAmount saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID)); uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); const uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); + Log(lsINFO) << str(boost::format("calcNodeOfferRev> uIndex=%d prv=%s/%s cur=%s/%s nxt=%s/%s saTransferRate=%s") + % uIndex + % STAmount::createHumanCurrency(uPrvCurrencyID) + % NewcoinAddress::createHumanAccountID(uPrvIssuerID) + % STAmount::createHumanCurrency(uCurCurrencyID) + % NewcoinAddress::createHumanAccountID(uCurIssuerID) + % STAmount::createHumanCurrency(uNxtCurrencyID) + % NewcoinAddress::createHumanAccountID(uNxtIssuerID) + % saTransferRate.getText()); + STAmount& saPrvDlvReq = pnPrv.saRevDeliver; // To be adjusted. STAmount saPrvDlvAct; const STAmount& saCurDlvReq = pnCur.saRevDeliver; // Reverse driver. STAmount saCurDlvAct; + Log(lsINFO) << str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString()); + while (!!uDirectTip // Have a quality. && saCurDlvAct != saCurDlvReq) { @@ -1934,6 +1961,8 @@ bool TransactionEngine::calcNodeOfferRev( if (bAdvance) { uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd); + + Log(lsINFO) << str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString()); } else { @@ -1953,6 +1982,8 @@ bool TransactionEngine::calcNodeOfferRev( while (saCurDlvReq != saCurDlvAct // Have not met request. && dirNext(uDirectTip, sleDirectDir, uEntry, uCurIndex)) { + Log(lsINFO) << str(boost::format("calcNodeOfferRev: uCurIndex=%s") % uCurIndex.ToString()); + SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex); uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); STAmount saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); @@ -2085,6 +2116,11 @@ bool TransactionEngine::calcNodeOfferRev( bSuccess = true; } + Log(lsINFO) << str(boost::format("calcNodeOfferRev< uIndex=%d saPrvDlvReq=%s bSuccess=%d") + % uIndex + % saPrvDlvReq.getText() + % bSuccess); + return bSuccess; } @@ -2108,7 +2144,7 @@ bool TransactionEngine::calcNodeOfferFwd( const uint160& uNxtIssuerID = pnNxt.uIssuerID; const uint160& uNxtAccountID = pnNxt.uAccountID; - const STAmount saTransferRate = STAmount(CURRENCY_ONE, rippleTransferRate(uCurIssuerID), -9); + const STAmount saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID)); uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); const uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); @@ -2601,8 +2637,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point const bool bPrvAccount = !uIndex || !!(pnPrv.uFlags & STPathElement::typeAccount); const bool bNxtAccount = uIndex == uLast || !!(pnNxt.uFlags & STPathElement::typeAccount); - const uint160& uPrvAccountID = pnPrv.uAccountID; const uint160& uCurAccountID = pnCur.uAccountID; + const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. const uint160& uCurrencyID = pnCur.uCurrencyID; @@ -2614,6 +2650,18 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point const STAmount saPrvBalance = uIndex && bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); const STAmount saPrvLimit = uIndex && bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); + Log(lsINFO) << str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvBalance=%s saPrvLimit=%s") + % uIndex + % uLast + % NewcoinAddress::createHumanAccountID(uPrvAccountID) + % NewcoinAddress::createHumanAccountID(uCurAccountID) + % NewcoinAddress::createHumanAccountID(uNxtAccountID) + % STAmount::createHumanCurrency(uCurrencyID) + % uQualityIn + % uQualityOut + % saPrvBalance.getText() + % saPrvLimit.getText()); + const STAmount saPrvRedeemReq = bPrvRedeem && saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); STAmount& saPrvRedeemAct = pnPrv.saRevRedeem; @@ -2621,7 +2669,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point STAmount& saPrvIssueAct = pnPrv.saRevIssue; // For !bPrvAccount - const STAmount saPrvDeliverReq = STAmount(uCurrencyID, -1); // Unlimited. + const STAmount saPrvDeliverReq = STAmount::saFromSigned(uCurrencyID, -1); // Unlimited. STAmount& saPrvDeliverAct = pnPrv.saRevDeliver; // For bNxtAccount @@ -2629,20 +2677,18 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point STAmount saCurRedeemAct(saCurRedeemReq.getCurrency()); const STAmount& saCurIssueReq = pnCur.saRevIssue; - STAmount saCurIssueAct(saCurIssueReq.getCurrency()); // Track progress. + STAmount saCurIssueAct(saCurIssueReq.getCurrency()); // Track progress. // For !bNxtAccount const STAmount& saCurDeliverReq = pnCur.saRevDeliver; STAmount saCurDeliverAct(saCurDeliverReq.getCurrency()); // For uIndex == uLast - const STAmount& saCurWantedReq = pspCur->saOutReq; // XXX Credit limits? + const STAmount& saCurWantedReq = pspCur->saOutReq; // XXX Credit limits? // STAmount saPrvDeliverReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; STAmount saCurWantedAct(saCurWantedReq.getCurrency()); - Log(lsINFO) << str(boost::format("calcNodeAccountRev> uIndex=%d/%d saPrvRedeemReq=%s/%s saPrvIssueReq=%s/%s saCurWantedReq=%s/%s") - % uIndex - % uLast + Log(lsINFO) << str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s/%s saPrvIssueReq=%s/%s saCurWantedReq=%s/%s") % saPrvRedeemReq.getText() % saPrvRedeemReq.getHumanCurrency() % saPrvIssueReq.getText() @@ -3188,7 +3234,8 @@ bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssu #endif bValid = pushNode( - 0, // Offer + STPathElement::typeCurrency // Offer. + | STPathElement::typeIssuer, ACCOUNT_ONE, // Placeholder for offers. uCurrencyID, // The offer's output is what is now wanted. uIssuerID); @@ -3417,14 +3464,21 @@ PathState::PathState( bValid = pushNode( STPathElement::typeAccount // Last node is always an account. | STPathElement::typeRedeem // Does not matter just pass error check. - | STPathElement::typeIssue, // Does not matter just pass error check. + | STPathElement::typeIssue // Does not matter just pass error check. + | STPathElement::typeCurrency + | STPathElement::typeIssuer, uReceiverID, // Receive to output uOutCurrencyID, // Desired currency uOutIssuerID); } } - Log(lsINFO) << "PathState: " << getJson(); + Log(lsINFO) << str(boost::format("PathState: in=%s/%s out=%s/%s %s") + % STAmount::createHumanCurrency(uInCurrencyID) + % NewcoinAddress::createHumanAccountID(uInIssuerID) + % STAmount::createHumanCurrency(uOutCurrencyID) + % NewcoinAddress::createHumanAccountID(uOutIssuerID) + % getJson()); } Json::Value PathState::getJson() const @@ -3517,6 +3571,8 @@ bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur, const bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount); bool bValid; + Log(lsINFO) << str(boost::format("calcNode> uIndex=%d") % uIndex); + // Do current node reverse. bValid = bCurAccount ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) @@ -3536,6 +3592,8 @@ bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur, : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); } + Log(lsINFO) << str(boost::format("calcNode< uIndex=%d bValid=%d") % uIndex % bValid); + return bValid; } @@ -3553,14 +3611,14 @@ void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) assert(pspCur->vpnNodes.size() >= 2); - bool bValid = calcNode(uLast, pspCur, iPaths == 1); + pspCur->bValid = calcNode(uLast, pspCur, iPaths == 1); Log(lsINFO) << "pathNext: bValid=" - << bValid + << pspCur->bValid << " saOutAct=" << pspCur->saOutAct.getText() << " saInAct=" << pspCur->saInAct.getText(); - pspCur->uQuality = bValid + pspCur->uQuality = pspCur->bValid ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. : 0; // Mark path as inactive. @@ -3614,7 +3672,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction return tenINVALID; } - SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); + SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); if (!sleDst) { // Destination account does not exist. @@ -3644,7 +3702,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction } // XXX Should bMax be sufficient to imply ripple? - bool bRipple = bPaths || bMax || !saDstAmount.isNative(); + bool bRipple = bPaths || bMax || !saDstAmount.isNative(); if (!bRipple) { From 27490e1f0b1a9bfcc5d2d896f4ee557f1507ebcc Mon Sep 17 00:00:00 2001 From: jed Date: Thu, 23 Aug 2012 14:01:39 -0700 Subject: [PATCH 105/426] pathfinding --- src/OrderBook.cpp | 19 +++++ src/OrderBook.h | 33 ++++++++ src/OrderBookDB.cpp | 56 ++++++++++++ src/OrderBookDB.h | 30 +++++++ src/Pathfinder.cpp | 202 ++++++++++++++++++++++++++++++++++++++++++++ src/Pathfinder.h | 52 ++++++++++++ 6 files changed, 392 insertions(+) create mode 100644 src/OrderBook.cpp create mode 100644 src/OrderBook.h create mode 100644 src/OrderBookDB.cpp create mode 100644 src/OrderBookDB.h create mode 100644 src/Pathfinder.cpp create mode 100644 src/Pathfinder.h diff --git a/src/OrderBook.cpp b/src/OrderBook.cpp new file mode 100644 index 0000000000..e3e41f4a10 --- /dev/null +++ b/src/OrderBook.cpp @@ -0,0 +1,19 @@ +#include "OrderBook.h" +#include "Ledger.h" + +OrderBook::pointer OrderBook::newOrderBook(SerializedLedgerEntry::pointer ledgerEntry) +{ + if(ledgerEntry->getType() != ltOFFER) return( OrderBook::pointer()); + + return( OrderBook::pointer(new OrderBook(ledgerEntry))); +} + +OrderBook::OrderBook(SerializedLedgerEntry::pointer ledgerEntry) +{ + mCurrencyIn=ledgerEntry->getIValueFieldAmount(sfTakerGets).getCurrency(); + mCurrencyOut=ledgerEntry->getIValueFieldAmount(sfTakerPays).getCurrency(); + mIssuerIn=ledgerEntry->getIValueFieldAccount(sfGetsIssuer).getAccountID(); + mIssuerOut=ledgerEntry->getIValueFieldAccount(sfPaysIssuer).getAccountID(); + + mBookBase=Ledger::getBookBase(mCurrencyOut,mIssuerOut,mCurrencyIn,mIssuerIn); +} \ No newline at end of file diff --git a/src/OrderBook.h b/src/OrderBook.h new file mode 100644 index 0000000000..1d0262b278 --- /dev/null +++ b/src/OrderBook.h @@ -0,0 +1,33 @@ +#include "SerializedLedger.h" +#include +/* + Encapsulates the SLE for an orderbook +*/ +class OrderBook +{ + uint256 mBookBase; + + uint160 mCurrencyIn; + uint160 mCurrencyOut; + uint160 mIssuerIn; + uint160 mIssuerOut; + + //SerializedLedgerEntry::pointer mLedgerEntry; + OrderBook(SerializedLedgerEntry::pointer ledgerEntry); // For accounts in a ledger +public: + typedef boost::shared_ptr pointer; + + // returns NULL if ledgerEntry doesn't point to an orderbook + static OrderBook::pointer newOrderBook(SerializedLedgerEntry::pointer ledgerEntry); + + uint256& getBookBase(){ return(mBookBase); } + uint160& getCurrencyIn(){ return(mCurrencyIn); } + uint160& getCurrencyOut(){ return(mCurrencyOut); } + uint160& getIssuerIn(){ return(mIssuerIn); } + uint160& getIssuerOut(){ return(mIssuerOut); } + + // looks through the best offers to see how much it would cost to take the given amount + STAmount& getTakePrice(STAmount& takeAmount); + + +}; \ No newline at end of file diff --git a/src/OrderBookDB.cpp b/src/OrderBookDB.cpp new file mode 100644 index 0000000000..4f49f01338 --- /dev/null +++ b/src/OrderBookDB.cpp @@ -0,0 +1,56 @@ +#include "OrderBookDB.h" +#include "Log.h" +#include + + +// TODO: this would be way faster if we could just look under the order dirs +OrderBookDB::OrderBookDB(Ledger::pointer ledger) +{ + // walk through the entire ledger looking for orderbook entries + uint256 currentIndex=ledger->getFirstLedgerIndex(); + while(currentIndex.isNonZero()) + { + SLE::pointer entry=ledger->getSLE(currentIndex); + + OrderBook::pointer book=OrderBook::newOrderBook(entry); + if(book) + { + if( mKnownMap.find(book->getBookBase()) != mKnownMap.end() ) + { + mKnownMap[book->getBookBase()]=true; + + if(!book->getCurrencyIn()) + { // XNS + mXNSOrders.push_back(book); + }else + { + mIssuerMap[book->getIssuerIn()].push_back(book); + } + } + } + + currentIndex=ledger->getNextLedgerIndex(currentIndex); + } +} + +// return list of all orderbooks that want IssuerID +std::vector& OrderBookDB::getBooks(const uint160& issuerID) +{ + if( mIssuerMap.find(issuerID) == mIssuerMap.end() ) return mEmptyVector; + else return( mIssuerMap[issuerID]); +} + +// return list of all orderbooks that want this issuerID and currencyID +void OrderBookDB::getBooks(const uint160& issuerID, const uint160& currencyID, std::vector& bookRet) +{ + if( mIssuerMap.find(issuerID) == mIssuerMap.end() ) + { + BOOST_FOREACH(OrderBook::pointer book, mIssuerMap[issuerID]) + { + if(book->getCurrencyIn()==currencyID) + { + bookRet.push_back(book); + } + } + } +} \ No newline at end of file diff --git a/src/OrderBookDB.h b/src/OrderBookDB.h new file mode 100644 index 0000000000..c8e598d186 --- /dev/null +++ b/src/OrderBookDB.h @@ -0,0 +1,30 @@ +#include "Ledger.h" +#include "OrderBook.h" + +/* +we can eventually make this cached and just update it as transactions come in. +But for now it is probably faster to just generate it each time +*/ + +class OrderBookDB +{ + std::vector mEmptyVector; + std::vector mXNSOrders; + std::map > mIssuerMap; + + std::map mKnownMap; + +public: + OrderBookDB(Ledger::pointer ledger); + + // return list of all orderbooks that want XNS + std::vector& getXNSInBooks(){ return mXNSOrders; } + // return list of all orderbooks that want IssuerID + std::vector& getBooks(const uint160& issuerID); + // return list of all orderbooks that want this issuerID and currencyID + void getBooks(const uint160& issuerID, const uint160& currencyID, std::vector& bookRet); + + // returns the best rate we can find + float getPrice(uint160& currencyIn,uint160& currencyOut); + +}; \ No newline at end of file diff --git a/src/Pathfinder.cpp b/src/Pathfinder.cpp new file mode 100644 index 0000000000..c1c5d86b30 --- /dev/null +++ b/src/Pathfinder.cpp @@ -0,0 +1,202 @@ +#include "Pathfinder.h" +#include "Application.h" +#include "RippleLines.h" +#include "Log.h" +#include + +/* +JED: V IIII + +we just need to find a succession of the highest quality paths there until we find enough width + +Don't do branching within each path + +We have a list of paths we are working on but how do we compare the ones that are terminating in a different currency? + +Loops + +TODO: what is a good way to come up with multiple paths? + Maybe just change the sort criteria? + first a low cost one and then a fat short one? + + +OrderDB: + getXNSOffers(); + + // return list of all orderbooks that want XNS + // return list of all orderbooks that want IssuerID + // return list of all orderbooks that want this issuerID and currencyID +*/ + +/* +Test sending to XNS +Test XNS to XNS +Test offer in middle +Test XNS to USD +Test USD to EUR +*/ + + +// we sort the options by: +// cost of path +// length of path +// width of path +// correct currency at the end + + + +bool sortPathOptions(PathOption::pointer first, PathOption::pointer second) +{ + if(first->mTotalCostmTotalCost) return(true); + if(first->mTotalCost>second->mTotalCost) return(false); + + if(first->mCorrectCurrency && !second->mCorrectCurrency) return(true); + if(!first->mCorrectCurrency && second->mCorrectCurrency) return(false); + + if(first->mPath.getElementCount()mPath.getElementCount()) return(true); + if(first->mPath.getElementCount()>second->mPath.getElementCount()) return(false); + + if(first->mMinWidthmMinWidth) return true; + + return false; +} + +PathOption::PathOption(uint160& srcAccount,uint160& srcCurrencyID,const uint160& dstCurrencyID) +{ + mCurrentAccount=srcAccount; + mCurrencyID=srcCurrencyID; + mCorrectCurrency=(srcCurrencyID==dstCurrencyID); + mQuality=0; + mMinWidth=STAmount(dstCurrencyID,99999,80); // this will get lowered when we convert back to the correct currency +} + +PathOption::PathOption(PathOption::pointer other) +{ + // TODO: +} + + +Pathfinder::Pathfinder(NewcoinAddress& srcAccountID, NewcoinAddress& dstAccountID, uint160& srcCurrencyID, STAmount dstAmount) : + mSrcAccountID(srcAccountID.getAccountID()) , mDstAccountID(dstAccountID.getAccountID()), mSrcCurrencyID(srcCurrencyID) , mDstAmount(dstAmount), mOrderBook(theApp->getMasterLedger().getCurrentLedger()) +{ + mLedger=theApp->getMasterLedger().getCurrentLedger(); +} + +bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet) +{ + if(mLedger) + { + PathOption::pointer head(new PathOption(mSrcAccountID,mSrcCurrencyID,mDstAmount.getCurrency())); + addOptions(head); + + for(int n=0; n tempPaths=mBuildingPaths; + mBuildingPaths.clear(); + BOOST_FOREACH(PathOption::pointer path,tempPaths) + { + addOptions(path); + } + if(checkComplete(retPathSet)) return(true); + } + + } + + return(false); +} + +bool Pathfinder::checkComplete(STPathSet& retPathSet) +{ + if(mCompletePaths.size()) + { // TODO: look through these and pick the most promising + int count=0; + BOOST_FOREACH(PathOption::pointer pathOption,mCompletePaths) + { + retPathSet.addPath(pathOption->mPath); + count++; + if(count>2) return(true); + } + return(true); + } + return(false); +} + + +// get all the options from this accountID +// if source is XNS +// every offer that wants XNS +// else +// every ripple line that starts with the source currency +// every offer that we can take that wants the source currency + +void Pathfinder::addOptions(PathOption::pointer tail) +{ + if(!tail->mCurrencyID) + { // source XNS + BOOST_FOREACH(OrderBook::pointer book,mOrderBook.getXNSInBooks()) + { + PathOption::pointer pathOption(new PathOption(tail)); + + STPathElement ele(uint160(), book->getCurrencyOut(), book->getIssuerOut()); + pathOption->mPath.addElement(ele); + + pathOption->mCurrentAccount=book->getIssuerOut(); + pathOption->mCurrencyID=book->getCurrencyOut(); + addPathOption(pathOption); + } + }else + { // ripple + RippleLines rippleLines(tail->mCurrentAccount); + BOOST_FOREACH(RippleState::pointer line,rippleLines.getLines()) + { + // TODO: make sure we can move in the correct direction + STAmount balance=line->getBalance(); + if(balance.getCurrency()==tail->mCurrencyID) + { // we have a ripple line from the tail to somewhere else + PathOption::pointer pathOption(new PathOption(tail)); + + STPathElement ele(line->getAccountIDPeer().getAccountID(), uint160(),uint160()); + pathOption->mPath.addElement(ele); + + + pathOption->mCurrentAccount=line->getAccountIDPeer().getAccountID(); + addPathOption(pathOption); + } + } + + // every offer that wants the source currency + std::vector books; + mOrderBook.getBooks(tail->mCurrentAccount, tail->mCurrencyID, books); + + BOOST_FOREACH(OrderBook::pointer book,books) + { + PathOption::pointer pathOption(new PathOption(tail)); + + STPathElement ele(uint160(), book->getCurrencyOut(), book->getIssuerOut()); + pathOption->mPath.addElement(ele); + + pathOption->mCurrentAccount=book->getIssuerOut(); + pathOption->mCurrencyID=book->getCurrencyOut(); + addPathOption(pathOption); + } + } +} + +void Pathfinder::addPathOption(PathOption::pointer pathOption) +{ + if(pathOption->mCurrencyID==mDstAmount.getCurrency()) + { + pathOption->mCorrectCurrency=true; + + if(pathOption->mCurrentAccount==mDstAccountID) + { // this path is complete + mCompletePaths.push_back(pathOption); + }else mBuildingPaths.push_back(pathOption); + }else + { + pathOption->mCorrectCurrency=false; + mBuildingPaths.push_back(pathOption); + } +} + + diff --git a/src/Pathfinder.h b/src/Pathfinder.h new file mode 100644 index 0000000000..5a7a4345a1 --- /dev/null +++ b/src/Pathfinder.h @@ -0,0 +1,52 @@ +#include "SerializedTypes.h" +#include "NewcoinAddress.h" +#include "OrderBookDB.h" +#include + +/* this is a very simple implementation. This can be made way better. +We are simply flooding from the start. And doing an exhaustive search of all paths under maxSearchSteps. An easy improvement would be to flood from both directions +*/ +class PathOption +{ +public: + typedef boost::shared_ptr pointer; + + STPath mPath; + bool mCorrectCurrency; // for the sorting + uint160 mCurrencyID; // what currency we currently have at the end of the path + uint160 mCurrentAccount; // what account is at the end of the path + int mTotalCost; // in send currency + STAmount mMinWidth; // in dest currency + float mQuality; + + PathOption(uint160& srcAccount,uint160& srcCurrencyID,const uint160& dstCurrencyID); + PathOption(PathOption::pointer other); +}; + +class Pathfinder +{ + uint160 mSrcAccountID; + uint160 mDstAccountID; + STAmount mDstAmount; + uint160 mSrcCurrencyID; + + OrderBookDB mOrderBook; + Ledger::pointer mLedger; + + + std::list mBuildingPaths; + std::list mCompletePaths; + + void addOptions(PathOption::pointer tail); + + // returns true if any building paths are now complete? + bool checkComplete(STPathSet& retPathSet); + + void addPathOption(PathOption::pointer pathOption); + +public: + Pathfinder(NewcoinAddress& srcAccountID, NewcoinAddress& dstAccountID, uint160& srcCurrencyID, STAmount dstAmount); + + // returns false if there is no path. otherwise fills out retPath + bool findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet); +}; \ No newline at end of file From e4b8d874e7e66626b980cd679d3b2390ea91bf33 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 23 Aug 2012 14:55:03 -0700 Subject: [PATCH 106/426] Encode issuer in STAmount. Breaking protocol and db version change. --- src/Amount.cpp | 32 ++++++++--- src/LedgerFormats.cpp | 4 +- src/SerializedObject.h | 2 - src/Transaction.cpp | 6 -- src/TransactionEngine.cpp | 111 ++++++++++++------------------------- src/TransactionFormats.cpp | 4 +- src/Version.h | 14 ++--- 7 files changed, 68 insertions(+), 105 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 60a4792fa4..1dfd549e47 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -288,6 +288,7 @@ void STAmount::add(Serializer& s) const s.add64(mValue | (static_cast(mOffset + 512 + 256 + 97) << (64 - 10))); s.add160(mCurrency); + s.add160(mIssuer); } } @@ -334,25 +335,38 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) return new STAmount(name, value, true); // negative } - uint160 currency = sit.get160(); - if (!currency) + uint160 uCurrencyID = sit.get160(); + if (!uCurrencyID) throw std::runtime_error("invalid native currency"); + uint160 uIssuerID = sit.get160(); + int offset = static_cast(value >> (64 - 10)); // 10 bits for the offset, sign and "not native" flag value &= ~(1023ull << (64-10)); - if (value == 0) + STAmount* sapResult; + + if (value) + { + bool isNegative = (offset & 256) == 0; + offset = (offset & 255) - 97; // center the range + if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset)) + throw std::runtime_error("invalid currency value"); + + sapResult = new STAmount(name, uCurrencyID, value, offset, isNegative); + } + else { if (offset != 512) throw std::runtime_error("invalid currency value"); - return new STAmount(name, currency); + + sapResult = new STAmount(name, uCurrencyID); } - bool isNegative = (offset & 256) == 0; - offset = (offset & 255) - 97; // center the range - if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset)) - throw std::runtime_error("invalid currency value"); - return new STAmount(name, currency, value, offset, isNegative); + if (sapResult) + sapResult->setIssuer(uIssuerID); + + return sapResult; } int64 STAmount::getSNValue() const diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index a0f0271d78..a5662004e7 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -57,9 +57,7 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(OwnerNode), STI_UINT64, SOE_REQUIRED, 0 }, { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(PaysIssuer), STI_ACCOUNT, SOE_IFFLAG, 1 }, - { S_FIELD(GetsIssuer), STI_ACCOUNT, SOE_IFFLAG, 2 }, - { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 4 }, + { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 8ee7a6b4c8..fde0d7ec3f 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -50,7 +50,6 @@ enum SOE_Field sfFlags, sfGenerator, sfGeneratorID, - sfGetsIssuer, sfHash, sfHighID, sfHighLimit, @@ -84,7 +83,6 @@ enum SOE_Field sfOfferSequence, sfOwnerNode, sfPaths, - sfPaysIssuer, sfPubKey, sfPublishHash, sfPublishSize, diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 224c65d4d6..38aec72865 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -362,12 +362,6 @@ Transaction::pointer Transaction::setOfferCreate( mTransaction->setITFieldAmount(sfTakerPays, saTakerPays); mTransaction->setITFieldAmount(sfTakerGets, saTakerGets); - if (!saTakerPays.isNative()) - mTransaction->setITFieldAccount(sfPaysIssuer, saTakerPays.getIssuer()); - - if (!saTakerGets.isNative()) - mTransaction->setITFieldAccount(sfGetsIssuer, saTakerGets.getIssuer()); - if (uExpiration) mTransaction->setITFieldU32(sfExpiration, uExpiration); diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index b1d18ff3bb..566a463d33 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -251,7 +251,7 @@ STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint16 { STAmount saAmount; - if (uCurrencyID.isZero()) + if (!uCurrencyID) { SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uAccountID)); @@ -397,7 +397,7 @@ STAmount TransactionEngine::rippleSend(const uint160& uSenderID, const uint160& STAmount saTransitFee = rippleTransferFee(uSenderID, uReceiverID, uIssuerID, saAmount); - saActual = saTransitFee.isZero() ? saAmount : saAmount+saTransitFee; + saActual = !saTransitFee ? saAmount : saAmount+saTransitFee; saActual.setIssuer(uIssuerID); // XXX Make sure this done in + above. @@ -833,7 +833,7 @@ SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint25 { SLE::pointer sleEntry; - if (!uIndex.isZero()) + if (!!uIndex) { LedgerEntryAction action; sleEntry = mNodes.getEntry(uIndex, action); @@ -852,7 +852,7 @@ SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint25 SLE::pointer TransactionEngine::entryCreate(LedgerEntryType letType, const uint256& uIndex) { - assert(!uIndex.isZero()); + assert(!!uIndex); SLE::pointer sleNew = boost::make_shared(letType); sleNew->setIndex(uIndex); @@ -1030,7 +1030,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran if (terSUCCESS == terResult && (params & tepNO_CHECK_FEE) == tepNONE) { - if (!saCost.isZero()) + if (!!saCost) { if (saPaid < saCost) { @@ -1041,7 +1041,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } else { - if (!saPaid.isZero()) + if (!!saPaid) { // Transaction is malformed. Log(lsWARNING) << "applyTransaction: fee not allowed"; @@ -1168,7 +1168,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // Deduct the fee, so it's not available during the transaction. // Will only write the account back, if the transaction succeeds. - if (terSUCCESS != terResult || saCost.isZero()) + if (terSUCCESS != terResult || !saCost) { nothing(); } @@ -1191,7 +1191,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { nothing(); } - else if (!saCost.isZero()) + else if (!!saCost) { uint32 a_seq = mTxnAccount->getIFieldU32(sfSequence); @@ -1340,7 +1340,7 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact { uint128 uHash = txn.getITFieldH128(sfEmailHash); - if (uHash.isZero()) + if (!uHash) { Log(lsINFO) << "doAccountSet: unset email hash"; @@ -1362,7 +1362,7 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact { uint256 uHash = txn.getITFieldH256(sfWalletLocator); - if (uHash.isZero()) + if (!uHash) { Log(lsINFO) << "doAccountSet: unset wallet locator"; @@ -1459,7 +1459,7 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact uint256 uHash = txn.getITFieldH256(sfPublishHash); uint32 uSize = txn.getITFieldU32(sfPublishSize); - if (uHash.isZero()) + if (!uHash) { Log(lsINFO) << "doAccountSet: unset publish"; @@ -1535,16 +1535,16 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti { // A line exists in one or more directions. #if 0 - if (saLimitAmount.isZero()) + if (!saLimitAmount) { // Zeroing line. uint160 uLowID = sleRippleState->getIValueFieldAccount(sfLowID).getAccountID(); uint160 uHighID = sleRippleState->getIValueFieldAccount(sfHighID).getAccountID(); bool bLow = uLowID == uSrcAccountID; bool bHigh = uLowID == uDstAccountID; - bool bBalanceZero = sleRippleState->getIValueFieldAmount(sfBalance).isZero(); + bool bBalanceZero = !sleRippleState->getIValueFieldAmount(sfBalance); STAmount saDstLimit = sleRippleState->getIValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit); - bool bDstLimitZero = saDstLimit.isZero(); + bool bDstLimitZero = !saDstLimit; assert(bLow || bHigh); @@ -1595,7 +1595,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti Log(lsINFO) << "doCreditSet: Modifying ripple line: bDelIndex=" << bDelIndex; } // Line does not exist. - else if (saLimitAmount.isZero()) + else if (!saLimitAmount) { Log(lsINFO) << "doCreditSet: Redundant: Setting non-existant ripple line to 0."; @@ -1829,12 +1829,6 @@ void TransactionEngine::calcOfferBridgeNext( STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); - if (sleOffer->getIFieldPresent(sfGetsIssuer)) - saOfferPays.setIssuer(sleOffer->getIValueFieldAccount(sfGetsIssuer).getAccountID()); - - if (sleOffer->getIFieldPresent(sfPaysIssuer)) - saOfferGets.setIssuer(sleOffer->getIValueFieldAccount(sfPaysIssuer).getAccountID()); - if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) { // Offer is expired. @@ -1986,14 +1980,8 @@ bool TransactionEngine::calcNodeOfferRev( SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex); uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); - STAmount saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); - STAmount saCurOfrIn = sleCurOfr->getIValueFieldAmount(sfTakerPays); - // XXX Move issuer into STAmount - if (sleCurOfr->getIFieldPresent(sfGetsIssuer)) - saCurOfrOutReq.setIssuer(sleCurOfr->getIValueFieldAccount(sfGetsIssuer).getAccountID()); - - if (sleCurOfr->getIFieldPresent(sfPaysIssuer)) - saCurOfrIn.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID()); + const STAmount& saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); + // UNUSED? const STAmount& saCurOfrIn = sleCurOfr->getIValueFieldAmount(sfTakerPays); STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. @@ -2070,10 +2058,7 @@ bool TransactionEngine::calcNodeOfferRev( // YYY This could combine offers with the same fee before doing math. SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex); uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); - STAmount saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); - // XXX Move issuer into STAmount - if (sleNxtOfr->getIFieldPresent(sfPaysIssuer)) - saNxtOfrIn.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID()); + const STAmount& saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID ? saOne @@ -2183,18 +2168,11 @@ bool TransactionEngine::calcNodeOfferFwd( { SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex); uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); - STAmount saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); - STAmount saCurOfrInReq = sleCurOfr->getIValueFieldAmount(sfTakerPays); - // XXX Move issuer into STAmount - if (sleCurOfr->getIFieldPresent(sfGetsIssuer)) - saCurOfrOutReq.setIssuer(sleCurOfr->getIValueFieldAccount(sfGetsIssuer).getAccountID()); - - if (sleCurOfr->getIFieldPresent(sfPaysIssuer)) - saCurOfrInReq.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID()); + const STAmount& saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); + const STAmount& saCurOfrInReq = sleCurOfr->getIValueFieldAmount(sfTakerPays); STAmount saCurOfrInAct; STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. - - saCurOfrInReq = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); + STAmount saCurOfrInMax = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); if (!!uNxtAccountID) { @@ -2202,10 +2180,10 @@ bool TransactionEngine::calcNodeOfferFwd( const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtAccountID == uCurIssuerID ? saOne - : saTransferRate; + : saTransferRate; const bool bFee = saFeeRate != saOne; - const STAmount saOutPass = STAmount::divide(saCurOfrInReq, saOfrRate, uCurCurrencyID); + const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID); const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. const STAmount saOutCost = MIN( bFee @@ -2255,17 +2233,14 @@ bool TransactionEngine::calcNodeOfferFwd( // YYY This could combine offers with the same fee before doing math. SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex); const uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); - STAmount saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); - // XXX Move issuer into STAmount - if (sleNxtOfr->getIFieldPresent(sfPaysIssuer)) - saNxtOfrIn.setIssuer(sleCurOfr->getIValueFieldAccount(sfPaysIssuer).getAccountID()); + const STAmount& saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID ? saOne : saTransferRate; const bool bFee = saFeeRate != saOne; - const STAmount saInBase = saCurOfrInReq-saCurOfrInAct; + const STAmount saInBase = saCurOfrInMax-saCurOfrInAct; const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID); STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. @@ -3772,7 +3747,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction return terOVER_LIMIT; } - if (saDstBalance.isZero()) + if (!saDstBalance) { // XXX May be able to delete indexes for credit limits which are zero. nothing(); @@ -3916,7 +3891,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // Partial payment not allowed. terResult = terPATH_PARTIAL; // XXX No effect, except unfunded and charge fee. } - else if (saPaid.isZero()) + else if (!saPaid) { // Nothing claimed. terResult = terPATH_EMPTY; // XXX No effect except unfundeds and charge fee. @@ -4022,7 +3997,7 @@ TransactionEngineResult TransactionEngine::takeOffers( STAmount& saTakerPaid, STAmount& saTakerGot) { - assert(!saTakerPays.isZero() && !saTakerGets.isZero()); + assert(!!saTakerPays && !!saTakerGets); Log(lsINFO) << "takeOffers: against book: " << uBookBase.ToString(); @@ -4091,12 +4066,6 @@ TransactionEngineResult TransactionEngine::takeOffers( STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); - if (sleOffer->getIFieldPresent(sfGetsIssuer)) - saOfferPays.setIssuer(sleOffer->getIValueFieldAccount(sfGetsIssuer).getAccountID()); - - if (sleOffer->getIFieldPresent(sfPaysIssuer)) - saOfferGets.setIssuer(sleOffer->getIValueFieldAccount(sfPaysIssuer).getAccountID()); - if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) { // Offer is expired. Delete it. @@ -4210,14 +4179,12 @@ TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransac Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); const uint32 txFlags = txn.getFlags(); const bool bPassive = !!(txFlags & tfPassive); - const uint160 uPaysIssuerID = txn.getITFieldAccount(sfPaysIssuer); - const uint160 uGetsIssuerID = txn.getITFieldAccount(sfGetsIssuer); - STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); - saTakerPays.setIssuer(uPaysIssuerID); -Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText(); + STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); - saTakerGets.setIssuer(uGetsIssuerID); +Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText(); Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); + const uint160 uPaysIssuerID = saTakerPays.getIssuer(); + const uint160 uGetsIssuerID = saTakerGets.getIssuer(); const uint32 uExpiration = txn.getITFieldU32(sfExpiration); const bool bHaveExpiration = txn.getITFieldPresent(sfExpiration); const uint32 uSequence = txn.getSequence(); @@ -4254,7 +4221,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); terResult = tenBAD_OFFER; } - else if (saTakerPays.isZero() || saTakerGets.isZero()) + else if (!saTakerPays || !saTakerGets) { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad amount"; @@ -4266,7 +4233,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); terResult = tenREDUNDANT; } - else if (saTakerPays.isNative() != uPaysIssuerID.isZero() || saTakerGets.isNative() != uGetsIssuerID.isZero()) + else if (saTakerPays.isNative() != !uPaysIssuerID || saTakerGets.isNative() != !uGetsIssuerID) { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad issuer"; @@ -4339,8 +4306,8 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); // Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); if (terSUCCESS == terResult - && !saTakerPays.isZero() // Still wanting something. - && !saTakerGets.isZero() // Still offering something. + && !!saTakerPays // Still wanting something. + && !!saTakerGets // Still offering something. && accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded. { // We need to place the remainder of the offer into its order book. @@ -4382,12 +4349,6 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); sleOffer->setIFieldU64(sfOwnerNode, uOwnerNode); sleOffer->setIFieldU64(sfBookNode, uBookNode); - if (!saTakerPays.isNative()) - sleOffer->setIFieldAccount(sfPaysIssuer, uPaysIssuerID); - - if (!saTakerGets.isNative()) - sleOffer->setIFieldAccount(sfGetsIssuer, uGetsIssuerID); - if (uExpiration) sleOffer->setIFieldU32(sfExpiration, uExpiration); diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 95a753d2dd..00318027b2 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -61,9 +61,7 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(TakerPays), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(TakerGets), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(PaysIssuer), STI_ACCOUNT, SOE_IFFLAG, 2 }, - { S_FIELD(GetsIssuer), STI_ACCOUNT, SOE_IFFLAG, 4 }, - { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 8 }, + { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 2 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, diff --git a/src/Version.h b/src/Version.h index 957327c2a0..df42303f00 100644 --- a/src/Version.h +++ b/src/Version.h @@ -4,10 +4,10 @@ // Versions // -#define SERVER_VERSION_MAJOR 0 -#define SERVER_VERSION_MINOR 4 -#define SERVER_VERSION_SUB "-a" -#define SERVER_NAME "NewCoin" +#define SERVER_VERSION_MAJOR 0 +#define SERVER_VERSION_MINOR 4 +#define SERVER_VERSION_SUB "-a" +#define SERVER_NAME "NewCoin" #define SV_STRINGIZE(x) SV_STRINGIZE2(x) #define SV_STRINGIZE2(x) #x @@ -16,11 +16,11 @@ // Version we prefer to speak: #define PROTO_VERSION_MAJOR 0 -#define PROTO_VERSION_MINOR 5 +#define PROTO_VERSION_MINOR 6 -// Version we wil speak to: +// Version we will speak to: #define MIN_PROTO_MAJOR 0 -#define MIN_PROTO_MINOR 5 +#define MIN_PROTO_MINOR 6 #define MAKE_VERSION_INT(maj,min) ((maj << 16) | min) #define GET_VERSION_MAJOR(ver) (ver >> 16) From 068b237784c7a85aeeaa8072530f5b2446aa7176 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 23 Aug 2012 14:59:03 -0700 Subject: [PATCH 107/426] Change order book for issuer in STAmount. --- src/OrderBook.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/OrderBook.cpp b/src/OrderBook.cpp index e3e41f4a10..d349609107 100644 --- a/src/OrderBook.cpp +++ b/src/OrderBook.cpp @@ -4,16 +4,20 @@ OrderBook::pointer OrderBook::newOrderBook(SerializedLedgerEntry::pointer ledgerEntry) { if(ledgerEntry->getType() != ltOFFER) return( OrderBook::pointer()); - + return( OrderBook::pointer(new OrderBook(ledgerEntry))); } OrderBook::OrderBook(SerializedLedgerEntry::pointer ledgerEntry) { - mCurrencyIn=ledgerEntry->getIValueFieldAmount(sfTakerGets).getCurrency(); - mCurrencyOut=ledgerEntry->getIValueFieldAmount(sfTakerPays).getCurrency(); - mIssuerIn=ledgerEntry->getIValueFieldAccount(sfGetsIssuer).getAccountID(); - mIssuerOut=ledgerEntry->getIValueFieldAccount(sfPaysIssuer).getAccountID(); + const STAmount saTakerGets = ledgerEntry->getIValueFieldAmount(sfTakerGets); + const STAmount saTakerPays = ledgerEntry->getIValueFieldAmount(sfTakerPays); + + mCurrencyIn = saTakerGets.getCurrency(); + mCurrencyOut = saTakerPays.getCurrency(); + mIssuerIn = saTakerGets.getIssuer(); + mIssuerOut = saTakerPays.getIssuer(); mBookBase=Ledger::getBookBase(mCurrencyOut,mIssuerOut,mCurrencyIn,mIssuerIn); -} \ No newline at end of file +} +// vim:ts=4 From 4bacf9997772cce73a0bfdd030f20e119cc2180a Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 23 Aug 2012 16:23:56 -0700 Subject: [PATCH 108/426] Use issuer from send and send_max when building paths in transaction engine. --- src/TransactionEngine.cpp | 118 ++++++++++++++++++++------------------ src/TransactionEngine.h | 28 ++++----- 2 files changed, 75 insertions(+), 71 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 566a463d33..e34387bae9 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -153,7 +153,7 @@ uint32 TransactionEngine::rippleTransferRate(const uint160& uIssuerID) ? sleAccount->getIFieldU32(sfTransferRate) : QUALITY_ONE; - Log(lsINFO) << str(boost::format("rippleTransferRate: uIssuerID=%s account_exists=%d transfer_rate=%f") + Log(lsINFO) << boost::str(boost::format("rippleTransferRate: uIssuerID=%s account_exists=%d transfer_rate=%f") % NewcoinAddress::createHumanAccountID(uIssuerID) % !!sleAccount % (uQuality/1000000000.0)); @@ -189,7 +189,7 @@ uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uin } } - Log(lsINFO) << str(boost::format("rippleQualityIn: uToAccountID=%s uFromAccountID=%s uCurrencyID=%s bLine=%d uQualityIn=%f") + Log(lsINFO) << boost::str(boost::format("rippleQualityIn: uToAccountID=%s uFromAccountID=%s uCurrencyID=%s bLine=%d uQualityIn=%f") % NewcoinAddress::createHumanAccountID(uToAccountID) % NewcoinAddress::createHumanAccountID(uFromAccountID) % STAmount::createHumanCurrency(uCurrencyID) @@ -417,7 +417,7 @@ STAmount TransactionEngine::accountSend(const uint160& uSenderID, const uint160& SLE::pointer sleSender = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uSenderID)); SLE::pointer sleReceiver = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uReceiverID)); - Log(lsINFO) << str(boost::format("accountSend> %s (%s) -> %s (%s) : %s") + Log(lsINFO) << boost::str(boost::format("accountSend> %s (%s) -> %s (%s) : %s") % NewcoinAddress::createHumanAccountID(uSenderID) % (sleSender->getIValueFieldAmount(sfBalance)).getFullText() % NewcoinAddress::createHumanAccountID(uReceiverID) @@ -427,7 +427,7 @@ STAmount TransactionEngine::accountSend(const uint160& uSenderID, const uint160& sleSender->setIFieldAmount(sfBalance, sleSender->getIValueFieldAmount(sfBalance) - saAmount); sleReceiver->setIFieldAmount(sfBalance, sleReceiver->getIValueFieldAmount(sfBalance) + saAmount); - Log(lsINFO) << str(boost::format("accountSend< %s (%s) -> %s (%s) : %s") + Log(lsINFO) << boost::str(boost::format("accountSend< %s (%s) -> %s (%s) : %s") % NewcoinAddress::createHumanAccountID(uSenderID) % (sleSender->getIValueFieldAmount(sfBalance)).getFullText() % NewcoinAddress::createHumanAccountID(uReceiverID) @@ -1076,7 +1076,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran if (!mTxnAccount) { - Log(lsTRACE) << str(boost::format("applyTransaction: Delay transaction: source account does not exist: %s") % + Log(lsTRACE) << boost::str(boost::format("applyTransaction: Delay transaction: source account does not exist: %s") % txn.getSourceAccount().humanAccountID()); terResult = terNO_ACCOUNT; @@ -1175,7 +1175,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran else if (saSrcBalance < saPaid) { Log(lsINFO) - << str(boost::format("applyTransaction: Delay: insufficent balance: balance=%s paid=%s") + << boost::str(boost::format("applyTransaction: Delay: insufficent balance: balance=%s paid=%s") % saSrcBalance.getText() % saPaid.getText()); @@ -1930,7 +1930,7 @@ bool TransactionEngine::calcNodeOfferRev( const uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); - Log(lsINFO) << str(boost::format("calcNodeOfferRev> uIndex=%d prv=%s/%s cur=%s/%s nxt=%s/%s saTransferRate=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev> uIndex=%d prv=%s/%s cur=%s/%s nxt=%s/%s saTransferRate=%s") % uIndex % STAmount::createHumanCurrency(uPrvCurrencyID) % NewcoinAddress::createHumanAccountID(uPrvIssuerID) @@ -1946,7 +1946,7 @@ bool TransactionEngine::calcNodeOfferRev( const STAmount& saCurDlvReq = pnCur.saRevDeliver; // Reverse driver. STAmount saCurDlvAct; - Log(lsINFO) << str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString()); + Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString()); while (!!uDirectTip // Have a quality. && saCurDlvAct != saCurDlvReq) @@ -1956,7 +1956,7 @@ bool TransactionEngine::calcNodeOfferRev( { uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd); - Log(lsINFO) << str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString()); + Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString()); } else { @@ -1976,7 +1976,7 @@ bool TransactionEngine::calcNodeOfferRev( while (saCurDlvReq != saCurDlvAct // Have not met request. && dirNext(uDirectTip, sleDirectDir, uEntry, uCurIndex)) { - Log(lsINFO) << str(boost::format("calcNodeOfferRev: uCurIndex=%s") % uCurIndex.ToString()); + Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uCurIndex=%s") % uCurIndex.ToString()); SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex); uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); @@ -2101,7 +2101,7 @@ bool TransactionEngine::calcNodeOfferRev( bSuccess = true; } - Log(lsINFO) << str(boost::format("calcNodeOfferRev< uIndex=%d saPrvDlvReq=%s bSuccess=%d") + Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev< uIndex=%d saPrvDlvReq=%s bSuccess=%d") % uIndex % saPrvDlvReq.getText() % bSuccess); @@ -2527,7 +2527,7 @@ void TransactionEngine::calcNodeRipple( STAmount& saPrvAct, // <-> in limit including achieved STAmount& saCurAct) // <-> out limit achieved. { - Log(lsINFO) << str(boost::format("calcNodeRipple> uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeRipple> uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s") % uQualityIn % uQualityOut % saPrvReq.getFullText() @@ -2542,7 +2542,7 @@ void TransactionEngine::calcNodeRipple( const STAmount saCur = saCurReq-saCurAct; #if 0 - Log(lsINFO) << str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCur=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCur=%s") % bPrvUnlimited % saPrv.getFullText() % saCur.getFullText()); @@ -2551,7 +2551,7 @@ void TransactionEngine::calcNodeRipple( if (uQualityIn >= uQualityOut) { // No fee. - Log(lsINFO) << str(boost::format("calcNodeRipple: No fees")); + Log(lsINFO) << boost::str(boost::format("calcNodeRipple: No fees")); STAmount saTransfer = bPrvUnlimited ? saCur : MIN(saPrv, saCur); @@ -2561,32 +2561,32 @@ void TransactionEngine::calcNodeRipple( else { // Fee. - Log(lsINFO) << str(boost::format("calcNodeRipple: Fee")); + Log(lsINFO) << boost::str(boost::format("calcNodeRipple: Fee")); uint160 uCurrencyID = saCur.getCurrency(); STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID), uQualityIn, uCurrencyID); -Log(lsINFO) << str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCurIn=%s") % bPrvUnlimited % saPrv.getFullText() % saCurIn.getFullText()); +Log(lsINFO) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCurIn=%s") % bPrvUnlimited % saPrv.getFullText() % saCurIn.getFullText()); if (bPrvUnlimited || saCurIn <= saPrv) { // All of cur. Some amount of prv. saCurAct += saCur; saPrvAct += saCurIn; -Log(lsINFO) << str(boost::format("calcNodeRipple:3c: saCurReq=%s saPrvAct=%s") % saCurReq.getFullText() % saPrvAct.getFullText()); +Log(lsINFO) << boost::str(boost::format("calcNodeRipple:3c: saCurReq=%s saPrvAct=%s") % saCurReq.getFullText() % saPrvAct.getFullText()); } else { // A part of cur. All of prv. (cur as driver) uint160 uCurrencyID = saPrv.getCurrency(); STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID), uQualityOut, uCurrencyID); -Log(lsINFO) << str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.getFullText()); +Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.getFullText()); saCurAct += saCurOut; saPrvAct = saPrvReq; } } - Log(lsINFO) << str(boost::format("calcNodeRipple< uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeRipple< uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s") % uQualityIn % uQualityOut % saPrvReq.getFullText() @@ -2625,7 +2625,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point const STAmount saPrvBalance = uIndex && bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); const STAmount saPrvLimit = uIndex && bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); - Log(lsINFO) << str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvBalance=%s saPrvLimit=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvBalance=%s saPrvLimit=%s") % uIndex % uLast % NewcoinAddress::createHumanAccountID(uPrvAccountID) @@ -2663,7 +2663,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // STAmount saPrvDeliverReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; STAmount saCurWantedAct(saCurWantedReq.getCurrency()); - Log(lsINFO) << str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s/%s saPrvIssueReq=%s/%s saCurWantedReq=%s/%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s/%s saPrvIssueReq=%s/%s saCurWantedReq=%s/%s") % saPrvRedeemReq.getText() % saPrvRedeemReq.getHumanCurrency() % saPrvIssueReq.getText() @@ -2684,14 +2684,14 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point else if (uIndex == uLast) { // account --> ACCOUNT --> $ - Log(lsINFO) << str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $")); // Calculate redeem if (bRedeem && saPrvRedeemReq) // Previous has IOUs to redeem. { // Redeem at 1:1 - Log(lsINFO) << str(boost::format("calcNodeAccountRev: Redeem at 1:1")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Redeem at 1:1")); saCurWantedAct = MIN(saPrvRedeemReq, saCurWantedReq); saPrvRedeemAct = saCurWantedAct; @@ -2703,7 +2703,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && saPrvIssueReq) // Will accept IOUs. { // Rate: quality in : 1.0 - Log(lsINFO) << str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurWantedReq, saPrvIssueAct, saCurWantedAct); } @@ -2726,7 +2726,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && saPrvBalance.isNegative()) // Previous has IOUs to redeem. { // Rate : 1.0 : quality out - Log(lsINFO) << str(boost::format("calcNodeAccountRev: Rate : 1.0 : quality out")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : quality out")); calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); } @@ -2739,7 +2739,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && saCurIssueReq) // Need some issued. { // Rate : 1.0 : transfer_rate - Log(lsINFO) << str(boost::format("calcNodeAccountRev: Rate : 1.0 : transfer_rate")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : transfer_rate")); calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); } @@ -2751,7 +2751,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && !saPrvBalance.isNegative()) // Previous has no IOUs. { // Rate: quality in : quality out - Log(lsINFO) << str(boost::format("calcNodeAccountRev: Rate: quality in : quality out")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : quality out")); calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); } @@ -2764,7 +2764,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point && saCurIssueReq != saCurIssueAct) // Need some issued. { // Rate: quality in : 1.0 - Log(lsINFO) << str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); } @@ -2775,7 +2775,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // terResult = tenBAD_AMOUNT; bSuccess = false; } - Log(lsINFO) << str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurRedeemReq=%s saCurIssueReq=%s saPrvBalance=%s saCurRedeemAct=%s saCurIssueAct=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurRedeemReq=%s saCurIssueReq=%s saPrvBalance=%s saCurRedeemAct=%s saCurIssueAct=%s") % bPrvRedeem % bPrvIssue % bRedeem @@ -2791,7 +2791,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point { // account --> ACCOUNT --> offer // Note: deliver is always issue as ACCOUNT is the issuer for the offer input. - Log(lsINFO) << str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> offer")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> offer")); // redeem -> deliver/issue. if (bPrvRedeem @@ -2825,7 +2825,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (uIndex == uLast) { // offer --> ACCOUNT --> $ - Log(lsINFO) << str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $")); // Rate: quality in : 1.0 calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct); @@ -2841,7 +2841,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point { // offer --> ACCOUNT --> account // Note: offer is always deliver/redeeming as account is issuer. - Log(lsINFO) << str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> account")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> account")); // deliver -> redeem if (bRedeem // Allowed to redeem. @@ -2874,7 +2874,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point { // offer --> ACCOUNT --> offer // deliver/redeem -> deliver/issue. - Log(lsINFO) << str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> offer")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> offer")); if (bIssue // Allowed to issue. && saCurDeliverReq != saCurDeliverAct) // Can only if issue if more can not be redeemed. @@ -2947,7 +2947,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point STAmount& saCurReceive = pspCur->saOutAct; - Log(lsINFO) << str(boost::format("calcNodeAccountFwd> uIndex=%d/%d saCurRedeemReq=%s/%s saCurIssueReq=%s/%s saCurDeliverReq=%s/%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uIndex=%d/%d saCurRedeemReq=%s/%s saCurIssueReq=%s/%s saCurDeliverReq=%s/%s") % uIndex % uLast % saCurRedeemReq.getText() @@ -3003,7 +3003,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point } saCurSendMaxAct += saCurIssueAct; - Log(lsINFO) << str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s") % saCurSendMaxReq.getFullText() % saCurRedeemAct.getFullText() % saCurIssueReq.getFullText() @@ -3012,7 +3012,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point else if (uIndex == uLast) { // account --> ACCOUNT --> $ - Log(lsINFO) << str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> $ : uPrvAccountID=%s uCurAccountID=%s saPrvRedeemReq=%s saPrvIssueReq=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> $ : uPrvAccountID=%s uCurAccountID=%s saPrvRedeemReq=%s saPrvIssueReq=%s") % NewcoinAddress::createHumanAccountID(uPrvAccountID) % NewcoinAddress::createHumanAccountID(uCurAccountID) % saPrvRedeemReq.getFullText() @@ -3033,7 +3033,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point else { // account --> ACCOUNT --> account - Log(lsINFO) << str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> account")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> account")); // Previous redeem part 1: redeem -> redeem if (bRedeem // Can redeem. @@ -3080,7 +3080,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point else if (bPrvAccount && !bNxtAccount) { // account --> ACCOUNT --> offer - Log(lsINFO) << str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> offer")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> offer")); // redeem -> issue. // wants to redeem and current would and can issue. @@ -3108,7 +3108,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point if (uIndex == uLast) { // offer --> ACCOUNT --> $ - Log(lsINFO) << str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $")); // Amount to credit. saCurReceive = saPrvDeliverAct; @@ -3118,7 +3118,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point else { // offer --> ACCOUNT --> account - Log(lsINFO) << str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> account")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> account")); // deliver -> redeem if (bRedeem // Allowed to redeem. @@ -3146,7 +3146,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point { // offer --> ACCOUNT --> offer // deliver/redeem -> deliver/issue. - Log(lsINFO) << str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> offer")); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> offer")); if (bIssue // Allowed to issue. && saPrvDeliverReq // Previous wants to deliver @@ -3390,22 +3390,22 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin // XXX Disallow loops in ripple paths PathState::PathState( - Ledger::pointer lpLedger, - int iIndex, + const Ledger::pointer& lpLedger, + const int iIndex, const LedgerEntrySet& lesSource, const STPath& spSourcePath, - uint160 uReceiverID, - uint160 uSenderID, - STAmount saSend, - STAmount saSendMax, - bool bPartialPayment + const uint160& uReceiverID, + const uint160& uSenderID, + const STAmount& saSend, + const STAmount& saSendMax, + const bool bPartialPayment ) : mLedger(lpLedger), mIndex(iIndex), uQuality(0) { const uint160 uInCurrencyID = saSendMax.getCurrency(); const uint160 uOutCurrencyID = saSend.getCurrency(); - const uint160 uInIssuerID = !!uInCurrencyID ? uSenderID : ACCOUNT_XNS; - const uint160 uOutIssuerID = !!uOutCurrencyID ? uReceiverID : ACCOUNT_XNS; + const uint160 uInIssuerID = !!uInCurrencyID ? saSendMax.getIssuer() : ACCOUNT_XNS; + const uint160 uOutIssuerID = !!uOutCurrencyID ? saSend.getIssuer() : ACCOUNT_XNS; lesEntries = lesSource.duplicate(); @@ -3448,7 +3448,7 @@ PathState::PathState( } } - Log(lsINFO) << str(boost::format("PathState: in=%s/%s out=%s/%s %s") + Log(lsINFO) << boost::str(boost::format("PathState: in=%s/%s out=%s/%s %s") % STAmount::createHumanCurrency(uInCurrencyID) % NewcoinAddress::createHumanAccountID(uInIssuerID) % STAmount::createHumanCurrency(uOutCurrencyID) @@ -3546,7 +3546,7 @@ bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur, const bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount); bool bValid; - Log(lsINFO) << str(boost::format("calcNode> uIndex=%d") % uIndex); + Log(lsINFO) << boost::str(boost::format("calcNode> uIndex=%d") % uIndex); // Do current node reverse. bValid = bCurAccount @@ -3567,7 +3567,7 @@ bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur, : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); } - Log(lsINFO) << str(boost::format("calcNode< uIndex=%d bValid=%d") % uIndex % bValid); + Log(lsINFO) << boost::str(boost::format("calcNode< uIndex=%d bValid=%d") % uIndex % bValid); return bValid; } @@ -3616,6 +3616,10 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction const uint160 uSrcCurrency = saMaxAmount.getCurrency(); const uint160 uDstCurrency = saDstAmount.getCurrency(); + Log(lsINFO) << boost::str(boost::format("doPayment> saMaxAmount=%s saDstAmount=%s") + % saMaxAmount.getFullText() + % saDstAmount.getFullText()); + if (!uDstAccountID) { Log(lsINFO) << "doPayment: Invalid transaction: Payment destination account not specifed."; @@ -3907,7 +3911,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction if (transResultInfo(terResult, strToken, strHuman)) { - Log(lsINFO) << str(boost::format("doPayment: %s: %s") % strToken % strHuman); + Log(lsINFO) << boost::str(boost::format("doPayment: %s: %s") % strToken % strHuman); } else { @@ -3949,7 +3953,7 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti if (saSrcBalance < saAmount) { std::cerr - << str(boost::format("WalletAdd: Delay transaction: insufficent balance: balance=%s amount=%s") + << boost::str(boost::format("WalletAdd: Delay transaction: insufficent balance: balance=%s amount=%s") % saSrcBalance.getText() % saAmount.getText()) << std::endl; @@ -4264,7 +4268,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); STAmount saOfferGot; const uint256 uTakeBookBase = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); - Log(lsINFO) << str(boost::format("doOfferCreate: take against book: %s : %s/%s -> %s/%s") + Log(lsINFO) << boost::str(boost::format("doOfferCreate: take against book: %s : %s/%s -> %s/%s") % uTakeBookBase.ToString() % saTakerGets.getHumanCurrency() % NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()) @@ -4319,7 +4323,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); { uint256 uBookBase = Ledger::getBookBase(uPaysCurrency, uPaysIssuerID, uGetsCurrency, uGetsIssuerID); - Log(lsINFO) << str(boost::format("doOfferCreate: adding to book: %s : %s/%s -> %s/%s") + Log(lsINFO) << boost::str(boost::format("doOfferCreate: adding to book: %s : %s/%s -> %s/%s") % uBookBase.ToString() % saTakerPays.getHumanCurrency() % NewcoinAddress::createHumanAccountID(saTakerPays.getIssuer()) diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index bfaee2f408..fa93481e8d 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -145,29 +145,29 @@ public: STAmount saOutAct; // Amount actually sent (calc output). PathState( - Ledger::pointer lpLedger, - int iIndex, + const Ledger::pointer& lpLedger, + const int iIndex, const LedgerEntrySet& lesSource, const STPath& spSourcePath, - uint160 uReceiverID, - uint160 uSenderID, - STAmount saSend, - STAmount saSendMax, - bool bPartialPayment + const uint160& uReceiverID, + const uint160& uSenderID, + const STAmount& saSend, + const STAmount& saSendMax, + const bool bPartialPayment ); Json::Value getJson() const; static PathState::pointer createPathState( - Ledger::pointer lpLedger, - int iIndex, + const Ledger::pointer& lpLedger, + const int iIndex, const LedgerEntrySet& lesSource, const STPath& spSourcePath, - uint160 uReceiverID, - uint160 uSenderID, - STAmount saSend, - STAmount saSendMax, - bool bPartialPayment + const uint160& uReceiverID, + const uint160& uSenderID, + const STAmount& saSend, + const STAmount& saSendMax, + const bool bPartialPayment ) { PathState::pointer pspNew = boost::make_shared(lpLedger, iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax, bPartialPayment); From 345c00e5699866c6f503be27b04ffc6b172f726c Mon Sep 17 00:00:00 2001 From: jed Date: Thu, 23 Aug 2012 16:30:15 -0700 Subject: [PATCH 109/426] . --- newcoin.vcxproj | 1 + newcoin.vcxproj.filters | 3 +++ src/OrderBook.h | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/newcoin.vcxproj b/newcoin.vcxproj index 0e7dfbd8fa..e29623a848 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -192,6 +192,7 @@ + diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index ae7712d308..dd3b6d700c 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -524,6 +524,9 @@ Header Files + + Header Files + diff --git a/src/OrderBook.h b/src/OrderBook.h index 1d0262b278..e143589f48 100644 --- a/src/OrderBook.h +++ b/src/OrderBook.h @@ -17,7 +17,8 @@ class OrderBook public: typedef boost::shared_ptr pointer; - // returns NULL if ledgerEntry doesn't point to an orderbook + // returns NULL if ledgerEntry doesn't point to an order + // if ledgerEntry is an Order it creates the OrderBook this order would live in static OrderBook::pointer newOrderBook(SerializedLedgerEntry::pointer ledgerEntry); uint256& getBookBase(){ return(mBookBase); } From e6511732c7bbaced3eb0aaf3350710b28d82b216 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 23 Aug 2012 22:31:14 -0700 Subject: [PATCH 110/426] Fix compiler warnings. --- src/Pathfinder.cpp | 31 +++++++++++++++---------------- src/Pathfinder.h | 4 ++-- src/TransactionEngine.cpp | 4 ++-- 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/Pathfinder.cpp b/src/Pathfinder.cpp index c1c5d86b30..a83771a57f 100644 --- a/src/Pathfinder.cpp +++ b/src/Pathfinder.cpp @@ -21,9 +21,9 @@ TODO: what is a good way to come up with multiple paths? OrderDB: - getXNSOffers(); - - // return list of all orderbooks that want XNS + getXNSOffers(); + + // return list of all orderbooks that want XNS // return list of all orderbooks that want IssuerID // return list of all orderbooks that want this issuerID and currencyID */ @@ -49,7 +49,7 @@ bool sortPathOptions(PathOption::pointer first, PathOption::pointer second) { if(first->mTotalCostmTotalCost) return(true); if(first->mTotalCost>second->mTotalCost) return(false); - + if(first->mCorrectCurrency && !second->mCorrectCurrency) return(true); if(!first->mCorrectCurrency && second->mCorrectCurrency) return(false); @@ -57,7 +57,7 @@ bool sortPathOptions(PathOption::pointer first, PathOption::pointer second) if(first->mPath.getElementCount()>second->mPath.getElementCount()) return(false); if(first->mMinWidthmMinWidth) return true; - + return false; } @@ -77,7 +77,7 @@ PathOption::PathOption(PathOption::pointer other) Pathfinder::Pathfinder(NewcoinAddress& srcAccountID, NewcoinAddress& dstAccountID, uint160& srcCurrencyID, STAmount dstAmount) : - mSrcAccountID(srcAccountID.getAccountID()) , mDstAccountID(dstAccountID.getAccountID()), mSrcCurrencyID(srcCurrencyID) , mDstAmount(dstAmount), mOrderBook(theApp->getMasterLedger().getCurrentLedger()) + mSrcAccountID(srcAccountID.getAccountID()), mDstAccountID(dstAccountID.getAccountID()), mDstAmount(dstAmount), mSrcCurrencyID(srcCurrencyID), mOrderBook(theApp->getMasterLedger().getCurrentLedger()) { mLedger=theApp->getMasterLedger().getCurrentLedger(); } @@ -99,9 +99,8 @@ bool Pathfinder::findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet } if(checkComplete(retPathSet)) return(true); } - } - + return(false); } @@ -125,8 +124,8 @@ bool Pathfinder::checkComplete(STPathSet& retPathSet) // get all the options from this accountID // if source is XNS // every offer that wants XNS -// else -// every ripple line that starts with the source currency +// else +// every ripple line that starts with the source currency // every offer that we can take that wants the source currency void Pathfinder::addOptions(PathOption::pointer tail) @@ -150,7 +149,7 @@ void Pathfinder::addOptions(PathOption::pointer tail) BOOST_FOREACH(RippleState::pointer line,rippleLines.getLines()) { // TODO: make sure we can move in the correct direction - STAmount balance=line->getBalance(); + STAmount balance=line->getBalance(); if(balance.getCurrency()==tail->mCurrencyID) { // we have a ripple line from the tail to somewhere else PathOption::pointer pathOption(new PathOption(tail)); @@ -161,7 +160,7 @@ void Pathfinder::addOptions(PathOption::pointer tail) pathOption->mCurrentAccount=line->getAccountIDPeer().getAccountID(); addPathOption(pathOption); - } + } } // every offer that wants the source currency @@ -184,7 +183,7 @@ void Pathfinder::addOptions(PathOption::pointer tail) void Pathfinder::addPathOption(PathOption::pointer pathOption) { - if(pathOption->mCurrencyID==mDstAmount.getCurrency()) + if(pathOption->mCurrencyID==mDstAmount.getCurrency()) { pathOption->mCorrectCurrency=true; @@ -192,11 +191,11 @@ void Pathfinder::addPathOption(PathOption::pointer pathOption) { // this path is complete mCompletePaths.push_back(pathOption); }else mBuildingPaths.push_back(pathOption); - }else + } + else { pathOption->mCorrectCurrency=false; mBuildingPaths.push_back(pathOption); } } - - +// vim:ts=4 diff --git a/src/Pathfinder.h b/src/Pathfinder.h index 5a7a4345a1..cc900e1e13 100644 --- a/src/Pathfinder.h +++ b/src/Pathfinder.h @@ -33,7 +33,6 @@ class Pathfinder OrderBookDB mOrderBook; Ledger::pointer mLedger; - std::list mBuildingPaths; std::list mCompletePaths; @@ -49,4 +48,5 @@ public: // returns false if there is no path. otherwise fills out retPath bool findPaths(int maxSearchSteps, int maxPay, STPathSet& retPathSet); -}; \ No newline at end of file +}; +// vim:ts=4 diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index e34387bae9..6db4f518b3 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -2618,8 +2618,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point const uint160& uCurrencyID = pnCur.uCurrencyID; - const uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : 1; - const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : 1; + const uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; + const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; // For bPrvAccount const STAmount saPrvBalance = uIndex && bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); From db873ff9f52961526f07e4f78ca1743a4b624ba2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 24 Aug 2012 09:32:58 -0700 Subject: [PATCH 111/426] Functions for owned nodes (nodes that have a single other node that owns them) and dual-owner nodes (nodes that have two other nodes that own them). Owned nodes would be things like nicknames. Dual-owner nodes would be things like ripple balances. --- src/SerializedLedger.cpp | 25 +++++++++++++++++++++++++ src/SerializedLedger.h | 5 +++++ 2 files changed, 30 insertions(+) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index e79b19c1b7..5796952368 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -109,6 +109,31 @@ bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint25 return true; } +bool SerializedLedgerEntry::hasOneOwner() +{ + return (mType != ltACCOUNT_ROOT) && (getIFieldIndex(sfAccount) != -1); +} + +bool SerializedLedgerEntry::hasTwoOwners() +{ + return mType == ltRIPPLE_STATE; +} + +NewcoinAddress SerializedLedgerEntry::getOwner() +{ + return getIValueFieldAccount(sfAccount); +} + +NewcoinAddress SerializedLedgerEntry::getFirstOwner() +{ + return getIValueFieldAccount(sfLowID); +} + +NewcoinAddress SerializedLedgerEntry::getSecondOwner() +{ + return getIValueFieldAccount(sfHighID); +} + std::vector SerializedLedgerEntry::getOwners() { std::vector owners; diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index 5f66a765dc..21faba8c35 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -65,6 +65,11 @@ public: bool isThreadedType(); // is this a ledger entry that can be threaded bool isThreaded(); // is this ledger entry actually threaded + bool hasOneOwner(); // This node has one other node that owns it (like nickname) + bool hasTwoOwners(); // This node has two nodes that own it (like ripple balance) + NewcoinAddress getOwner(); + NewcoinAddress getFirstOwner(); + NewcoinAddress getSecondOwner(); uint256 getThreadedTransaction(); uint32 getThreadedLedger(); bool thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID); From 82c3a49e26cd4253d5465bb942a5e8c57ea933a8 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 24 Aug 2012 09:35:26 -0700 Subject: [PATCH 112/426] Missing newlins. --- src/TransactionMeta.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index b193afb48a..d6c80d9add 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -307,4 +307,4 @@ void TransactionMetaSet::deleteUnfunded(const uint256& nodeID, else node.addNode(new TMNEUnfunded(firstBalance, secondBalance)); } -#endif \ No newline at end of file +#endif From 4633aa019ccd25ef9a84fd6bea2d918fec2383a9 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 24 Aug 2012 09:35:35 -0700 Subject: [PATCH 113/426] Mid-level threading code. --- src/LedgerEntrySet.cpp | 94 +++++++++++++++++++++++++++++++++++++++++- src/LedgerEntrySet.h | 14 ++++++- 2 files changed, 105 insertions(+), 3 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index ac110df3c3..06a718b52c 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -230,8 +230,70 @@ Json::Value LedgerEntrySet::getJson(int) const return ret; } -void LedgerEntrySet::addRawMeta(Serializer& s, Ledger::pointer origLedger) +SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::pointer& ledger, + boost::unordered_map& newMods) { + boost::unordered_map::iterator it = mEntries.find(node); + if (it != mEntries.end()) + { + if (it->second.mAction == taaDELETE) + return SLE::pointer(); + if (it->second.mAction == taaCACHED) + it->second.mAction = taaMODIFY; + if (it->second.mSeq != mSeq) + { + it->second.mEntry = boost::make_shared(*it->second.mEntry); + it->second.mSeq = mSeq; + } + return it->second.mEntry; + } + + boost::unordered_map::iterator me = newMods.find(node); + if (me != newMods.end()) + return me->second; + + SLE::pointer ret = ledger->getSLE(node); + if (ret) + newMods.insert(std::make_pair(node, ret)); + return ret; + +} + +bool LedgerEntrySet::threadNode(SLE::pointer& node, const NewcoinAddress& threadTo, Ledger::pointer& ledger, + boost::unordered_map& newMods) +{ + SLE::pointer sle = getForMod(Ledger::getAccountRootIndex(threadTo.getAccountID()), ledger, newMods); + if ((!sle) || (sle->getIndex() == node->getIndex())) // do not self-thread + return false; + return threadNode(node, sle, ledger, newMods); +} + +bool LedgerEntrySet::threadNode(SLE::pointer& node, SLE::pointer& threadTo, Ledger::pointer& ledger, + boost::unordered_map& newMods) +{ + // WRITEME + return false; +} + +bool LedgerEntrySet::threadOwners(SLE::pointer& node, Ledger::pointer& ledger, + boost::unordered_map& newMods) +{ // thread new or modified node to owner or owners + if (node->hasOneOwner()) // thread to owner's account + return threadNode(node, node->getOwner(), ledger, newMods); + else if (node->hasTwoOwners()) // thread to owner's accounts + return + threadNode(node, node->getFirstOwner(), ledger, newMods) || + threadNode(node, node->getSecondOwner(), ledger, newMods); + else + return false; +} + +void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::pointer& origLedger) +{ // calculate the raw meta data and return it. This must be called before the set is committed + + // Entries modified only as a result of building the transaction metadata + boost::unordered_map newMod; + for (boost::unordered_map::const_iterator it = mEntries.begin(), end = mEntries.end(); it != end; ++it) { @@ -257,10 +319,38 @@ void LedgerEntrySet::addRawMeta(Serializer& s, Ledger::pointer origLedger) SLE::pointer origNode = origLedger->getSLE(it->first); SLE::pointer curNode = it->second.mEntry; - // FINISH + if (nType == TMNDeletedNode) + { + threadOwners(origNode, origLedger, newMod); + if (origNode->getType() == ltOFFER) + { // check for non-zero balances + // WRITEME + } + } + + if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode)) + { + if (nType == TMNCreatedNode) // if created, thread to owner(s) + threadOwners(curNode, origLedger, newMod); + + if (curNode->isThreadedType()) // always thread to self + threadNode(curNode, curNode, origLedger, newMod); + + if (nType == TMNModifiedNode) + { + // analyze changes WRITEME + } + + } } } + + // add any new modified nodes to the modification set + for (boost::unordered_map::iterator it = newMod.begin(), end = newMod.end(); + it != end; ++it) + entryCache(it->second); + mSet.addRaw(s); } diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index cf4ee9b281..6d77b35928 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -38,6 +38,18 @@ protected: LedgerEntrySet(const boost::unordered_map &e, const TransactionMetaSet& s, int m) : mEntries(e), mSet(s), mSeq(m) { ; } + SLE::pointer getForMod(const uint256& node, Ledger::pointer& ledger, + boost::unordered_map& newMods); + + bool threadNode(SLE::pointer& node, const NewcoinAddress& threadTo, Ledger::pointer& ledger, + boost::unordered_map& newMods); + + bool threadNode(SLE::pointer& node, SLE::pointer& threadTo, Ledger::pointer& ledger, + boost::unordered_map& newMods); + + bool threadOwners(SLE::pointer& node, Ledger::pointer& ledger, + boost::unordered_map& newMods); + public: LedgerEntrySet() : mSeq(0) { ; } @@ -60,7 +72,7 @@ public: void entryModify(const SLE::pointer&); // This entry will be modified Json::Value getJson(int) const; - void addRawMeta(Serializer&, Ledger::pointer originalLedger); + void calcRawMeta(Serializer&, Ledger::pointer& originalLedger); // iterator functions bool isEmpty() const { return mEntries.empty(); } From 59cf54895395f0fd8682994ca7cf08395347285f Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 24 Aug 2012 20:17:46 -0700 Subject: [PATCH 114/426] Add issuer support to RPC send commend. --- src/RPCServer.cpp | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 8cd2a27f14..58f74143fc 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -45,7 +45,7 @@ Json::Value RPCServer::RPCError(int iError) { rpcBAD_SEED, "badSeed", "Disallowed seed." }, { rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." }, { rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exists." }, - { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." }, + { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency/issuer is malformed." }, { rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." }, { rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." }, { rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets amount malformed." }, @@ -74,7 +74,7 @@ Json::Value RPCServer::RPCError(int iError) { rpcQUALITY_MALFORMED, "qualityMalformed", "Quality malformed." }, { rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." }, { rpcSRC_ACT_MISSING, "srcActMissing", "Source account does not exist." }, - { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency is malformed." }, + { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed." }, { rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." }, { rpcSUCCESS, "success", "Success." }, { rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." }, @@ -1706,7 +1706,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) return ret; } -// send regular_seed paying_account account_id amount [currency] [send_max] [send_currency] +// send regular_seed paying_account account_id amount [currency] [issuer] [send_max] [send_currency] [send_issuer] Json::Value RPCServer::doSend(const Json::Value& params) { NewcoinAddress naSeed; @@ -1716,13 +1716,21 @@ Json::Value RPCServer::doSend(const Json::Value& params) STAmount saDstAmount; std::string sSrcCurrency; std::string sDstCurrency; + std::string sSrcIssuer; + std::string sDstIssuer; if (params.size() >= 5) sDstCurrency = params[4u].asString(); + if (params.size() >= 6) + sDstIssuer = params[5u].asString(); + if (params.size() >= 7) sSrcCurrency = params[6u].asString(); + if (params.size() >= 8) + sSrcIssuer = params[7u].asString(); + if (!naSeed.setSeedGeneric(params[0u].asString())) { return RPCError(rpcBAD_SEED); @@ -1735,11 +1743,11 @@ Json::Value RPCServer::doSend(const Json::Value& params) { return RPCError(rpcDST_ACT_MALFORMED); } - else if (!saDstAmount.setFullValue(params[3u].asString(), sDstCurrency)) + else if (!saDstAmount.setFullValue(params[3u].asString(), sDstCurrency, sDstIssuer)) { return RPCError(rpcDST_AMT_MALFORMED); } - else if (params.size() >= 6 && !saSrcAmountMax.setFullValue(params[5u].asString(), sSrcCurrency)) + else if (params.size() >= 7 && !saSrcAmountMax.setFullValue(params[5u].asString(), sSrcCurrency, sSrcIssuer)) { return RPCError(rpcSRC_AMT_MALFORMED); } @@ -1758,10 +1766,16 @@ Json::Value RPCServer::doSend(const Json::Value& params) Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, saFee, asSrc, naVerifyGenerator); + // Log(lsINFO) << boost::str(boost::format("doSend: sSrcIssuer=%s sDstIssuer=%s saSrcAmountMax=%s saDstAmount=%s") + // % sSrcIssuer + // % sDstIssuer + // % saSrcAmountMax.getFullText() + // % saDstAmount.getFullText()); + if (!obj.empty()) return obj; - if (params.size() < 6) + if (params.size() < 7) saSrcAmountMax = saDstAmount; // Do a few simple checks. @@ -2554,7 +2568,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "ripple", &RPCServer::doRipple, 8, -1, false, optCurrent|optClosed }, { "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent }, { "ripple_line_set", &RPCServer::doRippleLineSet, 4, 7, false, optCurrent }, - { "send", &RPCServer::doSend, 3, 7, false, optCurrent }, + { "send", &RPCServer::doSend, 3, 9, false, optCurrent }, { "server_info", &RPCServer::doServerInfo, 0, 0, true }, { "stop", &RPCServer::doStop, 0, 0, true }, { "tx", &RPCServer::doTx, 1, 1, true }, From ba45778a08122a41e33a86e3749be3b310c55970 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 24 Aug 2012 20:18:07 -0700 Subject: [PATCH 115/426] Fixes for ripple quality in transaction engine. --- src/TransactionEngine.cpp | 65 ++++++++++++++------------------------- src/TransactionEngine.h | 5 +-- 2 files changed, 26 insertions(+), 44 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 6db4f518b3..88d7be6421 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -164,9 +164,9 @@ uint32 TransactionEngine::rippleTransferRate(const uint160& uIssuerID) } // XXX Might not need this, might store in nodes on calc reverse. -uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) +uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, const SOE_Field sfLow, const SOE_Field sfHigh) { - uint32 uQualityIn = QUALITY_ONE; + uint32 uQuality = QUALITY_ONE; SLE::pointer sleRippleState; if (uToAccountID == uFromAccountID) @@ -179,53 +179,28 @@ uint32 TransactionEngine::rippleQualityIn(const uint160& uToAccountID, const uin if (sleRippleState) { - SOE_Field sfField = uToAccountID < uFromAccountID ? sfLowQualityIn : sfHighQualityIn; + SOE_Field sfField = uToAccountID < uFromAccountID ? sfLow: sfHigh; - uQualityIn = sleRippleState->getIFieldPresent(sfField) + uQuality = sleRippleState->getIFieldPresent(sfField) ? sleRippleState->getIFieldU32(sfField) : QUALITY_ONE; - if (!uQualityIn) - uQualityIn = 1; + + if (!uQuality) + uQuality = 1; // Avoid divide by zero. } } - Log(lsINFO) << boost::str(boost::format("rippleQualityIn: uToAccountID=%s uFromAccountID=%s uCurrencyID=%s bLine=%d uQualityIn=%f") + 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 - % (uQualityIn/1000000000.0)); + % (uQuality/1000000000.0)); assert(uToAccountID == uFromAccountID || !!sleRippleState); - return uQualityIn; -} - -uint32 TransactionEngine::rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) -{ - uint32 uQualityOut = QUALITY_ONE; - - if (uToAccountID == uFromAccountID) - { - nothing(); - } - else - { - SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); - - if (sleRippleState) - { - uQualityOut = sleRippleState->getIFieldU32(uToAccountID < uFromAccountID ? sfLowQualityOut : sfHighQualityOut); - if (!uQualityOut) - uQualityOut = 1; - } - else - { - assert(false); - } - } - - return uQualityOut; + return uQuality; } // Return how much of uIssuerID's uCurrencyID IOUs that uAccountID holds. May be negative. @@ -2840,13 +2815,12 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point else { // offer --> ACCOUNT --> account - // Note: offer is always deliver/redeeming as account is issuer. + // Note: offer is always delivering(redeeming) as account is issuer. Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> account")); // deliver -> redeem if (bRedeem // Allowed to redeem. - && saCurRedeemReq // Next wants us to redeem. - && saPrvBalance.isNegative()) // Previous has IOUs to redeem. + && saCurRedeemReq) // Next wants us to redeem. { // Rate : 1.0 : quality out calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct); @@ -2854,15 +2828,22 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // deliver -> issue. if (bIssue // Allowed to issue. - && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. - && saPrvBalance.isNegative() // Previous still has IOUs. + && saCurRedeemReq == saCurRedeemAct // Can only if issue if more can not be redeemed. && saCurIssueReq) // Need some issued. { // Rate : 1.0 : transfer_rate calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct); } - if (!saCurDeliverAct && !saCurIssueAct) + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: bRedeem=%d saCurRedeemReq=%s saCurIssueAct=%s bIssue=%d saCurIssueReq=%s saPrvDeliverAct=%s") + % bRedeem + % saCurRedeemReq.getFullText() + % saCurRedeemAct.getFullText() + % bIssue + % saCurIssueReq.getFullText() + % saPrvDeliverAct.getFullText()); + + if (!saPrvDeliverAct) { // Must want something. // terResult = tenBAD_AMOUNT; diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index fa93481e8d..e6ff7d6183 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -228,8 +228,9 @@ protected: uint32 rippleTransferRate(const uint160& uIssuerID); STAmount rippleBalance(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); - uint32 rippleQualityOut(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); From cf450106c4e7da969368a26b6cfe567159473024 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 25 Aug 2012 14:49:45 -0700 Subject: [PATCH 116/426] Require issuer when specifying currency when creating STAmount. --- src/Amount.cpp | 78 ++++++++++---------- src/SerializedTypes.h | 19 ++--- src/TransactionEngine.cpp | 148 ++++++++++++++++++++++---------------- src/TransactionEngine.h | 2 +- 4 files changed, 136 insertions(+), 111 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 1dfd549e47..b1588dc05a 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -651,10 +651,10 @@ STAmount operator-(const STAmount& v1, const STAmount& v2) return STAmount(v1.name, v1.mCurrency, -fv, ov1, true); } -STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& currencyOut) +STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& uCurrencyID, const uint160& uIssuerID) { if (den.isZero()) throw std::runtime_error("division by zero"); - if (num.isZero()) return STAmount(currencyOut); + if (num.isZero()) return STAmount(uCurrencyID, uIssuerID); uint64 numVal = num.mValue, denVal = den.mValue; int numOffset = num.mOffset, denOffset = den.mOffset; @@ -690,14 +690,14 @@ STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint16 assert(BN_num_bytes(&v) <= 64); if (num.mIsNegative != den.mIsNegative) - return -STAmount(currencyOut, v.getulong(), finOffset); - else return STAmount(currencyOut, v.getulong(), finOffset); + return -STAmount(uCurrencyID, uIssuerID, v.getulong(), finOffset); + else return STAmount(uCurrencyID, uIssuerID, v.getulong(), finOffset); } -STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut) +STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID) { if (v1.isZero() || v2.isZero()) - return STAmount(currencyOut); + return STAmount(uCurrencyID, uIssuerID); if (v1.mIsNative && v2.mIsNative) // FIXME: overflow return STAmount(v1.name, v1.getSNValue() * v2.getSNValue()); @@ -753,8 +753,8 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16 assert(BN_num_bytes(&v) <= 64); if (v1.mIsNegative != v2.mIsNegative) - return -STAmount(currencyOut, v.getulong(), offset1 + offset2 + 14); - else return STAmount(currencyOut, v.getulong(), offset1 + offset2 + 14); + return -STAmount(uCurrencyID, uIssuerID, v.getulong(), offset1 + offset2 + 14); + else return STAmount(uCurrencyID, uIssuerID, v.getulong(), offset1 + offset2 + 14); } // Convert an offer into an index amount so they sort by rate. @@ -769,7 +769,7 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn) { if (offerOut.isZero()) throw std::runtime_error("Worthless offer"); - STAmount r = divide(offerIn, offerOut, uint160(1)); + STAmount r = divide(offerIn, offerOut, CURRENCY_ONE, ACCOUNT_ONE); assert((r.getExponent() >= -100) && (r.getExponent() <= 155)); @@ -778,12 +778,12 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn) return (ret << (64 - 8)) | r.getMantissa(); } -STAmount STAmount::setRate(uint64 rate, const uint160& currencyOut) +STAmount STAmount::setRate(uint64 rate) { uint64 mantissa = rate & ~(255ull << (64 - 8)); int exponent = static_cast(rate >> (64 - 8)) - 100; - return STAmount(currencyOut, mantissa, exponent); + return STAmount(CURRENCY_ONE, ACCOUNT_ONE, mantissa, exponent); } // Taker gets all taker can pay for with saTakerFunds, limited by saOfferPays and saOfferFunds. @@ -814,7 +814,7 @@ bool STAmount::applyOffer( STAmount saOfferGetsAvailable = saOfferFunds == saOfferPays ? saOfferGets // Offer was fully funded, avoid shenanigans. - : divide(multiply(saTakerPays, saOfferPaysAvailable, uint160(1)), saTakerGets, saOfferGets.getCurrency()); + : divide(multiply(saTakerPays, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saTakerGets, saOfferGets.getCurrency(), saOfferGets.getIssuer()); if (saOfferGets == saOfferGetsAvailable && saTakerFunds >= saOfferGets) { @@ -836,7 +836,7 @@ bool STAmount::applyOffer( { // Taker only get's a portion of offer. saTakerPaid = saTakerFunds; // Taker paid all he had. - saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, uint160(1)), saOfferGetsAvailable, saOfferPays.getCurrency()); + saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saOfferGetsAvailable, saOfferPays.getCurrency(), saOfferPays.getIssuer()); Log(lsINFO) << "applyOffer: saTakerGot=" << saTakerGot.getFullText(); Log(lsINFO) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable.getFullText(); @@ -848,7 +848,7 @@ bool STAmount::applyOffer( STAmount STAmount::getPay(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed) { // Someone wants to get (needed) out of the offer, how much should they pay in? if (offerOut.isZero()) - return STAmount(offerIn.getCurrency()); + return STAmount(offerIn.getCurrency(), offerIn.getIssuer()); if (needed >= offerOut) { @@ -856,7 +856,7 @@ STAmount STAmount::getPay(const STAmount& offerOut, const STAmount& offerIn, con return needed; } - STAmount ret = divide(multiply(needed, offerIn, uint160(1)), offerOut, offerIn.getCurrency()); + STAmount ret = divide(multiply(needed, offerIn, CURRENCY_ONE, ACCOUNT_ONE), offerOut, offerIn.getCurrency(), offerIn.getIssuer()); return (ret > offerIn) ? offerIn : ret; } @@ -1063,8 +1063,7 @@ BOOST_AUTO_TEST_CASE( NativeCurrency_test ) BOOST_AUTO_TEST_CASE( CustomCurrency_test ) { - uint160 currency(1); - STAmount zero(currency), one(currency, 1), hundred(currency, 100); + STAmount zero(CURRENCY_ONE, ACCOUNT_ONE), one(CURRENCY_ONE, ACCOUNT_ONE, 1), hundred(CURRENCY_ONE, ACCOUNT_ONE, 100); serdes(one).getRaw(); @@ -1131,33 +1130,33 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test ) if (!(hundred != zero)) BOOST_FAIL("STAmount fail"); if (!(hundred != one)) BOOST_FAIL("STAmount fail"); if ((hundred != hundred)) BOOST_FAIL("STAmount fail"); - if (STAmount(currency).getText() != "0") BOOST_FAIL("STAmount fail"); - if (STAmount(currency,31).getText() != "31") BOOST_FAIL("STAmount fail"); - if (STAmount(currency,31,1).getText() != "310") BOOST_FAIL("STAmount fail"); - if (STAmount(currency,31,-1).getText() != "3.1") BOOST_FAIL("STAmount fail"); - if (STAmount(currency,31,-2).getText() != "0.31") BOOST_FAIL("STAmount fail"); + if (STAmount(CURRENCY_ONE, ACCOUNT_ONE).getText() != "0") BOOST_FAIL("STAmount fail"); + if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31).getText() != "31") BOOST_FAIL("STAmount fail"); + if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,1).getText() != "310") BOOST_FAIL("STAmount fail"); + if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,-1).getText() != "3.1") BOOST_FAIL("STAmount fail"); + if (STAmount(CURRENCY_ONE, ACCOUNT_ONE, 31,-2).getText() != "0.31") BOOST_FAIL("STAmount fail"); - if (STAmount::multiply(STAmount(currency, 20), STAmount(3), currency).getText() != "60") + if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60") BOOST_FAIL("STAmount multiply fail"); - if (STAmount::multiply(STAmount(currency, 20), STAmount(3), uint160()).getText() != "60") + if (STAmount::multiply(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60") BOOST_FAIL("STAmount multiply fail"); - if (STAmount::multiply(STAmount(20), STAmount(3), currency).getText() != "60") + if (STAmount::multiply(STAmount(20), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "60") BOOST_FAIL("STAmount multiply fail"); - if (STAmount::multiply(STAmount(20), STAmount(3), uint160()).getText() != "60") + if (STAmount::multiply(STAmount(20), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "60") BOOST_FAIL("STAmount multiply fail"); - if (STAmount::divide(STAmount(currency, 60) , STAmount(3), currency).getText() != "20") + if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20") BOOST_FAIL("STAmount divide fail"); - if (STAmount::divide(STAmount(currency, 60) , STAmount(3), uint160()).getText() != "20") + if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(3), uint160(), ACCOUNT_XNS).getText() != "20") BOOST_FAIL("STAmount divide fail"); - if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), currency).getText() != "20") + if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), CURRENCY_ONE, ACCOUNT_ONE).getText() != "20") BOOST_FAIL("STAmount divide fail"); - if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), uint160()).getText() != "20") + if (STAmount::divide(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 60), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 3), uint160(), ACCOUNT_XNS).getText() != "20") BOOST_FAIL("STAmount divide fail"); - STAmount a1(currency, 60), a2 (currency, 10, -1); - if (STAmount::divide(a2, a1, currency) != STAmount::setRate(STAmount::getRate(a1, a2), currency)) + STAmount a1(CURRENCY_ONE, ACCOUNT_ONE, 60), a2 (CURRENCY_ONE, ACCOUNT_ONE, 10, -1); + if (STAmount::divide(a2, a1, CURRENCY_ONE, ACCOUNT_ONE) != STAmount::setRate(STAmount::getRate(a1, a2))) BOOST_FAIL("STAmount setRate(getRate) fail"); - if (STAmount::divide(a1, a2, currency) != STAmount::setRate(STAmount::getRate(a2, a1), currency)) + if (STAmount::divide(a1, a2, CURRENCY_ONE, ACCOUNT_ONE) != STAmount::setRate(STAmount::getRate(a2, a1))) BOOST_FAIL("STAmount setRate(getRate) fail"); BOOST_TEST_MESSAGE("Amount CC Complete"); @@ -1168,22 +1167,21 @@ BOOST_AUTO_TEST_CASE( CurrencyMulDivTests ) // Test currency multiplication and division operations such as // convertToDisplayAmount, convertToInternalAmount, getRate, getClaimed, and getNeeded - uint160 c(1); if (STAmount::getRate(STAmount(1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(c, 1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(c, 10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(c, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(c, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(1), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); - if (STAmount::getRate(STAmount(10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) + if (STAmount::getRate(STAmount(10), STAmount(CURRENCY_ONE, ACCOUNT_ONE, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) BOOST_FAIL("STAmount getRate fail"); } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 46439587a4..1017f758a3 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -261,10 +261,11 @@ public: : SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false) { ; } - STAmount(const uint160& uCurrency, uint64 uV=0, int iOff=0, bool bNegative=false) - : mCurrency(uCurrency), mValue(uV), mOffset(iOff), mIsNegative(bNegative) + STAmount(const uint160& uCurrencyID, const uint160& uIssuerID, uint64 uV=0, int iOff=0, bool bNegative=false) + : mCurrency(uCurrencyID), mIssuer(uIssuerID), mValue(uV), mOffset(iOff), mIsNegative(bNegative) { canonicalize(); } + // YYY This should probably require issuer too. STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0, bool isNeg = false) : SerializedType(n), mCurrency(currency), mValue(v), mOffset(off), mIsNegative(isNeg) { canonicalize(); } @@ -274,14 +275,14 @@ public: static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) { return std::auto_ptr(construct(sit, name)); } - static STAmount saFromRate(uint64 uV = 0) + static STAmount saFromRate(uint64 uRate = 0) { - return STAmount(CURRENCY_ONE, uV, -9, false); + return STAmount(CURRENCY_ONE, ACCOUNT_ONE, uRate, -9, false); } - static STAmount saFromSigned(const uint160& uCurrency, int64 iV=0, int iOff=0) + static STAmount saFromSigned(const uint160& uCurrencyID, const uint160& uIssuerID, int64 iV=0, int iOff=0) { - return STAmount(uCurrency, iV < 0 ? -iV : iV, iOff, iV < 0); + return STAmount(uCurrencyID, uIssuerID, iV < 0 ? -iV : iV, iOff, iV < 0); } int getLength() const { return mIsNative ? 8 : 28; } @@ -351,13 +352,13 @@ public: friend STAmount operator+(const STAmount& v1, const STAmount& v2); friend STAmount operator-(const STAmount& v1, const STAmount& v2); - static STAmount divide(const STAmount& v1, const STAmount& v2, const uint160& currencyOut); - static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& currencyOut); + static STAmount divide(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID); + static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID); // Someone is offering X for Y, what is the rate? // Rate: smaller is better, the taker wants the most out: in/out static uint64 getRate(const STAmount& offerOut, const STAmount& offerIn); - static STAmount setRate(uint64 rate, const uint160& currencyOut); + static STAmount setRate(uint64 rate); // Someone is offering X for Y, I try to pay Z, how much do I get? // And what's left of the offer? And how much do I actually pay? diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 88d7be6421..477ee82840 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -102,7 +102,9 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std return iIndex >= 0; } -STAmount TransactionEngine::rippleBalance(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) +// Returns amount owed by uToAccountID to uFromAccountID. +// <-- $owed/uCurrencyID/uToAccountID: positive: uFromAccountID holds IOUs., negative: uFromAccountID owes IOUs. +STAmount TransactionEngine::rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) { STAmount saBalance; SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(uToAccountID, uFromAccountID, uCurrencyID)); @@ -112,10 +114,11 @@ STAmount TransactionEngine::rippleBalance(const uint160& uToAccountID, const uin saBalance = sleRippleState->getIValueFieldAmount(sfBalance); if (uToAccountID < uFromAccountID) saBalance.negate(); + saBalance.setIssuer(uToAccountID); } else { - Log(lsINFO) << "rippleBalance: No credit line between " + Log(lsINFO) << "rippleOwed: No credit line between " << NewcoinAddress::createHumanAccountID(uFromAccountID) << " and " << NewcoinAddress::createHumanAccountID(uToAccountID) @@ -130,6 +133,8 @@ STAmount TransactionEngine::rippleBalance(const uint160& uToAccountID, const uin } +// Maximum amount of IOUs uToAccountID will hold from uFromAccountID. +// <-- $amount/uCurrencyID/uToAccountID. STAmount TransactionEngine::rippleLimit(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) { STAmount saLimit; @@ -139,6 +144,7 @@ STAmount TransactionEngine::rippleLimit(const uint160& uToAccountID, const uint1 if (sleRippleState) { saLimit = sleRippleState->getIValueFieldAmount(uToAccountID < uFromAccountID ? sfLowLimit : sfHighLimit); + saLimit.setIssuer(uToAccountID); } return saLimit; @@ -300,7 +306,7 @@ STAmount TransactionEngine::rippleTransferFee(const uint160& uSenderID, const ui { STAmount saTransitRate(CURRENCY_ONE, uTransitRate, -9); - saTransitFee = STAmount::multiply(saAmount, saTransitRate, saAmount.getCurrency()); + saTransitFee = STAmount::multiply(saAmount, saTransitRate, saAmount.getCurrency(), saAmount.getIssuer()); } } @@ -1583,9 +1589,9 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString(); - sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID)); // Zero balance in currency. + sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency. sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAmount); - sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID)); + sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, ACCOUNT_ONE)); sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, mTxnAccountID); sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uDstAccountID); if (uQualityIn) @@ -1944,7 +1950,7 @@ bool TransactionEngine::calcNodeOfferRev( // - Drive on computing saCurDlvAct to derive saPrvDlvAct. // XXX Behave well, if entry type is wrong (someone beat us to using the hash) SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); - STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip), uCurCurrencyID); // For correct ratio + STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio unsigned int uEntry = 0; uint256 uCurIndex; @@ -1987,13 +1993,13 @@ bool TransactionEngine::calcNodeOfferRev( STAmount saOutBase = MIN(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed. STAmount saOutCost = MIN( bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, saCurOfrFunds); // Limit cost by fees & funds. STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutCost; // Out amount after fees. - STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required. + STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required. saCurDlvAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saInDlvAct; // Portion needed in previous. @@ -2044,13 +2050,14 @@ bool TransactionEngine::calcNodeOfferRev( saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. STAmount saOutCost = MIN( bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, saCurOfrFunds); // Limit cost by fees & funds. STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutCost; // Out amount after fees. - STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required. + // Compute input w/o fees required. + STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); saCurDlvAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saInDlvAct; // Portion needed in previous. @@ -2078,7 +2085,7 @@ bool TransactionEngine::calcNodeOfferRev( Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev< uIndex=%d saPrvDlvReq=%s bSuccess=%d") % uIndex - % saPrvDlvReq.getText() + % saPrvDlvReq.getFullText() % bSuccess); return bSuccess; @@ -2134,7 +2141,7 @@ bool TransactionEngine::calcNodeOfferFwd( // Do a directory. // - Drive on computing saPrvDlvAct to derive saCurDlvAct. SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); - STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip), uCurCurrencyID); // For correct ratio + STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio unsigned int uEntry = 0; uint256 uCurIndex; @@ -2158,17 +2165,18 @@ bool TransactionEngine::calcNodeOfferFwd( : saTransferRate; const bool bFee = saFeeRate != saOne; - const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID); + const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID, uCurIssuerID); const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. const STAmount saOutCost = MIN( bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, saCurOfrFunds); // Limit cost by fees & funds. const STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutCost; // Out amount after fees. - const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID); // Compute input w/o fees required. + // Compute input w/o fees required. + const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID, uCurIssuerID); saCurDlvAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saInDlvAct; // Portion needed in previous. @@ -2216,18 +2224,18 @@ bool TransactionEngine::calcNodeOfferFwd( const bool bFee = saFeeRate != saOne; const STAmount saInBase = saCurOfrInMax-saCurOfrInAct; - const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID); + const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID); STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. const STAmount saOutCost = MIN( bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID) + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, saCurOfrFunds); // Limit cost by fees & funds. const STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID) + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutCost; // Out amount after fees. - const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID); // Compute input w/o fees required. + const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required. saCurOfrInAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saOutDlvAct; // Portion needed in previous. @@ -2538,8 +2546,11 @@ void TransactionEngine::calcNodeRipple( // Fee. Log(lsINFO) << boost::str(boost::format("calcNodeRipple: Fee")); - uint160 uCurrencyID = saCur.getCurrency(); - STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID), uQualityIn, uCurrencyID); + const uint160 uCurrencyID = saCur.getCurrency(); + const uint160 uCurIssuerID = saCur.getIssuer(); + const uint160 uPrvIssuerID = saPrv.getIssuer(); + + STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID, uCurIssuerID), uQualityIn, uCurrencyID, uCurIssuerID); Log(lsINFO) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCurIn=%s") % bPrvUnlimited % saPrv.getFullText() % saCurIn.getFullText()); if (bPrvUnlimited || saCurIn <= saPrv) @@ -2552,8 +2563,7 @@ Log(lsINFO) << boost::str(boost::format("calcNodeRipple:3c: saCurReq=%s saPrvAct else { // A part of cur. All of prv. (cur as driver) - uint160 uCurrencyID = saPrv.getCurrency(); - STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID), uQualityOut, uCurrencyID); + STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID, uCurIssuerID), uQualityOut, uCurrencyID, uCurIssuerID); Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.getFullText()); saCurAct += saCurOut; @@ -2597,25 +2607,32 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; // For bPrvAccount - const STAmount saPrvBalance = uIndex && bPrvAccount ? rippleBalance(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); - const STAmount saPrvLimit = uIndex && bPrvAccount ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID); + const STAmount saPrvOwed = uIndex && bPrvAccount // Previous account is owed. + ? rippleOwed(uCurAccountID, uPrvAccountID, uCurrencyID) + : STAmount(uCurrencyID, uCurAccountID); + const STAmount saPrvLimit = uIndex && bPrvAccount // Previous account may owe. + ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) + : STAmount(uCurrencyID, uCurAccountID); - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvBalance=%s saPrvLimit=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d bPrvIssue=%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s") % uIndex % uLast + % bPrvIssue % NewcoinAddress::createHumanAccountID(uPrvAccountID) % NewcoinAddress::createHumanAccountID(uCurAccountID) % NewcoinAddress::createHumanAccountID(uNxtAccountID) % STAmount::createHumanCurrency(uCurrencyID) % uQualityIn % uQualityOut - % saPrvBalance.getText() - % saPrvLimit.getText()); + % saPrvOwed.getFullText() + % saPrvLimit.getFullText()); - const STAmount saPrvRedeemReq = bPrvRedeem && saPrvBalance.isNegative() ? -saPrvBalance : STAmount(uCurrencyID, 0); + // Previous can redeem the owed IOUs it holds. + const STAmount saPrvRedeemReq = bPrvRedeem && saPrvOwed.isPositive() ? saPrvOwed : STAmount(uCurrencyID, 0); STAmount& saPrvRedeemAct = pnPrv.saRevRedeem; - const STAmount saPrvIssueReq = bPrvIssue ? saPrvLimit - saPrvBalance : STAmount(uCurrencyID); + // Previous can issue up to limit minus whatever portion of limit already used (not including redeemable amount). + const STAmount saPrvIssueReq = bPrvIssue && saPrvOwed.isNegative() ? saPrvLimit+saPrvOwed : saPrvLimit; STAmount& saPrvIssueAct = pnPrv.saRevIssue; // For !bPrvAccount @@ -2624,27 +2641,25 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // For bNxtAccount const STAmount& saCurRedeemReq = pnCur.saRevRedeem; - STAmount saCurRedeemAct(saCurRedeemReq.getCurrency()); + STAmount saCurRedeemAct(saCurRedeemReq.getCurrency(), saCurRedeemReq.getIssuer()); const STAmount& saCurIssueReq = pnCur.saRevIssue; - STAmount saCurIssueAct(saCurIssueReq.getCurrency()); // Track progress. + STAmount saCurIssueAct(saCurIssueReq.getCurrency(), saCurIssueReq.getIssuer()); // Track progress. // For !bNxtAccount const STAmount& saCurDeliverReq = pnCur.saRevDeliver; - STAmount saCurDeliverAct(saCurDeliverReq.getCurrency()); + STAmount saCurDeliverAct(saCurDeliverReq.getCurrency(), saCurDeliverReq.getIssuer()); - // For uIndex == uLast - const STAmount& saCurWantedReq = pspCur->saOutReq; // XXX Credit limits? - // STAmount saPrvDeliverReq = saPrvBalance.isPositive() ? saPrvLimit - saPrvBalance : saPrvLimit; - STAmount saCurWantedAct(saCurWantedReq.getCurrency()); + // For uIndex == uLast, over all deliverable. + const STAmount& saCurWantedReq = bPrvAccount + ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s/%s saPrvIssueReq=%s/%s saCurWantedReq=%s/%s") - % saPrvRedeemReq.getText() - % saPrvRedeemReq.getHumanCurrency() - % saPrvIssueReq.getText() - % saPrvIssueReq.getHumanCurrency() - % saCurWantedReq.getText() - % saCurWantedReq.getHumanCurrency()); + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurWantedReq=%s") + % saPrvRedeemReq.getFullText() + % saPrvIssueReq.getFullText() + % saCurWantedReq.getFullText()); Log(lsINFO) << pspCur->getJson(); @@ -2698,7 +2713,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (bPrvRedeem && bRedeem // Allowed to redeem. && saCurRedeemReq // Next wants us to redeem. - && saPrvBalance.isNegative()) // Previous has IOUs to redeem. + && saPrvOwed) // Previous has IOUs to redeem. { // Rate : 1.0 : quality out Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : quality out")); @@ -2710,7 +2725,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (bPrvRedeem && bIssue // Allowed to issue. && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. - && saPrvBalance.isNegative() // Previous still has IOUs. + && saPrvOwed // Previous still has IOUs. && saCurIssueReq) // Need some issued. { // Rate : 1.0 : transfer_rate @@ -2723,7 +2738,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (bPrvIssue && bRedeem // Allowed to redeem. && saCurRedeemReq != saCurRedeemAct // Can only redeem if more to be redeemed. - && !saPrvBalance.isNegative()) // Previous has no IOUs. + && !saPrvOwed.isPositive()) // Previous has no IOUs. { // Rate: quality in : quality out Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : quality out")); @@ -2735,7 +2750,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (bPrvIssue && bIssue // Allowed to issue. && saCurRedeemReq == saCurRedeemAct // Can only if issue if more can not be redeemed. - && !saPrvBalance.isNegative() // Previous has no IOUs. + && !saPrvOwed.isPositive() // Previous has no IOUs. && saCurIssueReq != saCurIssueAct) // Need some issued. { // Rate: quality in : 1.0 @@ -2750,14 +2765,15 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // terResult = tenBAD_AMOUNT; bSuccess = false; } - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurRedeemReq=%s saCurIssueReq=%s saPrvBalance=%s saCurRedeemAct=%s saCurIssueAct=%s") + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurRedeemReq=%s saCurIssueReq=%s saPrvOwed=%s saCurRedeemAct=%s saCurIssueAct=%s") % bPrvRedeem % bPrvIssue % bRedeem % bIssue % saCurRedeemReq.getFullText() % saCurIssueReq.getFullText() - % saPrvBalance.getFullText() + % saPrvOwed.getFullText() % saCurRedeemAct.getFullText() % saCurIssueAct.getFullText()); } @@ -2771,7 +2787,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // redeem -> deliver/issue. if (bPrvRedeem && bIssue // Allowed to issue. - && saPrvBalance.isNegative() // Previous redeeming: Previous still has IOUs. + && saPrvOwed.isPositive() // Previous redeeming: Previous still has IOUs. && saCurDeliverReq) // Need some issued. { // Rate : 1.0 : transfer_rate @@ -2781,7 +2797,8 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // issue -> deliver/issue if (bPrvIssue && bIssue // Allowed to issue. - && !saPrvBalance.isNegative() // Previous issuing: Previous has no IOUs. + && (!saPrvOwed.isPositive() // Previous issuing: Never had IOUs. + || saPrvOwed == saPrvRedeemAct) // Previous issuing: Previous has no IOUs left after redeeming. && saCurDeliverReq != saCurDeliverAct) // Need some issued. { // Rate: quality in : 1.0 @@ -2794,6 +2811,15 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // terResult = tenBAD_AMOUNT; bSuccess = false; } + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurDeliverReq=%s saCurDeliverAct=%s saPrvOwed=%s") + % bPrvRedeem + % bPrvIssue + % bRedeem + % bIssue + % saCurDeliverReq.getFullText() + % saCurDeliverAct.getFullText() + % saPrvOwed.getFullText()); } else if (!bPrvAccount && bNxtAccount) { @@ -2906,14 +2932,14 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point // For bNxtAccount const STAmount& saPrvRedeemReq = pnPrv.saFwdRedeem; - STAmount saPrvRedeemAct(saPrvRedeemReq.getCurrency()); + STAmount saPrvRedeemAct(saPrvRedeemReq.getCurrency(), saPrvRedeemReq.getIssuer()); const STAmount& saPrvIssueReq = pnPrv.saFwdIssue; - STAmount saPrvIssueAct(saPrvIssueReq.getCurrency()); + STAmount saPrvIssueAct(saPrvIssueReq.getCurrency(), saPrvIssueReq.getIssuer()); // For !bPrvAccount const STAmount& saPrvDeliverReq = pnPrv.saRevDeliver; - STAmount saPrvDeliverAct(saPrvDeliverReq.getCurrency()); + STAmount saPrvDeliverAct(saPrvDeliverReq.getCurrency(), saPrvDeliverReq.getIssuer()); // For bNxtAccount const STAmount& saCurRedeemReq = pnCur.saRevRedeem; @@ -3003,7 +3029,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point STAmount saIssueCrd = uQualityIn >= QUALITY_ONE ? saPrvIssueReq // No fee. - : STAmount::multiply(saPrvIssueReq, uQualityIn, uCurrencyID); // Fee. + : STAmount::multiply(saPrvIssueReq, uQualityIn, uCurrencyID, saPrvIssueReq.getIssuer()); // Fee. // Amount to credit. saCurReceive = saPrvRedeemReq+saIssueCrd; @@ -3259,8 +3285,8 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin pnCur.uAccountID = uAccountID; pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; - pnCur.saRevRedeem = STAmount(uCurrencyID); - pnCur.saRevIssue = STAmount(uCurrencyID); + pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID); + pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID); if (!bFirst) { diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index e6ff7d6183..6204650fe4 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -226,7 +226,7 @@ protected: void entryModify(SLE::pointer sleEntry); uint32 rippleTransferRate(const uint160& uIssuerID); - STAmount rippleBalance(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID); + 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) From 3fd5e10390538e40492f7b2cc4e43cabf0b9967d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 25 Aug 2012 18:03:05 -0700 Subject: [PATCH 117/426] More ripple engine fixes. --- src/TransactionEngine.cpp | 82 ++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 477ee82840..3a40198743 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1886,12 +1886,11 @@ void TransactionEngine::calcOfferBridgeNext( // <-- bSuccess: false= no transfer // XXX Make sure missing ripple path is addressed cleanly. bool TransactionEngine::calcNodeOfferRev( - unsigned int uIndex, // 0 < uIndex < uLast-1 + unsigned int uIndex, // 0 < uIndex < uLast PathState::pointer pspCur, - bool bMultiQuality - ) + bool bMultiQuality) { - bool bSuccess = false; + bool bSuccess = false; paymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; paymentNode& pnCur = pspCur->vpnNodes[uIndex]; @@ -2092,7 +2091,7 @@ bool TransactionEngine::calcNodeOfferRev( } bool TransactionEngine::calcNodeOfferFwd( - unsigned int uIndex, // 0 < uIndex < uLast-1 + unsigned int uIndex, // 0 < uIndex < uLast PathState::pointer pspCur, bool bMultiQuality ) @@ -2583,8 +2582,8 @@ Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCur // Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver; bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) { - bool bSuccess = true; - const unsigned int uLast = pspCur->vpnNodes.size() - 1; + bool bSuccess = true; + const unsigned int uLast = pspCur->vpnNodes.size() - 1; paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; paymentNode& pnCur = pspCur->vpnNodes[uIndex]; @@ -2636,7 +2635,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point STAmount& saPrvIssueAct = pnPrv.saRevIssue; // For !bPrvAccount - const STAmount saPrvDeliverReq = STAmount::saFromSigned(uCurrencyID, -1); // Unlimited. + const STAmount saPrvDeliverReq = STAmount::saFromSigned(uCurrencyID, uCurAccountID, -1); // Unlimited. STAmount& saPrvDeliverAct = pnPrv.saRevDeliver; // For bNxtAccount @@ -2650,16 +2649,9 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point const STAmount& saCurDeliverReq = pnCur.saRevDeliver; STAmount saCurDeliverAct(saCurDeliverReq.getCurrency(), saCurDeliverReq.getIssuer()); - // For uIndex == uLast, over all deliverable. - const STAmount& saCurWantedReq = bPrvAccount - ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. - : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. - STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurWantedReq=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s") % saPrvRedeemReq.getFullText() - % saPrvIssueReq.getFullText() - % saCurWantedReq.getFullText()); + % saPrvIssueReq.getFullText()); Log(lsINFO) << pspCur->getJson(); @@ -2674,7 +2666,14 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point else if (uIndex == uLast) { // account --> ACCOUNT --> $ - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $")); + // Overall deliverable. + const STAmount& saCurWantedReq = bPrvAccount + ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $ : saCurWantedReq=%s") + % saCurWantedReq.getFullText()); // Calculate redeem if (bRedeem @@ -2826,7 +2825,13 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (uIndex == uLast) { // offer --> ACCOUNT --> $ - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $")); + const STAmount& saCurWantedReq = bPrvAccount + ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $ : saCurWantedReq=%s") + % saCurWantedReq.getFullText()); // Rate: quality in : 1.0 calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct); @@ -2907,9 +2912,12 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // The current node: specify what to push through to next. // - Output to next node minus fees. // Perform balance adjustment with previous. -bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) +bool TransactionEngine::calcNodeAccountFwd( + unsigned int uIndex, // 0 <= uIndex <= uLast + PathState::pointer pspCur, + bool bMultiQuality) { - bool bSuccess = true; + bool bSuccess = true; const unsigned int uLast = pspCur->vpnNodes.size() - 1; paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; @@ -2921,14 +2929,14 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point const bool bPrvAccount = !!(pnPrv.uFlags & STPathElement::typeAccount); const bool bNxtAccount = !!(pnNxt.uFlags & STPathElement::typeAccount); - const uint160& uPrvAccountID = pnPrv.uAccountID; const uint160& uCurAccountID = pnCur.uAccountID; + const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. const uint160& uCurrencyID = pnCur.uCurrencyID; - uint32 uQualityIn = rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID); - uint32 uQualityOut = rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID); + uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; + uint32 uQualityOut = uIndex == uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; // For bNxtAccount const STAmount& saPrvRedeemReq = pnPrv.saFwdRedeem; @@ -2952,17 +2960,17 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point const STAmount& saCurDeliverReq = pnCur.saRevDeliver; STAmount& saCurDeliverAct = pnCur.saFwdDeliver; - STAmount& saCurReceive = pspCur->saOutAct; - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uIndex=%d/%d saCurRedeemReq=%s/%s saCurIssueReq=%s/%s saCurDeliverReq=%s/%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uIndex=%d/%d bRedeem=%d bIssue=%d saPrvRedeemReq=%s saPrvIssueReq=%s saPrvDeliverReq=%s saCurRedeemReq=%s saCurIssueReq=%s saCurDeliverReq=%s") % uIndex % uLast - % saCurRedeemReq.getText() - % saCurRedeemReq.getHumanCurrency() - % saCurIssueReq.getText() - % saCurIssueReq.getHumanCurrency() - % saCurDeliverReq.getText() - % saCurDeliverReq.getHumanCurrency()); + % bRedeem + % bIssue + % saPrvRedeemReq.getFullText() + % saPrvIssueReq.getFullText() + % saPrvDeliverReq.getFullText() + % saCurRedeemReq.getFullText() + % saCurIssueReq.getFullText() + % saCurDeliverReq.getFullText()); // Ripple through account. @@ -3027,7 +3035,9 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point // Last node. Accept all funds. Calculate amount actually to credit. - STAmount saIssueCrd = uQualityIn >= QUALITY_ONE + STAmount& saCurReceive = pspCur->saOutAct; + + STAmount saIssueCrd = uQualityIn >= QUALITY_ONE ? saPrvIssueReq // No fee. : STAmount::multiply(saPrvIssueReq, uQualityIn, uCurrencyID, saPrvIssueReq.getIssuer()); // Fee. @@ -3117,6 +3127,8 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point // offer --> ACCOUNT --> $ Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $")); + STAmount& saCurReceive = pspCur->saOutAct; + // Amount to credit. saCurReceive = saPrvDeliverAct; @@ -3143,7 +3155,7 @@ bool TransactionEngine::calcNodeAccountFwd(unsigned int uIndex, PathState::point && saCurIssueReq) // Current wants issue. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct); } // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. From bb7f692a762475159db9c85a842b25e56a6a1d20 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 26 Aug 2012 20:38:35 -0700 Subject: [PATCH 118/426] Rework transaction engine result codes. --- src/NetworkOPs.cpp | 8 +- src/TransactionEngine.cpp | 460 ++++++++++++++++---------------------- src/TransactionEngine.h | 124 +++++----- 3 files changed, 262 insertions(+), 330 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index adc8a3c7b9..40cd4cc856 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -85,7 +85,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, } TransactionEngineResult r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, tepNONE); - if (r == tenFAILED) throw Fault(IO_ERROR); + if (r == tefFAILURE) throw Fault(IO_ERROR); if (r == terPRE_SEQ) { // transaction should be held @@ -95,14 +95,14 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, mLedgerMaster->addHeldTransaction(trans); return trans; } - if ((r == terPAST_SEQ) || (r == terPAST_LEDGER)) + if ((r == tefPAST_SEQ)) { // duplicate or conflict Log(lsINFO) << "Transaction is obsolete"; trans->setStatus(OBSOLETE); return trans; } - if (r == terSUCCESS) + if (r == tesSUCCESS) { Log(lsINFO) << "Transaction is now included"; trans->setStatus(INCLUDED); @@ -875,7 +875,7 @@ void NetworkOPs::pubLedger(const Ledger::pointer& lpAccepted) SerializedTransaction::pointer stTxn = theApp->getMasterTransaction().fetch(item, false, 0); // XXX Need to support other results. // XXX Need to give failures too. - TransactionEngineResult terResult = terSUCCESS; + TransactionEngineResult terResult = tesSUCCESS; if (bAll) { diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 3a40198743..19d17e4113 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -31,61 +31,50 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std const char* cpToken; const char* cpHuman; } transResultInfoA[] = { - { tenBAD_ADD_AUTH, "tenBAD_ADD_AUTH", "Not authorized to add account." }, - { tenBAD_AMOUNT, "tenBAD_AMOUNT", "Can only send positive amounts." }, - { tenBAD_CLAIM_ID, "tenBAD_CLAIM_ID", "Malformed." }, - { tenBAD_EXPIRATION, "tenBAD_EXPIRATION", "Malformed." }, - { tenBAD_GEN_AUTH, "tenBAD_GEN_AUTH", "Not authorized to claim generator." }, - { tenBAD_ISSUER, "tenBAD_ISSUER", "Malformed." }, - { tenBAD_OFFER, "tenBAD_OFFER", "Malformed." }, - { tenBAD_PATH, "tenBAD_PATH", "Malformed: path." }, - { tenBAD_PATH_COUNT, "tenBAD_PATH_COUNT", "Malformed: too many paths." }, - { tenBAD_PUBLISH, "tenBAD_PUBLISH", "Malformed: bad publish." }, - { 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." }, - { tenCREATED, "tenCREATED", "Can't add an already created account." }, - { tenCREATEXNS, "tenCREATEXNS", "Can not specify non XNS for Create." }, - { tenDST_IS_SRC, "tenDST_IS_SRC", "Destination may not be source." }, - { tenDST_NEEDED, "tenDST_NEEDED", "Destination not specified." }, - { tenEXPIRED, "tenEXPIRED", "Won't add an expired offer." }, - { tenEXPLICITXNS, "tenEXPLICITXNS", "XNS is used by default, don't specify it." }, - { tenFAILED, "tenFAILED", "Something broke horribly" }, - { tenGEN_IN_USE, "tenGEN_IN_USE", "Generator already in use." }, - { tenINSUF_FEE_P, "tenINSUF_FEE_P", "fee totally insufficient" }, - { tenINVALID, "tenINVALID", "The transaction is ill-formed" }, - { tenMSG_SET, "tenMSG_SET", "Can't change a message key." }, - { tenREDUNDANT, "tenREDUNDANT", "Sends same currency to self." }, - { tenRIPPLE_EMPTY, "tenRIPPLE_EMPTY", "PathSet with no paths." }, - { tenUNKNOWN, "tenUNKNOWN", "The transactions requires logic not implemented yet" }, - { terALREADY, "terALREADY", "The exact transaction was already in this ledger" }, - { terBAD_AUTH, "terBAD_AUTH", "Transaction's public key is not authorized." }, - { terBAD_AUTH_MASTER, "terBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." }, - { terBAD_LEDGER, "terBAD_LEDGER", "Ledger in unexpected state." }, - { terBAD_RIPPLE, "terBAD_RIPPLE", "No ripple path can be satisfied." }, - { terBAD_SEQ, "terBAD_SEQ", "This sequence number should be zero for prepaid transactions." }, + { tefALREADY, "tefALREADY", "The exact transaction was already in this ledger" }, + { tefBAD_ADD_AUTH, "tefBAD_ADD_AUTH", "Not authorized to add account." }, + { tefBAD_AUTH, "tefBAD_AUTH", "Transaction's public key is not authorized." }, + { tefBAD_CLAIM_ID, "tefBAD_CLAIM_ID", "Malformed." }, + { tefBAD_GEN_AUTH, "tefBAD_GEN_AUTH", "Not authorized to claim generator." }, + { tefBAD_LEDGER, "tefBAD_LEDGER", "Ledger in unexpected state." }, + { tefCLAIMED, "tefCLAIMED", "Can not claim a previously claimed account." }, + { tefCREATED, "tefCREATED", "Can't add an already created account." }, + { tefGEN_IN_USE, "tefGEN_IN_USE", "Generator already in use." }, + { tefPAST_SEQ, "tefPAST_SEQ", "This sequence number has already past" }, + + { telBAD_PATH_COUNT, "telBAD_PATH_COUNT", "Malformed: too many paths." }, + { telINSUF_FEE_P, "telINSUF_FEE_P", "Fee insufficient." }, + + { temBAD_AMOUNT, "temBAD_AMOUNT", "Can only send positive amounts." }, + { temBAD_AUTH_MASTER, "temBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." }, + { temBAD_EXPIRATION, "temBAD_EXPIRATION", "Malformed." }, + { temBAD_ISSUER, "temBAD_ISSUER", "Malformed." }, + { temBAD_OFFER, "temBAD_OFFER", "Malformed." }, + { temBAD_PUBLISH, "temBAD_PUBLISH", "Malformed: bad publish." }, + { temBAD_SET_ID, "temBAD_SET_ID", "Malformed." }, + { temCREATEXNS, "temCREATEXNS", "Can not specify non XNS for Create." }, + { temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." }, + { temDST_NEEDED, "temDST_NEEDED", "Destination not specified." }, + { temINSUF_FEE_P, "temINSUF_FEE_P", "Fee not allowed." }, + { temINVALID, "temINVALID", "The transaction is ill-formed" }, + { temREDUNDANT, "temREDUNDANT", "Sends same currency to self." }, + { temRIPPLE_EMPTY, "temRIPPLE_EMPTY", "PathSet with no paths." }, + { temUNKNOWN, "temUNKNOWN", "The transactions requires logic not implemented yet" }, + { terDIR_FULL, "terDIR_FULL", "Can not add entry to full dir." }, { terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." }, - { terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee" }, - { terINSUF_FEE_T, "terINSUF_FEE_T", "fee insufficient now (account doesn't exist, network load)" }, - { terNODE_NOT_FOUND, "terNODE_NOT_FOUND", "Can not delete a directory node." }, - { terNODE_NOT_MENTIONED, "terNODE_NOT_MENTIONED", "Could not remove node from a directory." }, - { terNODE_NO_ROOT, "terNODE_NO_ROOT", "Directory doesn't exist." }, - { terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist" }, + { terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee." }, + { terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist." }, { terNO_DST, "terNO_DST", "The destination does not exist" }, { terNO_LINE_NO_ZERO, "terNO_LINE_NO_ZERO", "Can't zero non-existant line, destination might make it." }, - { terNO_PATH, "terNO_PATH", "No path existed or met transaction/balance requirements" }, { terOFFER_NOT_FOUND, "terOFFER_NOT_FOUND", "Can not cancel offer." }, - { 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" }, - { terUNCLAIMED, "terUNCLAIMED", "Can not use an unclaimed account." }, { terUNFUNDED, "terUNFUNDED", "Source account had insufficient balance for transaction." }, + + { tesSUCCESS, "tesSUCCESS", "The transaction was applied" }, }; int iIndex = NUMBER(transResultInfoA); @@ -433,7 +422,7 @@ TransactionEngineResult TransactionEngine::offerDelete(const SLE::pointer& sleOf uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode); TransactionEngineResult terResult = dirDelete(false, uOwnerNode, Ledger::getOwnerDirIndex(uOwnerID), uOfferIndex); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { uint256 uDirectory = sleOffer->getIFieldH256(sfBookDirectory); uint64 uBookNode = sleOffer->getIFieldU64(sfBookNode); @@ -536,7 +525,7 @@ TransactionEngineResult TransactionEngine::dirAdd( Log(lsINFO) << "dirAdd: appending: Node: " << strHex(uNodeDir); // Log(lsINFO) << "dirAdd: appending: PREV: " << svIndexes.peekValue()[0].ToString(); - return terSUCCESS; + return tesSUCCESS; } // --> bKeepRoot: True, if we never completely clean up, after we overflow the root node. @@ -559,7 +548,7 @@ TransactionEngineResult TransactionEngine::dirDelete( { Log(lsWARNING) << "dirDelete: no such node"; - return terBAD_LEDGER; + return tefBAD_LEDGER; } STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes); @@ -575,7 +564,7 @@ TransactionEngineResult TransactionEngine::dirDelete( Log(lsWARNING) << "dirDelete: no such entry"; - return terBAD_LEDGER; + return tefBAD_LEDGER; } // Remove the element. @@ -655,14 +644,14 @@ TransactionEngineResult TransactionEngine::dirDelete( { Log(lsWARNING) << "dirDelete: previous node is missing"; - return terBAD_LEDGER; + return tefBAD_LEDGER; } if (!sleNext) { Log(lsWARNING) << "dirDelete: next node is missing"; - return terBAD_LEDGER; + return tefBAD_LEDGER; } // Fix previous to point to its new next. @@ -704,7 +693,7 @@ TransactionEngineResult TransactionEngine::dirDelete( } } - return terSUCCESS; + return tesSUCCESS; } // Return the first entry and advance uDirEntry. @@ -775,7 +764,7 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac { Log(lsWARNING) << "createGenerator: bad signature unauthorized generator claim"; - return tenBAD_GEN_AUTH; + return tefBAD_GEN_AUTH; } // Create generator. @@ -797,7 +786,7 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac // Generator is already in use. Regular passphrases limited to one wallet. Log(lsWARNING) << "createGenerator: generator already in use"; - return tenGEN_IN_USE; + return tefGEN_IN_USE; } // Set the public key needed to use the account. @@ -807,7 +796,7 @@ TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransac mTxnAccount->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); - return terSUCCESS; + return tesSUCCESS; } SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint256& uIndex) @@ -842,9 +831,9 @@ SLE::pointer TransactionEngine::entryCreate(LedgerEntryType letType, const uint2 return sleNew; } -void TransactionEngine::entryDelete(SLE::pointer sleEntry, bool unfunded) +void TransactionEngine::entryDelete(SLE::pointer sleEntry, bool bUnfunded) { - mNodes.entryDelete(sleEntry, unfunded); + mNodes.entryDelete(sleEntry, bUnfunded); } void TransactionEngine::entryModify(SLE::pointer sleEntry) @@ -925,14 +914,14 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } #endif - TransactionEngineResult terResult = terSUCCESS; + TransactionEngineResult terResult = tesSUCCESS; uint256 txID = txn.getTransactionID(); if (!txID) { Log(lsWARNING) << "applyTransaction: invalid transaction id"; - terResult = tenINVALID; + terResult = temINVALID; } // @@ -946,21 +935,21 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // XXX This could be a lot cleaner to prevent unnecessary copying. NewcoinAddress naSigningPubKey; - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) naSigningPubKey = NewcoinAddress::createAccountPublic(txn.peekSigningPubKey()); // Consistency: really signed. - if ((terSUCCESS == terResult) && ((params & tepNO_CHECK_SIGN) == 0) && !txn.checkSign(naSigningPubKey)) + if ((tesSUCCESS == terResult) && ((params & tepNO_CHECK_SIGN) == 0) && !txn.checkSign(naSigningPubKey)) { Log(lsWARNING) << "applyTransaction: Invalid transaction: bad signature"; - terResult = tenINVALID; + terResult = temINVALID; } STAmount saCost = theConfig.FEE_DEFAULT; // Customize behavoir based on transaction type. - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { switch (txn.getTxnType()) { @@ -997,27 +986,28 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran case ttINVALID: Log(lsWARNING) << "applyTransaction: Invalid transaction: ttINVALID transaction type"; - terResult = tenINVALID; + terResult = temINVALID; break; default: Log(lsWARNING) << "applyTransaction: Invalid transaction: unknown transaction type"; - terResult = tenUNKNOWN; + terResult = temUNKNOWN; break; } } STAmount saPaid = txn.getTransactionFee(); - if (terSUCCESS == terResult && (params & tepNO_CHECK_FEE) == tepNONE) + if (tesSUCCESS == terResult && (params & tepNO_CHECK_FEE) == tepNONE) { if (!!saCost) { + // XXX DO NOT CHECK ON CONSENSUS PASS if (saPaid < saCost) { Log(lsINFO) << "applyTransaction: insufficient fee"; - terResult = tenINSUF_FEE_P; + terResult = telINSUF_FEE_P; } } else @@ -1027,21 +1017,21 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // Transaction is malformed. Log(lsWARNING) << "applyTransaction: fee not allowed"; - terResult = tenINSUF_FEE_P; + terResult = temINSUF_FEE_P; } } } // Get source account ID. mTxnAccountID = txn.getSourceAccount().getAccountID(); - if (terSUCCESS == terResult && !mTxnAccountID) + if (tesSUCCESS == terResult && !mTxnAccountID) { Log(lsWARNING) << "applyTransaction: bad source id"; - terResult = tenINVALID; + terResult = temINVALID; } - if (terSUCCESS != terResult) + if (tesSUCCESS != terResult) return terResult; boost::recursive_mutex::scoped_lock sl(mLedger->mLock); @@ -1069,7 +1059,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } // Check if account claimed. - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { switch (txn.getTxnType()) { @@ -1078,7 +1068,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { Log(lsWARNING) << "applyTransaction: Account already claimed."; - terResult = tenCLAIMED; + terResult = tefCLAIMED; } break; @@ -1089,7 +1079,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } // Consistency: Check signature - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { switch (txn.getTxnType()) { @@ -1102,7 +1092,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran Log(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID(); Log(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID(); - terResult = tenBAD_CLAIM_ID; + terResult = tefBAD_CLAIM_ID; } break; @@ -1115,7 +1105,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran Log(lsWARNING) << "sourceAccountID: " << naSigningPubKey.humanAccountID(); Log(lsWARNING) << "txn accountID: " << txn.getSourceAccount().humanAccountID(); - terResult = tenBAD_SET_ID; + terResult = temBAD_SET_ID; } break; @@ -1135,13 +1125,13 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { Log(lsINFO) << "applyTransaction: Delay: Not authorized to use account."; - terResult = terBAD_AUTH; + terResult = tefBAD_AUTH; } else { Log(lsINFO) << "applyTransaction: Invalid: Not authorized to use account."; - terResult = terBAD_AUTH_MASTER; + terResult = temBAD_AUTH_MASTER; } break; } @@ -1149,7 +1139,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran // Deduct the fee, so it's not available during the transaction. // Will only write the account back, if the transaction succeeds. - if (terSUCCESS != terResult || !saCost) + if (tesSUCCESS != terResult || !saCost) { nothing(); } @@ -1168,7 +1158,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } // Validate sequence - if (terSUCCESS != terResult) + if (tesSUCCESS != terResult) { nothing(); } @@ -1190,13 +1180,13 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { Log(lsWARNING) << "applyTransaction: duplicate sequence number"; - terResult = terALREADY; + terResult = tefALREADY; } else { Log(lsWARNING) << "applyTransaction: past sequence number"; - terResult = terPAST_SEQ; + terResult = tefPAST_SEQ; } } else @@ -1212,12 +1202,12 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran { Log(lsINFO) << "applyTransaction: bad sequence for pre-paid transaction"; - terResult = terPAST_SEQ; + terResult = tefPAST_SEQ; } } mTxnAccount->setIFieldU32(sfLastSignedSeq, mLedger->getLedgerSeq()); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { entryModify(mTxnAccount); @@ -1237,7 +1227,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran case ttINVALID: Log(lsINFO) << "applyTransaction: invalid type"; - terResult = tenINVALID; + terResult = temINVALID; break; case ttINVOICE: @@ -1273,7 +1263,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran break; default: - terResult = tenUNKNOWN; + terResult = temUNKNOWN; break; } } @@ -1285,7 +1275,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran Log(lsINFO) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman; - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { txnWrite(); @@ -1365,12 +1355,6 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact { nothing(); } - else if (mTxnAccount->getIFieldPresent(sfMessageKey)) - { - Log(lsINFO) << "doAccountSet: can not change message key"; - - return tenMSG_SET; - } else { Log(lsINFO) << "doAccountSet: set message key"; @@ -1433,7 +1417,7 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact { Log(lsINFO) << "doAccountSet: bad publish"; - return tenBAD_PUBLISH; + return temBAD_PUBLISH; } else if (bPublishHash && bPublishSize) { @@ -1458,7 +1442,7 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact Log(lsINFO) << "doAccountSet<"; - return terSUCCESS; + return tesSUCCESS; } TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& txn) @@ -1474,7 +1458,7 @@ TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransaction& txn) { - TransactionEngineResult terResult = terSUCCESS; + TransactionEngineResult terResult = tesSUCCESS; Log(lsINFO) << "doCreditSet>"; // Check if destination makes sense. @@ -1484,13 +1468,13 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti { Log(lsINFO) << "doCreditSet: Invalid transaction: Destination account not specifed."; - return tenDST_NEEDED; + return temDST_NEEDED; } else if (mTxnAccountID == uDstAccountID) { Log(lsINFO) << "doCreditSet: Invalid transaction: Can not extend credit to self."; - return tenDST_IS_SRC; + return temDST_IS_SRC; } SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); @@ -1603,7 +1587,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti terResult = dirAdd(uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex()); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) terResult = dirAdd(uSrcRef, Ledger::getOwnerDirIndex(uDstAccountID), sleRippleState->getIndex()); } @@ -1655,7 +1639,7 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac std::cerr << "doNicknameSet<" << std::endl; - return terSUCCESS; + return tesSUCCESS; } TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransaction& txn) @@ -1689,7 +1673,7 @@ TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransa std::cerr << "doPasswordFund<" << std::endl; - return terSUCCESS; + return tesSUCCESS; } TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransaction& txn) @@ -1722,7 +1706,7 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac // <-- pnDst.saReceive // <-- pnDst.saIOUForgive // <-- pnDst.saIOUAccept -// <-- terResult : terSUCCESS = no error and if !bAllowPartial complelely satisfied wanted. +// <-- terResult : tesSUCCESS = no error and if !bAllowPartial complelely satisfied wanted. // <-> usOffersDeleteAlways: // <-> usOffersDeleteOnSuccess: TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bool bAllowPartial) @@ -1756,7 +1740,7 @@ TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bo pnDst.saIOUForgive, bAllowPartial); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { // Issue to wanted. terResult = calcOfferFill( @@ -1766,7 +1750,7 @@ TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bo bAllowPartial); } - if (terSUCCESS == terResult && !bAllowPartial) + if (tesSUCCESS == terResult && !bAllowPartial) { STAmount saTotal = pnDst.saIOUForgive + pnSrc.saIOUAccept; @@ -2147,6 +2131,7 @@ bool TransactionEngine::calcNodeOfferFwd( while (saPrvDlvReq != saPrvDlvAct // Have not met request. && dirNext(uDirectTip, sleDirectDir, uEntry, uCurIndex)) { + // Have an entry from the directory. SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex); uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); const STAmount& saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); @@ -2155,7 +2140,33 @@ bool TransactionEngine::calcNodeOfferFwd( STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. STAmount saCurOfrInMax = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); - if (!!uNxtAccountID) + if (!saCurOfrFunds) + { +#ifdef WORK_IN_PROGRESS + // Offer is unfunded. + pspCur->usUnfunded.add(uCurIndex); // Add offer to found unfunded. + + entryDelete(sleCurOfr, true); // Delete unfunded offer. + + // Delete unfunded offer from owner's directory. + const uint64 uOwnerNode = sleCurOffer->getIFieldU64(sfOwnerNode); + + terResult = dirDelete( + true, // YYY We don't delete owner directories? + uOwnerNode, + uDirectTip, + uCurIndex); + + // Delete unfunded offer from quality directory. + // XXX Need a dir walking version of delete. + terResult = dirDelete( + false, // Don't need to keep root. + const uint64& uNodeDir, + uDirectTip, + uCurIndex); +#endif + } + else if (!!uNxtAccountID) { // Next is an account. @@ -2165,19 +2176,24 @@ bool TransactionEngine::calcNodeOfferFwd( const bool bFee = saFeeRate != saOne; const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID, uCurIssuerID); - const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. - const STAmount saOutCost = MIN( - bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutBase, - saCurOfrFunds); // Limit cost by fees & funds. + const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. + const STAmount saOutCostRaw= bFee + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) + : saOutBase; + const STAmount saOutCost = MIN(saOutCostRaw, saCurOfrFunds); // Limit cost by fees & funds. const STAmount saOutDlvAct = bFee ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; // Out amount after fees. + : saOutCost; // Out amount after fees. // Compute input w/o fees required. const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID, uCurIssuerID); + // XXX Send from offer owner +// accountSend(uCurIssuerID, uNxtAccountID, saOutDlvAct); + saCurDlvAct += saOutDlvAct; // Portion of driver served. + +// XXX accountCredit(uCurIssuerID, uNxtAccountID, saOutDlvAct); + saPrvDlvAct += saInDlvAct; // Portion needed in previous. } else @@ -2298,7 +2314,7 @@ void TransactionEngine::calcNodeOffer( STAmount& saGot ) const { - TransactionEngineResult terResult = tenUNKNOWN; + TransactionEngineResult terResult = temUNKNOWN; // Direct: not bridging via XNS bool bDirectNext = true; // True, if need to load. @@ -2425,10 +2441,10 @@ void TransactionEngine::calcNodeOffer( { // No more offers. Declare success, even if none returned. saGot = saWanted-saNeed; - terResult = terSUCCESS; + terResult = tesSUCCESS; } - if (terSUCCESS != terResult) + if (tesSUCCESS != terResult) { STAmount& saAvailIn = bUseBridge ? saBridgeIn : saDirectIn; STAmount& saAvailOut = bUseBridge ? saBridgeOut : saDirectOut; @@ -2700,7 +2716,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saCurWantedAct) { // Must have processed something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } } @@ -2761,7 +2777,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saCurRedeemAct && !saCurIssueAct) { // Must want something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } @@ -2807,7 +2823,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saCurDeliverAct) { // Must want something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } @@ -2839,7 +2855,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saCurWantedAct) { // Must have processed something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } } @@ -2877,7 +2893,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saPrvDeliverAct) { // Must want something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } } @@ -2898,7 +2914,7 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point if (!saCurDeliverAct) { // Must want something. - // terResult = tenBAD_AMOUNT; + // terResult = temBAD_AMOUNT; bSuccess = false; } } @@ -3196,6 +3212,12 @@ bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::poi } // Make sure the path delivers to uAccountID: uCurrencyID from uIssuerID. +// +// Rules: +// - Currencies must be converted via an offer. +// - A node names it's output. +// - A ripple nodes output issuer must be the node's account or the next node's account. +// - Offers can only go directly to another offer if the currency and issuer are an exact match. bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) { const paymentNode& pnPrv = vpnNodes.back(); @@ -3209,23 +3231,6 @@ bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssu if (pnPrv.uCurrencyID != uCurrencyID) { // Need to convert via an offer. -#if 0 -// XXX Don't know if need this. - bool bPrvAccount = !!pnPrv.uAccountID; - - if (!bPrvAccount) // Previous is an offer. - { - // Direct offer --> offer is not allowed for non-stamps. - // Need to ripple through uIssuerID's account. - - bValid = pushNode( - STPathElement::typeAccount - | STPathElement::typeIssue, - pnPrv.uIssuerID, // Intermediate account is the needed issuer. - CURRENCY_ONE, // Inherit from previous. - ACCOUNT_ONE); // Default same as account. - } -#endif bValid = pushNode( STPathElement::typeCurrency // Offer. @@ -3550,7 +3555,8 @@ Json::Value PathState::getJson() const } // Calculate a node and its previous nodes. -// From the destination work towards the source calculating how much must be asked for. +// From the destination work in reverse towards the source calculating how much must be asked for. +// Then work forward, figuring out how much can actually be delivered. // --> bAllowPartial: If false, fail if can't meet requirements. // <-- bValid: true=success, false=insufficient funds / liqudity. // <-> pnNodes: @@ -3643,13 +3649,13 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction { Log(lsINFO) << "doPayment: Invalid transaction: Payment destination account not specifed."; - return tenDST_NEEDED; + return temDST_NEEDED; } else if (!saDstAmount.isPositive()) { Log(lsINFO) << "doPayment: Invalid transaction: bad amount: " << saDstAmount.getHumanCurrency() << " " << saDstAmount.getText(); - return tenBAD_AMOUNT; + return temBAD_AMOUNT; } else if (mTxnAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths) { @@ -3659,7 +3665,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction % uSrcCurrency.ToString() % uDstCurrency.ToString()); - return tenREDUNDANT; + return temREDUNDANT; } else if (bMax && ((saMaxAmount == saDstAmount && saMaxAmount.getCurrency() == saDstAmount.getCurrency()) @@ -3667,7 +3673,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction { Log(lsINFO) << "doPayment: Invalid transaction: bad SendMax."; - return tenINVALID; + return temINVALID; } SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); @@ -3679,7 +3685,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction // This restriction could be relaxed. Log(lsINFO) << "doPayment: Invalid transaction: Create account may only fund XNS."; - return tenCREATEXNS; + return temCREATEXNS; } else if (!bCreate) { @@ -3718,112 +3724,26 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction mTxnAccount->setIFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); sleDst->setIFieldAmount(sfBalance, sleDst->getIValueFieldAmount(sfBalance) + saDstAmount); - return terSUCCESS; + return tesSUCCESS; } // // Ripple payment // -#if 0 -// Disabled to make sure full ripple code is correct. - // Try direct ripple first. - if (!bNoRippleDirect && mTxnAccountID != uDstAccountID && uSrcCurrency == uDstCurrency) - { - // XXX Does not handle quality. - SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uDstCurrency)); - - if (sleRippleState) - { - // There is a direct credit-line of some direction. - // - We can always pay IOUs back. - // - We can issue IOUs to the limit. - uint160 uLowID = sleRippleState->getIValueFieldAccount(sfLowID).getAccountID(); - uint160 uHighID = sleRippleState->getIValueFieldAccount(sfHighID).getAccountID(); - bool bSendHigh = uLowID == mTxnAccountID && uHighID == uDstAccountID; - bool bSendLow = uLowID == uDstAccountID && uHighID == mTxnAccountID; - // Flag we need if we end up owing IOUs. - uint32 uFlags = bSendHigh ? lsfLowIndexed : lsfHighIndexed; - - assert(bSendLow || bSendHigh); - - STAmount saDstLimit = sleRippleState->getIValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit); - - STAmount saDstBalance = sleRippleState->getIValueFieldAmount(sfBalance); - if (bSendHigh) - { - // Put balance in dst terms. - saDstBalance.negate(); - } - - saDstBalance += saDstAmount; - if (saDstBalance > saDstLimit) - { - // Would exceed credit limit. - // YYY Note: in the future could push out other credits to make payment fit. - - Log(lsINFO) << "doPayment: Delay transaction: Over limit: proposed balance=" - << saDstBalance.getText() - << " limit=" - << saDstLimit.getText(); - - return terOVER_LIMIT; - } - - if (!saDstBalance) - { - // XXX May be able to delete indexes for credit limits which are zero. - nothing(); - } - else if (saDstBalance.isNegative()) - { - // dst still has outstanding IOUs, sle already indexed. - nothing(); - } - // src has outstanding IOUs, sle should be indexed. - else if (! (sleRippleState->getFlags() & uFlags)) - { - // Need to add index. - TransactionEngineResult terResult = terSUCCESS; - uint64 uSrcRef; // Ignored, ripple_state dirs never delete. - - terResult = dirAdd( - uSrcRef, - Ledger::getOwnerDirIndex(mTxnAccountID), // The source ended up owing. - sleRippleState->getIndex()); // Adding current entry. - - if (terSUCCESS != terResult) - return terResult; - - sleRippleState->setFlag(uFlags); // Note now indexed. - } - - if (bSendHigh) - { - // Put balance in low terms. - saDstBalance.negate(); - } - - sleRippleState->setIFieldAmount(sfBalance, saDstBalance); - entryModify(sleRippleState); - - return terSUCCESS; - } - } -#endif - STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); if (bNoRippleDirect && spsPaths.isEmpty()) { Log(lsINFO) << "doPayment: Invalid transaction: No paths and direct ripple not allowed."; - return tenRIPPLE_EMPTY; + return temRIPPLE_EMPTY; } + // XXX Skip check if final processing. if (spsPaths.getPathCount() > RIPPLE_PATHS_MAX) { - return tenBAD_PATH_COUNT; + return telBAD_PATH_COUNT; } // Incrementally search paths. @@ -3874,9 +3794,10 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction TransactionEngineResult terResult; STAmount saPaid; STAmount saWanted; + LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. - terResult = tenUNKNOWN; - while (tenUNKNOWN == terResult) + terResult = temUNKNOWN; + while (temUNKNOWN == terResult) { PathState::pointer pspBest; LedgerEntrySet lesCheckpoint = mNodes; @@ -3903,25 +3824,29 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction mNodes.swapWith(pspBest->lesEntries); // Figure out if done. - if (tenUNKNOWN == terResult && saPaid == saWanted) + if (temUNKNOWN == terResult && saPaid == saWanted) { - terResult = terSUCCESS; + terResult = tesSUCCESS; } } - // Ran out of paths. + // Not done and ran out of paths. else if (!bPartialPayment) { // Partial payment not allowed. - terResult = terPATH_PARTIAL; // XXX No effect, except unfunded and charge fee. + terResult = terPATH_PARTIAL; + mNodes = lesBase; // Revert to just fees charged. } + // Partial payment ok. else if (!saPaid) { - // Nothing claimed. - terResult = terPATH_EMPTY; // XXX No effect except unfundeds and charge fee. + // No payment at all. + // XXX Mark for retry? + terResult = terPATH_EMPTY; + mNodes = lesBase; // Revert to just fees charged. } else { - terResult = terSUCCESS; + terResult = tesSUCCESS; } } @@ -3954,7 +3879,7 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti { std::cerr << "WalletAdd: unauthorized: bad signature " << std::endl; - return tenBAD_ADD_AUTH; + return tefBAD_ADD_AUTH; } SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); @@ -3963,7 +3888,7 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti { std::cerr << "WalletAdd: account already created" << std::endl; - return tenCREATED; + return tefCREATED; } STAmount saAmount = txn.getITFieldAmount(sfAmount); @@ -3993,12 +3918,12 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti std::cerr << "WalletAdd<" << std::endl; - return terSUCCESS; + return tesSUCCESS; } TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction& txn) { - return tenUNKNOWN; + return temUNKNOWN; } // Take as much as possible. Adjusts account balances. Charges fees on top to taker. @@ -4007,7 +3932,7 @@ TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction // --> saTakerGets: What the taker wanted (w/ issuer) // <-- saTakerPaid: What taker paid not including fees. To reduce an offer. // <-- saTakerGot: What taker got not including fees. To reduce an offer. -// <-- terResult: terSUCCESS or terNO_ACCOUNT +// <-- terResult: tesSUCCESS or terNO_ACCOUNT // Note: All SLE modifications must always occur even on failure. // XXX: Fees should be paid by the source of the currency. TransactionEngineResult TransactionEngine::takeOffers( @@ -4031,12 +3956,12 @@ TransactionEngineResult TransactionEngine::takeOffers( const uint160 uTakerPaysCurrency = saTakerPays.getCurrency(); const uint160 uTakerGetsAccountID = saTakerGets.getIssuer(); const uint160 uTakerGetsCurrency = saTakerGets.getCurrency(); - TransactionEngineResult terResult = tenUNKNOWN; + TransactionEngineResult terResult = temUNKNOWN; saTakerPaid = 0; saTakerGot = 0; - while (tenUNKNOWN == terResult) + while (temUNKNOWN == terResult) { SLE::pointer sleOfferDir; uint64 uTipQuality; @@ -4068,7 +3993,7 @@ TransactionEngineResult TransactionEngine::takeOffers( // Done. Log(lsINFO) << "takeOffers: done"; - terResult = terSUCCESS; + terResult = tesSUCCESS; } else { @@ -4221,7 +4146,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); const uint160 uGetsCurrency = saTakerGets.getCurrency(); const uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays); - TransactionEngineResult terResult = terSUCCESS; + TransactionEngineResult terResult = tesSUCCESS; uint256 uDirectory; // Delete hints. uint64 uOwnerNode; uint64 uBookNode; @@ -4230,37 +4155,38 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad expiration"; - terResult = tenBAD_EXPIRATION; + terResult = temBAD_EXPIRATION; } else if (bHaveExpiration && mLedger->getParentCloseTimeNC() >= uExpiration) { Log(lsWARNING) << "doOfferCreate: Expired transaction: offer expired"; - terResult = tenEXPIRED; + // XXX CHARGE FEE ONLY. + terResult = tesSUCCESS; } else if (saTakerPays.isNative() && saTakerGets.isNative()) { Log(lsWARNING) << "doOfferCreate: Malformed offer: XNS for XNS"; - terResult = tenBAD_OFFER; + terResult = temBAD_OFFER; } else if (!saTakerPays || !saTakerGets) { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad amount"; - terResult = tenBAD_OFFER; + terResult = temBAD_OFFER; } else if (uPaysCurrency == uGetsCurrency && uPaysIssuerID == uGetsIssuerID) { Log(lsWARNING) << "doOfferCreate: Malformed offer: redundant offer"; - terResult = tenREDUNDANT; + terResult = temREDUNDANT; } else if (saTakerPays.isNative() != !uPaysIssuerID || saTakerGets.isNative() != !uGetsIssuerID) { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad issuer"; - terResult = tenBAD_ISSUER; + terResult = temBAD_ISSUER; } else if (!accountFunds(mTxnAccountID, saTakerGets).isPositive()) { @@ -4269,7 +4195,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); terResult = terUNFUNDED; } - if (terSUCCESS == terResult && !saTakerPays.isNative()) + if (tesSUCCESS == terResult && !saTakerPays.isNative()) { SLE::pointer sleTakerPays = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uPaysIssuerID)); @@ -4281,7 +4207,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); } } - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { STAmount saOfferPaid; STAmount saOfferGot; @@ -4312,7 +4238,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText(); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { saTakerPays -= saOfferGot; // Reduce payin from takers by what offer just got. saTakerGets -= saOfferPaid; // Reduce payout to takers by what srcAccount just paid. @@ -4328,7 +4254,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); // Log(lsWARNING) << "doOfferCreate: takeOffers: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); // Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); - if (terSUCCESS == terResult + if (tesSUCCESS == terResult && !!saTakerPays // Still wanting something. && !!saTakerGets // Still offering something. && accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded. @@ -4338,7 +4264,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); // Add offer to owner's directory. terResult = dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex); - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { uint256 uBookBase = Ledger::getBookBase(uPaysCurrency, uPaysIssuerID, uGetsCurrency, uGetsIssuerID); @@ -4355,7 +4281,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); terResult = dirAdd(uBookNode, uDirectory, uLedgerIndex); } - if (terSUCCESS == terResult) + if (tesSUCCESS == terResult) { // Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); // Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); @@ -4411,17 +4337,17 @@ TransactionEngineResult TransactionEngine::doOfferCancel(const SerializedTransac TransactionEngineResult TransactionEngine::doTake(const SerializedTransaction& txn) { - return tenUNKNOWN; + return temUNKNOWN; } TransactionEngineResult TransactionEngine::doStore(const SerializedTransaction& txn) { - return tenUNKNOWN; + return temUNKNOWN; } TransactionEngineResult TransactionEngine::doDelete(const SerializedTransaction& txn) { - return tenUNKNOWN; + return temUNKNOWN; } // vim:ts=4 diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 6204650fe4..990bc8061d 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -14,75 +14,71 @@ enum TransactionEngineResult { - // Note: Numbers are currently unstable. Use tokens. + // Note: Range is stable. Exact numbers are currently unstable. Use tokens. - // tenCAN_NEVER_SUCCEED = <0 + // -399 .. -300: L Local error (transaction fee inadequate, exceeds local limit) + // Not forwarded, no fee. Only valid during non-consensus processing + telLOCAL_ERROR = -399, + telBAD_PATH_COUNT, + telINSUF_FEE_P, - // Malformed: Fee claimed - tenGEN_IN_USE = -300, - tenBAD_ADD_AUTH, - tenBAD_AMOUNT, - tenBAD_CLAIM_ID, - tenBAD_EXPIRATION, - tenBAD_GEN_AUTH, - tenBAD_ISSUER, - tenBAD_OFFER, - tenBAD_PATH, - tenBAD_PATH_COUNT, - tenBAD_PUBLISH, - tenBAD_SET_ID, - tenCREATEXNS, - tenDST_IS_SRC, - tenDST_NEEDED, - tenEXPLICITXNS, - tenREDUNDANT, - tenRIPPLE_EMPTY, + // -299 .. -200: M Malformed (bad signature) + // Transaction corrupt, not forwarded, cannot charge fee, reject + // Never can succeed in any ledger + temMALFORMED = -299, + temBAD_AMOUNT, + temBAD_AUTH_MASTER, + temBAD_EXPIRATION, + temBAD_ISSUER, + temBAD_OFFER, + temBAD_PUBLISH, + temBAD_SET_ID, + temCREATEXNS, + temDST_IS_SRC, + temDST_NEEDED, + temINSUF_FEE_P, + temINVALID, + temREDUNDANT, + temRIPPLE_EMPTY, + temUNKNOWN, - // Invalid: Ledger won't allow. - tenCLAIMED = -200, - tenBAD_RIPPLE, - tenCREATED, - tenEXPIRED, - tenMSG_SET, - terALREADY, + // -199 .. -100: F Failure (sequence number previously used) + // Transaction cannot succeed because of ledger state, unexpected ledger state, C++ exception, not forwarded, cannot be + // applied, Could succeed in an imaginary ledger. + tefFAILURE = -199, + tefALREADY, + tefBAD_ADD_AUTH, + tefBAD_AUTH, + tefBAD_CLAIM_ID, + tefBAD_GEN_AUTH, + tefBAD_LEDGER, + tefCLAIMED, + tefCREATED, + tefGEN_IN_USE, + tefPAST_SEQ, - // Other - tenFAILED = -100, - tenINSUF_FEE_P, - tenINVALID, - tenUNKNOWN, - - terSUCCESS = 0, - - // terFAILED_BUT_COULD_SUCCEED = >0 - // Conflict with ledger database: Fee claimed - // Might succeed if not conflict is not caused by transaction ordering. - terBAD_AUTH, - terBAD_AUTH_MASTER, - terBAD_LEDGER, - terBAD_RIPPLE, - terBAD_SEQ, - terCREATED, + // -99 .. -1: R Retry (sequence too high, no funds for txn fee, originating account non-existent) + // Transaction cannot be applied, cannot charge fee, not forwarded, might succeed later, hold + terRETRY = -99, terDIR_FULL, terFUNDS_SPENT, terINSUF_FEE_B, - terINSUF_FEE_T, - terNODE_NOT_FOUND, - terNODE_NOT_MENTIONED, - terNODE_NO_ROOT, terNO_ACCOUNT, terNO_DST, terNO_LINE_NO_ZERO, - terNO_PATH, - terOFFER_NOT_FOUND, - terOVER_LIMIT, - terPAST_LEDGER, - terPAST_SEQ, + terOFFER_NOT_FOUND, // XXX If we check sequence first this could be hard failure. terPRE_SEQ, terSET_MISSING_DST, - terUNCLAIMED, terUNFUNDED, + // 0: S Success (success) + // Transaction succeeds, can be applied, can charge fee, forwarded + tesSUCCESS = 0, + + // 100 .. P Partial success (SR) (ripple transaction with no good paths, pay to non-existent account) + // Transaction can be applied, can charge fee, forwarded, but does not achieve optimal result. + tesPARITAL = 100, + // Might succeed in different order. // XXX claim fee and try to delete unfunded. terPATH_EMPTY, @@ -133,9 +129,19 @@ protected: public: typedef boost::shared_ptr pointer; - bool bValid; - std::vector vpnNodes; - LedgerEntrySet lesEntries; + bool bValid; + std::vector vpnNodes; + + // If the transaction fails to meet some constraint, still need to delete unfunded offers. + boost::unordered_set usUnfundedFound; // Offers that were found unfunded. + + // When processing, don't want to complicate directory walking with deletion. + std::vector vUnfundedBecame; // Offers that became unfunded. + + // First time working in reverse a funding source was mentioned. Source may only be used there. + boost::unordered_map, int> umSource; // Map of currency, issuer to node index. + + LedgerEntrySet lesEntries; int mIndex; uint64 uQuality; // 0 = none. @@ -222,7 +228,7 @@ protected: SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex); SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex); - void entryDelete(SLE::pointer sleEntry, bool unfunded = false); + void entryDelete(SLE::pointer sleEntry, bool bUnfunded = false); void entryModify(SLE::pointer sleEntry); uint32 rippleTransferRate(const uint160& uIssuerID); From 9148127083ea1b27c53152717d2289b66ee77d6e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 27 Aug 2012 03:04:33 -0700 Subject: [PATCH 119/426] Fix threading. --- src/LedgerEntrySet.cpp | 34 +++++++++++++++++++++------------- src/LedgerEntrySet.h | 6 +++--- src/TransactionMeta.cpp | 33 ++++++++------------------------- src/TransactionMeta.h | 7 ++++--- 4 files changed, 36 insertions(+), 44 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 06a718b52c..f6ba5405a2 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -259,31 +259,38 @@ SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::pointer& led } -bool LedgerEntrySet::threadNode(SLE::pointer& node, const NewcoinAddress& threadTo, Ledger::pointer& ledger, +bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::pointer& ledger, boost::unordered_map& newMods) { SLE::pointer sle = getForMod(Ledger::getAccountRootIndex(threadTo.getAccountID()), ledger, newMods); - if ((!sle) || (sle->getIndex() == node->getIndex())) // do not self-thread + if (!sle) return false; - return threadNode(node, sle, ledger, newMods); + return threadTx(metaNode, sle, ledger, newMods); } -bool LedgerEntrySet::threadNode(SLE::pointer& node, SLE::pointer& threadTo, Ledger::pointer& ledger, +bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::pointer& ledger, boost::unordered_map& newMods) -{ - // WRITEME +{ // node = the node that was modified/deleted/created + // threadTo = the node that needs to know + uint256 prevTxID; + uint32 prevLgrID; + if (!threadTo->thread(mSet.getTxID(), mSet.getLgrSeq(), prevTxID, prevLgrID)) + return false; + if (metaNode.thread(prevTxID, prevLgrID)) + return true; + assert(false); return false; } -bool LedgerEntrySet::threadOwners(SLE::pointer& node, Ledger::pointer& ledger, +bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::pointer& ledger, boost::unordered_map& newMods) { // thread new or modified node to owner or owners if (node->hasOneOwner()) // thread to owner's account - return threadNode(node, node->getOwner(), ledger, newMods); + return threadTx(metaNode, node->getOwner(), ledger, newMods); else if (node->hasTwoOwners()) // thread to owner's accounts return - threadNode(node, node->getFirstOwner(), ledger, newMods) || - threadNode(node, node->getSecondOwner(), ledger, newMods); + threadTx(metaNode, node->getFirstOwner(), ledger, newMods) || + threadTx(metaNode, node->getSecondOwner(), ledger, newMods); else return false; } @@ -318,10 +325,11 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::pointer& origLedger) { SLE::pointer origNode = origLedger->getSLE(it->first); SLE::pointer curNode = it->second.mEntry; + TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType); if (nType == TMNDeletedNode) { - threadOwners(origNode, origLedger, newMod); + threadOwners(metaNode, origNode, origLedger, newMod); if (origNode->getType() == ltOFFER) { // check for non-zero balances @@ -332,10 +340,10 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::pointer& origLedger) if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode)) { if (nType == TMNCreatedNode) // if created, thread to owner(s) - threadOwners(curNode, origLedger, newMod); + threadOwners(metaNode, curNode, origLedger, newMod); if (curNode->isThreadedType()) // always thread to self - threadNode(curNode, curNode, origLedger, newMod); + threadTx(metaNode, curNode, origLedger, newMod); if (nType == TMNModifiedNode) { diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 6d77b35928..da66cda2d2 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -41,13 +41,13 @@ protected: SLE::pointer getForMod(const uint256& node, Ledger::pointer& ledger, boost::unordered_map& newMods); - bool threadNode(SLE::pointer& node, const NewcoinAddress& threadTo, Ledger::pointer& ledger, + bool threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::pointer& ledger, boost::unordered_map& newMods); - bool threadNode(SLE::pointer& node, SLE::pointer& threadTo, Ledger::pointer& ledger, + bool threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::pointer& ledger, boost::unordered_map& newMods); - bool threadOwners(SLE::pointer& node, Ledger::pointer& ledger, + bool threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::pointer& ledger, boost::unordered_map& newMods); public: diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index d6c80d9add..d637710029 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -262,6 +262,14 @@ bool TransactionMetaSet::isNodeAffected(const uint256& node) const return mNodes.find(node) != mNodes.end(); } +TransactionMetaNode& TransactionMetaSet::getAffectedNode(const uint256& node, int type) +{ + std::map::iterator it = mNodes.find(node); + if (it != mNodes.end()) + return it->second; + return mNodes.insert(std::make_pair(node, TransactionMetaNode(node, type))).first->second; +} + const TransactionMetaNode& TransactionMetaSet::peekAffectedNode(const uint256& node) const { std::map::const_iterator it = mNodes.find(node); @@ -283,28 +291,3 @@ void TransactionMetaSet::swap(TransactionMetaSet& s) mNodes.swap(s.mNodes); } -TransactionMetaNode& TransactionMetaSet::modifyNode(const uint256& node) -{ - std::map::iterator it = mNodes.find(node); - if (it != mNodes.end()) - return it->second; - return mNodes.insert(std::make_pair(node, TransactionMetaNode(node))).first->second; -} - -#if 0 -void TransactionMetaSet::threadNode(const uint256& node, const uint256& prevTx, uint32 prevLgr) -{ - modifyNode(node).thread(prevTx, prevLgr); -} - -void TransactionMetaSet::deleteUnfunded(const uint256& nodeID, - const STAmount& firstBalance, const STAmount &secondBalance) -{ - TransactionMetaNode& node = modifyNode(nodeID); - TMNEUnfunded* entry = dynamic_cast(node.findEntry(TransactionMetaNodeEntry::TMNDeleteUnfunded)); - if (entry) - entry->setBalances(firstBalance, secondBalance); - else - node.addNode(new TMNEUnfunded(firstBalance, secondBalance)); -} -#endif diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index 4060353221..165db3c46b 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -133,7 +133,7 @@ protected: boost::ptr_vector mEntries; public: - TransactionMetaNode(const uint256 &node) : mNode(node) { ; } + TransactionMetaNode(const uint256 &node, int type) : mType(type), mNode(node) { ; } const uint256& getNode() const { return mNode; } const boost::ptr_vector& peekEntries() const { return mEntries; } @@ -163,8 +163,6 @@ protected: uint32 mLedger; std::map mNodes; - TransactionMetaNode& modifyNode(const uint256&); - public: TransactionMetaSet() : mLedger(0) { ; } TransactionMetaSet(const uint256& txID, uint32 ledger) : mTransactionID(txID), mLedger(ledger) { ; } @@ -174,6 +172,9 @@ public: void clear() { mNodes.clear(); } void swap(TransactionMetaSet&); + const uint256& getTxID() { return mTransactionID; } + uint32 getLgrSeq() { return mLedger; } + bool isNodeAffected(const uint256&) const; TransactionMetaNode& getAffectedNode(const uint256&, int type); const TransactionMetaNode& peekAffectedNode(const uint256&) const; From e02e785a723a7910a346c64af5bc1b069a1f3d59 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 27 Aug 2012 12:22:03 -0700 Subject: [PATCH 120/426] Work on transaction engine offer deleting. --- src/TransactionEngine.cpp | 67 +++++++++++++++++++++++++++++++-------- src/TransactionEngine.h | 27 +++++++++------- 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 19d17e4113..cda485002c 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -59,7 +59,11 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { temINVALID, "temINVALID", "The transaction is ill-formed" }, { temREDUNDANT, "temREDUNDANT", "Sends same currency to self." }, { temRIPPLE_EMPTY, "temRIPPLE_EMPTY", "PathSet with no paths." }, - { temUNKNOWN, "temUNKNOWN", "The transactions requires logic not implemented yet" }, + { temUNCERTAIN, "temUNCERTAIN", "In process of determining result. Never returned." }, + { temUNKNOWN, "temUNKNOWN", "The transactions requires logic not implemented yet." }, + + { tepPATH_DRY, "tepPATH_DRY", "Path could not send partial amount." }, + { tepPATH_PARTIAL, "tepPATH_PARTIAL", "Path could not send full amount." }, { terDIR_FULL, "terDIR_FULL", "Can not add entry to full dir." }, { terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." }, @@ -68,8 +72,6 @@ bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std { terNO_DST, "terNO_DST", "The destination does not exist" }, { terNO_LINE_NO_ZERO, "terNO_LINE_NO_ZERO", "Can't zero non-existant line, destination might make it." }, { terOFFER_NOT_FOUND, "terOFFER_NOT_FOUND", "Can not cancel offer." }, - { 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." }, { terUNFUNDED, "terUNFUNDED", "Source account had insufficient balance for transaction." }, @@ -435,6 +437,14 @@ TransactionEngineResult TransactionEngine::offerDelete(const SLE::pointer& sleOf return terResult; } +TransactionEngineResult TransactionEngine::offerDelete(const uint256& uOfferIndex) +{ + SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); + const uint160 uOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + + return offerDelete(sleOffer, uOfferIndex, uOwnerID); +} + // <-- uNodeDir: For deletion, present to make dirDelete efficient. // --> uRootIndex: The index of the base of the directory. Nodes are based off of this. // --> uLedgerIndex: Value to add to directory. @@ -1294,7 +1304,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran mTxnAccount = SLE::pointer(); mNodes.clear(); - mUnfunded.clear(); + musUnfundedFound.clear(); return terResult; } @@ -1860,7 +1870,7 @@ void TransactionEngine::calcOfferBridgeNext( if (!bDone) { - // mUnfunded.insert(uOfferIndex); + // musUnfundedFound.insert(uOfferIndex); } } while (bNext); @@ -3611,6 +3621,9 @@ void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) assert(pspCur->vpnNodes.size() >= 2); + pspCur->vUnfundedBecame.clear(); + pspCur->umSource.clear(); + pspCur->bValid = calcNode(uLast, pspCur, iPaths == 1); Log(lsINFO) << "pathNext: bValid=" @@ -3796,8 +3809,8 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction STAmount saWanted; LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. - terResult = temUNKNOWN; - while (temUNKNOWN == terResult) + terResult = temUNCERTAIN; + while (temUNCERTAIN == terResult) { PathState::pointer pspBest; LedgerEntrySet lesCheckpoint = mNodes; @@ -3820,28 +3833,37 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction { // Apply best path. - // Install ledger for best past. + // Record best pass' offers that became unfunded for deletion on success. + mvUnfundedBecame.insert(mvUnfundedBecame.end(), pspBest->vUnfundedBecame.begin(), pspBest->vUnfundedBecame.end()); + + // Record best pass' LedgerEntrySet to build off of and potentially return. mNodes.swapWith(pspBest->lesEntries); // Figure out if done. - if (temUNKNOWN == terResult && saPaid == saWanted) + if (temUNCERTAIN == terResult && saPaid == saWanted) { terResult = tesSUCCESS; } + else + { + // Prepare for next pass. + + // Merge best pass' umSource. + mumSource.insert(pspBest->umSource.begin(), pspBest->umSource.end()); + } } // Not done and ran out of paths. else if (!bPartialPayment) { // Partial payment not allowed. - terResult = terPATH_PARTIAL; + terResult = tepPATH_PARTIAL; mNodes = lesBase; // Revert to just fees charged. } // Partial payment ok. else if (!saPaid) { // No payment at all. - // XXX Mark for retry? - terResult = terPATH_EMPTY; + terResult = tepPATH_DRY; mNodes = lesBase; // Revert to just fees charged. } else @@ -3850,6 +3872,23 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction } } + if (tesSUCCESS == terResult) + { + // Delete became unfunded offers. + BOOST_FOREACH(const uint256& uOfferIndex, mvUnfundedBecame) + { + if (tesSUCCESS == terResult) + terResult = offerDelete(uOfferIndex); + } + } + + // Delete found unfunded offers. + BOOST_FOREACH(const uint256& uOfferIndex, musUnfundedFound) + { + if (tesSUCCESS == terResult) + terResult = offerDelete(uOfferIndex); + } + std::string strToken; std::string strHuman; @@ -4021,7 +4060,7 @@ TransactionEngineResult TransactionEngine::takeOffers( offerDelete(sleOffer, uOfferIndex, uOfferOwnerID); - mUnfunded.insert(uOfferIndex); + musUnfundedFound.insert(uOfferIndex); } else if (uOfferOwnerID == uTakerAccountID) { @@ -4047,7 +4086,7 @@ TransactionEngineResult TransactionEngine::takeOffers( offerDelete(sleOffer, uOfferIndex, uOfferOwnerID); - mUnfunded.insert(uOfferIndex); + musUnfundedFound.insert(uOfferIndex); } else { diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 990bc8061d..4e2558db61 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -40,6 +40,7 @@ enum TransactionEngineResult temINVALID, temREDUNDANT, temRIPPLE_EMPTY, + temUNCERTAIN, temUNKNOWN, // -199 .. -100: F Failure (sequence number previously used) @@ -77,12 +78,9 @@ enum TransactionEngineResult // 100 .. P Partial success (SR) (ripple transaction with no good paths, pay to non-existent account) // Transaction can be applied, can charge fee, forwarded, but does not achieve optimal result. - tesPARITAL = 100, - - // Might succeed in different order. - // XXX claim fee and try to delete unfunded. - terPATH_EMPTY, - terPATH_PARTIAL, + tepPARITAL = 100, + tepPATH_DRY, + tepPATH_PARTIAL, }; bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std::string& strHuman); @@ -132,9 +130,6 @@ public: bool bValid; std::vector vpnNodes; - // If the transaction fails to meet some constraint, still need to delete unfunded offers. - boost::unordered_set usUnfundedFound; // Offers that were found unfunded. - // When processing, don't want to complicate directory walking with deletion. std::vector vUnfundedBecame; // Offers that became unfunded. @@ -224,13 +219,23 @@ protected: uint160 mTxnAccountID; SLE::pointer mTxnAccount; - boost::unordered_set mUnfunded; // Indexes that were found unfunded. + // First time working in reverse a funding source was mentioned. Source may only be used there. + boost::unordered_map, int> mumSource; // Map of currency, issuer to node index. + + // When processing, don't want to complicate directory walking with deletion. + std::vector mvUnfundedBecame; // Offers that became unfunded. + + // If the transaction fails to meet some constraint, still need to delete unfunded offers. + boost::unordered_set musUnfundedFound; // Offers that were found unfunded. SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex); SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex); void entryDelete(SLE::pointer sleEntry, bool bUnfunded = false); void entryModify(SLE::pointer sleEntry); + TransactionEngineResult offerDelete(const uint256& uOfferIndex); + TransactionEngineResult 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); @@ -260,8 +265,6 @@ protected: void txnWrite(); - TransactionEngineResult offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID); - TransactionEngineResult doAccountSet(const SerializedTransaction& txn); TransactionEngineResult doClaim(const SerializedTransaction& txn); TransactionEngineResult doCreditSet(const SerializedTransaction& txn); From 421841b209f57a4f9294436b653c892695fc306a Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 27 Aug 2012 13:15:04 -0700 Subject: [PATCH 121/426] Fix offer creation to support threading. --- src/TransactionEngine.cpp | 133 +++++++++++++++++++++++++++----------- src/TransactionEngine.h | 5 +- 2 files changed, 99 insertions(+), 39 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index cda485002c..7cf1460c99 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -422,14 +422,14 @@ STAmount TransactionEngine::accountSend(const uint160& uSenderID, const uint160& TransactionEngineResult TransactionEngine::offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID) { uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode); - TransactionEngineResult terResult = dirDelete(false, uOwnerNode, Ledger::getOwnerDirIndex(uOwnerID), uOfferIndex); + TransactionEngineResult 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); + terResult = dirDelete(false, uBookNode, uDirectory, uOfferIndex, true); } entryDelete(sleOffer); @@ -538,16 +538,13 @@ TransactionEngineResult TransactionEngine::dirAdd( return tesSUCCESS; } -// --> bKeepRoot: True, if we never completely clean up, after we overflow the root node. -// --> uNodeDir: Node containing entry. -// --> uRootIndex: The index of the base of the directory. Nodes are based off of this. -// --> uLedgerIndex: Value to add to directory. // Ledger must be in a state for this to work. TransactionEngineResult TransactionEngine::dirDelete( - bool bKeepRoot, - const uint64& uNodeDir, - const uint256& uRootIndex, - const uint256& uLedgerIndex) + const bool bKeepRoot, // --> True, if we never completely clean up, after we overflow the root node. + const uint64& uNodeDir, // --> Node containing entry. + const uint256& uRootIndex, // --> The index of the base of the directory. Nodes are based off of this. + const uint256& uLedgerIndex, // --> Value to add to directory. + const bool bStable) // --> True, not to change relative order of entries. { uint64 uNodeCur = uNodeDir; SLE::pointer sleNode = entryCache(ltDIR_NODE, uNodeCur ? Ledger::getDirNodeIndex(uRootIndex, uNodeCur) : uRootIndex); @@ -579,9 +576,21 @@ TransactionEngineResult TransactionEngine::dirDelete( // Remove the element. if (vuiIndexes.size() > 1) - *it = vuiIndexes[vuiIndexes.size()-1]; - - vuiIndexes.resize(vuiIndexes.size()-1); + { + if (bStable) + { + vuiIndexes.erase(it); + } + else + { + *it = vuiIndexes[vuiIndexes.size()-1]; + vuiIndexes.resize(vuiIndexes.size()-1); + } + } + else + { + vuiIndexes.clear(); + } sleNode->setIFieldV256(sfIndexes, svIndexes); entryModify(sleNode); @@ -1528,7 +1537,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti // Zero balance and eliminating last limit. bDelIndex = true; - terResult = dirDelete(false, uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex()); + terResult = dirDelete(false, uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex(), false); } } #endif @@ -3995,12 +4004,16 @@ TransactionEngineResult TransactionEngine::takeOffers( const uint160 uTakerPaysCurrency = saTakerPays.getCurrency(); const uint160 uTakerGetsAccountID = saTakerGets.getIssuer(); const uint160 uTakerGetsCurrency = saTakerGets.getCurrency(); - TransactionEngineResult terResult = temUNKNOWN; + TransactionEngineResult terResult = temUNCERTAIN; + + boost::unordered_set usOfferUnfundedFound; // Offers found unfunded. + boost::unordered_set usOfferUnfundedBecame; // Offers that became unfunded. + boost::unordered_set usAccountTouched; // Accounts touched. saTakerPaid = 0; saTakerGot = 0; - while (temUNKNOWN == terResult) + while (temUNCERTAIN == terResult) { SLE::pointer sleOfferDir; uint64 uTipQuality; @@ -4027,7 +4040,9 @@ TransactionEngineResult TransactionEngine::takeOffers( } } - if (!sleOfferDir || uTakeQuality < uTipQuality || (bPassive && uTakeQuality == uTipQuality)) + if (!sleOfferDir // No offer directory to take. + || uTakeQuality < uTipQuality // No offer's of sufficient quality available. + || (bPassive && uTakeQuality == uTipQuality)) { // Done. Log(lsINFO) << "takeOffers: done"; @@ -4036,7 +4051,7 @@ TransactionEngineResult TransactionEngine::takeOffers( } else { - // Have an offer to consider. + // Have an offer directory to consider. Log(lsINFO) << "takeOffers: considering dir : " << sleOfferDir->getJson(0); SLE::pointer sleBookNode; @@ -4055,19 +4070,17 @@ TransactionEngineResult TransactionEngine::takeOffers( if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) { - // Offer is expired. Delete it. + // Offer is expired. Expired offers are considered unfunded. Delete it. Log(lsINFO) << "takeOffers: encountered expired offer"; - offerDelete(sleOffer, uOfferIndex, uOfferOwnerID); - - musUnfundedFound.insert(uOfferIndex); + usOfferUnfundedFound.insert(uOfferIndex); } else if (uOfferOwnerID == uTakerAccountID) { - // Would take own offer. Consider old offer unfunded. + // Would take own offer. Consider old offer expired. Delete it. Log(lsINFO) << "takeOffers: encountered taker's own old offer"; - offerDelete(sleOffer, uOfferIndex, uOfferOwnerID); + usOfferUnfundedFound.insert(uOfferIndex); } else { @@ -4084,9 +4097,17 @@ TransactionEngineResult TransactionEngine::takeOffers( // Offer is unfunded, possibly due to previous balance action. Log(lsINFO) << "takeOffers: offer unfunded: delete"; - offerDelete(sleOffer, uOfferIndex, uOfferOwnerID); - - musUnfundedFound.insert(uOfferIndex); + boost::unordered_set::iterator account = usAccountTouched.find(uOfferOwnerID); + if (account != usAccountTouched.end()) + { + // Previously touched account. + usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success. + } + else + { + // Never touched source account. + usOfferUnfundedFound.insert(uOfferIndex); // Delete found unfunded offer when possible. + } } else { @@ -4120,24 +4141,28 @@ TransactionEngineResult TransactionEngine::takeOffers( Log(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText(); // Adjust offer + + // Offer owner will pay less. Subtract what taker just got. + sleOffer->setIFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot); + + // Offer owner will get less. Subtract what owner just paid. + sleOffer->setIFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid); + + entryModify(sleOffer); + if (bOfferDelete) { // Offer now fully claimed or now unfunded. Log(lsINFO) << "takeOffers: offer claimed: delete"; - offerDelete(sleOffer, uOfferIndex, uOfferOwnerID); + usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success. + + // Offer owner's account is no longer pristine. + usAccountTouched.insert(uOfferOwnerID); } else { - Log(lsINFO) << "takeOffers: offer partial claim: modify"; - - // Offer owner will pay less. Subtract what taker just got. - sleOffer->setIFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot); - - // Offer owner will get less. Subtract what owner just paid. - sleOffer->setIFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid); - - entryModify(sleOffer); + Log(lsINFO) << "takeOffers: offer partial claim."; } // Offer owner pays taker. @@ -4158,6 +4183,40 @@ TransactionEngineResult TransactionEngine::takeOffers( } } + // On storing meta data, delete offers that were found unfunded to prevent encountering them in future. + switch (terResult) + { + case tesSUCCESS: + case tepPATH_DRY: + case tepPATH_PARTIAL: + BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedFound) + { + TransactionEngineResult terDelete = offerDelete(uOfferIndex); + + if (tesSUCCESS != terDelete) + terResult = terDelete; + break; + } + break; + + default: + nothing(); + break; + } + + if (tesSUCCESS == terResult) + { + // On success, delete offers that became unfunded. + BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedBecame) + { + TransactionEngineResult terDelete = offerDelete(uOfferIndex); + + if (tesSUCCESS != terDelete) + terResult = terDelete; + break; + } + } + return terResult; } diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 4e2558db61..f8b7f34ed1 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -192,10 +192,11 @@ private: const uint256& uLedgerIndex); TransactionEngineResult dirDelete( - bool bKeepRoot, + const bool bKeepRoot, const uint64& uNodeDir, // Node item is mentioned in. const uint256& uRootIndex, - const uint256& uLedgerIndex); // Item being deleted + const uint256& uLedgerIndex, // Item being deleted + const bool bStable); 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); From 0d8ad928f618d8a3298e91fa8ac58522942ca3a8 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 27 Aug 2012 13:20:47 -0700 Subject: [PATCH 122/426] Simplify clean up for takeOffers. --- src/TransactionEngine.cpp | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 7cf1460c99..694892fae0 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -4184,24 +4184,14 @@ TransactionEngineResult TransactionEngine::takeOffers( } // On storing meta data, delete offers that were found unfunded to prevent encountering them in future. - switch (terResult) + if (tesSUCCESS == terResult) { - case tesSUCCESS: - case tepPATH_DRY: - case tepPATH_PARTIAL: - BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedFound) - { - TransactionEngineResult terDelete = offerDelete(uOfferIndex); - - if (tesSUCCESS != terDelete) - terResult = terDelete; - break; - } - break; - - default: - nothing(); - break; + BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedFound) + { + terResult = offerDelete(uOfferIndex); + if (tesSUCCESS != terResult) + break; + } } if (tesSUCCESS == terResult) @@ -4209,10 +4199,8 @@ TransactionEngineResult TransactionEngine::takeOffers( // On success, delete offers that became unfunded. BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedBecame) { - TransactionEngineResult terDelete = offerDelete(uOfferIndex); - - if (tesSUCCESS != terDelete) - terResult = terDelete; + terResult = offerDelete(uOfferIndex); + if (tesSUCCESS != terResult) break; } } From bcd08c368c19ace041ff8b6324a1a50038b0961e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 28 Aug 2012 04:05:19 -0700 Subject: [PATCH 123/426] This should complete the code to build the transaction meta data based on the ledger entry set. --- src/LedgerEntrySet.cpp | 88 ++++++++++++++++++++++++++++++----------- src/TransactionMeta.cpp | 63 ++++++++++++++++++++++++----- src/TransactionMeta.h | 29 +++++++++----- 3 files changed, 137 insertions(+), 43 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index f6ba5405a2..7015a7b76f 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -311,46 +311,88 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::pointer& origLedger) case taaMODIFY: nType = TMNModifiedNode; break; + case taaDELETE: nType = TMNDeletedNode; break; + case taaCREATE: nType = TMNCreatedNode; break; + default: // ignore these break; } - if (nType != TMNEndOfMetadata) + + if (nType == TMNEndOfMetadata) + continue; + + SLE::pointer origNode = origLedger->getSLE(it->first); + SLE::pointer curNode = it->second.mEntry; + TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType); + + if (nType == TMNDeletedNode) { - SLE::pointer origNode = origLedger->getSLE(it->first); - SLE::pointer curNode = it->second.mEntry; - TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType); + threadOwners(metaNode, origNode, origLedger, newMod); - if (nType == TMNDeletedNode) - { - threadOwners(metaNode, origNode, origLedger, newMod); + if (origNode->getIFieldPresent(sfAmount)) + { // node has an amount, covers ripple state nodes + STAmount amount = origNode->getIValueFieldAmount(sfAmount); + if (amount.isNonZero()) + metaNode.addAmount(TMSPrevBalance, amount); + amount = curNode->getIValueFieldAmount(sfAmount); + if (amount.isNonZero()) + metaNode.addAmount(TMSFinalBalance, amount); - if (origNode->getType() == ltOFFER) - { // check for non-zero balances - // WRITEME - } - } - - if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode)) - { - if (nType == TMNCreatedNode) // if created, thread to owner(s) - threadOwners(metaNode, curNode, origLedger, newMod); - - if (curNode->isThreadedType()) // always thread to self - threadTx(metaNode, curNode, origLedger, newMod); - - if (nType == TMNModifiedNode) + if (origNode->getType() == ltRIPPLE_STATE) { - // analyze changes WRITEME + metaNode.addAccount(TMSLowID, origNode->getIValueFieldAccount(sfLowID)); + metaNode.addAccount(TMSHighID, origNode->getIValueFieldAccount(sfHighID)); } } + + if (origNode->getType() == ltOFFER) + { // check for non-zero balances + STAmount amount = origNode->getIValueFieldAmount(sfTakerPays); + if (amount.isNonZero()) + metaNode.addAmount(TMSFinalTakerPays, amount); + amount = origNode->getIValueFieldAmount(sfTakerGets); + if (amount.isNonZero()) + metaNode.addAmount(TMSFinalTakerGets, amount); + } + + } + + if (nType == TMNCreatedNode) // if created, thread to owner(s) + threadOwners(metaNode, curNode, origLedger, newMod); + + if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode)) + { + if (curNode->isThreadedType()) // always thread to self + threadTx(metaNode, curNode, origLedger, newMod); + } + + if (nType == TMNModifiedNode) + { + if (origNode->getIFieldPresent(sfAmount)) + { // node has an amount, covers account root nodes and ripple nodes + STAmount amount = origNode->getIValueFieldAmount(sfAmount); + if (amount != curNode->getIValueFieldAmount(sfAmount)) + metaNode.addAmount(TMSPrevBalance, amount); + } + + if (origNode->getType() == ltOFFER) + { + STAmount amount = origNode->getIValueFieldAmount(sfTakerPays); + if (amount != curNode->getIValueFieldAmount(sfTakerPays)) + metaNode.addAmount(TMSPrevTakerPays, amount); + amount = origNode->getIValueFieldAmount(sfTakerGets); + if (amount != curNode->getIValueFieldAmount(sfTakerGets)) + metaNode.addAmount(TMSPrevTakerGets, amount); + } + } } diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index d637710029..396f863f52 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -65,13 +65,13 @@ Json::Value TMNEThread::getJson(int) const TMNEAmount::TMNEAmount(int type, SerializerIterator& sit) : TransactionMetaNodeEntry(type) { - mPrevAmount = *dynamic_cast(STAmount::deserialize(sit, NULL).get()); // Ouch + mAmount = *dynamic_cast(STAmount::deserialize(sit, NULL).get()); // Ouch } void TMNEAmount::addRaw(Serializer& s) const { s.add8(mType); - mPrevAmount.add(s); + mAmount.add(s); } Json::Value TMNEAmount::getJson(int v) const @@ -79,11 +79,12 @@ Json::Value TMNEAmount::getJson(int v) const Json::Value outer(Json::objectValue); switch (mType) { - case TMSPrevBalance: outer["prev_balance"] = mPrevAmount.getJson(v); break; - case TMSPrevTakerPays: outer["prev_taker_pays"] = mPrevAmount.getJson(v); break; - case TMSPrevTakerGets: outer["prev_taker_gets"] = mPrevAmount.getJson(v); break; - case TMSFinalTakerPays: outer["final_taker_pays"] = mPrevAmount.getJson(v); break; - case TMSFinalTakerGets: outer["final_taker_gets"] = mPrevAmount.getJson(v); break; + case TMSPrevBalance: outer["prev_balance"] = mAmount.getJson(v); break; + case TMSFinalBalance: outer["final_balance"] = mAmount.getJson(v); break; + case TMSPrevTakerPays: outer["prev_taker_pays"] = mAmount.getJson(v); break; + case TMSPrevTakerGets: outer["prev_taker_gets"] = mAmount.getJson(v); break; + case TMSFinalTakerPays: outer["final_taker_pays"] = mAmount.getJson(v); break; + case TMSFinalTakerGets: outer["final_taker_gets"] = mAmount.getJson(v); break; default: assert(false); } return outer; @@ -96,19 +97,28 @@ int TMNEAmount::compare(const TransactionMetaNodeEntry& e) const } TMNEAccount::TMNEAccount(int type, SerializerIterator& sit) - : TransactionMetaNodeEntry(type), mPrevAccount(sit.get256()) + : TransactionMetaNodeEntry(type), mAccount(STAccount(sit.getVL()).getValueNCA()) { ; } void TMNEAccount::addRaw(Serializer& sit) const { sit.add8(mType); - sit.add256(mPrevAccount); + + STAccount sta; + sta.setValueNCA(mAccount); + sta.add(sit); } Json::Value TMNEAccount::getJson(int) const { Json::Value outer(Json::objectValue); - outer["prev_account"] = mPrevAccount.GetHex(); + switch (mType) + { + case TMSPrevAccount: outer["prev_account"] = mAccount.humanAccountID(); break; + case TMSLowID: outer["lowID"] = mAccount.humanAccountID(); break; + case TMSHighID: outer["highID"] = mAccount.humanAccountID(); break; + default: assert(false); + } return outer; } @@ -149,6 +159,11 @@ TransactionMetaNode::TransactionMetaNode(int type, const uint256& node, Serializ void TransactionMetaNode::addRaw(Serializer& s) { + if (mEntries.empty()) + { // ack, an empty node + assert(false); + return; + } s.add8(mType); s.add256(mNode); mEntries.sort(); @@ -193,6 +208,34 @@ bool TransactionMetaNode::thread(const uint256& prevTx, uint32 prevLgr) return true; } +bool TransactionMetaNode::addAmount(int nodeType, const STAmount& amount) +{ + for (boost::ptr_vector::iterator it = mEntries.begin(), end = mEntries.end(); + it != end; ++it) + if (it->getType() == nodeType) + { + TMNEAmount* a = dynamic_cast(&*it); + assert(a && (a->getAmount() == amount)); + return false; + } + addNode(new TMNEAmount(nodeType, amount)); + return true; +} + +bool TransactionMetaNode::addAccount(int nodeType, const NewcoinAddress& account) +{ + for (boost::ptr_vector::iterator it = mEntries.begin(), end = mEntries.end(); + it != end; ++it) + if (it->getType() == nodeType) + { + TMNEAccount* a = dynamic_cast(&*it); + assert(a && (a->getAccount() == account)); + return false; + } + addNode(new TMNEAccount(nodeType, account)); + return true; +} + Json::Value TransactionMetaNode::getJson(int v) const { Json::Value ret = Json::objectValue; diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index 165db3c46b..eecc70bfb4 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -24,13 +24,16 @@ static const int TMSThread = 0x01; // Holds previous TxID and LgrSeq for thre // sub record types - containing an amount static const int TMSPrevBalance = 0x11; // Balances prior to the transaction -static const int TMSPrevTakerPays = 0x12; -static const int TMSPrevTakerGets = 0x13; -static const int TMSFinalTakerPays = 0x14; // Balances at node deletion time -static const int TMSFinalTakerGets = 0x15; +static const int TMSFinalBalance = 0x12; // deleted with non-zero balance +static const int TMSPrevTakerPays = 0x13; +static const int TMSPrevTakerGets = 0x14; +static const int TMSFinalTakerPays = 0x15; // Balances at node deletion time +static const int TMSFinalTakerGets = 0x16; // sub record types - containing an account (for example, for when a nickname is transferred) -static const int TMSPrevAccount = 0x20; +static const int TMSPrevAccount = 0x20; +static const int TMSLowID = 0x21; +static const int TMSHighID = 0x22; class TransactionMetaNodeEntry @@ -85,16 +88,17 @@ protected: class TMNEAmount : public TransactionMetaNodeEntry { // a transaction affected the balance of a node protected: - STAmount mPrevAmount; + STAmount mAmount; public: TMNEAmount(int type) : TransactionMetaNodeEntry(type) { ; } + TMNEAmount(int type, const STAmount &a) : TransactionMetaNodeEntry(type), mAmount(a) { ; } TMNEAmount(int type, SerializerIterator&); virtual void addRaw(Serializer&) const; - const STAmount& getAmount() const { return mPrevAmount; } - void setAmount(const STAmount& a) { mPrevAmount = a; } + const STAmount& getAmount() const { return mAmount; } + void setAmount(const STAmount& a) { mAmount = a; } virtual Json::Value getJson(int) const; @@ -106,14 +110,17 @@ protected: class TMNEAccount : public TransactionMetaNodeEntry { // node was deleted because it was unfunded protected: - uint256 mPrevAccount; + NewcoinAddress mAccount; public: - TMNEAccount(int type, uint256 prev) : TransactionMetaNodeEntry(type), mPrevAccount(prev) { ; } + TMNEAccount(int type, const NewcoinAddress& acct) : TransactionMetaNodeEntry(type), mAccount(acct) { ; } TMNEAccount(int type, SerializerIterator&); virtual void addRaw(Serializer&) const; virtual Json::Value getJson(int) const; + const NewcoinAddress& getAccount() const { return mAccount; } + void setAccount(const NewcoinAddress& a) { mAccount = a; } + protected: virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEAccount(*this); } virtual int compare(const TransactionMetaNodeEntry&) const; @@ -152,6 +159,8 @@ public: void addRaw(Serializer&); Json::Value getJson(int) const; + bool addAmount(int nodeType, const STAmount& amount); + bool addAccount(int nodeType, const NewcoinAddress& account); TMNEAmount* findAmount(int nodeType); }; From 354c33f71a42716e2f3b2513cf41ce5d89596489 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 28 Aug 2012 13:27:54 -0700 Subject: [PATCH 124/426] Work toward ripple loop detection and offer deletion. --- src/TransactionEngine.cpp | 126 ++++++++++++++++++++++++++++---------- src/TransactionEngine.h | 34 ++++++---- 2 files changed, 117 insertions(+), 43 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 694892fae0..df8a0c7082 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -24,6 +24,17 @@ static STAmount saZero(CURRENCY_ONE, 0, 0); static STAmount saOne(CURRENCY_ONE, 1, 0); +std::size_t hash_value(const aciSource& asValue) +{ + std::size_t seed = 0; + + asValue.get<0>().hash_combine(seed); + asValue.get<1>().hash_combine(seed); + asValue.get<2>().hash_combine(seed); + + return seed; +} + bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std::string& strHuman) { static struct { @@ -1887,11 +1898,10 @@ void TransactionEngine::calcOfferBridgeNext( #endif // <-- bSuccess: false= no transfer -// XXX Make sure missing ripple path is addressed cleanly. bool TransactionEngine::calcNodeOfferRev( - unsigned int uIndex, // 0 < uIndex < uLast - PathState::pointer pspCur, - bool bMultiQuality) + const unsigned int uIndex, // 0 < uIndex < uLast + const PathState::pointer& pspCur, + const bool bMultiQuality) { bool bSuccess = false; @@ -1950,9 +1960,9 @@ bool TransactionEngine::calcNodeOfferRev( { // Do a directory. // - Drive on computing saCurDlvAct to derive saPrvDlvAct. - // XXX Behave well, if entry type is wrong (someone beat us to using the hash) + // XXX Behave well, if entry type is not ltDIR_NODE (someone beat us to using the hash) SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); - STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio + const STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio unsigned int uEntry = 0; uint256 uCurIndex; @@ -1962,28 +1972,55 @@ bool TransactionEngine::calcNodeOfferRev( Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uCurIndex=%s") % uCurIndex.ToString()); SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex); - uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); + + if (sleCurOfr->getIFieldPresent(sfExpiration) && sleCurOfr->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + { + // Offer is expired. + Log(lsINFO) << "calcNodeOfferRev: encountered expired offer"; + + musUnfundedFound.insert(uCurIndex); // Mark offer for always deletion. + continue; + } + + const uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); + const aciSource asLine = boost::make_tuple(uCurOfrAccountID, uCurCurrencyID, uCurIssuerID); + + // Allowed to access source from this node? + curIssuerNodeConstIterator it = pspCur->umReverse.find(asLine); + + if (it == pspCur->umReverse.end()) + { + // Temporarily unfunded. ignore in this column. + + nothing(); + continue; + } + const STAmount& saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); // UNUSED? const STAmount& saCurOfrIn = sleCurOfr->getIValueFieldAmount(sfTakerPays); STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. - // XXX Offer is also unfunded if funding source previously mentioned. if (!saCurOfrFunds) { // Offer is unfunded. Log(lsINFO) << "calcNodeOfferRev: encountered unfunded offer"; - // XXX Mark unfunded. + curIssuerNodeConstIterator itSource = mumSource.find(asLine); + if (itSource == mumSource.end()) + { + // Never mentioned before: found unfunded. + musUnfundedFound.insert(uCurIndex); // Mark offer for always deletion. + } + else + { + // Mentioned before: source became unfunded. + pspCur->vUnfundedBecame.push_back(uCurIndex); // Mark offer for deletion on use. + } + continue; } - else if (sleCurOfr->getIFieldPresent(sfExpiration) && sleCurOfr->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) - { - // Offer is expired. - Log(lsINFO) << "calcNodeOfferRev: encountered expired offer"; - // XXX Mark unfunded. - } - else if (!!uNxtAccountID) + if (!!uNxtAccountID) { // Next is an account. @@ -2094,9 +2131,9 @@ bool TransactionEngine::calcNodeOfferRev( } bool TransactionEngine::calcNodeOfferFwd( - unsigned int uIndex, // 0 < uIndex < uLast - PathState::pointer pspCur, - bool bMultiQuality + const unsigned int uIndex, // 0 < uIndex < uLast + const PathState::pointer& pspCur, + const bool bMultiQuality ) { bool bSuccess = false; @@ -2615,7 +2652,7 @@ Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCur } // Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver; -bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) +bool TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) { bool bSuccess = true; const unsigned int uLast = pspCur->vpnNodes.size() - 1; @@ -2948,9 +2985,9 @@ bool TransactionEngine::calcNodeAccountRev(unsigned int uIndex, PathState::point // - Output to next node minus fees. // Perform balance adjustment with previous. bool TransactionEngine::calcNodeAccountFwd( - unsigned int uIndex, // 0 <= uIndex <= uLast - PathState::pointer pspCur, - bool bMultiQuality) + const unsigned int uIndex, // 0 <= uIndex <= uLast + const PathState::pointer& pspCur, + const bool bMultiQuality) { bool bSuccess = true; const unsigned int uLast = pspCur->vpnNodes.size() - 1; @@ -3282,7 +3319,8 @@ bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssu } // Append a node and insert before it any implied nodes. -// <-- bValid: true, if node is valid. false, if node is malformed. +// <-- bValid: true, if node is valid. false, if node is malformed or missing credit link. +// XXX Report missinge credit link distinct from malformed for retry. bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) { Log(lsINFO) << "pushNode> " @@ -3431,7 +3469,6 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin return bValid; } -// XXX Disallow loops in ripple paths PathState::PathState( const Ledger::pointer& lpLedger, const int iIndex, @@ -3491,6 +3528,33 @@ PathState::PathState( } } + if (bValid) + { + // Look for first mention of source in nodes and detect loops. + // Note: The output is not allowed to be a source. + + const unsigned int uNodes = vpnNodes.size(); + + for (unsigned int uIndex = 0; bValid && uIndex != uNodes; ++uIndex) + { + const paymentNode& pnCur = vpnNodes[uIndex]; + + if (!!pnCur.uAccountID) + { + // Source is a ripple line + nothing(); + } + else if (!umForward.insert(std::make_pair(boost::make_tuple(pnCur.uAccountID, pnCur.uCurrencyID, pnCur.uIssuerID), uIndex)).second) + { + // Failed to insert. Have a loop. + Log(lsINFO) << boost::str(boost::format("PathState: loop detected: %s") + % getJson()); + + bValid = false; + } + } + } + Log(lsINFO) << boost::str(boost::format("PathState: in=%s/%s out=%s/%s %s") % STAmount::createHumanCurrency(uInCurrencyID) % NewcoinAddress::createHumanAccountID(uInIssuerID) @@ -3583,8 +3647,7 @@ Json::Value PathState::getJson() const // --> [all]saWanted.mCurrency // --> [all]saAccount // <-> [0]saWanted.mAmount : --> limit, <-- actual -// XXX Disallow looping. -bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality) +bool TransactionEngine::calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) { const paymentNode& pnCur = pspCur->vpnNodes[uIndex]; const bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount); @@ -3619,7 +3682,7 @@ bool TransactionEngine::calcNode(unsigned int uIndex, PathState::pointer pspCur, // Calculate the next increment of a path. // The increment is what can satisfy a portion or all of the requested output at the best quality. // <-- pspCur->uQuality -void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) +void TransactionEngine::pathNext(const PathState::pointer& pspCur, const int iPaths) { // The next state is what is available in preference order. // This is calculated when referenced accounts changed. @@ -3631,7 +3694,7 @@ void TransactionEngine::pathNext(PathState::pointer pspCur, int iPaths) assert(pspCur->vpnNodes.size() >= 2); pspCur->vUnfundedBecame.clear(); - pspCur->umSource.clear(); + pspCur->umReverse.clear(); pspCur->bValid = calcNode(uLast, pspCur, iPaths == 1); @@ -3857,8 +3920,8 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction { // Prepare for next pass. - // Merge best pass' umSource. - mumSource.insert(pspBest->umSource.begin(), pspBest->umSource.end()); + // Merge best pass' umReverse. + mumSource.insert(pspBest->umReverse.begin(), pspBest->umReverse.end()); } } // Not done and ran out of paths. @@ -3981,7 +4044,6 @@ TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction // <-- saTakerPaid: What taker paid not including fees. To reduce an offer. // <-- saTakerGot: What taker got not including fees. To reduce an offer. // <-- terResult: tesSUCCESS or terNO_ACCOUNT -// Note: All SLE modifications must always occur even on failure. // XXX: Fees should be paid by the source of the currency. TransactionEngineResult TransactionEngine::takeOffers( bool bPassive, diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index f8b7f34ed1..5a88c1775c 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -1,6 +1,7 @@ #ifndef __TRANSACTIONENGINE__ #define __TRANSACTIONENGINE__ +#include #include #include @@ -97,8 +98,8 @@ enum TransactionEngineParams typedef struct { uint16 uFlags; // --> From path. - uint160 uAccountID; // --> Recieving/sending account. - uint160 uCurrencyID; // --> Accounts: receive and send, Offers: send. + 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 @@ -115,6 +116,13 @@ typedef struct { STAmount saFwdDeliver; // <-- Amount to deliver to next regardless of fee. } paymentNode; +// account id, currency id, issuer id :: node +typedef boost::tuple aciSource; +typedef boost::unordered_map curIssuerNode; // Map of currency, issuer to node index. +typedef boost::unordered_map::const_iterator curIssuerNodeConstIterator; + +extern std::size_t hash_value(const aciSource& asValue); + // Hold a path state under incremental application. class PathState { @@ -133,8 +141,12 @@ public: // When processing, don't want to complicate directory walking with deletion. std::vector vUnfundedBecame; // Offers that became unfunded. - // First time working in reverse a funding source was mentioned. Source may only be used there. - boost::unordered_map, int> umSource; // Map of currency, issuer to node index. + // First time working foward 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; @@ -221,7 +233,7 @@ protected: SLE::pointer mTxnAccount; // First time working in reverse a funding source was mentioned. Source may only be used there. - boost::unordered_map, int> mumSource; // Map of currency, issuer to node index. + curIssuerNode mumSource; // Map of currency, issuer to node index. // When processing, don't want to complicate directory walking with deletion. std::vector mvUnfundedBecame; // Offers that became unfunded. @@ -254,12 +266,12 @@ protected: STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault); PathState::pointer pathCreate(const STPath& spPath); - void pathNext(PathState::pointer pspCur, int iPaths); - bool calcNode(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); - bool calcNodeOfferRev(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); - bool calcNodeOfferFwd(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); - bool calcNodeAccountRev(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); - bool calcNodeAccountFwd(unsigned int uIndex, PathState::pointer pspCur, bool bMultiQuality); + void pathNext(const PathState::pointer& pspCur, const int iPaths); + bool calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); + bool calcNodeOfferRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); + bool calcNodeOfferFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); + bool calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); + bool calcNodeAccountFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); void calcNodeRipple(const uint32 uQualityIn, const uint32 uQualityOut, const STAmount& saPrvReq, const STAmount& saCurReq, STAmount& saPrvAct, STAmount& saCurAct); From 7bf224200b2b8e6665ea0e27bd967cf19ac00a2b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 28 Aug 2012 15:31:41 -0700 Subject: [PATCH 125/426] This is not only simpler, but should perform slightly better too. --- src/LedgerConsensus.cpp | 115 +++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 55 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 52e4173c1c..fdc822f7a1 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../json/writer.h" @@ -19,6 +20,9 @@ // #define LC_DEBUG +typedef std::pair u160_prop_pair; +typedef std::pair u256_lct_pair; + TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false) { mMap = boost::make_shared(); @@ -214,9 +218,9 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, const Ledger::point mHaveCorrectLCL = mProposing = mValidating = false; mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(prevLCLHash); std::vector peerList = theApp->getConnectionPool().getPeerVector(); - for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) - if ((*it)->hasLedger(prevLCLHash)) - mAcquiringLedger->peerHas(*it); + BOOST_FOREACH(const Peer::pointer& peer, peerList) + if (peer->hasLedger(prevLCLHash)) + mAcquiringLedger->peerHas(peer); } else if (mValSeed.isValid()) { @@ -238,12 +242,16 @@ void LedgerConsensus::checkLCL() int netLgrCount = 0; { boost::unordered_map vals = theApp->getValidations().getCurrentValidations(); - for (boost::unordered_map::iterator it = vals.begin(), end = vals.end(); it != end; ++it) - if ((it->second > netLgrCount) && !theApp->getValidations().isDeadLedger(it->first)) + + typedef std::pair u256_int_pair; + BOOST_FOREACH(u256_int_pair& it, vals) + { + if ((it.second > netLgrCount) && !theApp->getValidations().isDeadLedger(it.first)) { - netLgr = it->first; - netLgrCount = it->second; + netLgr = it.first; + netLgrCount = it.second; } + } } if (netLgr != mPrevLedgerHash) { // LCL change @@ -255,15 +263,19 @@ void LedgerConsensus::checkLCL() mProposing = false; mValidating = false; bool found = false; - for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) - if ((*it)->hasLedger(mPrevLedgerHash)) + BOOST_FOREACH(Peer::pointer& peer, peerList) + { + if (peer->hasLedger(mPrevLedgerHash)) { found = true; - mAcquiringLedger->peerHas(*it); + mAcquiringLedger->peerHas(peer); } + } if (!found) - for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) - mAcquiringLedger->peerHas(*it); + { + BOOST_FOREACH(Peer::pointer& peer, peerList) + mAcquiringLedger->peerHas(peer); + } } } @@ -275,15 +287,14 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) // if any peers have taken a contrary position, process disputes boost::unordered_set found; - for (boost::unordered_map::iterator it = mPeerPositions.begin(), - end = mPeerPositions.end(); it != end; ++it) + BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) { - uint256 set = it->second->getCurrentHash(); + uint256 set = it.second->getCurrentHash(); if (found.insert(set).second) { - boost::unordered_map::iterator it = mComplete.find(set); - if (it != mComplete.end()) - createDisputes(initialSet, it->second); + boost::unordered_map::iterator iit = mComplete.find(set); + if (iit != mComplete.end()) + createDisputes(initialSet, iit->second); } } @@ -347,11 +358,10 @@ void LedgerConsensus::mapComplete(const uint256& hash, const SHAMap::pointer& ma // Adjust tracking for each peer that takes this position std::vector peers; - for (boost::unordered_map::iterator it = mPeerPositions.begin(), - end = mPeerPositions.end(); it != end; ++it) + BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) { - if (it->second->getCurrentHash() == map->getHash()) - peers.push_back(it->second->getPeerID()); + if (it.second->getCurrentHash() == map->getHash()) + peers.push_back(it.second->getPeerID()); } if (!peers.empty()) adjustCount(map, peers); @@ -372,12 +382,11 @@ void LedgerConsensus::sendHaveTxSet(const uint256& hash, bool direct) void LedgerConsensus::adjustCount(const SHAMap::pointer& map, const std::vector& peers) { // Adjust the counts on all disputed transactions based on the set of peers taking this position - for (boost::unordered_map::iterator it = mDisputes.begin(), end = mDisputes.end(); - it != end; ++it) + BOOST_FOREACH(u256_lct_pair& it, mDisputes) { - bool setHas = map->hasItem(it->second->getTransactionID()); - for (std::vector::const_iterator pit = peers.begin(), pend = peers.end(); pit != pend; ++pit) - it->second->setVote(*pit, setHas); + bool setHas = map->hasItem(it.second->getTransactionID()); + BOOST_FOREACH(const uint160& pit, peers) + it.second->setVote(pit, setHas); } } @@ -502,33 +511,32 @@ void LedgerConsensus::updateOurPositions() SHAMap::pointer ourPosition; std::vector addedTx, removedTx; - for (boost::unordered_map::iterator it = mDisputes.begin(), - end = mDisputes.end(); it != end; ++it) + BOOST_FOREACH(u256_lct_pair& it, mDisputes) { - if (it->second->updatePosition(mClosePercent, mProposing)) + if (it.second->updatePosition(mClosePercent, mProposing)) { if (!changes) { ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); changes = true; } - if (it->second->getOurPosition()) // now a yes + if (it.second->getOurPosition()) // now a yes { - ourPosition->addItem(SHAMapItem(it->first, it->second->peekTransaction()), true, false); - addedTx.push_back(it->first); + ourPosition->addItem(SHAMapItem(it.first, it.second->peekTransaction()), true, false); + addedTx.push_back(it.first); } else // now a no { - ourPosition->delItem(it->first); - removedTx.push_back(it->first); + ourPosition->delItem(it.first); + removedTx.push_back(it.first); } } } std::map closeTimes; - for (boost::unordered_map::iterator it = mPeerPositions.begin(), - end = mPeerPositions.end(); it != end; ++it) - ++closeTimes[it->second->getCloseTime() - (it->second->getCloseTime() % mCloseResolution)]; + + BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) + ++closeTimes[it.second->getCloseTime() - (it.second->getCloseTime() % mCloseResolution)]; int neededWeight; if (mClosePercent < AV_MID_CONSENSUS_TIME) @@ -594,10 +602,9 @@ bool LedgerConsensus::haveConsensus() { int agree = 0, disagree = 0; uint256 ourPosition = mOurPosition->getCurrentHash(); - for (boost::unordered_map::iterator it = mPeerPositions.begin(), - end = mPeerPositions.end(); it != end; ++it) + BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) { - if (it->second->getCurrentHash() == ourPosition) + if (it.second->getCurrentHash() == ourPosition) ++agree; else ++disagree; @@ -703,13 +710,12 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec LCTransaction::pointer txn = boost::make_shared(txID, tx, ourPosition); mDisputes[txID] = txn; - for (boost::unordered_map::iterator pit = mPeerPositions.begin(), - pend = mPeerPositions.end(); pit != pend; ++pit) + BOOST_FOREACH(u160_prop_pair& pit, mPeerPositions) { boost::unordered_map::const_iterator cit = - mComplete.find(pit->second->getCurrentHash()); + mComplete.find(pit.second->getCurrentHash()); if (cit != mComplete.end() && cit->second) - txn->setVote(pit->first, cit->second->hasItem(txID)); + txn->setVote(pit.first, cit->second->hasItem(txID)); } } @@ -736,9 +742,8 @@ bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) SHAMap::pointer set = getTransactionTree(newPosition->getCurrentHash(), true); if (set) { - for (boost::unordered_map::iterator it = mDisputes.begin(), - end = mDisputes.end(); it != end; ++it) - it->second->setVote(newPosition->getPeerID(), set->hasItem(it->first)); + BOOST_FOREACH(u256_lct_pair& it, mDisputes) + it.second->setVote(newPosition->getPeerID(), set->hasItem(it.first)); } else Log(lsTRACE) << "Don't have that tx set"; @@ -752,8 +757,8 @@ bool LedgerConsensus::peerHasSet(const Peer::pointer& peer, const uint256& hashS return true; std::vector< boost::weak_ptr >& set = mPeerData[hashSet]; - for (std::vector< boost::weak_ptr >::iterator iit = set.begin(), iend = set.end(); iit != iend; ++iit) - if (iit->lock() == peer) + BOOST_FOREACH(boost::weak_ptr& iit, set) + if (iit.lock() == peer) return false; set.push_back(peer); @@ -934,15 +939,14 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) // Apply disputed transactions that didn't get in TransactionEngine engine(newOL); - for (boost::unordered_map::iterator it = mDisputes.begin(), - end = mDisputes.end(); it != end; ++it) + BOOST_FOREACH(u256_lct_pair& it, mDisputes) { - if (!it->second->getOurPosition()) + if (!it.second->getOurPosition()) { // we voted NO try { Log(lsINFO) << "Test applying disputed transaction that did not get in"; - SerializerIterator sit(it->second->peekTransaction()); + SerializerIterator sit(it.second->peekTransaction()); SerializedTransaction::pointer txn = boost::make_shared(boost::ref(sit)); applyTransaction(engine, txn, newOL, failedTransactions, false); } @@ -966,7 +970,8 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) Log(lsINFO) << "We closed at " << boost::lexical_cast(mCloseTime); uint64 closeTotal = mCloseTime; int closeCount = 1; - for (std::map::iterator it = mCloseTimes.begin(), end = mCloseTimes.end(); it != end; ++it) + for (std::map::iterator it = mCloseTimes.begin(), end = + mCloseTimes.end(); it != end; ++it) { Log(lsINFO) << boost::lexical_cast(it->second) << " time votes for " << boost::lexical_cast(it->first); From 192c64461dfe86c5b7ec62def347fd9018ba0c53 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 28 Aug 2012 15:35:47 -0700 Subject: [PATCH 126/426] Simplify and improve performance a bit. --- src/LedgerConsensus.cpp | 115 +++++++++++++++++++++------------------- 1 file changed, 60 insertions(+), 55 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 52e4173c1c..fdc822f7a1 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../json/writer.h" @@ -19,6 +20,9 @@ // #define LC_DEBUG +typedef std::pair u160_prop_pair; +typedef std::pair u256_lct_pair; + TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false) { mMap = boost::make_shared(); @@ -214,9 +218,9 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, const Ledger::point mHaveCorrectLCL = mProposing = mValidating = false; mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(prevLCLHash); std::vector peerList = theApp->getConnectionPool().getPeerVector(); - for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) - if ((*it)->hasLedger(prevLCLHash)) - mAcquiringLedger->peerHas(*it); + BOOST_FOREACH(const Peer::pointer& peer, peerList) + if (peer->hasLedger(prevLCLHash)) + mAcquiringLedger->peerHas(peer); } else if (mValSeed.isValid()) { @@ -238,12 +242,16 @@ void LedgerConsensus::checkLCL() int netLgrCount = 0; { boost::unordered_map vals = theApp->getValidations().getCurrentValidations(); - for (boost::unordered_map::iterator it = vals.begin(), end = vals.end(); it != end; ++it) - if ((it->second > netLgrCount) && !theApp->getValidations().isDeadLedger(it->first)) + + typedef std::pair u256_int_pair; + BOOST_FOREACH(u256_int_pair& it, vals) + { + if ((it.second > netLgrCount) && !theApp->getValidations().isDeadLedger(it.first)) { - netLgr = it->first; - netLgrCount = it->second; + netLgr = it.first; + netLgrCount = it.second; } + } } if (netLgr != mPrevLedgerHash) { // LCL change @@ -255,15 +263,19 @@ void LedgerConsensus::checkLCL() mProposing = false; mValidating = false; bool found = false; - for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) - if ((*it)->hasLedger(mPrevLedgerHash)) + BOOST_FOREACH(Peer::pointer& peer, peerList) + { + if (peer->hasLedger(mPrevLedgerHash)) { found = true; - mAcquiringLedger->peerHas(*it); + mAcquiringLedger->peerHas(peer); } + } if (!found) - for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) - mAcquiringLedger->peerHas(*it); + { + BOOST_FOREACH(Peer::pointer& peer, peerList) + mAcquiringLedger->peerHas(peer); + } } } @@ -275,15 +287,14 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) // if any peers have taken a contrary position, process disputes boost::unordered_set found; - for (boost::unordered_map::iterator it = mPeerPositions.begin(), - end = mPeerPositions.end(); it != end; ++it) + BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) { - uint256 set = it->second->getCurrentHash(); + uint256 set = it.second->getCurrentHash(); if (found.insert(set).second) { - boost::unordered_map::iterator it = mComplete.find(set); - if (it != mComplete.end()) - createDisputes(initialSet, it->second); + boost::unordered_map::iterator iit = mComplete.find(set); + if (iit != mComplete.end()) + createDisputes(initialSet, iit->second); } } @@ -347,11 +358,10 @@ void LedgerConsensus::mapComplete(const uint256& hash, const SHAMap::pointer& ma // Adjust tracking for each peer that takes this position std::vector peers; - for (boost::unordered_map::iterator it = mPeerPositions.begin(), - end = mPeerPositions.end(); it != end; ++it) + BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) { - if (it->second->getCurrentHash() == map->getHash()) - peers.push_back(it->second->getPeerID()); + if (it.second->getCurrentHash() == map->getHash()) + peers.push_back(it.second->getPeerID()); } if (!peers.empty()) adjustCount(map, peers); @@ -372,12 +382,11 @@ void LedgerConsensus::sendHaveTxSet(const uint256& hash, bool direct) void LedgerConsensus::adjustCount(const SHAMap::pointer& map, const std::vector& peers) { // Adjust the counts on all disputed transactions based on the set of peers taking this position - for (boost::unordered_map::iterator it = mDisputes.begin(), end = mDisputes.end(); - it != end; ++it) + BOOST_FOREACH(u256_lct_pair& it, mDisputes) { - bool setHas = map->hasItem(it->second->getTransactionID()); - for (std::vector::const_iterator pit = peers.begin(), pend = peers.end(); pit != pend; ++pit) - it->second->setVote(*pit, setHas); + bool setHas = map->hasItem(it.second->getTransactionID()); + BOOST_FOREACH(const uint160& pit, peers) + it.second->setVote(pit, setHas); } } @@ -502,33 +511,32 @@ void LedgerConsensus::updateOurPositions() SHAMap::pointer ourPosition; std::vector addedTx, removedTx; - for (boost::unordered_map::iterator it = mDisputes.begin(), - end = mDisputes.end(); it != end; ++it) + BOOST_FOREACH(u256_lct_pair& it, mDisputes) { - if (it->second->updatePosition(mClosePercent, mProposing)) + if (it.second->updatePosition(mClosePercent, mProposing)) { if (!changes) { ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); changes = true; } - if (it->second->getOurPosition()) // now a yes + if (it.second->getOurPosition()) // now a yes { - ourPosition->addItem(SHAMapItem(it->first, it->second->peekTransaction()), true, false); - addedTx.push_back(it->first); + ourPosition->addItem(SHAMapItem(it.first, it.second->peekTransaction()), true, false); + addedTx.push_back(it.first); } else // now a no { - ourPosition->delItem(it->first); - removedTx.push_back(it->first); + ourPosition->delItem(it.first); + removedTx.push_back(it.first); } } } std::map closeTimes; - for (boost::unordered_map::iterator it = mPeerPositions.begin(), - end = mPeerPositions.end(); it != end; ++it) - ++closeTimes[it->second->getCloseTime() - (it->second->getCloseTime() % mCloseResolution)]; + + BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) + ++closeTimes[it.second->getCloseTime() - (it.second->getCloseTime() % mCloseResolution)]; int neededWeight; if (mClosePercent < AV_MID_CONSENSUS_TIME) @@ -594,10 +602,9 @@ bool LedgerConsensus::haveConsensus() { int agree = 0, disagree = 0; uint256 ourPosition = mOurPosition->getCurrentHash(); - for (boost::unordered_map::iterator it = mPeerPositions.begin(), - end = mPeerPositions.end(); it != end; ++it) + BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) { - if (it->second->getCurrentHash() == ourPosition) + if (it.second->getCurrentHash() == ourPosition) ++agree; else ++disagree; @@ -703,13 +710,12 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec LCTransaction::pointer txn = boost::make_shared(txID, tx, ourPosition); mDisputes[txID] = txn; - for (boost::unordered_map::iterator pit = mPeerPositions.begin(), - pend = mPeerPositions.end(); pit != pend; ++pit) + BOOST_FOREACH(u160_prop_pair& pit, mPeerPositions) { boost::unordered_map::const_iterator cit = - mComplete.find(pit->second->getCurrentHash()); + mComplete.find(pit.second->getCurrentHash()); if (cit != mComplete.end() && cit->second) - txn->setVote(pit->first, cit->second->hasItem(txID)); + txn->setVote(pit.first, cit->second->hasItem(txID)); } } @@ -736,9 +742,8 @@ bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) SHAMap::pointer set = getTransactionTree(newPosition->getCurrentHash(), true); if (set) { - for (boost::unordered_map::iterator it = mDisputes.begin(), - end = mDisputes.end(); it != end; ++it) - it->second->setVote(newPosition->getPeerID(), set->hasItem(it->first)); + BOOST_FOREACH(u256_lct_pair& it, mDisputes) + it.second->setVote(newPosition->getPeerID(), set->hasItem(it.first)); } else Log(lsTRACE) << "Don't have that tx set"; @@ -752,8 +757,8 @@ bool LedgerConsensus::peerHasSet(const Peer::pointer& peer, const uint256& hashS return true; std::vector< boost::weak_ptr >& set = mPeerData[hashSet]; - for (std::vector< boost::weak_ptr >::iterator iit = set.begin(), iend = set.end(); iit != iend; ++iit) - if (iit->lock() == peer) + BOOST_FOREACH(boost::weak_ptr& iit, set) + if (iit.lock() == peer) return false; set.push_back(peer); @@ -934,15 +939,14 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) // Apply disputed transactions that didn't get in TransactionEngine engine(newOL); - for (boost::unordered_map::iterator it = mDisputes.begin(), - end = mDisputes.end(); it != end; ++it) + BOOST_FOREACH(u256_lct_pair& it, mDisputes) { - if (!it->second->getOurPosition()) + if (!it.second->getOurPosition()) { // we voted NO try { Log(lsINFO) << "Test applying disputed transaction that did not get in"; - SerializerIterator sit(it->second->peekTransaction()); + SerializerIterator sit(it.second->peekTransaction()); SerializedTransaction::pointer txn = boost::make_shared(boost::ref(sit)); applyTransaction(engine, txn, newOL, failedTransactions, false); } @@ -966,7 +970,8 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) Log(lsINFO) << "We closed at " << boost::lexical_cast(mCloseTime); uint64 closeTotal = mCloseTime; int closeCount = 1; - for (std::map::iterator it = mCloseTimes.begin(), end = mCloseTimes.end(); it != end; ++it) + for (std::map::iterator it = mCloseTimes.begin(), end = + mCloseTimes.end(); it != end; ++it) { Log(lsINFO) << boost::lexical_cast(it->second) << " time votes for " << boost::lexical_cast(it->first); From e4f7ffe99569208710923c6b095b53ea17f01238 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 28 Aug 2012 16:07:44 -0700 Subject: [PATCH 127/426] Some cleanups that should make Arthur happy. --- src/HashedObject.cpp | 12 +++++----- src/NetworkOPs.cpp | 42 +++++++++++++++------------------ src/SerializedObject.cpp | 33 +++++++++++--------------- src/SerializedTransaction.cpp | 7 +++--- src/TransactionEngine.cpp | 1 + src/TransactionMeta.cpp | 44 +++++++++++++++-------------------- src/ValidationCollection.cpp | 16 ++++++++----- 7 files changed, 73 insertions(+), 82 deletions(-) diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp index 71730bfb19..fcbbee41bc 100644 --- a/src/HashedObject.cpp +++ b/src/HashedObject.cpp @@ -2,6 +2,7 @@ #include "HashedObject.h" #include +#include #include "Serializer.h" #include "Application.h" @@ -63,13 +64,12 @@ void HashedObjectStore::bulkWrite() db->executeSQL("BEGIN TRANSACTION;"); - for (std::vector< boost::shared_ptr >::iterator it = set.begin(), end = set.end(); it != end; ++it) + BOOST_FOREACH(const boost::shared_ptr& it, set) { - HashedObject& obj = **it; - if (!SQL_EXISTS(db, boost::str(fExists % obj.getHash().GetHex()))) + if (!SQL_EXISTS(db, boost::str(fExists % it->getHash().GetHex()))) { char type; - switch(obj.getType()) + switch(it->getType()) { case LEDGER: type = 'L'; break; case TRANSACTION: type = 'T'; break; @@ -78,8 +78,8 @@ void HashedObjectStore::bulkWrite() default: type = 'U'; } std::string rawData; - db->escape(&(obj.getData().front()), obj.getData().size(), rawData); - db->executeSQL(boost::str(fAdd % obj.getHash().GetHex() % type % obj.getIndex() % rawData )); + db->escape(&(it->getData().front()), it->getData().size(), rawData); + db->executeSQL(boost::str(fAdd % it->getHash().GetHex() % type % it->getIndex() % rawData )); } } diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 40cd4cc856..32e0c61620 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -444,23 +444,23 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis ourVC.highNode = theApp->getWallet().getNodePublic(); } - for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) + BOOST_FOREACH(const Peer::pointer& it, peerList) { - if (!*it) + if (!it) { Log(lsDEBUG) << "NOP::CS Dead pointer in peer list"; } - else if ((*it)->isConnected()) + else if (it->isConnected()) { - uint256 peerLedger = (*it)->getClosedLedgerHash(); + uint256 peerLedger = it->getClosedLedgerHash(); if (peerLedger.isNonZero()) { ValidationCount& vc = ledgers[peerLedger]; - if ((vc.nodesUsing == 0) || ((*it)->getNodePublic() > vc.highNode)) - vc.highNode = (*it)->getNodePublic(); + if ((vc.nodesUsing == 0) || (it->getNodePublic() > vc.highNode)) + vc.highNode = it->getNodePublic(); ++vc.nodesUsing; } - else Log(lsTRACE) << "Connected peer announces no LCL " << (*it)->getIP(); + else Log(lsTRACE) << "Connected peer announces no LCL " << it->getIP(); } } @@ -522,23 +522,19 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis { // add more peers int count = 0; std::vector peers=theApp->getConnectionPool().getPeerVector(); - for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); - it != end; ++it) + BOOST_FOREACH(const Peer::pointer& it, peerList) { - if ((*it)->getClosedLedgerHash() == closedLedger) + if (it->getClosedLedgerHash() == closedLedger) { ++count; - mAcquiringLedger->peerHas(*it); + mAcquiringLedger->peerHas(it); } } if (!count) { // just ask everyone - for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); - it != end; ++it) - { - if ((*it)->isConnected()) - mAcquiringLedger->peerHas(*it); - } + BOOST_FOREACH(const Peer::pointer& it, peerList) + if (it->isConnected()) + mAcquiringLedger->peerHas(it); } return true; } @@ -678,12 +674,12 @@ void NetworkOPs::endConsensus(bool correctLCL) Log(lsTRACE) << "Ledger " << deadLedger.GetHex() << " is now dead"; theApp->getValidations().addDeadLedger(deadLedger); std::vector peerList = theApp->getConnectionPool().getPeerVector(); - for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) - if (*it && ((*it)->getClosedLedgerHash() == deadLedger)) - { - Log(lsTRACE) << "Killing obsolete peer status"; - (*it)->cycleStatus(); - } + BOOST_FOREACH(const Peer::pointer& it, peerList) + if (it && (it->getClosedLedgerHash() == deadLedger)) + { + Log(lsTRACE) << "Killing obsolete peer status"; + it->cycleStatus(); + } mConsensus = boost::shared_ptr(); } diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 0f9af758e5..7600d803b7 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -185,15 +185,13 @@ std::string STObject::getFullText() const } else ret = "{"; - for (boost::ptr_vector::const_iterator it = mData.begin(), end = mData.end(); it != end; ++it) - { - if (it->getSType() != STI_NOTPRESENT) + BOOST_FOREACH(const SerializedType& it, mData) + if (it.getSType() != STI_NOTPRESENT) { if (!first) ret += ", "; else first = false; - ret += it->getFullText(); + ret += it.getFullText(); } - } ret += "}"; return ret; @@ -202,29 +200,29 @@ std::string STObject::getFullText() const int STObject::getLength() const { int ret = 0; - for (boost::ptr_vector::const_iterator it = mData.begin(), end = mData.end(); it != end; ++it) - ret += it->getLength(); + BOOST_FOREACH(const SerializedType& it, mData) + ret += it.getLength(); return ret; } void STObject::add(Serializer& s) const { - for (boost::ptr_vector::const_iterator it = mData.begin(), end = mData.end(); it != end; ++it) - it->add(s); + BOOST_FOREACH(const SerializedType& it, mData) + it.add(s); } std::string STObject::getText() const { std::string ret = "{"; bool first = false; - for (boost::ptr_vector::const_iterator it = mData.begin(), end = mData.end(); it != end; ++it) + BOOST_FOREACH(const SerializedType& it, mData) { if (!first) { ret += ", "; first = false; } - ret += it->getText(); + ret += it.getText(); } ret += "}"; return ret; @@ -654,14 +652,13 @@ Json::Value STObject::getJson(int options) const { Json::Value ret(Json::objectValue); int index = 1; - for(boost::ptr_vector::const_iterator it = mData.begin(), end = mData.end(); it != end; - ++it, ++index) + BOOST_FOREACH(const SerializedType& it, mData) { - if (it->getSType() != STI_NOTPRESENT) + if (it.getSType() != STI_NOTPRESENT) { - if (it->getName() == NULL) - ret[boost::lexical_cast(index)] = it->getJson(options); - else ret[it->getName()] = it->getJson(options); + if (it.getName() == NULL) + ret[boost::lexical_cast(index)] = it.getJson(options); + else ret[it.getName()] = it.getJson(options); } } return ret; @@ -672,9 +669,7 @@ Json::Value STVector256::getJson(int options) const Json::Value ret(Json::arrayValue); BOOST_FOREACH(std::vector::const_iterator::value_type vEntry, mValue) - { ret.append(vEntry.ToString()); - } return ret; } diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index bab0a4a9f5..0ee218028c 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -1,6 +1,8 @@ #include "SerializedTransaction.h" +#include + #include "Application.h" #include "Log.h" #include "HashPrefixes.h" @@ -83,10 +85,9 @@ std::vector SerializedTransaction::getAffectedAccounts() const std::vector accounts; accounts.push_back(mSourceAccount); - for(boost::ptr_vector::const_iterator it = mInnerTxn.peekData().begin(), - end = mInnerTxn.peekData().end(); it != end ; ++it) + BOOST_FOREACH(const SerializedType& it, mInnerTxn.peekData()) { - const STAccount* sa = dynamic_cast(&*it); + const STAccount* sa = dynamic_cast(&it); if (sa != NULL) { bool found = false; diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index df8a0c7082..ec277b2e4a 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include "../json/writer.h" diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index 396f863f52..8a14cbbf14 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -4,6 +4,7 @@ #include #include +#include bool TransactionMetaNodeEntry::operator<(const TransactionMetaNodeEntry& e) const { @@ -167,27 +168,24 @@ void TransactionMetaNode::addRaw(Serializer& s) s.add8(mType); s.add256(mNode); mEntries.sort(); - for (boost::ptr_vector::const_iterator it = mEntries.begin(), end = mEntries.end(); - it != end; ++it) - it->addRaw(s); + BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries) + it.addRaw(s); s.add8(TMSEndOfNode); } TransactionMetaNodeEntry* TransactionMetaNode::findEntry(int nodeType) { - for (boost::ptr_vector::iterator it = mEntries.begin(), end = mEntries.end(); - it != end; ++it) - if (it->getType() == nodeType) - return &*it; + BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries) + if (it.getType() == nodeType) + return ⁢ return NULL; } TMNEAmount* TransactionMetaNode::findAmount(int nType) { - for (boost::ptr_vector::iterator it = mEntries.begin(), end = mEntries.end(); - it != end; ++it) - if (it->getType() == nType) - return dynamic_cast(&*it); + BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries) + if (it.getType() == nType) + return dynamic_cast(&it); TMNEAmount* node = new TMNEAmount(nType); mEntries.push_back(node); return node; @@ -200,9 +198,8 @@ void TransactionMetaNode::addNode(TransactionMetaNodeEntry* node) bool TransactionMetaNode::thread(const uint256& prevTx, uint32 prevLgr) { - for (boost::ptr_vector::iterator it = mEntries.begin(), end = mEntries.end(); - it != end; ++it) - if (it->getType() == TMSThread) + BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries) + if (it.getType() == TMSThread) return false; addNode(new TMNEThread(prevTx, prevLgr)); return true; @@ -210,11 +207,10 @@ bool TransactionMetaNode::thread(const uint256& prevTx, uint32 prevLgr) bool TransactionMetaNode::addAmount(int nodeType, const STAmount& amount) { - for (boost::ptr_vector::iterator it = mEntries.begin(), end = mEntries.end(); - it != end; ++it) - if (it->getType() == nodeType) + BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries) + if (it.getType() == nodeType) { - TMNEAmount* a = dynamic_cast(&*it); + TMNEAmount* a = dynamic_cast(&it); assert(a && (a->getAmount() == amount)); return false; } @@ -224,11 +220,10 @@ bool TransactionMetaNode::addAmount(int nodeType, const STAmount& amount) bool TransactionMetaNode::addAccount(int nodeType, const NewcoinAddress& account) { - for (boost::ptr_vector::iterator it = mEntries.begin(), end = mEntries.end(); - it != end; ++it) - if (it->getType() == nodeType) + BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries) + if (it.getType() == nodeType) { - TMNEAccount* a = dynamic_cast(&*it); + TMNEAccount* a = dynamic_cast(&it); assert(a && (a->getAccount() == account)); return false; } @@ -252,9 +247,8 @@ Json::Value TransactionMetaNode::getJson(int v) const ret["node"] = mNode.GetHex(); Json::Value e = Json::arrayValue; - for (boost::ptr_vector::const_iterator it = mEntries.begin(), end = mEntries.end(); - it != end; ++it) - e.append(it->getJson(v)); + BOOST_FOREACH(const TransactionMetaNodeEntry& it, mEntries) + e.append(it.getJson(v)); ret["entries"] = e; return ret; diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 1bb971c576..0dee29b63e 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -1,6 +1,8 @@ #include "ValidationCollection.h" +#include + #include "Application.h" #include "LedgerTiming.h" #include "Log.h" @@ -192,8 +194,8 @@ boost::unordered_map ValidationCollection::getCurrentValidations() bool ValidationCollection::isDeadLedger(const uint256& ledger) { - for (std::list::iterator it = mDeadLedgers.begin(), end = mDeadLedgers.end(); it != end; ++it) - if (*it == ledger) + BOOST_FOREACH(const uint256& it, mDeadLedgers) + if (it == ledger) return true; return false; } @@ -259,10 +261,12 @@ void ValidationCollection::doWrite() ScopedLock dbl(theApp->getLedgerDB()->getDBLock()); Database *db = theApp->getLedgerDB()->getDB(); db->executeSQL("BEGIN TRANSACTION;"); - for (std::vector::iterator it = vector.begin(); it != vector.end(); ++it) - db->executeSQL(boost::str(insVal % (*it)->getLedgerHash().GetHex() - % (*it)->getSignerPublic().humanNodePublic() % (*it)->getFlags() % (*it)->getCloseTime() - % db->escape(strCopy((*it)->getSignature())))); + + + BOOST_FOREACH(const SerializedValidation::pointer& it, vector) + db->executeSQL(boost::str(insVal % it->getLedgerHash().GetHex() + % it->getSignerPublic().humanNodePublic() % it->getFlags() % it->getCloseTime() + % db->escape(strCopy(it->getSignature())))); db->executeSQL("END TRANSACTION;"); } From 54eca8a3bbf3e0b2d063bb67762d5126e6103927 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 28 Aug 2012 23:44:19 -0700 Subject: [PATCH 128/426] Whitespace fix. --- src/LedgerConsensus.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index fdc822f7a1..59b1d83f03 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -534,7 +534,6 @@ void LedgerConsensus::updateOurPositions() } std::map closeTimes; - BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) ++closeTimes[it.second->getCloseTime() - (it.second->getCloseTime() % mCloseResolution)]; From 004f3719a515673d51ee5ac8499629643dd2e9d0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 28 Aug 2012 23:44:29 -0700 Subject: [PATCH 129/426] Perhaps a fix for the problem. Try to make sure there's no window in which we can receive a proposal and be unable to act on it, even if our clock is way off and there are no transactions. The basic problem is this: With no transactions and no clock synchronization, we have no way to know when to close an idle ledger. --- src/NetworkOPs.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 32e0c61620..2f7a4fca87 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -614,12 +614,6 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint if (!theApp->isNew(s.getSHA512Half())) return false; - if (!mConsensus) - { // FIXME: CLC - Log(lsWARNING) << "Received proposal when full but not during consensus window"; - return false; - } - NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey)); LedgerProposal::pointer proposal = boost::make_shared(mConsensus->getLCL(), proposeSeq, proposeHash, closeTime, naPeerPublic); @@ -637,6 +631,22 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint return true; } + if ((!mConsensus) && (mMode == omFULL)) + { + uint256 networkClosed; + bool ledgerChange = checkLastClosedLedger(peerList, networkClosed); + if (!ledgerChange) + { + Log(lsWARNING) << "Beginning consensus due to proposal from peer"; + beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger()); + } + } + if (!mConsensus) + { + Log(lsWARNING) << "Received proposal when full but not during consensus window"; + return false; + } + return mConsensus->peerPosition(proposal); } From af5c04b81663226c7a74a7686ad281deb23e6f1a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 29 Aug 2012 00:03:30 -0700 Subject: [PATCH 130/426] Some extra debug. --- src/LedgerTiming.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index 9243dd6ce0..369e559a0c 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -33,7 +33,8 @@ int ContinuousLedgerTiming::shouldClose( { // no transactions so far this interval if (proposersClosed > (previousProposers / 4)) // did we miss a transaction? { - Log(lsTRACE) << "no transactions, many proposers: now"; + Log(lsTRACE) << "no transactions, many proposers: now (" << proposersClose << "closed, " + << previousProposers << " before)"; return currentMSeconds; } if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close From 45329b8d08b003f04f5e4dd358ca96a24f6f7be0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 29 Aug 2012 00:09:28 -0700 Subject: [PATCH 131/426] Remove some dead code. --- src/Peer.cpp | 2 -- src/Peer.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index 0a258c477e..75a5f2f656 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -648,7 +648,6 @@ void Peer::recvHello(newcoin::TMHello& packet) if ((packet.has_ledgerprevious()) && (packet.ledgerprevious().size() == (256 / 8))) memcpy(mPreviousLedgerHash.begin(), packet.ledgerprevious().data(), 256 / 8); else mPreviousLedgerHash.zero(); - mClosedLedgerTime = boost::posix_time::second_clock::universal_time(); } bDetach = false; @@ -908,7 +907,6 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet) if (packet.has_ledgerhash() && (packet.ledgerhash().size() == (256 / 8))) { // a peer has changed ledgers memcpy(mClosedLedgerHash.begin(), packet.ledgerhash().data(), 256 / 8); - mClosedLedgerTime = ptFromSeconds(packet.networktime()); Log(lsTRACE) << "peer LCL is " << mClosedLedgerHash.GetHex() << " " << getIP(); } else diff --git a/src/Peer.h b/src/Peer.h index 01c5863714..85666c9c69 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -43,9 +43,7 @@ private: ipPort mIpPortConnect; uint256 mCookieHash; - // network state information uint256 mClosedLedgerHash, mPreviousLedgerHash; - boost::posix_time::ptime mClosedLedgerTime; boost::asio::ssl::stream mSocketSsl; From d96070f08398059d1eca6e6d156ea705f29b08b5 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 29 Aug 2012 11:58:34 -0700 Subject: [PATCH 132/426] Rename TransactionEngineResult to TER & work on ripple. --- src/LedgerConsensus.cpp | 4 +- src/LedgerMaster.cpp | 4 +- src/LedgerMaster.h | 2 +- src/NetworkOPs.cpp | 12 +- src/NetworkOPs.h | 8 +- src/TransactionEngine.cpp | 253 ++++++++++++++++++++++---------------- src/TransactionEngine.h | 58 ++++----- 7 files changed, 190 insertions(+), 151 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 52e4173c1c..ae3c7813b7 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -799,7 +799,7 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, const Serializ try { #endif - TransactionEngineResult result = engine.applyTransaction(*txn, parms); + TER result = engine.applyTransaction(*txn, parms); if (result > 0) { Log(lsINFO) << " retry"; @@ -861,7 +861,7 @@ void LedgerConsensus::applyTransactions(const SHAMap::pointer& set, const Ledger { try { - TransactionEngineResult result = engine.applyTransaction(*it->second, parms); + TER result = engine.applyTransaction(*it->second, parms); if (result <= 0) { if (result == 0) ++successes; diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp index e7b571f361..7228ff6b96 100644 --- a/src/LedgerMaster.cpp +++ b/src/LedgerMaster.cpp @@ -80,10 +80,10 @@ Ledger::pointer LedgerMaster::closeLedger() return closingLedger; } -TransactionEngineResult LedgerMaster::doTransaction(const SerializedTransaction& txn, uint32 targetLedger, +TER LedgerMaster::doTransaction(const SerializedTransaction& txn, uint32 targetLedger, TransactionEngineParams params) { - TransactionEngineResult result = mEngine.applyTransaction(txn, params); + TER result = mEngine.applyTransaction(txn, params); theApp->getOPs().pubTransaction(mEngine.getLedger(), txn, result); return result; } diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h index dd51333283..f3e58d5ba6 100644 --- a/src/LedgerMaster.h +++ b/src/LedgerMaster.h @@ -45,7 +45,7 @@ public: void runStandAlone() { mFinalizedLedger = mCurrentLedger; } - TransactionEngineResult doTransaction(const SerializedTransaction& txn, uint32 targetLedger, + TER doTransaction(const SerializedTransaction& txn, uint32 targetLedger, TransactionEngineParams params); void pushLedger(const Ledger::pointer& newLedger); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 40cd4cc856..b2cbb51ce1 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -84,7 +84,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, return trans; } - TransactionEngineResult r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, tepNONE); + TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, tepNONE); if (r == tefFAILURE) throw Fault(IO_ERROR); if (r == terPRE_SEQ) @@ -875,7 +875,7 @@ void NetworkOPs::pubLedger(const Ledger::pointer& lpAccepted) SerializedTransaction::pointer stTxn = theApp->getMasterTransaction().fetch(item, false, 0); // XXX Need to support other results. // XXX Need to give failures too. - TransactionEngineResult terResult = tesSUCCESS; + TER terResult = tesSUCCESS; if (bAll) { @@ -909,7 +909,7 @@ void NetworkOPs::pubLedger(const Ledger::pointer& lpAccepted) // XXX Publish delta information for accounts. } -Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TransactionEngineResult terResult, const std::string& strStatus, int iSeq, const std::string& strType) +Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terResult, const std::string& strStatus, int iSeq, const std::string& strType) { Json::Value jvObj(Json::objectValue); std::string strToken; @@ -927,7 +927,7 @@ Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, Transactio return jvObj; } -void NetworkOPs::pubTransactionAll(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState) +void NetworkOPs::pubTransactionAll(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState) { Json::Value jvObj = transJson(stTxn, terResult, pState, lpCurrent->getLedgerSeq(), "transaction"); @@ -937,7 +937,7 @@ void NetworkOPs::pubTransactionAll(const Ledger::pointer& lpCurrent, const Seria } } -void NetworkOPs::pubTransactionAccounts(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState) +void NetworkOPs::pubTransactionAccounts(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState) { boost::unordered_set usisNotify; @@ -972,7 +972,7 @@ void NetworkOPs::pubTransactionAccounts(const Ledger::pointer& lpCurrent, const } } -void NetworkOPs::pubTransaction(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult) +void NetworkOPs::pubTransaction(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TER terResult) { boost::interprocess::sharable_lock sl(mMonitorLock); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 91ac722a05..9b324edddc 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -77,9 +77,9 @@ protected: void setMode(OperatingMode); - Json::Value transJson(const SerializedTransaction& stTxn, TransactionEngineResult terResult, const std::string& strStatus, int iSeq, const std::string& strType); - void pubTransactionAll(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState); - void pubTransactionAccounts(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState); + Json::Value transJson(const SerializedTransaction& stTxn, TER terResult, const std::string& strStatus, int iSeq, const std::string& strType); + void pubTransactionAll(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState); + void pubTransactionAccounts(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState); Json::Value pubBootstrapAccountInfo(const Ledger::pointer& lpAccepted, const NewcoinAddress& naAccountID); @@ -195,7 +195,7 @@ public: void pubAccountInfo(const NewcoinAddress& naAccountID, const Json::Value& jvObj); void pubLedger(const Ledger::pointer& lpAccepted); - void pubTransaction(const Ledger::pointer& lpLedger, const SerializedTransaction& stTxn, TransactionEngineResult terResult); + void pubTransaction(const Ledger::pointer& lpLedger, const SerializedTransaction& stTxn, TER terResult); // // Monitoring: subscriber side diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index df8a0c7082..b8b32e6f60 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -35,12 +35,12 @@ std::size_t hash_value(const aciSource& asValue) return seed; } -bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std::string& strHuman) +bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman) { static struct { - TransactionEngineResult terCode; - const char* cpToken; - const char* cpHuman; + TER terCode; + const char* cpToken; + const char* cpHuman; } transResultInfoA[] = { { tefALREADY, "tefALREADY", "The exact transaction was already in this ledger" }, { tefBAD_ADD_AUTH, "tefBAD_ADD_AUTH", "Not authorized to add account." }, @@ -430,10 +430,10 @@ STAmount TransactionEngine::accountSend(const uint160& uSenderID, const uint160& return saActualCost; } -TransactionEngineResult TransactionEngine::offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID) +TER TransactionEngine::offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID) { - uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode); - TransactionEngineResult terResult = dirDelete(false, uOwnerNode, Ledger::getOwnerDirIndex(uOwnerID), uOfferIndex, false); + uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode); + TER terResult = dirDelete(false, uOwnerNode, Ledger::getOwnerDirIndex(uOwnerID), uOfferIndex, false); if (tesSUCCESS == terResult) { @@ -448,7 +448,7 @@ TransactionEngineResult TransactionEngine::offerDelete(const SLE::pointer& sleOf return terResult; } -TransactionEngineResult TransactionEngine::offerDelete(const uint256& uOfferIndex) +TER TransactionEngine::offerDelete(const uint256& uOfferIndex) { SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); const uint160 uOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); @@ -461,7 +461,7 @@ TransactionEngineResult TransactionEngine::offerDelete(const uint256& uOfferInde // --> uLedgerIndex: Value to add to directory. // We only append. This allow for things that watch append only structure to just monitor from the last node on ward. // Within a node with no deletions order of elements is sequential. Otherwise, order of elements is random. -TransactionEngineResult TransactionEngine::dirAdd( +TER TransactionEngine::dirAdd( uint64& uNodeDir, const uint256& uRootIndex, const uint256& uLedgerIndex) @@ -550,7 +550,7 @@ TransactionEngineResult TransactionEngine::dirAdd( } // Ledger must be in a state for this to work. -TransactionEngineResult TransactionEngine::dirDelete( +TER TransactionEngine::dirDelete( const bool bKeepRoot, // --> True, if we never completely clean up, after we overflow the root node. const uint64& uNodeDir, // --> Node containing entry. const uint256& uRootIndex, // --> The index of the base of the directory. Nodes are based off of this. @@ -778,7 +778,7 @@ bool TransactionEngine::dirNext( } // Set the authorized public key for an account. May also set the generator map. -TransactionEngineResult TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator) +TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator) { // // Verify that submitter knows the private key for the generator. @@ -918,7 +918,7 @@ void TransactionEngine::txnWrite() } } -TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTransaction& txn, +TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, TransactionEngineParams params) { Log(lsTRACE) << "applyTransaction>"; @@ -944,9 +944,8 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran } #endif - TransactionEngineResult terResult = tesSUCCESS; - - uint256 txID = txn.getTransactionID(); + TER terResult = tesSUCCESS; + uint256 txID = txn.getTransactionID(); if (!txID) { Log(lsWARNING) << "applyTransaction: invalid transaction id"; @@ -1329,7 +1328,7 @@ TransactionEngineResult TransactionEngine::applyTransaction(const SerializedTran return terResult; } -TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransaction& txn) +TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { Log(lsINFO) << "doAccountSet>"; @@ -1475,24 +1474,24 @@ TransactionEngineResult TransactionEngine::doAccountSet(const SerializedTransact return tesSUCCESS; } -TransactionEngineResult TransactionEngine::doClaim(const SerializedTransaction& txn) +TER TransactionEngine::doClaim(const SerializedTransaction& txn) { Log(lsINFO) << "doClaim>"; - TransactionEngineResult terResult = setAuthorized(txn, true); + TER terResult = setAuthorized(txn, true); Log(lsINFO) << "doClaim<"; return terResult; } -TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransaction& txn) +TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) { - TransactionEngineResult terResult = tesSUCCESS; + TER terResult = tesSUCCESS; Log(lsINFO) << "doCreditSet>"; // Check if destination makes sense. - uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); + uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); if (!uDstAccountID) { @@ -1626,7 +1625,7 @@ TransactionEngineResult TransactionEngine::doCreditSet(const SerializedTransacti return terResult; } -TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransaction& txn) +TER TransactionEngine::doNicknameSet(const SerializedTransaction& txn) { std::cerr << "doNicknameSet>" << std::endl; @@ -1672,7 +1671,7 @@ TransactionEngineResult TransactionEngine::doNicknameSet(const SerializedTransac return tesSUCCESS; } -TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransaction& txn) +TER TransactionEngine::doPasswordFund(const SerializedTransaction& txn) { std::cerr << "doPasswordFund>" << std::endl; @@ -1706,7 +1705,7 @@ TransactionEngineResult TransactionEngine::doPasswordFund(const SerializedTransa return tesSUCCESS; } -TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransaction& txn) +TER TransactionEngine::doPasswordSet(const SerializedTransaction& txn) { std::cerr << "doPasswordSet>" << std::endl; @@ -1719,7 +1718,7 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac mTxnAccount->setFlag(lsfPasswordSpent); - TransactionEngineResult terResult = setAuthorized(txn, false); + TER terResult = setAuthorized(txn, false); std::cerr << "doPasswordSet<" << std::endl; @@ -1739,9 +1738,9 @@ TransactionEngineResult TransactionEngine::doPasswordSet(const SerializedTransac // <-- terResult : tesSUCCESS = no error and if !bAllowPartial complelely satisfied wanted. // <-> usOffersDeleteAlways: // <-> usOffersDeleteOnSuccess: -TransactionEngineResult calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bool bAllowPartial) +TER calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bool bAllowPartial) { - TransactionEngineResult terResult; + TER terResult; if (pnDst.saWanted.isNative()) { @@ -1897,13 +1896,12 @@ void TransactionEngine::calcOfferBridgeNext( } #endif -// <-- bSuccess: false= no transfer -bool TransactionEngine::calcNodeOfferRev( +TER TransactionEngine::calcNodeOfferRev( const unsigned int uIndex, // 0 < uIndex < uLast const PathState::pointer& pspCur, const bool bMultiQuality) { - bool bSuccess = false; + TER terResult = tepPATH_DRY; paymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; paymentNode& pnCur = pspCur->vpnNodes[uIndex]; @@ -1964,65 +1962,77 @@ bool TransactionEngine::calcNodeOfferRev( SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); const STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio unsigned int uEntry = 0; - uint256 uCurIndex; + uint256 uOfferIndex; while (saCurDlvReq != saCurDlvAct // Have not met request. - && dirNext(uDirectTip, sleDirectDir, uEntry, uCurIndex)) + && dirNext(uDirectTip, sleDirectDir, uEntry, uOfferIndex)) { - Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uCurIndex=%s") % uCurIndex.ToString()); + Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uOfferIndex=%s") % uOfferIndex.ToString()); - SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex); + SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - if (sleCurOfr->getIFieldPresent(sfExpiration) && sleCurOfr->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) { // Offer is expired. Log(lsINFO) << "calcNodeOfferRev: encountered expired offer"; - musUnfundedFound.insert(uCurIndex); // Mark offer for always deletion. + musUnfundedFound.insert(uOfferIndex); // Mark offer for always deletion. continue; } - const uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); - const aciSource asLine = boost::make_tuple(uCurOfrAccountID, uCurCurrencyID, uCurIssuerID); + const uint160 uCurOfrAccountID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + const aciSource asLine = boost::make_tuple(uCurOfrAccountID, uCurCurrencyID, uCurIssuerID); // Allowed to access source from this node? - curIssuerNodeConstIterator it = pspCur->umReverse.find(asLine); + curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine); + bool bFoundForward = itAllow != pspCur->umForward.end(); - if (it == pspCur->umReverse.end()) + if (bFoundForward || itAllow->second != uIndex) { - // Temporarily unfunded. ignore in this column. + // Temporarily unfunded. Another node uses this source, ignore in this node. nothing(); continue; } - const STAmount& saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); - // UNUSED? const STAmount& saCurOfrIn = sleCurOfr->getIValueFieldAmount(sfTakerPays); + const STAmount& saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets); + // UNUSED? const STAmount& saCurOfrIn = sleOffer->getIValueFieldAmount(sfTakerPays); - STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. + STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. + + curIssuerNodeConstIterator itSourcePast = mumSource.find(asLine); + bool bFoundPast = itSourcePast != mumSource.end(); if (!saCurOfrFunds) { // Offer is unfunded. Log(lsINFO) << "calcNodeOfferRev: encountered unfunded offer"; - curIssuerNodeConstIterator itSource = mumSource.find(asLine); - if (itSource == mumSource.end()) + curIssuerNodeConstIterator itSourceCur = bFoundPast + ? pspCur->umReverse.end() + : pspCur->umReverse.find(asLine); + bool bFoundReverse = itSourceCur != pspCur->umReverse.end(); + + if (!bFoundReverse && !bFoundPast) { // Never mentioned before: found unfunded. - musUnfundedFound.insert(uCurIndex); // Mark offer for always deletion. + musUnfundedFound.insert(uOfferIndex); // Mark offer for always deletion. } else { // Mentioned before: source became unfunded. - pspCur->vUnfundedBecame.push_back(uCurIndex); // Mark offer for deletion on use. + pspCur->vUnfundedBecame.push_back(uOfferIndex); // Mark offer for deletion on use of current path state. } continue; } + bool bMentioned = false; + if (!!uNxtAccountID) { // Next is an account. + // Next is redeeming it's own IOUs - no quality. + // Offer is paying out IOUs via offer - no quality. STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtAccountID == uCurIssuerID ? saOne @@ -2042,6 +2052,9 @@ bool TransactionEngine::calcNodeOfferRev( saCurDlvAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saInDlvAct; // Portion needed in previous. + + if (!bMentioned) + bMentioned = true; } else { @@ -2067,6 +2080,9 @@ bool TransactionEngine::calcNodeOfferRev( { // Do a directory. // - Drive on computing saCurDlvAct to derive saPrvDlvAct. + // Although the fee varies based upon the next offer it does not matter as the offer maker knows in + // advance that they are obligated to pay a transfer fee of necessary. The owner of next offer has no + // expectation of a quality in being applied. SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); // ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip), uCurCurrencyID); // For correct ratio unsigned int uEntry = 0; @@ -2080,6 +2096,24 @@ bool TransactionEngine::calcNodeOfferRev( uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); const STAmount& saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); + const aciSource asLineNxt = boost::make_tuple(uNxtOfrAccountID, uNxtCurrencyID, uNxtIssuerID); + + // Allowed to access source from this node? + curIssuerNodeConstIterator itAllowNxt = pspCur->umForward.find(asLineNxt); + curIssuerNodeConstIterator itNxt = itAllowNxt == pspCur->umForward.end() + ? mumSource.find(asLine) + : itAllowNxt; + + assert(itNxt != mumSource.end()); + + if (uIndex+1 != itNxt->second) + { + // Temporarily unfunded. Another node uses this source, ignore in this node. + + nothing(); + continue; + } + STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID ? saOne : saTransferRate; @@ -2100,6 +2134,8 @@ bool TransactionEngine::calcNodeOfferRev( saCurDlvAct += saOutDlvAct; // Portion of driver served. saPrvDlvAct += saInDlvAct; // Portion needed in previous. + if (!bMentioned) + bMentioned = true; } } @@ -2108,6 +2144,14 @@ bool TransactionEngine::calcNodeOfferRev( uNxtTip = 0; } } + + if (bMentioned // Need to remember reverse mention. + && !bFoundPast // Not mentioned in previous passes. + && !bFoundForward) // Not mentioned for pass. + { + // Consider source mentioned by current path state. + pspCur->umReverse.insert(std::make_pair(asLine, uIndex)); + } } } @@ -2119,24 +2163,24 @@ bool TransactionEngine::calcNodeOfferRev( if (saPrvDlvAct) { saPrvDlvReq = saPrvDlvAct; // Adjust request. - bSuccess = true; + terResult = tesSUCCESS; } - Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev< uIndex=%d saPrvDlvReq=%s bSuccess=%d") + Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev< uIndex=%d saPrvDlvReq=%s terResult=%d") % uIndex % saPrvDlvReq.getFullText() - % bSuccess); + % terResult); - return bSuccess; + return terResult; } -bool TransactionEngine::calcNodeOfferFwd( +TER TransactionEngine::calcNodeOfferFwd( const unsigned int uIndex, // 0 < uIndex < uLast const PathState::pointer& pspCur, const bool bMultiQuality ) { - bool bSuccess = false; + TER terResult = tepPATH_DRY; paymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; paymentNode& pnCur = pspCur->vpnNodes[uIndex]; @@ -2330,10 +2374,10 @@ bool TransactionEngine::calcNodeOfferFwd( if (saCurDlvAct) { saCurDlvReq = saCurDlvAct; // Adjust request. - bSuccess = true; + terResult = tesSUCCESS; } - return bSuccess; + return terResult; } #if 0 @@ -2370,7 +2414,7 @@ void TransactionEngine::calcNodeOffer( STAmount& saGot ) const { - TransactionEngineResult terResult = temUNKNOWN; + TER terResult = temUNKNOWN; // Direct: not bridging via XNS bool bDirectNext = true; // True, if need to load. @@ -2652,9 +2696,10 @@ Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCur } // Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver; -bool TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) +// <-- tesSUCCESS or tepPATH_DRY +TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) { - bool bSuccess = true; + TER terResult = tesSUCCESS; const unsigned int uLast = pspCur->vpnNodes.size() - 1; paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; @@ -2772,8 +2817,7 @@ bool TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const Path if (!saCurWantedAct) { // Must have processed something. - // terResult = temBAD_AMOUNT; - bSuccess = false; + terResult = tepPATH_DRY; } } else @@ -2833,8 +2877,7 @@ bool TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const Path if (!saCurRedeemAct && !saCurIssueAct) { // Must want something. - // terResult = temBAD_AMOUNT; - bSuccess = false; + terResult = tepPATH_DRY; } Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurRedeemReq=%s saCurIssueReq=%s saPrvOwed=%s saCurRedeemAct=%s saCurIssueAct=%s") @@ -2879,8 +2922,7 @@ bool TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const Path if (!saCurDeliverAct) { // Must want something. - // terResult = temBAD_AMOUNT; - bSuccess = false; + terResult = tepPATH_DRY; } Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurDeliverReq=%s saCurDeliverAct=%s saPrvOwed=%s") @@ -2911,8 +2953,7 @@ bool TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const Path if (!saCurWantedAct) { // Must have processed something. - // terResult = temBAD_AMOUNT; - bSuccess = false; + terResult = tepPATH_DRY; } } else @@ -2949,8 +2990,7 @@ bool TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const Path if (!saPrvDeliverAct) { // Must want something. - // terResult = temBAD_AMOUNT; - bSuccess = false; + terResult = tepPATH_DRY; } } } @@ -2970,13 +3010,11 @@ bool TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const Path if (!saCurDeliverAct) { // Must want something. - // terResult = temBAD_AMOUNT; - bSuccess = false; + terResult = tepPATH_DRY; } } - // XXX Need a more nuanced return: temporary fail vs perm? - return bSuccess; + return terResult; } // The previous node: specifies what to push through to current. @@ -2984,12 +3022,12 @@ bool TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const Path // The current node: specify what to push through to next. // - Output to next node minus fees. // Perform balance adjustment with previous. -bool TransactionEngine::calcNodeAccountFwd( +TER TransactionEngine::calcNodeAccountFwd( const unsigned int uIndex, // 0 <= uIndex <= uLast const PathState::pointer& pspCur, const bool bMultiQuality) { - bool bSuccess = true; + TER terResult = tesSUCCESS; const unsigned int uLast = pspCur->vpnNodes.size() - 1; paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; @@ -3250,7 +3288,7 @@ bool TransactionEngine::calcNodeAccountFwd( // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. } - return bSuccess; + return terResult; } // Return true, iff lhs has less priority than rhs. @@ -3640,43 +3678,42 @@ Json::Value PathState::getJson() const // Calculate a node and its previous nodes. // From the destination work in reverse towards the source calculating how much must be asked for. // Then work forward, figuring out how much can actually be delivered. -// --> bAllowPartial: If false, fail if can't meet requirements. -// <-- bValid: true=success, false=insufficient funds / liqudity. +// <-- terResult: tesSUCCESS or tepPATH_DRY // <-> pnNodes: // --> [end]saWanted.mAmount // --> [all]saWanted.mCurrency // --> [all]saAccount // <-> [0]saWanted.mAmount : --> limit, <-- actual -bool TransactionEngine::calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) +TER TransactionEngine::calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) { - const paymentNode& pnCur = pspCur->vpnNodes[uIndex]; - const bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount); - bool bValid; + const paymentNode& pnCur = pspCur->vpnNodes[uIndex]; + const bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount); + TER terResult; Log(lsINFO) << boost::str(boost::format("calcNode> uIndex=%d") % uIndex); // Do current node reverse. - bValid = bCurAccount + terResult = bCurAccount ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); // Do previous. - if (bValid && uIndex) + if (tesSUCCESS == terResult && uIndex) { - bValid = calcNode(uIndex-1, pspCur, bMultiQuality); + terResult = calcNode(uIndex-1, pspCur, bMultiQuality); } // Do current node forward. - if (bValid) + if (tesSUCCESS == terResult) { - bValid = bCurAccount + terResult = bCurAccount ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); } - Log(lsINFO) << boost::str(boost::format("calcNode< uIndex=%d bValid=%d") % uIndex % bValid); + Log(lsINFO) << boost::str(boost::format("calcNode< uIndex=%d terResult=%d") % uIndex % terResult); - return bValid; + return terResult; } // Calculate the next increment of a path. @@ -3711,7 +3748,7 @@ void TransactionEngine::pathNext(const PathState::pointer& pspCur, const int iPa } // XXX Need to audit for things like setting accountID not having memory. -TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction& txn) +TER TransactionEngine::doPayment(const SerializedTransaction& txn) { // Ripple if source or destination is non-native or if there are paths. const uint32 uTxFlags = txn.getFlags(); @@ -3876,10 +3913,10 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction vpsPaths.push_back(pspExpanded); } - TransactionEngineResult terResult; - STAmount saPaid; - STAmount saWanted; - LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. + TER terResult; + STAmount saPaid; + STAmount saWanted; + LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. terResult = temUNCERTAIN; while (temUNCERTAIN == terResult) @@ -3976,7 +4013,7 @@ TransactionEngineResult TransactionEngine::doPayment(const SerializedTransaction return terResult; } -TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransaction& txn) +TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn) { std::cerr << "WalletAdd>" << std::endl; @@ -4032,7 +4069,7 @@ TransactionEngineResult TransactionEngine::doWalletAdd(const SerializedTransacti return tesSUCCESS; } -TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction& txn) +TER TransactionEngine::doInvoice(const SerializedTransaction& txn) { return temUNKNOWN; } @@ -4045,7 +4082,7 @@ TransactionEngineResult TransactionEngine::doInvoice(const SerializedTransaction // <-- saTakerGot: What taker got not including fees. To reduce an offer. // <-- terResult: tesSUCCESS or terNO_ACCOUNT // XXX: Fees should be paid by the source of the currency. -TransactionEngineResult TransactionEngine::takeOffers( +TER TransactionEngine::takeOffers( bool bPassive, const uint256& uBookBase, const uint160& uTakerAccountID, @@ -4066,7 +4103,7 @@ TransactionEngineResult TransactionEngine::takeOffers( const uint160 uTakerPaysCurrency = saTakerPays.getCurrency(); const uint160 uTakerGetsAccountID = saTakerGets.getIssuer(); const uint160 uTakerGetsCurrency = saTakerGets.getCurrency(); - TransactionEngineResult terResult = temUNCERTAIN; + TER terResult = temUNCERTAIN; boost::unordered_set usOfferUnfundedFound; // Offers found unfunded. boost::unordered_set usOfferUnfundedBecame; // Offers that became unfunded. @@ -4270,7 +4307,7 @@ TransactionEngineResult TransactionEngine::takeOffers( return terResult; } -TransactionEngineResult TransactionEngine::doOfferCreate(const SerializedTransaction& txn) +TER TransactionEngine::doOfferCreate(const SerializedTransaction& txn) { Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); const uint32 txFlags = txn.getFlags(); @@ -4294,7 +4331,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); const uint160 uGetsCurrency = saTakerGets.getCurrency(); const uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays); - TransactionEngineResult terResult = tesSUCCESS; + TER terResult = tesSUCCESS; uint256 uDirectory; // Delete hints. uint64 uOwnerNode; uint64 uBookNode; @@ -4457,12 +4494,12 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); return terResult; } -TransactionEngineResult TransactionEngine::doOfferCancel(const SerializedTransaction& txn) +TER TransactionEngine::doOfferCancel(const SerializedTransaction& txn) { - TransactionEngineResult terResult; - const uint32 uSequence = txn.getITFieldU32(sfOfferSequence); - const uint256 uOfferIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); - SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); + TER terResult; + const uint32 uSequence = txn.getITFieldU32(sfOfferSequence); + const uint256 uOfferIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); + SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); if (sleOffer) { @@ -4483,17 +4520,17 @@ TransactionEngineResult TransactionEngine::doOfferCancel(const SerializedTransac return terResult; } -TransactionEngineResult TransactionEngine::doTake(const SerializedTransaction& txn) +TER TransactionEngine::doTake(const SerializedTransaction& txn) { return temUNKNOWN; } -TransactionEngineResult TransactionEngine::doStore(const SerializedTransaction& txn) +TER TransactionEngine::doStore(const SerializedTransaction& txn) { return temUNKNOWN; } -TransactionEngineResult TransactionEngine::doDelete(const SerializedTransaction& txn) +TER TransactionEngine::doDelete(const SerializedTransaction& txn) { return temUNKNOWN; } diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 5a88c1775c..4ae85c94f5 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -2,6 +2,7 @@ #define __TRANSACTIONENGINE__ #include +#include #include #include @@ -13,7 +14,7 @@ // A TransactionEngine applies serialized transactions to a ledger // It can also, verify signatures, verify fees, and give rejection reasons -enum TransactionEngineResult +enum TER // aka TransactionEngineResult { // Note: Range is stable. Exact numbers are currently unstable. Use tokens. @@ -84,7 +85,7 @@ enum TransactionEngineResult tepPATH_PARTIAL, }; -bool transResultInfo(TransactionEngineResult terCode, std::string& strToken, std::string& strHuman); +bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman); enum TransactionEngineParams { @@ -122,6 +123,7 @@ typedef boost::unordered_map curIssuerNode; // Map typedef boost::unordered_map::const_iterator curIssuerNodeConstIterator; extern std::size_t hash_value(const aciSource& asValue); +// extern std::size_t hash_value(const boost::tuple& bt); // Hold a path state under incremental application. class PathState @@ -198,12 +200,12 @@ class TransactionEngine private: LedgerEntrySet mNodes; - TransactionEngineResult dirAdd( + TER dirAdd( uint64& uNodeDir, // Node of entry. const uint256& uRootIndex, const uint256& uLedgerIndex); - TransactionEngineResult dirDelete( + TER dirDelete( const bool bKeepRoot, const uint64& uNodeDir, // Node item is mentioned in. const uint256& uRootIndex, @@ -213,9 +215,9 @@ private: 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); - TransactionEngineResult setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator); + TER setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator); - TransactionEngineResult takeOffers( + TER takeOffers( bool bPassive, const uint256& uBookBase, const uint160& uTakerAccountID, @@ -246,8 +248,8 @@ protected: void entryDelete(SLE::pointer sleEntry, bool bUnfunded = false); void entryModify(SLE::pointer sleEntry); - TransactionEngineResult offerDelete(const uint256& uOfferIndex); - TransactionEngineResult offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID); + 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); @@ -267,31 +269,31 @@ protected: PathState::pointer pathCreate(const STPath& spPath); void pathNext(const PathState::pointer& pspCur, const int iPaths); - bool calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); - bool calcNodeOfferRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); - bool calcNodeOfferFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); - bool calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); - bool calcNodeAccountFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality); + TER calcNode(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); void calcNodeRipple(const uint32 uQualityIn, const uint32 uQualityOut, const STAmount& saPrvReq, const STAmount& saCurReq, STAmount& saPrvAct, STAmount& saCurAct); void txnWrite(); - TransactionEngineResult doAccountSet(const SerializedTransaction& txn); - TransactionEngineResult doClaim(const SerializedTransaction& txn); - TransactionEngineResult doCreditSet(const SerializedTransaction& txn); - TransactionEngineResult doDelete(const SerializedTransaction& txn); - TransactionEngineResult doInvoice(const SerializedTransaction& txn); - TransactionEngineResult doOfferCreate(const SerializedTransaction& txn); - TransactionEngineResult doOfferCancel(const SerializedTransaction& txn); - TransactionEngineResult doNicknameSet(const SerializedTransaction& txn); - TransactionEngineResult doPasswordFund(const SerializedTransaction& txn); - TransactionEngineResult doPasswordSet(const SerializedTransaction& txn); - TransactionEngineResult doPayment(const SerializedTransaction& txn); - TransactionEngineResult doStore(const SerializedTransaction& txn); - TransactionEngineResult doTake(const SerializedTransaction& txn); - TransactionEngineResult doWalletAdd(const SerializedTransaction& txn); + TER doAccountSet(const SerializedTransaction& txn); + TER doClaim(const SerializedTransaction& txn); + TER doCreditSet(const SerializedTransaction& txn); + TER doDelete(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 doStore(const SerializedTransaction& txn); + TER doTake(const SerializedTransaction& txn); + TER doWalletAdd(const SerializedTransaction& txn); public: TransactionEngine() { ; } @@ -300,7 +302,7 @@ public: Ledger::pointer getLedger() { return mLedger; } void setLedger(const Ledger::pointer& ledger) { assert(ledger); mLedger = ledger; } - TransactionEngineResult applyTransaction(const SerializedTransaction&, TransactionEngineParams); + TER applyTransaction(const SerializedTransaction&, TransactionEngineParams); }; inline TransactionEngineParams operator|(const TransactionEngineParams& l1, const TransactionEngineParams& l2) From 7967b4ec11ecf446b09bf079dc21b61fd9bbb99f Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 29 Aug 2012 12:38:24 -0700 Subject: [PATCH 133/426] Improve error handling for transaction engine path creation. --- src/TransactionEngine.cpp | 128 +++++++++++++++++++++++++------------- src/TransactionEngine.h | 24 +++---- 2 files changed, 98 insertions(+), 54 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index b8b32e6f60..5917c2a59d 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -49,6 +49,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman) { tefBAD_GEN_AUTH, "tefBAD_GEN_AUTH", "Not authorized to claim generator." }, { tefBAD_LEDGER, "tefBAD_LEDGER", "Ledger in unexpected state." }, { tefCLAIMED, "tefCLAIMED", "Can not claim a previously claimed account." }, + { tefEXCEPTION, "tefEXCEPTION", "Unexpected program state." }, { tefCREATED, "tefCREATED", "Can't add an already created account." }, { tefGEN_IN_USE, "tefGEN_IN_USE", "Generator already in use." }, { tefPAST_SEQ, "tefPAST_SEQ", "This sequence number has already past" }, @@ -61,6 +62,8 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman) { temBAD_EXPIRATION, "temBAD_EXPIRATION", "Malformed." }, { temBAD_ISSUER, "temBAD_ISSUER", "Malformed." }, { temBAD_OFFER, "temBAD_OFFER", "Malformed." }, + { temBAD_PATH, "temBAD_PATH", "Malformed." }, + { temBAD_PATH_LOOP, "temBAD_PATH_LOOP", "Malformed." }, { temBAD_PUBLISH, "temBAD_PUBLISH", "Malformed: bad publish." }, { temBAD_SET_ID, "temBAD_SET_ID", "Malformed." }, { temCREATEXNS, "temCREATEXNS", "Can not specify non XNS for Create." }, @@ -81,6 +84,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman) { terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee." }, { terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist." }, { terNO_DST, "terNO_DST", "The destination does not exist" }, + { terNO_LINE, "terNO_LINE", "No such line." }, { terNO_LINE_NO_ZERO, "terNO_LINE_NO_ZERO", "Can't zero non-existant line, destination might make it." }, { terOFFER_NOT_FOUND, "terOFFER_NOT_FOUND", "Can not cancel offer." }, { terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction" }, @@ -3312,10 +3316,10 @@ bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::poi // - A node names it's output. // - A ripple nodes output issuer must be the node's account or the next node's account. // - Offers can only go directly to another offer if the currency and issuer are an exact match. -bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) +TER PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) { - const paymentNode& pnPrv = vpnNodes.back(); - bool bValid = true; + const paymentNode& pnPrv = vpnNodes.back(); + TER terResult = tesSUCCESS; Log(lsINFO) << "pushImply> " << NewcoinAddress::createHumanAccountID(uAccountID) @@ -3326,7 +3330,7 @@ bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssu { // Need to convert via an offer. - bValid = pushNode( + terResult = pushNode( STPathElement::typeCurrency // Offer. | STPathElement::typeIssuer, ACCOUNT_ONE, // Placeholder for offers. @@ -3335,14 +3339,14 @@ bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssu } - if (bValid + if (tesSUCCESS == terResult && !!uCurrencyID // Not stamps. && (pnPrv.uAccountID != uIssuerID // Previous is not issuing own IOUs. && uAccountID != uIssuerID)) // Current is not receiving own IOUs. { // Need to ripple through uIssuerID's account. - bValid = pushNode( + terResult = pushNode( STPathElement::typeAccount | STPathElement::typeRedeem | STPathElement::typeIssue, @@ -3351,15 +3355,14 @@ bool PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssu uIssuerID); } - Log(lsINFO) << "pushImply< " << bValid; + Log(lsINFO) << "pushImply< " << terResult; - return bValid; + return terResult; } // Append a node and insert before it any implied nodes. -// <-- bValid: true, if node is valid. false, if node is malformed or missing credit link. -// XXX Report missinge credit link distinct from malformed for retry. -bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) +// <-- terResult: tesSUCCESS, temBAD_PATH, terNO_LINE +TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) { Log(lsINFO) << "pushNode> " << NewcoinAddress::createHumanAccountID(uAccountID) @@ -3378,7 +3381,7 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin // true, iff account is allowed to redeem it's IOUs to next node. const bool bRedeem = !!(iType & STPathElement::typeRedeem); const bool bIssue = !!(iType & STPathElement::typeIssue); - bool bValid = true; + TER terResult = tesSUCCESS; pnCur.uFlags = iType; @@ -3386,7 +3389,7 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin { Log(lsINFO) << "pushNode: bad bits."; - bValid = false; + terResult = temBAD_PATH; } else if (bAccount) { @@ -3403,13 +3406,13 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin if (!bFirst) { // Add required intermediate nodes to deliver to current account. - bValid = pushImply( + terResult = pushImply( pnCur.uAccountID, // Current account. pnCur.uCurrencyID, // Wanted currency. !!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as issuer. } - if (bValid && !vpnNodes.empty()) + if (tesSUCCESS == terResult && !vpnNodes.empty()) { const paymentNode& pnBck = vpnNodes.back(); bool bBckAccount = !!(pnBck.uFlags & STPathElement::typeAccount); @@ -3428,7 +3431,7 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin << STAmount::createHumanCurrency(pnPrv.uCurrencyID) << "." ; - bValid = false; + terResult = terNO_LINE; } else { @@ -3443,14 +3446,14 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin } } - if (bValid) + if (tesSUCCESS == terResult) vpnNodes.push_back(pnCur); } else { Log(lsINFO) << "pushNode: Account must redeem and/or issue."; - bValid = false; + terResult = temBAD_PATH; } } else @@ -3458,7 +3461,7 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin // Offer link if (bRedeem || bIssue) { - bValid = false; + terResult = temBAD_PATH; } else { @@ -3471,7 +3474,7 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin // Previous is an account. // Insert intermediary account if needed. - bValid = pushImply( + terResult = pushImply( !!pnPrv.uCurrencyID ? ACCOUNT_ONE : ACCOUNT_XNS, pnPrv.uCurrencyID, pnPrv.uIssuerID); @@ -3483,7 +3486,7 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin nothing(); } - if (bValid) + if (tesSUCCESS == terResult) { // Verify that previous account is allowed to issue. const paymentNode& pnBck = vpnNodes.back(); @@ -3494,17 +3497,17 @@ bool PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uin { Log(lsINFO) << "pushNode: previous account must be allowed to issue."; - bValid = false; // Malformed path. + terResult = temBAD_PATH; } } - if (bValid) + if (tesSUCCESS == terResult) vpnNodes.push_back(pnCur); } } - Log(lsINFO) << "pushNode< " << bValid; + Log(lsINFO) << "pushNode< " << terResult; - return bValid; + return terResult; } PathState::PathState( @@ -3531,7 +3534,7 @@ PathState::PathState( saOutReq = saSend; // Push sending node. - bValid = pushNode( + terStatus = pushNode( STPathElement::typeAccount | STPathElement::typeRedeem | STPathElement::typeIssue @@ -3543,18 +3546,18 @@ PathState::PathState( BOOST_FOREACH(const STPathElement& speElement, spSourcePath) { - if (bValid) - bValid = pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID()); + if (tesSUCCESS == terStatus) + terStatus = pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID()); } - if (bValid) + if (tesSUCCESS == terStatus) { // Create receiver node. - bValid = pushImply(uReceiverID, uOutCurrencyID, uOutIssuerID); - if (bValid) + terStatus = pushImply(uReceiverID, uOutCurrencyID, uOutIssuerID); + if (tesSUCCESS == terStatus) { - bValid = pushNode( + terStatus = pushNode( STPathElement::typeAccount // Last node is always an account. | STPathElement::typeRedeem // Does not matter just pass error check. | STPathElement::typeIssue // Does not matter just pass error check. @@ -3566,14 +3569,14 @@ PathState::PathState( } } - if (bValid) + if (tesSUCCESS == terStatus) { // Look for first mention of source in nodes and detect loops. // Note: The output is not allowed to be a source. const unsigned int uNodes = vpnNodes.size(); - for (unsigned int uIndex = 0; bValid && uIndex != uNodes; ++uIndex) + for (unsigned int uIndex = 0; tesSUCCESS == terStatus && uIndex != uNodes; ++uIndex) { const paymentNode& pnCur = vpnNodes[uIndex]; @@ -3588,7 +3591,7 @@ PathState::PathState( Log(lsINFO) << boost::str(boost::format("PathState: loop detected: %s") % getJson()); - bValid = false; + terStatus = temBAD_PATH_LOOP; } } } @@ -3653,7 +3656,7 @@ Json::Value PathState::getJson() const jvNodes.append(jvNode); } - jvPathState["valid"] = bValid; + jvPathState["status"] = terStatus; jvPathState["index"] = mIndex; jvPathState["nodes"] = jvNodes; @@ -3733,14 +3736,14 @@ void TransactionEngine::pathNext(const PathState::pointer& pspCur, const int iPa pspCur->vUnfundedBecame.clear(); pspCur->umReverse.clear(); - pspCur->bValid = calcNode(uLast, pspCur, iPaths == 1); + pspCur->terStatus = calcNode(uLast, pspCur, iPaths == 1); - Log(lsINFO) << "pathNext: bValid=" - << pspCur->bValid + Log(lsINFO) << "pathNext: terStatus=" + << pspCur->terStatus << " saOutAct=" << pspCur->saOutAct.getText() << " saInAct=" << pspCur->saInAct.getText(); - pspCur->uQuality = pspCur->bValid + pspCur->uQuality = tesSUCCESS == pspCur->terStatus ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. : 0; // Mark path as inactive. @@ -3871,6 +3874,8 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) // Incrementally search paths. std::vector vpsPaths; + TER terResult = temUNCERTAIN; + if (!bNoRippleDirect) { // Direct path. @@ -3889,7 +3894,19 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) bPartialPayment); if (pspDirect) + { + // Return if malformed. + if (pspDirect->terStatus >= temMALFORMED && pspDirect->terStatus < tefFAILURE) + return pspDirect->terStatus; + + if (tesSUCCESS == pspDirect->terStatus) + { + // Had a success. + terResult = tesSUCCESS; + } + vpsPaths.push_back(pspDirect); + } } Log(lsINFO) << "doPayment: Paths: " << spsPaths.getPathCount(); @@ -3910,15 +3927,40 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) bPartialPayment); if (pspExpanded) + { + // Return if malformed. + if (pspExpanded->terStatus >= temMALFORMED && pspExpanded->terStatus < tefFAILURE) + return pspExpanded->terStatus; + + if (tesSUCCESS == pspExpanded->terStatus) + { + // Had a success. + terResult = tesSUCCESS; + } + vpsPaths.push_back(pspExpanded); + } + } + + if (vpsPaths.empty()) + { + return tefEXCEPTION; + } + else if (tesSUCCESS != terResult) + { + // No path successes. + + return vpsPaths[0]->terStatus; + } + else + { + terResult = temUNCERTAIN; } - TER terResult; STAmount saPaid; STAmount saWanted; - LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. + LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. - terResult = temUNCERTAIN; while (temUNCERTAIN == terResult) { PathState::pointer pspBest; diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 4ae85c94f5..4c84145800 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -33,6 +33,8 @@ enum TER // aka TransactionEngineResult temBAD_EXPIRATION, temBAD_ISSUER, temBAD_OFFER, + temBAD_PATH, + temBAD_PATH_LOOP, temBAD_PUBLISH, temBAD_SET_ID, temCREATEXNS, @@ -57,6 +59,7 @@ enum TER // aka TransactionEngineResult tefBAD_LEDGER, tefCLAIMED, tefCREATED, + tefEXCEPTION, tefGEN_IN_USE, tefPAST_SEQ, @@ -68,6 +71,7 @@ enum TER // aka TransactionEngineResult terINSUF_FEE_B, terNO_ACCOUNT, terNO_DST, + terNO_LINE, terNO_LINE_NO_ZERO, terOFFER_NOT_FOUND, // XXX If we check sequence first this could be hard failure. terPRE_SEQ, @@ -131,26 +135,26 @@ class PathState protected: Ledger::pointer mLedger; - bool pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID); - bool pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID); + TER pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID); + TER pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID); public: typedef boost::shared_ptr pointer; - bool bValid; - std::vector vpnNodes; + TER terStatus; + std::vector vpnNodes; // When processing, don't want to complicate directory walking with deletion. - std::vector vUnfundedBecame; // Offers that became unfunded. + std::vector vUnfundedBecame; // Offers that became unfunded. // First time working foward a funding source was mentioned for accounts. Source may only be used there. - curIssuerNode umForward; // Map of currency, issuer to node index. + 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. + curIssuerNode umReverse; // Map of currency, issuer to node index. - LedgerEntrySet lesEntries; + LedgerEntrySet lesEntries; int mIndex; uint64 uQuality; // 0 = none. @@ -185,9 +189,7 @@ public: const bool bPartialPayment ) { - PathState::pointer pspNew = boost::make_shared(lpLedger, iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax, bPartialPayment); - - return pspNew && pspNew->bValid ? pspNew : PathState::pointer(); + return boost::make_shared(lpLedger, iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax, bPartialPayment); } static bool lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs); From 5db8082608637e684bd73d26d08af2b6c5d394a7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 29 Aug 2012 14:39:43 -0700 Subject: [PATCH 134/426] Small bugfixes. --- src/LedgerConsensus.cpp | 4 ++-- src/LedgerTiming.cpp | 2 +- src/NetworkOPs.cpp | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 59b1d83f03..6d61f5216e 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -431,7 +431,7 @@ void LedgerConsensus::statePreClose() { // it is time to close the ledger Log(lsINFO) << "CLC: closing ledger"; mState = lcsESTABLISH; - mConsensusStartTime = boost::posix_time::second_clock::universal_time(); + mConsensusStartTime = boost::posix_time::microsec_clock::universal_time(); mCloseTime = theApp->getOPs().getCloseTimeNC(); theApp->getOPs().setLastCloseNetTime(mCloseTime); statusChange(newcoin::neCLOSING_LEDGER, *mPreviousLedger); @@ -492,7 +492,7 @@ void LedgerConsensus::timerEntry() } mCurrentMSeconds = (mCloseTime == 0) ? 0 : - (boost::posix_time::second_clock::universal_time() - mConsensusStartTime).total_milliseconds(); + (boost::posix_time::microsec_clock::universal_time() - mConsensusStartTime).total_milliseconds(); mClosePercent = mCurrentMSeconds * 100 / mPreviousMSeconds; switch (mState) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index 369e559a0c..ce737c2a63 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -33,7 +33,7 @@ int ContinuousLedgerTiming::shouldClose( { // no transactions so far this interval if (proposersClosed > (previousProposers / 4)) // did we miss a transaction? { - Log(lsTRACE) << "no transactions, many proposers: now (" << proposersClose << "closed, " + Log(lsTRACE) << "no transactions, many proposers: now (" << proposersClosed << "closed, " << previousProposers << " before)"; return currentMSeconds; } diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 2f7a4fca87..29531461bb 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -33,7 +33,7 @@ boost::posix_time::ptime NetworkOPs::getNetworkTimePT() { int offset = 0; theApp->getSystemTimeOffset(offset); - return boost::posix_time::second_clock::universal_time() + boost::posix_time::seconds(offset); + return boost::posix_time::microsec_clock::universal_time() + boost::posix_time::seconds(offset); } uint32 NetworkOPs::getNetworkTimeNC() @@ -634,6 +634,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint if ((!mConsensus) && (mMode == omFULL)) { uint256 networkClosed; + std::vector peerList = theApp->getConnectionPool().getPeerVector(); bool ledgerChange = checkLastClosedLedger(peerList, networkClosed); if (!ledgerChange) { From 774110eef9ddf65afcd538d3cca2d55576634996 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 29 Aug 2012 16:01:30 -0700 Subject: [PATCH 135/426] Fix a bug that could cause an idle ledger to spend insufficient time establishing a consensus. --- src/LedgerConsensus.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 432d619f26..08df045123 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -200,6 +200,8 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, const Ledger::point mCurrentMSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false) { mValSeed = theConfig.VALIDATION_SEED; + mConsensusStartTime = boost::posix_time::microsec_clock::universal_time(); + Log(lsDEBUG) << "Creating consensus object"; Log(lsTRACE) << "LCL:" << previousLedger->getHash().GetHex() <<", ct=" << closeTime; mPreviousProposers = theApp->getOPs().getPreviousProposers(); @@ -491,8 +493,8 @@ void LedgerConsensus::timerEntry() Log(lsINFO) << "Need consensus ledger " << mPrevLedgerHash.GetHex(); } - mCurrentMSeconds = (mCloseTime == 0) ? 0 : - (boost::posix_time::microsec_clock::universal_time() - mConsensusStartTime).total_milliseconds(); + mCurrentMSeconds = + (boost::posix_time::microsec_clock::universal_time() - mConsensusStartTime).total_milliseconds(); mClosePercent = mCurrentMSeconds * 100 / mPreviousMSeconds; switch (mState) From 6b144f874952f731dafe1e7c063f02432557f649 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 29 Aug 2012 17:33:37 -0700 Subject: [PATCH 136/426] Quick fix to the bug causing crashes. Will rethink shortly to make sure it's correct, but this should be adequate. --- src/NetworkOPs.cpp | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 509f6baa9e..eb0aedc5c6 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -615,21 +615,6 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint return false; NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey)); - LedgerProposal::pointer proposal = - boost::make_shared(mConsensus->getLCL(), proposeSeq, proposeHash, closeTime, naPeerPublic); - if (!proposal->checkSign(signature)) - { // Note that if the LCL is different, the signature check will fail - Log(lsWARNING) << "Ledger proposal fails signature check"; - return false; - } - - // Is this node on our UNL? - if (!theApp->getUNL().nodeInUNL(proposal->peekPublic())) - { - Log(lsINFO) << "Untrusted proposal: " << naPeerPublic.humanNodePublic() << " " << - proposal->getCurrentHash().GetHex(); - return true; - } if ((!mConsensus) && (mMode == omFULL)) { @@ -644,10 +629,26 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint } if (!mConsensus) { - Log(lsWARNING) << "Received proposal when full but not during consensus window"; + Log(lsINFO) << "Received proposal outside consensus window"; + return (mMode != omFULL); + } + + LedgerProposal::pointer proposal = + boost::make_shared(mConsensus->getLCL(), proposeSeq, proposeHash, closeTime, naPeerPublic); + if (!proposal->checkSign(signature)) + { // Note that if the LCL is different, the signature check will fail + Log(lsWARNING) << "Ledger proposal fails signature check"; return false; } + // Is this node on our UNL? + if (!theApp->getUNL().nodeInUNL(proposal->peekPublic())) + { + Log(lsINFO) << "Untrusted proposal: " << naPeerPublic.humanNodePublic() << " " << + proposal->getCurrentHash().GetHex(); + return true; + } + return mConsensus->peerPosition(proposal); } From 6282ad4a88080daa8378951f303b67716ec70dee Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 29 Aug 2012 23:02:06 -0700 Subject: [PATCH 137/426] Clean up the TransactionEngineParameter flags. Clarify the semantics for soft failure. Note that the code will not yet invoke a transaction with a retry flag, but the support is there for transcations to handle it. --- src/LedgerConsensus.cpp | 16 ++++++++-------- src/LedgerConsensus.h | 4 ++-- src/NetworkOPs.cpp | 2 +- src/TransactionEngine.cpp | 8 ++++---- src/TransactionEngine.h | 12 ++++++------ 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 08df045123..46cd2deb2e 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -799,9 +799,9 @@ void LedgerConsensus::Saccept(boost::shared_ptr This, SHAMap::p } void LedgerConsensus::applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn, - const Ledger::pointer& ledger, CanonicalTXSet& failedTransactions, bool final) + const Ledger::pointer& ledger, CanonicalTXSet& failedTransactions, bool openLedger) { - TransactionEngineParams parms = final ? (tepNO_CHECK_FEE | tepUPDATE_TOTAL | tepMETADATA) : tepNONE; + TransactionEngineParams parms = openLedger ? temOPEN_LEDGER : temFINAL; #ifndef TRUST_NETWORK try { @@ -832,9 +832,9 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, const Serializ } void LedgerConsensus::applyTransactions(const SHAMap::pointer& set, const Ledger::pointer& applyLedger, - const Ledger::pointer& checkLedger, CanonicalTXSet& failedTransactions, bool final) + const Ledger::pointer& checkLedger, CanonicalTXSet& failedTransactions, bool openLgr) { - TransactionEngineParams parms = final ? (tepNO_CHECK_FEE | tepUPDATE_TOTAL) : tepNONE; + TransactionEngineParams parms = openLgr ? temOPEN_LEDGER : temFINAL; TransactionEngine engine(applyLedger); for (SHAMapItem::pointer item = set->peekFirstItem(); !!item; item = set->peekNextItem(item->getTag())) @@ -848,7 +848,7 @@ void LedgerConsensus::applyTransactions(const SHAMap::pointer& set, const Ledger #endif SerializerIterator sit(item->peekSerializer()); SerializedTransaction::pointer txn = boost::make_shared(boost::ref(sit)); - applyTransaction(engine, txn, applyLedger, failedTransactions, final); + applyTransaction(engine, txn, applyLedger, failedTransactions, openLgr); #ifndef TRUST_NETWORK } catch (...) @@ -906,7 +906,7 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) newLCL->armDirty(); CanonicalTXSet failedTransactions(set->getHash()); - applyTransactions(set, newLCL, newLCL, failedTransactions, true); + applyTransactions(set, newLCL, newLCL, failedTransactions, false); newLCL->setClosed(); bool closeTimeCorrect = true; @@ -950,7 +950,7 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) Log(lsINFO) << "Test applying disputed transaction that did not get in"; SerializerIterator sit(it.second->peekTransaction()); SerializedTransaction::pointer txn = boost::make_shared(boost::ref(sit)); - applyTransaction(engine, txn, newOL, failedTransactions, false); + applyTransaction(engine, txn, newOL, failedTransactions, true); } catch (...) { @@ -961,7 +961,7 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) Log(lsINFO) << "Applying transactions from current ledger"; applyTransactions(theApp->getMasterLedger().getCurrentLedger()->peekTransactionMap(), newOL, newLCL, - failedTransactions, false); + failedTransactions, true); theApp->getMasterLedger().pushLedger(newLCL, newOL); mNewLedgerHash = newLCL->getHash(); mState = lcsACCEPTED; diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index e95ed6328a..362c621f6e 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -128,9 +128,9 @@ protected: void removePosition(LedgerProposal&, bool ours); void sendHaveTxSet(const uint256& set, bool direct); void applyTransactions(const SHAMap::pointer& transactionSet, const Ledger::pointer& targetLedger, - const Ledger::pointer& checkLedger, CanonicalTXSet& failedTransactions, bool final); + const Ledger::pointer& checkLedger, CanonicalTXSet& failedTransactions, bool openLgr); void applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn, - const Ledger::pointer& targetLedger, CanonicalTXSet& failedTransactions, bool final); + const Ledger::pointer& targetLedger, CanonicalTXSet& failedTransactions, bool openLgr); // manipulating our own position void statusChange(newcoin::NodeEvent, Ledger& ledger); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index eb0aedc5c6..58bd6290c1 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -84,7 +84,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, return trans; } - TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, tepNONE); + TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, temOPEN_LEDGER); if (r == tefFAILURE) throw Fault(IO_ERROR); if (r == terPRE_SEQ) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 9411512f3b..70f57303e8 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -973,7 +973,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, naSigningPubKey = NewcoinAddress::createAccountPublic(txn.peekSigningPubKey()); // Consistency: really signed. - if ((tesSUCCESS == terResult) && ((params & tepNO_CHECK_SIGN) == 0) && !txn.checkSign(naSigningPubKey)) + if ((tesSUCCESS == terResult) && ((params & temNO_CHECK_SIGN) == 0) && !txn.checkSign(naSigningPubKey)) { Log(lsWARNING) << "applyTransaction: Invalid transaction: bad signature"; @@ -1032,8 +1032,8 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, STAmount saPaid = txn.getTransactionFee(); - if (tesSUCCESS == terResult && (params & tepNO_CHECK_FEE) == tepNONE) - { + if (tesSUCCESS == terResult && (params & temOPEN_LEDGER) != temNONE) + { // Applying to open ledger, check fee if (!!saCost) { // XXX DO NOT CHECK ON CONSENSUS PASS @@ -1322,7 +1322,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, if (!mLedger->addTransaction(txID, s)) assert(false); - if ((params & tepUPDATE_TOTAL) != tepNONE) + if ((params & temOPEN_LEDGER) == temNONE) mLedger->destroyCoins(saPaid.getNValue()); } diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 4c84145800..c231e33b47 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -84,7 +84,7 @@ enum TER // aka TransactionEngineResult // 100 .. P Partial success (SR) (ripple transaction with no good paths, pay to non-existent account) // Transaction can be applied, can charge fee, forwarded, but does not achieve optimal result. - tepPARITAL = 100, + tepPARTIAL = 100, tepPATH_DRY, tepPATH_PARTIAL, }; @@ -93,11 +93,11 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman); enum TransactionEngineParams { - tepNONE = 0, - tepNO_CHECK_SIGN = 1, // Signature already checked - tepNO_CHECK_FEE = 2, // It was voted into a ledger anyway - tepUPDATE_TOTAL = 4, // Update the total coins - tepMETADATA = 5, // put metadata in tree, not transaction + temNONE = 0x00, + temNO_CHECK_SIGN = 0x01, // Signature already checked + temOPEN_LEDGER = 0x10, // Transaction is running against an open ledger + temRETRY_OK = 0x20, // It was voted into a ledger anyway + temFINAL = 0x40, // This may be the transaction's last pass }; typedef struct { From f63d9df60b96534beb082a25373e18fadee55bd0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 29 Aug 2012 23:38:35 -0700 Subject: [PATCH 138/426] Ledger idle timing fixes. --- src/Application.cpp | 2 +- src/LedgerConsensus.cpp | 21 ++++++++++++++++----- src/LedgerTiming.cpp | 5 +++-- src/LedgerTiming.h | 3 ++- src/NetworkOPs.h | 6 +++--- 5 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 2fe18c161f..45adfccf43 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -153,7 +153,7 @@ void Application::run() secondLedger->setAccepted(); mMasterLedger.pushLedger(secondLedger, boost::make_shared(true, boost::ref(*secondLedger))); assert(!!secondLedger->getAccountState(rootAddress)); - mNetOps.setLastCloseNetTime(secondLedger->getCloseTimeNC()); + mNetOps.setLastCloseTime(secondLedger->getCloseTimeNC()); } diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 46cd2deb2e..e3c49bb677 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -421,21 +421,32 @@ void LedgerConsensus::statePreClose() int proposersClosed = mPeerPositions.size(); // This ledger is open. This computes how long since the last ledger closed - int lastCloseTime; - if (!anyTransactions && mPreviousLedger->getCloseAgree()) + uint32 lastCloseTime; + int ledgerInterval = 0; + + if (mHaveCorrectLCL && mPreviousLedger->getCloseAgree()) + { // we can use consensus timing lastCloseTime = mPreviousLedger->getCloseTimeNC(); + ledgerInterval = 2 * mPreviousLedger->getCloseResolution(); + if (ledgerInterval < LEDGER_IDLE_INTERVAL) + ledgerInterval = LEDGER_IDLE_INTERVAL; + } else - lastCloseTime = theApp->getOPs().getLastCloseNetTime(); + { + lastCloseTime = theApp->getOPs().getLastCloseTime(); + ledgerInterval = LEDGER_IDLE_INTERVAL; + } + int sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - lastCloseTime); if (sinceClose >= ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed, - mPreviousMSeconds, sinceClose)) + mPreviousMSeconds, sinceClose, ledgerInterval)) { // it is time to close the ledger Log(lsINFO) << "CLC: closing ledger"; mState = lcsESTABLISH; mConsensusStartTime = boost::posix_time::microsec_clock::universal_time(); mCloseTime = theApp->getOPs().getCloseTimeNC(); - theApp->getOPs().setLastCloseNetTime(mCloseTime); + theApp->getOPs().setLastCloseTime(mCloseTime); statusChange(newcoin::neCLOSING_LEDGER, *mPreviousLedger); takeInitialPosition(*theApp->getMasterLedger().closeLedger()); } diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index ce737c2a63..f10acbaadd 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -17,7 +17,8 @@ int ContinuousLedgerTiming::shouldClose( int previousProposers, // proposers in the last closing int proposersClosed, // proposers who have currently closed this ledgers int previousMSeconds, // seconds the previous ledger took to reach consensus - int currentMSeconds) // seconds since the previous ledger closed + int currentMSeconds, // seconds since the previous ledger closed + int idleInterval) // network's desired idle interval { if ((previousMSeconds < -1000) || (previousMSeconds > 600000) || (currentMSeconds < -1000) || (currentMSeconds > 600000)) @@ -44,7 +45,7 @@ int ContinuousLedgerTiming::shouldClose( return previousMSeconds; return previousMSeconds - 1000; } - return LEDGER_IDLE_INTERVAL * 1000; // normal idle + return idleInterval * 1000; // normal idle } Log(lsTRACE) << "close now"; diff --git a/src/LedgerTiming.h b/src/LedgerTiming.h index eb8f2d56c8..bed4673319 100644 --- a/src/LedgerTiming.h +++ b/src/LedgerTiming.h @@ -49,7 +49,8 @@ public: static int shouldClose( bool anyTransactions, int previousProposers, int proposersClosed, - int previousSeconds, int currentSeconds); + int previousSeconds, int currentSeconds, + int idleInterval); static bool haveConsensus( int previousProposers, int currentProposers, diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 9b324edddc..e0a73052f4 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -63,7 +63,7 @@ protected: // last ledger close int mLastCloseProposers, mLastCloseConvergeTime; uint256 mLastCloseHash; - uint32 mLastCloseNetTime; + uint32 mLastCloseTime; // XXX Split into more locks. boost::interprocess::interprocess_upgradable_mutex mMonitorLock; @@ -179,8 +179,8 @@ public: void newLCL(int proposers, int convergeTime, const uint256& ledgerHash); int getPreviousProposers() { return mLastCloseProposers; } int getPreviousConvergeTime() { return mLastCloseConvergeTime; } - uint32 getLastCloseNetTime() { return mLastCloseNetTime; } - void setLastCloseNetTime(uint32 t) { mLastCloseNetTime = t; } + uint32 getLastCloseTime() { return mLastCloseTime; } + void setLastCloseTime(uint32 t) { mLastCloseTime = t; } Json::Value getServerInfo(); // client information retrieval functions From 1813e8365d4d49f25635cfd975a0b8fe5c18742d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 08:59:25 -0700 Subject: [PATCH 139/426] Fix crash on txn against non-existent account. --- src/TransactionEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 70f57303e8..2e755c975d 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1239,10 +1239,10 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, terResult = tefPAST_SEQ; } } - mTxnAccount->setIFieldU32(sfLastSignedSeq, mLedger->getLedgerSeq()); if (tesSUCCESS == terResult) { + mTxnAccount->setIFieldU32(sfLastSignedSeq, mLedger->getLedgerSeq()); entryModify(mTxnAccount); switch (txn.getTxnType()) From 56b1939f434a50d07763b4f3982d19521c418f6e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 09:19:05 -0700 Subject: [PATCH 140/426] Extra safety. --- src/TransactionEngine.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index c231e33b47..08481fcefa 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -299,7 +299,7 @@ protected: public: TransactionEngine() { ; } - TransactionEngine(const Ledger::pointer& ledger) : mLedger(ledger) { ; } + TransactionEngine(const Ledger::pointer& ledger) : mLedger(ledger) { assert(mLedger); } Ledger::pointer getLedger() { return mLedger; } void setLedger(const Ledger::pointer& ledger) { assert(ledger); mLedger = ledger; } From 727d2644a4c12e855007a316c358fb2a849fab03 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 09:19:14 -0700 Subject: [PATCH 141/426] We mishandle the cases where we already have the new consensus LCL. --- src/LedgerConsensus.cpp | 48 +++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index e3c49bb677..ff21a1d5ab 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -259,24 +259,40 @@ void LedgerConsensus::checkLCL() { // LCL change Log(lsWARNING) << "View of consensus changed during consensus (" << netLgrCount << ")"; mPrevLedgerHash = netLgr; - mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash); - std::vector peerList = theApp->getConnectionPool().getPeerVector(); - mHaveCorrectLCL = false; - mProposing = false; - mValidating = false; - bool found = false; - BOOST_FOREACH(Peer::pointer& peer, peerList) + + Ledger::pointer newLedger = theApp->getMasterLedger()->getLedgerByHash(netLgr); + if (newLedger) { - if (peer->hasLedger(mPrevLedgerHash)) - { - found = true; - mAcquiringLedger->peerHas(peer); - } + Log(lsINFO) << "Acquired the consensus ledger " << mPrevLedgerHash.GetHex(); + if (theApp->getMasterLedger().getClosedLedger()->getHash() != mPrevLedgerHash) + theApp->getOPs().switchLastClosedLedger(consensus, true); + mPreviousLedger = consensus; + mHaveCorrectLCL = true; + mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution( + mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(), + mPreviousLedger->getLedgerSeq() + 1); } - if (!found) + else { + mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash); + std::vector peerList = theApp->getConnectionPool().getPeerVector(); + mHaveCorrectLCL = false; + mProposing = false; + mValidating = false; + bool found = false; BOOST_FOREACH(Peer::pointer& peer, peerList) - mAcquiringLedger->peerHas(peer); + { + if (peer->hasLedger(mPrevLedgerHash)) + { + found = true; + mAcquiringLedger->peerHas(peer); + } + } + if (!found) + { + BOOST_FOREACH(Peer::pointer& peer, peerList) + mAcquiringLedger->peerHas(peer); + } } } } @@ -450,8 +466,8 @@ void LedgerConsensus::statePreClose() statusChange(newcoin::neCLOSING_LEDGER, *mPreviousLedger); takeInitialPosition(*theApp->getMasterLedger().closeLedger()); } - else - checkLCL(); + else if (mHaveCorrectLCL) + checkLCL(); // double check } void LedgerConsensus::stateEstablish() From c481bd6cba31923999fc2deac52b1ff5c430b23b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 09:38:44 -0700 Subject: [PATCH 142/426] Simplify the code that handles a ledger change in the consensus window. Remove duplicate code. Handle edge cases correctly in all code paths. --- src/LedgerConsensus.cpp | 122 ++++++++++++++++++---------------------- src/LedgerConsensus.h | 1 + 2 files changed, 55 insertions(+), 68 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index ff21a1d5ab..db4d493c0b 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -211,31 +211,24 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, const Ledger::point mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution( mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(), previousLedger->getLedgerSeq() + 1); - mHaveCorrectLCL = previousLedger->getHash() == prevLCLHash; - - if (!mHaveCorrectLCL) - { - Log(lsINFO) << "Entering consensus with: " << previousLedger->getHash().GetHex(); - Log(lsINFO) << "Correct LCL is: " << prevLCLHash.GetHex(); - mHaveCorrectLCL = mProposing = mValidating = false; - mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(prevLCLHash); - std::vector peerList = theApp->getConnectionPool().getPeerVector(); - BOOST_FOREACH(const Peer::pointer& peer, peerList) - if (peer->hasLedger(prevLCLHash)) - mAcquiringLedger->peerHas(peer); - } - else if (mValSeed.isValid()) + if (mValSeed.isValid()) { Log(lsINFO) << "Entering consensus process, validating"; - mHaveCorrectLCL = mValidating = true; + mValidating = true; mProposing = theApp->getOPs().getOperatingMode() == NetworkOPs::omFULL; } else { Log(lsINFO) << "Entering consensus process, watching"; - mHaveCorrectLCL = true; mProposing = mValidating = false; } + + handleLCL(prevLCLHash); + if (!mHaveCorrectLCL) + { + Log(lsINFO) << "Entering consensus with: " << previousLedger->getHash().GetHex(); + Log(lsINFO) << "Correct LCL is: " << prevLCLHash.GetHex(); + } } void LedgerConsensus::checkLCL() @@ -258,45 +251,54 @@ void LedgerConsensus::checkLCL() if (netLgr != mPrevLedgerHash) { // LCL change Log(lsWARNING) << "View of consensus changed during consensus (" << netLgrCount << ")"; - mPrevLedgerHash = netLgr; - - Ledger::pointer newLedger = theApp->getMasterLedger()->getLedgerByHash(netLgr); - if (newLedger) - { - Log(lsINFO) << "Acquired the consensus ledger " << mPrevLedgerHash.GetHex(); - if (theApp->getMasterLedger().getClosedLedger()->getHash() != mPrevLedgerHash) - theApp->getOPs().switchLastClosedLedger(consensus, true); - mPreviousLedger = consensus; - mHaveCorrectLCL = true; - mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution( - mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(), - mPreviousLedger->getLedgerSeq() + 1); - } - else - { - mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash); - std::vector peerList = theApp->getConnectionPool().getPeerVector(); - mHaveCorrectLCL = false; - mProposing = false; - mValidating = false; - bool found = false; - BOOST_FOREACH(Peer::pointer& peer, peerList) - { - if (peer->hasLedger(mPrevLedgerHash)) - { - found = true; - mAcquiringLedger->peerHas(peer); - } - } - if (!found) - { - BOOST_FOREACH(Peer::pointer& peer, peerList) - mAcquiringLedger->peerHas(peer); - } - } + handleLCL(netLgr); } } +void LedgerConsensus::handleLCL(const uint256& lclHash) +{ + mPrevLedgerHash = lclHash; + if (mPreviousLedger->getHash() == mPrevLedgerHash) + return; + + Ledger::pointer newLCL = theApp->getMasterLedger().getLedgerByHash(lclHash); + if (newLCL) + mPreviousLedger = newLCL; + else if (mAcquiringLedger && (mAcquiringLedger->getHash() == mPrevLedgerHash)) + return; + else + { + Log(lsWARNING) << "Need consensus ledger " << mPrevLedgerHash.GetHex(); + mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash); + std::vector peerList = theApp->getConnectionPool().getPeerVector(); + bool found = false; + BOOST_FOREACH(Peer::pointer& peer, peerList) + { + if (peer->hasLedger(mPrevLedgerHash)) + { + found = true; + mAcquiringLedger->peerHas(peer); + } + } + if (!found) + { + BOOST_FOREACH(Peer::pointer& peer, peerList) + mAcquiringLedger->peerHas(peer); + } + mHaveCorrectLCL = false; + mProposing = false; + mValidating = false; + return; + } + + Log(lsINFO) << "Acquired the consensus ledger " << mPrevLedgerHash.GetHex(); + mHaveCorrectLCL = true; + mAcquiringLedger = LedgerAcquire::pointer(); + mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution( + mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(), + mPreviousLedger->getLedgerSeq() + 1); +} + void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) { SHAMap::pointer initialSet = initialLedger.peekTransactionMap()->snapShot(false); @@ -502,23 +504,7 @@ void LedgerConsensus::stateAccepted() void LedgerConsensus::timerEntry() { if (!mHaveCorrectLCL) - { checkLCL(); - Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(mPrevLedgerHash); - if (consensus) - { - Log(lsINFO) << "Acquired the consensus ledger " << mPrevLedgerHash.GetHex(); - if (theApp->getMasterLedger().getClosedLedger()->getHash() != mPrevLedgerHash) - theApp->getOPs().switchLastClosedLedger(consensus, true); - mPreviousLedger = consensus; - mHaveCorrectLCL = true; - mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution( - mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(), - mPreviousLedger->getLedgerSeq() + 1); - } - else - Log(lsINFO) << "Need consensus ledger " << mPrevLedgerHash.GetHex(); - } mCurrentMSeconds = (boost::posix_time::microsec_clock::universal_time() - mConsensusStartTime).total_milliseconds(); diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 362c621f6e..538b21152c 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -153,6 +153,7 @@ public: TransactionAcquire::pointer getAcquiring(const uint256& hash); void mapComplete(const uint256& hash, const SHAMap::pointer& map, bool acquired); void checkLCL(); + void handleLCL(const uint256& lclHash); void timerEntry(); From c8d3de7b7dcac8ee8fabce12773b79b9028f8f74 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 09:48:59 -0700 Subject: [PATCH 143/426] Remove an incorrect assertion. --- src/LedgerConsensus.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index db4d493c0b..77a4ac1ac8 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -303,7 +303,6 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) { SHAMap::pointer initialSet = initialLedger.peekTransactionMap()->snapShot(false); uint256 txSet = initialSet->getHash(); - assert (!mHaveCorrectLCL || (initialLedger.getParentHash() == mPreviousLedger->getHash())); // if any peers have taken a contrary position, process disputes boost::unordered_set found; From e5af7072bcf101fc2f5be416a3257d8553d01454 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 10:04:58 -0700 Subject: [PATCH 144/426] Propogate a view change during consensus to the NetworkOPs code. --- src/LedgerConsensus.cpp | 2 ++ src/LedgerTiming.cpp | 2 +- src/NetworkOPs.cpp | 6 ++++++ src/NetworkOPs.h | 1 + 4 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 77a4ac1ac8..ea9f81e99a 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -251,6 +251,8 @@ void LedgerConsensus::checkLCL() if (netLgr != mPrevLedgerHash) { // LCL change Log(lsWARNING) << "View of consensus changed during consensus (" << netLgrCount << ")"; + if (mHaveCorrectLCL) + theApp->getOPs().consensusViewChange(); handleLCL(netLgr); } } diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index f10acbaadd..229fa71faa 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -40,7 +40,7 @@ int ContinuousLedgerTiming::shouldClose( } if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close { - Log(lsTRACE) << "slow to close"; + Log(lsTRACE) << "slow to close (p=" << previousmSeconds) << ")"; if (previousMSeconds < 2000) return previousMSeconds; return previousMSeconds - 1000; diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 58bd6290c1..2d210b78db 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -695,6 +695,12 @@ void NetworkOPs::endConsensus(bool correctLCL) mConsensus = boost::shared_ptr(); } +void NetworkOPs::consensusViewChange() +{ + if ((mMode == omFULL) || (mMode == omTRACKING)) + setMode(omCONNECTED); +} + void NetworkOPs::setMode(OperatingMode om) { if (mMode == om) return; diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index e0a73052f4..9c16caac19 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -177,6 +177,7 @@ public: void setStandAlone() { setMode(omFULL); } void setStateTimer(); void newLCL(int proposers, int convergeTime, const uint256& ledgerHash); + void consensusViewChange(); int getPreviousProposers() { return mLastCloseProposers; } int getPreviousConvergeTime() { return mLastCloseConvergeTime; } uint32 getLastCloseTime() { return mLastCloseTime; } From 9308abc8e1b58569a9f99f1a912f1291be445ed0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 10:05:33 -0700 Subject: [PATCH 145/426] Extra logging. --- src/LedgerTiming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index 229fa71faa..20eb463d06 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -40,7 +40,7 @@ int ContinuousLedgerTiming::shouldClose( } if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close { - Log(lsTRACE) << "slow to close (p=" << previousmSeconds) << ")"; + Log(lsTRACE) << "slow to close (p=" << (previousMSeconds) << ")"; if (previousMSeconds < 2000) return previousMSeconds; return previousMSeconds - 1000; From ee71603dec884875642e43f963f2e741cfea5d9d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 10:29:56 -0700 Subject: [PATCH 146/426] Logic error in last close logic making us thing consensus was slow. --- src/LedgerConsensus.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index ea9f81e99a..e4df9584d2 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -440,24 +440,22 @@ void LedgerConsensus::statePreClose() int proposersClosed = mPeerPositions.size(); // This ledger is open. This computes how long since the last ledger closed - uint32 lastCloseTime; + int sinceClose; int ledgerInterval = 0; if (mHaveCorrectLCL && mPreviousLedger->getCloseAgree()) { // we can use consensus timing - lastCloseTime = mPreviousLedger->getCloseTimeNC(); + sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - mPreviousLedger->getCloseTimeNC()); ledgerInterval = 2 * mPreviousLedger->getCloseResolution(); if (ledgerInterval < LEDGER_IDLE_INTERVAL) ledgerInterval = LEDGER_IDLE_INTERVAL; } else { - lastCloseTime = theApp->getOPs().getLastCloseTime(); + sinceClose = theApp->getOPs().getLastCloseTime(); ledgerInterval = LEDGER_IDLE_INTERVAL; } - int sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - lastCloseTime); - if (sinceClose >= ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed, mPreviousMSeconds, sinceClose, ledgerInterval)) { // it is time to close the ledger From dbc2b4c4e9309d9ee3cefc360bae6c44f562390a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 10:30:19 -0700 Subject: [PATCH 147/426] Improve log message text. --- src/LedgerTiming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index 20eb463d06..fb28164f51 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -40,7 +40,7 @@ int ContinuousLedgerTiming::shouldClose( } if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close { - Log(lsTRACE) << "slow to close (p=" << (previousMSeconds) << ")"; + Log(lsTRACE) << "was slow to converge (p=" << (previousMSeconds) << ")"; if (previousMSeconds < 2000) return previousMSeconds; return previousMSeconds - 1000; From de5c9cc1a264f0fc44f4e147c9d01eaedb85c896 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 10:44:09 -0700 Subject: [PATCH 148/426] Comment out some code that's causing an issue. --- src/LedgerTiming.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index fb28164f51..a29f7ad2fa 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -38,6 +38,7 @@ int ContinuousLedgerTiming::shouldClose( << previousProposers << " before)"; return currentMSeconds; } +#if 0 // This false triggers on the genesis ledger if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close { Log(lsTRACE) << "was slow to converge (p=" << (previousMSeconds) << ")"; @@ -45,6 +46,7 @@ int ContinuousLedgerTiming::shouldClose( return previousMSeconds; return previousMSeconds - 1000; } +#endif return idleInterval * 1000; // normal idle } From 651cee5738304cafb5c5a4c32638e507ed134cac Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 10:44:21 -0700 Subject: [PATCH 149/426] Clean up ledger JSON output. --- src/Ledger.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index b6b7eedb0c..7895f81b98 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -417,23 +417,26 @@ void Ledger::addJson(Json::Value& ret, int options) bool full = (options & LEDGER_JSON_FULL) != 0; if(mClosed || full) { + if (mClosed) + ledger["closed"] = true; ledger["hash"] = mHash.GetHex(); ledger["transactionHash"] = mTransHash.GetHex(); ledger["accountHash"] = mAccountHash.GetHex(); - if (mClosed) ledger["closed"] = true; ledger["accepted"] = mAccepted; ledger["totalCoins"] = boost::lexical_cast(mTotCoins); - if ((mCloseFlags & sLCF_NoConsensusTime) != 0) - ledger["closeTimeEstimate"] = mCloseTime; - else + if (mCloseTime != 0) { - ledger["closeTime"] = mCloseTime; - ledger["closeTimeResolution"] = mCloseResolution; + if ((mCloseFlags & sLCF_NoConsensusTime) != 0) + ledger["closeTimeEstimate"] = boost::posix_time::to_simple_string(ptFromSeconds(mCloseTime)); + else + { + ledger["closeTime"] = boost::posix_time::to_simple_string(ptFromSeconds(mCloseTime)); + ledger["closeTimeResolution"] = mCloseResolution; + } } } - else ledger["closed"] = false; - if (mCloseTime != 0) - ledger["closeTime"] = boost::posix_time::to_simple_string(ptFromSeconds(mCloseTime)); + else + ledger["closed"] = false; if (mTransactionMap && (full || ((options & LEDGER_JSON_DUMP_TXNS) != 0))) { Json::Value txns(Json::arrayValue); From faaedb806f2a7620a38c3c81ef7e8f40e7251c55 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 11:43:20 -0700 Subject: [PATCH 150/426] Start of the proposal defer/playback code. Clean up tem codes to tap codes. --- src/LedgerConsensus.cpp | 19 +++++++++++++++++-- src/LedgerConsensus.h | 5 +++++ src/NetworkOPs.cpp | 6 ++++-- src/NetworkOPs.h | 2 +- src/Peer.cpp | 2 +- src/TransactionEngine.cpp | 6 +++--- src/TransactionEngine.h | 15 ++++++++++----- 7 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index e4df9584d2..916290d6dd 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -299,6 +299,7 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution( mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(), mPreviousLedger->getLedgerSeq() + 1); + playbackProposals(); } void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) @@ -810,10 +811,24 @@ void LedgerConsensus::Saccept(boost::shared_ptr This, SHAMap::p This->accept(txSet); } +void LedgerConsensus::deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic) +{ + /**/ +} + +void LedgerConsensus::playbackProposals() +{ + for ( boost::unordered_map< uint160, std::list >::iterator + it = mDeferredProposals.begin(), end = mDeferredProposals.end(); it != end; ++it) + { + /**/ + } +} + void LedgerConsensus::applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn, const Ledger::pointer& ledger, CanonicalTXSet& failedTransactions, bool openLedger) { - TransactionEngineParams parms = openLedger ? temOPEN_LEDGER : temFINAL; + TransactionEngineParams parms = openLedger ? tapOPEN_LEDGER : tapNONE; #ifndef TRUST_NETWORK try { @@ -846,7 +861,7 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, const Serializ void LedgerConsensus::applyTransactions(const SHAMap::pointer& set, const Ledger::pointer& applyLedger, const Ledger::pointer& checkLedger, CanonicalTXSet& failedTransactions, bool openLgr) { - TransactionEngineParams parms = openLgr ? temOPEN_LEDGER : temFINAL; + TransactionEngineParams parms = openLgr ? tapOPEN_LEDGER : tapNONE; TransactionEngine engine(applyLedger); for (SHAMapItem::pointer item = set->peekFirstItem(); !!item; item = set->peekNextItem(item->getTag())) diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 538b21152c..eae19d222b 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -111,6 +111,9 @@ protected: // Close time estimates std::map mCloseTimes; + // deferred proposals (node ID -> proposals from that peer) + boost::unordered_map< uint160, std::list > mDeferredProposals; + // final accept logic static void Saccept(boost::shared_ptr This, SHAMap::pointer txSet); void accept(const SHAMap::pointer& txSet); @@ -136,6 +139,7 @@ protected: void statusChange(newcoin::NodeEvent, Ledger& ledger); void takeInitialPosition(Ledger& initialLedger); void updateOurPositions(); + void playbackProposals(); int getThreshold(); void beginAccept(); void endConsensus(); @@ -167,6 +171,7 @@ public: bool haveConsensus(); bool peerPosition(const LedgerProposal::pointer&); + void deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic); bool peerHasSet(const Peer::pointer& peer, const uint256& set, newcoin::TxSetStatus status); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 2d210b78db..642877bd95 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -84,7 +84,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, return trans; } - TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, temOPEN_LEDGER); + TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, tapOPEN_LEDGER); if (r == tefFAILURE) throw Fault(IO_ERROR); if (r == terPRE_SEQ) @@ -599,7 +599,7 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo // <-- bool: true to relay bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint32 closeTime, - const std::string& pubKey, const std::string& signature) + const std::string& pubKey, const std::string& signature, const NewcoinAddress& nodePublic) { // JED: does mConsensus need to be locked? @@ -638,6 +638,8 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint if (!proposal->checkSign(signature)) { // Note that if the LCL is different, the signature check will fail Log(lsWARNING) << "Ledger proposal fails signature check"; + if ((mMode != omFULL) && (mMode != omTRACKING) && theApp->getUNL().nodeInUNL(proposal->peekPublic())) + mConsensus->deferProposal(proposal, nodePublic); return false; } diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 9c16caac19..5e53b98194 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -160,7 +160,7 @@ public: // ledger proposal/close functions bool recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint32 closeTime, - const std::string& pubKey, const std::string& signature); + const std::string& pubKey, const std::string& signature, const NewcoinAddress& nodePublic); bool gotTXData(const boost::shared_ptr& peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); bool recvValidation(const SerializedValidation::pointer& val); diff --git a/src/Peer.cpp b/src/Peer.cpp index 75a5f2f656..1ca2d8fa58 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -726,7 +726,7 @@ void Peer::recvPropose(newcoin::TMProposeSet& packet) memcpy(currentTxHash.begin(), packet.currenttxhash().data(), 32); if(theApp->getOPs().recvPropose(proposeSeq, currentTxHash, packet.closetime(), - packet.nodepubkey(), packet.signature())) + packet.nodepubkey(), packet.signature(), mNodePublic)) { // FIXME: Not all nodes will want proposals PackedMessage::pointer message = boost::make_shared(packet, newcoin::mtPROPOSE_LEDGER); theApp->getConnectionPool().relayMessage(this, message); diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 2e755c975d..8cde2efd83 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -973,7 +973,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, naSigningPubKey = NewcoinAddress::createAccountPublic(txn.peekSigningPubKey()); // Consistency: really signed. - if ((tesSUCCESS == terResult) && ((params & temNO_CHECK_SIGN) == 0) && !txn.checkSign(naSigningPubKey)) + if ((tesSUCCESS == terResult) && ((params & tapNO_CHECK_SIGN) == 0) && !txn.checkSign(naSigningPubKey)) { Log(lsWARNING) << "applyTransaction: Invalid transaction: bad signature"; @@ -1032,7 +1032,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, STAmount saPaid = txn.getTransactionFee(); - if (tesSUCCESS == terResult && (params & temOPEN_LEDGER) != temNONE) + if (tesSUCCESS == terResult && (params & tapOPEN_LEDGER) != tapNONE) { // Applying to open ledger, check fee if (!!saCost) { @@ -1322,7 +1322,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, if (!mLedger->addTransaction(txID, s)) assert(false); - if ((params & temOPEN_LEDGER) == temNONE) + if ((params & tapOPEN_LEDGER) == tapNONE) mLedger->destroyCoins(saPaid.getNValue()); } diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 08481fcefa..71183b58e5 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -93,11 +93,16 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman); enum TransactionEngineParams { - temNONE = 0x00, - temNO_CHECK_SIGN = 0x01, // Signature already checked - temOPEN_LEDGER = 0x10, // Transaction is running against an open ledger - temRETRY_OK = 0x20, // It was voted into a ledger anyway - temFINAL = 0x40, // This may be the transaction's last pass + 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 }; typedef struct { From 4d3fc5b6a5bddcb563cf51e372a3c5d3f1839741 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 30 Aug 2012 12:28:02 -0700 Subject: [PATCH 151/426] Stash and apply proposals received with a different LCL. --- src/LedgerConsensus.cpp | 17 +++++++++++++++-- src/LedgerConsensus.h | 2 +- src/LedgerProposal.h | 12 ++++++++++-- src/NetworkOPs.cpp | 3 +++ 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 916290d6dd..980e0be376 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -813,7 +813,12 @@ void LedgerConsensus::Saccept(boost::shared_ptr This, SHAMap::p void LedgerConsensus::deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic) { - /**/ + if (!peerPublic.isValid()) + return; + std::list& props = mDeferredProposals[peerPublic.getNodeID()]; + if (props.size() > (mPreviousProposers + 10)) + props.pop_front(); + props.push_back(proposal); } void LedgerConsensus::playbackProposals() @@ -821,7 +826,15 @@ void LedgerConsensus::playbackProposals() for ( boost::unordered_map< uint160, std::list >::iterator it = mDeferredProposals.begin(), end = mDeferredProposals.end(); it != end; ++it) { - /**/ + BOOST_FOREACH(const LedgerProposal::pointer& proposal, it->second) + { + proposal->setPrevLedger(mPrevLedgerHash); + if (proposal->checkSign()) + { + Log(lsINFO) << "Applying deferred proposal"; + peerPosition(proposal); + } + } } } diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index eae19d222b..31ffdf06c9 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -171,7 +171,7 @@ public: bool haveConsensus(); bool peerPosition(const LedgerProposal::pointer&); - void deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic); + void deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic); bool peerHasSet(const Peer::pointer& peer, const uint256& set, newcoin::TxSetStatus status); diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index 790b61fb4d..70d4bbbe7a 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -2,6 +2,7 @@ #define __PROPOSELEDEGR__ #include +#include #include @@ -21,6 +22,8 @@ protected: NewcoinAddress mPublicKey; NewcoinAddress mPrivateKey; // If ours + std::string mSignature; // set only if needed + public: typedef boost::shared_ptr pointer; @@ -39,16 +42,21 @@ public: uint256 getSigningHash() const; bool checkSign(const std::string& signature, const uint256& signingHash); bool checkSign(const std::string& signature) { return checkSign(signature, getSigningHash()); } + bool checkSign() { return checkSign(mSignature, getSigningHash()); } const uint160& getPeerID() const { return mPeerID; } const uint256& getCurrentHash() const { return mCurrentHash; } const uint256& getPrevLedger() const { return mPreviousLedger; } uint32 getProposeSeq() const { return mProposeSeq; } uint32 getCloseTime() const { return mCloseTime; } - const NewcoinAddress& peekPublic() const { return mPublicKey; } - std::vector getPubKey() const { return mPublicKey.getNodePublic(); } + const NewcoinAddress& peekPublic() const { return mPublicKey; } + std::vector getPubKey() const { return mPublicKey.getNodePublic(); } std::vector sign(); + void setPrevLedger(const uint256& prevLedger) { mPreviousLedger = prevLedger; } + void setSignature(const std::string& signature) { mSignature = signature; } + + void changePosition(const uint256& newPosition, uint32 newCloseTime); Json::Value getJson() const; }; diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 642877bd95..06d4b64a5f 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -639,7 +639,10 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint { // Note that if the LCL is different, the signature check will fail Log(lsWARNING) << "Ledger proposal fails signature check"; if ((mMode != omFULL) && (mMode != omTRACKING) && theApp->getUNL().nodeInUNL(proposal->peekPublic())) + { + proposal->setSignature(signature); mConsensus->deferProposal(proposal, nodePublic); + } return false; } From 657084f5b901f9ce356d86614193807fa3b5b958 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 30 Aug 2012 13:17:38 -0700 Subject: [PATCH 152/426] Rework applyTransaction to use new TERs. --- src/TransactionEngine.cpp | 206 ++++++++++++++++++++++++-------------- src/TransactionEngine.h | 9 +- src/utils.h | 2 + 3 files changed, 141 insertions(+), 76 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 8cde2efd83..1fbb473c26 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -372,6 +372,8 @@ STAmount TransactionEngine::rippleSend(const uint160& uSenderID, const uint160& STAmount saActual; const uint160 uIssuerID = saAmount.getIssuer(); + assert(!!uSenderID && !!uReceiverID); + if (uSenderID == uIssuerID || uReceiverID == uIssuerID) { // Direct send: redeeming IOUs and/or sending own IOUs. @@ -396,43 +398,53 @@ STAmount TransactionEngine::rippleSend(const uint160& uSenderID, const uint160& return saActual; } -STAmount TransactionEngine::accountSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount) +void TransactionEngine::accountSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount) { - STAmount saActualCost; + assert(!saAmount.isNegative()); - if (saAmount.isNative()) + if (!saAmount) { - SLE::pointer sleSender = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uSenderID)); - SLE::pointer sleReceiver = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uReceiverID)); + 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->getIValueFieldAmount(sfBalance)).getFullText() + % (sleSender ? (sleSender->getIValueFieldAmount(sfBalance)).getFullText() : "-") % NewcoinAddress::createHumanAccountID(uReceiverID) - % (sleReceiver->getIValueFieldAmount(sfBalance)).getFullText() + % (sleReceiver ? (sleReceiver->getIValueFieldAmount(sfBalance)).getFullText() : "-") % saAmount.getFullText()); - sleSender->setIFieldAmount(sfBalance, sleSender->getIValueFieldAmount(sfBalance) - saAmount); - sleReceiver->setIFieldAmount(sfBalance, sleReceiver->getIValueFieldAmount(sfBalance) + saAmount); + 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->getIValueFieldAmount(sfBalance)).getFullText() + % (sleSender ? (sleSender->getIValueFieldAmount(sfBalance)).getFullText() : "-") % NewcoinAddress::createHumanAccountID(uReceiverID) - % (sleReceiver->getIValueFieldAmount(sfBalance)).getFullText() + % (sleReceiver ? (sleReceiver->getIValueFieldAmount(sfBalance)).getFullText() : "-") % saAmount.getFullText()); - - entryModify(sleSender); - entryModify(sleReceiver); - - saActualCost = saAmount; } else { - saActualCost = rippleSend(uSenderID, uReceiverID, saAmount); + rippleSend(uSenderID, uReceiverID, saAmount); } - - return saActualCost; } TER TransactionEngine::offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID) @@ -973,7 +985,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, naSigningPubKey = NewcoinAddress::createAccountPublic(txn.peekSigningPubKey()); // Consistency: really signed. - if ((tesSUCCESS == terResult) && ((params & tapNO_CHECK_SIGN) == 0) && !txn.checkSign(naSigningPubKey)) + if ((tesSUCCESS == terResult) && !isSetBit(params, tapNO_CHECK_SIGN) && !txn.checkSign(naSigningPubKey)) { Log(lsWARNING) << "applyTransaction: Invalid transaction: bad signature"; @@ -1032,12 +1044,12 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, STAmount saPaid = txn.getTransactionFee(); - if (tesSUCCESS == terResult && (params & tapOPEN_LEDGER) != tapNONE) - { // Applying to open ledger, check fee + if (tesSUCCESS == terResult) + { if (!!saCost) { - // XXX DO NOT CHECK ON CONSENSUS PASS - if (saPaid < saCost) + // Only check fee is sufficient when the ledger is open. + if (isSetBit(params, tapOPEN_LEDGER) && saPaid < saCost) { Log(lsINFO) << "applyTransaction: insufficient fee"; @@ -1309,27 +1321,39 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Log(lsINFO) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman; - if (tesSUCCESS == terResult) + if (terResult >= tepPATH_PARTIAL && isSetBit(params, tapRETRY)) { + // Partial result and allowed to retry, reclassify as a retry. + terResult = terRETRY; + } + + if (tesSUCCESS == terResult || terResult >= tepPATH_PARTIAL) + { + // Transaction succeeded fully or (retries are not allowed and the transaction succeeded partially). txnWrite(); Serializer s; txn.add(s); - // XXX add failed status too - // XXX do fees as need. if (!mLedger->addTransaction(txID, s)) assert(false); - if ((params & tapOPEN_LEDGER) == tapNONE) - mLedger->destroyCoins(saPaid.getNValue()); + // Charge whatever fee they specified. + mLedger->destroyCoins(saPaid.getNValue()); } mTxnAccount = SLE::pointer(); mNodes.clear(); musUnfundedFound.clear(); + if (!isSetBit(params, tapOPEN_LEDGER) + && ((terResult >= temMALFORMED && terResult <= tefFAILURE) + || ((terResult >= tefFAILURE && terResult <= terRETRY)))) + { + // XXX Malformed or failed transaction in closed ledger must bow out. + } + return terResult; } @@ -1995,6 +2019,7 @@ TER TransactionEngine::calcNodeOfferRev( if (bFoundForward || itAllow->second != uIndex) { // Temporarily unfunded. Another node uses this source, ignore in this node. + Log(lsINFO) << "calcNodeOfferRev: temporarily unfunded offer"; nothing(); continue; @@ -2198,6 +2223,7 @@ TER TransactionEngine::calcNodeOfferFwd( const uint160& uNxtCurrencyID = pnNxt.uCurrencyID; const uint160& uNxtIssuerID = pnNxt.uIssuerID; +// const uint160& uPrvAccountID = pnPrv.uAccountID; const uint160& uNxtAccountID = pnNxt.uAccountID; const STAmount saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID)); @@ -2231,50 +2257,63 @@ TER TransactionEngine::calcNodeOfferFwd( SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio unsigned int uEntry = 0; - uint256 uCurIndex; + uint256 uOfferIndex; while (saPrvDlvReq != saPrvDlvAct // Have not met request. - && dirNext(uDirectTip, sleDirectDir, uEntry, uCurIndex)) + && dirNext(uDirectTip, sleDirectDir, uEntry, uOfferIndex)) { - // Have an entry from the directory. - SLE::pointer sleCurOfr = entryCache(ltOFFER, uCurIndex); - uint160 uCurOfrAccountID = sleCurOfr->getIValueFieldAccount(sfAccount).getAccountID(); - const STAmount& saCurOfrOutReq = sleCurOfr->getIValueFieldAmount(sfTakerGets); - const STAmount& saCurOfrInReq = sleCurOfr->getIValueFieldAmount(sfTakerPays); + // Have an offer from the directory. + // Handle offers such that there is no need to look back to the previous nodes offers. + + SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); + const uint160 uCurOfrAccountID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + const aciSource asLine = boost::make_tuple(uCurOfrAccountID, uCurCurrencyID, uCurIssuerID); + if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + { + // Offer is expired. + Log(lsINFO) << "calcNodeOfferFwd: expired offer"; + + assert(musUnfundedFound.find(uOfferIndex) != musUnfundedFound.end()); + continue; + } + + // Allowed to access source from this node? + curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine); + bool bFoundForward = itAllow != pspCur->umForward.end(); + + if (bFoundForward || itAllow->second != uIndex) + { + // Temporarily unfunded. Another node uses this source, ignore in this node. + Log(lsINFO) << "calcNodeOfferFwd: temporarily unfunded offer"; + + nothing(); + continue; + } + + const STAmount& saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets); + const STAmount& saCurOfrInReq = sleOffer->getIValueFieldAmount(sfTakerPays); STAmount saCurOfrInAct; STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. STAmount saCurOfrInMax = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); if (!saCurOfrFunds) { -#ifdef WORK_IN_PROGRESS // Offer is unfunded. - pspCur->usUnfunded.add(uCurIndex); // Add offer to found unfunded. + Log(lsINFO) << "calcNodeOfferFwd: unfunded offer"; - entryDelete(sleCurOfr, true); // Delete unfunded offer. - - // Delete unfunded offer from owner's directory. - const uint64 uOwnerNode = sleCurOffer->getIFieldU64(sfOwnerNode); - - terResult = dirDelete( - true, // YYY We don't delete owner directories? - uOwnerNode, - uDirectTip, - uCurIndex); - - // Delete unfunded offer from quality directory. - // XXX Need a dir walking version of delete. - terResult = dirDelete( - false, // Don't need to keep root. - const uint64& uNodeDir, - uDirectTip, - uCurIndex); -#endif + // YYY Could verify offer is correct place for unfundeds. + nothing(); + continue; } - else if (!!uNxtAccountID) - { - // Next is an account. + if (!!uNxtAccountID) + { + // Next is an account node. + // If previous is an account, then inbound funds can be credited offer with no fees or quality. + // Transfer fees were previously handled. XXX Verify. + // If previous is an offer, then inbound funds are with issuer or in limbo. + + // The only fee ever charged is an output transfer fee. const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtAccountID == uCurIssuerID ? saOne : saTransferRate; @@ -2287,29 +2326,26 @@ TER TransactionEngine::calcNodeOfferFwd( : saOutBase; const STAmount saOutCost = MIN(saOutCostRaw, saCurOfrFunds); // Limit cost by fees & funds. const STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; // Out amount after fees. + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) + : saOutCost; // Out amount after fees. // Compute input w/o fees required. - const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uCurCurrencyID, uCurIssuerID); + const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uPrvIssuerID); - // XXX Send from offer owner -// accountSend(uCurIssuerID, uNxtAccountID, saOutDlvAct); + // Deliver to output. + accountSend(uCurOfrAccountID, uNxtAccountID, saOutDlvAct); saCurDlvAct += saOutDlvAct; // Portion of driver served. - -// XXX accountCredit(uCurIssuerID, uNxtAccountID, saOutDlvAct); - - saPrvDlvAct += saInDlvAct; // Portion needed in previous. } else { - // Next is an offer. + // Next is an offer node. + // Need to step through next offer's nodes to figure out fees. uint256 uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); const uint256 uNxtEnd = Ledger::getQualityNext(uNxtTip); bool bNxtAdvance = !entryCache(ltDIR_NODE, uNxtTip); - while (!!uNxtTip // Have a quality. + while (!!uNxtTip // Have a quality. && saPrvDlvAct != saPrvDlvReq) // Have more to do. { if (bNxtAdvance) @@ -2343,10 +2379,11 @@ TER TransactionEngine::calcNodeOfferFwd( : saTransferRate; const bool bFee = saFeeRate != saOne; +// XXX Skip expireds and unfundeds. const STAmount saInBase = saCurOfrInMax-saCurOfrInAct; const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID); - STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. - saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. + STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. + saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. const STAmount saOutCost = MIN( bFee ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) @@ -2367,7 +2404,30 @@ TER TransactionEngine::calcNodeOfferFwd( if (!bMultiQuality) uNxtTip = 0; } +#if 0 + // Deliver output to limbo or currency issuer. + accountSend( + uCurOfrAccountID, // Offer owner pays. + !!uCurIssuerID + ? uCurIssuerID // Output is non-XNS send to issuer. + : ACCOUNT_XNS, // Output is XNS send to limbo (ACCOUNT_XNS). + saOutDlvAct); +#endif } + + // Deliver input to offer owner. +#if 0 + accountSend( + !!uPrvAccountID + ? uPrvAccountID // Previous is an account. Source is previous account. + : !!uPrvIssuerID + ? ACCOUNT_XNS // Previous is offer outputing XNS, source is limbo (ACCOUNT_XNS). + : uPrvIssuerID, // Previous is offer outputing non-XNS, source is input issuer. + uCurOfrAccountID, // Offer owner receives. + saInDlvAct); + + saPrvDlvAct += saInDlvAct; // Portion needed in previous. +#endif } } diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 71183b58e5..115e4e68a2 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -64,7 +64,7 @@ enum TER // aka TransactionEngineResult tefPAST_SEQ, // -99 .. -1: R Retry (sequence too high, no funds for txn fee, originating account non-existent) - // Transaction cannot be applied, cannot charge fee, not forwarded, might succeed later, hold + // Transaction cannot be applied, not forwarded, might succeed later, hold terRETRY = -99, terDIR_FULL, terFUNDS_SPENT, @@ -80,10 +80,13 @@ enum TER // aka TransactionEngineResult // 0: S Success (success) // Transaction succeeds, can be applied, can charge fee, forwarded + // applyTransaction: addTransaction and destroyCoins tesSUCCESS = 0, // 100 .. P Partial success (SR) (ripple transaction with no good paths, pay to non-existent account) - // Transaction can be applied, can charge fee, forwarded, but does not achieve optimal result. + // Transaction can be applied, forwarded, but does not achieve optimal result. + // Only allowed as a return code of appliedTransaction when !tapRetry. + // applyTransaction: addTransaction and destroyCoins tepPARTIAL = 100, tepPATH_DRY, tepPATH_PARTIAL, @@ -271,7 +274,7 @@ protected: STAmount rippleSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); STAmount accountHolds(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID); - STAmount accountSend(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount); + 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); diff --git a/src/utils.h b/src/utils.h index 9da1b76aba..f11b82a1b7 100644 --- a/src/utils.h +++ b/src/utils.h @@ -24,6 +24,8 @@ #define MIN(x,y) ((x) > (y) ? (y) : (x)) #endif +#define isSetBit(x,y) (!!((x) & (y))) + #ifdef WIN32 extern uint64_t htobe64(uint64_t value); extern uint64_t be64toh(uint64_t value); From 22a1cb6eedd049f2aedbb745989b18b6a4d3badb Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 30 Aug 2012 15:19:28 -0700 Subject: [PATCH 153/426] Work towards ripple. --- src/TransactionEngine.cpp | 104 +++++++++++++++++++++++--------------- src/TransactionEngine.h | 48 ++++++++++++++---- 2 files changed, 101 insertions(+), 51 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 1fbb473c26..9809364661 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -2204,6 +2204,7 @@ TER TransactionEngine::calcNodeOfferRev( return terResult; } +// Offer input and output is issuer or limbo. TER TransactionEngine::calcNodeOfferFwd( const unsigned int uIndex, // 0 < uIndex < uLast const PathState::pointer& pspCur, @@ -2223,7 +2224,7 @@ TER TransactionEngine::calcNodeOfferFwd( const uint160& uNxtCurrencyID = pnNxt.uCurrencyID; const uint160& uNxtIssuerID = pnNxt.uIssuerID; -// const uint160& uPrvAccountID = pnPrv.uAccountID; + const uint160& uPrvAccountID = pnPrv.uAccountID; const uint160& uNxtAccountID = pnNxt.uAccountID; const STAmount saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID)); @@ -2234,15 +2235,28 @@ TER TransactionEngine::calcNodeOfferFwd( const STAmount& saPrvDlvReq = pnPrv.saFwdDeliver; // Forward driver. STAmount saPrvDlvAct; - STAmount& saCurDlvReq = pnCur.saFwdDeliver; - STAmount saCurDlvAct; + STAmount& saCurDlvAct = pnCur.saFwdDeliver; // How much current node will deliver. + saCurDlvAct; = 0; - while (!!uDirectTip // Have a quality. - && saPrvDlvAct != saPrvDlvReq) + bool bNxtOffer = !uNxtAccountID; + uint256 uNxtTip; + uint256 uNxtEnd; + bool bNxtDirAdvance; + bool bNxtSubAdvance; + + if (bNxtOffer) + { + uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); + uNxtEnd = Ledger::getQualityNext(uNxtTip); + bNxtDirAdvance = !entryCache(ltDIR_NODE, uNxtTip); + bNxtSubAdvance = true; + } + + while (!!uDirectTip && saPrvDlvAct != saPrvDlvReq) // Have a quality and not done. { - // Get next quality. if (bAdvance) { + // Get next quality. uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd); } else @@ -2291,10 +2305,7 @@ TER TransactionEngine::calcNodeOfferFwd( } const STAmount& saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets); - const STAmount& saCurOfrInReq = sleOffer->getIValueFieldAmount(sfTakerPays); - STAmount saCurOfrInAct; STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. - STAmount saCurOfrInMax = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); if (!saCurOfrFunds) { @@ -2306,6 +2317,12 @@ TER TransactionEngine::calcNodeOfferFwd( continue; } + const STAmount& saCurOfrInReq = sleOffer->getIValueFieldAmount(sfTakerPays); + STAmount saCurOfrInMax = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); + STAmount saCurOfrInAct; + + STAmount saInDlvAct; + if (!!uNxtAccountID) { // Next is an account node. @@ -2328,8 +2345,9 @@ TER TransactionEngine::calcNodeOfferFwd( const STAmount saOutDlvAct = bFee ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutCost; // Out amount after fees. + // Compute input w/o fees required. - const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uPrvIssuerID); + saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uPrvIssuerID); // Deliver to output. accountSend(uCurOfrAccountID, uNxtAccountID, saOutDlvAct); @@ -2341,20 +2359,15 @@ TER TransactionEngine::calcNodeOfferFwd( // Next is an offer node. // Need to step through next offer's nodes to figure out fees. - uint256 uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); - const uint256 uNxtEnd = Ledger::getQualityNext(uNxtTip); - bool bNxtAdvance = !entryCache(ltDIR_NODE, uNxtTip); + STAmount saOutDlvAct; - while (!!uNxtTip // Have a quality. - && saPrvDlvAct != saPrvDlvReq) // Have more to do. + while (!!uNxtTip && saCurOfrInAct != saCurOfrInMax) // An offer may be available and have more to do. { - if (bNxtAdvance) + if (bNxtDirAdvance) { - uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd); - } - else - { - bNxtAdvance = true; + uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd); + bNxtSubAdvance = true; + bNxtDirAdvance = false; } if (!!uNxtTip) @@ -2366,10 +2379,25 @@ TER TransactionEngine::calcNodeOfferFwd( unsigned int uEntry = 0; uint256 uNxtIndex; - while (saPrvDlvReq != saPrvDlvAct // Have not met request. - && dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex)) + while (saCurOfrInAct != saCurOfrInMax) // Have not met request. { - // YYY This could combine offers with the same fee before doing math. + if (!bNxtSubAdvance) + { + // Continue with current uNxtIndex. + nothing(); + } + else if (dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex)) + { + // Found a next uNxtIndex. + bNxtSubAdvance = false; + } + else + { + // No more offers in directory. + bNxtDirAdvance = true; + break; + } + SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex); const uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); const STAmount& saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); @@ -2389,14 +2417,19 @@ TER TransactionEngine::calcNodeOfferFwd( ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, saCurOfrFunds); // Limit cost by fees & funds. - const STAmount saOutDlvAct = bFee + const STAmount saOutDlvPass= bFee ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutCost; // Out amount after fees. - const STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required. + const STAmount saInDlvPass = STAmount::multiply(saOutDlvPass, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required. - saCurOfrInAct += saOutDlvAct; // Portion of driver served. - saPrvDlvAct += saOutDlvAct; // Portion needed in previous. - saCurDlvAct += saInDlvAct; // Portion of driver served. + saCurOfrInAct += saOutDlvPass; // Portion of driver served. + saCurDlvAct += saInDlvPass; // Portion of driver served. + + // Deliver input + saInDlvAct += saInDlvPass; + + // Deliver output. + saOutDlvAct += saOutDlvPass; } } @@ -2404,7 +2437,7 @@ TER TransactionEngine::calcNodeOfferFwd( if (!bMultiQuality) uNxtTip = 0; } -#if 0 + // Deliver output to limbo or currency issuer. accountSend( uCurOfrAccountID, // Offer owner pays. @@ -2412,11 +2445,9 @@ TER TransactionEngine::calcNodeOfferFwd( ? uCurIssuerID // Output is non-XNS send to issuer. : ACCOUNT_XNS, // Output is XNS send to limbo (ACCOUNT_XNS). saOutDlvAct); -#endif } // Deliver input to offer owner. -#if 0 accountSend( !!uPrvAccountID ? uPrvAccountID // Previous is an account. Source is previous account. @@ -2427,7 +2458,6 @@ TER TransactionEngine::calcNodeOfferFwd( saInDlvAct); saPrvDlvAct += saInDlvAct; // Portion needed in previous. -#endif } } @@ -2436,13 +2466,7 @@ TER TransactionEngine::calcNodeOfferFwd( uDirectTip = 0; } - if (saCurDlvAct) - { - saCurDlvReq = saCurDlvAct; // Adjust request. - terResult = tesSUCCESS; - } - - return terResult; + return !!saCurDlvAct ? tesSUCCESS : terResult; } #if 0 diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 115e4e68a2..67f8077819 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -19,14 +19,22 @@ enum TER // aka TransactionEngineResult // Note: Range is stable. Exact numbers are currently unstable. Use tokens. // -399 .. -300: L Local error (transaction fee inadequate, exceeds local limit) - // Not forwarded, no fee. Only valid during non-consensus processing + // Only valid during non-consensus processing. + // Implications: + // - Not forwarded + // - No fee check telLOCAL_ERROR = -399, telBAD_PATH_COUNT, telINSUF_FEE_P, // -299 .. -200: M Malformed (bad signature) - // Transaction corrupt, not forwarded, cannot charge fee, reject - // Never can succeed in any ledger + // Causes: + // - Transaction corrupt. + // Implications: + // - Not applied + // - Not forwarded + // - Reject + // - Can not succeed in any imagined ledger. temMALFORMED = -299, temBAD_AMOUNT, temBAD_AUTH_MASTER, @@ -48,8 +56,14 @@ enum TER // aka TransactionEngineResult temUNKNOWN, // -199 .. -100: F Failure (sequence number previously used) - // Transaction cannot succeed because of ledger state, unexpected ledger state, C++ exception, not forwarded, cannot be - // applied, Could succeed in an imaginary ledger. + // Causes: + // - Transaction cannot succeed because of ledger state. + // - Unexpected ledger state. + // - C++ exception. + // Implications: + // - Not applied + // - Not forwarded + // - Could succeed in an imaginared ledger. tefFAILURE = -199, tefALREADY, tefBAD_ADD_AUTH, @@ -64,7 +78,13 @@ enum TER // aka TransactionEngineResult tefPAST_SEQ, // -99 .. -1: R Retry (sequence too high, no funds for txn fee, originating account non-existent) - // Transaction cannot be applied, not forwarded, might succeed later, hold + // Causes: + // - Priror application of another, possibly non-existant, transaction could allow this transaction to succeed. + // Implications: + // - Not applied + // - Not forwarded + // - Might succeed later + // - Hold terRETRY = -99, terDIR_FULL, terFUNDS_SPENT, @@ -79,14 +99,20 @@ enum TER // aka TransactionEngineResult terUNFUNDED, // 0: S Success (success) - // Transaction succeeds, can be applied, can charge fee, forwarded - // applyTransaction: addTransaction and destroyCoins + // Causes: + // - Success. + // Implications: + // - Applied + // - Forwarded tesSUCCESS = 0, // 100 .. P Partial success (SR) (ripple transaction with no good paths, pay to non-existent account) - // Transaction can be applied, forwarded, but does not achieve optimal result. - // Only allowed as a return code of appliedTransaction when !tapRetry. - // applyTransaction: addTransaction and destroyCoins + // Causes: + // - Success, but does not achieve optimal result. + // Implications: + // - Applied + // - Forwarded + // Only allowed as a return code of appliedTransaction when !tapRetry. Otherwise, treated as terRETRY. tepPARTIAL = 100, tepPATH_DRY, tepPATH_PARTIAL, From e8a74c7679dade6b15c0e17a5bc1ac9a74db92f5 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 30 Aug 2012 21:15:46 -0700 Subject: [PATCH 154/426] Work on ripple. --- src/TransactionEngine.cpp | 170 +++++++++++++++++++++----------------- src/TransactionEngine.h | 20 +++-- 2 files changed, 107 insertions(+), 83 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 9809364661..dfecf4489c 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -266,7 +266,7 @@ STAmount TransactionEngine::accountHolds(const uint160& uAccountID, const uint16 // 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, result is Default. +// If the issuer is the same as uAccountID, funds are unlimited, use result is saDefault. STAmount TransactionEngine::accountFunds(const uint160& uAccountID, const STAmount& saDefault) { STAmount saFunds; @@ -1321,13 +1321,13 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Log(lsINFO) << "applyTransaction: terResult=" << strToken << " : " << terResult << " : " << strHuman; - if (terResult >= tepPATH_PARTIAL && isSetBit(params, tapRETRY)) + if (isTepPartial(terResult) && isSetBit(params, tapRETRY)) { // Partial result and allowed to retry, reclassify as a retry. terResult = terRETRY; } - if (tesSUCCESS == terResult || terResult >= tepPATH_PARTIAL) + if (tesSUCCESS == terResult || isTepPartial(terResult)) { // Transaction succeeded fully or (retries are not allowed and the transaction succeeded partially). txnWrite(); @@ -1348,8 +1348,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, musUnfundedFound.clear(); if (!isSetBit(params, tapOPEN_LEDGER) - && ((terResult >= temMALFORMED && terResult <= tefFAILURE) - || ((terResult >= tefFAILURE && terResult <= terRETRY)))) + && (isTemMalformed(terResult) || isTefFailure(terResult))) { // XXX Malformed or failed transaction in closed ledger must bow out. } @@ -1968,8 +1967,7 @@ TER TransactionEngine::calcNodeOfferRev( Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString()); - while (!!uDirectTip // Have a quality. - && saCurDlvAct != saCurDlvReq) + while (!!uDirectTip && saCurDlvAct != saCurDlvReq) // Have a quality and not done. { // Get next quality. if (bAdvance) @@ -2033,7 +2031,7 @@ TER TransactionEngine::calcNodeOfferRev( curIssuerNodeConstIterator itSourcePast = mumSource.find(asLine); bool bFoundPast = itSourcePast != mumSource.end(); - if (!saCurOfrFunds) + if (!saCurOfrFunds.isPositive()) { // Offer is unfunded. Log(lsINFO) << "calcNodeOfferRev: encountered unfunded offer"; @@ -2048,11 +2046,6 @@ TER TransactionEngine::calcNodeOfferRev( // Never mentioned before: found unfunded. musUnfundedFound.insert(uOfferIndex); // Mark offer for always deletion. } - else - { - // Mentioned before: source became unfunded. - pspCur->vUnfundedBecame.push_back(uOfferIndex); // Mark offer for deletion on use of current path state. - } continue; } @@ -2069,8 +2062,8 @@ TER TransactionEngine::calcNodeOfferRev( : saTransferRate; bool bFee = saFeeRate != saOne; - STAmount saOutBase = MIN(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed. - STAmount saOutCost = MIN( + STAmount saOutBase = std::min(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed. + STAmount saOutCost = std::min( bFee ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, @@ -2149,9 +2142,9 @@ TER TransactionEngine::calcNodeOfferRev( : saTransferRate; bool bFee = saFeeRate != saOne; - STAmount saOutBase = MIN(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed. - saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. - STAmount saOutCost = MIN( + STAmount saOutBase = std::min(saCurOfrOutReq, saCurDlvReq-saCurDlvAct);// Limit offer out by needed. + saOutBase = std::min(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. + STAmount saOutCost = std::min( bFee ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase, @@ -2236,19 +2229,23 @@ TER TransactionEngine::calcNodeOfferFwd( STAmount saPrvDlvAct; STAmount& saCurDlvAct = pnCur.saFwdDeliver; // How much current node will deliver. - saCurDlvAct; = 0; + saCurDlvAct = 0; bool bNxtOffer = !uNxtAccountID; uint256 uNxtTip; uint256 uNxtEnd; bool bNxtDirAdvance; bool bNxtSubAdvance; + unsigned int uNxtEntry = 0; + uint256 uNxtIndex; + SLE::pointer sleNxtDir; if (bNxtOffer) { uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); uNxtEnd = Ledger::getQualityNext(uNxtTip); - bNxtDirAdvance = !entryCache(ltDIR_NODE, uNxtTip); + sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); + bNxtDirAdvance = !sleNxtDir; bNxtSubAdvance = true; } @@ -2306,8 +2303,9 @@ TER TransactionEngine::calcNodeOfferFwd( const STAmount& saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets); STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. + STAmount saCurOfrSpent; - if (!saCurOfrFunds) + if (!saCurOfrFunds.isPositive()) { // Offer is unfunded. Log(lsINFO) << "calcNodeOfferFwd: unfunded offer"; @@ -2318,10 +2316,9 @@ TER TransactionEngine::calcNodeOfferFwd( } const STAmount& saCurOfrInReq = sleOffer->getIValueFieldAmount(sfTakerPays); - STAmount saCurOfrInMax = MIN(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); + STAmount saCurOfrInMax = std::min(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); STAmount saCurOfrInAct; - - STAmount saInDlvAct; + STAmount saCurOfrOutAct; if (!!uNxtAccountID) { @@ -2337,49 +2334,47 @@ TER TransactionEngine::calcNodeOfferFwd( const bool bFee = saFeeRate != saOne; const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID, uCurIssuerID); - const STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. + const STAmount saOutBase = std::min(saCurOfrOutReq, saOutPass); // Limit offer out by needed. const STAmount saOutCostRaw= bFee ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) : saOutBase; - const STAmount saOutCost = MIN(saOutCostRaw, saCurOfrFunds); // Limit cost by fees & funds. - const STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; // Out amount after fees. + const STAmount saOutCost = std::min(saOutCostRaw, saCurOfrFunds); // Limit cost by fees & funds. + + saCurOfrSpent = saOutCost; // XXX Check. + saCurOfrOutAct = bFee + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) + : saOutCost; // Out amount after fees. // Compute input w/o fees required. - saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uPrvIssuerID); + saCurOfrInAct = STAmount::multiply(saCurOfrOutAct, saOfrRate, uPrvCurrencyID, uPrvIssuerID); // Deliver to output. - accountSend(uCurOfrAccountID, uNxtAccountID, saOutDlvAct); - - saCurDlvAct += saOutDlvAct; // Portion of driver served. + accountSend(uCurOfrAccountID, uNxtAccountID, saCurOfrOutAct); } else { // Next is an offer node. // Need to step through next offer's nodes to figure out fees. - STAmount saOutDlvAct; - - while (!!uNxtTip && saCurOfrInAct != saCurOfrInMax) // An offer may be available and have more to do. + while (!!uNxtTip && saCurOfrInAct != saCurOfrInMax) // A next offer may be available and have more to do. { if (bNxtDirAdvance) { uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd); bNxtSubAdvance = true; bNxtDirAdvance = false; + uNxtEntry = 0; + if (!!uNxtTip) + sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); } if (!!uNxtTip) { // Do a directory. // - Drive on computing saCurDlvAct to derive saPrvDlvAct. - SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); // ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip)); // For correct ratio - unsigned int uEntry = 0; - uint256 uNxtIndex; - while (saCurOfrInAct != saCurOfrInMax) // Have not met request. + while (saCurOfrInAct != saCurOfrInMax) // Have more to do. { if (!bNxtSubAdvance) { @@ -2401,35 +2396,53 @@ TER TransactionEngine::calcNodeOfferFwd( SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex); const uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); const STAmount& saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); + const STAmount& saNxtOfrOut = sleNxtOfr->getIValueFieldAmount(sfTakerGets); - const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID - ? saOne - : saTransferRate; - const bool bFee = saFeeRate != saOne; + const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID + ? saOne + : saTransferRate; + const bool bFee = saFeeRate != saOne; -// XXX Skip expireds and unfundeds. - const STAmount saInBase = saCurOfrInMax-saCurOfrInAct; - const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID); - STAmount saOutBase = MIN(saCurOfrOutReq, saOutPass); // Limit offer out by needed. - saOutBase = MIN(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. - const STAmount saOutCost = MIN( - bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutBase, - saCurOfrFunds); // Limit cost by fees & funds. - const STAmount saOutDlvPass= bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; // Out amount after fees. - const STAmount saInDlvPass = STAmount::multiply(saOutDlvPass, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required. + bool bNxtExpired = sleNxtOfr->getIFieldPresent(sfExpiration) + && sleNxtOfr->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC(); + STAmount saNxtOfrFunds = accountFunds(uNxtOfrAccountID, saNxtOfrOut); // Funds left. - saCurOfrInAct += saOutDlvPass; // Portion of driver served. - saCurDlvAct += saInDlvPass; // Portion of driver served. + if (!bNxtExpired && saNxtOfrFunds.isPositive()) + { + // Offer is not expired and is funded. + const STAmount saInBase = saCurOfrInMax-saCurOfrInAct; + const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID); + STAmount saOutBase = std::min(saCurOfrOutReq, saOutPass); // Limit offer out by needed. + saOutBase = std::min(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. + const STAmount saOutCost = std::min( + bFee + ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) + : saOutBase, + saCurOfrFunds); // Limit cost by fees & funds. + const STAmount saOutDlvPass= bFee + ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) + : saOutCost; // Out amount after fees. + const STAmount saInDlvPass = STAmount::multiply(saOutDlvPass, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required. - // Deliver input - saInDlvAct += saInDlvPass; + // XXX Check fees. + sleNxtOfr->setIFieldAmount(sfTakerGets, saNxtOfrIn - saInDlvPass); + sleNxtOfr->setIFieldAmount(sfTakerPays, saNxtOfrOut - saOutDlvPass); - // Deliver output. - saOutDlvAct += saOutDlvPass; + if (saNxtOfrOut == saOutDlvPass) { + // Consumed all of offer. + Log(lsINFO) << "calcNodeOfferFwd: offer consumed"; + + pspCur->vUnfundedBecame.push_back(uNxtIndex); // Mark offer for deletion on use of current path state. + + bNxtSubAdvance = true; + } + + saCurOfrSpent += saOutDlvPass; // XXX Check. + + saCurOfrInAct += saInDlvPass; // Add to input handled. + + saCurOfrOutAct += saOutDlvPass; // Add to output handled. + } } } @@ -2440,11 +2453,11 @@ TER TransactionEngine::calcNodeOfferFwd( // Deliver output to limbo or currency issuer. accountSend( - uCurOfrAccountID, // Offer owner pays. + uCurOfrAccountID, // Offer owner pays. !!uCurIssuerID ? uCurIssuerID // Output is non-XNS send to issuer. : ACCOUNT_XNS, // Output is XNS send to limbo (ACCOUNT_XNS). - saOutDlvAct); + saCurOfrOutAct); } // Deliver input to offer owner. @@ -2455,9 +2468,16 @@ TER TransactionEngine::calcNodeOfferFwd( ? ACCOUNT_XNS // Previous is offer outputing XNS, source is limbo (ACCOUNT_XNS). : uPrvIssuerID, // Previous is offer outputing non-XNS, source is input issuer. uCurOfrAccountID, // Offer owner receives. - saInDlvAct); + saCurOfrInAct); - saPrvDlvAct += saInDlvAct; // Portion needed in previous. + if (saCurOfrFunds == saCurOfrSpent) + { + // Offer became unfunded. + pspCur->vUnfundedBecame.push_back(uOfferIndex); // Mark offer for deletion on use of current path state. + } + + saPrvDlvAct += saCurOfrInAct; // Portion needed in previous. + saCurDlvAct += saCurOfrOutAct; // Portion of driver served. } } @@ -2740,7 +2760,7 @@ void TransactionEngine::calcNodeRipple( // No fee. Log(lsINFO) << boost::str(boost::format("calcNodeRipple: No fees")); - STAmount saTransfer = bPrvUnlimited ? saCur : MIN(saPrv, saCur); + STAmount saTransfer = bPrvUnlimited ? saCur : std::min(saPrv, saCur); saPrvAct += saTransfer; saCurAct += saTransfer; @@ -2874,8 +2894,8 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS // account --> ACCOUNT --> $ // Overall deliverable. const STAmount& saCurWantedReq = bPrvAccount - ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. - : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + ? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $ : saCurWantedReq=%s") @@ -2888,7 +2908,7 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS // Redeem at 1:1 Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Redeem at 1:1")); - saCurWantedAct = MIN(saPrvRedeemReq, saCurWantedReq); + saCurWantedAct = std::min(saPrvRedeemReq, saCurWantedReq); saPrvRedeemAct = saCurWantedAct; } @@ -3029,7 +3049,7 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS { // offer --> ACCOUNT --> $ const STAmount& saCurWantedReq = bPrvAccount - ? MIN(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + ? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); @@ -3196,7 +3216,7 @@ TER TransactionEngine::calcNodeAccountFwd( // Redeem requested. saCurRedeemAct = saCurRedeemReq.isNegative() ? saCurRedeemReq - : MIN(saCurRedeemReq, saCurSendMaxReq); + : std::min(saCurRedeemReq, saCurSendMaxReq); } else { @@ -3209,7 +3229,7 @@ TER TransactionEngine::calcNodeAccountFwd( // Issue requested and not over budget. saCurIssueAct = saCurSendMaxReq.isNegative() ? saCurIssueReq - : MIN(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); + : std::min(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); } else { diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 67f8077819..149c6289b7 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -118,6 +118,10 @@ enum TER // aka TransactionEngineResult tepPATH_PARTIAL, }; +#define isTemMalformed(x) ((x) >= temMALFORMED && (x) < tefFAILURE) +#define isTefFailure(x) ((x) >= tefFAILURE && (x) < terRETRY) +#define isTepPartial(x) ((x) >= tepPATH_PARTIAL) + bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman); enum TransactionEngineParams @@ -179,23 +183,23 @@ public: std::vector vpnNodes; // When processing, don't want to complicate directory walking with deletion. - std::vector vUnfundedBecame; // Offers that became unfunded. + std::vector vUnfundedBecame; // Offers that became unfunded or were completely consumed. // First time working foward a funding source was mentioned for accounts. Source may only be used there. - curIssuerNode umForward; // Map of currency, issuer to node index. + 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. + 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). + 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 Ledger::pointer& lpLedger, From 73e6e70f13a17d9229fdb285d88c75d634ca0c0e Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 30 Aug 2012 21:16:07 -0700 Subject: [PATCH 155/426] Use stl for min and max. --- src/Config.cpp | 11 ++++++----- src/ConnectionPool.cpp | 3 ++- src/utils.h | 8 -------- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/Config.cpp b/src/Config.cpp index 4e36f39a1b..a419ae0aae 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #define SECTION_ACCOUNT_PROBE_MAX "account_probe_max" #define SECTION_DEBUG_LOGFILE "debug_logfile" @@ -232,19 +233,19 @@ void Config::load() if (sectionSingleB(secConfig, SECTION_PEER_SCAN_INTERVAL_MIN, strTemp)) // Minimum for min is 60 seconds. - PEER_SCAN_INTERVAL_MIN = MAX(60, boost::lexical_cast(strTemp)); + PEER_SCAN_INTERVAL_MIN = std::max(60, boost::lexical_cast(strTemp)); if (sectionSingleB(secConfig, SECTION_PEER_START_MAX, strTemp)) - PEER_START_MAX = MAX(1, boost::lexical_cast(strTemp)); + PEER_START_MAX = std::max(1, boost::lexical_cast(strTemp)); if (sectionSingleB(secConfig, SECTION_PEER_CONNECT_LOW_WATER, strTemp)) - PEER_CONNECT_LOW_WATER = MAX(1, boost::lexical_cast(strTemp)); + PEER_CONNECT_LOW_WATER = std::max(1, boost::lexical_cast(strTemp)); if (sectionSingleB(secConfig, SECTION_NETWORK_QUORUM, strTemp)) - NETWORK_QUORUM = MAX(0, boost::lexical_cast(strTemp)); + NETWORK_QUORUM = std::max(0, boost::lexical_cast(strTemp)); if (sectionSingleB(secConfig, SECTION_VALIDATION_QUORUM, strTemp)) - VALIDATION_QUORUM = MAX(0, boost::lexical_cast(strTemp)); + VALIDATION_QUORUM = std::max(0, boost::lexical_cast(strTemp)); if (sectionSingleB(secConfig, SECTION_FEE_ACCOUNT_CREATE, strTemp)) FEE_ACCOUNT_CREATE = boost::lexical_cast(strTemp); diff --git a/src/ConnectionPool.cpp b/src/ConnectionPool.cpp index 14e5604841..acceef4887 100644 --- a/src/ConnectionPool.cpp +++ b/src/ConnectionPool.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "Config.h" #include "Peer.h" @@ -645,7 +646,7 @@ void ConnectionPool::scanRefresh() (void) mScanTimer.cancel(); - iInterval = MAX(iInterval, theConfig.PEER_SCAN_INTERVAL_MIN); + iInterval = std::max(iInterval, theConfig.PEER_SCAN_INTERVAL_MIN); tpNext = tpNow + boost::posix_time::seconds(iInterval); diff --git a/src/utils.h b/src/utils.h index f11b82a1b7..91c5ff9b36 100644 --- a/src/utils.h +++ b/src/utils.h @@ -16,14 +16,6 @@ #define ADDRESS(p) strHex(uint64( ((char*) p) - ((char*) 0))) #define ADDRESS_SHARED(p) strHex(uint64( ((char*) (p).get()) - ((char*) 0))) -#ifndef MAX -#define MAX(x,y) ((x) < (y) ? (y) : (x)) -#endif - -#ifndef MIN -#define MIN(x,y) ((x) > (y) ? (y) : (x)) -#endif - #define isSetBit(x,y) (!!((x) & (y))) #ifdef WIN32 From 69de9f9ce2829f3609191b242540051b80b15c2e Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 31 Aug 2012 14:05:37 -0700 Subject: [PATCH 156/426] Progress toward ripple pre restructuring forward. --- src/TransactionEngine.cpp | 323 +++++++++++++++++++++++--------------- 1 file changed, 199 insertions(+), 124 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index dfecf4489c..a99b4088fa 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -861,7 +861,9 @@ SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint25 mNodes.entryCache(sleEntry); } else if (action == taaDELETE) + { assert(false); + } } return sleEntry; @@ -2106,7 +2108,7 @@ TER TransactionEngine::calcNodeOfferRev( // Although the fee varies based upon the next offer it does not matter as the offer maker knows in // advance that they are obligated to pay a transfer fee of necessary. The owner of next offer has no // expectation of a quality in being applied. - SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); + SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); // ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip), uCurCurrencyID); // For correct ratio unsigned int uEntry = 0; uint256 uNxtIndex; @@ -2197,7 +2199,12 @@ TER TransactionEngine::calcNodeOfferRev( return terResult; } -// Offer input and output is issuer or limbo. +// - Offer input is limbo. +// - Current offers consumed. +// - Current offer owners debited. +// - Transfer fees credited to issuer. +// - Payout to issuer or limbo. +// - Deliver is set without transfer fees. TER TransactionEngine::calcNodeOfferFwd( const unsigned int uIndex, // 0 < uIndex < uLast const PathState::pointer& pspCur, @@ -2205,7 +2212,7 @@ TER TransactionEngine::calcNodeOfferFwd( ) { TER terResult = tepPATH_DRY; - +#if 0 paymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; paymentNode& pnCur = pspCur->vpnNodes[uIndex]; paymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; @@ -2234,19 +2241,29 @@ TER TransactionEngine::calcNodeOfferFwd( bool bNxtOffer = !uNxtAccountID; uint256 uNxtTip; uint256 uNxtEnd; - bool bNxtDirAdvance; - bool bNxtSubAdvance; - unsigned int uNxtEntry = 0; - uint256 uNxtIndex; SLE::pointer sleNxtDir; + bool bNxtDirAdvance; + bool bNxtEntryDirty; + bool bNxtEntryAdvance; + unsigned int uNxtEntry; // Next nodes index. + uint256 uNxtIndex; // Next offer. + boost::unordered_map umNxtBalance; // Account valances. + STAmount saNxtOfrFunds; + STAmount saNxtOfrIn; + STAmount saNxtOfrOut; + SLE::pointer sleNxtOfr; + uint160 uNxtOfrAccountID; + STAmount saNxtFeeRate; + bool bNxtFee; if (bNxtOffer) { - uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); - uNxtEnd = Ledger::getQualityNext(uNxtTip); - sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); - bNxtDirAdvance = !sleNxtDir; - bNxtSubAdvance = true; + uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); + uNxtEnd = Ledger::getQualityNext(uNxtTip); + sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); + bNxtDirAdvance = !sleNxtDir; + uNxtEntry = 0; + bNxtEntryAdvance = true; } while (!!uDirectTip && saPrvDlvAct != saPrvDlvReq) // Have a quality and not done. @@ -2289,8 +2306,8 @@ TER TransactionEngine::calcNodeOfferFwd( } // Allowed to access source from this node? - curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine); - bool bFoundForward = itAllow != pspCur->umForward.end(); + curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine); + const bool bFoundForward = itAllow != pspCur->umForward.end(); if (bFoundForward || itAllow->second != uIndex) { @@ -2301,7 +2318,7 @@ TER TransactionEngine::calcNodeOfferFwd( continue; } - const STAmount& saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets); + const STAmount saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets); STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. STAmount saCurOfrSpent; @@ -2315,7 +2332,7 @@ TER TransactionEngine::calcNodeOfferFwd( continue; } - const STAmount& saCurOfrInReq = sleOffer->getIValueFieldAmount(sfTakerPays); + const STAmount saCurOfrInReq = sleOffer->getIValueFieldAmount(sfTakerPays); STAmount saCurOfrInMax = std::min(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); STAmount saCurOfrInAct; STAmount saCurOfrOutAct; @@ -2355,100 +2372,155 @@ TER TransactionEngine::calcNodeOfferFwd( { // Next is an offer node. // Need to step through next offer's nodes to figure out fees. + STAmount saNxtOfrRate; + bool bDirectoryFirst = true; while (!!uNxtTip && saCurOfrInAct != saCurOfrInMax) // A next offer may be available and have more to do. { - if (bNxtDirAdvance) + if (!bNxtDirAdvance) { - uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd); - bNxtSubAdvance = true; - bNxtDirAdvance = false; - uNxtEntry = 0; - if (!!uNxtTip) - sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); + // Current directory is fine. + nothing(); } - - if (!!uNxtTip) + else if (bDirectoryFirst || bMultiQuality) { - // Do a directory. - // - Drive on computing saCurDlvAct to derive saPrvDlvAct. -// ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip)); // For correct ratio + if (bDirectoryFirst) + bDirectoryFirst = false; - while (saCurOfrInAct != saCurOfrInMax) // Have more to do. + uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd); + if (!!uNxtTip) { - if (!bNxtSubAdvance) - { - // Continue with current uNxtIndex. - nothing(); - } - else if (dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex)) - { - // Found a next uNxtIndex. - bNxtSubAdvance = false; - } - else - { - // No more offers in directory. - bNxtDirAdvance = true; - break; - } + saNxtOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip)); // For correct ratio + sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); - SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex); - const uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); - const STAmount& saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); - const STAmount& saNxtOfrOut = sleNxtOfr->getIValueFieldAmount(sfTakerGets); + assert(!!sleNxtDir); - const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID - ? saOne - : saTransferRate; - const bool bFee = saFeeRate != saOne; - - bool bNxtExpired = sleNxtOfr->getIFieldPresent(sfExpiration) - && sleNxtOfr->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC(); - STAmount saNxtOfrFunds = accountFunds(uNxtOfrAccountID, saNxtOfrOut); // Funds left. - - if (!bNxtExpired && saNxtOfrFunds.isPositive()) - { - // Offer is not expired and is funded. - const STAmount saInBase = saCurOfrInMax-saCurOfrInAct; - const STAmount saOutPass = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID); - STAmount saOutBase = std::min(saCurOfrOutReq, saOutPass); // Limit offer out by needed. - saOutBase = std::min(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. - const STAmount saOutCost = std::min( - bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutBase, - saCurOfrFunds); // Limit cost by fees & funds. - const STAmount saOutDlvPass= bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; // Out amount after fees. - const STAmount saInDlvPass = STAmount::multiply(saOutDlvPass, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required. - - // XXX Check fees. - sleNxtOfr->setIFieldAmount(sfTakerGets, saNxtOfrIn - saInDlvPass); - sleNxtOfr->setIFieldAmount(sfTakerPays, saNxtOfrOut - saOutDlvPass); - - if (saNxtOfrOut == saOutDlvPass) { - // Consumed all of offer. - Log(lsINFO) << "calcNodeOfferFwd: offer consumed"; - - pspCur->vUnfundedBecame.push_back(uNxtIndex); // Mark offer for deletion on use of current path state. - - bNxtSubAdvance = true; - } - - saCurOfrSpent += saOutDlvPass; // XXX Check. - - saCurOfrInAct += saInDlvPass; // Add to input handled. - - saCurOfrOutAct += saOutDlvPass; // Add to output handled. - } + bNxtDirAdvance = false; + uNxtEntry = 0; + bNxtEntryAdvance = true; + } + else + { + // No more next offers. Should be done rather than fall off end of book. + Log(lsINFO) << "Unreachable."; + assert(false); } } + else + { + // Don't do another directory. + break; + } - // Do another nxt directory iff bMultiQuality - if (!bMultiQuality) - uNxtTip = 0; + if (!bNxtEntryAdvance) + { + // Current next directory is fine. + nothing(); + } + else if (dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex)) + { + // Found a next uNxtIndex. + bNxtEntryAdvance = false; + bNxtEntryDirty = true; + } + else + { + // No more offers in nxt directory. + bNxtDirAdvance = true; + continue; + } + + if (bNxtEntryDirty) + { + sleNxtOfr = entryCache(ltOFFER, uNxtIndex); + + if (sleNxtOfr->getIFieldPresent(sfExpiration) + && sleNxtOfr->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + { + // Offer is expired. + bNxtEntryAdvance = true; + continue; + } + + uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); + + saNxtFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID + ? saOne + : saTransferRate; + + bNxtFee = saNxtFeeRate != saOne; + + boost::unordered_map::const_iterator itNxtBalance = umNxtBalance.find(uNxtOfrAccountID); + saNxtOfrFunds = itNxtBalance == umNxtBalance.end() + ? accountFunds(uNxtOfrAccountID, saNxtOfrOut) + : it->second; + + saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); + saNxtOfrOut = sleNxtOfr->getIValueFieldAmount(sfTakerGets); + + // Cost (payout + fees) to next offer owner if offer is fully redeem. + STAmount saNxtOutCost = STAmount::multiply(saNxtOfrOut, saNxtFeeRate, saNxtOfrOut.getCurrency(), saNxtOfrOut.getIssuer()); + + if (saNxtOfrOut > saNxtOfrFunds) + { + // Limit offer by funds available. + STAmount saNxtOutMax = STAmount::divide(saNxtOfrOut, saNxtFeeRate, uCurCurrencyID, uCurIssuerID); + + } + + bNxtEntryDirty = false; + } + + if (!saNxtOfrFunds.isPositive()) + { + // Offer is unfunded. + bNxtEntryAdvance = true; + continue; + } + + STAmount saNxtOutAvail = + // Driving amount of input. + const STAmount saInBase = saCurOfrInMax-saCurOfrInAct; + + // Desired amount of output not including fees. + const STAmount saOutReq = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID); + STAmount saOutBase = std::min( + std::min(saCurOfrOutReq, saOutReq), // Limit offer out by needed. + saNxtOfrIn); // Limit offer out by supplying offer. + // Limit cost by fees & funds. + const STAmount saOutCost = std::min( + bNxtFee + ? STAmount::multiply(saOutBase, saNxtFeeRate, uCurCurrencyID, uCurIssuerID) + : saOutBase, + saCurOfrFunds); + // Compute output minus fees. Fees are offer's obligation and not passed to input. + const STAmount saOutDlvPass= bNxtFee + ? STAmount::divide(saOutCost, saNxtFeeRate, uCurCurrencyID, uCurIssuerID) + : saOutCost; + // Compute input based on output minus fees. + const STAmount saInDlvPass = STAmount::multiply(saOutDlvPass, saOfrRate, uPrvCurrencyID, uCurIssuerID); + + // XXX Check fees. + sleNxtOfr->setIFieldAmount(sfTakerGets, saNxtOfrIn - saInDlvPass); + sleNxtOfr->setIFieldAmount(sfTakerPays, saNxtOfrOut - saOutDlvPass); + + if (saNxtOfrOut == saOutDlvPass) { + // Consumed all of offer. + // XXX Move to outside. + Log(lsINFO) << "calcNodeOfferFwd: offer consumed"; + + pspCur->vUnfundedBecame.push_back(uNxtIndex); // Mark offer for deletion on use of current path state. + + bNxtEntryAdvance = true; + } + + umNxtBalance[uNxtOfrAccountID] = saNxtOfrFunds; + + saCurOfrSpent += saOutDlvPass; // XXX Check. + + saCurOfrInAct += saInDlvPass; // Add to input handled. + + saCurOfrOutAct += saOutDlvPass; // Add to output handled. } // Deliver output to limbo or currency issuer. @@ -2487,6 +2559,9 @@ TER TransactionEngine::calcNodeOfferFwd( } return !!saCurDlvAct ? tesSUCCESS : terResult; +#else + return terResult; +#endif } #if 0 @@ -2815,12 +2890,12 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS paymentNode& pnCur = pspCur->vpnNodes[uIndex]; paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - const bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem); - const bool bPrvRedeem = !!(pnPrv.uFlags & STPathElement::typeRedeem); - const bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue); - const bool bPrvIssue = !!(pnPrv.uFlags & STPathElement::typeIssue); - const bool bPrvAccount = !uIndex || !!(pnPrv.uFlags & STPathElement::typeAccount); - const bool bNxtAccount = uIndex == uLast || !!(pnNxt.uFlags & STPathElement::typeAccount); + const bool bRedeem = isSetBit(pnCur.uFlags, STPathElement::typeRedeem); + const bool bPrvRedeem = isSetBit(pnPrv.uFlags, STPathElement::typeRedeem); + const bool bIssue = isSetBit(pnCur.uFlags, STPathElement::typeIssue); + const bool bPrvIssue = isSetBit(pnPrv.uFlags, STPathElement::typeIssue); + const bool bPrvAccount = !uIndex || isSetBit(pnPrv.uFlags, STPathElement::typeAccount); + const bool bNxtAccount = uIndex == uLast || isSetBit(pnNxt.uFlags, STPathElement::typeAccount); const uint160& uCurAccountID = pnCur.uAccountID; const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; @@ -3143,10 +3218,10 @@ TER TransactionEngine::calcNodeAccountFwd( paymentNode& pnCur = pspCur->vpnNodes[uIndex]; paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - const bool bRedeem = !!(pnCur.uFlags & STPathElement::typeRedeem); - const bool bIssue = !!(pnCur.uFlags & STPathElement::typeIssue); - const bool bPrvAccount = !!(pnPrv.uFlags & STPathElement::typeAccount); - const bool bNxtAccount = !!(pnNxt.uFlags & STPathElement::typeAccount); + const bool bRedeem = isSetBit(pnCur.uFlags, STPathElement::typeRedeem); + const bool bIssue = isSetBit(pnCur.uFlags, STPathElement::typeIssue); + const bool bPrvAccount = isSetBit(pnPrv.uFlags, STPathElement::typeAccount); + const bool bNxtAccount = isSetBit(pnNxt.uFlags, STPathElement::typeAccount); const uint160& uCurAccountID = pnCur.uAccountID; const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; @@ -3477,15 +3552,15 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint const bool bFirst = vpnNodes.empty(); const paymentNode& pnPrv = bFirst ? paymentNode() : vpnNodes.back(); // true, iff node is a ripple account. false, iff node is an offer node. - const bool bAccount = !!(iType & STPathElement::typeAccount); + const bool bAccount = isSetBit(iType, STPathElement::typeAccount); // true, iff currency supplied. // Currency is specified for the output of the current node. - const bool bCurrency = !!(iType & STPathElement::typeCurrency); + const bool bCurrency = isSetBit(iType, STPathElement::typeCurrency); // Issuer is specified for the output of the current node. - const bool bIssuer = !!(iType & STPathElement::typeIssuer); + const bool bIssuer = isSetBit(iType, STPathElement::typeIssuer); // true, iff account is allowed to redeem it's IOUs to next node. - const bool bRedeem = !!(iType & STPathElement::typeRedeem); - const bool bIssue = !!(iType & STPathElement::typeIssue); + const bool bRedeem = isSetBit(iType, STPathElement::typeRedeem); + const bool bIssue = isSetBit(iType, STPathElement::typeIssue); TER terResult = tesSUCCESS; pnCur.uFlags = iType; @@ -3520,7 +3595,7 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint if (tesSUCCESS == terResult && !vpnNodes.empty()) { const paymentNode& pnBck = vpnNodes.back(); - bool bBckAccount = !!(pnBck.uFlags & STPathElement::typeAccount); + bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); if (bBckAccount) { @@ -3595,8 +3670,8 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint { // Verify that previous account is allowed to issue. const paymentNode& pnBck = vpnNodes.back(); - bool bBckAccount = !!(pnBck.uFlags & STPathElement::typeAccount); - bool bBckIssue = !!(pnBck.uFlags & STPathElement::typeIssue); + bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); + bool bBckIssue = isSetBit(pnBck.uFlags, STPathElement::typeIssue); if (bBckAccount && !bBckIssue) { @@ -3795,15 +3870,15 @@ Json::Value PathState::getJson() const TER TransactionEngine::calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) { const paymentNode& pnCur = pspCur->vpnNodes[uIndex]; - const bool bCurAccount = !!(pnCur.uFlags & STPathElement::typeAccount); + const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); TER terResult; Log(lsINFO) << boost::str(boost::format("calcNode> uIndex=%d") % uIndex); // Do current node reverse. terResult = bCurAccount - ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) - : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); + ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) + : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); // Do previous. if (tesSUCCESS == terResult && uIndex) @@ -3815,8 +3890,8 @@ TER TransactionEngine::calcNode(const unsigned int uIndex, const PathState::poin if (tesSUCCESS == terResult) { terResult = bCurAccount - ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) - : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); + ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) + : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); } Log(lsINFO) << boost::str(boost::format("calcNode< uIndex=%d terResult=%d") % uIndex % terResult); @@ -3860,9 +3935,9 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) { // Ripple if source or destination is non-native or if there are paths. const uint32 uTxFlags = txn.getFlags(); - const bool bCreate = !!(uTxFlags & tfCreateAccount); - const bool bNoRippleDirect = !!(uTxFlags & tfNoRippleDirect); - const bool bPartialPayment = !!(uTxFlags & tfPartialPayment); + const bool bCreate = isSetBit(uTxFlags, tfCreateAccount); + const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect); + const bool bPartialPayment = isSetBit(uTxFlags, tfPartialPayment); const bool bPaths = txn.getITFieldPresent(sfPaths); const bool bMax = txn.getITFieldPresent(sfSendMax); const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); @@ -4458,7 +4533,7 @@ TER TransactionEngine::doOfferCreate(const SerializedTransaction& txn) { Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); const uint32 txFlags = txn.getFlags(); - const bool bPassive = !!(txFlags & tfPassive); + const bool bPassive = isSetBit(txFlags, tfPassive); STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText(); From c3603c403d98d13347d6d553873db7d5787ace14 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 31 Aug 2012 14:47:31 -0700 Subject: [PATCH 157/426] Code to determine how old a proposal is. Low-level code to remove a peer from the consensus process. --- src/LedgerConsensus.cpp | 19 +++++++++++++++++++ src/LedgerConsensus.h | 2 ++ src/LedgerProposal.cpp | 7 ++++--- src/LedgerProposal.h | 5 +++-- 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 980e0be376..a0ae08095b 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -161,6 +161,18 @@ void LCTransaction::setVote(const uint160& peer, bool votesYes) } } +void LCTransaction::unVote(const uint160& peer) +{ + boost::unordered_map::iterator it = mVotes.find(peer); + if (it != mVotes.end()) + { + if (it->second) + --mYays; + else + --mNays; + } +} + bool LCTransaction::updatePosition(int percentTime, bool proposing) { // this many seconds after close, should our position change if (mOurPosition && (mNays == 0)) @@ -766,6 +778,13 @@ bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) return true; } +void LedgerConsensus::removePeer(const uint160& peerID) +{ + mPeerPositions.erase(peerID); + BOOST_FOREACH(u256_lct_pair& it, mDisputes) + it.second->unVote(peerID); +} + bool LedgerConsensus::peerHasSet(const Peer::pointer& peer, const uint256& hashSet, newcoin::TxSetStatus status) { if (status != newcoin::tsHAVE) // Indirect requests are for future support diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 31ffdf06c9..e4e71da0ab 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -64,6 +64,7 @@ public: Serializer& peekTransaction() { return transaction; } void setVote(const uint160& peer, bool votesYes); + void unVote(const uint160& peer); bool updatePosition(int percentTime, bool proposing); }; @@ -171,6 +172,7 @@ public: bool haveConsensus(); bool peerPosition(const LedgerProposal::pointer&); + void removePeer(const uint160& peerID); void deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic); bool peerHasSet(const Peer::pointer& peer, const uint256& set, newcoin::TxSetStatus status); diff --git a/src/LedgerProposal.cpp b/src/LedgerProposal.cpp index 70d9458f6c..cb3ef93ec6 100644 --- a/src/LedgerProposal.cpp +++ b/src/LedgerProposal.cpp @@ -9,14 +9,14 @@ LedgerProposal::LedgerProposal(const uint256& pLgr, uint32 seq, const uint256& tx, uint32 closeTime, const NewcoinAddress& naPeerPublic) : - mPreviousLedger(pLgr), mCurrentHash(tx), mCloseTime(closeTime), mProposeSeq(seq) + mPreviousLedger(pLgr), mCurrentHash(tx), mCloseTime(closeTime), mProposeSeq(seq), mPublicKey(naPeerPublic) { - mPublicKey = naPeerPublic; // XXX Validate key. // if (!mKey->SetPubKey(pubKey)) // throw std::runtime_error("Invalid public key in proposal"); mPeerID = mPublicKey.getNodeID(); + mTime = boost::posix_time::second_clock::universal_time(); } @@ -27,12 +27,13 @@ LedgerProposal::LedgerProposal(const NewcoinAddress& naSeed, const uint256& prev mPublicKey = NewcoinAddress::createNodePublic(naSeed); mPrivateKey = NewcoinAddress::createNodePrivate(naSeed); mPeerID = mPublicKey.getNodeID(); + mTime = boost::posix_time::second_clock::universal_time(); } LedgerProposal::LedgerProposal(const uint256& prevLgr, const uint256& position, uint32 closeTime) : mPreviousLedger(prevLgr), mCurrentHash(position), mCloseTime(closeTime), mProposeSeq(0) { - ; + mTime = boost::posix_time::second_clock::universal_time(); } uint256 LedgerProposal::getSigningHash() const diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index 70d4bbbe7a..3ecd39efeb 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -22,7 +22,8 @@ protected: NewcoinAddress mPublicKey; NewcoinAddress mPrivateKey; // If ours - std::string mSignature; // set only if needed + std::string mSignature; // set only if needed + boost::posix_time::ptime mTime; public: @@ -55,7 +56,7 @@ public: void setPrevLedger(const uint256& prevLedger) { mPreviousLedger = prevLedger; } void setSignature(const std::string& signature) { mSignature = signature; } - + const boost::posix_time::ptime getCreateTime() { return mTime; } void changePosition(const uint256& newPosition, uint32 newCloseTime); Json::Value getJson() const; From ad12e318ba8cbb24a73b6a6c89e2524368b81046 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 31 Aug 2012 15:51:41 -0700 Subject: [PATCH 158/426] Allow a peer position to be removed from the consensus logic if the peer is not responding. This version uses static timing. A peer takes a position every 12 seconds and a position is valid for 20 seconds. It might make sense to either make that timing adaptive or include a "validity time" field in the position. However, I think this is really only going to be an issue in fairly small networks (which is why we are seeing it). --- src/LedgerConsensus.cpp | 48 +++++++++++++++++++++++++---------------- src/LedgerConsensus.h | 1 - src/LedgerProposal.cpp | 5 +++-- src/LedgerProposal.h | 2 ++ src/LedgerTiming.h | 6 ++++++ 5 files changed, 41 insertions(+), 21 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index a0ae08095b..e4d91b83e8 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -534,10 +534,34 @@ void LedgerConsensus::timerEntry() void LedgerConsensus::updateOurPositions() { + boost::posix_time::ptime peerCutoff = boost::posix_time::second_clock::universal_time(); + boost::posix_time::ptime ourCutoff = peerCutoff - boost::posix_time::seconds(PROPOSE_INTERVAL); + peerCutoff -= boost::posix_time::seconds(PROPOSE_FRESHNESS); + bool changes = false; SHAMap::pointer ourPosition; std::vector addedTx, removedTx; + // Verify freshness of peer positions and compute close times + std::map closeTimes; + boost::unordered_map::iterator + it = mPeerPositions.begin(), end = mPeerPositions.end(); + while (it != end) + { + if (it->second->isStale(peerCutoff)) + { // proposal is stale + uint160 peerID = it->second->getPeerID(); + BOOST_FOREACH(u256_lct_pair& it, mDisputes) + it.second->unVote(peerID); + mPeerPositions.erase(it++); + } + else + { // proposal is still fresh + ++closeTimes[it->second->getCloseTime() - (it->second->getCloseTime() % mCloseResolution)]; + ++it; + } + } + BOOST_FOREACH(u256_lct_pair& it, mDisputes) { if (it.second->updatePosition(mClosePercent, mProposing)) @@ -560,10 +584,6 @@ void LedgerConsensus::updateOurPositions() } } - std::map closeTimes; - - BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) - ++closeTimes[it.second->getCloseTime() - (it.second->getCloseTime() % mCloseResolution)]; int neededWeight; if (mClosePercent < AV_MID_CONSENSUS_TIME) @@ -605,13 +625,12 @@ void LedgerConsensus::updateOurPositions() } } - if (closeTime != (mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution))) - { - if (!changes) - { - ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); - changes = true; - } + if ((!changes) && + ((closeTime != (mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution))) || + (mOurPosition->isStale(ourCutoff)))) + { // close time changed or our position is stale + ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); + changes = true; } if (changes) @@ -778,13 +797,6 @@ bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) return true; } -void LedgerConsensus::removePeer(const uint160& peerID) -{ - mPeerPositions.erase(peerID); - BOOST_FOREACH(u256_lct_pair& it, mDisputes) - it.second->unVote(peerID); -} - bool LedgerConsensus::peerHasSet(const Peer::pointer& peer, const uint256& hashSet, newcoin::TxSetStatus status) { if (status != newcoin::tsHAVE) // Indirect requests are for future support diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index e4e71da0ab..7736c3a5f3 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -172,7 +172,6 @@ public: bool haveConsensus(); bool peerPosition(const LedgerProposal::pointer&); - void removePeer(const uint160& peerID); void deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic); bool peerHasSet(const Peer::pointer& peer, const uint256& set, newcoin::TxSetStatus status); diff --git a/src/LedgerProposal.cpp b/src/LedgerProposal.cpp index cb3ef93ec6..d96b397434 100644 --- a/src/LedgerProposal.cpp +++ b/src/LedgerProposal.cpp @@ -56,8 +56,9 @@ bool LedgerProposal::checkSign(const std::string& signature, const uint256& sign void LedgerProposal::changePosition(const uint256& newPosition, uint32 closeTime) { - mCurrentHash = newPosition; - mCloseTime = closeTime; + mCurrentHash = newPosition; + mCloseTime = closeTime; + mTime = boost::posix_time::second_clock::universal_time(); ++mProposeSeq; } diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index 3ecd39efeb..6bb833cc2d 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -56,7 +56,9 @@ public: void setPrevLedger(const uint256& prevLedger) { mPreviousLedger = prevLedger; } void setSignature(const std::string& signature) { mSignature = signature; } + const boost::posix_time::ptime getCreateTime() { return mTime; } + bool isStale(boost::posix_time::ptime cutoff) { return mTime > cutoff; } void changePosition(const uint256& newPosition, uint32 newCloseTime); Json::Value getJson() const; diff --git a/src/LedgerTiming.h b/src/LedgerTiming.h index bed4673319..2a8fb207a2 100644 --- a/src/LedgerTiming.h +++ b/src/LedgerTiming.h @@ -28,6 +28,12 @@ // How often we check state or change positions (in milliseconds) # define LEDGER_GRANULARITY 1000 +// How long we consider a proposal fresh +# define PROPOSE_FRESHNESS 20 + +// How often we force generating a new proposal to keep ours fresh +# define PROPOSE_INTERVAL 12 + // Avalanche tuning #define AV_INIT_CONSENSUS_PCT 50 // percentage of nodes on our UNL that must vote yes From 9ef0a5491b1f7c684783e5bfbe78caa819b2b47f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 31 Aug 2012 18:11:41 -0700 Subject: [PATCH 159/426] Use "Ledger::ref" instead of "const Ledger::pointer&". --- src/Ledger.cpp | 2 +- src/Ledger.h | 5 +++-- src/LedgerConsensus.cpp | 9 +++++---- src/LedgerConsensus.h | 8 ++++---- src/LedgerEntrySet.cpp | 10 +++++----- src/LedgerEntrySet.h | 10 +++++----- src/LedgerMaster.cpp | 8 ++++---- src/LedgerMaster.h | 8 ++++---- src/NetworkOPs.cpp | 10 +++++----- src/NetworkOPs.h | 10 +++++----- src/Peer.h | 10 +++++----- src/TransactionEngine.cpp | 2 +- src/TransactionEngine.h | 10 +++++----- 13 files changed, 52 insertions(+), 50 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 7895f81b98..a24ca1fbc7 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -258,7 +258,7 @@ uint256 Ledger::getHash() return(mHash); } -void Ledger::saveAcceptedLedger(const Ledger::pointer& ledger) +void Ledger::saveAcceptedLedger(Ledger::ref ledger) { static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers where LedgerSeq = %d;"); static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %d;"); diff --git a/src/Ledger.h b/src/Ledger.h index dd8a770805..4ab62f7445 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -41,7 +41,8 @@ class Ledger : public boost::enable_shared_from_this { // The basic Ledger structure, can be opened, closed, or synching friend class TransactionEngine; public: - typedef boost::shared_ptr pointer; + typedef boost::shared_ptr pointer; + typedef const boost::shared_ptr& ref; enum TransResult { @@ -161,7 +162,7 @@ public: SLE::pointer getAccountRoot(const NewcoinAddress& naAccountID); // database functions - static void saveAcceptedLedger(const Ledger::pointer&); + static void saveAcceptedLedger(Ledger::ref); static Ledger::pointer loadByIndex(uint32 ledgerIndex); static Ledger::pointer loadByHash(const uint256& ledgerHash); diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index e4d91b83e8..3c85ebe7ee 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -207,7 +207,7 @@ bool LCTransaction::updatePosition(int percentTime, bool proposing) return true; } -LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, const Ledger::pointer& previousLedger, uint32 closeTime) +LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::ref previousLedger, uint32 closeTime) : mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger), mCurrentMSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false) { @@ -551,6 +551,7 @@ void LedgerConsensus::updateOurPositions() if (it->second->isStale(peerCutoff)) { // proposal is stale uint160 peerID = it->second->getPeerID(); + Log(lsWARNING) << "Removing stale proposal from " << peerID.GetHex(); BOOST_FOREACH(u256_lct_pair& it, mDisputes) it.second->unVote(peerID); mPeerPositions.erase(it++); @@ -870,7 +871,7 @@ void LedgerConsensus::playbackProposals() } void LedgerConsensus::applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn, - const Ledger::pointer& ledger, CanonicalTXSet& failedTransactions, bool openLedger) + Ledger::ref ledger, CanonicalTXSet& failedTransactions, bool openLedger) { TransactionEngineParams parms = openLedger ? tapOPEN_LEDGER : tapNONE; #ifndef TRUST_NETWORK @@ -902,8 +903,8 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, const Serializ #endif } -void LedgerConsensus::applyTransactions(const SHAMap::pointer& set, const Ledger::pointer& applyLedger, - const Ledger::pointer& checkLedger, CanonicalTXSet& failedTransactions, bool openLgr) +void LedgerConsensus::applyTransactions(const SHAMap::pointer& set, Ledger::ref applyLedger, + Ledger::ref checkLedger, CanonicalTXSet& failedTransactions, bool openLgr) { TransactionEngineParams parms = openLgr ? tapOPEN_LEDGER : tapNONE; TransactionEngine engine(applyLedger); diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 7736c3a5f3..d5e55ac0cc 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -131,10 +131,10 @@ protected: void addPosition(LedgerProposal&, bool ours); void removePosition(LedgerProposal&, bool ours); void sendHaveTxSet(const uint256& set, bool direct); - void applyTransactions(const SHAMap::pointer& transactionSet, const Ledger::pointer& targetLedger, - const Ledger::pointer& checkLedger, CanonicalTXSet& failedTransactions, bool openLgr); + void applyTransactions(const SHAMap::pointer& transactionSet, Ledger::ref targetLedger, + Ledger::ref checkLedger, CanonicalTXSet& failedTransactions, bool openLgr); void applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn, - const Ledger::pointer& targetLedger, CanonicalTXSet& failedTransactions, bool openLgr); + Ledger::ref targetLedger, CanonicalTXSet& failedTransactions, bool openLgr); // manipulating our own position void statusChange(newcoin::NodeEvent, Ledger& ledger); @@ -146,7 +146,7 @@ protected: void endConsensus(); public: - LedgerConsensus(const uint256& prevLCLHash, const Ledger::pointer& previousLedger, uint32 closeTime); + LedgerConsensus(const uint256& prevLCLHash, Ledger::ref previousLedger, uint32 closeTime); int startup(); Json::Value getJson(); diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 7015a7b76f..722527fe41 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -230,7 +230,7 @@ Json::Value LedgerEntrySet::getJson(int) const return ret; } -SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::pointer& ledger, +SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::ref ledger, boost::unordered_map& newMods) { boost::unordered_map::iterator it = mEntries.find(node); @@ -259,7 +259,7 @@ SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::pointer& led } -bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::pointer& ledger, +bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::ref ledger, boost::unordered_map& newMods) { SLE::pointer sle = getForMod(Ledger::getAccountRootIndex(threadTo.getAccountID()), ledger, newMods); @@ -268,7 +268,7 @@ bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddres return threadTx(metaNode, sle, ledger, newMods); } -bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::pointer& ledger, +bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::ref ledger, boost::unordered_map& newMods) { // node = the node that was modified/deleted/created // threadTo = the node that needs to know @@ -282,7 +282,7 @@ bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::pointer& threa return false; } -bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::pointer& ledger, +bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::ref ledger, boost::unordered_map& newMods) { // thread new or modified node to owner or owners if (node->hasOneOwner()) // thread to owner's account @@ -295,7 +295,7 @@ bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::pointer& n return false; } -void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::pointer& origLedger) +void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger) { // calculate the raw meta data and return it. This must be called before the set is committed // Entries modified only as a result of building the transaction metadata diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index da66cda2d2..cfd6f13193 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -38,16 +38,16 @@ protected: LedgerEntrySet(const boost::unordered_map &e, const TransactionMetaSet& s, int m) : mEntries(e), mSet(s), mSeq(m) { ; } - SLE::pointer getForMod(const uint256& node, Ledger::pointer& ledger, + SLE::pointer getForMod(const uint256& node, Ledger::ref ledger, boost::unordered_map& newMods); - bool threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::pointer& ledger, + bool threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::ref ledger, boost::unordered_map& newMods); - bool threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::pointer& ledger, + bool threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::ref ledger, boost::unordered_map& newMods); - bool threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::pointer& ledger, + bool threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::ref ledger, boost::unordered_map& newMods); public: @@ -72,7 +72,7 @@ public: void entryModify(const SLE::pointer&); // This entry will be modified Json::Value getJson(int) const; - void calcRawMeta(Serializer&, Ledger::pointer& originalLedger); + void calcRawMeta(Serializer&, Ledger::ref originalLedger); // iterator functions bool isEmpty() const { return mEntries.empty(); } diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp index 7228ff6b96..93e8724637 100644 --- a/src/LedgerMaster.cpp +++ b/src/LedgerMaster.cpp @@ -19,7 +19,7 @@ bool LedgerMaster::addHeldTransaction(const Transaction::pointer& transaction) return mHeldTransactionsByID.insert(std::make_pair(transaction->getID(), transaction)).second; } -void LedgerMaster::pushLedger(const Ledger::pointer& newLedger) +void LedgerMaster::pushLedger(Ledger::ref newLedger) { // Caller should already have properly assembled this ledger into "ready-to-close" form -- // all candidate transactions must already be appled @@ -35,7 +35,7 @@ void LedgerMaster::pushLedger(const Ledger::pointer& newLedger) mEngine.setLedger(newLedger); } -void LedgerMaster::pushLedger(const Ledger::pointer& newLCL, const Ledger::pointer& newOL) +void LedgerMaster::pushLedger(Ledger::ref newLCL, Ledger::ref newOL) { assert(newLCL->isClosed() && newLCL->isAccepted()); assert(!newOL->isClosed() && !newOL->isAccepted()); @@ -54,7 +54,7 @@ void LedgerMaster::pushLedger(const Ledger::pointer& newLCL, const Ledger::point mEngine.setLedger(newOL); } -void LedgerMaster::switchLedgers(const Ledger::pointer& lastClosed, const Ledger::pointer& current) +void LedgerMaster::switchLedgers(Ledger::ref lastClosed, Ledger::ref current) { assert(lastClosed && current); mFinalizedLedger = lastClosed; @@ -66,7 +66,7 @@ void LedgerMaster::switchLedgers(const Ledger::pointer& lastClosed, const Ledger mEngine.setLedger(mCurrentLedger); } -void LedgerMaster::storeLedger(const Ledger::pointer& ledger) +void LedgerMaster::storeLedger(Ledger::ref ledger) { mLedgerHistory.addLedger(ledger); } diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h index f3e58d5ba6..8db6f34490 100644 --- a/src/LedgerMaster.h +++ b/src/LedgerMaster.h @@ -48,11 +48,11 @@ public: TER doTransaction(const SerializedTransaction& txn, uint32 targetLedger, TransactionEngineParams params); - void pushLedger(const Ledger::pointer& newLedger); - void pushLedger(const Ledger::pointer& newLCL, const Ledger::pointer& newOL); - void storeLedger(const Ledger::pointer&); + void pushLedger(Ledger::ref newLedger); + void pushLedger(Ledger::ref newLCL, Ledger::ref newOL); + void storeLedger(Ledger::ref); - void switchLedgers(const Ledger::pointer& lastClosed, const Ledger::pointer& newCurrent); + void switchLedgers(Ledger::ref lastClosed, Ledger::ref newCurrent); Ledger::pointer closeLedger(); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 06d4b64a5f..d5af469891 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -798,7 +798,7 @@ Json::Value NetworkOPs::getServerInfo() // Monitoring: publisher side // -Json::Value NetworkOPs::pubBootstrapAccountInfo(const Ledger::pointer& lpAccepted, const NewcoinAddress& naAccountID) +Json::Value NetworkOPs::pubBootstrapAccountInfo(Ledger::ref lpAccepted, const NewcoinAddress& naAccountID) { Json::Value jvObj(Json::objectValue); @@ -833,7 +833,7 @@ void NetworkOPs::pubAccountInfo(const NewcoinAddress& naAccountID, const Json::V } } -void NetworkOPs::pubLedger(const Ledger::pointer& lpAccepted) +void NetworkOPs::pubLedger(Ledger::ref lpAccepted) { { boost::interprocess::sharable_lock sl(mMonitorLock); @@ -946,7 +946,7 @@ Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terRes return jvObj; } -void NetworkOPs::pubTransactionAll(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState) +void NetworkOPs::pubTransactionAll(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState) { Json::Value jvObj = transJson(stTxn, terResult, pState, lpCurrent->getLedgerSeq(), "transaction"); @@ -956,7 +956,7 @@ void NetworkOPs::pubTransactionAll(const Ledger::pointer& lpCurrent, const Seria } } -void NetworkOPs::pubTransactionAccounts(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState) +void NetworkOPs::pubTransactionAccounts(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState) { boost::unordered_set usisNotify; @@ -991,7 +991,7 @@ void NetworkOPs::pubTransactionAccounts(const Ledger::pointer& lpCurrent, const } } -void NetworkOPs::pubTransaction(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TER terResult) +void NetworkOPs::pubTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult) { boost::interprocess::sharable_lock sl(mMonitorLock); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 5e53b98194..f4dac510cb 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -78,10 +78,10 @@ protected: void setMode(OperatingMode); Json::Value transJson(const SerializedTransaction& stTxn, TER terResult, const std::string& strStatus, int iSeq, const std::string& strType); - void pubTransactionAll(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState); - void pubTransactionAccounts(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState); + void pubTransactionAll(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState); + void pubTransactionAccounts(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState); - Json::Value pubBootstrapAccountInfo(const Ledger::pointer& lpAccepted, const NewcoinAddress& naAccountID); + Json::Value pubBootstrapAccountInfo(Ledger::ref lpAccepted, const NewcoinAddress& naAccountID); public: NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster); @@ -195,8 +195,8 @@ public: // void pubAccountInfo(const NewcoinAddress& naAccountID, const Json::Value& jvObj); - void pubLedger(const Ledger::pointer& lpAccepted); - void pubTransaction(const Ledger::pointer& lpLedger, const SerializedTransaction& stTxn, TER terResult); + void pubLedger(Ledger::ref lpAccepted); + void pubTransaction(Ledger::ref lpLedger, const SerializedTransaction& stTxn, TER terResult); // // Monitoring: subscriber side diff --git a/src/Peer.h b/src/Peer.h index 85666c9c69..7bfe692977 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -141,19 +141,19 @@ public: bool samePeer(const Peer& p) { return this == &p; } void sendPacket(const PackedMessage::pointer& packet); - void sendLedgerProposal(const Ledger::pointer& ledger); - void sendFullLedger(const Ledger::pointer& ledger); + void sendLedgerProposal(Ledger::ref ledger); + void sendFullLedger(Ledger::ref ledger); void sendGetFullLedger(uint256& hash); void sendGetPeers(); void punishPeer(PeerPunish pp); Json::Value getJson(); - bool isConnected() const { return mHelloed && !mDetaching; } + bool isConnected() const { return mHelloed && !mDetaching; } - uint256 getClosedLedgerHash() const { return mClosedLedgerHash; } + uint256 getClosedLedgerHash() const { return mClosedLedgerHash; } bool hasLedger(const uint256& hash) const; - NewcoinAddress getNodePublic() const { return mNodePublic; } + NewcoinAddress getNodePublic() const { return mNodePublic; } void cycleStatus() { mPreviousLedgerHash = mClosedLedgerHash; mClosedLedgerHash.zero(); } }; diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index a99b4088fa..aa58296949 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -3691,7 +3691,7 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint } PathState::PathState( - const Ledger::pointer& lpLedger, + Ledger::ref lpLedger, const int iIndex, const LedgerEntrySet& lesSource, const STPath& spSourcePath, diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 149c6289b7..9747850e6b 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -202,7 +202,7 @@ public: STAmount saOutAct; // Amount actually sent (calc output). PathState( - const Ledger::pointer& lpLedger, + Ledger::ref lpLedger, const int iIndex, const LedgerEntrySet& lesSource, const STPath& spSourcePath, @@ -216,7 +216,7 @@ public: Json::Value getJson() const; static PathState::pointer createPathState( - const Ledger::pointer& lpLedger, + Ledger::ref lpLedger, const int iIndex, const LedgerEntrySet& lesSource, const STPath& spSourcePath, @@ -337,10 +337,10 @@ protected: public: TransactionEngine() { ; } - TransactionEngine(const Ledger::pointer& ledger) : mLedger(ledger) { assert(mLedger); } + TransactionEngine(Ledger::ref ledger) : mLedger(ledger) { assert(mLedger); } - Ledger::pointer getLedger() { return mLedger; } - void setLedger(const Ledger::pointer& ledger) { assert(ledger); mLedger = ledger; } + Ledger::pointer getLedger() { return mLedger; } + void setLedger(Ledger::ref ledger) { assert(ledger); mLedger = ledger; } TER applyTransaction(const SerializedTransaction&, TransactionEngineParams); }; From 02bd898e519e4218f19fcac229267dcf0270e133 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 31 Aug 2012 18:26:45 -0700 Subject: [PATCH 160/426] Some const-correctness. const SLE::pointer & -> SLE::ref --- src/AccountState.cpp | 2 +- src/AccountState.h | 2 +- src/ConnectionPool.cpp | 8 ++++---- src/ConnectionPool.h | 8 ++++---- src/Ledger.cpp | 2 +- src/Ledger.h | 2 +- src/LedgerAcquire.cpp | 10 +++++----- src/LedgerAcquire.h | 14 +++++++------- src/LedgerConsensus.cpp | 12 ++++++------ src/LedgerConsensus.h | 14 +++++++------- src/LedgerEntrySet.cpp | 12 ++++++------ src/LedgerEntrySet.h | 14 +++++++------- src/NetworkOPs.cpp | 8 ++++---- src/Peer.cpp | 2 +- src/Peer.h | 23 ++++++++++++----------- src/SerializedLedger.h | 13 +++++++------ 16 files changed, 74 insertions(+), 72 deletions(-) diff --git a/src/AccountState.cpp b/src/AccountState.cpp index b48bcbd131..774e4247db 100644 --- a/src/AccountState.cpp +++ b/src/AccountState.cpp @@ -21,7 +21,7 @@ AccountState::AccountState(const NewcoinAddress& naAccountID) : mAccountID(naAcc mValid = true; } -AccountState::AccountState(const SerializedLedgerEntry::pointer& ledgerEntry, const NewcoinAddress& naAccountID) : +AccountState::AccountState(SLE::ref ledgerEntry, const NewcoinAddress& naAccountID) : mAccountID(naAccountID), mLedgerEntry(ledgerEntry), mValid(false) { if (!mLedgerEntry) diff --git a/src/AccountState.h b/src/AccountState.h index 1a3de87095..5559990a72 100644 --- a/src/AccountState.h +++ b/src/AccountState.h @@ -29,7 +29,7 @@ private: public: AccountState(const NewcoinAddress& naAccountID); // For new accounts - AccountState(const SerializedLedgerEntry::pointer& ledgerEntry,const NewcoinAddress& naAccountI); // For accounts in a ledger + AccountState(SLE::ref ledgerEntry,const NewcoinAddress& naAccountI); // For accounts in a ledger bool bHaveAuthorizedKey() { diff --git a/src/ConnectionPool.cpp b/src/ConnectionPool.cpp index acceef4887..ed196af6c6 100644 --- a/src/ConnectionPool.cpp +++ b/src/ConnectionPool.cpp @@ -340,7 +340,7 @@ std::vector ConnectionPool::getPeerVector() // Now know peer's node public key. Determine if we want to stay connected. // <-- bNew: false = redundant -bool ConnectionPool::peerConnected(const Peer::pointer& peer, const NewcoinAddress& naPeer, +bool ConnectionPool::peerConnected(Peer::ref peer, const NewcoinAddress& naPeer, const std::string& strIP, int iPort) { bool bNew = false; @@ -399,7 +399,7 @@ bool ConnectionPool::peerConnected(const Peer::pointer& peer, const NewcoinAddre } // We maintain a map of public key to peer for connected and verified peers. Maintain it. -void ConnectionPool::peerDisconnected(const Peer::pointer& peer, const NewcoinAddress& naPeer) +void ConnectionPool::peerDisconnected(Peer::ref peer, const NewcoinAddress& naPeer) { if (naPeer.isValid()) { @@ -486,7 +486,7 @@ bool ConnectionPool::peerScanSet(const std::string& strIp, int iPort) } // --> strIp: not empty -void ConnectionPool::peerClosed(const Peer::pointer& peer, const std::string& strIp, int iPort) +void ConnectionPool::peerClosed(Peer::ref peer, const std::string& strIp, int iPort) { ipPort ipPeer = make_pair(strIp, iPort); bool bScanRefresh = false; @@ -541,7 +541,7 @@ void ConnectionPool::peerClosed(const Peer::pointer& peer, const std::string& st scanRefresh(); } -void ConnectionPool::peerVerified(const Peer::pointer& peer) +void ConnectionPool::peerVerified(Peer::ref peer) { if (mScanning && mScanning == peer) { diff --git a/src/ConnectionPool.h b/src/ConnectionPool.h index b7983b751b..bb13d06436 100644 --- a/src/ConnectionPool.h +++ b/src/ConnectionPool.h @@ -72,16 +72,16 @@ public: // We know peers node public key. // <-- bool: false=reject - bool peerConnected(const Peer::pointer& peer, const NewcoinAddress& naPeer, const std::string& strIP, int iPort); + bool peerConnected(Peer::ref peer, const NewcoinAddress& naPeer, const std::string& strIP, int iPort); // No longer connected. - void peerDisconnected(const Peer::pointer& peer, const NewcoinAddress& naPeer); + void peerDisconnected(Peer::ref peer, const NewcoinAddress& naPeer); // As client accepted. - void peerVerified(const Peer::pointer& peer); + void peerVerified(Peer::ref peer); // As client failed connect and be accepted. - void peerClosed(const Peer::pointer& peer, const std::string& strIp, int iPort); + void peerClosed(Peer::ref peer, const std::string& strIp, int iPort); Json::Value getPeersJson(); std::vector getPeerVector(); diff --git a/src/Ledger.cpp b/src/Ledger.cpp index a24ca1fbc7..08fd23cd7a 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -508,7 +508,7 @@ void Ledger::setCloseTime(boost::posix_time::ptime ptm) } // XXX Use shared locks where possible? -LedgerStateParms Ledger::writeBack(LedgerStateParms parms, const SLE::pointer& entry) +LedgerStateParms Ledger::writeBack(LedgerStateParms parms, SLE::ref entry) { ScopedLock l(mAccountStateMap->Lock()); bool create = false; diff --git a/src/Ledger.h b/src/Ledger.h index 4ab62f7445..c671a57bf2 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -157,7 +157,7 @@ public: // high-level functions AccountState::pointer getAccountState(const NewcoinAddress& acctID); - LedgerStateParms writeBack(LedgerStateParms parms, const SLE::pointer&); + LedgerStateParms writeBack(LedgerStateParms parms, SLE::ref); SLE::pointer getAccountRoot(const uint160& accountID); SLE::pointer getAccountRoot(const NewcoinAddress& naAccountID); diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 949cc7e851..adeab57039 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -20,7 +20,7 @@ PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterva assert((mTimerInterval > 10) && (mTimerInterval < 30000)); } -void PeerSet::peerHas(const Peer::pointer& ptr) +void PeerSet::peerHas(Peer::ref ptr) { boost::recursive_mutex::scoped_lock sl(mLock); std::vector< boost::weak_ptr >::iterator it = mPeers.begin(); @@ -40,7 +40,7 @@ void PeerSet::peerHas(const Peer::pointer& ptr) newPeer(ptr); } -void PeerSet::badPeer(const Peer::pointer& ptr) +void PeerSet::badPeer(Peer::ref ptr) { boost::recursive_mutex::scoped_lock sl(mLock); std::vector< boost::weak_ptr >::iterator it = mPeers.begin(); @@ -142,7 +142,7 @@ void LedgerAcquire::addOnComplete(boost::function mLock.unlock(); } -void LedgerAcquire::trigger(const Peer::pointer& peer, bool timer) +void LedgerAcquire::trigger(Peer::ref peer, bool timer) { if (mAborted || mComplete || mFailed) return; @@ -257,7 +257,7 @@ void LedgerAcquire::trigger(const Peer::pointer& peer, bool timer) resetTimer(); } -void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL, const Peer::pointer& peer) +void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL, Peer::ref peer) { if (!peer) sendRequest(tmGL); @@ -435,7 +435,7 @@ void LedgerAcquireMaster::dropLedger(const uint256& hash) mLedgers.erase(hash); } -bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, const Peer::pointer& peer) +bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::ref peer) { #ifdef LA_DEBUG Log(lsTRACE) << "got data for acquiring ledger "; diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index ff92ad4ef8..6781eddf88 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -31,7 +31,7 @@ protected: virtual ~PeerSet() { ; } void sendRequest(const newcoin::TMGetLedger& message); - void sendRequest(const newcoin::TMGetLedger& message, const Peer::pointer& peer); + void sendRequest(const newcoin::TMGetLedger& message, Peer::ref peer); public: const uint256& getHash() const { return mHash; } @@ -41,12 +41,12 @@ public: void progress() { mProgress = true; } - void peerHas(const Peer::pointer&); - void badPeer(const Peer::pointer&); + void peerHas(Peer::ref); + void badPeer(Peer::ref); void resetTimer(); protected: - virtual void newPeer(const Peer::pointer&) = 0; + virtual void newPeer(Peer::ref) = 0; virtual void onTimer(void) = 0; virtual boost::weak_ptr pmDowncast() = 0; @@ -72,7 +72,7 @@ protected: void done(); void onTimer(); - void newPeer(const Peer::pointer& peer) { trigger(peer, false); } + void newPeer(Peer::ref peer) { trigger(peer, false); } boost::weak_ptr pmDowncast(); @@ -92,7 +92,7 @@ public: bool takeTxRootNode(const std::vector& data); bool takeAsNode(const std::list& IDs, const std::list >& data); bool takeAsRootNode(const std::vector& data); - void trigger(const Peer::pointer&, bool timer); + void trigger(Peer::ref, bool timer); }; class LedgerAcquireMaster @@ -108,7 +108,7 @@ public: LedgerAcquire::pointer find(const uint256& hash); bool hasLedger(const uint256& ledgerHash); void dropLedger(const uint256& ledgerHash); - bool gotLedgerData(newcoin::TMLedgerData& packet, const Peer::pointer&); + bool gotLedgerData(newcoin::TMLedgerData& packet, Peer::ref); }; #endif diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 3c85ebe7ee..2aacf34c47 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -45,7 +45,7 @@ boost::weak_ptr TransactionAcquire::pmDowncast() return boost::shared_polymorphic_downcast(shared_from_this()); } -void TransactionAcquire::trigger(const Peer::pointer& peer, bool timer) +void TransactionAcquire::trigger(Peer::ref peer, bool timer) { if (mComplete || mFailed) return; @@ -87,7 +87,7 @@ void TransactionAcquire::trigger(const Peer::pointer& peer, bool timer) } bool TransactionAcquire::takeNodes(const std::list& nodeIDs, - const std::list< std::vector >& data, const Peer::pointer& peer) + const std::list< std::vector >& data, Peer::ref peer) { if (mComplete) return true; @@ -286,7 +286,7 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash); std::vector peerList = theApp->getConnectionPool().getPeerVector(); bool found = false; - BOOST_FOREACH(Peer::pointer& peer, peerList) + BOOST_FOREACH(Peer::ref peer, peerList) { if (peer->hasLedger(mPrevLedgerHash)) { @@ -296,7 +296,7 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) } if (!found) { - BOOST_FOREACH(Peer::pointer& peer, peerList) + BOOST_FOREACH(Peer::ref peer, peerList) mAcquiringLedger->peerHas(peer); } mHaveCorrectLCL = false; @@ -798,7 +798,7 @@ bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) return true; } -bool LedgerConsensus::peerHasSet(const Peer::pointer& peer, const uint256& hashSet, newcoin::TxSetStatus status) +bool LedgerConsensus::peerHasSet(Peer::ref peer, const uint256& hashSet, newcoin::TxSetStatus status) { if (status != newcoin::tsHAVE) // Indirect requests are for future support return true; @@ -815,7 +815,7 @@ bool LedgerConsensus::peerHasSet(const Peer::pointer& peer, const uint256& hashS return true; } -bool LedgerConsensus::peerGaveNodes(const Peer::pointer& peer, const uint256& setHash, +bool LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { boost::unordered_map::iterator acq = mAcquiring.find(setHash); diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index d5e55ac0cc..e8ae389ced 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -27,11 +27,11 @@ protected: SHAMap::pointer mMap; bool mHaveRoot; - void onTimer() { trigger(Peer::pointer(), true); } - void newPeer(const Peer::pointer& peer) { trigger(peer, false); } + void onTimer() { trigger(Peer::pointer(), true); } + void newPeer(Peer::ref peer) { trigger(peer, false); } void done(); - void trigger(const Peer::pointer&, bool timer); + void trigger(Peer::ref, bool timer); boost::weak_ptr pmDowncast(); public: @@ -41,7 +41,7 @@ public: SHAMap::pointer getMap() { return mMap; } bool takeNodes(const std::list& IDs, const std::list< std::vector >& data, - const Peer::pointer&); + Peer::ref); }; class LCTransaction @@ -119,7 +119,7 @@ protected: static void Saccept(boost::shared_ptr This, SHAMap::pointer txSet); void accept(const SHAMap::pointer& txSet); - void weHave(const uint256& id, const Peer::pointer& avoidPeer); + void weHave(const uint256& id, Peer::ref avoidPeer); void startAcquiring(const TransactionAcquire::pointer&); SHAMap::pointer find(const uint256& hash); @@ -174,9 +174,9 @@ public: bool peerPosition(const LedgerProposal::pointer&); void deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic); - bool peerHasSet(const Peer::pointer& peer, const uint256& set, newcoin::TxSetStatus status); + bool peerHasSet(Peer::ref peer, const uint256& set, newcoin::TxSetStatus status); - bool peerGaveNodes(const Peer::pointer& peer, const uint256& setHash, + bool peerGaveNodes(Peer::ref peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); }; diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 722527fe41..2f31478bd2 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -61,7 +61,7 @@ LedgerEntryAction LedgerEntrySet::hasEntry(const uint256& index) const return it->second.mAction; } -void LedgerEntrySet::entryCache(const SLE::pointer& sle) +void LedgerEntrySet::entryCache(SLE::ref sle) { boost::unordered_map::iterator it = mEntries.find(sle->getIndex()); if (it == mEntries.end()) @@ -82,7 +82,7 @@ void LedgerEntrySet::entryCache(const SLE::pointer& sle) } } -void LedgerEntrySet::entryCreate(const SLE::pointer& sle) +void LedgerEntrySet::entryCreate(SLE::ref sle) { boost::unordered_map::iterator it = mEntries.find(sle->getIndex()); if (it == mEntries.end()) @@ -112,7 +112,7 @@ void LedgerEntrySet::entryCreate(const SLE::pointer& sle) } } -void LedgerEntrySet::entryModify(const SLE::pointer& sle) +void LedgerEntrySet::entryModify(SLE::ref sle) { boost::unordered_map::iterator it = mEntries.find(sle->getIndex()); if (it == mEntries.end()) @@ -147,7 +147,7 @@ void LedgerEntrySet::entryModify(const SLE::pointer& sle) } } -void LedgerEntrySet::entryDelete(const SLE::pointer& sle, bool unfunded) +void LedgerEntrySet::entryDelete(SLE::ref sle, bool unfunded) { boost::unordered_map::iterator it = mEntries.find(sle->getIndex()); if (it == mEntries.end()) @@ -268,7 +268,7 @@ bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddres return threadTx(metaNode, sle, ledger, newMods); } -bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::ref ledger, +bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map& newMods) { // node = the node that was modified/deleted/created // threadTo = the node that needs to know @@ -282,7 +282,7 @@ bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::pointer& threa return false; } -bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::ref ledger, +bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::ref node, Ledger::ref ledger, boost::unordered_map& newMods) { // thread new or modified node to owner or owners if (node->hasOneOwner()) // thread to owner's account diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index cfd6f13193..0ab19896b9 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -24,7 +24,7 @@ public: LedgerEntryAction mAction; int mSeq; - LedgerEntrySetEntry(const SLE::pointer& e, LedgerEntryAction a, int s) : mEntry(e), mAction(a), mSeq(s) { ; } + LedgerEntrySetEntry(SLE::ref e, LedgerEntryAction a, int s) : mEntry(e), mAction(a), mSeq(s) { ; } }; @@ -44,10 +44,10 @@ protected: bool threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::ref ledger, boost::unordered_map& newMods); - bool threadTx(TransactionMetaNode& metaNode, SLE::pointer& threadTo, Ledger::ref ledger, + bool threadTx(TransactionMetaNode& metaNode, SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map& newMods); - bool threadOwners(TransactionMetaNode& metaNode, SLE::pointer& node, Ledger::ref ledger, + bool threadOwners(TransactionMetaNode& metaNode, SLE::ref node, Ledger::ref ledger, boost::unordered_map& newMods); public: @@ -66,10 +66,10 @@ public: // basic entry functions SLE::pointer getEntry(const uint256& index, LedgerEntryAction&); LedgerEntryAction hasEntry(const uint256& index) const; - void entryCache(const SLE::pointer&); // Add this entry to the cache - void entryCreate(const SLE::pointer&); // This entry will be created - void entryDelete(const SLE::pointer&, bool unfunded); - void entryModify(const SLE::pointer&); // This entry will be modified + void entryCache(SLE::ref); // Add this entry to the cache + void entryCreate(SLE::ref); // This entry will be created + void entryDelete(SLE::ref, bool unfunded); + void entryModify(SLE::ref); // This entry will be modified Json::Value getJson(int) const; void calcRawMeta(Serializer&, Ledger::ref originalLedger); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index d5af469891..a250d8c2ab 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -444,7 +444,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis ourVC.highNode = theApp->getWallet().getNodePublic(); } - BOOST_FOREACH(const Peer::pointer& it, peerList) + BOOST_FOREACH(Peer::ref it, peerList) { if (!it) { @@ -522,7 +522,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis { // add more peers int count = 0; std::vector peers=theApp->getConnectionPool().getPeerVector(); - BOOST_FOREACH(const Peer::pointer& it, peerList) + BOOST_FOREACH(Peer::ref it, peerList) { if (it->getClosedLedgerHash() == closedLedger) { @@ -532,7 +532,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis } if (!count) { // just ask everyone - BOOST_FOREACH(const Peer::pointer& it, peerList) + BOOST_FOREACH(Peer::ref it, peerList) if (it->isConnected()) mAcquiringLedger->peerHas(it); } @@ -691,7 +691,7 @@ void NetworkOPs::endConsensus(bool correctLCL) Log(lsTRACE) << "Ledger " << deadLedger.GetHex() << " is now dead"; theApp->getValidations().addDeadLedger(deadLedger); std::vector peerList = theApp->getConnectionPool().getPeerVector(); - BOOST_FOREACH(const Peer::pointer& it, peerList) + BOOST_FOREACH(Peer::ref it, peerList) if (it && (it->getClosedLedgerHash() == deadLedger)) { Log(lsTRACE) << "Killing obsolete peer status"; diff --git a/src/Peer.cpp b/src/Peer.cpp index 1ca2d8fa58..40b243f865 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -140,7 +140,7 @@ void Peer::handleVerifyTimer(const boost::system::error_code& ecResult) // Begin trying to connect. We are not connected till we know and accept peer's public key. // Only takes IP addresses (not domains). -void Peer::connect(const std::string strIp, int iPort) +void Peer::connect(const std::string& strIp, int iPort) { int iPortAct = (iPort <= 0) ? SYSTEM_PEER_PORT : iPort; diff --git a/src/Peer.h b/src/Peer.h index 7bfe692977..13c5fdb2de 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -24,13 +24,14 @@ typedef std::pair ipPort; class Peer : public boost::enable_shared_from_this { public: - typedef boost::shared_ptr pointer; + typedef boost::shared_ptr pointer; + typedef const boost::shared_ptr& ref; static const int psbGotHello = 0, psbSentHello = 1, psbInMap = 2, psbTrusted = 3; static const int psbNoLedgers = 4, psbNoTransactions = 5, psbDownLevel = 6; void handleConnect(const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it); - static void sHandleConnect(const Peer::pointer& ptr, const boost::system::error_code& error, + static void sHandleConnect(Peer::ref ptr, const boost::system::error_code& error, boost::asio::ip::tcp::resolver::iterator it) { ptr->handleConnect(error, it); } @@ -50,11 +51,11 @@ private: boost::asio::deadline_timer mVerifyTimer; void handleStart(const boost::system::error_code& ecResult); - static void sHandleStart(const Peer::pointer& ptr, const boost::system::error_code& ecResult) + static void sHandleStart(Peer::ref ptr, const boost::system::error_code& ecResult) { ptr->handleStart(ecResult); } void handleVerifyTimer(const boost::system::error_code& ecResult); - static void sHandleVerifyTimer(const Peer::pointer& ptr, const boost::system::error_code& ecResult) + static void sHandleVerifyTimer(Peer::ref ptr, const boost::system::error_code& ecResult) { ptr->handleVerifyTimer(ecResult); } protected: @@ -68,19 +69,19 @@ protected: Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx); void handleShutdown(const boost::system::error_code& error) { ; } - static void sHandleShutdown(const Peer::pointer& ptr, const boost::system::error_code& error) + static void sHandleShutdown(Peer::ref ptr, const boost::system::error_code& error) { ptr->handleShutdown(error); } void handle_write(const boost::system::error_code& error, size_t bytes_transferred); - static void sHandle_write(const Peer::pointer& ptr, const boost::system::error_code& error, size_t bytes_transferred) + static void sHandle_write(Peer::ref ptr, const boost::system::error_code& error, size_t bytes_transferred) { ptr->handle_write(error, bytes_transferred); } void handle_read_header(const boost::system::error_code& error); - static void sHandle_read_header(const Peer::pointer& ptr, const boost::system::error_code& error) + static void sHandle_read_header(Peer::ref ptr, const boost::system::error_code& error) { ptr->handle_read_header(error); } void handle_read_body(const boost::system::error_code& error); - static void sHandle_read_body(const Peer::pointer& ptr, const boost::system::error_code& error) + static void sHandle_read_body(Peer::ref ptr, const boost::system::error_code& error) { ptr->handle_read_body(error); } void processReadBuffer(); @@ -134,11 +135,11 @@ public: return mSocketSsl.lowest_layer(); } - void connect(const std::string strIp, int iPort); + void connect(const std::string& strIp, int iPort); void connected(const boost::system::error_code& error); void detach(const char *); - bool samePeer(const Peer::pointer& p) { return samePeer(*p); } - bool samePeer(const Peer& p) { return this == &p; } + bool samePeer(Peer::ref p) { return samePeer(*p); } + bool samePeer(const Peer& p) { return this == &p; } void sendPacket(const PackedMessage::pointer& packet); void sendLedgerProposal(Ledger::ref ledger); diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index 21faba8c35..1069887cc2 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -8,14 +8,15 @@ class SerializedLedgerEntry : public SerializedType { public: - typedef boost::shared_ptr pointer; + typedef boost::shared_ptr pointer; + typedef const boost::shared_ptr& ref; protected: - uint256 mIndex; - LedgerEntryType mType; - STUInt16 mVersion; - STObject mObject; - const LedgerEntryFormat* mFormat; + uint256 mIndex; + LedgerEntryType mType; + STUInt16 mVersion; + STObject mObject; + const LedgerEntryFormat* mFormat; SerializedLedgerEntry* duplicate() const { return new SerializedLedgerEntry(*this); } From 3bd054748e0d7ae0eac1e113aa1c95325e039996 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 1 Sep 2012 00:53:40 -0700 Subject: [PATCH 161/426] Fix a vulnerability. Someone could see a ledger proposal and send us a malformed version of that ledger proposal that failed our validity check but was similar enough to the real proposal to trick us into suppressing that proposal as a duplicate. --- src/NetworkOPs.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index a250d8c2ab..71737638c0 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -607,10 +607,12 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint // XXX Take a vuc for pubkey. // Get a preliminary hash to use to suppress duplicates - Serializer s(128); + Serializer s(256); + s.add256(proposeHash); s.add32(proposeSeq); - s.add32(getCurrentLedgerID()); + s.add32(closeTime); s.addRaw(pubKey); + s.addRaw(signature); if (!theApp->isNew(s.getSHA512Half())) return false; From 3005d46b1246d75021fad5475367d591ea7ba0ac Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 1 Sep 2012 01:01:28 -0700 Subject: [PATCH 162/426] Cleanup. --- src/Suppression.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Suppression.cpp b/src/Suppression.cpp index c285d5f349..4b7cad5711 100644 --- a/src/Suppression.cpp +++ b/src/Suppression.cpp @@ -1,6 +1,7 @@ - #include "Suppression.h" +#include + bool SuppressionTable::addSuppression(const uint160& suppression) { boost::mutex::scoped_lock sl(mSuppressionMutex); @@ -9,15 +10,16 @@ bool SuppressionTable::addSuppression(const uint160& suppression) return false; time_t now = time(NULL); + time_t expireTime = now - mHoldTime; - boost::unordered_map< time_t, std::list >::iterator it = mSuppressionTimes.begin(); - while (it != mSuppressionTimes.end()) + boost::unordered_map< time_t, std::list >::iterator + it = mSuppressionTimes.begin(), end = mSuppressionTimes.end(); + while (it != end) { - if ((it->first + mHoldTime) < now) + if (it->first <= expireTime) { - for (std::list::iterator lit = it->second.begin(), end = it->second.end(); - lit != end; ++lit) - mSuppressionMap.erase(*lit); + BOOST_FOREACH(const uint160& lit, it->second) + mSuppressionMap.erase(lit); it = mSuppressionTimes.erase(it); } else ++it; From 8d7773dcd63af57f181a9a8d2945448f702f8e60 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 1 Sep 2012 17:23:40 -0700 Subject: [PATCH 163/426] Remove unused variable. --- src/RPCServer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 58f74143fc..5c47ed30a3 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1341,7 +1341,6 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) STAmount saDstAmount; uint160 uDstCurrencyID; - std::vector vpnPath; STPathSet spsPaths; naSrcIssuerID.setAccountID(params[4u].asString()); // From 60653a5108531e1d2fefa291cb1920552174f21d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 1 Sep 2012 17:24:12 -0700 Subject: [PATCH 164/426] Add STAmount divide and multiply shortcuts. --- src/SerializedTypes.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 1017f758a3..065c6895d7 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -353,7 +353,16 @@ public: friend STAmount operator-(const STAmount& v1, const STAmount& v2); static STAmount divide(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID); + static STAmount divide(const STAmount& v1, const STAmount& v2, const STAmount& saUnit) + { return divide(v1, v2, saUnit.getCurrency(), saUnit.getIssuer()); } + static STAmount divide(const STAmount& v1, const STAmount& v2) + { return divide(v1, v2, v1); } + static STAmount multiply(const STAmount& v1, const STAmount& v2, const uint160& uCurrencyID, const uint160& uIssuerID); + static STAmount multiply(const STAmount& v1, const STAmount& v2, const STAmount& saUnit) + { return multiply(v1, v2, saUnit.getCurrency(), saUnit.getIssuer()); } + static STAmount multiply(const STAmount& v1, const STAmount& v2) + { return multiply(v1, v2, v1); } // Someone is offering X for Y, what is the rate? // Rate: smaller is better, the taker wants the most out: in/out From 93296048367cfef2b6ef873a6478c2782d632be3 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 1 Sep 2012 17:24:14 -0700 Subject: [PATCH 165/426] Restructure forward ripple through offers. --- src/TransactionEngine.cpp | 1555 +++++++++++++++++++------------------ src/TransactionEngine.h | 51 +- 2 files changed, 823 insertions(+), 783 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index a99b4088fa..b7cc2200d2 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1755,177 +1755,7 @@ TER TransactionEngine::doPasswordSet(const SerializedTransaction& txn) return terResult; } -#if 0 -// XXX Need to adjust for fees. -// Find offers to satisfy pnDst. -// - Does not adjust any balances as there is at least a forward pass to come. -// --> pnDst.saWanted: currency and amount wanted -// --> pnSrc.saIOURedeem.mCurrency: use this before saIOUIssue, limit to use. -// --> pnSrc.saIOUIssue.mCurrency: use this after saIOURedeem, limit to use. -// <-- pnDst.saReceive -// <-- pnDst.saIOUForgive -// <-- pnDst.saIOUAccept -// <-- terResult : tesSUCCESS = no error and if !bAllowPartial complelely satisfied wanted. -// <-> usOffersDeleteAlways: -// <-> usOffersDeleteOnSuccess: -TER calcOfferFill(paymentNode& pnSrc, paymentNode& pnDst, bool bAllowPartial) -{ - TER terResult; - - if (pnDst.saWanted.isNative()) - { - // Transfer stamps. - - STAmount saSrcFunds = pnSrc.saAccount->accountHolds(pnSrc.saAccount, uint160(0), uint160(0)); - - if (saSrcFunds && (bAllowPartial || saSrcFunds > pnDst.saWanted)) - { - pnSrc.saSend = min(saSrcFunds, pnDst.saWanted); - pnDst.saReceive = pnSrc.saSend; - } - else - { - terResult = terINSUF_PATH; - } - } - else - { - // Ripple funds. - - // Redeem to limit. - terResult = calcOfferFill( - accountHolds(pnSrc.saAccount, pnDst.saWanted.getCurrency(), pnDst.saWanted.getIssuer()), - pnSrc.saIOURedeem, - pnDst.saIOUForgive, - bAllowPartial); - - if (tesSUCCESS == terResult) - { - // Issue to wanted. - terResult = calcOfferFill( - pnDst.saWanted, // As much as wanted is available, limited by credit limit. - pnSrc.saIOUIssue, - pnDst.saIOUAccept, - bAllowPartial); - } - - if (tesSUCCESS == terResult && !bAllowPartial) - { - STAmount saTotal = pnDst.saIOUForgive + pnSrc.saIOUAccept; - - if (saTotal != saWanted) - terResult = terINSUF_PATH; - } - } - - return terResult; -} -#endif - -#if 0 -// Get the next offer limited by funding. -// - Stop when becomes unfunded. -void TransactionEngine::calcOfferBridgeNext( - const uint256& uBookRoot, // --> Which order book to look in. - const uint256& uBookEnd, // --> Limit of how far to look. - uint256& uBookDirIndex, // <-> Current directory. <-- 0 = no offer available. - uint64& uBookDirNode, // <-> Which node. 0 = first. - unsigned int& uBookDirEntry, // <-> Entry in node. 0 = first. - STAmount& saOfferIn, // <-- How much to pay in, fee inclusive, to get saOfferOut out. - STAmount& saOfferOut // <-- How much offer pays out. - ) -{ - saOfferIn = 0; // XXX currency & issuer - saOfferOut = 0; // XXX currency & issuer - - bool bDone = false; - - while (!bDone) - { - uint256 uOfferIndex; - - // Get uOfferIndex. - dirNext(uBookRoot, uBookEnd, uBookDirIndex, uBookDirNode, uBookDirEntry, uOfferIndex); - - SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - - uint160 uOfferOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); - STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); - STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); - - if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) - { - // Offer is expired. - Log(lsINFO) << "calcOfferFirst: encountered expired offer"; - } - else - { - STAmount saOfferFunds = accountFunds(uOfferOwnerID, saOfferPays); - // Outbound fees are paid by offer owner. - // XXX Calculate outbound fee rate. - - if (saOfferPays.isNative()) - { - // No additional fees for stamps. - - nothing(); - } - else if (saOfferPays.getIssuer() == uOfferOwnerID) - { - // Offerer is issue own IOUs. - // No fees at this exact point, XXX receiving node may charge a fee. - // XXX Make sure has a credit line with receiver, limit by credit line. - - nothing(); - // XXX Broken - could be issuing or redeeming or both. - } - else - { - // Offer must be redeeming IOUs. - - // No additional - // XXX Broken - } - - if (!saOfferFunds.isPositive()) - { - // Offer is unfunded. - Log(lsINFO) << "calcOfferFirst: offer unfunded: delete"; - } - else if (saOfferFunds >= saOfferPays) - { - // Offer fully funded. - - // Account transfering funds in to offer always pays inbound fees. - - saOfferIn = saOfferGets; // XXX Add in fees? - - saOfferOut = saOfferPays; - - bDone = true; - } - else - { - // Offer partially funded. - - // saOfferIn/saOfferFunds = saOfferGets/saOfferPays - // XXX Round such that all saOffer funds are exhausted. - saOfferIn = (saOfferFunds*saOfferGets)/saOfferPays; // XXX Add in fees? - saOfferOut = saOfferFunds; - - bDone = true; - } - } - - if (!bDone) - { - // musUnfundedFound.insert(uOfferIndex); - } - } - while (bNext); -} -#endif - +// XXX Need to track balances for offer funding. TER TransactionEngine::calcNodeOfferRev( const unsigned int uIndex, // 0 < uIndex < uLast const PathState::pointer& pspCur, @@ -1933,9 +1763,9 @@ TER TransactionEngine::calcNodeOfferRev( { TER terResult = tepPATH_DRY; - paymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; - paymentNode& pnCur = pspCur->vpnNodes[uIndex]; - paymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; const uint160& uPrvIssuerID = pnPrv.uIssuerID; @@ -1945,12 +1775,12 @@ TER TransactionEngine::calcNodeOfferRev( const uint160& uNxtIssuerID = pnNxt.uIssuerID; const uint160& uNxtAccountID = pnNxt.uAccountID; - const STAmount saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID)); - uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); const uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); + const STAmount& saTransferRate = pnCur.saTransferRate; + Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev> uIndex=%d prv=%s/%s cur=%s/%s nxt=%s/%s saTransferRate=%s") % uIndex % STAmount::createHumanCurrency(uPrvCurrencyID) @@ -2199,6 +2029,295 @@ TER TransactionEngine::calcNodeOfferRev( return terResult; } +// If needed, advance to next funded offer. +TER TransactionEngine::calcNodeAdvance( + const unsigned int uIndex, // 0 < uIndex < uLast + const PathState::pointer& pspCur, + const bool bMultiQuality) +{ + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; +// PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; + + const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; + const uint160& uPrvIssuerID = pnPrv.uIssuerID; + const uint160& uCurCurrencyID = pnCur.uCurrencyID; + const uint160& uCurIssuerID = pnCur.uIssuerID; +// const uint160& uNxtCurrencyID = pnNxt.uCurrencyID; +// const uint160& uNxtIssuerID = pnNxt.uIssuerID; + +// const uint160& uPrvAccountID = pnPrv.uAccountID; +// const uint160& uNxtAccountID = pnNxt.uAccountID; + + uint256& uDirectTip = pnCur.uDirectTip; + uint256 uDirectEnd = pnCur.uDirectEnd; + bool& bDirectAdvance = pnCur.bDirectAdvance; + SLE::pointer& sleDirectDir = pnCur.sleDirectDir; + STAmount& saOfrRate = pnCur.saOfrRate; + + bool& bEntryAdvance = pnCur.bEntryAdvance; + unsigned int& uEntry = pnCur.uEntry; + uint256& uOfferIndex = pnCur.uOfferIndex; + SLE::pointer& sleOffer = pnCur.sleOffer; + uint160& uOfrOwnerID = pnCur.uOfrOwnerID; + STAmount& saOfferFunds = pnCur.saOfferFunds; + STAmount& saTakerPays = pnCur.saTakerPays; + STAmount& saTakerGets = pnCur.saTakerGets; + bool& bFundsDirty = pnCur.bFundsDirty; + + TER terResult = tesSUCCESS; + + do + { + bool bDirectDirDirty = false; + + if (!pnCur.uDirectEnd) + { + // Need to initialize current node. + + uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); + uDirectEnd = Ledger::getQualityNext(uDirectTip); + sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); + bDirectAdvance = !sleDirectDir; + bDirectDirDirty = true; + } + + if (bDirectAdvance) + { + // Get next quality. + uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd); + bDirectDirDirty = true; + bDirectAdvance = false; + + if (!uDirectTip) + { + // No more offers. Should be done rather than fall off end of book. + Log(lsINFO) << "calcNodeAdvance: Unreachable: Fell off end of order book."; + assert(false); + } + } + + if (bDirectDirDirty) + { + saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio + uEntry = 0; + bEntryAdvance = true; + } + + if (!bEntryAdvance) + { + if (bFundsDirty) + { + saTakerPays = sleOffer->getIValueFieldAmount(sfTakerPays); + saTakerGets = sleOffer->getIValueFieldAmount(sfTakerGets); + + saOfferFunds = accountFunds(uOfrOwnerID, saTakerGets); // Funds left. + bFundsDirty = false; + } + } + else if (!dirNext(uDirectTip, sleDirectDir, uEntry, uOfferIndex)) + { + // Failed to find an entry in directory. + + uOfferIndex = 0; + + // Do another cur directory iff bMultiQuality + if (bMultiQuality) + { + bDirectAdvance = true; + } + else + { + assert(false); // Can't run out of offers in forward direction. + terResult = tefEXCEPTION; + } + } + else + { + // Got a new offer. + sleOffer = entryCache(ltOFFER, uOfferIndex); + uOfrOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + + const aciSource asLine = boost::make_tuple(uOfrOwnerID, uCurCurrencyID, uCurIssuerID); + + if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + { + // Offer is expired. + Log(lsINFO) << "calcNodeAdvance: expired offer"; + + assert(musUnfundedFound.find(uOfferIndex) != musUnfundedFound.end()); // Verify reverse found it too. + bEntryAdvance = true; + continue; + } + + // Allowed to access source from this node? + curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine); + const bool bFoundForward = itAllow != pspCur->umForward.end(); + + if (bFoundForward || itAllow->second != uIndex) + { + // Temporarily unfunded. Another node uses this source, ignore in this offer. + Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer"; + + bEntryAdvance = true; + continue; + } + + saTakerPays = sleOffer->getIValueFieldAmount(sfTakerPays); + saTakerGets = sleOffer->getIValueFieldAmount(sfTakerGets); + + saOfferFunds = accountFunds(uOfrOwnerID, saTakerGets); // Funds left. + + if (!saOfferFunds.isPositive()) + { + // Offer is unfunded. + Log(lsINFO) << "calcNodeAdvance: unfunded offer"; + + // YYY Could verify offer is correct place for unfundeds. + bEntryAdvance = true; + continue; + } + + bFundsDirty = false; + bEntryAdvance = false; + } + } + while (tesSUCCESS == terResult && (bEntryAdvance || bDirectAdvance)); + + return terResult; +} + +// Deliver maximum amount of funds from previous node. +// Goal: Make progress consuming the offer. +TER TransactionEngine::calcNodeDeliver( + const unsigned int uIndex, // 0 < uIndex < uLast + const PathState::pointer& 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. + STAmount& saInAct, // <-- Amount delivered. + STAmount& saInFees) // <-- Fees charged. +{ + TER terResult = tesSUCCESS; + + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; + + const uint160& uNxtAccountID = pnNxt.uAccountID; + const uint160& uCurIssuerID = pnCur.uIssuerID; + const uint160& uPrvIssuerID = pnPrv.uIssuerID; + const STAmount& saTransferRate = pnPrv.saTransferRate; + + saInAct = 0; + saInFees = 0; + + while (tesSUCCESS == terResult + && saInAct != saInReq // Did not deliver limit. + && saInAct + saInFees != saInFunds) // Did not deliver all funds. + { + terResult = calcNodeAdvance(uIndex, pspCur, bMultiQuality); // If needed, advance to next funded offer. + + if (tesSUCCESS == terResult) + { + bool& bEntryAdvance = pnCur.bEntryAdvance; + STAmount& saOfrRate = pnCur.saOfrRate; + uint256& uOfferIndex = pnCur.uOfferIndex; + SLE::pointer& sleOffer = pnCur.sleOffer; + const uint160& uOfrOwnerID = pnCur.uOfrOwnerID; + bool& bFundsDirty = pnCur.bFundsDirty; + STAmount& saOfferFunds = pnCur.saOfferFunds; + 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. + + // + // First calculate assuming no output fees. + // XXX Make sure derived in does not exceed actual saTakerPays + + 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 saInPassAct = STAmount::divide(saInSum, saInFeeRate); // In without fees. + STAmount saOutPassMax = STAmount::divide(saInPassAct, saOfrRate); // Out. + + STAmount saInPassFees; + STAmount saOutPassAct; + + if (!!uNxtAccountID) + { + // ? --> 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. + accountSend(uOfrOwnerID, uCurIssuerID, saOutPassMax); + + saOutPassAct = saOutPassMax; + } + else + { + // ? --> OFFER --> offer + STAmount saOutPassFees; + + terResult = TransactionEngine::calcNodeDeliver( + uIndex+1, + pspCur, + bMultiQuality, + uOfrOwnerID, + saOutPassMax, + saOutPassMax, + saOutPassAct, // <-- Amount delivered. + saOutPassFees); // <-- Fees charged. + + if (tesSUCCESS != terResult) + break; + + // Offer maximum in limited by next payout. + saInPassAct = STAmount::multiply(saOutPassAct, saOfrRate); + saInPassFees = STAmount::multiply(saInFunded, saInFeeRate)-saInPassAct; + } + + // Funds were spent. + bFundsDirty = true; + + // Credit issuer transfer fees. + accountSend(uInAccountID, uOfrOwnerID, saInPassFees); + + // Credit offer owner from offer. + accountSend(uInAccountID, uOfrOwnerID, saInPassAct); + + // Adjust offer + sleOffer->setIFieldAmount(sfTakerGets, saTakerGets - saOutPassAct); + sleOffer->setIFieldAmount(sfTakerPays, saTakerPays - saInPassAct); + + entryModify(sleOffer); + + if (saOutPassAct == saTakerGets) + { + // Offer became unfunded. + pspCur->vUnfundedBecame.push_back(uOfferIndex); + bEntryAdvance = true; + } + + saInAct += saInPassAct; + saInFees += saInPassFees; + } + } + + return terResult; +} + +// Called to drive the from the first offer node in a chain. // - Offer input is limbo. // - Current offers consumed. // - Current offer owners debited. @@ -2211,586 +2330,36 @@ TER TransactionEngine::calcNodeOfferFwd( const bool bMultiQuality ) { - TER terResult = tepPATH_DRY; -#if 0 - paymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; - paymentNode& pnCur = pspCur->vpnNodes[uIndex]; - paymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; + TER terResult; + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; - const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; - const uint160& uPrvIssuerID = pnPrv.uIssuerID; - const uint160& uCurCurrencyID = pnCur.uCurrencyID; - const uint160& uCurIssuerID = pnCur.uIssuerID; - const uint160& uNxtCurrencyID = pnNxt.uCurrencyID; - const uint160& uNxtIssuerID = pnNxt.uIssuerID; - - const uint160& uPrvAccountID = pnPrv.uAccountID; - const uint160& uNxtAccountID = pnNxt.uAccountID; - const STAmount saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID)); - - uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); - const uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); - bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); - - const STAmount& saPrvDlvReq = pnPrv.saFwdDeliver; // Forward driver. - STAmount saPrvDlvAct; - - STAmount& saCurDlvAct = pnCur.saFwdDeliver; // How much current node will deliver. - saCurDlvAct = 0; - - bool bNxtOffer = !uNxtAccountID; - uint256 uNxtTip; - uint256 uNxtEnd; - SLE::pointer sleNxtDir; - bool bNxtDirAdvance; - bool bNxtEntryDirty; - bool bNxtEntryAdvance; - unsigned int uNxtEntry; // Next nodes index. - uint256 uNxtIndex; // Next offer. - boost::unordered_map umNxtBalance; // Account valances. - STAmount saNxtOfrFunds; - STAmount saNxtOfrIn; - STAmount saNxtOfrOut; - SLE::pointer sleNxtOfr; - uint160 uNxtOfrAccountID; - STAmount saNxtFeeRate; - bool bNxtFee; - - if (bNxtOffer) + if (!!pnPrv.uAccountID) { - uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); - uNxtEnd = Ledger::getQualityNext(uNxtTip); - sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); - bNxtDirAdvance = !sleNxtDir; - uNxtEntry = 0; - bNxtEntryAdvance = true; - } - - while (!!uDirectTip && saPrvDlvAct != saPrvDlvReq) // Have a quality and not done. - { - if (bAdvance) - { - // Get next quality. - uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd); - } - else - { - bAdvance = true; - } - - if (!!uDirectTip) - { - // Do a directory. - // - Drive on computing saPrvDlvAct to derive saCurDlvAct. - SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); - STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio - unsigned int uEntry = 0; - uint256 uOfferIndex; - - while (saPrvDlvReq != saPrvDlvAct // Have not met request. - && dirNext(uDirectTip, sleDirectDir, uEntry, uOfferIndex)) - { - // Have an offer from the directory. - // Handle offers such that there is no need to look back to the previous nodes offers. - - SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - const uint160 uCurOfrAccountID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); - const aciSource asLine = boost::make_tuple(uCurOfrAccountID, uCurCurrencyID, uCurIssuerID); - if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) - { - // Offer is expired. - Log(lsINFO) << "calcNodeOfferFwd: expired offer"; - - assert(musUnfundedFound.find(uOfferIndex) != musUnfundedFound.end()); - continue; - } - - // Allowed to access source from this node? - curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine); - const bool bFoundForward = itAllow != pspCur->umForward.end(); - - if (bFoundForward || itAllow->second != uIndex) - { - // Temporarily unfunded. Another node uses this source, ignore in this node. - Log(lsINFO) << "calcNodeOfferFwd: temporarily unfunded offer"; - - nothing(); - continue; - } - - const STAmount saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets); - STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. - STAmount saCurOfrSpent; - - if (!saCurOfrFunds.isPositive()) - { - // Offer is unfunded. - Log(lsINFO) << "calcNodeOfferFwd: unfunded offer"; - - // YYY Could verify offer is correct place for unfundeds. - nothing(); - continue; - } - - const STAmount saCurOfrInReq = sleOffer->getIValueFieldAmount(sfTakerPays); - STAmount saCurOfrInMax = std::min(saCurOfrInReq, saPrvDlvReq-saPrvDlvAct); - STAmount saCurOfrInAct; - STAmount saCurOfrOutAct; - - if (!!uNxtAccountID) - { - // Next is an account node. - // If previous is an account, then inbound funds can be credited offer with no fees or quality. - // Transfer fees were previously handled. XXX Verify. - // If previous is an offer, then inbound funds are with issuer or in limbo. - - // The only fee ever charged is an output transfer fee. - const STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtAccountID == uCurIssuerID - ? saOne - : saTransferRate; - const bool bFee = saFeeRate != saOne; - - const STAmount saOutPass = STAmount::divide(saCurOfrInMax, saOfrRate, uCurCurrencyID, uCurIssuerID); - const STAmount saOutBase = std::min(saCurOfrOutReq, saOutPass); // Limit offer out by needed. - const STAmount saOutCostRaw= bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutBase; - const STAmount saOutCost = std::min(saOutCostRaw, saCurOfrFunds); // Limit cost by fees & funds. - - saCurOfrSpent = saOutCost; // XXX Check. - saCurOfrOutAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; // Out amount after fees. - - // Compute input w/o fees required. - saCurOfrInAct = STAmount::multiply(saCurOfrOutAct, saOfrRate, uPrvCurrencyID, uPrvIssuerID); - - // Deliver to output. - accountSend(uCurOfrAccountID, uNxtAccountID, saCurOfrOutAct); - } - else - { - // Next is an offer node. - // Need to step through next offer's nodes to figure out fees. - STAmount saNxtOfrRate; - bool bDirectoryFirst = true; - - while (!!uNxtTip && saCurOfrInAct != saCurOfrInMax) // A next offer may be available and have more to do. - { - if (!bNxtDirAdvance) - { - // Current directory is fine. - nothing(); - } - else if (bDirectoryFirst || bMultiQuality) - { - if (bDirectoryFirst) - bDirectoryFirst = false; - - uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd); - if (!!uNxtTip) - { - saNxtOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip)); // For correct ratio - sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); - - assert(!!sleNxtDir); - - bNxtDirAdvance = false; - uNxtEntry = 0; - bNxtEntryAdvance = true; - } - else - { - // No more next offers. Should be done rather than fall off end of book. - Log(lsINFO) << "Unreachable."; - assert(false); - } - } - else - { - // Don't do another directory. - break; - } - - if (!bNxtEntryAdvance) - { - // Current next directory is fine. - nothing(); - } - else if (dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex)) - { - // Found a next uNxtIndex. - bNxtEntryAdvance = false; - bNxtEntryDirty = true; - } - else - { - // No more offers in nxt directory. - bNxtDirAdvance = true; - continue; - } - - if (bNxtEntryDirty) - { - sleNxtOfr = entryCache(ltOFFER, uNxtIndex); - - if (sleNxtOfr->getIFieldPresent(sfExpiration) - && sleNxtOfr->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) - { - // Offer is expired. - bNxtEntryAdvance = true; - continue; - } - - uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); - - saNxtFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID - ? saOne - : saTransferRate; - - bNxtFee = saNxtFeeRate != saOne; - - boost::unordered_map::const_iterator itNxtBalance = umNxtBalance.find(uNxtOfrAccountID); - saNxtOfrFunds = itNxtBalance == umNxtBalance.end() - ? accountFunds(uNxtOfrAccountID, saNxtOfrOut) - : it->second; - - saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); - saNxtOfrOut = sleNxtOfr->getIValueFieldAmount(sfTakerGets); - - // Cost (payout + fees) to next offer owner if offer is fully redeem. - STAmount saNxtOutCost = STAmount::multiply(saNxtOfrOut, saNxtFeeRate, saNxtOfrOut.getCurrency(), saNxtOfrOut.getIssuer()); - - if (saNxtOfrOut > saNxtOfrFunds) - { - // Limit offer by funds available. - STAmount saNxtOutMax = STAmount::divide(saNxtOfrOut, saNxtFeeRate, uCurCurrencyID, uCurIssuerID); - - } - - bNxtEntryDirty = false; - } - - if (!saNxtOfrFunds.isPositive()) - { - // Offer is unfunded. - bNxtEntryAdvance = true; - continue; - } - - STAmount saNxtOutAvail = - // Driving amount of input. - const STAmount saInBase = saCurOfrInMax-saCurOfrInAct; - - // Desired amount of output not including fees. - const STAmount saOutReq = STAmount::divide(saInBase, saOfrRate, uCurCurrencyID, uCurIssuerID); - STAmount saOutBase = std::min( - std::min(saCurOfrOutReq, saOutReq), // Limit offer out by needed. - saNxtOfrIn); // Limit offer out by supplying offer. - // Limit cost by fees & funds. - const STAmount saOutCost = std::min( - bNxtFee - ? STAmount::multiply(saOutBase, saNxtFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutBase, - saCurOfrFunds); - // Compute output minus fees. Fees are offer's obligation and not passed to input. - const STAmount saOutDlvPass= bNxtFee - ? STAmount::divide(saOutCost, saNxtFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; - // Compute input based on output minus fees. - const STAmount saInDlvPass = STAmount::multiply(saOutDlvPass, saOfrRate, uPrvCurrencyID, uCurIssuerID); - - // XXX Check fees. - sleNxtOfr->setIFieldAmount(sfTakerGets, saNxtOfrIn - saInDlvPass); - sleNxtOfr->setIFieldAmount(sfTakerPays, saNxtOfrOut - saOutDlvPass); - - if (saNxtOfrOut == saOutDlvPass) { - // Consumed all of offer. - // XXX Move to outside. - Log(lsINFO) << "calcNodeOfferFwd: offer consumed"; - - pspCur->vUnfundedBecame.push_back(uNxtIndex); // Mark offer for deletion on use of current path state. - - bNxtEntryAdvance = true; - } - - umNxtBalance[uNxtOfrAccountID] = saNxtOfrFunds; - - saCurOfrSpent += saOutDlvPass; // XXX Check. - - saCurOfrInAct += saInDlvPass; // Add to input handled. - - saCurOfrOutAct += saOutDlvPass; // Add to output handled. - } - - // Deliver output to limbo or currency issuer. - accountSend( - uCurOfrAccountID, // Offer owner pays. - !!uCurIssuerID - ? uCurIssuerID // Output is non-XNS send to issuer. - : ACCOUNT_XNS, // Output is XNS send to limbo (ACCOUNT_XNS). - saCurOfrOutAct); - } - - // Deliver input to offer owner. - accountSend( - !!uPrvAccountID - ? uPrvAccountID // Previous is an account. Source is previous account. - : !!uPrvIssuerID - ? ACCOUNT_XNS // Previous is offer outputing XNS, source is limbo (ACCOUNT_XNS). - : uPrvIssuerID, // Previous is offer outputing non-XNS, source is input issuer. - uCurOfrAccountID, // Offer owner receives. - saCurOfrInAct); - - if (saCurOfrFunds == saCurOfrSpent) - { - // Offer became unfunded. - pspCur->vUnfundedBecame.push_back(uOfferIndex); // Mark offer for deletion on use of current path state. - } - - saPrvDlvAct += saCurOfrInAct; // Portion needed in previous. - saCurDlvAct += saCurOfrOutAct; // Portion of driver served. - } - } - - // Do another cur directory iff bMultiQuality - if (!bMultiQuality) - uDirectTip = 0; - } - - return !!saCurDlvAct ? tesSUCCESS : terResult; -#else - return terResult; -#endif -} - -#if 0 -// If either currency is not stamps, then also calculates vs stamp bridge. -// --> saWanted: Limit of how much is wanted out. -// <-- saPay: How much to pay into the offer. -// <-- saGot: How much to the offer pays out. Never more than saWanted. -// Given two value's enforce a minimum: -// - reverse: prv is maximum to pay in (including fee) - cur is what is wanted: generally, minimizing prv -// - forward: prv is actual amount to pay in (including fee) - cur is what is wanted: generally, minimizing cur -// Value in is may be rippled or credited from limbo. Value out is put in limbo. -// If next is an offer, the amount needed is in cur reedem. -// XXX What about account mentioned multiple times via offers? -void TransactionEngine::calcNodeOffer( - bool bForward, - bool bMultiQuality, // True, if this is the only active path: we can do multiple qualities in this pass. - const uint160& uPrvAccountID, // If 0, then funds from previous offer's limbo - const uint160& uPrvCurrencyID, - const uint160& uPrvIssuerID, - const uint160& uCurCurrencyID, - const uint160& uCurIssuerID, - - const STAmount& uPrvRedeemReq, // --> In limit. - STAmount& uPrvRedeemAct, // <-> In limit achived. - const STAmount& uCurRedeemReq, // --> Out limit. Driver when uCurIssuerID == uNxtIssuerID (offer would redeem to next) - STAmount& uCurRedeemAct, // <-> Out limit achived. - - const STAmount& uCurIssueReq, // --> In limit. - STAmount& uCurIssueAct, // <-> In limit achived. - const STAmount& uCurIssueReq, // --> Out limit. Driver when uCurIssueReq != uNxtIssuerID (offer would effectively issue or transfer to next) - STAmount& uCurIssueAct, // <-> Out limit achived. - - STAmount& saPay, - STAmount& saGot - ) const -{ - TER terResult = temUNKNOWN; - - // Direct: not bridging via XNS - bool bDirectNext = true; // True, if need to load. - uint256 uDirectQuality; - uint256 uDirectTip = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); - uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); - - // Bridging: bridging via XNS - bool bBridge = true; // True, if bridging active. False, missing an offer. - uint256 uBridgeQuality; - STAmount saBridgeIn; // Amount available. - STAmount saBridgeOut; - - bool bInNext = true; // True, if need to load. - STAmount saInIn; // Amount available. Consumed in loop. Limited by offer funding. - STAmount saInOut; - uint256 uInTip; // Current entry. - uint256 uInEnd; - unsigned int uInEntry; - - bool bOutNext = true; - STAmount saOutIn; - STAmount saOutOut; - uint256 uOutTip; - uint256 uOutEnd; - unsigned int uOutEntry; - - saPay.zero(); - saPay.setCurrency(uPrvCurrencyID); - saPay.setIssuer(uPrvIssuerID); - - saNeed = saWanted; - - if (!uCurCurrencyID && !uPrvCurrencyID) - { - // Bridging: Neither currency is XNS. - uInTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, CURRENCY_XNS, ACCOUNT_XNS); - uInEnd = Ledger::getQualityNext(uInTip); - uOutTip = Ledger::getBookBase(CURRENCY_XNS, ACCOUNT_XNS, uCurCurrencyID, uCurIssuerID); - uOutEnd = Ledger::getQualityNext(uInTip); - } - - // Find our head offer. - - bool bRedeeming = false; - bool bIssuing = false; - - // The price varies as we change between issuing and transfering, so unless bMultiQuality, we must stick with a mode once it - // is determined. - - if (bBridge && (bInNext || bOutNext)) - { - // Bridging and need to calculate next bridge rate. - // A bridge can consist of multiple offers. As offer's are consumed, the effective rate changes. - - if (bInNext) - { -// sleInDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uInIndex, uInEnd)); - // Get the next funded offer. - offerBridgeNext(uInIndex, uInEnd, uInEntry, saInIn, saInOut); // Get offer limited by funding. - bInNext = false; - } - - if (bOutNext) - { -// sleOutDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uOutIndex, uOutEnd)); - offerNext(uOutIndex, uOutEnd, uOutEntry, saOutIn, saOutOut); - bOutNext = false; - } - - if (!uInIndex || !uOutIndex) - { - bBridge = false; // No more offers to bridge. - } - else - { - // Have bridge in and out entries. - // Calculate bridge rate. Out offer pay ripple fee. In offer fee is added to in cost. - - saBridgeOut.zero(); - - if (saInOut < saOutIn) - { - // Limit by in. - - // XXX Need to include fees in saBridgeIn. - saBridgeIn = saInIn; // All of in - // Limit bridge out: saInOut/saBridgeOut = saOutIn/saOutOut - // Round such that we would take all of in offer, otherwise would have leftovers. - saBridgeOut = (saInOut * saOutOut) / saOutIn; - } - else if (saInOut > saOutIn) - { - // Limit by out, if at all. - - // XXX Need to include fees in saBridgeIn. - // Limit bridge in:saInIn/saInOuts = aBridgeIn/saOutIn - // Round such that would take all of out offer. - saBridgeIn = (saInIn * saOutIn) / saInOuts; - saBridgeOut = saOutOut; // All of out. - } - else - { - // Entries match, - - // XXX Need to include fees in saBridgeIn. - saBridgeIn = saInIn; // All of in - saBridgeOut = saOutOut; // All of out. - } - - uBridgeQuality = STAmount::getRate(saBridgeIn, saBridgeOut); // Inclusive of fees. - } - } - - if (bBridge) - { - bUseBridge = !uDirectTip || (uBridgeQuality < uDirectQuality) - } - else if (!!uDirectTip) - { - bUseBridge = false + // Previous is an account node, resolve its deliver. + STAmount saInAct; + STAmount saInFees; + + terResult = calcNodeDeliver( + uIndex, + pspCur, + bMultiQuality, + pnPrv.uAccountID, + pnPrv.saFwdDeliver, + pnPrv.saFwdDeliver, + saInAct, + saInFees); + + assert(tesSUCCESS != terResult || pnPrv.saFwdDeliver == saInAct+saInFees); } else { - // No more offers. Declare success, even if none returned. - saGot = saWanted-saNeed; + // Previous is an offer. Deliver has already been resolved. terResult = tesSUCCESS; } - if (tesSUCCESS != terResult) - { - STAmount& saAvailIn = bUseBridge ? saBridgeIn : saDirectIn; - STAmount& saAvailOut = bUseBridge ? saBridgeOut : saDirectOut; + return terResult; - if (saAvailOut > saNeed) - { - // Consume part of offer. Done. - - saNeed = 0; - saPay += (saNeed*saAvailIn)/saAvailOut; // Round up, prefer to pay more. - } - else - { - // Consume entire offer. - - saNeed -= saAvailOut; - saPay += saAvailIn; - - if (bUseBridge) - { - // Consume bridge out. - if (saOutOut == saAvailOut) - { - // Consume all. - saOutOut = 0; - saOutIn = 0; - bOutNext = true; - } - else - { - // Consume portion of bridge out, must be consuming all of bridge in. - // saOutIn/saOutOut = saSpent/saAvailOut - // Round? - saOutIn -= (saOutIn*saAvailOut)/saOutOut; - saOutOut -= saAvailOut; - } - - // Consume bridge in. - if (saOutIn == saAvailIn) - { - // Consume all. - saInOut = 0; - saInIn = 0; - bInNext = true; - } - else - { - // Consume portion of bridge in, must be consuming all of bridge out. - // saInIn/saInOut = saAvailIn/saPay - // Round? - saInOut -= (saInOut*saAvailIn)/saInIn; - saInIn -= saAvailIn; - } - } - else - { - bDirectNext = true; - } - } - } } -#endif // Cur is the driver and will be filled exactly. // uQualityIn -> uQualityOut @@ -2886,9 +2455,9 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS TER terResult = tesSUCCESS; const unsigned int uLast = pspCur->vpnNodes.size() - 1; - paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; - paymentNode& pnCur = pspCur->vpnNodes[uIndex]; - paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; const bool bRedeem = isSetBit(pnCur.uFlags, STPathElement::typeRedeem); const bool bPrvRedeem = isSetBit(pnPrv.uFlags, STPathElement::typeRedeem); @@ -3214,9 +2783,9 @@ TER TransactionEngine::calcNodeAccountFwd( TER terResult = tesSUCCESS; const unsigned int uLast = pspCur->vpnNodes.size() - 1; - paymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; - paymentNode& pnCur = pspCur->vpnNodes[uIndex]; - paymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; const bool bRedeem = isSetBit(pnCur.uFlags, STPathElement::typeRedeem); const bool bIssue = isSetBit(pnCur.uFlags, STPathElement::typeIssue); @@ -3276,7 +2845,7 @@ TER TransactionEngine::calcNodeAccountFwd( // First node, calculate amount to send. // XXX Use stamp/ripple balance - paymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; const STAmount& saCurRedeemReq = pnCur.saRevRedeem; STAmount& saCurRedeemAct = pnCur.saFwdRedeem; @@ -3498,7 +3067,7 @@ bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::poi // - Offers can only go directly to another offer if the currency and issuer are an exact match. TER PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) { - const paymentNode& pnPrv = vpnNodes.back(); + const PaymentNode& pnPrv = vpnNodes.back(); TER terResult = tesSUCCESS; Log(lsINFO) << "pushImply> " @@ -3548,9 +3117,9 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint << NewcoinAddress::createHumanAccountID(uAccountID) << " " << STAmount::createHumanCurrency(uCurrencyID) << " " << NewcoinAddress::createHumanAccountID(uIssuerID); - paymentNode pnCur; + PaymentNode pnCur; const bool bFirst = vpnNodes.empty(); - const paymentNode& pnPrv = bFirst ? paymentNode() : vpnNodes.back(); + const PaymentNode& pnPrv = bFirst ? PaymentNode() : vpnNodes.back(); // true, iff node is a ripple account. false, iff node is an offer node. const bool bAccount = isSetBit(iType, STPathElement::typeAccount); // true, iff currency supplied. @@ -3594,7 +3163,7 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint if (tesSUCCESS == terResult && !vpnNodes.empty()) { - const paymentNode& pnBck = vpnNodes.back(); + const PaymentNode& pnBck = vpnNodes.back(); bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); if (bBckAccount) @@ -3669,7 +3238,7 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint if (tesSUCCESS == terResult) { // Verify that previous account is allowed to issue. - const paymentNode& pnBck = vpnNodes.back(); + const PaymentNode& pnBck = vpnNodes.back(); bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); bool bBckIssue = isSetBit(pnBck.uFlags, STPathElement::typeIssue); @@ -3682,7 +3251,9 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint } if (tesSUCCESS == terResult) + { vpnNodes.push_back(pnCur); + } } } Log(lsINFO) << "pushNode< " << terResult; @@ -3758,7 +3329,7 @@ PathState::PathState( for (unsigned int uIndex = 0; tesSUCCESS == terStatus && uIndex != uNodes; ++uIndex) { - const paymentNode& pnCur = vpnNodes[uIndex]; + const PaymentNode& pnCur = vpnNodes[uIndex]; if (!!pnCur.uAccountID) { @@ -3789,7 +3360,7 @@ Json::Value PathState::getJson() const Json::Value jvPathState(Json::objectValue); Json::Value jvNodes(Json::arrayValue); - BOOST_FOREACH(const paymentNode& pnNode, vpnNodes) + BOOST_FOREACH(const PaymentNode& pnNode, vpnNodes) { Json::Value jvNode(Json::objectValue); @@ -3858,6 +3429,27 @@ Json::Value PathState::getJson() const return jvPathState; } +TER TransactionEngine::calcNodeFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) +{ + const PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); + + Log(lsINFO) << boost::str(boost::format("calcNodeFwd> uIndex=%d") % uIndex); + + TER terResult = bCurAccount + ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) + : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); + + if (tesSUCCESS == terResult && uIndex != pspCur->vpnNodes.size()) + { + terResult = calcNodeFwd(uIndex+1, pspCur, bMultiQuality); + } + + Log(lsINFO) << boost::str(boost::format("calcNodeFwd< uIndex=%d terResult=%d") % uIndex % terResult); + + return terResult; +} + // Calculate a node and its previous nodes. // From the destination work in reverse towards the source calculating how much must be asked for. // Then work forward, figuring out how much can actually be delivered. @@ -3867,34 +3459,44 @@ Json::Value PathState::getJson() const // --> [all]saWanted.mCurrency // --> [all]saAccount // <-> [0]saWanted.mAmount : --> limit, <-- actual -TER TransactionEngine::calcNode(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) +TER TransactionEngine::calcNodeRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) { - const paymentNode& pnCur = pspCur->vpnNodes[uIndex]; - const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); - TER terResult; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); + TER terResult; - Log(lsINFO) << boost::str(boost::format("calcNode> uIndex=%d") % uIndex); + Log(lsINFO) << boost::str(boost::format("calcNodeRev> uIndex=%d") % uIndex); // Do current node reverse. + const uint160& uCurIssuerID = pnCur.uIssuerID; + STAmount& saTransferRate = pnCur.saTransferRate; + + saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID)); + terResult = bCurAccount ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); // Do previous. - if (tesSUCCESS == terResult && uIndex) + if (tesSUCCESS != terResult) { - terResult = calcNode(uIndex-1, pspCur, bMultiQuality); + // Error, don't continue. + nothing(); + } + else if (uIndex) + { + // Continue in reverse. + + terResult = calcNodeRev(uIndex-1, pspCur, bMultiQuality); + } + else + { + // Do forward. + + terResult = calcNodeFwd(0, pspCur, bMultiQuality); } - // Do current node forward. - if (tesSUCCESS == terResult) - { - terResult = bCurAccount - ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) - : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); - } - - Log(lsINFO) << boost::str(boost::format("calcNode< uIndex=%d terResult=%d") % uIndex % terResult); + Log(lsINFO) << boost::str(boost::format("calcNodeRev< uIndex=%d terResult=%d") % uIndex % terResult); return terResult; } @@ -3916,7 +3518,7 @@ void TransactionEngine::pathNext(const PathState::pointer& pspCur, const int iPa pspCur->vUnfundedBecame.clear(); pspCur->umReverse.clear(); - pspCur->terStatus = calcNode(uLast, pspCur, iPaths == 1); + pspCur->terStatus = calcNodeRev(uLast, pspCur, iPaths == 1); Log(lsINFO) << "pathNext: terStatus=" << pspCur->terStatus @@ -4757,4 +4359,403 @@ TER TransactionEngine::doDelete(const SerializedTransaction& txn) return temUNKNOWN; } +#if 0 +// XXX Need to adjust for fees. +// Find offers to satisfy pnDst. +// - Does not adjust any balances as there is at least a forward pass to come. +// --> pnDst.saWanted: currency and amount wanted +// --> pnSrc.saIOURedeem.mCurrency: use this before saIOUIssue, limit to use. +// --> pnSrc.saIOUIssue.mCurrency: use this after saIOURedeem, limit to use. +// <-- pnDst.saReceive +// <-- pnDst.saIOUForgive +// <-- pnDst.saIOUAccept +// <-- terResult : tesSUCCESS = no error and if !bAllowPartial complelely satisfied wanted. +// <-> usOffersDeleteAlways: +// <-> usOffersDeleteOnSuccess: +TER calcOfferFill(PaymentNode& pnSrc, PaymentNode& pnDst, bool bAllowPartial) +{ + TER terResult; + + if (pnDst.saWanted.isNative()) + { + // Transfer stamps. + + STAmount saSrcFunds = pnSrc.saAccount->accountHolds(pnSrc.saAccount, uint160(0), uint160(0)); + + if (saSrcFunds && (bAllowPartial || saSrcFunds > pnDst.saWanted)) + { + pnSrc.saSend = min(saSrcFunds, pnDst.saWanted); + pnDst.saReceive = pnSrc.saSend; + } + else + { + terResult = terINSUF_PATH; + } + } + else + { + // Ripple funds. + + // Redeem to limit. + terResult = calcOfferFill( + accountHolds(pnSrc.saAccount, pnDst.saWanted.getCurrency(), pnDst.saWanted.getIssuer()), + pnSrc.saIOURedeem, + pnDst.saIOUForgive, + bAllowPartial); + + if (tesSUCCESS == terResult) + { + // Issue to wanted. + terResult = calcOfferFill( + pnDst.saWanted, // As much as wanted is available, limited by credit limit. + pnSrc.saIOUIssue, + pnDst.saIOUAccept, + bAllowPartial); + } + + if (tesSUCCESS == terResult && !bAllowPartial) + { + STAmount saTotal = pnDst.saIOUForgive + pnSrc.saIOUAccept; + + if (saTotal != saWanted) + terResult = terINSUF_PATH; + } + } + + return terResult; +} +#endif + +#if 0 +// Get the next offer limited by funding. +// - Stop when becomes unfunded. +void TransactionEngine::calcOfferBridgeNext( + const uint256& uBookRoot, // --> Which order book to look in. + const uint256& uBookEnd, // --> Limit of how far to look. + uint256& uBookDirIndex, // <-> Current directory. <-- 0 = no offer available. + uint64& uBookDirNode, // <-> Which node. 0 = first. + unsigned int& uBookDirEntry, // <-> Entry in node. 0 = first. + STAmount& saOfferIn, // <-- How much to pay in, fee inclusive, to get saOfferOut out. + STAmount& saOfferOut // <-- How much offer pays out. + ) +{ + saOfferIn = 0; // XXX currency & issuer + saOfferOut = 0; // XXX currency & issuer + + bool bDone = false; + + while (!bDone) + { + uint256 uOfferIndex; + + // Get uOfferIndex. + dirNext(uBookRoot, uBookEnd, uBookDirIndex, uBookDirNode, uBookDirEntry, uOfferIndex); + + SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); + + uint160 uOfferOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); + STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); + + if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + { + // Offer is expired. + Log(lsINFO) << "calcOfferFirst: encountered expired offer"; + } + else + { + STAmount saOfferFunds = accountFunds(uOfferOwnerID, saOfferPays); + // Outbound fees are paid by offer owner. + // XXX Calculate outbound fee rate. + + if (saOfferPays.isNative()) + { + // No additional fees for stamps. + + nothing(); + } + else if (saOfferPays.getIssuer() == uOfferOwnerID) + { + // Offerer is issue own IOUs. + // No fees at this exact point, XXX receiving node may charge a fee. + // XXX Make sure has a credit line with receiver, limit by credit line. + + nothing(); + // XXX Broken - could be issuing or redeeming or both. + } + else + { + // Offer must be redeeming IOUs. + + // No additional + // XXX Broken + } + + if (!saOfferFunds.isPositive()) + { + // Offer is unfunded. + Log(lsINFO) << "calcOfferFirst: offer unfunded: delete"; + } + else if (saOfferFunds >= saOfferPays) + { + // Offer fully funded. + + // Account transfering funds in to offer always pays inbound fees. + + saOfferIn = saOfferGets; // XXX Add in fees? + + saOfferOut = saOfferPays; + + bDone = true; + } + else + { + // Offer partially funded. + + // saOfferIn/saOfferFunds = saOfferGets/saOfferPays + // XXX Round such that all saOffer funds are exhausted. + saOfferIn = (saOfferFunds*saOfferGets)/saOfferPays; // XXX Add in fees? + saOfferOut = saOfferFunds; + + bDone = true; + } + } + + if (!bDone) + { + // musUnfundedFound.insert(uOfferIndex); + } + } + while (bNext); +} +#endif + +#if 0 +// If either currency is not stamps, then also calculates vs stamp bridge. +// --> saWanted: Limit of how much is wanted out. +// <-- saPay: How much to pay into the offer. +// <-- saGot: How much to the offer pays out. Never more than saWanted. +// Given two value's enforce a minimum: +// - reverse: prv is maximum to pay in (including fee) - cur is what is wanted: generally, minimizing prv +// - forward: prv is actual amount to pay in (including fee) - cur is what is wanted: generally, minimizing cur +// Value in is may be rippled or credited from limbo. Value out is put in limbo. +// If next is an offer, the amount needed is in cur reedem. +// XXX What about account mentioned multiple times via offers? +void TransactionEngine::calcNodeOffer( + bool bForward, + bool bMultiQuality, // True, if this is the only active path: we can do multiple qualities in this pass. + const uint160& uPrvAccountID, // If 0, then funds from previous offer's limbo + const uint160& uPrvCurrencyID, + const uint160& uPrvIssuerID, + const uint160& uCurCurrencyID, + const uint160& uCurIssuerID, + + const STAmount& uPrvRedeemReq, // --> In limit. + STAmount& uPrvRedeemAct, // <-> In limit achived. + const STAmount& uCurRedeemReq, // --> Out limit. Driver when uCurIssuerID == uNxtIssuerID (offer would redeem to next) + STAmount& uCurRedeemAct, // <-> Out limit achived. + + const STAmount& uCurIssueReq, // --> In limit. + STAmount& uCurIssueAct, // <-> In limit achived. + const STAmount& uCurIssueReq, // --> Out limit. Driver when uCurIssueReq != uNxtIssuerID (offer would effectively issue or transfer to next) + STAmount& uCurIssueAct, // <-> Out limit achived. + + STAmount& saPay, + STAmount& saGot + ) const +{ + TER terResult = temUNKNOWN; + + // Direct: not bridging via XNS + bool bDirectNext = true; // True, if need to load. + uint256 uDirectQuality; + uint256 uDirectTip = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); + uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); + + // Bridging: bridging via XNS + bool bBridge = true; // True, if bridging active. False, missing an offer. + uint256 uBridgeQuality; + STAmount saBridgeIn; // Amount available. + STAmount saBridgeOut; + + bool bInNext = true; // True, if need to load. + STAmount saInIn; // Amount available. Consumed in loop. Limited by offer funding. + STAmount saInOut; + uint256 uInTip; // Current entry. + uint256 uInEnd; + unsigned int uInEntry; + + bool bOutNext = true; + STAmount saOutIn; + STAmount saOutOut; + uint256 uOutTip; + uint256 uOutEnd; + unsigned int uOutEntry; + + saPay.zero(); + saPay.setCurrency(uPrvCurrencyID); + saPay.setIssuer(uPrvIssuerID); + + saNeed = saWanted; + + if (!uCurCurrencyID && !uPrvCurrencyID) + { + // Bridging: Neither currency is XNS. + uInTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, CURRENCY_XNS, ACCOUNT_XNS); + uInEnd = Ledger::getQualityNext(uInTip); + uOutTip = Ledger::getBookBase(CURRENCY_XNS, ACCOUNT_XNS, uCurCurrencyID, uCurIssuerID); + uOutEnd = Ledger::getQualityNext(uInTip); + } + + // Find our head offer. + + bool bRedeeming = false; + bool bIssuing = false; + + // The price varies as we change between issuing and transfering, so unless bMultiQuality, we must stick with a mode once it + // is determined. + + if (bBridge && (bInNext || bOutNext)) + { + // Bridging and need to calculate next bridge rate. + // A bridge can consist of multiple offers. As offer's are consumed, the effective rate changes. + + if (bInNext) + { +// sleInDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uInIndex, uInEnd)); + // Get the next funded offer. + offerBridgeNext(uInIndex, uInEnd, uInEntry, saInIn, saInOut); // Get offer limited by funding. + bInNext = false; + } + + if (bOutNext) + { +// sleOutDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uOutIndex, uOutEnd)); + offerNext(uOutIndex, uOutEnd, uOutEntry, saOutIn, saOutOut); + bOutNext = false; + } + + if (!uInIndex || !uOutIndex) + { + bBridge = false; // No more offers to bridge. + } + else + { + // Have bridge in and out entries. + // Calculate bridge rate. Out offer pay ripple fee. In offer fee is added to in cost. + + saBridgeOut.zero(); + + if (saInOut < saOutIn) + { + // Limit by in. + + // XXX Need to include fees in saBridgeIn. + saBridgeIn = saInIn; // All of in + // Limit bridge out: saInOut/saBridgeOut = saOutIn/saOutOut + // Round such that we would take all of in offer, otherwise would have leftovers. + saBridgeOut = (saInOut * saOutOut) / saOutIn; + } + else if (saInOut > saOutIn) + { + // Limit by out, if at all. + + // XXX Need to include fees in saBridgeIn. + // Limit bridge in:saInIn/saInOuts = aBridgeIn/saOutIn + // Round such that would take all of out offer. + saBridgeIn = (saInIn * saOutIn) / saInOuts; + saBridgeOut = saOutOut; // All of out. + } + else + { + // Entries match, + + // XXX Need to include fees in saBridgeIn. + saBridgeIn = saInIn; // All of in + saBridgeOut = saOutOut; // All of out. + } + + uBridgeQuality = STAmount::getRate(saBridgeIn, saBridgeOut); // Inclusive of fees. + } + } + + if (bBridge) + { + bUseBridge = !uDirectTip || (uBridgeQuality < uDirectQuality) + } + else if (!!uDirectTip) + { + bUseBridge = false + } + else + { + // No more offers. Declare success, even if none returned. + saGot = saWanted-saNeed; + terResult = tesSUCCESS; + } + + if (tesSUCCESS != terResult) + { + STAmount& saAvailIn = bUseBridge ? saBridgeIn : saDirectIn; + STAmount& saAvailOut = bUseBridge ? saBridgeOut : saDirectOut; + + if (saAvailOut > saNeed) + { + // Consume part of offer. Done. + + saNeed = 0; + saPay += (saNeed*saAvailIn)/saAvailOut; // Round up, prefer to pay more. + } + else + { + // Consume entire offer. + + saNeed -= saAvailOut; + saPay += saAvailIn; + + if (bUseBridge) + { + // Consume bridge out. + if (saOutOut == saAvailOut) + { + // Consume all. + saOutOut = 0; + saOutIn = 0; + bOutNext = true; + } + else + { + // Consume portion of bridge out, must be consuming all of bridge in. + // saOutIn/saOutOut = saSpent/saAvailOut + // Round? + saOutIn -= (saOutIn*saAvailOut)/saOutOut; + saOutOut -= saAvailOut; + } + + // Consume bridge in. + if (saOutIn == saAvailIn) + { + // Consume all. + saInOut = 0; + saInIn = 0; + bInNext = true; + } + else + { + // Consume portion of bridge in, must be consuming all of bridge out. + // saInIn/saInOut = saAvailIn/saPay + // Round? + saInOut -= (saInOut*saAvailIn)/saInIn; + saInIn -= saAvailIn; + } + } + else + { + bDirectNext = true; + } + } + } +} +#endif + // vim:ts=4 diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 149c6289b7..2310551db6 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -138,7 +138,11 @@ enum TransactionEngineParams // Transaction can be retried, soft failures allowed }; -typedef struct { +class PaymentNode { +protected: + friend class TransactionEngine; + friend class PathState; + uint16 uFlags; // --> From path. uint160 uAccountID; // --> Accounts: Recieving/sending account. @@ -146,6 +150,8 @@ typedef struct { // --- 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. @@ -157,7 +163,27 @@ typedef struct { STAmount saFwdIssue; // <-- Amount node will issue to next. // Issue isn't used by offers. STAmount saFwdDeliver; // <-- Amount to deliver to next regardless of fee. -} paymentNode; + + // For offers: + + // 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 aciSource; @@ -165,9 +191,8 @@ typedef boost::unordered_map curIssuerNode; // Map typedef boost::unordered_map::const_iterator curIssuerNodeConstIterator; extern std::size_t hash_value(const aciSource& asValue); -// extern std::size_t hash_value(const boost::tuple& bt); -// Hold a path state under incremental application. +// Holds a path state under incremental application. class PathState { protected: @@ -180,12 +205,13 @@ public: typedef boost::shared_ptr pointer; TER terStatus; - std::vector vpnNodes; + std::vector vpnNodes; // When processing, don't want to complicate directory walking with deletion. std::vector vUnfundedBecame; // Offers that became unfunded or were completely consumed. - // First time working foward a funding source was mentioned for accounts. Source may only be used there. + // 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. @@ -310,10 +336,23 @@ protected: PathState::pointer pathCreate(const STPath& spPath); void pathNext(const PathState::pointer& pspCur, const int iPaths); 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); + TER calcNodeDeliver( + 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); From 1024af54b6455e35ff7b67d42227477a10050ac7 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 2 Sep 2012 21:32:52 -0700 Subject: [PATCH 166/426] Modify RPC and transactions to use quality flags for ripple. --- src/RPCServer.cpp | 59 +++++++++++++++------------------------ src/SerializedTypes.cpp | 4 +-- src/SerializedTypes.h | 6 ++-- src/Transaction.cpp | 10 +++++-- src/Transaction.h | 8 ++++-- src/TransactionEngine.cpp | 9 +++--- src/TransactionFormats.h | 3 +- 7 files changed, 46 insertions(+), 53 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 5c47ed30a3..cd79010c4a 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1316,15 +1316,15 @@ Json::Value RPCServer::doPeers(const Json::Value& params) } // ripple -// [] // XXX [noredeem] [noissue] +// [] // + -// full|partial [] +// full|partial limit|average [] // // path: // path + // // path_element: -// account [] [] [noredeem] [noissue] +// account [] [] // offer [] Json::Value RPCServer::doRipple(const Json::Value ¶ms) { @@ -1333,10 +1333,10 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) uint160 uSrcCurrencyID; NewcoinAddress naSrcAccountID; NewcoinAddress naSrcIssuerID; - bool bSrcRedeem = true; - bool bSrcIssue = true; bool bPartial; bool bFull; + bool bLimit; + bool bAverage; NewcoinAddress naDstAccountID; STAmount saDstAmount; uint160 uDstCurrencyID; @@ -1366,18 +1366,6 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) int iArg = 4 + naSrcIssuerID.isValid(); - if (params[iArg].asString() == "noredeem") // [noredeem] - { - ++iArg; - bSrcRedeem = false; - } - - if (params[iArg].asString() == "noissue") // [noissue] - { - ++iArg; - bSrcIssue = false; - } - // XXX bSrcRedeem & bSrcIssue not used. STPath spPath; @@ -1417,8 +1405,6 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) NewcoinAddress naAccountID; uint160 uCurrencyID; NewcoinAddress naIssuerID; - bool bRedeem = true; - bool bIssue = true; ++iArg; @@ -1437,24 +1423,10 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) ++iArg; } - if (params.size() != iArg && params[iArg].asString() == "noredeem") // [noredeem] - { - ++iArg; - bRedeem = false; - } - - if (params.size() != iArg && params[iArg].asString() == "noissue") // [noissue] - { - ++iArg; - bIssue = false; - } - spPath.addElement(STPathElement( naAccountID.getAccountID(), uCurrencyID, - naIssuerID.isValid() ? naIssuerID.getAccountID() : uint160(0), - bRedeem, - bIssue)); + naIssuerID.isValid() ? naIssuerID.getAccountID() : uint160(0))); } else { @@ -1486,6 +1458,19 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) ++iArg; } + // limit|average + bLimit = params.size() != iArg ? params[iArg].asString() == "limit" : false; + bAverage = params.size() != iArg ? params[iArg].asString() == "average" : false; + + if (!bPartial && !bFull) + { + return RPCError(rpcINVALID_PARAMS); + } + else + { + ++iArg; + } + if (params.size() != iArg && !naDstAccountID.setAccountID(params[iArg++].asString())) // { return RPCError(rpcDST_ACT_MALFORMED); @@ -1543,7 +1528,9 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) naDstAccountID, saDstAmount, saSrcAmountMax, - spsPaths); + spsPaths, + bPartial, + bLimit); trans = mNetOps->submitTransaction(trans); @@ -2564,7 +2551,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "password_fund", &RPCServer::doPasswordFund, 2, 3, false, optCurrent }, { "password_set", &RPCServer::doPasswordSet, 2, 3, false, optNetwork }, { "peers", &RPCServer::doPeers, 0, 0, true }, - { "ripple", &RPCServer::doRipple, 8, -1, false, optCurrent|optClosed }, + { "ripple", &RPCServer::doRipple, 9, -1, false, optCurrent|optClosed }, { "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent }, { "ripple_line_set", &RPCServer::doRippleLineSet, 4, 7, false, optCurrent }, { "send", &RPCServer::doSend, 3, 9, false, optCurrent }, diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 16572e5d78..4684345496 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -332,8 +332,6 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) else { const bool bAccount = !!(iType & STPathElement::typeAccount); - const bool bRedeem = !!(iType & STPathElement::typeRedeem); - const bool bIssue = !!(iType & STPathElement::typeIssue); const bool bCurrency = !!(iType & STPathElement::typeCurrency); const bool bIssuer = !!(iType & STPathElement::typeIssuer); @@ -350,7 +348,7 @@ STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) if (bIssuer) uIssuerID = s.get160(); - path.push_back(STPathElement(uAccountID, uCurrency, uIssuerID, bRedeem, bIssue)); + path.push_back(STPathElement(uAccountID, uCurrency, uIssuerID)); } } while(1); } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 065c6895d7..4baa4e9b40 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -564,15 +564,13 @@ protected: uint160 mIssuerID; public: - STPathElement(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID, bool bRedeem=false, bool bIssue=false) + STPathElement(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID) : mAccountID(uAccountID), mCurrencyID(uCurrencyID), mIssuerID(uIssuerID) { mType = (uAccountID.isZero() ? 0 : STPathElement::typeAccount) | (uCurrencyID.isZero() ? 0 : STPathElement::typeCurrency) - | (uIssuerID.isZero() ? 0 : STPathElement::typeIssuer) - | (bRedeem ? STPathElement::typeRedeem : 0) - | (bIssue ? STPathElement::typeIssue : 0); + | (uIssuerID.isZero() ? 0 : STPathElement::typeIssuer); } int getNodeType() const { return mType; } diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 38aec72865..00988712d9 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -489,7 +489,9 @@ Transaction::pointer Transaction::setPayment( const NewcoinAddress& naDstAccountID, const STAmount& saAmount, const STAmount& saSendMax, - const STPathSet& spsPaths) + const STPathSet& spsPaths, + const bool bPartial, + const bool bLimit) { mTransaction->setITFieldAccount(sfDestination, naDstAccountID); mTransaction->setITFieldAmount(sfAmount, saAmount); @@ -518,11 +520,13 @@ Transaction::pointer Transaction::sharedPayment( const NewcoinAddress& naDstAccountID, const STAmount& saAmount, const STAmount& saSendMax, - const STPathSet& spsPaths) + const STPathSet& spsPaths, + const bool bPartial, + const bool bLimit) { pointer tResult = boost::make_shared(ttPAYMENT, naPublicKey, naSourceAccount, uSeq, saFee, uSourceTag); - return tResult->setPayment(naPrivateKey, naDstAccountID, saAmount, saSendMax, spsPaths); + return tResult->setPayment(naPrivateKey, naDstAccountID, saAmount, saSendMax, spsPaths, bPartial, bLimit); } // diff --git a/src/Transaction.h b/src/Transaction.h index 7198ef04ea..1ae8c0aa43 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -116,7 +116,9 @@ private: const NewcoinAddress& naDstAccountID, const STAmount& saAmount, const STAmount& saSendMax, - const STPathSet& spsPaths); + const STPathSet& spsPaths, + const bool bPartial, + const bool bLimit); Transaction::pointer setWalletAdd( const NewcoinAddress& naPrivateKey, @@ -231,7 +233,9 @@ public: const NewcoinAddress& naDstAccountID, const STAmount& saAmount, const STAmount& saSendMax, - const STPathSet& spsPaths); + const STPathSet& spsPaths, + const bool bPartial = false, + const bool bLimit = false); // Place an offer. static Transaction::pointer sharedOfferCreate( diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index b7cc2200d2..947b53f50d 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -2770,11 +2770,12 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS return terResult; } -// The previous node: specifies what to push through to current. +// Perfrom balance adjustments between previous and current node. +// - The previous node: specifies what to push through to current. // - All of previous output is consumed. -// The current node: specify what to push through to next. -// - Output to next node minus fees. -// Perform balance adjustment with previous. +// Then, compute 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. TER TransactionEngine::calcNodeAccountFwd( const unsigned int uIndex, // 0 <= uIndex <= uLast const PathState::pointer& pspCur, diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index a49a1513e1..6aadec3a68 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -45,7 +45,8 @@ const uint32 tfPassive = 0x00010000; // Payment flags: const uint32 tfCreateAccount = 0x00010000; const uint32 tfPartialPayment = 0x00020000; -const uint32 tfNoRippleDirect = 0x00040000; +const uint32 tfLimitQuality = 0x00040000; +const uint32 tfNoRippleDirect = 0x00080000; extern TransactionFormat InnerTxnFormats[]; extern TransactionFormat* getTxnFormat(TransactionType t); From b95087775818a507588142336b15253104e3b9e8 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 01:19:58 -0700 Subject: [PATCH 167/426] Some proposal cleanups. --- src/LedgerConsensus.cpp | 6 ++---- src/NetworkOPs.cpp | 26 +++++++++++--------------- src/NewcoinAddress.cpp | 9 +++++++++ src/NewcoinAddress.h | 1 + src/Peer.cpp | 3 +-- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 2aacf34c47..c98ce7c1b7 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -845,17 +845,15 @@ void LedgerConsensus::Saccept(boost::shared_ptr This, SHAMap::p void LedgerConsensus::deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic) { - if (!peerPublic.isValid()) - return; std::list& props = mDeferredProposals[peerPublic.getNodeID()]; - if (props.size() > (mPreviousProposers + 10)) + if (props.size() >= (mPreviousProposers + 10)) props.pop_front(); props.push_back(proposal); } void LedgerConsensus::playbackProposals() { - for ( boost::unordered_map< uint160, std::list >::iterator + for (boost::unordered_map< uint160, std::list >::iterator it = mDeferredProposals.begin(), end = mDeferredProposals.end(); it != end; ++it) { BOOST_FOREACH(const LedgerProposal::pointer& proposal, it->second) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 71737638c0..4fba90529e 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -616,7 +616,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint if (!theApp->isNew(s.getSHA512Half())) return false; - NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey)); + NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(pubKey); if ((!mConsensus) && (mMode == omFULL)) { @@ -632,7 +632,14 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint if (!mConsensus) { Log(lsINFO) << "Received proposal outside consensus window"; - return (mMode != omFULL); + return mMode != omFULL; + } + + // Is this node on our UNL? + if (!theApp->getUNL().nodeInUNL(naPeerPublic)) + { + Log(lsINFO) << "Untrusted proposal: " << naPeerPublic.humanNodePublic() << " " << proposeHash.GetHex(); + return true; } LedgerProposal::pointer proposal = @@ -640,22 +647,11 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint if (!proposal->checkSign(signature)) { // Note that if the LCL is different, the signature check will fail Log(lsWARNING) << "Ledger proposal fails signature check"; - if ((mMode != omFULL) && (mMode != omTRACKING) && theApp->getUNL().nodeInUNL(proposal->peekPublic())) - { - proposal->setSignature(signature); - mConsensus->deferProposal(proposal, nodePublic); - } + proposal->setSignature(signature); + mConsensus->deferProposal(proposal, nodePublic); return false; } - // Is this node on our UNL? - if (!theApp->getUNL().nodeInUNL(proposal->peekPublic())) - { - Log(lsINFO) << "Untrusted proposal: " << naPeerPublic.humanNodePublic() << " " << - proposal->getCurrentHash().GetHex(); - return true; - } - return mConsensus->peerPosition(proposal); } diff --git a/src/NewcoinAddress.cpp b/src/NewcoinAddress.cpp index 29b87fe378..be7583dcd7 100644 --- a/src/NewcoinAddress.cpp +++ b/src/NewcoinAddress.cpp @@ -95,6 +95,15 @@ NewcoinAddress NewcoinAddress::createNodePublic(const std::vector return naNew; } +NewcoinAddress NewcoinAddress::createNodePublic(const std::string& strPublic) +{ + NewcoinAddress naNew; + + naNew.setNodePublic(strPublic); + + return naNew; +} + uint160 NewcoinAddress::getNodeID() const { switch (nVersion) { diff --git a/src/NewcoinAddress.h b/src/NewcoinAddress.h index c591d1b0d7..369b609d04 100644 --- a/src/NewcoinAddress.h +++ b/src/NewcoinAddress.h @@ -46,6 +46,7 @@ public: static NewcoinAddress createNodePublic(const NewcoinAddress& naSeed); static NewcoinAddress createNodePublic(const std::vector& vPublic); + static NewcoinAddress createNodePublic(const std::string& strPublic); // // Node Private diff --git a/src/Peer.cpp b/src/Peer.cpp index 40b243f865..83a4272f76 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -721,11 +721,10 @@ void Peer::recvPropose(newcoin::TMProposeSet& packet) return; } - uint32 proposeSeq = packet.proposeseq(); uint256 currentTxHash; memcpy(currentTxHash.begin(), packet.currenttxhash().data(), 32); - if(theApp->getOPs().recvPropose(proposeSeq, currentTxHash, packet.closetime(), + if(theApp->getOPs().recvPropose(packet.proposeseq(), currentTxHash, packet.closetime(), packet.nodepubkey(), packet.signature(), mNodePublic)) { // FIXME: Not all nodes will want proposals PackedMessage::pointer message = boost::make_shared(packet, newcoin::mtPROPOSE_LEDGER); From d5fe3261abf27f38c2f80f29525b7b18e7fc32da Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 01:47:03 -0700 Subject: [PATCH 168/426] Cleanups and simplfications. --- src/HashedObject.cpp | 8 +++--- src/LedgerAcquire.cpp | 18 +++++++------- src/LedgerConsensus.cpp | 48 +++++++++++++++++------------------- src/LedgerMaster.cpp | 6 ++--- src/NetworkOPs.cpp | 20 +++++++-------- src/Peer.cpp | 2 +- src/SHAMap.cpp | 20 +++++++-------- src/SHAMapNodes.cpp | 6 ++--- src/ValidationCollection.cpp | 14 +++++------ src/uint256.h | 7 +++++- 10 files changed, 76 insertions(+), 73 deletions(-) diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp index fcbbee41bc..f5717e879a 100644 --- a/src/HashedObject.cpp +++ b/src/HashedObject.cpp @@ -23,7 +23,7 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index, if (mCache.touch(hash)) { #ifdef HS_DEBUG - Log(lsTRACE) << "HOS: " << hash.GetHex() << " store: incache"; + Log(lsTRACE) << "HOS: " << hash << " store: incache"; #endif return false; } @@ -94,7 +94,7 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash) obj = mCache.fetch(hash); if (obj) { - Log(lsTRACE) << "HOS: " << hash.GetHex() << " fetch: incache"; + Log(lsTRACE) << "HOS: " << hash << " fetch: incache"; return obj; } } @@ -113,7 +113,7 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash) if (!db->executeSQL(sql) || !db->startIterRows()) { - Log(lsTRACE) << "HOS: " << hash.GetHex() << " fetch: not in db"; + Log(lsTRACE) << "HOS: " << hash << " fetch: not in db"; return HashedObject::pointer(); } @@ -145,7 +145,7 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash) obj = boost::make_shared(htype, index, data, hash); mCache.canonicalize(hash, obj); } - Log(lsTRACE) << "HOS: " << hash.GetHex() << " fetch: in db"; + Log(lsTRACE) << "HOS: " << hash << " fetch: in db"; return obj; } diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index adeab57039..2b4452fca8 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -72,7 +72,7 @@ void PeerSet::invokeOnTimer() if (!mProgress) { ++mTimeouts; - Log(lsWARNING) << "Timeout " << mTimeouts << " acquiring " << mHash.GetHex(); + Log(lsWARNING) << "Timeout " << mTimeouts << " acquiring " << mHash; } else mProgress = false; @@ -93,7 +93,7 @@ LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false), mSignaled(false) { #ifdef LA_DEBUG - Log(lsTRACE) << "Acquiring ledger " << mHash.GetHex(); + Log(lsTRACE) << "Acquiring ledger " << mHash; #endif } @@ -118,7 +118,7 @@ void LedgerAcquire::done() return; mSignaled = true; #ifdef LA_DEBUG - Log(lsTRACE) << "Done acquiring ledger " << mHash.GetHex(); + Log(lsTRACE) << "Done acquiring ledger " << mHash; #endif std::vector< boost::function > triggers; @@ -147,8 +147,8 @@ void LedgerAcquire::trigger(Peer::ref peer, bool timer) if (mAborted || mComplete || mFailed) return; #ifdef LA_DEBUG - if(peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex() << " from " << peer->getIP(); - else Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex(); + if(peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash << " from " << peer->getIP(); + else Log(lsTRACE) << "Trigger acquiring ledger " << mHash; if (mComplete || mFailed) Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed; else @@ -290,7 +290,7 @@ void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL) bool LedgerAcquire::takeBase(const std::string& data) { // Return value: true=normal, false=bad data #ifdef LA_DEBUG - Log(lsTRACE) << "got base acquiring ledger " << mHash.GetHex(); + Log(lsTRACE) << "got base acquiring ledger " << mHash; #endif boost::recursive_mutex::scoped_lock sl(mLock); if (mHaveBase) return true; @@ -298,7 +298,7 @@ bool LedgerAcquire::takeBase(const std::string& data) if (mLedger->getHash() != mHash) { Log(lsWARNING) << "Acquire hash mismatch"; - Log(lsWARNING) << mLedger->getHash().GetHex() << "!=" << mHash.GetHex(); + Log(lsWARNING) << mLedger->getHash() << "!=" << mHash; mLedger = Ledger::pointer(); #ifdef TRUST_NETWORK assert(false); @@ -357,7 +357,7 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, const std::list< std::vector >& data) { #ifdef LA_DEBUG - Log(lsTRACE) << "got ASdata acquiring ledger " << mHash.GetHex(); + Log(lsTRACE) << "got ASdata acquiring ledger " << mHash; #endif if (!mHaveBase) return false; std::list::const_iterator nodeIDit = nodeIDs.begin(); @@ -448,7 +448,7 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::ref } memcpy(hash.begin(), packet.ledgerhash().data(), 32); #ifdef LA_DEBUG - Log(lsTRACE) << hash.GetHex(); + Log(lsTRACE) << hash; #endif LedgerAcquire::pointer ledger = find(hash); diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index c98ce7c1b7..00916c24cb 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -33,7 +33,7 @@ void TransactionAcquire::done() { if (mFailed) { - Log(lsWARNING) << "Failed to acqiure TXs " << mHash.GetHex(); + Log(lsWARNING) << "Failed to acqiure TXs " << mHash; theApp->getOPs().mapComplete(mHash, SHAMap::pointer()); } else @@ -136,25 +136,25 @@ void LCTransaction::setVote(const uint160& peer, bool votesYes) { // new vote if (votesYes) { - Log(lsTRACE) << "Peer " << peer.GetHex() << " votes YES on " << mTransactionID.GetHex(); + Log(lsTRACE) << "Peer " << peer << " votes YES on " << mTransactionID; ++mYays; } else { - Log(lsTRACE) << "Peer " << peer.GetHex() << " votes NO on " << mTransactionID.GetHex(); + Log(lsTRACE) << "Peer " << peer << " votes NO on " << mTransactionID; ++mNays; } } else if (votesYes && !res.first->second) { // changes vote to yes - Log(lsTRACE) << "Peer " << peer.GetHex() << " now votes YES on " << mTransactionID.GetHex(); + Log(lsTRACE) << "Peer " << peer << " now votes YES on " << mTransactionID; --mNays; ++mYays; res.first->second = true; } else if (!votesYes && res.first->second) { // changes vote to no - Log(lsTRACE) << "Peer " << peer.GetHex() << " now votes NO on " << mTransactionID.GetHex(); + Log(lsTRACE) << "Peer " << peer << " now votes NO on " << mTransactionID; ++mNays; --mYays; res.first->second = false; @@ -203,7 +203,7 @@ bool LCTransaction::updatePosition(int percentTime, bool proposing) return false; } mOurPosition = newPosition; - Log(lsTRACE) << "We now vote " << (mOurPosition ? "YES" : "NO") << " on " << mTransactionID.GetHex(); + Log(lsTRACE) << "We now vote " << (mOurPosition ? "YES" : "NO") << " on " << mTransactionID; return true; } @@ -215,7 +215,7 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::ref previou mConsensusStartTime = boost::posix_time::microsec_clock::universal_time(); Log(lsDEBUG) << "Creating consensus object"; - Log(lsTRACE) << "LCL:" << previousLedger->getHash().GetHex() <<", ct=" << closeTime; + Log(lsTRACE) << "LCL:" << previousLedger->getHash() <<", ct=" << closeTime; mPreviousProposers = theApp->getOPs().getPreviousProposers(); mPreviousMSeconds = theApp->getOPs().getPreviousConvergeTime(); assert(mPreviousMSeconds); @@ -238,8 +238,8 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::ref previou handleLCL(prevLCLHash); if (!mHaveCorrectLCL) { - Log(lsINFO) << "Entering consensus with: " << previousLedger->getHash().GetHex(); - Log(lsINFO) << "Correct LCL is: " << prevLCLHash.GetHex(); + Log(lsINFO) << "Entering consensus with: " << previousLedger->getHash(); + Log(lsINFO) << "Correct LCL is: " << prevLCLHash; } } @@ -282,7 +282,7 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) return; else { - Log(lsWARNING) << "Need consensus ledger " << mPrevLedgerHash.GetHex(); + Log(lsWARNING) << "Need consensus ledger " << mPrevLedgerHash; mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash); std::vector peerList = theApp->getConnectionPool().getPeerVector(); bool found = false; @@ -305,7 +305,7 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) return; } - Log(lsINFO) << "Acquired the consensus ledger " << mPrevLedgerHash.GetHex(); + Log(lsINFO) << "Acquired the consensus ledger " << mPrevLedgerHash; mHaveCorrectLCL = true; mAcquiringLedger = LedgerAcquire::pointer(); mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution( @@ -365,7 +365,7 @@ void LedgerConsensus::createDisputes(const SHAMap::pointer& m1, const SHAMap::po void LedgerConsensus::mapComplete(const uint256& hash, const SHAMap::pointer& map, bool acquired) { if (acquired) - Log(lsINFO) << "We have acquired TXS " << hash.GetHex(); + Log(lsINFO) << "We have acquired TXS " << hash; mAcquiring.erase(hash); if (!map) @@ -400,7 +400,7 @@ void LedgerConsensus::mapComplete(const uint256& hash, const SHAMap::pointer& ma if (!peers.empty()) adjustCount(map, peers); else if (acquired) - Log(lsWARNING) << "By the time we got the map " << hash.GetHex() << " no peers were proposing it"; + Log(lsWARNING) << "By the time we got the map " << hash << " no peers were proposing it"; sendHaveTxSet(hash, true); } @@ -551,7 +551,7 @@ void LedgerConsensus::updateOurPositions() if (it->second->isStale(peerCutoff)) { // proposal is stale uint160 peerID = it->second->getPeerID(); - Log(lsWARNING) << "Removing stale proposal from " << peerID.GetHex(); + Log(lsWARNING) << "Removing stale proposal from " << peerID; BOOST_FOREACH(u256_lct_pair& it, mDisputes) it.second->unVote(peerID); mPeerPositions.erase(it++); @@ -641,7 +641,7 @@ void LedgerConsensus::updateOurPositions() if (mProposing) propose(addedTx, removedTx); mapComplete(newHash, ourPosition, false); - Log(lsINFO) << "Position change: CTime " << closeTime << ", tx " << newHash.GetHex(); + Log(lsINFO) << "Position change: CTime " << closeTime << ", tx " << newHash; } } @@ -725,7 +725,7 @@ void LedgerConsensus::startAcquiring(const TransactionAcquire::pointer& acquire) void LedgerConsensus::propose(const std::vector& added, const std::vector& removed) { - Log(lsTRACE) << "We propose: " << mOurPosition->getCurrentHash().GetHex(); + Log(lsTRACE) << "We propose: " << mOurPosition->getCurrentHash(); newcoin::TMProposeSet prop; prop.set_currenttxhash(mOurPosition->getCurrentHash().begin(), 256 / 8); prop.set_proposeseq(mOurPosition->getProposeSeq()); @@ -741,7 +741,7 @@ void LedgerConsensus::propose(const std::vector& added, const std::vect void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vector& tx) { - Log(lsTRACE) << "Transaction " << txID.GetHex() << " is disputed"; + Log(lsTRACE) << "Transaction " << txID << " is disputed"; boost::unordered_map::iterator it = mDisputes.find(txID); if (it != mDisputes.end()) return; @@ -783,8 +783,7 @@ bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) ++mCloseTimes[newPosition->getCloseTime()]; } - Log(lsINFO) << "Processing peer proposal " << newPosition->getProposeSeq() << "/" - << newPosition->getCurrentHash().GetHex(); + Log(lsINFO) << "Processing peer proposal " << newPosition->getProposeSeq() << "/" << newPosition->getCurrentHash(); currentPosition = newPosition; SHAMap::pointer set = getTransactionTree(newPosition->getCurrentHash(), true); if (set) @@ -911,7 +910,7 @@ void LedgerConsensus::applyTransactions(const SHAMap::pointer& set, Ledger::ref { if (!checkLedger->hasTransaction(item->getTag())) { - Log(lsINFO) << "Processing candidate transaction: " << item->getTag().GetHex(); + Log(lsINFO) << "Processing candidate transaction: " << item->getTag(); #ifndef TRUST_NETWORK try { @@ -967,9 +966,8 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) Log(lsINFO) << "Computing new LCL based on network consensus"; if (mHaveCorrectLCL) { - Log(lsINFO) << "CNF tx " << mOurPosition->getCurrentHash().GetHex() << ", close " << closeTime; - Log(lsINFO) << "CNF mode " << theApp->getOPs().getOperatingMode() - << ", oldLCL " << mPrevLedgerHash.GetHex(); + Log(lsINFO) << "CNF tx " << mOurPosition->getCurrentHash() << ", close " << closeTime; + Log(lsINFO) << "CNF mode " << theApp->getOPs().getOperatingMode() << ", oldLCL " << mPrevLedgerHash; } Ledger::pointer newLCL = boost::make_shared(false, boost::ref(*mPreviousLedger)); @@ -996,7 +994,7 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) SerializedValidation::pointer v = boost::make_shared (newLCLHash, newLCL->getCloseTimeNC(), mValSeed, mProposing); v->setTrusted(); - Log(lsINFO) << "CNF Val " << newLCLHash.GetHex(); + Log(lsINFO) << "CNF Val " << newLCLHash; theApp->getValidations().addValidation(v); std::vector validation = v->getSigned(); newcoin::TMValidation val; @@ -1004,7 +1002,7 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) theApp->getConnectionPool().relayMessage(NULL, boost::make_shared(val, newcoin::mtVALIDATION)); } else - Log(lsINFO) << "CNF newLCL " << newLCLHash.GetHex(); + Log(lsINFO) << "CNF newLCL " << newLCLHash; Ledger::pointer newOL = boost::make_shared(true, boost::ref(*newLCL)); ScopedLock sl = theApp->getMasterLedger().getLock(); diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp index 93e8724637..a3cc5a1475 100644 --- a/src/LedgerMaster.cpp +++ b/src/LedgerMaster.cpp @@ -23,12 +23,12 @@ void LedgerMaster::pushLedger(Ledger::ref newLedger) { // Caller should already have properly assembled this ledger into "ready-to-close" form -- // all candidate transactions must already be appled - Log(lsINFO) << "PushLedger: " << newLedger->getHash().GetHex(); + Log(lsINFO) << "PushLedger: " << newLedger->getHash(); ScopedLock sl(mLock); if (!!mFinalizedLedger) { mFinalizedLedger->setClosed(); - Log(lsTRACE) << "Finalizes: " << mFinalizedLedger->getHash().GetHex(); + Log(lsTRACE) << "Finalizes: " << mFinalizedLedger->getHash(); } mFinalizedLedger = mCurrentLedger; mCurrentLedger = newLedger; @@ -45,7 +45,7 @@ void LedgerMaster::pushLedger(Ledger::ref newLCL, Ledger::ref newOL) assert(newLCL->isClosed()); assert(newLCL->isImmutable()); mLedgerHistory.addAcceptedLedger(newLCL); - Log(lsINFO) << "StashAccepted: " << newLCL->getHash().GetHex(); + Log(lsINFO) << "StashAccepted: " << newLCL->getHash(); } mFinalizedLedger = newLCL; diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 4fba90529e..aca2ba73ed 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -472,7 +472,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis it != end; ++it) { bool isDead = theApp->getValidations().isDeadLedger(it->first); - Log(lsTRACE) << "L: " << it->first.GetHex() << ((isDead) ? " dead" : " live") << + Log(lsTRACE) << "L: " << it->first << ((isDead) ? " dead" : " live") << " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; if ((it->second > bestVC) && !isDead) { @@ -502,15 +502,15 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis } Log(lsWARNING) << "We are not running on the consensus ledger"; - Log(lsINFO) << "Our LCL " << ourClosed->getHash().GetHex(); - Log(lsINFO) << "Net LCL " << closedLedger.GetHex(); + Log(lsINFO) << "Our LCL " << ourClosed->getHash(); + Log(lsINFO) << "Net LCL " << closedLedger; if ((mMode == omTRACKING) || (mMode == omFULL)) setMode(omCONNECTED); Ledger::pointer consensus = mLedgerMaster->getLedgerByHash(closedLedger); if (!consensus) { - Log(lsINFO) << "Acquiring consensus ledger " << closedLedger.GetHex(); + Log(lsINFO) << "Acquiring consensus ledger " << closedLedger; LedgerAcquire::pointer mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(closedLedger); if (!mAcquiringLedger || mAcquiringLedger->isFailed()) { @@ -552,9 +552,9 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger, bool duringCo { // set the newledger as our last closed ledger -- this is abnormal code if (duringConsensus) - Log(lsERROR) << "JUMPdc last closed ledger to " << newLedger->getHash().GetHex(); + Log(lsERROR) << "JUMPdc last closed ledger to " << newLedger->getHash(); else - Log(lsERROR) << "JUMP last closed ledger to " << newLedger->getHash().GetHex(); + Log(lsERROR) << "JUMP last closed ledger to " << newLedger->getHash(); newLedger->setClosed(); Ledger::pointer openLedger = boost::make_shared(false, boost::ref(*newLedger)); @@ -575,7 +575,7 @@ void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger, bool duringCo int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger) { Log(lsINFO) << "Consensus time for ledger " << closingLedger->getLedgerSeq(); - Log(lsINFO) << " LCL is " << closingLedger->getParentHash().GetHex(); + Log(lsINFO) << " LCL is " << closingLedger->getParentHash(); Ledger::pointer prevLedger = mLedgerMaster->getLedgerByHash(closingLedger->getParentHash()); if (!prevLedger) @@ -638,7 +638,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint // Is this node on our UNL? if (!theApp->getUNL().nodeInUNL(naPeerPublic)) { - Log(lsINFO) << "Untrusted proposal: " << naPeerPublic.humanNodePublic() << " " << proposeHash.GetHex(); + Log(lsINFO) << "Untrusted proposal: " << naPeerPublic.humanNodePublic() << " " << proposeHash; return true; } @@ -686,7 +686,7 @@ void NetworkOPs::mapComplete(const uint256& hash, const SHAMap::pointer& map) void NetworkOPs::endConsensus(bool correctLCL) { uint256 deadLedger = theApp->getMasterLedger().getClosedLedger()->getParentHash(); - Log(lsTRACE) << "Ledger " << deadLedger.GetHex() << " is now dead"; + Log(lsTRACE) << "Ledger " << deadLedger << " is now dead"; theApp->getValidations().addDeadLedger(deadLedger); std::vector peerList = theApp->getConnectionPool().getPeerVector(); BOOST_FOREACH(Peer::ref it, peerList) @@ -766,7 +766,7 @@ std::vector bool NetworkOPs::recvValidation(const SerializedValidation::pointer& val) { - Log(lsINFO) << "recvValidation " << val->getLedgerHash().GetHex(); + Log(lsINFO) << "recvValidation " << val->getLedgerHash(); return theApp->getValidations().addValidation(val); } diff --git a/src/Peer.cpp b/src/Peer.cpp index 83a4272f76..4a08ea56eb 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -906,7 +906,7 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet) if (packet.has_ledgerhash() && (packet.ledgerhash().size() == (256 / 8))) { // a peer has changed ledgers memcpy(mClosedLedgerHash.begin(), packet.ledgerhash().data(), 256 / 8); - Log(lsTRACE) << "peer LCL is " << mClosedLedgerHash.GetHex() << " " << getIP(); + Log(lsTRACE) << "peer LCL is " << mClosedLedgerHash << " " << getIP(); } else { diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 2a9b48520b..046abe75c7 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -125,7 +125,7 @@ void SHAMap::dirtyUp(std::stack& stack, const uint256& return; } #ifdef ST_DEBUG - std::cerr << "dirtyUp sets branch " << branch << " to " << prevHash.GetHex() << std::endl; + std::cerr << "dirtyUp sets branch " << branch << " to " << prevHash << std::endl; #endif prevHash = node->getNodeHash(); assert(prevHash.isNonZero()); @@ -188,8 +188,8 @@ SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& has { std::cerr << "Attempt to get node, hash not in tree" << std::endl; std::cerr << "ID: " << id.getString() << std::endl; - std::cerr << "TgtHash " << hash.GetHex() << std::endl; - std::cerr << "NodHash " << node->getNodeHash().GetHex() << std::endl; + std::cerr << "TgtHash " << hash << std::endl; + std::cerr << "NodHash " << node->getNodeHash() << std::endl; dump(); throw std::runtime_error("invalid node"); } @@ -255,7 +255,7 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node) #ifdef ST_DEBUG std::cerr << " FB: node " << node->getString() << std::endl; std::cerr << " has non-empty branch " << i << " : " << - node->getChildNodeID(i).getString() << ", " << node->getChildHash(i).GetHex() << std::endl; + node->getChildNodeID(i).getString() << ", " << node->getChildHash(i) << std::endl; #endif node = getNodePointer(node->getChildNodeID(i), node->getChildHash(i)); foundNode = true; @@ -501,7 +501,7 @@ bool SHAMap::delItem(const uint256& id) bool SHAMap::addGiveItem(const SHAMapItem::pointer& item, bool isTransaction, bool hasMeta) { // add the specified item, does not update #ifdef ST_DEBUG - std::cerr << "aGI " << item->getTag().GetHex() << std::endl; + std::cerr << "aGI " << item->getTag() << std::endl; #endif uint256 tag = item->getTag(); @@ -547,7 +547,7 @@ bool SHAMap::addGiveItem(const SHAMapItem::pointer& item, bool isTransaction, bo { // this is a leaf node that has to be made an inner node holding two items #ifdef ST_DEBUG std::cerr << "aGI leaf " << node->getString() << std::endl; - std::cerr << "Existing: " << node->peekItem()->getTag().GetHex() << std::endl; + std::cerr << "Existing: " << node->peekItem()->getTag() << std::endl; #endif SHAMapItem::pointer otherItem = node->peekItem(); assert(otherItem && (tag != otherItem->getTag())); @@ -629,7 +629,7 @@ bool SHAMap::updateGiveItem(const SHAMapItem::pointer& item, bool isTransaction, void SHAMapItem::dump() { - std::cerr << "SHAMapItem(" << mTag.GetHex() << ") " << mData.size() << "bytes" << std::endl; + std::cerr << "SHAMapItem(" << mTag << ") " << mData.size() << "bytes" << std::endl; } SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const uint256& hash) @@ -652,7 +652,7 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui } catch (...) { - Log(lsWARNING) << "fetchNodeExternal gets an invalid node: " << hash.GetHex(); + Log(lsWARNING) << "fetchNodeExternal gets an invalid node: " << hash; throw SHAMapMissingNode(id, hash); } } @@ -719,7 +719,7 @@ void SHAMap::dump(bool hash) SHAMapItem::pointer i=peekFirstItem(); while (i) { - std::cerr << "Item: id=" << i->getTag().GetHex() << std::endl; + std::cerr << "Item: id=" << i->getTag() << std::endl; i = peekNextItem(i->getTag()); } std::cerr << "SHAMap::dump done" << std::endl; @@ -732,7 +732,7 @@ void SHAMap::dump(bool hash) { std::cerr << it->second->getString() << std::endl; if (hash) - std::cerr << " " << it->second->getNodeHash().GetHex() << std::endl; + std::cerr << " " << it->second->getNodeHash() << std::endl; } } diff --git a/src/SHAMapNodes.cpp b/src/SHAMapNodes.cpp index 144ccaf993..65514ad95f 100644 --- a/src/SHAMapNodes.cpp +++ b/src/SHAMapNodes.cpp @@ -73,7 +73,7 @@ bool SHAMapNode::operator!=(const uint256 &s) const return s != mNodeID; } -static bool j = SHAMapNode::ClassInit(); +bool SMN_j = SHAMapNode::ClassInit(); bool SHAMapNode::ClassInit() { // set up the depth masks @@ -147,7 +147,7 @@ int SHAMapNode::selectBranch(const uint256& hash) const if ((hash & smMasks[mDepth]) != mNodeID) { std::cerr << "selectBranch(" << getString() << std::endl; - std::cerr << " " << hash.GetHex() << " off branch" << std::endl; + std::cerr << " " << hash << " off branch" << std::endl; assert(false); return -1; // does not go under this node } @@ -464,7 +464,7 @@ void SHAMapTreeNode::makeInner() void SHAMapTreeNode::dump() { - Log(lsDEBUG) << "SHAMapTreeNode(" << getNodeID().GetHex() << ")"; + Log(lsDEBUG) << "SHAMapTreeNode(" << getNodeID() << ")"; } std::string SHAMapTreeNode::getString() const diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 0dee29b63e..cb173f63ef 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -54,7 +54,7 @@ bool ValidationCollection::addValidation(const SerializedValidation::pointer& va } } - Log(lsINFO) << "Val for " << hash.GetHex() << " from " << signer.humanNodePublic() + Log(lsINFO) << "Val for " << hash << " from " << signer.humanNodePublic() << " added " << (val->isTrusted() ? "trusted/" : "UNtrusted/") << (isCurrent ? "current" : "stale"); return isCurrent; } @@ -90,7 +90,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren else { #ifdef VC_DEBUG - Log(lsINFO) << "VC: Untrusted due to time " << ledger.GetHex(); + Log(lsINFO) << "VC: Untrusted due to time " << ledger; #endif } } @@ -101,7 +101,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren } } #ifdef VC_DEBUG - Log(lsINFO) << "VC: " << ledger.GetHex() << "t:" << trusted << " u:" << untrusted; + Log(lsINFO) << "VC: " << ledger << "t:" << trusted << " u:" << untrusted; #endif } @@ -149,7 +149,7 @@ boost::unordered_map ValidationCollection::getCurrentValidations() if (pair.oldest && (now > (pair.oldest->getCloseTime() + LEDGER_VAL_INTERVAL))) { #ifdef VC_DEBUG - Log(lsINFO) << "VC: " << it->first.GetHex() << " removeOldestStale"; + Log(lsINFO) << "VC: " << it->first << " removeOldestStale"; #endif mStaleValidations.push_back(pair.oldest); pair.oldest = SerializedValidation::pointer(); @@ -158,7 +158,7 @@ boost::unordered_map ValidationCollection::getCurrentValidations() if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_VAL_INTERVAL))) { #ifdef VC_DEBUG - Log(lsINFO) << "VC: " << it->first.GetHex() << " removeNewestStale"; + Log(lsINFO) << "VC: " << it->first << " removeNewestStale"; #endif mStaleValidations.push_back(pair.newest); pair.newest = SerializedValidation::pointer(); @@ -171,7 +171,7 @@ boost::unordered_map ValidationCollection::getCurrentValidations() if (pair.oldest) { #ifdef VC_DEBUG - Log(lsTRACE) << "VC: OLD " << pair.oldest->getLedgerHash().GetHex() << " " << + Log(lsTRACE) << "VC: OLD " << pair.oldest->getLedgerHash() << " " << boost::lexical_cast(pair.oldest->getCloseTime()); #endif ++ret[pair.oldest->getLedgerHash()]; @@ -179,7 +179,7 @@ boost::unordered_map ValidationCollection::getCurrentValidations() if (pair.newest) { #ifdef VC_DEBUG - Log(lsTRACE) << "VC: NEW " << pair.newest->getLedgerHash().GetHex() << " " << + Log(lsTRACE) << "VC: NEW " << pair.newest->getLedgerHash() << " " << boost::lexical_cast(pair.newest->getCloseTime()); #endif ++ret[pair.newest->getLedgerHash()]; diff --git a/src/uint256.h b/src/uint256.h index a5cb8c456a..bb11b101b4 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -278,7 +278,7 @@ public: std::string ToString() const { - return (GetHex()); + return GetHex(); } unsigned char* begin() @@ -559,6 +559,11 @@ inline const uint256 operator&(const uint256& a, const uint256& b) { return (b inline const uint256 operator|(const uint256& a, const uint256& b) { return (base_uint256)a | (base_uint256)b; } extern std::size_t hash_value(const uint256&); +template inline std::ostream& operator<<(std::ostream& out, const base_uint& u) +{ + return out << u.GetHex(); +} + inline int Testuint256AdHoc(std::vector vArg) { uint256 g(0); From 9977463122f5e91e9c51039e63420822743b528c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 02:30:17 -0700 Subject: [PATCH 169/426] You no longer need .getFullText() on an operator<< to an ostream. There's like 25 of them in TransactionEngine.cpp that can be removed when convenient --- src/Amount.cpp | 4 ++-- src/SerializedTypes.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index b1588dc05a..afd6da562e 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -838,8 +838,8 @@ bool STAmount::applyOffer( saTakerPaid = saTakerFunds; // Taker paid all he had. saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saOfferGetsAvailable, saOfferPays.getCurrency(), saOfferPays.getIssuer()); - Log(lsINFO) << "applyOffer: saTakerGot=" << saTakerGot.getFullText(); - Log(lsINFO) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable.getFullText(); + Log(lsINFO) << "applyOffer: saTakerGot=" << saTakerGot; + Log(lsINFO) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable; } return saTakerGot >= saOfferPays; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 1017f758a3..12abb0370c 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -100,6 +100,7 @@ public: inline SerializedType* new_clone(const SerializedType& s) { return s.clone().release(); } inline void delete_clone(const SerializedType* s) { boost::checked_delete(s); } +inline std::ostream& operator<<(std::ostream& out, const SerializedType& t) { return out << t.getFullText(); } class STUInt8 : public SerializedType { From 9f8c1bdc7ab9062a58e525c1b55c2ff6581a30f1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 03:15:42 -0700 Subject: [PATCH 170/426] Cleanups. --- src/SHAMap.cpp | 22 +++++++++++----------- src/SHAMap.h | 2 ++ src/SHAMapSync.cpp | 8 ++++---- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 046abe75c7..8ae69c405e 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -187,7 +187,7 @@ SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& has if (node->getNodeHash() != hash) { std::cerr << "Attempt to get node, hash not in tree" << std::endl; - std::cerr << "ID: " << id.getString() << std::endl; + std::cerr << "ID: " << id << std::endl; std::cerr << "TgtHash " << hash << std::endl; std::cerr << "NodHash " << node->getNodeHash() << std::endl; dump(); @@ -242,7 +242,7 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node) { // Return the first item below this node #ifdef ST_DEBUG - std::cerr << "firstBelow(" << node->getString() << ")" << std::endl; + std::cerr << "firstBelow(" << *node << ")" << std::endl; #endif do { // Walk down the tree @@ -253,9 +253,9 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node) if (!node->isEmptyBranch(i)) { #ifdef ST_DEBUG - std::cerr << " FB: node " << node->getString() << std::endl; + std::cerr << " FB: node " << *node << std::endl; std::cerr << " has non-empty branch " << i << " : " << - node->getChildNodeID(i).getString() << ", " << node->getChildHash(i) << std::endl; + node->getChildNodeID(i) << ", " << node->getChildHash(i) << std::endl; #endif node = getNodePointer(node->getChildNodeID(i), node->getChildHash(i)); foundNode = true; @@ -268,7 +268,7 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node) SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node) { #ifdef DEBUG - std::cerr << "lastBelow(" << node->getString() << ")" << std::endl; + std::cerr << "lastBelow(" << *node << ")" << std::endl; #endif do @@ -306,7 +306,7 @@ SHAMapItem::pointer SHAMap::onlyBelow(SHAMapTreeNode* node) if (!found) { - std::cerr << node->getString() << std::endl; + std::cerr << *node << std::endl; assert(false); return SHAMapItem::pointer(); } @@ -480,7 +480,7 @@ bool SHAMap::delItem(const uint256& id) { eraseChildren(node); #ifdef ST_DEBUG - std::cerr << "Making item node " << node->getString() << std::endl; + std::cerr << "Making item node " << *node << std::endl; #endif node->setItem(item, type); } @@ -527,7 +527,7 @@ bool SHAMap::addGiveItem(const SHAMapItem::pointer& item, bool isTransaction, bo if (node->isInner()) { // easy case, we end on an inner node #ifdef ST_DEBUG - std::cerr << "aGI inner " << node->getString() << std::endl; + std::cerr << "aGI inner " << *node << std::endl; #endif int branch = node->selectBranch(tag); assert(node->isEmptyBranch(branch)); @@ -535,8 +535,8 @@ bool SHAMap::addGiveItem(const SHAMapItem::pointer& item, bool isTransaction, bo boost::make_shared(node->getChildNodeID(branch), item, type, mSeq); if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) { - std::cerr << "Node: " << node->getString() << std::endl; - std::cerr << "NewNode: " << newNode->getString() << std::endl; + std::cerr << "Node: " << *node << std::endl; + std::cerr << "NewNode: " << *newNode << std::endl; dump(); assert(false); throw std::runtime_error("invalid inner node"); @@ -546,7 +546,7 @@ bool SHAMap::addGiveItem(const SHAMapItem::pointer& item, bool isTransaction, bo else { // this is a leaf node that has to be made an inner node holding two items #ifdef ST_DEBUG - std::cerr << "aGI leaf " << node->getString() << std::endl; + std::cerr << "aGI leaf " << *node << std::endl; std::cerr << "Existing: " << node->peekItem()->getTag() << std::endl; #endif SHAMapItem::pointer otherItem = node->peekItem(); diff --git a/src/SHAMap.h b/src/SHAMap.h index 2e5c0ccbc8..b84dcb7272 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -78,6 +78,8 @@ public: extern std::size_t hash_value(const SHAMapNode& mn); +inline std::ostream& operator<<(std::ostream& out, const SHAMapNode& node) { return out << node.getString(); } + class SHAMapItem { // an item stored in a SHAMap public: diff --git a/src/SHAMapSync.cpp b/src/SHAMapSync.cpp index ee3bb0e1d5..5ae0af44c5 100644 --- a/src/SHAMapSync.cpp +++ b/src/SHAMapSync.cpp @@ -66,7 +66,7 @@ void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vectorgetString(); + Log(lsTRACE) << "Got sync node from cache: " << *d; mTNByID[*d] = d; } } @@ -222,8 +222,8 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vectorgetDepth() != (node.getDepth() - 1)) { // Either this node is broken or we didn't request it (yet) - Log(lsINFO) << "unable to hook node " << node.getString(); - Log(lsINFO) << " stuck at " << iNode->getString(); + Log(lsINFO) << "unable to hook node " << node; + Log(lsINFO) << " stuck at " << *iNode; Log(lsINFO) << "got depth=" << node.getDepth() << ", walked to= " << iNode->getDepth(); return false; } @@ -304,7 +304,7 @@ bool SHAMap::deepCompare(SHAMap& other) return false; } -// Log(lsTRACE) << "Comparing inner nodes " << node->getString(); +// Log(lsTRACE) << "Comparing inner nodes " << *node; if (node->getNodeHash() != otherNode->getNodeHash()) return false; From 81793192cbbdba5b5f5b9c8c686e507634c77d10 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 04:37:25 -0700 Subject: [PATCH 171/426] Bugfix and close time offset set function. --- src/NetworkOPs.cpp | 9 ++++++++- src/NetworkOPs.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index aca2ba73ed..f8860a56e1 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -46,6 +46,13 @@ uint32 NetworkOPs::getCloseTimeNC() return iToSeconds(getNetworkTimePT() + boost::posix_time::seconds(mCloseTimeOffset)); } +void NetworkOPs::closeTimeOffset(int offset) +{ + mCloseTimeOffset += offset / 4; + if (mCloseTimeOffset) + Log(lsINFO) << "Close time offset now " << mCloseTimeOffset; +} + uint32 NetworkOPs::getCurrentLedgerID() { return mLedgerMaster->getCurrentLedger()->getLedgerSeq(); @@ -616,7 +623,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint if (!theApp->isNew(s.getSHA512Half())) return false; - NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(pubKey); + NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey)); if ((!mConsensus) && (mMode == omFULL)) { diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index f4dac510cb..862b1e97c9 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -89,6 +89,7 @@ public: // network information uint32 getNetworkTimeNC(); uint32 getCloseTimeNC(); + void closeTimeOffset(int); boost::posix_time::ptime getNetworkTimePT(); uint32 getCurrentLedgerID(); OperatingMode getOperatingMode() { return mMode; } From 8eb33f6bb5a1f19f0742980bc6c69a96c5add696 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 05:16:08 -0700 Subject: [PATCH 172/426] Better logging of time offsets on connection. --- src/Peer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index 4a08ea56eb..6d0a6be41a 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -586,7 +586,10 @@ void Peer::recvHello(newcoin::TMHello& packet) if (packet.has_nettime() && ((packet.nettime() < minTime) || (packet.nettime() > maxTime))) { - Log(lsINFO) << "Recv(Hello): Disconnect: Clock is far off"; + if (packet.nettime() > maxTime) + Log(lsINFO) << "Recv(Hello): Disconnect: Clock is far off +" << packet.nettime() - ourTime; + else if(packet.nettime() < minTime) + Log(lsINFO) << "Recv(Hello): Disconnect: Clock is far off -" << ourTime - packet.nettime(); } else if (packet.protoversionmin() < MAKE_VERSION_INT(MIN_PROTO_MAJOR, MIN_PROTO_MINOR)) { From 4f598af5826cdc7b7f5682797b3caa557f1d1421 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 05:16:32 -0700 Subject: [PATCH 173/426] Change 'shouldClose' to return a bool. Clear structures on LCL view change during consensus window. Cleaner calculation of 'rounded' close times. Maintain close time offset. --- src/LedgerConsensus.cpp | 46 ++++++++++++++++++++++++----------------- src/LedgerConsensus.h | 3 +++ src/LedgerTiming.cpp | 11 +++++----- src/LedgerTiming.h | 2 +- 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 00916c24cb..44aae4eabc 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -302,6 +302,9 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) mHaveCorrectLCL = false; mProposing = false; mValidating = false; + mCloseTimes.clear(); + mPeerPositions.clear(); + mDisputes.clear(); return; } @@ -318,6 +321,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) { SHAMap::pointer initialSet = initialLedger.peekTransactionMap()->snapShot(false); uint256 txSet = initialSet->getHash(); + Log(lsINFO) << "initial position " << txSet; // if any peers have taken a contrary position, process disputes boost::unordered_set found; @@ -454,25 +458,24 @@ void LedgerConsensus::statePreClose() // This ledger is open. This computes how long since the last ledger closed int sinceClose; - int ledgerInterval = 0; + int idleInterval = 0; if (mHaveCorrectLCL && mPreviousLedger->getCloseAgree()) { // we can use consensus timing sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - mPreviousLedger->getCloseTimeNC()); - ledgerInterval = 2 * mPreviousLedger->getCloseResolution(); - if (ledgerInterval < LEDGER_IDLE_INTERVAL) - ledgerInterval = LEDGER_IDLE_INTERVAL; + idleInterval = 2 * mPreviousLedger->getCloseResolution(); + if (idleInterval < LEDGER_IDLE_INTERVAL) + idleInterval = LEDGER_IDLE_INTERVAL; } else { sinceClose = theApp->getOPs().getLastCloseTime(); - ledgerInterval = LEDGER_IDLE_INTERVAL; + idleInterval = LEDGER_IDLE_INTERVAL; } - if (sinceClose >= ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed, - mPreviousMSeconds, sinceClose, ledgerInterval)) + if (ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed, + mPreviousMSeconds, sinceClose, idleInterval)) { // it is time to close the ledger - Log(lsINFO) << "CLC: closing ledger"; mState = lcsESTABLISH; mConsensusStartTime = boost::posix_time::microsec_clock::universal_time(); mCloseTime = theApp->getOPs().getCloseTimeNC(); @@ -496,7 +499,7 @@ void LedgerConsensus::stateEstablish() } if (haveConsensus()) { - Log(lsINFO) << "Converge cutoff"; + Log(lsINFO) << "Converge cutoff (" << mPeerPositions.size() << " participants)"; mState = lcsFINISHED; beginAccept(); } @@ -524,7 +527,7 @@ void LedgerConsensus::timerEntry() switch (mState) { - case lcsPRE_CLOSE: statePreClose(); if (mState != lcsESTABLISH) return; fallthru(); + case lcsPRE_CLOSE: statePreClose(); return; case lcsESTABLISH: stateEstablish(); if (mState != lcsFINISHED) return; fallthru(); case lcsFINISHED: stateFinished(); if (mState != lcsACCEPTED) return; fallthru(); case lcsACCEPTED: stateAccepted(); return; @@ -558,7 +561,7 @@ void LedgerConsensus::updateOurPositions() } else { // proposal is still fresh - ++closeTimes[it->second->getCloseTime() - (it->second->getCloseTime() % mCloseResolution)]; + ++closeTimes[roundCloseTime(it->second->getCloseTime())]; ++it; } } @@ -600,13 +603,13 @@ void LedgerConsensus::updateOurPositions() if (thresh == 0) { // no other times mHaveCloseTimeConsensus = true; - closeTime = mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution); + closeTime = roundCloseTime(mOurPosition->getCloseTime()); } else { if (mProposing) { - ++closeTimes[mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)]; + ++closeTimes[roundCloseTime(mOurPosition->getCloseTime())]; ++thresh; } thresh = thresh * neededWeight / 100; @@ -627,7 +630,7 @@ void LedgerConsensus::updateOurPositions() } if ((!changes) && - ((closeTime != (mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution))) || + ((closeTime != (roundCloseTime(mOurPosition->getCloseTime()))) || (mOurPosition->isStale(ourCutoff)))) { // close time changed or our position is stale ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); @@ -957,11 +960,16 @@ void LedgerConsensus::applyTransactions(const SHAMap::pointer& set, Ledger::ref } while (successes > 0); } +uint32 LedgerConsensus::roundCloseTime(uint32 closeTime) +{ + return closeTime - (closeTime % mCloseResolution); +} + void LedgerConsensus::accept(const SHAMap::pointer& set) { assert(set->getHash() == mOurPosition->getCurrentHash()); - uint32 closeTime = mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() & mCloseResolution); + uint32 closeTime = roundCloseTime(mOurPosition->getCloseTime()); Log(lsINFO) << "Computing new LCL based on network consensus"; if (mHaveCorrectLCL) @@ -1035,14 +1043,13 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) mState = lcsACCEPTED; sl.unlock(); - if (mValidating && mOurPosition->getCurrentHash().isNonZero()) + if (mValidating) { // see how close our close time is to other node's close time reports Log(lsINFO) << "We closed at " << boost::lexical_cast(mCloseTime); uint64 closeTotal = mCloseTime; int closeCount = 1; - for (std::map::iterator it = mCloseTimes.begin(), end = - mCloseTimes.end(); it != end; ++it) - { + for (std::map::iterator it = mCloseTimes.begin(), end = mCloseTimes.end(); it != end; ++it) + { // FIXME: Use median, not average Log(lsINFO) << boost::lexical_cast(it->second) << " time votes for " << boost::lexical_cast(it->first); closeCount += it->second; @@ -1052,6 +1059,7 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) closeTotal /= closeCount; int offset = static_cast(closeTotal) - static_cast(mCloseTime); Log(lsINFO) << "Our close offset is estimated at " << offset << " (" << closeCount << ")"; + theApp->getOPs().closeTimeOffset(offset); } #ifdef DEBUG diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index e8ae389ced..12bd725582 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -136,12 +136,15 @@ protected: void applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn, Ledger::ref targetLedger, CanonicalTXSet& failedTransactions, bool openLgr); + uint32 roundCloseTime(uint32 closeTime); + // manipulating our own position void statusChange(newcoin::NodeEvent, Ledger& ledger); void takeInitialPosition(Ledger& initialLedger); void updateOurPositions(); void playbackProposals(); int getThreshold(); + void beginAccept(); void endConsensus(); diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index a29f7ad2fa..05736d28ea 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -12,7 +12,7 @@ int ContinuousLedgerTiming::LedgerTimeResolution[] = { 10, 10, 20, 30, 60, 90, 1 // Called when a ledger is open and no close is in progress -- when a transaction is received and no close // is in process, or when a close completes. Returns the number of seconds the ledger should be be open. -int ContinuousLedgerTiming::shouldClose( +bool ContinuousLedgerTiming::shouldClose( bool anyTransactions, int previousProposers, // proposers in the last closing int proposersClosed, // proposers who have currently closed this ledgers @@ -27,7 +27,7 @@ int ContinuousLedgerTiming::shouldClose( boost::str(boost::format("CLC::shouldClose range Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") % (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentMSeconds % previousMSeconds); - return currentMSeconds; + return true;; } if (!anyTransactions) @@ -36,7 +36,7 @@ int ContinuousLedgerTiming::shouldClose( { Log(lsTRACE) << "no transactions, many proposers: now (" << proposersClosed << "closed, " << previousProposers << " before)"; - return currentMSeconds; + return true; } #if 0 // This false triggers on the genesis ledger if (previousMSeconds > (1000 * (LEDGER_IDLE_INTERVAL + 2))) // the last ledger was very slow to close @@ -47,11 +47,10 @@ int ContinuousLedgerTiming::shouldClose( return previousMSeconds - 1000; } #endif - return idleInterval * 1000; // normal idle + return currentMSeconds >= (idleInterval * 1000); // normal idle } - Log(lsTRACE) << "close now"; - return currentMSeconds; // this ledger should close now + return true; // this ledger should close now } // Returns whether we have a consensus or not. If so, we expect all honest nodes diff --git a/src/LedgerTiming.h b/src/LedgerTiming.h index 2a8fb207a2..80e89b30f4 100644 --- a/src/LedgerTiming.h +++ b/src/LedgerTiming.h @@ -52,7 +52,7 @@ public: // Returns the number of seconds the ledger was or should be open // Call when a consensus is reached and when any transaction is relayed to be added - static int shouldClose( + static bool shouldClose( bool anyTransactions, int previousProposers, int proposersClosed, int previousSeconds, int currentSeconds, From 7d6259d8b35cfe3f6e1b7103db9b14de9097fa0c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 06:02:42 -0700 Subject: [PATCH 174/426] Whitespace fix. --- src/LedgerAcquire.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 2b4452fca8..177dfa6dd6 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -431,7 +431,7 @@ bool LedgerAcquireMaster::hasLedger(const uint256& hash) void LedgerAcquireMaster::dropLedger(const uint256& hash) { assert(hash.isNonZero()); - boost::mutex::scoped_lock sl(mLock); + boost::mutex::scoped_lock sl(mLock); mLedgers.erase(hash); } From cc4827559c899eee322cbe50f574835f43a267eb Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 06:03:09 -0700 Subject: [PATCH 175/426] Support for proposals that contain the previous ledger hash. A fix for ledger acquires not stopping when they should. --- src/LedgerConsensus.cpp | 15 ++++++++++----- src/LedgerProposal.h | 2 ++ src/NetworkOPs.cpp | 24 ++++++++++++++++++++---- src/Peer.cpp | 11 ++++++++--- src/newcoin.proto | 5 +++-- 5 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 44aae4eabc..cf36b77ea6 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -860,12 +860,17 @@ void LedgerConsensus::playbackProposals() { BOOST_FOREACH(const LedgerProposal::pointer& proposal, it->second) { - proposal->setPrevLedger(mPrevLedgerHash); - if (proposal->checkSign()) - { - Log(lsINFO) << "Applying deferred proposal"; - peerPosition(proposal); + if (proposal->hasSignature()) + { // old-style + proposal->setPrevLedger(mPrevLedgerHash); + if (proposal->checkSign()) + { + Log(lsINFO) << "Applying deferred proposal"; + peerPosition(proposal); + } } + else if (proposal->isPrevLedger(mPrevLedgerHash)) + peerPosition(proposal); } } } diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index 6bb833cc2d..a3d7faecde 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -56,6 +56,8 @@ public: void setPrevLedger(const uint256& prevLedger) { mPreviousLedger = prevLedger; } void setSignature(const std::string& signature) { mSignature = signature; } + bool hasSignature() { return !mSignature.empty(); } + bool isPrevLedger(const uint256& pl) { return mPreviousLedger == pl; } const boost::posix_time::ptime getCreateTime() { return mTime; } bool isStale(boost::posix_time::ptime cutoff) { return mTime > cutoff; } diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index f8860a56e1..6946687a61 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -518,7 +518,8 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis if (!consensus) { Log(lsINFO) << "Acquiring consensus ledger " << closedLedger; - LedgerAcquire::pointer mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(closedLedger); + if (!mAcquiringLedger || (mAcquiringLedger->getHash() != closedLedger)) + mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(closedLedger); if (!mAcquiringLedger || mAcquiringLedger->isFailed()) { theApp->getMasterLedgerAcquire().dropLedger(closedLedger); @@ -605,8 +606,8 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo } // <-- bool: true to relay -bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint32 closeTime, - const std::string& pubKey, const std::string& signature, const NewcoinAddress& nodePublic) +bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger, + uint32 closeTime, const std::string& pubKey, const std::string& signature, const NewcoinAddress& nodePublic) { // JED: does mConsensus need to be locked? @@ -616,6 +617,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint // Get a preliminary hash to use to suppress duplicates Serializer s(256); s.add256(proposeHash); + s.add256(prevLedger); s.add32(proposeSeq); s.add32(closeTime); s.addRaw(pubKey); @@ -649,6 +651,21 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint return true; } + if (prevLedger.isNonZero()) + { // new-style + LedgerProposal::pointer proposal = + boost::make_shared(prevLedger, proposeSeq, proposeHash, closeTime, naPeerPublic); + if (!proposal->checkSign(signature)) + { + Log(lsWARNING) << "New-style ledger proposal fails signature check"; + return false; + } + if (prevLedger == mConsensus->getLCL()) + return mConsensus->peerPosition(proposal); + mConsensus->deferProposal(proposal, nodePublic); + return false; + } + LedgerProposal::pointer proposal = boost::make_shared(mConsensus->getLCL(), proposeSeq, proposeHash, closeTime, naPeerPublic); if (!proposal->checkSign(signature)) @@ -658,7 +675,6 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint mConsensus->deferProposal(proposal, nodePublic); return false; } - return mConsensus->peerPosition(proposal); } diff --git a/src/Peer.cpp b/src/Peer.cpp index 6d0a6be41a..d2955b6d59 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -724,10 +724,13 @@ void Peer::recvPropose(newcoin::TMProposeSet& packet) return; } - uint256 currentTxHash; + uint256 currentTxHash, prevLedger; memcpy(currentTxHash.begin(), packet.currenttxhash().data(), 32); - if(theApp->getOPs().recvPropose(packet.proposeseq(), currentTxHash, packet.closetime(), + if ((packet.has_previousledger()) && (packet.previousledger().size() == 32)) + memcpy(prevLedger.begin(), packet.previousledger().data(), 32); + + if(theApp->getOPs().recvPropose(packet.proposeseq(), currentTxHash, prevLedger, packet.closetime(), packet.nodepubkey(), packet.signature(), mNodePublic)) { // FIXME: Not all nodes will want proposals PackedMessage::pointer message = boost::make_shared(packet, newcoin::mtPROPOSE_LEDGER); @@ -969,6 +972,8 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) } memcpy(ledgerhash.begin(), packet.ledgerhash().data(), 32); ledger = theApp->getMasterLedger().getLedgerByHash(ledgerhash); + if (!ledger) + Log(lsINFO) << "Don't have ledger " << ledgerhash; } else if (packet.has_ledgerseq()) ledger = theApp->getMasterLedger().getLedgerBySeq(packet.ledgerseq()); @@ -987,7 +992,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) return; } - if ((!ledger) || (packet.has_ledgerseq() && (packet.ledgerseq()!=ledger->getLedgerSeq()))) + if ((!ledger) || (packet.has_ledgerseq() && (packet.ledgerseq() != ledger->getLedgerSeq()))) { punishPeer(PP_UNKNOWN_REQUEST); Log(lsWARNING) << "Can't find the ledger they want"; diff --git a/src/newcoin.proto b/src/newcoin.proto index 79f517468f..2426f16ece 100644 --- a/src/newcoin.proto +++ b/src/newcoin.proto @@ -107,8 +107,9 @@ message TMProposeSet { required bytes nodePubKey = 3; required uint32 closeTime = 4; required bytes signature = 5; // signature of above fields - repeated bytes addedTransactions = 6; // not required if number is large - repeated bytes removedTransactions = 7; // not required if number is large + optional bytes previousledger = 6; + repeated bytes addedTransactions = 10; // not required if number is large + repeated bytes removedTransactions = 11; // not required if number is large } enum TxSetStatus { From b4548760df98d3ad444dab99fe257299d936e4b7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 06:03:45 -0700 Subject: [PATCH 176/426] New-style proposal support. --- src/NetworkOPs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 862b1e97c9..c59ce687a8 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -160,7 +160,7 @@ public: const std::vector& myNode, std::list< std::vector >& newNodes); // ledger proposal/close functions - bool recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint32 closeTime, + bool recvPropose(uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger, uint32 closeTime, const std::string& pubKey, const std::string& signature, const NewcoinAddress& nodePublic); bool gotTXData(const boost::shared_ptr& peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); From df1e5ab95a89cf30b2b43137490f3431e3a52385 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 08:35:53 -0700 Subject: [PATCH 177/426] Cleanup. Fix a bug when we incompletely remove a vote on a disputed transaction. --- src/LedgerConsensus.cpp | 17 +++++++++-------- src/LedgerConsensus.h | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index cf36b77ea6..744ca1785e 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -170,6 +170,7 @@ void LCTransaction::unVote(const uint160& peer) --mYays; else --mNays; + mVotes.erase(it); } } @@ -208,8 +209,8 @@ bool LCTransaction::updatePosition(int percentTime, bool proposing) } LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::ref previousLedger, uint32 closeTime) - : mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger), - mCurrentMSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false) + : mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), + mPreviousLedger(previousLedger), mCurrentMSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false) { mValSeed = theConfig.VALIDATION_SEED; mConsensusStartTime = boost::posix_time::microsec_clock::universal_time(); @@ -343,7 +344,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) mOurPosition = boost::make_shared(initialLedger.getParentHash(), txSet, mCloseTime); mapComplete(txSet, initialSet, false); if (mProposing) - propose(std::vector(), std::vector()); + propose(); } void LedgerConsensus::createDisputes(const SHAMap::pointer& m1, const SHAMap::pointer& m2) @@ -543,7 +544,7 @@ void LedgerConsensus::updateOurPositions() bool changes = false; SHAMap::pointer ourPosition; - std::vector addedTx, removedTx; +// std::vector addedTx, removedTx; // Verify freshness of peer positions and compute close times std::map closeTimes; @@ -578,12 +579,12 @@ void LedgerConsensus::updateOurPositions() if (it.second->getOurPosition()) // now a yes { ourPosition->addItem(SHAMapItem(it.first, it.second->peekTransaction()), true, false); - addedTx.push_back(it.first); +// addedTx.push_back(it.first); } else // now a no { ourPosition->delItem(it.first); - removedTx.push_back(it.first); +// removedTx.push_back(it.first); } } } @@ -642,7 +643,7 @@ void LedgerConsensus::updateOurPositions() uint256 newHash = ourPosition->getHash(); mOurPosition->changePosition(newHash, closeTime); if (mProposing) - propose(addedTx, removedTx); + propose(); mapComplete(newHash, ourPosition, false); Log(lsINFO) << "Position change: CTime " << closeTime << ", tx " << newHash; } @@ -726,7 +727,7 @@ void LedgerConsensus::startAcquiring(const TransactionAcquire::pointer& acquire) acquire->resetTimer(); } -void LedgerConsensus::propose(const std::vector& added, const std::vector& removed) +void LedgerConsensus::propose() { Log(lsTRACE) << "We propose: " << mOurPosition->getCurrentHash(); newcoin::TMProposeSet prop; diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 12bd725582..eef08c8807 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -126,7 +126,7 @@ protected: void createDisputes(const SHAMap::pointer&, const SHAMap::pointer&); void addDisputedTransaction(const uint256&, const std::vector& transaction); void adjustCount(const SHAMap::pointer& map, const std::vector& peers); - void propose(const std::vector& addedTx, const std::vector& removedTx); + void propose(); void addPosition(LedgerProposal&, bool ours); void removePosition(LedgerProposal&, bool ours); From 46f6110cddb3e210ffa126777cb0aa4e774dc5f3 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 08:40:10 -0700 Subject: [PATCH 178/426] Small cleanup. --- src/NetworkOPs.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 6946687a61..25ffb1ecb5 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -436,8 +436,9 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis { boost::unordered_map current = theApp->getValidations().getCurrentValidations(); - for (boost::unordered_map::iterator it = current.begin(), end = current.end(); it != end; ++it) - ledgers[it->first].trustedValidations += it->second; + typedef std::pair u256_int_pair; + BOOST_FOREACH(u256_int_pair& it, current) + ledgers[it.first].trustedValidations += it.second; } Ledger::pointer ourClosed = mLedgerMaster->getClosedLedger(); From 0149c3948ba4061768d9b79aec40da8d33ee0fdd Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 08:50:28 -0700 Subject: [PATCH 179/426] Ack! Test for stale proposals was backwards. --- src/LedgerProposal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index a3d7faecde..c9c6fa8dd9 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -60,7 +60,7 @@ public: bool isPrevLedger(const uint256& pl) { return mPreviousLedger == pl; } const boost::posix_time::ptime getCreateTime() { return mTime; } - bool isStale(boost::posix_time::ptime cutoff) { return mTime > cutoff; } + bool isStale(boost::posix_time::ptime cutoff) { return mTime <= cutoff; } void changePosition(const uint256& newPosition, uint32 newCloseTime); Json::Value getJson() const; From 203533db3d4e92c5467676228dcbb6402dfb441e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 09:46:35 -0700 Subject: [PATCH 180/426] Remove chatty debug. --- src/NetworkOPs.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 25ffb1ecb5..aefa4065af 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -468,7 +468,6 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis vc.highNode = it->getNodePublic(); ++vc.nodesUsing; } - else Log(lsTRACE) << "Connected peer announces no LCL " << it->getIP(); } } From c598b25b8739c9732f4712016065d1cc3ff5052a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 09:46:49 -0700 Subject: [PATCH 181/426] Remove annoying debug. --- src/Peer.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index d2955b6d59..a70fa76d7f 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -904,9 +904,12 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet) if (packet.newevent() == newcoin::neLOST_SYNC) { - Log(lsTRACE) << "peer has lost sync " << getIP(); + if (!mClosedLedgerHash.isZero()) + { + Log(lsTRACE) << "peer has lost sync " << getIP(); + mClosedLedgerHash.zero(); + } mPreviousLedgerHash.zero(); - mClosedLedgerHash.zero(); return; } if (packet.has_ledgerhash() && (packet.ledgerhash().size() == (256 / 8))) From 7eef087d53fcf14d309c8dc32b570537741b1666 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 09:47:03 -0700 Subject: [PATCH 182/426] Typo. --- src/LedgerTiming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index 05736d28ea..b19ee994bd 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -34,7 +34,7 @@ bool ContinuousLedgerTiming::shouldClose( { // no transactions so far this interval if (proposersClosed > (previousProposers / 4)) // did we miss a transaction? { - Log(lsTRACE) << "no transactions, many proposers: now (" << proposersClosed << "closed, " + Log(lsTRACE) << "no transactions, many proposers: now (" << proposersClosed << " closed, " << previousProposers << " before)"; return true; } From ee781140332fdc3cd1b44869bd07f21056699e07 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 09:47:14 -0700 Subject: [PATCH 183/426] Convenience type. --- src/SerializedValidation.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/SerializedValidation.h b/src/SerializedValidation.h index dddd1fdce6..5886b6dbba 100644 --- a/src/SerializedValidation.h +++ b/src/SerializedValidation.h @@ -13,7 +13,8 @@ protected: void setNode(); public: - typedef boost::shared_ptr pointer; + typedef boost::shared_ptr pointer; + typedef const boost::shared_ptr& ref; static SOElement sValidationFormat[16]; static const uint32 sFullFlag; From 1891cf06545423816500c50489163a60b5ec1897 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 09:50:25 -0700 Subject: [PATCH 184/426] Improve error message. --- src/Peer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index a70fa76d7f..27db8ff017 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -587,9 +587,9 @@ void Peer::recvHello(newcoin::TMHello& packet) if (packet.has_nettime() && ((packet.nettime() < minTime) || (packet.nettime() > maxTime))) { if (packet.nettime() > maxTime) - Log(lsINFO) << "Recv(Hello): Disconnect: Clock is far off +" << packet.nettime() - ourTime; + Log(lsINFO) << "Recv(Hello): " << getIP() << " :Clock far off +" << packet.nettime() - ourTime; else if(packet.nettime() < minTime) - Log(lsINFO) << "Recv(Hello): Disconnect: Clock is far off -" << ourTime - packet.nettime(); + Log(lsINFO) << "Recv(Hello): " << getIP() << " :Clock far off -" << ourTime - packet.nettime(); } else if (packet.protoversionmin() < MAKE_VERSION_INT(MIN_PROTO_MAJOR, MIN_PROTO_MINOR)) { From f4dad6fe3c06caddd1cabb739bfa9633b7d6879f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 09:54:27 -0700 Subject: [PATCH 185/426] Timestamps were expiring too soon. --- src/SNTPClient.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index d204b6a8ec..bb1daa098b 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -14,8 +14,8 @@ static uint8_t SNTPQueryData[48] = { 0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; -// NTP query frequency - 5 minutes -#define NTP_QUERY_FREQUENCY (5 * 60) +// NTP query frequency - 4 minutes +#define NTP_QUERY_FREQUENCY (4 * 60) // NTP minimum interval to query same servers - 3 minutes #define NTP_MIN_QUERY (3 * 60) @@ -26,6 +26,9 @@ static uint8_t SNTPQueryData[48] = // NTP timestamp constant #define NTP_UNIX_OFFSET 0x83AA7E80 +// NTP timestamp validity +#define NTP_TIMESTAMP_VALID ((NTP_QUERY_FREQUENCY + NTP_MIN_QUERY) * 2) + // SNTP packet offsets #define NTP_OFF_INFO 0 #define NTP_OFF_ROOTDELAY 1 @@ -215,7 +218,7 @@ void SNTPClient::queryAll() bool SNTPClient::getOffset(int& offset) { boost::mutex::scoped_lock sl(mLock); - if ((mLastOffsetUpdate == (time_t) -1) || ((mLastOffsetUpdate + 90) < time(NULL))) + if ((mLastOffsetUpdate == (time_t) -1) || ((mLastOffsetUpdate + NTP_TIMESTAMP_VALID) < time(NULL))) return false; offset = mOffset; return true; From 0862ed2957a185cbedd84fca58a57f859165120c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 10:14:25 -0700 Subject: [PATCH 186/426] Don't get stuck in consensus process. --- src/LedgerConsensus.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 744ca1785e..1a5b975ad3 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -519,8 +519,7 @@ void LedgerConsensus::stateAccepted() void LedgerConsensus::timerEntry() { - if (!mHaveCorrectLCL) - checkLCL(); + checkLCL(); mCurrentMSeconds = (boost::posix_time::microsec_clock::universal_time() - mConsensusStartTime).total_milliseconds(); From 61831eaa3c76e340a9b8e9d49b68bef5de9196ff Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 3 Sep 2012 13:57:01 -0700 Subject: [PATCH 187/426] Obsolete redeem and issue flag support from ripple paths. --- src/Amount.cpp | 2 + src/SerializedTypes.h | 2 + src/TransactionEngine.cpp | 251 ++++++++++++++++++-------------------- src/TransactionEngine.h | 11 +- 4 files changed, 129 insertions(+), 137 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index b1588dc05a..3391f470ff 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -10,6 +10,8 @@ #include "SerializedTypes.h" #include "utils.h" +uint64 STAmount::uRateOne = STAmount::getRate(STAmount(1), STAmount(1)); + bool STAmount::currencyFromString(uint160& uDstCurrency, const std::string& sCurrency) { bool bSuccess = true; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 4baa4e9b40..8f8718fa0c 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -254,6 +254,8 @@ protected: static uint64 muldiv(uint64, uint64, uint64); public: + static uint64 uRateOne; + STAmount(uint64 v = 0, bool isNeg = false) : mValue(v), mOffset(0), mIsNative(true), mIsNegative(isNeg) { if (v==0) mIsNegative = false; } diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 947b53f50d..7ff93aaca9 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1048,7 +1048,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, if (tesSUCCESS == terResult) { - if (!!saCost) + if (saCost) { // Only check fee is sufficient when the ledger is open. if (isSetBit(params, tapOPEN_LEDGER) && saPaid < saCost) @@ -1060,7 +1060,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, } else { - if (!!saPaid) + if (saPaid) { // Transaction is malformed. Log(lsWARNING) << "applyTransaction: fee not allowed"; @@ -1210,7 +1210,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, { nothing(); } - else if (!!saCost) + else if (saCost) { uint32 a_seq = mTxnAccount->getIFieldU32(sfSequence); @@ -1670,7 +1670,7 @@ TER TransactionEngine::doNicknameSet(const SerializedTransaction& txn) // Edit old entry. sleNickname->setIFieldAccount(sfAccount, mTxnAccountID); - if (bMinOffer && !!saMinOffer) + if (bMinOffer && saMinOffer) { sleNickname->setIFieldAmount(sfMinimumOffer, saMinOffer); } @@ -1692,7 +1692,7 @@ TER TransactionEngine::doNicknameSet(const SerializedTransaction& txn) sleNickname->setIFieldAccount(sfAccount, mTxnAccountID); - if (bMinOffer && !!saMinOffer) + if (bMinOffer && saMinOffer) sleNickname->setIFieldAmount(sfMinimumOffer, saMinOffer); } @@ -2376,7 +2376,8 @@ void TransactionEngine::calcNodeRipple( const STAmount& saPrvReq, // --> in limit including fees, <0 = unlimited const STAmount& saCurReq, // --> out limit (driver) STAmount& saPrvAct, // <-> in limit including achieved - STAmount& saCurAct) // <-> out limit achieved. + STAmount& saCurAct, // <-> out limit achieved. + uint64& uRateMax) { Log(lsINFO) << boost::str(boost::format("calcNodeRipple> uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s") % uQualityIn @@ -2404,38 +2405,52 @@ void TransactionEngine::calcNodeRipple( // No fee. Log(lsINFO) << boost::str(boost::format("calcNodeRipple: No fees")); - STAmount saTransfer = bPrvUnlimited ? saCur : std::min(saPrv, saCur); + if (!uRateMax || STAmount::uRateOne <= uRateMax) + { + STAmount saTransfer = bPrvUnlimited ? saCur : std::min(saPrv, saCur); - saPrvAct += saTransfer; - saCurAct += saTransfer; + saPrvAct += saTransfer; + saCurAct += saTransfer; + + if (!uRateMax) + uRateMax = STAmount::uRateOne; + } } else { // Fee. Log(lsINFO) << boost::str(boost::format("calcNodeRipple: Fee")); - const uint160 uCurrencyID = saCur.getCurrency(); - const uint160 uCurIssuerID = saCur.getIssuer(); - const uint160 uPrvIssuerID = saPrv.getIssuer(); + uint64 uRate = STAmount::getRate(STAmount(uQualityIn), STAmount(uQualityOut)); - STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID, uCurIssuerID), uQualityIn, uCurrencyID, uCurIssuerID); - -Log(lsINFO) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCurIn=%s") % bPrvUnlimited % saPrv.getFullText() % saCurIn.getFullText()); - if (bPrvUnlimited || saCurIn <= saPrv) + if (!uRateMax || uRate <= uRateMax) { - // All of cur. Some amount of prv. - saCurAct += saCur; - saPrvAct += saCurIn; -Log(lsINFO) << boost::str(boost::format("calcNodeRipple:3c: saCurReq=%s saPrvAct=%s") % saCurReq.getFullText() % saPrvAct.getFullText()); - } - else - { - // A part of cur. All of prv. (cur as driver) - STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID, uCurIssuerID), uQualityOut, uCurrencyID, uCurIssuerID); -Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.getFullText()); + const uint160 uCurrencyID = saCur.getCurrency(); + const uint160 uCurIssuerID = saCur.getIssuer(); + const uint160 uPrvIssuerID = saPrv.getIssuer(); - saCurAct += saCurOut; - saPrvAct = saPrvReq; + STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID, uCurIssuerID), uQualityIn, uCurrencyID, uCurIssuerID); + + Log(lsINFO) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCurIn=%s") % bPrvUnlimited % saPrv.getFullText() % saCurIn.getFullText()); + if (bPrvUnlimited || saCurIn <= saPrv) + { + // All of cur. Some amount of prv. + saCurAct += saCur; + saPrvAct += saCurIn; + Log(lsINFO) << boost::str(boost::format("calcNodeRipple:3c: saCurReq=%s saPrvAct=%s") % saCurReq.getFullText() % saPrvAct.getFullText()); + } + else + { + // A part of cur. All of prv. (cur as driver) + STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID, uCurIssuerID), uQualityOut, uCurrencyID, uCurIssuerID); + Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.getFullText()); + + saCurAct += saCurOut; + saPrvAct = saPrvReq; + + if (!uRateMax) + uRateMax = uRate; + } } } @@ -2455,14 +2470,13 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS TER terResult = tesSUCCESS; const unsigned int uLast = pspCur->vpnNodes.size() - 1; + uint64 uRateMax = 0; + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - const bool bRedeem = isSetBit(pnCur.uFlags, STPathElement::typeRedeem); - const bool bPrvRedeem = isSetBit(pnPrv.uFlags, STPathElement::typeRedeem); - const bool bIssue = isSetBit(pnCur.uFlags, STPathElement::typeIssue); - const bool bPrvIssue = isSetBit(pnPrv.uFlags, STPathElement::typeIssue); + // Current is allowed to redeem to next. const bool bPrvAccount = !uIndex || isSetBit(pnPrv.uFlags, STPathElement::typeAccount); const bool bNxtAccount = uIndex == uLast || isSetBit(pnNxt.uFlags, STPathElement::typeAccount); @@ -2483,10 +2497,13 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID, uCurAccountID); - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d bPrvIssue=%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s") + const STAmount saNxtOwed = uIndex != uLast && bNxtAccount // Next account is owed. + ? rippleOwed(uCurAccountID, uNxtAccountID, uCurrencyID) + : STAmount(uCurrencyID, uCurAccountID); + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s") % uIndex % uLast - % bPrvIssue % NewcoinAddress::createHumanAccountID(uPrvAccountID) % NewcoinAddress::createHumanAccountID(uCurAccountID) % NewcoinAddress::createHumanAccountID(uNxtAccountID) @@ -2497,11 +2514,11 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS % saPrvLimit.getFullText()); // Previous can redeem the owed IOUs it holds. - const STAmount saPrvRedeemReq = bPrvRedeem && saPrvOwed.isPositive() ? saPrvOwed : STAmount(uCurrencyID, 0); + const STAmount saPrvRedeemReq = saPrvOwed.isPositive() ? saPrvOwed : STAmount(uCurrencyID, 0); STAmount& saPrvRedeemAct = pnPrv.saRevRedeem; // Previous can issue up to limit minus whatever portion of limit already used (not including redeemable amount). - const STAmount saPrvIssueReq = bPrvIssue && saPrvOwed.isNegative() ? saPrvLimit+saPrvOwed : saPrvLimit; + const STAmount saPrvIssueReq = saPrvOwed.isNegative() ? saPrvLimit+saPrvOwed : saPrvLimit; STAmount& saPrvIssueAct = pnPrv.saRevIssue; // For !bPrvAccount @@ -2546,25 +2563,26 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS % saCurWantedReq.getFullText()); // Calculate redeem - if (bRedeem - && saPrvRedeemReq) // Previous has IOUs to redeem. + if (saPrvRedeemReq) // Previous has IOUs to redeem. { // Redeem at 1:1 Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Redeem at 1:1")); saCurWantedAct = std::min(saPrvRedeemReq, saCurWantedReq); saPrvRedeemAct = saCurWantedAct; + + uRateMax = STAmount::uRateOne; } // Calculate issuing. - if (bIssue - && saCurWantedReq != saCurWantedAct // Need more. - && saPrvIssueReq) // Will accept IOUs. + if (saCurWantedReq != saCurWantedAct // Need more. + && saPrvIssueReq) // Will accept IOUs from prevous. { // Rate: quality in : 1.0 Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurWantedReq, saPrvIssueAct, saCurWantedAct); + // If we previously redeemed and this has a poorer rate, this won't be included the current increment. + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurWantedReq, saPrvIssueAct, saCurWantedAct, uRateMax); } if (!saCurWantedAct) @@ -2578,53 +2596,46 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS // ^|account --> ACCOUNT --> account // redeem (part 1) -> redeem - if (bPrvRedeem - && bRedeem // Allowed to redeem. - && saCurRedeemReq // Next wants us to redeem. - && saPrvOwed) // Previous has IOUs to redeem. + if (saCurRedeemReq // Next wants us to redeem. + && saPrvRedeemReq) // Previous has IOUs to redeem. { // Rate : 1.0 : quality out Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : quality out")); - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); - } - - // redeem (part 2) -> issue. - if (bPrvRedeem - && bIssue // Allowed to issue. - && saCurRedeemReq != saCurRedeemAct // Can only if issue if more can not be redeemed. - && saPrvOwed // Previous still has IOUs. - && saCurIssueReq) // Need some issued. - { - // Rate : 1.0 : transfer_rate - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : transfer_rate")); - - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax); } // issue (part 1)-> redeem - if (bPrvIssue - && bRedeem // Allowed to redeem. - && saCurRedeemReq != saCurRedeemAct // Can only redeem if more to be redeemed. - && !saPrvOwed.isPositive()) // Previous has no IOUs. + if (saCurRedeemReq != saCurRedeemAct // More to redeem. + && saPrvRedeemReq == saPrvRedeemAct) // Previously redeemed all owed IOUs. { // Rate: quality in : quality out Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : quality out")); - calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct, uRateMax); + } + + // redeem (part 2) -> issue. + if (saCurIssueReq // Need some issued. + && saCurRedeemAct == saNxtOwed // Can only issue if previously redeemed all owed. + && saPrvOwed.isPositive() // Previous has IOUs to redeem. + && saPrvRedeemAct != saPrvOwed) // Did not previously redeem all IOUs. + { + // Rate : 1.0 : transfer_rate + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : transfer_rate")); + + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax); } // issue (part 2) -> issue - if (bPrvIssue - && bIssue // Allowed to issue. - && saCurRedeemReq == saCurRedeemAct // Can only if issue if more can not be redeemed. - && !saPrvOwed.isPositive() // Previous has no IOUs. - && saCurIssueReq != saCurIssueAct) // Need some issued. + if (saCurIssueReq != saCurIssueAct // Need some issued. + && saCurRedeemAct == saNxtOwed // Can only issue if previously redeemed all owed. + && saPrvRedeemReq == saPrvRedeemAct) // Previously redeemed all owed IOUs. { // Rate: quality in : 1.0 Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax); } if (!saCurRedeemAct && !saCurIssueAct) @@ -2633,11 +2644,7 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS terResult = tepPATH_DRY; } - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurRedeemReq=%s saCurIssueReq=%s saPrvOwed=%s saCurRedeemAct=%s saCurIssueAct=%s") - % bPrvRedeem - % bPrvIssue - % bRedeem - % bIssue + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : saCurRedeemReq=%s saCurIssueReq=%s saPrvOwed=%s saCurRedeemAct=%s saCurIssueAct=%s") % saCurRedeemReq.getFullText() % saCurIssueReq.getFullText() % saPrvOwed.getFullText() @@ -2652,24 +2659,19 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> offer")); // redeem -> deliver/issue. - if (bPrvRedeem - && bIssue // Allowed to issue. - && saPrvOwed.isPositive() // Previous redeeming: Previous still has IOUs. + if (saPrvOwed.isPositive() // Previous has IOUs to redeem. && saCurDeliverReq) // Need some issued. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct, uRateMax); } // issue -> deliver/issue - if (bPrvIssue - && bIssue // Allowed to issue. - && (!saPrvOwed.isPositive() // Previous issuing: Never had IOUs. - || saPrvOwed == saPrvRedeemAct) // Previous issuing: Previous has no IOUs left after redeeming. - && saCurDeliverReq != saCurDeliverAct) // Need some issued. + if (saPrvRedeemReq == saPrvRedeemAct // Previously redeemed all owed. + && saCurDeliverReq != saCurDeliverAct) // Still need some issued. { // Rate: quality in : 1.0 - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurDeliverReq, saPrvIssueAct, saCurDeliverAct); + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurDeliverReq, saPrvIssueAct, saCurDeliverAct, uRateMax); } if (!saCurDeliverAct) @@ -2678,11 +2680,7 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS terResult = tepPATH_DRY; } - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: bPrvRedeem=%d bPrvIssue=%d bRedeem=%d bIssue=%d saCurDeliverReq=%s saCurDeliverAct=%s saPrvOwed=%s") - % bPrvRedeem - % bPrvIssue - % bRedeem - % bIssue + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saCurDeliverReq=%s saCurDeliverAct=%s saPrvOwed=%s") % saCurDeliverReq.getFullText() % saCurDeliverAct.getFullText() % saPrvOwed.getFullText()); @@ -2694,14 +2692,14 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS // offer --> ACCOUNT --> $ const STAmount& saCurWantedReq = bPrvAccount ? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. - : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $ : saCurWantedReq=%s") % saCurWantedReq.getFullText()); // Rate: quality in : 1.0 - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct); + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct, uRateMax); if (!saCurWantedAct) { @@ -2716,27 +2714,23 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> account")); // deliver -> redeem - if (bRedeem // Allowed to redeem. - && saCurRedeemReq) // Next wants us to redeem. + if (saCurRedeemReq) // Next wants us to redeem. { // Rate : 1.0 : quality out - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct); + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct, uRateMax); } // deliver -> issue. - if (bIssue // Allowed to issue. - && saCurRedeemReq == saCurRedeemAct // Can only if issue if more can not be redeemed. + if (saCurRedeemReq == saCurRedeemAct // Can only issue if previously redeemed all. && saCurIssueReq) // Need some issued. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct, uRateMax); } - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: bRedeem=%d saCurRedeemReq=%s saCurIssueAct=%s bIssue=%d saCurIssueReq=%s saPrvDeliverAct=%s") - % bRedeem + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saCurRedeemReq=%s saCurIssueAct=%s saCurIssueReq=%s saPrvDeliverAct=%s") % saCurRedeemReq.getFullText() % saCurRedeemAct.getFullText() - % bIssue % saCurIssueReq.getFullText() % saPrvDeliverAct.getFullText()); @@ -2753,12 +2747,8 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS // deliver/redeem -> deliver/issue. Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> offer")); - if (bIssue // Allowed to issue. - && saCurDeliverReq != saCurDeliverAct) // Can only if issue if more can not be redeemed. - { - // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct); - } + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct, uRateMax); if (!saCurDeliverAct) { @@ -2784,6 +2774,8 @@ TER TransactionEngine::calcNodeAccountFwd( TER terResult = tesSUCCESS; const unsigned int uLast = pspCur->vpnNodes.size() - 1; + uint64 uRateMax = 0; + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; @@ -2921,7 +2913,7 @@ TER TransactionEngine::calcNodeAccountFwd( && saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. { // Rate : 1.0 : quality out - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct); + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax); } // Previous redeem part 2: redeem -> issue. @@ -2933,7 +2925,7 @@ TER TransactionEngine::calcNodeAccountFwd( && saCurIssueReq) { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax); } // Previous issue part 1: issue -> redeem @@ -2942,7 +2934,7 @@ TER TransactionEngine::calcNodeAccountFwd( && saCurRedeemReq != saCurRedeemAct) // Current has more to redeem to next. { // Rate: quality in : quality out - calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct); + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct, uRateMax); } // Previous issue part 2 : issue -> issue @@ -2950,7 +2942,7 @@ TER TransactionEngine::calcNodeAccountFwd( && saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. { // Rate: quality in : 1.0 - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct); + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax); } // Adjust prv --> cur balance : take all inbound @@ -2969,7 +2961,7 @@ TER TransactionEngine::calcNodeAccountFwd( if (saPrvRedeemReq) // Previous wants to redeem. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct, uRateMax); } // issue -> issue @@ -2977,7 +2969,7 @@ TER TransactionEngine::calcNodeAccountFwd( && saPrvIssueReq) // Previous wants to issue. To next must be ok. { // Rate: quality in : 1.0 - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurDeliverReq, saPrvIssueAct, saCurDeliverAct); + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurDeliverReq, saPrvIssueAct, saCurDeliverAct, uRateMax); } // Adjust prv --> cur balance : take all inbound @@ -3008,7 +3000,7 @@ TER TransactionEngine::calcNodeAccountFwd( && saPrvDeliverReq) // Previous wants to deliver. { // Rate : 1.0 : quality out - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct); + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct, uRateMax); } // deliver -> issue @@ -3019,7 +3011,7 @@ TER TransactionEngine::calcNodeAccountFwd( && saCurIssueReq) // Current wants issue. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct, uRateMax); } // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. @@ -3036,7 +3028,7 @@ TER TransactionEngine::calcNodeAccountFwd( && saCurIssueReq) // Current wants issue. { // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct); + calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct, uRateMax); } // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. @@ -3270,8 +3262,7 @@ PathState::PathState( const uint160& uReceiverID, const uint160& uSenderID, const STAmount& saSend, - const STAmount& saSendMax, - const bool bPartialPayment + const STAmount& saSendMax ) : mLedger(lpLedger), mIndex(iIndex), uQuality(0) { @@ -3412,16 +3403,16 @@ Json::Value PathState::getJson() const jvPathState["index"] = mIndex; jvPathState["nodes"] = jvNodes; - if (!!saInReq) + if (saInReq) jvPathState["in_req"] = saInReq.getJson(0); - if (!!saInAct) + if (saInAct) jvPathState["in_act"] = saInAct.getJson(0); - if (!!saOutReq) + if (saOutReq) jvPathState["out_req"] = saOutReq.getJson(0); - if (!!saOutAct) + if (saOutAct) jvPathState["out_act"] = saOutAct.getJson(0); if (uQuality) @@ -3539,8 +3530,8 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) // Ripple if source or destination is non-native or if there are paths. const uint32 uTxFlags = txn.getFlags(); const bool bCreate = isSetBit(uTxFlags, tfCreateAccount); - const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect); const bool bPartialPayment = isSetBit(uTxFlags, tfPartialPayment); + const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect); const bool bPaths = txn.getITFieldPresent(sfPaths); const bool bMax = txn.getITFieldPresent(sfSendMax); const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); @@ -3673,8 +3664,7 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) uDstAccountID, mTxnAccountID, saDstAmount, - saMaxAmount, - bPartialPayment); + saMaxAmount); if (pspDirect) { @@ -3706,8 +3696,7 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) uDstAccountID, mTxnAccountID, saDstAmount, - saMaxAmount, - bPartialPayment); + saMaxAmount); if (pspExpanded) { @@ -3917,7 +3906,7 @@ TER TransactionEngine::takeOffers( STAmount& saTakerPaid, STAmount& saTakerGot) { - assert(!!saTakerPays && !!saTakerGets); + assert(saTakerPays && saTakerGets); Log(lsINFO) << "takeOffers: against book: " << uBookBase.ToString(); @@ -4265,8 +4254,8 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); // Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); if (tesSUCCESS == terResult - && !!saTakerPays // Still wanting something. - && !!saTakerGets // Still offering something. + && saTakerPays // Still wanting something. + && saTakerGets // Still offering something. && accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded. { // We need to place the remainder of the offer into its order book. diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 2310551db6..4d8aae4148 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -235,8 +235,7 @@ public: const uint160& uReceiverID, const uint160& uSenderID, const STAmount& saSend, - const STAmount& saSendMax, - const bool bPartialPayment + const STAmount& saSendMax ); Json::Value getJson() const; @@ -249,11 +248,10 @@ public: const uint160& uReceiverID, const uint160& uSenderID, const STAmount& saSend, - const STAmount& saSendMax, - const bool bPartialPayment + const STAmount& saSendMax ) { - return boost::make_shared(lpLedger, iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax, bPartialPayment); + return boost::make_shared(lpLedger, iIndex, lesSource, spSourcePath, uReceiverID, uSenderID, saSend, saSendMax); } static bool lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs); @@ -355,7 +353,8 @@ protected: void calcNodeRipple(const uint32 uQualityIn, const uint32 uQualityOut, const STAmount& saPrvReq, const STAmount& saCurReq, - STAmount& saPrvAct, STAmount& saCurAct); + STAmount& saPrvAct, STAmount& saCurAct, + uint64& uRateMax); void txnWrite(); From 8910a3e14b7659bb8eb5fde09646c9157b06416a Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 3 Sep 2012 14:15:31 -0700 Subject: [PATCH 188/426] Implement quality limit for ripple. --- src/TransactionEngine.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 7ff93aaca9..92f8c31514 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -3531,6 +3531,7 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) const uint32 uTxFlags = txn.getFlags(); const bool bCreate = isSetBit(uTxFlags, tfCreateAccount); const bool bPartialPayment = isSetBit(uTxFlags, tfPartialPayment); + const bool bLimitQuality = isSetBit(uTxFlags, tfLimitQuality); const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect); const bool bPaths = txn.getITFieldPresent(sfPaths); const bool bMax = txn.getITFieldPresent(sfSendMax); @@ -3731,7 +3732,8 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) STAmount saPaid; STAmount saWanted; - LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. + LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. + uint64 uQualityLimit = STAmount::getRate(saDstAmount, saMaxAmount); while (temUNCERTAIN == terResult) { @@ -3748,8 +3750,12 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) mNodes.swapWith(pspCur->lesEntries); // For the path, save ledger state. - if (!pspBest || (pspCur->uQuality && PathState::lessPriority(pspBest, pspCur))) + if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality. + || !pspBest // Best is not yet set. + || (pspCur->uQuality && PathState::lessPriority(pspBest, pspCur))) // Current is better than set. + { pspBest = pspCur; + } } if (pspBest) From 74392e59291736a0a9386437f3ff839384c7eaeb Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 3 Sep 2012 14:28:45 -0700 Subject: [PATCH 189/426] Provide seperate ledger entry to state to ripple reverse. --- src/TransactionEngine.cpp | 42 ++++++++++++++++++++------------------- src/TransactionEngine.h | 2 +- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 92f8c31514..e81ffee320 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -3481,12 +3481,6 @@ TER TransactionEngine::calcNodeRev(const unsigned int uIndex, const PathState::p terResult = calcNodeRev(uIndex-1, pspCur, bMultiQuality); } - else - { - // Do forward. - - terResult = calcNodeFwd(0, pspCur, bMultiQuality); - } Log(lsINFO) << boost::str(boost::format("calcNodeRev< uIndex=%d terResult=%d") % uIndex % terResult); @@ -3496,12 +3490,12 @@ TER TransactionEngine::calcNodeRev(const unsigned int uIndex, const PathState::p // Calculate the next increment of a path. // The increment is what can satisfy a portion or all of the requested output at the best quality. // <-- pspCur->uQuality -void TransactionEngine::pathNext(const PathState::pointer& pspCur, const int iPaths) +void TransactionEngine::pathNext(const PathState::pointer& pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint) { // The next state is what is available in preference order. // This is calculated when referenced accounts changed. - - unsigned int uLast = pspCur->vpnNodes.size() - 1; + const bool bMultiQuality = iPaths == 1; + const unsigned int uLast = pspCur->vpnNodes.size() - 1; Log(lsINFO) << "Path In: " << pspCur->getJson(); @@ -3510,7 +3504,19 @@ void TransactionEngine::pathNext(const PathState::pointer& pspCur, const int iPa pspCur->vUnfundedBecame.clear(); pspCur->umReverse.clear(); - pspCur->terStatus = calcNodeRev(uLast, pspCur, iPaths == 1); + mNodes = lesCheckpoint; // Restore from checkpoint. + mNodes.bumpSeq(); // Begin ledger varance. + + pspCur->terStatus = calcNodeRev(uLast, pspCur, bMultiQuality); + + if (tesSUCCESS == pspCur->terStatus) + { + // Do forward. + mNodes = lesCheckpoint; // Restore from checkpoint. + mNodes.bumpSeq(); // Begin ledger varance. + + pspCur->terStatus = calcNodeFwd(0, pspCur, bMultiQuality); + } Log(lsINFO) << "pathNext: terStatus=" << pspCur->terStatus @@ -3518,8 +3524,8 @@ void TransactionEngine::pathNext(const PathState::pointer& pspCur, const int iPa << " saInAct=" << pspCur->saInAct.getText(); pspCur->uQuality = tesSUCCESS == pspCur->terStatus - ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. - : 0; // Mark path as inactive. + ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. + : 0; // Mark path as inactive. Log(lsINFO) << "Path Out: " << pspCur->getJson(); } @@ -3732,8 +3738,8 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) STAmount saPaid; STAmount saWanted; - LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. - uint64 uQualityLimit = STAmount::getRate(saDstAmount, saMaxAmount); + LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. + uint64 uQualityLimit = bLimitQuality ? STAmount::getRate(saDstAmount, saMaxAmount) : 0; while (temUNCERTAIN == terResult) { @@ -3743,17 +3749,13 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) // Find the best path. BOOST_FOREACH(PathState::pointer pspCur, vpsPaths) { - mNodes = lesCheckpoint; // Restore from checkpoint. - mNodes.bumpSeq(); // Begin ledger varance. - - pathNext(pspCur, vpsPaths.size()); // Compute increment - - mNodes.swapWith(pspCur->lesEntries); // For the path, save ledger state. + pathNext(pspCur, vpsPaths.size(), lesCheckpoint); // Compute increment. if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality. || !pspBest // Best is not yet set. || (pspCur->uQuality && PathState::lessPriority(pspBest, pspCur))) // Current is better than set. { + mNodes.swapWith(pspCur->lesEntries); // For the path, save ledger state. pspBest = pspCur; } } diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 4d8aae4148..2dcd04e2fa 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -332,7 +332,7 @@ protected: STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault); PathState::pointer pathCreate(const STPath& spPath); - void pathNext(const PathState::pointer& pspCur, const int iPaths); + 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); From dda279e5a62c4c0df76f19807aaeec13abb52dfd Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 3 Sep 2012 14:37:00 -0700 Subject: [PATCH 190/426] Remove remaining support for redeem and issue flags. --- src/SerializedTypes.h | 4 - src/TransactionEngine.cpp | 217 +++++++++++++++----------------------- 2 files changed, 87 insertions(+), 134 deletions(-) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 8f8718fa0c..b875acffb1 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -545,15 +545,11 @@ public: enum { typeEnd = 0x00, typeAccount = 0x01, // Rippling through an account (vs taking an offer). - typeRedeem = 0x04, // Redeem IOUs. - typeIssue = 0x08, // Issue IOUs. typeCurrency = 0x10, // Currency follows. typeIssuer = 0x20, // Issuer follows. typeBoundary = 0xFF, // Boundary between alternate paths. typeValidBits = ( typeAccount - | typeRedeem - | typeIssue | typeCurrency | typeIssuer ), // Bits that may be non-zero. diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index e81ffee320..d9d94fefcf 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -2780,8 +2780,6 @@ TER TransactionEngine::calcNodeAccountFwd( PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - const bool bRedeem = isSetBit(pnCur.uFlags, STPathElement::typeRedeem); - const bool bIssue = isSetBit(pnCur.uFlags, STPathElement::typeIssue); const bool bPrvAccount = isSetBit(pnPrv.uFlags, STPathElement::typeAccount); const bool bNxtAccount = isSetBit(pnNxt.uFlags, STPathElement::typeAccount); @@ -2816,11 +2814,9 @@ TER TransactionEngine::calcNodeAccountFwd( const STAmount& saCurDeliverReq = pnCur.saRevDeliver; STAmount& saCurDeliverAct = pnCur.saFwdDeliver; - Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uIndex=%d/%d bRedeem=%d bIssue=%d saPrvRedeemReq=%s saPrvIssueReq=%s saPrvDeliverReq=%s saCurRedeemReq=%s saCurIssueReq=%s saCurDeliverReq=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uIndex=%d/%d saPrvRedeemReq=%s saPrvIssueReq=%s saPrvDeliverReq=%s saCurRedeemReq=%s saCurIssueReq=%s saCurDeliverReq=%s") % uIndex % uLast - % bRedeem - % bIssue % saPrvRedeemReq.getFullText() % saPrvIssueReq.getFullText() % saPrvDeliverReq.getFullText() @@ -2909,18 +2905,24 @@ TER TransactionEngine::calcNodeAccountFwd( Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> account")); // Previous redeem part 1: redeem -> redeem - if (bRedeem // Can redeem. - && saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. + if (saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. { // Rate : 1.0 : quality out calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax); } + // Previous issue part 1: issue -> redeem + if (saPrvIssueReq != saPrvIssueAct // Previous wants to issue. + && saCurRedeemReq != saCurRedeemAct) // Current has more to redeem to next. + { + // Rate: quality in : quality out + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct, uRateMax); + } + // Previous redeem part 2: redeem -> issue. // wants to redeem and current would and can issue. // If redeeming cur to next is done, this implies can issue. - if (bIssue // Can issue. - && saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem. + if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem. && saCurRedeemReq == saCurRedeemAct // Current has no more to redeem to next. && saCurIssueReq) { @@ -2928,18 +2930,8 @@ TER TransactionEngine::calcNodeAccountFwd( calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax); } - // Previous issue part 1: issue -> redeem - if (bRedeem // Can redeem. - && saPrvIssueReq != saPrvIssueAct // Previous wants to issue. - && saCurRedeemReq != saCurRedeemAct) // Current has more to redeem to next. - { - // Rate: quality in : quality out - calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct, uRateMax); - } - // Previous issue part 2 : issue -> issue - if (bIssue // Can issue. - && saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. + if (saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. { // Rate: quality in : 1.0 calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax); @@ -2996,8 +2988,7 @@ TER TransactionEngine::calcNodeAccountFwd( Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> account")); // deliver -> redeem - if (bRedeem // Allowed to redeem. - && saPrvDeliverReq) // Previous wants to deliver. + if (saPrvDeliverReq) // Previous wants to deliver. { // Rate : 1.0 : quality out calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct, uRateMax); @@ -3005,8 +2996,7 @@ TER TransactionEngine::calcNodeAccountFwd( // deliver -> issue // Wants to redeem and current would and can issue. - if (bIssue // Allowed to issue. - && saPrvDeliverReq != saPrvDeliverAct // Previous still wants to deliver. + if (saPrvDeliverReq != saPrvDeliverAct // Previous still wants to deliver. && saCurRedeemReq == saCurRedeemAct // Current has more to redeem to next. && saCurIssueReq) // Current wants issue. { @@ -3023,8 +3013,7 @@ TER TransactionEngine::calcNodeAccountFwd( // deliver/redeem -> deliver/issue. Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> offer")); - if (bIssue // Allowed to issue. - && saPrvDeliverReq // Previous wants to deliver + if (saPrvDeliverReq // Previous wants to deliver && saCurIssueReq) // Current wants issue. { // Rate : 1.0 : transfer_rate @@ -3089,9 +3078,7 @@ TER PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssue // Need to ripple through uIssuerID's account. terResult = pushNode( - STPathElement::typeAccount - | STPathElement::typeRedeem - | STPathElement::typeIssue, + STPathElement::typeAccount, uIssuerID, // Intermediate account is the needed issuer. uCurrencyID, uIssuerID); @@ -3120,9 +3107,6 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint const bool bCurrency = isSetBit(iType, STPathElement::typeCurrency); // Issuer is specified for the output of the current node. const bool bIssuer = isSetBit(iType, STPathElement::typeIssuer); - // true, iff account is allowed to redeem it's IOUs to next node. - const bool bRedeem = isSetBit(iType, STPathElement::typeRedeem); - const bool bIssue = isSetBit(iType, STPathElement::typeIssue); TER terResult = tesSUCCESS; pnCur.uFlags = iType; @@ -3135,118 +3119,101 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint } else if (bAccount) { - if (bRedeem || bIssue) + // Account link + + pnCur.uAccountID = uAccountID; + pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; + pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; + pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID); + pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID); + + if (!bFirst) { - // Account link + // Add required intermediate nodes to deliver to current account. + terResult = pushImply( + pnCur.uAccountID, // Current account. + pnCur.uCurrencyID, // Wanted currency. + !!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as issuer. + } - pnCur.uAccountID = uAccountID; - pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; - pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; - pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID); - pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID); + if (tesSUCCESS == terResult && !vpnNodes.empty()) + { + const PaymentNode& pnBck = vpnNodes.back(); + bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); - if (!bFirst) + if (bBckAccount) { - // Add required intermediate nodes to deliver to current account. - terResult = pushImply( - pnCur.uAccountID, // Current account. - pnCur.uCurrencyID, // Wanted currency. - !!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as issuer. - } + SLE::pointer sleRippleState = mLedger->getSLE(Ledger::getRippleStateIndex(pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID)); - if (tesSUCCESS == terResult && !vpnNodes.empty()) - { - const PaymentNode& pnBck = vpnNodes.back(); - bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); - - if (bBckAccount) + if (!sleRippleState) { - SLE::pointer sleRippleState = mLedger->getSLE(Ledger::getRippleStateIndex(pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID)); + Log(lsINFO) << "pushNode: No credit line between " + << NewcoinAddress::createHumanAccountID(pnBck.uAccountID) + << " and " + << NewcoinAddress::createHumanAccountID(pnCur.uAccountID) + << " for " + << STAmount::createHumanCurrency(pnPrv.uCurrencyID) + << "." ; - if (!sleRippleState) - { - Log(lsINFO) << "pushNode: No credit line between " - << NewcoinAddress::createHumanAccountID(pnBck.uAccountID) - << " and " - << NewcoinAddress::createHumanAccountID(pnCur.uAccountID) - << " for " - << STAmount::createHumanCurrency(pnPrv.uCurrencyID) - << "." ; - - terResult = terNO_LINE; - } - else - { - Log(lsINFO) << "pushNode: Credit line found between " - << NewcoinAddress::createHumanAccountID(pnBck.uAccountID) - << " and " - << NewcoinAddress::createHumanAccountID(pnCur.uAccountID) - << " for " - << STAmount::createHumanCurrency(pnPrv.uCurrencyID) - << "." ; - } + terResult = terNO_LINE; + } + else + { + Log(lsINFO) << "pushNode: Credit line found between " + << NewcoinAddress::createHumanAccountID(pnBck.uAccountID) + << " and " + << NewcoinAddress::createHumanAccountID(pnCur.uAccountID) + << " for " + << STAmount::createHumanCurrency(pnPrv.uCurrencyID) + << "." ; } } - - if (tesSUCCESS == terResult) - vpnNodes.push_back(pnCur); } - else - { - Log(lsINFO) << "pushNode: Account must redeem and/or issue."; - terResult = temBAD_PATH; - } + if (tesSUCCESS == terResult) + vpnNodes.push_back(pnCur); } else { // Offer link - if (bRedeem || bIssue) + // Offers bridge a change in currency & issuer or just a change in issuer. + pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; + pnCur.uIssuerID = bIssuer ? uIssuerID : pnCur.uAccountID; + + if (!!pnPrv.uAccountID) { - terResult = temBAD_PATH; + // Previous is an account. + + // Insert intermediary account if needed. + terResult = pushImply( + !!pnPrv.uCurrencyID ? ACCOUNT_ONE : ACCOUNT_XNS, + pnPrv.uCurrencyID, + pnPrv.uIssuerID); } else { - // Offers bridge a change in currency & issuer or just a change in issuer. - pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; - pnCur.uIssuerID = bIssuer ? uIssuerID : pnCur.uAccountID; + // Previous is an offer. + // XXX Need code if we don't do offer to offer. + nothing(); + } - if (!!pnPrv.uAccountID) + if (tesSUCCESS == terResult) + { + // Verify that previous is an account. + const PaymentNode& pnBck = vpnNodes.back(); + bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); + + if (bBckAccount) { - // Previous is an account. + Log(lsINFO) << "pushNode: previous must be account."; - // Insert intermediary account if needed. - terResult = pushImply( - !!pnPrv.uCurrencyID ? ACCOUNT_ONE : ACCOUNT_XNS, - pnPrv.uCurrencyID, - pnPrv.uIssuerID); - } - else - { - // Previous is an offer. - // XXX Need code if we don't do offer to offer. - nothing(); + terResult = temBAD_PATH; } + } - if (tesSUCCESS == terResult) - { - // Verify that previous account is allowed to issue. - const PaymentNode& pnBck = vpnNodes.back(); - bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); - bool bBckIssue = isSetBit(pnBck.uFlags, STPathElement::typeIssue); - - if (bBckAccount && !bBckIssue) - { - Log(lsINFO) << "pushNode: previous account must be allowed to issue."; - - terResult = temBAD_PATH; - } - } - - if (tesSUCCESS == terResult) - { - vpnNodes.push_back(pnCur); - } + if (tesSUCCESS == terResult) + { + vpnNodes.push_back(pnCur); } } Log(lsINFO) << "pushNode< " << terResult; @@ -3279,8 +3246,6 @@ PathState::PathState( // Push sending node. terStatus = pushNode( STPathElement::typeAccount - | STPathElement::typeRedeem - | STPathElement::typeIssue | STPathElement::typeCurrency | STPathElement::typeIssuer, uSenderID, @@ -3302,8 +3267,6 @@ PathState::PathState( { terStatus = pushNode( STPathElement::typeAccount // Last node is always an account. - | STPathElement::typeRedeem // Does not matter just pass error check. - | STPathElement::typeIssue // Does not matter just pass error check. | STPathElement::typeCurrency | STPathElement::typeIssuer, uReceiverID, // Receive to output @@ -3361,12 +3324,6 @@ Json::Value PathState::getJson() const if (pnNode.uFlags & STPathElement::typeAccount) jvFlags.append("account"); - if (pnNode.uFlags & STPathElement::typeRedeem) - jvFlags.append("redeem"); - - if (pnNode.uFlags & STPathElement::typeIssue) - jvFlags.append("issue"); - jvNode["flags"] = jvFlags; if (pnNode.uFlags & STPathElement::typeAccount) From 9a5d23d5d48957c888e36c21c379acf83c78cc8c Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 3 Sep 2012 14:43:16 -0700 Subject: [PATCH 191/426] Cosmetic. --- src/TransactionEngine.cpp | 87 +++++++++++++++------------------------ src/TransactionEngine.h | 3 -- 2 files changed, 33 insertions(+), 57 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index d9d94fefcf..d15eadb200 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -2037,17 +2037,11 @@ TER TransactionEngine::calcNodeAdvance( { PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; -// PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; const uint160& uPrvIssuerID = pnPrv.uIssuerID; const uint160& uCurCurrencyID = pnCur.uCurrencyID; const uint160& uCurIssuerID = pnCur.uIssuerID; -// const uint160& uNxtCurrencyID = pnNxt.uCurrencyID; -// const uint160& uNxtIssuerID = pnNxt.uIssuerID; - -// const uint160& uPrvAccountID = pnPrv.uAccountID; -// const uint160& uNxtAccountID = pnNxt.uAccountID; uint256& uDirectTip = pnCur.uDirectTip; uint256 uDirectEnd = pnCur.uDirectEnd; @@ -2425,9 +2419,9 @@ void TransactionEngine::calcNodeRipple( if (!uRateMax || uRate <= uRateMax) { - const uint160 uCurrencyID = saCur.getCurrency(); - const uint160 uCurIssuerID = saCur.getIssuer(); - const uint160 uPrvIssuerID = saPrv.getIssuer(); + const uint160 uCurrencyID = saCur.getCurrency(); + const uint160 uCurIssuerID = saCur.getIssuer(); + const uint160 uPrvIssuerID = saPrv.getIssuer(); STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID, uCurIssuerID), uQualityIn, uCurrencyID, uCurIssuerID); @@ -2472,32 +2466,32 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS uint64 uRateMax = 0; - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; // Current is allowed to redeem to next. - const bool bPrvAccount = !uIndex || isSetBit(pnPrv.uFlags, STPathElement::typeAccount); - const bool bNxtAccount = uIndex == uLast || isSetBit(pnNxt.uFlags, STPathElement::typeAccount); + const bool bPrvAccount = !uIndex || isSetBit(pnPrv.uFlags, STPathElement::typeAccount); + const bool bNxtAccount = uIndex == uLast || isSetBit(pnNxt.uFlags, STPathElement::typeAccount); - const uint160& uCurAccountID = pnCur.uAccountID; - const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; - const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. + const uint160& uCurAccountID = pnCur.uAccountID; + const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; + const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. - const uint160& uCurrencyID = pnCur.uCurrencyID; + const uint160& uCurrencyID = pnCur.uCurrencyID; - const uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; - const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; + const uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; + const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; // For bPrvAccount - const STAmount saPrvOwed = uIndex && bPrvAccount // Previous account is owed. - ? rippleOwed(uCurAccountID, uPrvAccountID, uCurrencyID) - : STAmount(uCurrencyID, uCurAccountID); - const STAmount saPrvLimit = uIndex && bPrvAccount // Previous account may owe. - ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) - : STAmount(uCurrencyID, uCurAccountID); + const STAmount saPrvOwed = uIndex && bPrvAccount // Previous account is owed. + ? rippleOwed(uCurAccountID, uPrvAccountID, uCurrencyID) + : STAmount(uCurrencyID, uCurAccountID); + const STAmount saPrvLimit = uIndex && bPrvAccount // Previous account may owe. + ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) + : STAmount(uCurrencyID, uCurAccountID); - const STAmount saNxtOwed = uIndex != uLast && bNxtAccount // Next account is owed. + const STAmount saNxtOwed = uIndex != uLast && bNxtAccount // Next account is owed. ? rippleOwed(uCurAccountID, uNxtAccountID, uCurrencyID) : STAmount(uCurrencyID, uCurAccountID); @@ -3335,22 +3329,22 @@ Json::Value PathState::getJson() const if (!!pnNode.uIssuerID) jvNode["issuer"] = NewcoinAddress::createHumanAccountID(pnNode.uIssuerID); - // if (!!pnNode.saRevRedeem) + // if (pnNode.saRevRedeem) jvNode["rev_redeem"] = pnNode.saRevRedeem.getFullText(); - // if (!!pnNode.saRevIssue) + // if (pnNode.saRevIssue) jvNode["rev_issue"] = pnNode.saRevIssue.getFullText(); - // if (!!pnNode.saRevDeliver) + // if (pnNode.saRevDeliver) jvNode["rev_deliver"] = pnNode.saRevDeliver.getFullText(); - // if (!!pnNode.saFwdRedeem) + // if (pnNode.saFwdRedeem) jvNode["fwd_redeem"] = pnNode.saFwdRedeem.getFullText(); - // if (!!pnNode.saFwdIssue) + // if (pnNode.saFwdIssue) jvNode["fwd_issue"] = pnNode.saFwdIssue.getFullText(); - // if (!!pnNode.saFwdDeliver) + // if (pnNode.saFwdDeliver) jvNode["fwd_deliver"] = pnNode.saFwdDeliver.getFullText(); jvNodes.append(jvNode); @@ -3569,7 +3563,7 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) } // XXX Should bMax be sufficient to imply ripple? - bool bRipple = bPaths || bMax || !saDstAmount.isNative(); + const bool bRipple = bPaths || bMax || !saDstAmount.isNative(); if (!bRipple) { @@ -3693,15 +3687,15 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) terResult = temUNCERTAIN; } - STAmount saPaid; - STAmount saWanted; - LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. - uint64 uQualityLimit = bLimitQuality ? STAmount::getRate(saDstAmount, saMaxAmount) : 0; + STAmount saPaid; + STAmount saWanted; + const LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. + const uint64 uQualityLimit = bLimitQuality ? STAmount::getRate(saDstAmount, saMaxAmount) : 0; while (temUNCERTAIN == terResult) { PathState::pointer pspBest; - LedgerEntrySet lesCheckpoint = mNodes; + const LedgerEntrySet lesCheckpoint = mNodes; // Find the best path. BOOST_FOREACH(PathState::pointer pspCur, vpsPaths) @@ -4299,21 +4293,6 @@ TER TransactionEngine::doOfferCancel(const SerializedTransaction& txn) return terResult; } -TER TransactionEngine::doTake(const SerializedTransaction& txn) -{ - return temUNKNOWN; -} - -TER TransactionEngine::doStore(const SerializedTransaction& txn) -{ - return temUNKNOWN; -} - -TER TransactionEngine::doDelete(const SerializedTransaction& txn) -{ - return temUNKNOWN; -} - #if 0 // XXX Need to adjust for fees. // Find offers to satisfy pnDst. diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 2dcd04e2fa..7c6ff47e5d 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -361,7 +361,6 @@ protected: TER doAccountSet(const SerializedTransaction& txn); TER doClaim(const SerializedTransaction& txn); TER doCreditSet(const SerializedTransaction& txn); - TER doDelete(const SerializedTransaction& txn); TER doInvoice(const SerializedTransaction& txn); TER doOfferCreate(const SerializedTransaction& txn); TER doOfferCancel(const SerializedTransaction& txn); @@ -369,8 +368,6 @@ protected: TER doPasswordFund(const SerializedTransaction& txn); TER doPasswordSet(const SerializedTransaction& txn); TER doPayment(const SerializedTransaction& txn); - TER doStore(const SerializedTransaction& txn); - TER doTake(const SerializedTransaction& txn); TER doWalletAdd(const SerializedTransaction& txn); public: From 4930ebb945a204eb81778f1883496b5be731062b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 20:13:57 -0700 Subject: [PATCH 192/426] Simplify the way we handle validations. Include a signing time instead of a closing time. Keep only the validation with the most recent signing time. Sign using network time. This eliminates the ValidationPair nightmare and makes the logic must easier to understand, increasing confidence that it does what it's supposed to do. --- src/DBInit.cpp | 2 +- src/LedgerConsensus.cpp | 2 +- src/NetworkOPs.cpp | 11 +++- src/NetworkOPs.h | 2 + src/SerializedObject.h | 1 + src/SerializedValidation.cpp | 10 ++-- src/SerializedValidation.h | 4 +- src/ValidationCollection.cpp | 98 ++++++++++++------------------------ src/ValidationCollection.h | 16 ++---- 9 files changed, 57 insertions(+), 89 deletions(-) diff --git a/src/DBInit.cpp b/src/DBInit.cpp index 245b2c5f78..e968ddf3c0 100644 --- a/src/DBInit.cpp +++ b/src/DBInit.cpp @@ -56,7 +56,7 @@ const char *LedgerDBInit[] = { LedgerHash CHARACTER(64), \ NodePubKey CHARACTER(56), \ Flags BIGINT UNSIGNED, \ - CloseTime BIGINT UNSIGNED, \ + SignTime BIGINT UNSIGNED, \ Signature BLOB \ );", "CREATE INDEX ValidationByHash ON \ diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 1a5b975ad3..b60c42fb64 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -1005,7 +1005,7 @@ void LedgerConsensus::accept(const SHAMap::pointer& set) if (mValidating) { SerializedValidation::pointer v = boost::make_shared - (newLCLHash, newLCL->getCloseTimeNC(), mValSeed, mProposing); + (newLCLHash, theApp->getOPs().getValidationTimeNC(), mValSeed, mProposing); v->setTrusted(); Log(lsINFO) << "CNF Val " << newLCLHash; theApp->getValidations().addValidation(v); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index aefa4065af..8ec3e71289 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -25,7 +25,7 @@ NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) : mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster), mCloseTimeOffset(0), - mLastCloseProposers(0), mLastCloseConvergeTime(LEDGER_IDLE_INTERVAL) + mLastCloseProposers(0), mLastCloseConvergeTime(LEDGER_IDLE_INTERVAL), mLastValidationTime(0) { } @@ -46,6 +46,15 @@ uint32 NetworkOPs::getCloseTimeNC() return iToSeconds(getNetworkTimePT() + boost::posix_time::seconds(mCloseTimeOffset)); } +uint32 NetworkOPs::getValidationTimeNC() +{ + uint32 vt = getNetworkTimeNC(); + if (vt >= mLastValidationTime) + vt = mLastValidationTime + 1; + mLastValidationTime = vt; + return vt; +} + void NetworkOPs::closeTimeOffset(int offset) { mCloseTimeOffset += offset / 4; diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index c59ce687a8..25ac145f40 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -64,6 +64,7 @@ protected: int mLastCloseProposers, mLastCloseConvergeTime; uint256 mLastCloseHash; uint32 mLastCloseTime; + uint32 mLastValidationTime; // XXX Split into more locks. boost::interprocess::interprocess_upgradable_mutex mMonitorLock; @@ -89,6 +90,7 @@ public: // network information uint32 getNetworkTimeNC(); uint32 getCloseTimeNC(); + uint32 getValidationTimeNC(); void closeTimeOffset(int); boost::posix_time::ptime getNetworkTimePT(); uint32 getCurrentLedgerID(); diff --git a/src/SerializedObject.h b/src/SerializedObject.h index fde0d7ec3f..d53dd5ed12 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -92,6 +92,7 @@ enum SOE_Field sfSequence, sfSignature, sfSigningKey, + sfSigningTime, sfSourceTag, sfTakerGets, sfTakerPays, diff --git a/src/SerializedValidation.cpp b/src/SerializedValidation.cpp index a87aa141e5..9ae32c31bb 100644 --- a/src/SerializedValidation.cpp +++ b/src/SerializedValidation.cpp @@ -6,7 +6,7 @@ SOElement SerializedValidation::sValidationFormat[] = { { sfFlags, "Flags", STI_UINT32, SOE_FLAGS, 0 }, { sfLedgerHash, "LedgerHash", STI_HASH256, SOE_REQUIRED, 0 }, - { sfCloseTime, "CloseTime", STI_UINT32, SOE_REQUIRED, 0 }, + { sfSigningTime, "SignTime", STI_UINT32, SOE_REQUIRED, 0 }, { sfSigningKey, "SigningKey", STI_VL, SOE_REQUIRED, 0 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 }, }; @@ -19,12 +19,12 @@ SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSi if (checkSignature && !isValid()) throw std::runtime_error("Invalid validation"); } -SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint32 closeTime, +SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint32 signTime, const NewcoinAddress& naSeed, bool isFull) : STObject(sValidationFormat), mSignature("Signature"), mTrusted(false) { setValueFieldH256(sfLedgerHash, ledgerHash); - setValueFieldU32(sfCloseTime, closeTime); + setValueFieldU32(sfSigningTime, signTime); if (naSeed.isValid()) setValueFieldVL(sfSigningKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic()); if (!isFull) setFlag(sFullFlag); @@ -50,9 +50,9 @@ uint256 SerializedValidation::getLedgerHash() const return getValueFieldH256(sfLedgerHash); } -uint32 SerializedValidation::getCloseTime() const +uint32 SerializedValidation::getSignTime() const { - return getValueFieldU32(sfCloseTime); + return getValueFieldU32(sfSigningTime); } uint32 SerializedValidation::getFlags() const diff --git a/src/SerializedValidation.h b/src/SerializedValidation.h index 5886b6dbba..81e4c1d6e1 100644 --- a/src/SerializedValidation.h +++ b/src/SerializedValidation.h @@ -23,10 +23,10 @@ public: SerializedValidation(SerializerIterator& sit, bool checkSignature = true); SerializedValidation(const Serializer& s, bool checkSignature = true); - SerializedValidation(const uint256& ledgerHash, uint32 closeTime, const NewcoinAddress& naSeed, bool isFull); + SerializedValidation(const uint256& ledgerHash, uint32 signTime, const NewcoinAddress& naSeed, bool isFull); uint256 getLedgerHash() const; - uint32 getCloseTime() const; + uint32 getSignTime() const; uint32 getFlags() const; NewcoinAddress getSignerPublic() const; bool isValid() const; diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index cb173f63ef..b6d109777c 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -17,7 +17,7 @@ bool ValidationCollection::addValidation(const SerializedValidation::pointer& va { val->setTrusted(); uint32 now = theApp->getOPs().getCloseTimeNC(); - uint32 valClose = val->getCloseTime(); + uint32 valClose = val->getSignTime(); if ((now > (valClose - LEDGER_EARLY_INTERVAL)) && (now < (valClose + LEDGER_VAL_INTERVAL))) isCurrent = true; else @@ -34,22 +34,16 @@ bool ValidationCollection::addValidation(const SerializedValidation::pointer& va return false; if (isCurrent) { - boost::unordered_map::iterator it = mCurrentValidations.find(node); - if ((it == mCurrentValidations.end()) || (!it->second.newest) || - (val->getCloseTime() > it->second.newest->getCloseTime())) + boost::unordered_map::iterator it = mCurrentValidations.find(node); + if (it == mCurrentValidations.end()) + mCurrentValidations.insert(std::make_pair(node, val)); + else if (!it->second) + it->second = val; + else if (val->getSignTime() > it->second->getSignTime()) { - if (it != mCurrentValidations.end()) - { - if (it->second.oldest) - { - mStaleValidations.push_back(it->second.oldest); - condWrite(); - } - it->second.oldest = it->second.newest; - it->second.newest = val; - } - else - mCurrentValidations.insert(std::make_pair(node, ValidationPair(val))); + mStaleValidations.push_back(it->second); + it->second = val; + condWrite(); } } } @@ -76,7 +70,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren trusted = untrusted = 0; boost::mutex::scoped_lock sl(mValidationLock); boost::unordered_map::iterator it = mValidations.find(ledger); - uint32 now = theApp->getOPs().getCloseTimeNC(); + uint32 now = theApp->getOPs().getNetworkTimeNC(); if (it != mValidations.end()) { for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end(); vit != end; ++vit) @@ -84,7 +78,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren bool isTrusted = vit->second->isTrusted(); if (isTrusted && currentOnly) { - uint32 closeTime = vit->second->getCloseTime(); + uint32 closeTime = vit->second->getSignTime(); if ((now < (closeTime - LEDGER_EARLY_INTERVAL)) || (now > (closeTime + LEDGER_VAL_INTERVAL))) isTrusted = false; else @@ -125,10 +119,10 @@ int ValidationCollection::getCurrentValidationCount(uint32 afterTime) { int count = 0; boost::mutex::scoped_lock sl(mValidationLock); - for (boost::unordered_map::iterator it = mCurrentValidations.begin(), + for (boost::unordered_map::iterator it = mCurrentValidations.begin(), end = mCurrentValidations.end(); it != end; ++it) { - if (it->second.newest->isTrusted() && (it->second.newest->getCloseTime() > afterTime)) + if (it->second->isTrusted() && (it->second->getSignTime() > afterTime)) ++count; } return count; @@ -136,54 +130,26 @@ int ValidationCollection::getCurrentValidationCount(uint32 afterTime) boost::unordered_map ValidationCollection::getCurrentValidations() { - uint32 now = theApp->getOPs().getCloseTimeNC(); + uint32 cutoff = theApp->getOPs().getNetworkTimeNC() - LEDGER_VAL_INTERVAL; boost::unordered_map ret; { boost::mutex::scoped_lock sl(mValidationLock); - boost::unordered_map::iterator it = mCurrentValidations.begin(); + boost::unordered_map::iterator it = mCurrentValidations.begin(); while (it != mCurrentValidations.end()) { - ValidationPair& pair = it->second; - - if (pair.oldest && (now > (pair.oldest->getCloseTime() + LEDGER_VAL_INTERVAL))) - { -#ifdef VC_DEBUG - Log(lsINFO) << "VC: " << it->first << " removeOldestStale"; -#endif - mStaleValidations.push_back(pair.oldest); - pair.oldest = SerializedValidation::pointer(); - condWrite(); - } - if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_VAL_INTERVAL))) - { -#ifdef VC_DEBUG - Log(lsINFO) << "VC: " << it->first << " removeNewestStale"; -#endif - mStaleValidations.push_back(pair.newest); - pair.newest = SerializedValidation::pointer(); - condWrite(); - } - if (!pair.newest && !pair.oldest) + 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 = SerializedValidation::pointer(); + condWrite(); + it = mCurrentValidations.erase(it); + } else - { - if (pair.oldest) - { -#ifdef VC_DEBUG - Log(lsTRACE) << "VC: OLD " << pair.oldest->getLedgerHash() << " " << - boost::lexical_cast(pair.oldest->getCloseTime()); -#endif - ++ret[pair.oldest->getLedgerHash()]; - } - if (pair.newest) - { -#ifdef VC_DEBUG - Log(lsTRACE) << "VC: NEW " << pair.newest->getLedgerHash() << " " << - boost::lexical_cast(pair.newest->getCloseTime()); -#endif - ++ret[pair.newest->getLedgerHash()]; - } + { // contains a live record + ++ret[it->second->getLedgerHash()]; ++it; } } @@ -213,14 +179,12 @@ void ValidationCollection::addDeadLedger(const uint256& ledger) void ValidationCollection::flush() { boost::mutex::scoped_lock sl(mValidationLock); - boost::unordered_map::iterator it = mCurrentValidations.begin(); + boost::unordered_map::iterator it = mCurrentValidations.begin(); bool anyNew = false; while (it != mCurrentValidations.end()) { - if (it->second.oldest) - mStaleValidations.push_back(it->second.oldest); - if (it->second.newest) - mStaleValidations.push_back(it->second.newest); + if (it->second) + mStaleValidations.push_back(it->second); ++it; anyNew = true; } @@ -247,7 +211,7 @@ void ValidationCollection::condWrite() void ValidationCollection::doWrite() { static boost::format insVal("INSERT INTO LedgerValidations " - "(LedgerHash,NodePubKey,Flags,CloseTime,Signature) VALUES ('%s','%s','%u','%u',%s);"); + "(LedgerHash,NodePubKey,Flags,SignTime,Signature) VALUES ('%s','%s','%u','%u',%s);"); boost::mutex::scoped_lock sl(mValidationLock); assert(mWriting); @@ -265,7 +229,7 @@ void ValidationCollection::doWrite() BOOST_FOREACH(const SerializedValidation::pointer& it, vector) db->executeSQL(boost::str(insVal % it->getLedgerHash().GetHex() - % it->getSignerPublic().humanNodePublic() % it->getFlags() % it->getCloseTime() + % it->getSignerPublic().humanNodePublic() % it->getFlags() % it->getSignTime() % db->escape(strCopy(it->getSignature())))); db->executeSQL("END TRANSACTION;"); } diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index bdd224a040..4a5912abfe 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -12,23 +12,15 @@ typedef boost::unordered_map ValidationSet; -class ValidationPair -{ -public: - SerializedValidation::pointer oldest, newest; - - ValidationPair(const SerializedValidation::pointer& v) : newest(v) { ; } -}; - class ValidationCollection { protected: boost::mutex mValidationLock; - boost::unordered_map mValidations; - boost::unordered_map mCurrentValidations; - std::vector mStaleValidations; - std::list mDeadLedgers; + boost::unordered_map mValidations; + boost::unordered_map mCurrentValidations; + std::vector mStaleValidations; + std::list mDeadLedgers; bool mWriting; From cfedc4b981b6611b6c47f5012cbebb4544c915c0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 20:29:29 -0700 Subject: [PATCH 193/426] Bugfix. --- src/NetworkOPs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 8ec3e71289..fc2b547541 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -49,7 +49,7 @@ uint32 NetworkOPs::getCloseTimeNC() uint32 NetworkOPs::getValidationTimeNC() { uint32 vt = getNetworkTimeNC(); - if (vt >= mLastValidationTime) + if (vt <= mLastValidationTime) vt = mLastValidationTime + 1; mLastValidationTime = vt; return vt; From 00199d39156181d812045f903926015cf6cc7e39 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 3 Sep 2012 20:36:51 -0700 Subject: [PATCH 194/426] An imperfect fix for the case where we get validations during the consensus process for the next ledger and think it's a change in the previous ledger. --- src/LedgerConsensus.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index b60c42fb64..fa94f5630b 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -264,6 +264,7 @@ void LedgerConsensus::checkLCL() if (netLgr != mPrevLedgerHash) { // LCL change Log(lsWARNING) << "View of consensus changed during consensus (" << netLgrCount << ")"; + Log(lsWARNING) << mPrevLedgerHash << " to " << netLgr; if (mHaveCorrectLCL) theApp->getOPs().consensusViewChange(); handleLCL(netLgr); @@ -519,7 +520,8 @@ void LedgerConsensus::stateAccepted() void LedgerConsensus::timerEntry() { - checkLCL(); + if ((!mHaveCorrectLCL) || (mState == lcsPRE_CLOSE)) + checkLCL(); mCurrentMSeconds = (boost::posix_time::microsec_clock::universal_time() - mConsensusStartTime).total_milliseconds(); From 829b57173f5fb1f8d731e0e5fa76b2a702dccdfc Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 4 Sep 2012 15:40:53 -0700 Subject: [PATCH 195/426] Restruct reverse ripple through offers. --- src/TransactionEngine.cpp | 509 +++++++++++++++++--------------------- src/TransactionEngine.h | 14 +- 2 files changed, 236 insertions(+), 287 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index d15eadb200..f1718518e0 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1755,285 +1755,12 @@ TER TransactionEngine::doPasswordSet(const SerializedTransaction& txn) return terResult; } -// XXX Need to track balances for offer funding. -TER TransactionEngine::calcNodeOfferRev( - const unsigned int uIndex, // 0 < uIndex < uLast - const PathState::pointer& pspCur, - const bool bMultiQuality) -{ - TER terResult = tepPATH_DRY; - - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; - - const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; - const uint160& uPrvIssuerID = pnPrv.uIssuerID; - const uint160& uCurCurrencyID = pnCur.uCurrencyID; - const uint160& uCurIssuerID = pnCur.uIssuerID; - const uint160& uNxtCurrencyID = pnNxt.uCurrencyID; - const uint160& uNxtIssuerID = pnNxt.uIssuerID; - const uint160& uNxtAccountID = pnNxt.uAccountID; - - uint256 uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); - const uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); - bool bAdvance = !entryCache(ltDIR_NODE, uDirectTip); - - const STAmount& saTransferRate = pnCur.saTransferRate; - - Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev> uIndex=%d prv=%s/%s cur=%s/%s nxt=%s/%s saTransferRate=%s") - % uIndex - % STAmount::createHumanCurrency(uPrvCurrencyID) - % NewcoinAddress::createHumanAccountID(uPrvIssuerID) - % STAmount::createHumanCurrency(uCurCurrencyID) - % NewcoinAddress::createHumanAccountID(uCurIssuerID) - % STAmount::createHumanCurrency(uNxtCurrencyID) - % NewcoinAddress::createHumanAccountID(uNxtIssuerID) - % saTransferRate.getText()); - - STAmount& saPrvDlvReq = pnPrv.saRevDeliver; // To be adjusted. - STAmount saPrvDlvAct; - - const STAmount& saCurDlvReq = pnCur.saRevDeliver; // Reverse driver. - STAmount saCurDlvAct; - - Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString()); - - while (!!uDirectTip && saCurDlvAct != saCurDlvReq) // Have a quality and not done. - { - // Get next quality. - if (bAdvance) - { - uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd); - - Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uDirectTip=%s") % uDirectTip.ToString()); - } - else - { - bAdvance = true; - } - - if (!!uDirectTip) - { - // Do a directory. - // - Drive on computing saCurDlvAct to derive saPrvDlvAct. - // XXX Behave well, if entry type is not ltDIR_NODE (someone beat us to using the hash) - SLE::pointer sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); - const STAmount saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio - unsigned int uEntry = 0; - uint256 uOfferIndex; - - while (saCurDlvReq != saCurDlvAct // Have not met request. - && dirNext(uDirectTip, sleDirectDir, uEntry, uOfferIndex)) - { - Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev: uOfferIndex=%s") % uOfferIndex.ToString()); - - SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - - if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) - { - // Offer is expired. - Log(lsINFO) << "calcNodeOfferRev: encountered expired offer"; - - musUnfundedFound.insert(uOfferIndex); // Mark offer for always deletion. - continue; - } - - const uint160 uCurOfrAccountID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); - const aciSource asLine = boost::make_tuple(uCurOfrAccountID, uCurCurrencyID, uCurIssuerID); - - // Allowed to access source from this node? - curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine); - bool bFoundForward = itAllow != pspCur->umForward.end(); - - if (bFoundForward || itAllow->second != uIndex) - { - // Temporarily unfunded. Another node uses this source, ignore in this node. - Log(lsINFO) << "calcNodeOfferRev: temporarily unfunded offer"; - - nothing(); - continue; - } - - const STAmount& saCurOfrOutReq = sleOffer->getIValueFieldAmount(sfTakerGets); - // UNUSED? const STAmount& saCurOfrIn = sleOffer->getIValueFieldAmount(sfTakerPays); - - STAmount saCurOfrFunds = accountFunds(uCurOfrAccountID, saCurOfrOutReq); // Funds left. - - curIssuerNodeConstIterator itSourcePast = mumSource.find(asLine); - bool bFoundPast = itSourcePast != mumSource.end(); - - if (!saCurOfrFunds.isPositive()) - { - // Offer is unfunded. - Log(lsINFO) << "calcNodeOfferRev: encountered unfunded offer"; - - curIssuerNodeConstIterator itSourceCur = bFoundPast - ? pspCur->umReverse.end() - : pspCur->umReverse.find(asLine); - bool bFoundReverse = itSourceCur != pspCur->umReverse.end(); - - if (!bFoundReverse && !bFoundPast) - { - // Never mentioned before: found unfunded. - musUnfundedFound.insert(uOfferIndex); // Mark offer for always deletion. - } - continue; - } - - bool bMentioned = false; - - if (!!uNxtAccountID) - { - // Next is an account. - // Next is redeeming it's own IOUs - no quality. - // Offer is paying out IOUs via offer - no quality. - - STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtAccountID == uCurIssuerID - ? saOne - : saTransferRate; - bool bFee = saFeeRate != saOne; - - STAmount saOutBase = std::min(saCurOfrOutReq, saCurDlvReq-saCurDlvAct); // Limit offer out by needed. - STAmount saOutCost = std::min( - bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutBase, - saCurOfrFunds); // Limit cost by fees & funds. - STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; // Out amount after fees. - STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); // Compute input w/o fees required. - - saCurDlvAct += saOutDlvAct; // Portion of driver served. - saPrvDlvAct += saInDlvAct; // Portion needed in previous. - - if (!bMentioned) - bMentioned = true; - } - else - { - // Next is an offer. - - uint256 uNxtTip = Ledger::getBookBase(uCurCurrencyID, uCurIssuerID, uNxtCurrencyID, uNxtIssuerID); - uint256 uNxtEnd = Ledger::getQualityNext(uNxtTip); - bool bNxtAdvance = !entryCache(ltDIR_NODE, uNxtTip); - - while (!!uNxtTip // Have a quality. - && saCurDlvAct != saCurDlvReq) // Have more to do. - { - if (bNxtAdvance) - { - uNxtTip = mLedger->getNextLedgerIndex(uNxtTip, uNxtEnd); - } - else - { - bNxtAdvance = true; - } - - if (!!uNxtTip) - { - // Do a directory. - // - Drive on computing saCurDlvAct to derive saPrvDlvAct. - // Although the fee varies based upon the next offer it does not matter as the offer maker knows in - // advance that they are obligated to pay a transfer fee of necessary. The owner of next offer has no - // expectation of a quality in being applied. - SLE::pointer sleNxtDir = entryCache(ltDIR_NODE, uNxtTip); -// ??? STAmount saOfrRate = STAmount::setRate(STAmount::getQuality(uNxtTip), uCurCurrencyID); // For correct ratio - unsigned int uEntry = 0; - uint256 uNxtIndex; - - while (saCurDlvReq != saCurDlvAct // Have not met request. - && dirNext(uNxtTip, sleNxtDir, uEntry, uNxtIndex)) - { - // YYY This could combine offers with the same fee before doing math. - SLE::pointer sleNxtOfr = entryCache(ltOFFER, uNxtIndex); - uint160 uNxtOfrAccountID = sleNxtOfr->getIValueFieldAccount(sfAccount).getAccountID(); - const STAmount& saNxtOfrIn = sleNxtOfr->getIValueFieldAmount(sfTakerPays); - - const aciSource asLineNxt = boost::make_tuple(uNxtOfrAccountID, uNxtCurrencyID, uNxtIssuerID); - - // Allowed to access source from this node? - curIssuerNodeConstIterator itAllowNxt = pspCur->umForward.find(asLineNxt); - curIssuerNodeConstIterator itNxt = itAllowNxt == pspCur->umForward.end() - ? mumSource.find(asLine) - : itAllowNxt; - - assert(itNxt != mumSource.end()); - - if (uIndex+1 != itNxt->second) - { - // Temporarily unfunded. Another node uses this source, ignore in this node. - - nothing(); - continue; - } - - STAmount saFeeRate = uCurOfrAccountID == uCurIssuerID || uNxtOfrAccountID == uCurIssuerID - ? saOne - : saTransferRate; - bool bFee = saFeeRate != saOne; - - STAmount saOutBase = std::min(saCurOfrOutReq, saCurDlvReq-saCurDlvAct);// Limit offer out by needed. - saOutBase = std::min(saOutBase, saNxtOfrIn); // Limit offer out by supplying offer. - STAmount saOutCost = std::min( - bFee - ? STAmount::multiply(saOutBase, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutBase, - saCurOfrFunds); // Limit cost by fees & funds. - STAmount saOutDlvAct = bFee - ? STAmount::divide(saOutCost, saFeeRate, uCurCurrencyID, uCurIssuerID) - : saOutCost; // Out amount after fees. - // Compute input w/o fees required. - STAmount saInDlvAct = STAmount::multiply(saOutDlvAct, saOfrRate, uPrvCurrencyID, uCurIssuerID); - - saCurDlvAct += saOutDlvAct; // Portion of driver served. - saPrvDlvAct += saInDlvAct; // Portion needed in previous. - if (!bMentioned) - bMentioned = true; - } - } - - // Do another nxt directory iff bMultiQuality - if (!bMultiQuality) - uNxtTip = 0; - } - } - - if (bMentioned // Need to remember reverse mention. - && !bFoundPast // Not mentioned in previous passes. - && !bFoundForward) // Not mentioned for pass. - { - // Consider source mentioned by current path state. - pspCur->umReverse.insert(std::make_pair(asLine, uIndex)); - } - } - } - - // Do another cur directory iff bMultiQuality - if (!bMultiQuality) - uDirectTip = 0; - } - - if (saPrvDlvAct) - { - saPrvDlvReq = saPrvDlvAct; // Adjust request. - terResult = tesSUCCESS; - } - - Log(lsINFO) << boost::str(boost::format("calcNodeOfferRev< uIndex=%d saPrvDlvReq=%s terResult=%d") - % uIndex - % saPrvDlvReq.getFullText() - % terResult); - - return terResult; -} - // If needed, advance to next funded offer. TER TransactionEngine::calcNodeAdvance( const unsigned int uIndex, // 0 < uIndex < uLast const PathState::pointer& pspCur, - const bool bMultiQuality) + const bool bMultiQuality, + const bool bReverse) { PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; @@ -2145,13 +1872,38 @@ TER TransactionEngine::calcNodeAdvance( } // Allowed to access source from this node? - curIssuerNodeConstIterator itAllow = pspCur->umForward.find(asLine); - const bool bFoundForward = itAllow != pspCur->umForward.end(); + // XXX This can get called multiple times for same source in a row, caching result would be nice. + curIssuerNodeConstIterator itForward = pspCur->umForward.find(asLine); + const bool bFoundForward = itForward != pspCur->umForward.end(); - if (bFoundForward || itAllow->second != uIndex) + if (bFoundForward || itForward->second != uIndex) { // Temporarily unfunded. Another node uses this source, ignore in this offer. - Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer"; + Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (forward)"; + + bEntryAdvance = true; + continue; + } + + curIssuerNodeConstIterator itPast = mumSource.find(asLine); + bool bFoundPast = itPast != mumSource.end(); + + if (bFoundPast || itPast->second != uIndex) + { + // Temporarily unfunded. Another node uses this source, ignore in this offer. + Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (past)"; + + bEntryAdvance = true; + continue; + } + + curIssuerNodeConstIterator itReverse = pspCur->umReverse.find(asLine); + bool bFoundReverse = itReverse != pspCur->umReverse.end(); + + if (bFoundReverse || itReverse->second != uIndex) + { + // Temporarily unfunded. Another node uses this source, ignore in this offer. + Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (reverse)"; bEntryAdvance = true; continue; @@ -2167,11 +1919,25 @@ TER TransactionEngine::calcNodeAdvance( // Offer is unfunded. Log(lsINFO) << "calcNodeAdvance: unfunded offer"; + if (bReverse && !bFoundReverse && !bFoundPast) + { + // Never mentioned before: found unfunded. + musUnfundedFound.insert(uOfferIndex); // Mark offer for always deletion. + } + // YYY Could verify offer is correct place for unfundeds. bEntryAdvance = true; continue; } + if (bReverse // Need to remember reverse mention. + && !bFoundPast // Not mentioned in previous passes. + && !bFoundReverse) // Not mentioned for pass. + { + // Consider source mentioned by current path state. + pspCur->umReverse.insert(std::make_pair(asLine, uIndex)); + } + bFundsDirty = false; bEntryAdvance = false; } @@ -2181,9 +1947,147 @@ TER TransactionEngine::calcNodeAdvance( return terResult; } +// Between offer nodes, the fee charged may vary. Therefore, process one inbound offer at a time. +// Propagate the inbound offer's requirements to the previous node. The previous node adjusts the amount output and the +// amount spent on fees. +// Continue process till request is satisified while we the rate does not increase past the initial rate. +TER TransactionEngine::calcNodeDeliverRev( + const unsigned int uIndex, // 0 < uIndex < uLast + const PathState::pointer& pspCur, + const bool bMultiQuality, + const uint160& uOutAccountID, // --> Output owner's account. + const STAmount& saOutReq, // --> Funds wanted. + STAmount& saOutAct) // <-- Funds delivered. +{ + TER terResult = tesSUCCESS; + + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + + const uint160& uCurIssuerID = pnCur.uIssuerID; + const uint160& uPrvAccountID = pnPrv.uAccountID; + const STAmount& saTransferRate = pnCur.saTransferRate; + + STAmount& saPrvDlvReq = pnPrv.saRevDeliver; // To be adjusted. + + saOutAct = 0; + + while (saOutAct != saOutReq) // Did not deliver limit. + { + bool& bEntryAdvance = pnCur.bEntryAdvance; + STAmount& saOfrRate = pnCur.saOfrRate; + uint256& uOfferIndex = pnCur.uOfferIndex; + SLE::pointer& sleOffer = pnCur.sleOffer; + const uint160& uOfrOwnerID = pnCur.uOfrOwnerID; + bool& bFundsDirty = pnCur.bFundsDirty; + STAmount& saOfferFunds = pnCur.saOfferFunds; + STAmount& saTakerPays = pnCur.saTakerPays; + STAmount& saTakerGets = pnCur.saTakerGets; + STAmount& saRateMax = pnCur.saRateMax; + + terResult = calcNodeAdvance(uIndex, pspCur, bMultiQuality, true); // If needed, advance to next funded offer. + + if (tesSUCCESS != terResult || !uOfferIndex) + { + // Error or out of offers. + break; + } + + const STAmount saOutFeeRate = uOfrOwnerID == uCurIssuerID || uOutAccountID == uCurIssuerID // Issuer receiving or sending. + ? saOne // No fee. + : saTransferRate; // Transfer rate of issuer. + + if (!saRateMax) + { + // Set initial rate. + saRateMax = saOutFeeRate; + } + else if (saRateMax < saOutFeeRate) + { + // Offer exceeds initial rate. + break; + } + + STAmount saOutPass = std::max(std::max(saOfferFunds, saTakerGets), saOutReq-saOutAct); // Offer maximum out - assuming no out fees. + STAmount saOutPlusFees = STAmount::divide(saOutPass, saOutFeeRate); // Offer out with fees. + + if (saOutPlusFees > saOfferFunds) + { + // Offer owner can not cover all fees, compute saOutPass based on saOfferFunds. + + saOutPlusFees = saOfferFunds; + saOutPass = STAmount::divide(saOutPlusFees, saOutFeeRate); + } + + // Compute portion of input needed to cover output. + + STAmount saInPassReq = STAmount::multiply(saOutPass, saOfrRate, saTakerPays); + STAmount saInPassAct; + + // Find out input amount actually available at current rate. + if (!!uPrvAccountID) + { + // account --> OFFER --> ? + // Previous is the issuer and receiver is an offer, so no fee or quality. + // Previous is the issuer and has unlimited funds. + // Offer owner is obtaining IOUs via an offer, so credit line limits are ignored. + // As limits are ignored, don't need to adjust previous account's balance. + + saInPassAct = saInPassReq; + + saPrvDlvReq = saInPassAct; + } + else + { + terResult = calcNodeDeliverRev( + uIndex-1, + pspCur, + bMultiQuality, + uOfrOwnerID, + saInPassReq, + saInPassAct); + } + + if (tesSUCCESS != terResult) + break; + + if (saInPassAct != saInPassReq) + { + // Adjust output to conform to limited input. + saOutPass = STAmount::divide(saInPassAct, saOfrRate, saTakerGets); + saOutPlusFees = STAmount::multiply(saOutPass, saOutFeeRate); + } + + // Funds were spent. + bFundsDirty = true; + + // Deduct output, don't actually need to send. + accountSend(uOfrOwnerID, uCurIssuerID, saOutPass); + + // Adjust offer + sleOffer->setIFieldAmount(sfTakerGets, saTakerGets - saOutPass); + sleOffer->setIFieldAmount(sfTakerPays, saTakerPays - saInPassAct); + + entryModify(sleOffer); + + if (saOutPass == saTakerGets) + { + // Offer became unfunded. + bEntryAdvance = true; + } + + saOutAct += saOutPass; + } + + if (!saOutAct) + terResult = tepPATH_DRY; + + return terResult; +} + // Deliver maximum amount of funds from previous node. // Goal: Make progress consuming the offer. -TER TransactionEngine::calcNodeDeliver( +TER TransactionEngine::calcNodeDeliverFwd( const unsigned int uIndex, // 0 < uIndex < uLast const PathState::pointer& pspCur, const bool bMultiQuality, @@ -2211,7 +2115,7 @@ TER TransactionEngine::calcNodeDeliver( && saInAct != saInReq // Did not deliver limit. && saInAct + saInFees != saInFunds) // Did not deliver all funds. { - terResult = calcNodeAdvance(uIndex, pspCur, bMultiQuality); // If needed, advance to next funded offer. + terResult = calcNodeAdvance(uIndex, pspCur, bMultiQuality, false); // If needed, advance to next funded offer. if (tesSUCCESS == terResult) { @@ -2232,7 +2136,7 @@ TER TransactionEngine::calcNodeDeliver( // // First calculate assuming no output fees. - // XXX Make sure derived in does not exceed actual saTakerPays + // XXX Make sure derived in does not exceed actual saTakerPays due to rounding. 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. @@ -2263,7 +2167,7 @@ TER TransactionEngine::calcNodeDeliver( // ? --> OFFER --> offer STAmount saOutPassFees; - terResult = TransactionEngine::calcNodeDeliver( + terResult = TransactionEngine::calcNodeDeliverFwd( uIndex+1, pspCur, bMultiQuality, @@ -2311,6 +2215,40 @@ TER TransactionEngine::calcNodeDeliver( return terResult; } +// Called to drive from the last offer node in a chain. +TER TransactionEngine::calcNodeOfferRev( + const unsigned int uIndex, // 0 < uIndex < uLast + const PathState::pointer& pspCur, + const bool bMultiQuality) +{ + TER terResult; + + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; + + if (!!pnNxt.uAccountID) + { + // Next is an account node, resolve current offer node's deliver. + STAmount saDeliverAct; + + terResult = calcNodeDeliverRev( + uIndex, + pspCur, + bMultiQuality, + + pnNxt.uAccountID, + pnCur.saRevDeliver, + saDeliverAct); + } + else + { + // Next is an offer. Deliver has already been resolved. + terResult = tesSUCCESS; + } + + return terResult; +} + // Called to drive the from the first offer node in a chain. // - Offer input is limbo. // - Current offers consumed. @@ -2333,7 +2271,7 @@ TER TransactionEngine::calcNodeOfferFwd( STAmount saInAct; STAmount saInFees; - terResult = calcNodeDeliver( + terResult = calcNodeDeliverFwd( uIndex, pspCur, bMultiQuality, @@ -2457,7 +2395,7 @@ void TransactionEngine::calcNodeRipple( % saCurAct.getFullText()); } -// Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver; +// Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver from saCur... // <-- tesSUCCESS or tepPATH_DRY TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) { @@ -3173,6 +3111,7 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint // Offers bridge a change in currency & issuer or just a change in issuer. pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; pnCur.uIssuerID = bIssuer ? uIssuerID : pnCur.uAccountID; + pnCur.saRateMax = saZero; if (!!pnPrv.uAccountID) { diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 7c6ff47e5d..d2e7cd4016 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -166,6 +166,8 @@ protected: // For offers: + STAmount saRateMax; // XXX Should rate be sticky for forward too? + // Directory uint256 uDirectTip; // Current directory. uint256 uDirectEnd; // Next order book. @@ -340,8 +342,16 @@ protected: 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); - TER calcNodeDeliver( + 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, From 090e7c6064d38693a3b0b685673841c22e264682 Mon Sep 17 00:00:00 2001 From: jed Date: Wed, 5 Sep 2012 07:12:00 -0700 Subject: [PATCH 196/426] start contracts --- newcoin.vcxproj | 3 +++ newcoin.vcxproj.filters | 9 +++++++++ src/Config.cpp | 6 ++++++ src/Config.h | 1 + 4 files changed, 19 insertions(+) diff --git a/newcoin.vcxproj b/newcoin.vcxproj index e29623a848..adb8abc714 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -102,12 +102,14 @@ + + @@ -198,6 +200,7 @@ + diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index dd3b6d700c..b97a607c9e 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -282,6 +282,12 @@ Source Files + + Source Files + + + Source Files + @@ -527,6 +533,9 @@ Header Files + + Source Files + diff --git a/src/Config.cpp b/src/Config.cpp index 4e36f39a1b..92034ed9d7 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -12,6 +12,7 @@ #define SECTION_FEE_DEFAULT "fee_default" #define SECTION_FEE_NICKNAME_CREATE "fee_nickname_create" #define SECTION_FEE_OFFER "fee_offer" +#define SECTION_FEE_OPERATION "fee_operation" #define SECTION_IPS "ips" #define SECTION_NETWORK_QUORUM "network_quorum" #define SECTION_PEER_CONNECT_LOW_WATER "peer_connect_low_water" @@ -37,6 +38,7 @@ #define DEFAULT_FEE_ACCOUNT_CREATE 1000 #define DEFAULT_FEE_NICKNAME_CREATE 1000 #define DEFAULT_FEE_OFFER DEFAULT_FEE_DEFAULT +#define DEFAULT_FEE_OPERATION 1 Config theConfig; @@ -145,6 +147,7 @@ void Config::setup(const std::string& strConf) FEE_NICKNAME_CREATE = DEFAULT_FEE_NICKNAME_CREATE; FEE_OFFER = DEFAULT_FEE_OFFER; FEE_DEFAULT = DEFAULT_FEE_DEFAULT; + FEE_CONTRACT_OPERATION = DEFAULT_FEE_OPERATION; ACCOUNT_PROBE_MAX = 10; @@ -258,6 +261,9 @@ void Config::load() if (sectionSingleB(secConfig, SECTION_FEE_DEFAULT, strTemp)) FEE_DEFAULT = boost::lexical_cast(strTemp); + if (sectionSingleB(secConfig, SECTION_FEE_OPERATION, strTemp)) + FEE_CONTRACT_OPERATION = boost::lexical_cast(strTemp); + if (sectionSingleB(secConfig, SECTION_ACCOUNT_PROBE_MAX, strTemp)) ACCOUNT_PROBE_MAX = boost::lexical_cast(strTemp); diff --git a/src/Config.h b/src/Config.h index 89fb60b3de..6fc42dca35 100644 --- a/src/Config.h +++ b/src/Config.h @@ -97,6 +97,7 @@ public: uint64 FEE_ACCOUNT_CREATE; // Fee to create an account. uint64 FEE_NICKNAME_CREATE; // Fee to create a nickname. uint64 FEE_OFFER; // Rate per day. + int FEE_CONTRACT_OPERATION; // fee for each contract operation // Client behavior int ACCOUNT_PROBE_MAX; // How far to scan for accounts. From 7785b89b5d6a8b2e8b70152a5eed51d532cfc948 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 5 Sep 2012 07:22:04 -0700 Subject: [PATCH 197/426] Some extra debugging. Don't jump back to the ledger we just left (yeah, there was another way that could happen.) --- src/LedgerConsensus.cpp | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index fa94f5630b..f2e73e647f 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -248,23 +248,39 @@ void LedgerConsensus::checkLCL() { uint256 netLgr = mPrevLedgerHash; int netLgrCount = 0; - { - boost::unordered_map vals = theApp->getValidations().getCurrentValidations(); - typedef std::pair u256_int_pair; - BOOST_FOREACH(u256_int_pair& it, vals) + boost::unordered_map vals = theApp->getValidations().getCurrentValidations(); + typedef std::pair u256_int_pair; + BOOST_FOREACH(u256_int_pair& it, vals) + { + if ((it.second > netLgrCount) && !theApp->getValidations().isDeadLedger(it.first)) { - if ((it.second > netLgrCount) && !theApp->getValidations().isDeadLedger(it.first)) - { - netLgr = it.first; - netLgrCount = it.second; - } + netLgr = it.first; + netLgrCount = it.second; } } + if (netLgr != mPrevLedgerHash) { // LCL change - Log(lsWARNING) << "View of consensus changed during consensus (" << netLgrCount << ")"; + const char *status; + switch (mState) + { + case lcsPRE_CLOSE: status="PreClose"; break; + case lcsESTABLISH: status="Establish"; break; + case lcsFINISHED: status="Finised"; break; + case lcsACCEPTED: status="Accepted"; break; + default: status="unknown"; + } + + Log(lsWARNING) << "View of consensus changed during consensus (" << netLgrCount << ") status=" + << status << ", " << (mHaveCorrectLCL ? "CorrectLCL" : "IncorrectLCL"); Log(lsWARNING) << mPrevLedgerHash << " to " << netLgr; + +#ifdef DEBUG + BOOST_FOREACH(u256_int_pair& it, vals) + Log(lsDEBUG) << "V: " << it.first << ", " << it.second; +#endif + if (mHaveCorrectLCL) theApp->getOPs().consensusViewChange(); handleLCL(netLgr); @@ -520,7 +536,7 @@ void LedgerConsensus::stateAccepted() void LedgerConsensus::timerEntry() { - if ((!mHaveCorrectLCL) || (mState == lcsPRE_CLOSE)) + if ((!mHaveCorrectLCL && (mState != lcsACCEPTED)) || (mState == lcsPRE_CLOSE)) checkLCL(); mCurrentMSeconds = From 1dfdf8e9d827634bf3d545854cd2db874e401257 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 5 Sep 2012 10:05:15 -0700 Subject: [PATCH 198/426] Count a validation for its previous ledger if it's during consensus time. --- src/LedgerConsensus.cpp | 2 +- src/SerializedValidation.h | 6 ++++++ src/ValidationCollection.cpp | 21 ++++++++++++++------- src/ValidationCollection.h | 2 +- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index f2e73e647f..12fd086f9c 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -249,7 +249,7 @@ void LedgerConsensus::checkLCL() uint256 netLgr = mPrevLedgerHash; int netLgrCount = 0; - boost::unordered_map vals = theApp->getValidations().getCurrentValidations(); + boost::unordered_map vals = theApp->getValidations().getCurrentValidations(mPrevLedgerHash); typedef std::pair u256_int_pair; BOOST_FOREACH(u256_int_pair& it, vals) { diff --git a/src/SerializedValidation.h b/src/SerializedValidation.h index 81e4c1d6e1..299c35a0ed 100644 --- a/src/SerializedValidation.h +++ b/src/SerializedValidation.h @@ -8,6 +8,7 @@ class SerializedValidation : public STObject { protected: STVariableLength mSignature; + uint256 mPreviousHash; bool mTrusted; void setNode(); @@ -40,6 +41,11 @@ public: void addSignature(Serializer&) const; std::vector getSigned() const; std::vector getSignature() const; + + // The validation this replaced + const uint256& getPreviousHash() { return mPreviousHash; } + bool isPreviousHash(const uint256& h) { return mPreviousHash == h; } + void setPreviousHash(const uint256& h) { mPreviousHash = h; } }; #endif diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index b6d109777c..28cb2a59d1 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -41,6 +41,7 @@ bool ValidationCollection::addValidation(const SerializedValidation::pointer& va it->second = val; else if (val->getSignTime() > it->second->getSignTime()) { + val->setPreviousHash(it->second->getPreviousHash()); mStaleValidations.push_back(it->second); it->second = val; condWrite(); @@ -128,9 +129,11 @@ int ValidationCollection::getCurrentValidationCount(uint32 afterTime) return count; } -boost::unordered_map ValidationCollection::getCurrentValidations() +boost::unordered_map ValidationCollection::getCurrentValidations(uint256 currentLedger) { uint32 cutoff = theApp->getOPs().getNetworkTimeNC() - LEDGER_VAL_INTERVAL; + bool valCurrentLedger = currentLedger.isNonZero(); + boost::unordered_map ret; { @@ -149,7 +152,10 @@ boost::unordered_map ValidationCollection::getCurrentValidations() } else { // contains a live record - ++ret[it->second->getLedgerHash()]; + if (valCurrentLedger && it->second->isPreviousHash(currentLedger)) + ++ret[currentLedger]; // count for the favored ledger + else + ++ret[it->second->getLedgerHash()]; ++it; } } @@ -160,6 +166,7 @@ boost::unordered_map ValidationCollection::getCurrentValidations() bool ValidationCollection::isDeadLedger(const uint256& ledger) { + boost::mutex::scoped_lock sl(mValidationLock); BOOST_FOREACH(const uint256& it, mDeadLedgers) if (it == ledger) return true; @@ -168,11 +175,13 @@ bool ValidationCollection::isDeadLedger(const uint256& ledger) void ValidationCollection::addDeadLedger(const uint256& ledger) { + boost::mutex::scoped_lock sl(mValidationLock); + if (isDeadLedger(ledger)) return; mDeadLedgers.push_back(ledger); - if (mDeadLedgers.size() >= 128) + if (mDeadLedgers.size() >= 32) mDeadLedgers.pop_front(); } @@ -220,13 +229,11 @@ void ValidationCollection::doWrite() std::vector vector; mStaleValidations.swap(vector); sl.unlock(); - { - ScopedLock dbl(theApp->getLedgerDB()->getDBLock()); Database *db = theApp->getLedgerDB()->getDB(); + ScopedLock dbl(theApp->getLedgerDB()->getDBLock()); + db->executeSQL("BEGIN TRANSACTION;"); - - BOOST_FOREACH(const SerializedValidation::pointer& it, vector) db->executeSQL(boost::str(insVal % it->getLedgerHash().GetHex() % it->getSignerPublic().humanNodePublic() % it->getFlags() % it->getSignTime() diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index 4a5912abfe..287ba6b68f 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -37,7 +37,7 @@ public: int getTrustedValidationCount(const uint256& ledger); int getCurrentValidationCount(uint32 afterTime); - boost::unordered_map getCurrentValidations(); + boost::unordered_map getCurrentValidations(uint256 currentLedger = uint256()); void addDeadLedger(const uint256&); bool isDeadLedger(const uint256&); From 7a300f6c7b8aad6e4e86a30c687435426f0bf25a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 5 Sep 2012 10:18:23 -0700 Subject: [PATCH 199/426] Fix deadlock. --- src/ValidationCollection.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 28cb2a59d1..74039ad009 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -177,8 +177,9 @@ void ValidationCollection::addDeadLedger(const uint256& ledger) { boost::mutex::scoped_lock sl(mValidationLock); - if (isDeadLedger(ledger)) - return; + BOOST_FOREACH(const uint256& it, mDeadLedgers) + if (it == ledger) + return; mDeadLedgers.push_back(ledger); if (mDeadLedgers.size() >= 32) From 986fd52f1971872cc8c00d224445985219ec53a0 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 5 Sep 2012 14:18:58 -0700 Subject: [PATCH 200/426] Get indirect ripple working again. --- src/TransactionEngine.cpp | 80 ++++++++++++++++++++++++--------------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index c710775406..15534fc26a 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -109,6 +109,24 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman) return iIndex >= 0; } +static std::string transToken(TER terCode) +{ + std::string strToken; + std::string strHuman; + + return transResultInfo(terCode, strToken, strHuman) ? strToken : "-"; +} + +#if 0 +static std::string transHuman(TER terCode) +{ + std::string strToken; + std::string strHuman; + + return transResultInfo(terCode, strToken, strHuman) ? strHuman : "-"; +} +#endif + // Returns amount owed by uToAccountID to uFromAccountID. // <-- $owed/uCurrencyID/uToAccountID: positive: uFromAccountID holds IOUs., negative: uFromAccountID owes IOUs. STAmount TransactionEngine::rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) @@ -1756,6 +1774,8 @@ TER TransactionEngine::doPasswordSet(const SerializedTransaction& txn) } // If needed, advance to next funded offer. +// - Automatically advances to first offer. +// - Set bEntryAdvance to advance to next entry. TER TransactionEngine::calcNodeAdvance( const unsigned int uIndex, // 0 < uIndex < uLast const PathState::pointer& pspCur, @@ -2425,13 +2445,14 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS const STAmount saPrvOwed = uIndex && bPrvAccount // Previous account is owed. ? rippleOwed(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID, uCurAccountID); + const STAmount saPrvLimit = uIndex && bPrvAccount // Previous account may owe. ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID, uCurAccountID); const STAmount saNxtOwed = uIndex != uLast && bNxtAccount // Next account is owed. - ? rippleOwed(uCurAccountID, uNxtAccountID, uCurrencyID) - : STAmount(uCurrencyID, uCurAccountID); + ? rippleOwed(uCurAccountID, uNxtAccountID, uCurrencyID) + : STAmount(uCurrencyID, uCurAccountID); Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s") % uIndex @@ -2474,6 +2495,9 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS Log(lsINFO) << pspCur->getJson(); + assert(!saCurRedeemReq || saNxtOwed >= saCurRedeemReq); // Current redeem req can't be more than IOUs on hand. + assert(!saCurIssueReq || !saNxtOwed.isPositive() || saNxtOwed == saCurRedeemReq); // If issue req, then redeem req must consume all owed. + if (bPrvAccount && bNxtAccount) { if (!uIndex) @@ -2528,7 +2552,7 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS // ^|account --> ACCOUNT --> account // redeem (part 1) -> redeem - if (saCurRedeemReq // Next wants us to redeem. + if (saCurRedeemReq // Next wants IOUs redeemed. && saPrvRedeemReq) // Previous has IOUs to redeem. { // Rate : 1.0 : quality out @@ -2537,9 +2561,9 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax); } - // issue (part 1)-> redeem - if (saCurRedeemReq != saCurRedeemAct // More to redeem. - && saPrvRedeemReq == saPrvRedeemAct) // Previously redeemed all owed IOUs. + // issue (part 1) -> redeem + if (saCurRedeemReq != saCurRedeemAct // Next wants more IOUs redeemed. + && saPrvRedeemAct == saPrvRedeemReq) // Previous has no IOUs to redeem remaining. { // Rate: quality in : quality out Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : quality out")); @@ -2548,10 +2572,9 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS } // redeem (part 2) -> issue. - if (saCurIssueReq // Need some issued. - && saCurRedeemAct == saNxtOwed // Can only issue if previously redeemed all owed. - && saPrvOwed.isPositive() // Previous has IOUs to redeem. - && saPrvRedeemAct != saPrvOwed) // Did not previously redeem all IOUs. + if (saCurIssueReq // Next wants IOUs issued. + && saCurRedeemAct == saCurRedeemReq // Can only issue if completed redeeming. + && saPrvRedeemAct != saPrvRedeemReq) // Did not complete redeeming previous IOUs. { // Rate : 1.0 : transfer_rate Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : transfer_rate")); @@ -2560,8 +2583,8 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS } // issue (part 2) -> issue - if (saCurIssueReq != saCurIssueAct // Need some issued. - && saCurRedeemAct == saNxtOwed // Can only issue if previously redeemed all owed. + if (saCurIssueReq != saCurIssueAct // Need wants more IOUs issued. + && saCurRedeemAct == saCurRedeemReq // Can only issue if completed redeeming. && saPrvRedeemReq == saPrvRedeemAct) // Previously redeemed all owed IOUs. { // Rate: quality in : 1.0 @@ -3372,7 +3395,7 @@ TER TransactionEngine::calcNodeRev(const unsigned int uIndex, const PathState::p terResult = calcNodeRev(uIndex-1, pspCur, bMultiQuality); } - Log(lsINFO) << boost::str(boost::format("calcNodeRev< uIndex=%d terResult=%d") % uIndex % terResult); + Log(lsINFO) << boost::str(boost::format("calcNodeRev< uIndex=%d terResult=%s/%d") % uIndex % transToken(terResult) % terResult); return terResult; } @@ -3399,6 +3422,8 @@ void TransactionEngine::pathNext(const PathState::pointer& pspCur, const int iPa pspCur->terStatus = calcNodeRev(uLast, pspCur, bMultiQuality); + Log(lsINFO) << "Path after reverse: " << pspCur->getJson(); + if (tesSUCCESS == pspCur->terStatus) { // Do forward. @@ -3406,18 +3431,13 @@ void TransactionEngine::pathNext(const PathState::pointer& pspCur, const int iPa mNodes.bumpSeq(); // Begin ledger varance. pspCur->terStatus = calcNodeFwd(0, pspCur, bMultiQuality); + + pspCur->uQuality = tesSUCCESS == pspCur->terStatus + ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. + : 0; // Mark path as inactive. + + Log(lsINFO) << "Path after forward: " << pspCur->getJson(); } - - Log(lsINFO) << "pathNext: terStatus=" - << pspCur->terStatus - << " saOutAct=" << pspCur->saOutAct.getText() - << " saInAct=" << pspCur->saInAct.getText(); - - pspCur->uQuality = tesSUCCESS == pspCur->terStatus - ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. - : 0; // Mark path as inactive. - - Log(lsINFO) << "Path Out: " << pspCur->getJson(); } // XXX Need to audit for things like setting accountID not having memory. @@ -3573,13 +3593,13 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) { // Had a success. terResult = tesSUCCESS; - } - vpsPaths.push_back(pspDirect); + vpsPaths.push_back(pspDirect); + } } } - Log(lsINFO) << "doPayment: Paths: " << spsPaths.getPathCount(); + Log(lsINFO) << "doPayment: Paths in set: " << spsPaths.getPathCount(); BOOST_FOREACH(const STPath& spPath, spsPaths) { @@ -3633,11 +3653,11 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) while (temUNCERTAIN == terResult) { - PathState::pointer pspBest; - const LedgerEntrySet lesCheckpoint = mNodes; + PathState::pointer pspBest; + const LedgerEntrySet lesCheckpoint = mNodes; // Find the best path. - BOOST_FOREACH(PathState::pointer pspCur, vpsPaths) + BOOST_FOREACH(PathState::pointer& pspCur, vpsPaths) { pathNext(pspCur, vpsPaths.size(), lesCheckpoint); // Compute increment. From 159fe2145a536467853b93094ebd601d5cee0a1d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 5 Sep 2012 14:36:50 -0700 Subject: [PATCH 201/426] Copy the correct hash --- src/ValidationCollection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 74039ad009..e788b98e73 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -41,7 +41,7 @@ bool ValidationCollection::addValidation(const SerializedValidation::pointer& va it->second = val; else if (val->getSignTime() > it->second->getSignTime()) { - val->setPreviousHash(it->second->getPreviousHash()); + val->setPreviousHash(it->second->getLedgerHash()); mStaleValidations.push_back(it->second); it->second = val; condWrite(); From ec625a608f2a30706f207d21c38d0283dae7860d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 5 Sep 2012 14:37:42 -0700 Subject: [PATCH 202/426] Small tweaks. --- src/LedgerConsensus.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 12fd086f9c..54c3caf61e 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -501,8 +501,6 @@ void LedgerConsensus::statePreClose() statusChange(newcoin::neCLOSING_LEDGER, *mPreviousLedger); takeInitialPosition(*theApp->getMasterLedger().closeLedger()); } - else if (mHaveCorrectLCL) - checkLCL(); // double check } void LedgerConsensus::stateEstablish() @@ -536,7 +534,7 @@ void LedgerConsensus::stateAccepted() void LedgerConsensus::timerEntry() { - if ((!mHaveCorrectLCL && (mState != lcsACCEPTED)) || (mState == lcsPRE_CLOSE)) + if ((mState != lcsFINISHED) && (mState != lcsACCEPTED)) checkLCL(); mCurrentMSeconds = @@ -639,7 +637,7 @@ void LedgerConsensus::updateOurPositions() Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << " out of " << thresh; if (it->second > thresh) { - Log(lsINFO) << "Close time consensus reached: " << closeTime; + Log(lsINFO) << "Close time consensus reached: " << it->first; mHaveCloseTimeConsensus = true; closeTime = it->first; thresh = it->second; From 2512eac3700e792eded5d1d8c3bd5b72ae6adc00 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 5 Sep 2012 14:52:55 -0700 Subject: [PATCH 203/426] Rounding was messing up the close time consensus test. --- src/LedgerConsensus.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 54c3caf61e..e7b984fa8d 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -249,7 +249,11 @@ void LedgerConsensus::checkLCL() uint256 netLgr = mPrevLedgerHash; int netLgrCount = 0; - boost::unordered_map vals = theApp->getValidations().getCurrentValidations(mPrevLedgerHash); + uint256 favorLedger; + if (mState != lcsPRE_CLOSE) + favorLedger = mPrevLedgerHash; + boost::unordered_map vals = theApp->getValidations().getCurrentValidations(favorLedger); + typedef std::pair u256_int_pair; BOOST_FOREACH(u256_int_pair& it, vals) { @@ -628,7 +632,7 @@ void LedgerConsensus::updateOurPositions() ++closeTimes[roundCloseTime(mOurPosition->getCloseTime())]; ++thresh; } - thresh = thresh * neededWeight / 100; + thresh = ((thresh * neededWeight) + (neededWeight / 2)) / 100; if (thresh == 0) thresh = 1; @@ -643,6 +647,9 @@ void LedgerConsensus::updateOurPositions() thresh = it->second; } } + if (!mHaveCloseTimeConsensus) + Log(lsDEBUG) << "No CT consensus: Proposers:" << mPeerPositions.size() << " Proposing:" << + (mProposing ? "yes" : "no") << " Thresh:" << thresh << " Pos:" << closeTime; } if ((!changes) && From 0d40390e6bbd5b2fa5dd7289f16f80e51f9b1121 Mon Sep 17 00:00:00 2001 From: jed Date: Wed, 5 Sep 2012 15:33:48 -0700 Subject: [PATCH 204/426] contract --- newcoin.vcxproj | 2 ++ newcoin.vcxproj.filters | 8 ++++- src/LedgerFormats.cpp | 16 +++++++++ src/LedgerFormats.h | 4 +-- src/SerializedObject.h | 11 ++++++ src/TransactionEngine.cpp | 69 ++++++++++++++++++++++++++++++++++---- src/TransactionEngine.h | 4 ++- src/TransactionFormats.cpp | 21 ++++++++++++ src/TransactionFormats.h | 4 ++- src/UniqueNodeList.cpp | 4 +++ 10 files changed, 132 insertions(+), 11 deletions(-) diff --git a/newcoin.vcxproj b/newcoin.vcxproj index adb8abc714..6f7548d105 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -141,6 +141,7 @@ + @@ -232,6 +233,7 @@ + diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index b97a607c9e..fcf37fc266 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -288,6 +288,9 @@ Source Files + + Source Files + @@ -533,8 +536,11 @@ Header Files + + Header Files + - Source Files + Header Files diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index a5662004e7..e1376ea3af 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -77,9 +77,25 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, + { "Contract", ltCONTRACT, { + { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, + { S_FIELD(Issuer), STI_ACCOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(Owner), STI_ACCOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(Expiration), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(BondAmount), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(StampEscrow), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(RippleEscrow), STI_AMOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(CreateCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, + { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + }, { NULL, ltINVALID } }; + LedgerEntryFormat* getLgrFormat(LedgerEntryType t) { LedgerEntryFormat* f = LedgerFormats; diff --git a/src/LedgerFormats.h b/src/LedgerFormats.h index 22ae55ebf2..c1cdc505b6 100644 --- a/src/LedgerFormats.h +++ b/src/LedgerFormats.h @@ -13,6 +13,7 @@ enum LedgerEntryType ltRIPPLE_STATE = 'r', ltNICKNAME = 'n', ltOFFER = 'o', + ltCONTRACT = 'c', }; // Used as a prefix for computing ledger indexes (keys). @@ -26,8 +27,7 @@ enum LedgerNameSpace spaceOffer = 'o', // Entry for an offer. spaceOwnerDir = 'O', // Directory of things owned by an account. spaceBookDir = 'B', // Directory of order books. - spaceBond = 'b', - spaceInvoice = 'i', + spaceContract = 'c', }; enum LedgerSpecificFlags diff --git a/src/SerializedObject.h b/src/SerializedObject.h index d53dd5ed12..3e36c07c9f 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -18,6 +18,8 @@ enum SOE_Type SOE_IFNFLAG = 3 // present if flag not set }; +// JED: seems like there would be a better way to do this +// maybe something that inherits from SerializedTransaction enum SOE_Field { sfInvalid = -1, @@ -31,12 +33,14 @@ enum SOE_Field sfAmount, sfAuthorizedKey, sfBalance, + sfBondAmount, sfBookDirectory, sfBookNode, sfBorrowExpire, sfBorrowRate, sfBorrowStart, sfBorrower, + sfCreateCode, sfCloseTime, sfCurrency, sfCurrencyIn, @@ -45,9 +49,11 @@ enum SOE_Field sfDomain, sfEmailHash, sfExpiration, + sfExpireCode, sfExtensions, sfFirstNode, sfFlags, + sfFundCode, sfGenerator, sfGeneratorID, sfHash, @@ -60,6 +66,7 @@ enum SOE_Field sfIndexNext, sfIndexPrevious, sfInvoiceID, + sfIssuer, sfLastNode, sfLastReceive, sfLastSignedSeq, @@ -81,6 +88,7 @@ enum SOE_Field sfNextTransitStart, sfNickname, sfOfferSequence, + sfOwner, sfOwnerNode, sfPaths, sfPubKey, @@ -88,12 +96,15 @@ enum SOE_Field sfPublishSize, sfQualityIn, sfQualityOut, + sfRemoveCode, + sfRippleEscrow, sfSendMax, sfSequence, sfSignature, sfSigningKey, sfSigningTime, sfSourceTag, + sfStampEscrow, sfTakerGets, sfTakerPays, sfTarget, diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index aa58296949..7bc875e06e 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -996,7 +996,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, STAmount saCost = theConfig.FEE_DEFAULT; - // Customize behavoir based on transaction type. + // Customize behavior based on transaction type. if (tesSUCCESS == terResult) { switch (txn.getTxnType()) @@ -1024,7 +1024,6 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, case ttACCOUNT_SET: case ttCREDIT_SET: - case ttINVOICE: case ttOFFER_CREATE: case ttOFFER_CANCEL: case ttPASSWORD_FUND: @@ -1194,7 +1193,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, else if (saSrcBalance < saPaid) { Log(lsINFO) - << boost::str(boost::format("applyTransaction: Delay: insufficent balance: balance=%s paid=%s") + << boost::str(boost::format("applyTransaction: Delay: insufficient balance: balance=%s paid=%s") % saSrcBalance.getText() % saPaid.getText()); @@ -1278,9 +1277,9 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, terResult = temINVALID; break; - case ttINVOICE: - terResult = doInvoice(txn); - break; + //case ttINVOICE: + // terResult = doInvoice(txn); + // break; case ttOFFER_CREATE: terResult = doOfferCreate(txn); @@ -1310,6 +1309,13 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, terResult = doWalletAdd(txn); break; + case ttCONTRACT: + terResult= doContractAdd(txn); + break; + case ttCONTRACT_REMOVE: + terResult=doContractRemove(txn); + break; + default: terResult = temUNKNOWN; break; @@ -1358,6 +1364,8 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, return terResult; } + + TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { Log(lsINFO) << "doAccountSet>"; @@ -4757,4 +4765,53 @@ TER TransactionEngine::doDelete(const SerializedTransaction& txn) return temUNKNOWN; } +#include "Interpreter.h" +#include "Contract.h" + +TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) +{ + Log(lsWARNING) << "doContractAdd> " << txn.getJson(0); + + const uint32 expiration = txn.getITFieldU32(sfExpiration); + const uint32 bondAmount = txn.getITFieldU32(sfBondAmount); + const uint32 stampEscrow = txn.getITFieldU32(sfStampEscrow); + STAmount rippleEscrow = txn.getITFieldAmount(sfRippleEscrow); + std::vector createCode = txn.getITFieldVL(sfCreateCode); + std::vector fundCode = txn.getITFieldVL(sfFundCode); + std::vector removeCode = txn.getITFieldVL(sfRemoveCode); + std::vector expireCode = txn.getITFieldVL(sfExpireCode); + + // make sure + // expiration hasn't passed + // bond amount is enough + // they have the stamps for the bond + + // place contract in ledger + // run create code + + + if (mLedger->getParentCloseTimeNC() >= expiration) + { + Log(lsWARNING) << "doContractAdd: Expired transaction: offer expired"; + return(tefALREADY); + } + //TODO: check bond + //if( txn.getSourceAccount() ) + + Contract contract; + Interpreter interpreter; + TER terResult=interpreter->interpret(&contract,txn,createCode); + if(tesSUCCESS != terResult) + { + + } + + return(terResult); +} + +TER TransactionEngine::doContractRemove(const SerializedTransaction& txn) +{ + +} + // vim:ts=4 diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 9747850e6b..364e69de34 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -63,7 +63,7 @@ enum TER // aka TransactionEngineResult // Implications: // - Not applied // - Not forwarded - // - Could succeed in an imaginared ledger. + // - Could succeed in an imagined ledger. tefFAILURE = -199, tefALREADY, tefBAD_ADD_AUTH, @@ -334,6 +334,8 @@ protected: TER doStore(const SerializedTransaction& txn); TER doTake(const SerializedTransaction& txn); TER doWalletAdd(const SerializedTransaction& txn); + TER doContractAdd(const SerializedTransaction& txn); + TER doContractRemove(const SerializedTransaction& txn); public: TransactionEngine() { ; } diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 00318027b2..5260b6bb66 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -37,6 +37,7 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, + /* { "Invoice", ttINVOICE, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 }, @@ -47,6 +48,7 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, + */ { "NicknameSet", ttNICKNAME_SET, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Nickname), STI_HASH256, SOE_REQUIRED, 0 }, @@ -110,6 +112,25 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, + { "Contract", ttCONTRACT, { + { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, + { S_FIELD(Expiration), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(BondAmount), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(StampEscrow), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(RippleEscrow), STI_AMOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(CreateCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, + { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + }, + { "Contract", ttCONTRACT_REMOVE, { + { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, + { S_FIELD(ContractID), STI_ACCOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, + { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + }, { NULL, ttINVALID } }; diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index a49a1513e1..a77fcd3ad0 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -15,8 +15,10 @@ enum TransactionType ttNICKNAME_SET = 6, ttOFFER_CREATE = 7, ttOFFER_CANCEL = 8, + ttCONTRACT = 9, + ttCONTRACT_REMOVE = 10, // can we use the same msg as offer cancel + ttCREDIT_SET = 20, - ttINVOICE = 10, }; struct TransactionFormat diff --git a/src/UniqueNodeList.cpp b/src/UniqueNodeList.cpp index 74ceb647fd..708a4f5e94 100644 --- a/src/UniqueNodeList.cpp +++ b/src/UniqueNodeList.cpp @@ -39,6 +39,10 @@ #define REFERRAL_VALIDATORS_MAX 50 #define REFERRAL_IPS_MAX 50 +#ifndef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + UniqueNodeList::UniqueNodeList(boost::asio::io_service& io_service) : mdtScoreTimer(io_service), mFetchActive(0), From 8e5374b338e18b741e013840d4987852254d54f5 Mon Sep 17 00:00:00 2001 From: jed Date: Wed, 5 Sep 2012 16:54:14 -0700 Subject: [PATCH 205/426] contract stuff. Still aways a way I just wanted to get it in github. --- src/Contract.cpp | 35 ++++ src/Contract.h | 30 +++ src/Interpreter.cpp | 367 +++++++++++++++++++++++++++++++++++++ src/Interpreter.h | 85 +++++++++ src/ScriptData.cpp | 1 + src/ScriptData.h | 94 ++++++++++ src/TransactionEngine.cpp | 11 +- src/TransactionFormats.cpp | 2 +- 8 files changed, 619 insertions(+), 6 deletions(-) create mode 100644 src/Contract.cpp create mode 100644 src/Contract.h create mode 100644 src/Interpreter.cpp create mode 100644 src/Interpreter.h create mode 100644 src/ScriptData.cpp create mode 100644 src/ScriptData.h diff --git a/src/Contract.cpp b/src/Contract.cpp new file mode 100644 index 0000000000..09c3a4ecfc --- /dev/null +++ b/src/Contract.cpp @@ -0,0 +1,35 @@ +#include "Contract.h" +#include "Interpreter.h" + +using namespace Script; +/* +JED: V III +*/ + +Contract::Contract() +{ + +} + + +void Contract::executeCreate() +{ + +} +void Contract::executeRemove() +{ + +} +void Contract::executeFund() +{ + +} +void Contract::executeAccept() +{ + //std::vector code; + + //Interpreter interpreter; + //interpreter.interpret(this,code); +} + + diff --git a/src/Contract.h b/src/Contract.h new file mode 100644 index 0000000000..76d30dc54a --- /dev/null +++ b/src/Contract.h @@ -0,0 +1,30 @@ +#ifndef __CONTRACT__ +#define __CONTRACT__ + +#include "SerializedLedger.h" +#include +#include "ScriptData.h" +/* + Encapsulates the SLE for a Contract +*/ + +class Contract +{ +public: + Contract(); + + uint160& getIssuer(); + uint160& getOwner(); + STAmount& getRippleEscrow(); + uint32 getEscrow(); + uint32 getBond(); + + Script::Data getData(int index); + + void executeCreate(); + void executeRemove(); + void executeFund(); + void executeAccept(); +}; + +#endif \ No newline at end of file diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp new file mode 100644 index 0000000000..0b370683f9 --- /dev/null +++ b/src/Interpreter.cpp @@ -0,0 +1,367 @@ +#include "Interpreter.h" +#include "Config.h" + +/* +We also need to charge for each op + +*/ + +namespace Script { + + +////////////////////////////////////////////////////////////////////////// +/// Operations + +int Operation::getFee() +{ + return(theConfig.FEE_CONTRACT_OPERATION); +} + +// this is just an Int in the code +class IntOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->getIntData(); + if(data->isInt32()) + { + interpreter->pushStack( data ); + return(true); + } + return(false); + } +}; + +class FloatOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->getFloatData(); + if(data->isFloat()) + { + interpreter->pushStack( data ); + return(true); + } + return(false); + } +}; + +class Uint160Op : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->getUint160Data(); + if(data->isUint160()) + { + interpreter->pushStack( data ); + return(true); + } + return(false); + } +}; + +class AddOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data1=interpreter->popStack(); + Data::pointer data2=interpreter->popStack(); + if( (data1->isInt32() || data1->isFloat()) && + (data2->isInt32() || data2->isFloat()) ) + { + if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()+data2->getFloat()))); + else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()+data2->getInt()))); + return(true); + }else + { + return(false); + } + } +}; + +class SubOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data1=interpreter->popStack(); + Data::pointer data2=interpreter->popStack(); + if( (data1->isInt32() || data1->isFloat()) && + (data2->isInt32() || data2->isFloat()) ) + { + if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()-data2->getFloat()))); + else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()-data2->getInt()))); + return(true); + }else + { + return(false); + } + } +}; + + +class StartBlockOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer offset=interpreter->getIntData(); + return(interpreter->startBlock(offset->getInt())); + } +}; + +class EndBlockOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + return(interpreter->endBlock()); + } +}; + +class StopOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + interpreter->stop(); + return(true); + } +}; + +class AcceptDataOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->popStack(); + if(data->isInt32()) + { + interpreter->pushStack( interpreter->getAcceptData(data->getInt()) ); + return(true); + } + return(false); + } +}; + +class JumpIfOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer offset=interpreter->getIntData(); + Data::pointer cond=interpreter->popStack(); + if(cond->isBool() && offset->isInt32()) + { + if(cond->isTrue()) + { + return(interpreter->jumpTo(offset->getInt())); + } + return(true); + } + return(false); + } +}; + +class JumpOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer offset=interpreter->getIntData(); + if(offset->isInt32()) + { + return(interpreter->jumpTo(offset->getInt())); + } + return(false); + } +}; + +class SendXNSOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer sourceID=interpreter->popStack(); + Data::pointer destID=interpreter->popStack(); + Data::pointer amount=interpreter->popStack(); + if(sourceID->isUint160() && destID->isUint160() && amount->isInt32() && interpreter->canSign(sourceID->getUint160())) + { + // make sure: + // source is either, this contract, issuer, or acceptor + + // TODO do the send + //interpreter->pushStack( send result); + + return(true); + } + + return(false); + } +}; + +class GetDataOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer index=interpreter->popStack(); + if(index->isInt32()) + { + interpreter->pushStack( interpreter->getContractData(index->getInt())); + return(true); + } + + return(false); + } +}; + +////////////////////////////////////////////////////////////////////////// + +Interpreter::Interpreter() +{ + mContract=NULL; + mCode=NULL; + mInstructionPointer=0; + mTotalFee=0; + + mInBlock=false; + mBlockSuccess=true; + mBlockJump=0; + + mFunctionTable.resize(NUM_OF_OPS); + + mFunctionTable[INT_OP]=new IntOp(); + mFunctionTable[FLOAT_OP]=new FloatOp(); + mFunctionTable[UINT160_OP]=new Uint160Op(); + + mFunctionTable[ADD_OP]=new AddOp(); + mFunctionTable[SUB_OP]=new SubOp(); + +} + +Data::pointer Interpreter::popStack() +{ + if(mStack.size()) + { + Data::pointer item=mStack[mStack.size()-1]; + mStack.pop_back(); + return(item); + }else + { + return(Data::pointer(new ErrorData())); + } +} + +void Interpreter::pushStack(Data::pointer data) +{ + mStack.push_back(data); +} + + +// offset is where to jump to if the block fails +bool Interpreter::startBlock(int offset) +{ + if(mInBlock) return(false); // can't nest blocks + mBlockSuccess=true; + mInBlock=true; + mBlockJump=offset+mInstructionPointer; + return(true); +} + +bool Interpreter::endBlock() +{ + if(!mInBlock) return(false); + mInBlock=false; + mBlockJump=0; + pushStack(Data::pointer(new BoolData(mBlockSuccess))); + return(true); +} + +TER Interpreter::interpret(Contract* contract,const SerializedTransaction& txn,std::vector& code) +{ + mContract=contract; + mCode=&code; + mTotalFee=0; + mInstructionPointer=0; + while(mInstructionPointer=mFunctionTable.size()) + { + // TODO: log + return(temMALFORMED); // TODO: is this actually what we want to do? + } + + mTotalFee += mFunctionTable[ fun ]->getFee(); + if(mTotalFee>txn.getTransactionFee().getNValue()) + { + // TODO: log + return(telINSUF_FEE_P); + }else + { + if(!mFunctionTable[ fun ]->work(this)) + { + // TODO: log + return(temMALFORMED); // TODO: is this actually what we want to do? + } + } + } + return(tesSUCCESS); +} + + +Data::pointer Interpreter::getIntData() +{ + int value=0; // TODO + mInstructionPointer += 4; + return(Data::pointer(new IntData(value))); +} + +Data::pointer Interpreter::getFloatData() +{ + float value=0; // TODO + mInstructionPointer += 4; + return(Data::pointer(new FloatData(value))); +} + +Data::pointer Interpreter::getUint160Data() +{ + uint160 value; // TODO + mInstructionPointer += 20; + return(Data::pointer(new Uint160Data(value))); +} + + + +bool Interpreter::jumpTo(int offset) +{ + mInstructionPointer += offset; + if( (mInstructionPointer<0) || (mInstructionPointer>mCode->size()) ) + { + mInstructionPointer -= offset; + return(false); + } + return(true); +} + +void Interpreter::stop() +{ + mInstructionPointer=mCode->size(); +} + +Data::pointer Interpreter::getContractData(int index) +{ + return(Data::pointer(new ErrorData())); +} + + + + +} // end namespace diff --git a/src/Interpreter.h b/src/Interpreter.h new file mode 100644 index 0000000000..5d8f58b009 --- /dev/null +++ b/src/Interpreter.h @@ -0,0 +1,85 @@ +#ifndef __INTERPRETER__ +#define __INTERPRETER__ + +#include "uint256.h" +#include "Contract.h" +#include +#include +#include "ScriptData.h" +#include "TransactionEngine.h" + +namespace Script { + +class Interpreter; + +// Contracts are non typed have variable data types + + +class Operation +{ +public: + // returns false if there was an error + virtual bool work(Interpreter* interpreter)=0; + + virtual int getFee(); +}; + +class Interpreter +{ + std::vector mFunctionTable; + + std::vector mStack; + + Contract* mContract; + std::vector* mCode; + unsigned int mInstructionPointer; + int mTotalFee; + + bool mInBlock; + int mBlockJump; + bool mBlockSuccess; + +public: + enum { INT_OP,FLOAT_OP,UINT160_OP,BOOL_OP,PATH_OP, + ADD_OP,SUB_OP,MUL_OP,DIV_OP,MOD_OP, + GTR_OP,LESS_OP,EQUAL_OP,NOT_EQUAL_OP, + AND_OP,OR_OP,NOT_OP, + BLOCK_OP, BLOCK_END_OP, + JUMP_OP, JUMPIF_OP, + STOP_OP, + SET_DATA_OP,GET_DATA_OP, GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, + ACCEPT_DATA_OP, + SEND_XNS_OP, NUM_OF_OPS }; + + Interpreter(); + + // returns a TransactionEngineResult + TER interpret(Contract* contract,const SerializedTransaction& txn,std::vector& code); + + void stop(); + + bool canSign(uint160& signer); + + int getInstructionPointer(){ return(mInstructionPointer); } + void setInstructionPointer(int n){ mInstructionPointer=n;} + + Data::pointer popStack(); + void pushStack(Data::pointer data); + bool jumpTo(int offset); + + bool startBlock(int offset); + bool endBlock(); + + + Data::pointer getIntData(); + Data::pointer getFloatData(); + Data::pointer getUint160Data(); + Data::pointer getAcceptData(int index); + Data::pointer getContractData(int index); + + +}; + +} // end namespace + +#endif \ No newline at end of file diff --git a/src/ScriptData.cpp b/src/ScriptData.cpp new file mode 100644 index 0000000000..52442c0d17 --- /dev/null +++ b/src/ScriptData.cpp @@ -0,0 +1 @@ +#include "ScriptData.h" \ No newline at end of file diff --git a/src/ScriptData.h b/src/ScriptData.h new file mode 100644 index 0000000000..af9ce45c0e --- /dev/null +++ b/src/ScriptData.h @@ -0,0 +1,94 @@ +#ifndef __SCRIPT_DATA__ +#define __SCRIPT_DATA__ +#include "uint256.h" +#include + +namespace Script { +class Data +{ +public: + typedef boost::shared_ptr pointer; + + virtual bool isInt32(){ return(false); } + virtual bool isFloat(){ return(false); } + virtual bool isUint160(){ return(false); } + virtual bool isError(){ return(false); } + virtual bool isTrue(){ return(false); } + virtual bool isBool(){ return(false); } + //virtual bool isBlockEnd(){ return(false); } + + virtual int getInt(){ return(0); } + virtual float getFloat(){ return(0); } + virtual uint160 getUint160(){ return(0); } + + //virtual bool isCurrency(){ return(false); } +}; + +class IntData : public Data +{ + int mValue; +public: + IntData(int value) + { + mValue=value; + } + bool isInt32(){ return(true); } + int getInt(){ return(mValue); } + float getFloat(){ return((float)mValue); } + bool isTrue(){ return(mValue!=0); } +}; + +class FloatData : public Data +{ + float mValue; +public: + FloatData(float value) + { + mValue=value; + } + bool isFloat(){ return(true); } + float getFloat(){ return(mValue); } + bool isTrue(){ return(mValue!=0); } +}; + +class Uint160Data : public Data +{ + uint160 mValue; +public: + Uint160Data(uint160 value) + { + mValue=value; + } + bool isUint160(){ return(true); } + uint160 getUint160(){ return(mValue); } +}; + +class BoolData : public Data +{ + bool mValue; +public: + BoolData(bool value) + { + mValue=value; + } + bool isBool(){ return(true); } + bool isTrue(){ return(mValue); } +}; + +class ErrorData : public Data +{ +public: + bool isError(){ return(true); } +}; + +class BlockEndData : public Data +{ +public: + bool isBlockEnd(){ return(true); } +}; + + +} + + +#endif \ No newline at end of file diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index aef58f3b4d..af72e38d78 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -17,6 +17,8 @@ #include "Log.h" #include "TransactionFormats.h" #include "utils.h" +#include "Interpreter.h" +#include "Contract.h" // Small for testing, should likely be 32 or 64. #define DIR_NODE_MAX 2 @@ -4659,8 +4661,6 @@ void TransactionEngine::calcNodeOffer( } #endif -#include "Interpreter.h" -#include "Contract.h" TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) { @@ -4693,8 +4693,8 @@ TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) //if( txn.getSourceAccount() ) Contract contract; - Interpreter interpreter; - TER terResult=interpreter->interpret(&contract,txn,createCode); + Script::Interpreter interpreter; + TER terResult=interpreter.interpret(&contract,txn,createCode); if(tesSUCCESS != terResult) { @@ -4705,7 +4705,8 @@ TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) TER TransactionEngine::doContractRemove(const SerializedTransaction& txn) { - + // TODO: + return(tesSUCCESS); } // vim:ts=4 diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 5260b6bb66..de18524c7c 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -127,7 +127,7 @@ TransactionFormat InnerTxnFormats[]= }, { "Contract", ttCONTRACT_REMOVE, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(ContractID), STI_ACCOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, From 687578abd9c8982879e6482602a06f9e144b80ea Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 5 Sep 2012 21:55:00 -0700 Subject: [PATCH 206/426] Get rid of "dead" ledgers. We don't need them any more and they make trouble. Fix close time synch to be more accurate. --- src/LedgerConsensus.cpp | 2 +- src/NetworkOPs.cpp | 18 ++++++++++-------- src/ValidationCollection.cpp | 22 ---------------------- src/ValidationCollection.h | 5 ----- 4 files changed, 11 insertions(+), 36 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index e7b984fa8d..cd30acf1e8 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -257,7 +257,7 @@ void LedgerConsensus::checkLCL() typedef std::pair u256_int_pair; BOOST_FOREACH(u256_int_pair& it, vals) { - if ((it.second > netLgrCount) && !theApp->getValidations().isDeadLedger(it.first)) + if (it.second > netLgrCount) { netLgr = it.first; netLgrCount = it.second; diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index fc2b547541..68127015f3 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -56,8 +56,13 @@ uint32 NetworkOPs::getValidationTimeNC() } void NetworkOPs::closeTimeOffset(int offset) -{ - mCloseTimeOffset += offset / 4; +{ // take large offsets, ignore small offsets, push towards our wall time + if (offset > 1) + mCloseTimeOffset += (offset + 3) / 4; + else if (offset < -1) + mCloseTimeOffset += (offset - 3) / 4; + else + mCloseTimeOffset = (mCloseTimeOffset * 3) / 4; if (mCloseTimeOffset) Log(lsINFO) << "Close time offset now " << mCloseTimeOffset; } @@ -487,10 +492,9 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis for (boost::unordered_map::iterator it = ledgers.begin(), end = ledgers.end(); it != end; ++it) { - bool isDead = theApp->getValidations().isDeadLedger(it->first); - Log(lsTRACE) << "L: " << it->first << ((isDead) ? " dead" : " live") << - " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; - if ((it->second > bestVC) && !isDead) + Log(lsTRACE) << "L: " << it->first << " t=" << it->second.trustedValidations << + ", n=" << it->second.nodesUsing; + if (it->second > bestVC) { bestVC = it->second; closedLedger = it->first; @@ -718,8 +722,6 @@ void NetworkOPs::mapComplete(const uint256& hash, const SHAMap::pointer& map) void NetworkOPs::endConsensus(bool correctLCL) { uint256 deadLedger = theApp->getMasterLedger().getClosedLedger()->getParentHash(); - Log(lsTRACE) << "Ledger " << deadLedger << " is now dead"; - theApp->getValidations().addDeadLedger(deadLedger); std::vector peerList = theApp->getConnectionPool().getPeerVector(); BOOST_FOREACH(Peer::ref it, peerList) if (it && (it->getClosedLedgerHash() == deadLedger)) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index e788b98e73..b11b38b633 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -164,28 +164,6 @@ boost::unordered_map ValidationCollection::getCurrentValidations(u return ret; } -bool ValidationCollection::isDeadLedger(const uint256& ledger) -{ - boost::mutex::scoped_lock sl(mValidationLock); - BOOST_FOREACH(const uint256& it, mDeadLedgers) - if (it == ledger) - return true; - return false; -} - -void ValidationCollection::addDeadLedger(const uint256& ledger) -{ - boost::mutex::scoped_lock sl(mValidationLock); - - BOOST_FOREACH(const uint256& it, mDeadLedgers) - if (it == ledger) - return; - - mDeadLedgers.push_back(ledger); - if (mDeadLedgers.size() >= 32) - mDeadLedgers.pop_front(); -} - void ValidationCollection::flush() { boost::mutex::scoped_lock sl(mValidationLock); diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index 287ba6b68f..1972b7b63e 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -20,7 +20,6 @@ protected: boost::unordered_map mValidations; boost::unordered_map mCurrentValidations; std::vector mStaleValidations; - std::list mDeadLedgers; bool mWriting; @@ -39,10 +38,6 @@ public: boost::unordered_map getCurrentValidations(uint256 currentLedger = uint256()); - void addDeadLedger(const uint256&); - bool isDeadLedger(const uint256&); - std::list getDeadLedgers() { return mDeadLedgers; } - void flush(); }; From 2da2b340fced9999b3c92c7418771ad91a32e87c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 5 Sep 2012 21:55:20 -0700 Subject: [PATCH 207/426] Make it compile. --- src/Interpreter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Interpreter.h b/src/Interpreter.h index 5d8f58b009..5375c1b690 100644 --- a/src/Interpreter.h +++ b/src/Interpreter.h @@ -58,7 +58,7 @@ public: void stop(); - bool canSign(uint160& signer); + bool canSign(const uint160& signer); int getInstructionPointer(){ return(mInstructionPointer); } void setInstructionPointer(int n){ mInstructionPointer=n;} From 6eacbf16e744338e95f053616ce50458777bf203 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 5 Sep 2012 22:23:03 -0700 Subject: [PATCH 208/426] Typo. --- src/LedgerProposal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index c9c6fa8dd9..74d0f7c071 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -1,5 +1,5 @@ #ifndef __PROPOSELEDGER__ -#define __PROPOSELEDEGR__ +#define __PROPOSELEDGER__ #include #include From 4737b960fc5e6bf424d47aabd952123bc5f24515 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 5 Sep 2012 22:23:12 -0700 Subject: [PATCH 209/426] Improve comment. --- src/LedgerConsensus.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index cd30acf1e8..ebe2b08794 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -884,7 +884,7 @@ void LedgerConsensus::playbackProposals() BOOST_FOREACH(const LedgerProposal::pointer& proposal, it->second) { if (proposal->hasSignature()) - { // old-style + { // we have the signature but don't know the ledger so couldn't verify proposal->setPrevLedger(mPrevLedgerHash); if (proposal->checkSign()) { From a3241dae560797d59eee075687e70daf41d86ba7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 5 Sep 2012 22:28:26 -0700 Subject: [PATCH 210/426] Fix a case where we could lose deferred prposals. --- src/LedgerConsensus.h | 4 ++++ src/NetworkOPs.cpp | 4 +++- src/NetworkOPs.h | 13 ++++++++----- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index eef08c8807..4e1db172dd 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -181,6 +181,10 @@ public: bool peerGaveNodes(Peer::ref peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); + + void swapDefer(boost::unordered_map< uint160, std::list > &n) + { mDeferredProposals.swap(n); } + }; diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 68127015f3..7706cd7ac9 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -613,6 +613,7 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo prevLedger->setImmutable(); mConsensus = boost::make_shared( networkClosed, prevLedger, theApp->getMasterLedger().getCurrentLedger()->getCloseTimeNC()); + mConsensus->swapDefer(mDeferredProposals); Log(lsDEBUG) << "Initiating consensus engine"; return mConsensus->startup(); @@ -665,7 +666,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, cons } if (prevLedger.isNonZero()) - { // new-style + { // proposal includes a previous ledger LedgerProposal::pointer proposal = boost::make_shared(prevLedger, proposeSeq, proposeHash, closeTime, naPeerPublic); if (!proposal->checkSign(signature)) @@ -729,6 +730,7 @@ void NetworkOPs::endConsensus(bool correctLCL) Log(lsTRACE) << "Killing obsolete peer status"; it->cycleStatus(); } + mConsensus->swapDefer(mDeferredProposals); mConsensus = boost::shared_ptr(); } diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 25ac145f40..401d33baee 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -1,17 +1,18 @@ #ifndef __NETWORK_OPS__ #define __NETWORK_OPS__ +#include +#include +#include +#include + #include "AccountState.h" #include "LedgerMaster.h" #include "NicknameState.h" #include "RippleState.h" #include "SerializedValidation.h" #include "LedgerAcquire.h" - -#include -#include -#include -#include +#include "LedgerProposal.h" // Operations that clients may wish to perform against the network // Master operational handler, server sequencer, network tracker @@ -54,6 +55,8 @@ protected: boost::posix_time::ptime mConnectTime; boost::asio::deadline_timer mNetTimer; boost::shared_ptr mConsensus; + boost::unordered_map > mDeferredProposals; LedgerMaster* mLedgerMaster; LedgerAcquire::pointer mAcquiringLedger; From 7a479d6035edfa3d5da04bc89f5d52f3ed94d7be Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 6 Sep 2012 21:32:07 -0700 Subject: [PATCH 211/426] Fixes for rippling through an offer. --- src/Amount.cpp | 10 +- src/TransactionEngine.cpp | 225 +++++++++++++++++++++++++++++--------- src/TransactionEngine.h | 4 +- 3 files changed, 180 insertions(+), 59 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 29fd0195be..4c35c46a06 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -61,6 +61,10 @@ std::string STAmount::createHumanCurrency(const uint160& uCurrency) { return SYSTEM_CURRENCY_CODE; } + else if (uCurrency == CURRENCY_ONE) + { + return "1"; + } else { Serializer s(160/8); @@ -76,15 +80,15 @@ std::string STAmount::createHumanCurrency(const uint160& uCurrency) if (!::isZero(vucZeros.begin(), vucZeros.size())) { - throw std::runtime_error("bad currency: zeros"); + throw std::runtime_error(boost::str(boost::format("bad currency: zeros: %s") % uCurrency)); } else if (!::isZero(vucVersion.begin(), vucVersion.size())) { - throw std::runtime_error("bad currency: version"); + throw std::runtime_error(boost::str(boost::format("bad currency: version: %s") % uCurrency)); } else if (!::isZero(vucReserved.begin(), vucReserved.size())) { - throw std::runtime_error("bad currency: reserved"); + throw std::runtime_error(boost::str(boost::format("bad currency: reserved: %s") % uCurrency)); } else { diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 15534fc26a..8b737f4a30 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -22,8 +22,8 @@ #define DIR_NODE_MAX 2 #define RIPPLE_PATHS_MAX 3 -static STAmount saZero(CURRENCY_ONE, 0, 0); -static STAmount saOne(CURRENCY_ONE, 1, 0); +static STAmount saZero(CURRENCY_ONE, ACCOUNT_ONE, 0); +static STAmount saOne(CURRENCY_ONE, ACCOUNT_ONE, 1); std::size_t hash_value(const aciSource& asValue) { @@ -808,6 +808,7 @@ bool TransactionEngine::dirNext( } uEntryIndex = vuiIndexes[uDirEntry++]; +Log(lsINFO) << boost::str(boost::format("dirNext: uDirEntry=%d uEntryIndex=%s") % uDirEntry % uEntryIndex); return true; } @@ -1776,6 +1777,7 @@ TER TransactionEngine::doPasswordSet(const SerializedTransaction& txn) // If needed, advance to next funded offer. // - Automatically advances to first offer. // - Set bEntryAdvance to advance to next entry. +// <-- uOfferIndex : 0=end of list. TER TransactionEngine::calcNodeAdvance( const unsigned int uIndex, // 0 < uIndex < uLast const PathState::pointer& pspCur, @@ -1812,7 +1814,7 @@ TER TransactionEngine::calcNodeAdvance( { bool bDirectDirDirty = false; - if (!pnCur.uDirectEnd) + if (!uDirectEnd) { // Need to initialize current node. @@ -1821,6 +1823,8 @@ TER TransactionEngine::calcNodeAdvance( sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); bDirectAdvance = !sleDirectDir; bDirectDirDirty = true; + + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: Initialize node: uDirectTip=%s uDirectEnd=%s bDirectAdvance=%d") % uDirectTip % uDirectEnd % bDirectAdvance); } if (bDirectAdvance) @@ -1830,11 +1834,27 @@ TER TransactionEngine::calcNodeAdvance( bDirectDirDirty = true; bDirectAdvance = false; - if (!uDirectTip) + if (!!uDirectTip) + { + // Have another quality directory. + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: Quality advance: uDirectTip=%s") % uDirectTip); + + sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); + } + else if (bReverse) + { + Log(lsINFO) << "calcNodeAdvance: No more offers."; + + uOfferIndex = 0; + break; + } + else { // No more offers. Should be done rather than fall off end of book. Log(lsINFO) << "calcNodeAdvance: Unreachable: Fell off end of order book."; assert(false); + + terResult = tefEXCEPTION; } } @@ -1843,6 +1863,8 @@ TER TransactionEngine::calcNodeAdvance( saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio uEntry = 0; bEntryAdvance = true; + + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: directory dirty: saOfrRate=%s") % saOfrRate); } if (!bEntryAdvance) @@ -1854,6 +1876,13 @@ TER TransactionEngine::calcNodeAdvance( saOfferFunds = accountFunds(uOfrOwnerID, saTakerGets); // Funds left. bFundsDirty = false; + + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: directory dirty: saOfrRate=%s") % saOfrRate); + } + else + { + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: as is")); + nothing(); } } else if (!dirNext(uDirectTip, sleDirectDir, uEntry, uOfferIndex)) @@ -1865,10 +1894,12 @@ TER TransactionEngine::calcNodeAdvance( // Do another cur directory iff bMultiQuality if (bMultiQuality) { + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: next quality")); bDirectAdvance = true; } - else + else if (!bReverse) { + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: unreachable: ran out of offers")); assert(false); // Can't run out of offers in forward direction. terResult = tefEXCEPTION; } @@ -1881,6 +1912,8 @@ TER TransactionEngine::calcNodeAdvance( const aciSource asLine = boost::make_tuple(uOfrOwnerID, uCurCurrencyID, uCurIssuerID); + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: uOfrOwnerID=%s") % NewcoinAddress::createHumanAccountID(uOfrOwnerID)); + if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) { // Offer is expired. @@ -1896,7 +1929,7 @@ TER TransactionEngine::calcNodeAdvance( curIssuerNodeConstIterator itForward = pspCur->umForward.find(asLine); const bool bFoundForward = itForward != pspCur->umForward.end(); - if (bFoundForward || itForward->second != uIndex) + if (bFoundForward && itForward->second != uIndex) { // Temporarily unfunded. Another node uses this source, ignore in this offer. Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (forward)"; @@ -1908,7 +1941,7 @@ TER TransactionEngine::calcNodeAdvance( curIssuerNodeConstIterator itPast = mumSource.find(asLine); bool bFoundPast = itPast != mumSource.end(); - if (bFoundPast || itPast->second != uIndex) + if (bFoundPast && itPast->second != uIndex) { // Temporarily unfunded. Another node uses this source, ignore in this offer. Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (past)"; @@ -1920,7 +1953,7 @@ TER TransactionEngine::calcNodeAdvance( curIssuerNodeConstIterator itReverse = pspCur->umReverse.find(asLine); bool bFoundReverse = itReverse != pspCur->umReverse.end(); - if (bFoundReverse || itReverse->second != uIndex) + if (bFoundReverse && itReverse->second != uIndex) { // Temporarily unfunded. Another node uses this source, ignore in this offer. Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (reverse)"; @@ -1955,6 +1988,11 @@ TER TransactionEngine::calcNodeAdvance( && !bFoundReverse) // Not mentioned for pass. { // Consider source mentioned by current path state. + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: remember=%s/%s/%s") + % NewcoinAddress::createHumanAccountID(uOfrOwnerID) + % STAmount::createHumanCurrency(uCurCurrencyID) + % NewcoinAddress::createHumanAccountID(uCurIssuerID)); + pspCur->umReverse.insert(std::make_pair(asLine, uIndex)); } @@ -1964,6 +2002,15 @@ TER TransactionEngine::calcNodeAdvance( } while (tesSUCCESS == terResult && (bEntryAdvance || bDirectAdvance)); + if (tesSUCCESS == terResult) + { + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: uOfferIndex=%s") % uOfferIndex); + } + else + { + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: terResult=%s") % transToken(terResult)); + } + return terResult; } @@ -1992,7 +2039,7 @@ TER TransactionEngine::calcNodeDeliverRev( saOutAct = 0; - while (saOutAct != saOutReq) // Did not deliver limit. + while (saOutAct != saOutReq) // Did not deliver limit. { bool& bEntryAdvance = pnCur.bEntryAdvance; STAmount& saOfrRate = pnCur.saOfrRate; @@ -2016,20 +2063,52 @@ TER TransactionEngine::calcNodeDeliverRev( const STAmount saOutFeeRate = uOfrOwnerID == uCurIssuerID || uOutAccountID == uCurIssuerID // Issuer receiving or sending. ? saOne // No fee. : saTransferRate; // Transfer rate of issuer. + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: uOfrOwnerID=%s uOutAccountID=%s uCurIssuerID=%s saTransferRate=%s saOutFeeRate=%s") + % NewcoinAddress::createHumanAccountID(uOfrOwnerID) + % NewcoinAddress::createHumanAccountID(uOutAccountID) + % NewcoinAddress::createHumanAccountID(uCurIssuerID) + % saTransferRate.getFullText() + % saOutFeeRate.getFullText()); if (!saRateMax) { // Set initial rate. saRateMax = saOutFeeRate; + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Set initial rate: saRateMax=%s saOutFeeRate=%s") + % saRateMax + % saOutFeeRate); } else if (saRateMax < saOutFeeRate) { // Offer exceeds initial rate. + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Offer exceeds initial rate: saRateMax=%s saOutFeeRate=%s") + % saRateMax + % saOutFeeRate); + + nothing(); break; } + else if (saOutFeeRate < saRateMax) + { + // Reducing rate. - STAmount saOutPass = std::max(std::max(saOfferFunds, saTakerGets), saOutReq-saOutAct); // Offer maximum out - assuming no out fees. - STAmount saOutPlusFees = STAmount::divide(saOutPass, saOutFeeRate); // Offer out with fees. + saRateMax = saOutFeeRate; + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Reducing rate: saRateMax=%s") + % saRateMax); + } + + STAmount saOutPass = std::min(std::min(saOfferFunds, saTakerGets), saOutReq-saOutAct); // Offer maximum out - assuming no out fees. + STAmount saOutPlusFees = STAmount::multiply(saOutPass, saOutFeeRate); // Offer out with fees. + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: saOutReq=%s saOutAct=%s saTakerGets=%s saOutPass=%s saOutPlusFees=%s saOfferFunds=%s") + % saOutReq + % saOutAct + % saTakerGets + % saOutPass + % saOutPlusFees + % saOfferFunds); if (saOutPlusFees > saOfferFunds) { @@ -2037,6 +2116,11 @@ TER TransactionEngine::calcNodeDeliverRev( saOutPlusFees = saOfferFunds; saOutPass = STAmount::divide(saOutPlusFees, saOutFeeRate); + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Total exceeds fees: saOutPass=%s saOutPlusFees=%s saOfferFunds=%s") + % saOutPass + % saOutPlusFees + % saOfferFunds); } // Compute portion of input needed to cover output. @@ -2044,6 +2128,12 @@ TER TransactionEngine::calcNodeDeliverRev( STAmount saInPassReq = STAmount::multiply(saOutPass, saOfrRate, saTakerPays); STAmount saInPassAct; + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: saInPassReq=%s saOfrRate=%s saOutPass=%s saOutPlusFees=%s") + % saInPassReq + % saOfrRate + % saOutPass + % saOutPlusFees); + // Find out input amount actually available at current rate. if (!!uPrvAccountID) { @@ -2055,10 +2145,13 @@ TER TransactionEngine::calcNodeDeliverRev( saInPassAct = saInPassReq; - saPrvDlvReq = saInPassAct; + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: account --> OFFER --> ? : saInPassAct=%s") + % saPrvDlvReq); } else { + // offer --> OFFER --> ? + terResult = calcNodeDeliverRev( uIndex-1, pspCur, @@ -2066,6 +2159,9 @@ TER TransactionEngine::calcNodeDeliverRev( uOfrOwnerID, saInPassReq, saInPassAct); + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: offer --> OFFER --> ? : saInPassAct=%s") + % saInPassAct); } if (tesSUCCESS != terResult) @@ -2076,6 +2172,10 @@ TER TransactionEngine::calcNodeDeliverRev( // Adjust output to conform to limited input. saOutPass = STAmount::divide(saInPassAct, saOfrRate, saTakerGets); saOutPlusFees = STAmount::multiply(saOutPass, saOutFeeRate); + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: adjusted: saOutPass=%s saOutPlusFees=%s") + % saOutPass + % saOutPlusFees); } // Funds were spent. @@ -2093,10 +2193,13 @@ TER TransactionEngine::calcNodeDeliverRev( if (saOutPass == saTakerGets) { // Offer became unfunded. + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: offer became unfunded.")); + bEntryAdvance = true; } saOutAct += saOutPass; + saPrvDlvReq += saInPassAct; } if (!saOutAct) @@ -2158,16 +2261,24 @@ TER TransactionEngine::calcNodeDeliverFwd( // First calculate assuming no output fees. // XXX Make sure derived in does not exceed actual saTakerPays due to rounding. - 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 saInPassAct = STAmount::divide(saInSum, saInFeeRate); // In without fees. - STAmount saOutPassMax = STAmount::divide(saInPassAct, saOfrRate); // Out. + 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 saInPassAct = STAmount::divide(saInSum, saInFeeRate); // In without fees. + STAmount saOutPassMax = STAmount::divide(saInPassAct, saOfrRate, saOutFunded); // Out. STAmount saInPassFees; STAmount saOutPassAct; + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: saOutFunded=%s saInFunded=%s saInTotal=%s saInSum=%s saInPassAct=%s saOutPassMax=%s") + % saOutFunded + % saInFunded + % saInTotal + % saInSum + % saInPassAct + % saOutPassMax); + if (!!uNxtAccountID) { // ? --> OFFER --> account @@ -2181,6 +2292,9 @@ TER TransactionEngine::calcNodeDeliverFwd( accountSend(uOfrOwnerID, uCurIssuerID, saOutPassMax); saOutPassAct = saOutPassMax; + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: ? --> OFFER --> account: saOutPassAct=%s") + % saOutPassAct); } else { @@ -2205,6 +2319,12 @@ TER TransactionEngine::calcNodeDeliverFwd( saInPassFees = STAmount::multiply(saInFunded, saInFeeRate)-saInPassAct; } + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: saTakerGets=%s saTakerPays=%s saInPassAct=%s saOutPassAct=%s") + % saTakerGets.getFullText() + % saTakerPays.getFullText() + % saInPassAct.getFullText() + % saOutPassAct.getFullText()); + // Funds were spent. bFundsDirty = true; @@ -2489,13 +2609,15 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS const STAmount& saCurDeliverReq = pnCur.saRevDeliver; STAmount saCurDeliverAct(saCurDeliverReq.getCurrency(), saCurDeliverReq.getIssuer()); - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s") + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurRedeemReq=%s saNxtOwed=%s") % saPrvRedeemReq.getFullText() - % saPrvIssueReq.getFullText()); + % saPrvIssueReq.getFullText() + % saCurRedeemReq.getFullText() + % saNxtOwed.getFullText()); Log(lsINFO) << pspCur->getJson(); - assert(!saCurRedeemReq || saNxtOwed >= saCurRedeemReq); // Current redeem req can't be more than IOUs on hand. + assert(!saCurRedeemReq || (-saNxtOwed) >= saCurRedeemReq); // Current redeem req can't be more than IOUs on hand. assert(!saCurIssueReq || !saNxtOwed.isPositive() || saNxtOwed == saCurRedeemReq); // If issue req, then redeem req must consume all owed. if (bPrvAccount && bNxtAccount) @@ -3002,7 +3124,10 @@ bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::poi // - A node names it's output. // - A ripple nodes output issuer must be the node's account or the next node's account. // - Offers can only go directly to another offer if the currency and issuer are an exact match. -TER PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) +TER PathState::pushImply( + const uint160& uAccountID, // --> Delivering to this account. + const uint160& uCurrencyID, // --> Delivering this currency. + const uint160& uIssuerID) // --> Delivering this issuer. { const PaymentNode& pnPrv = vpnNodes.back(); TER terResult = tesSUCCESS; @@ -3014,7 +3139,7 @@ TER PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssue if (pnPrv.uCurrencyID != uCurrencyID) { - // Need to convert via an offer. + // Currency is different, need to convert via an offer. terResult = pushNode( STPathElement::typeCurrency // Offer. @@ -3025,16 +3150,17 @@ TER PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssue } + // For ripple, non-stamps, ensure the issuer is on at least one side of the transaction. if (tesSUCCESS == terResult - && !!uCurrencyID // Not stamps. - && (pnPrv.uAccountID != uIssuerID // Previous is not issuing own IOUs. - && uAccountID != uIssuerID)) // Current is not receiving own IOUs. + && !!uCurrencyID // Not stamps. + && (pnPrv.uAccountID != uIssuerID // Previous is not issuing own IOUs. + && uAccountID != uIssuerID)) // Current is not receiving own IOUs. { // Need to ripple through uIssuerID's account. terResult = pushNode( STPathElement::typeAccount, - uIssuerID, // Intermediate account is the needed issuer. + uIssuerID, // Intermediate account is the needed issuer. uCurrencyID, uIssuerID); } @@ -3046,12 +3172,16 @@ TER PathState::pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssue // Append a node and insert before it any implied nodes. // <-- terResult: tesSUCCESS, temBAD_PATH, terNO_LINE -TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID) +TER PathState::pushNode( + const int iType, + const uint160& uAccountID, + const uint160& uCurrencyID, + const uint160& uIssuerID) { Log(lsINFO) << "pushNode> " << NewcoinAddress::createHumanAccountID(uAccountID) << " " << STAmount::createHumanCurrency(uCurrencyID) - << " " << NewcoinAddress::createHumanAccountID(uIssuerID); + << "/" << NewcoinAddress::createHumanAccountID(uIssuerID); PaymentNode pnCur; const bool bFirst = vpnNodes.empty(); const PaymentNode& pnPrv = bFirst ? PaymentNode() : vpnNodes.back(); @@ -3110,6 +3240,8 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint << STAmount::createHumanCurrency(pnPrv.uCurrencyID) << "." ; + Log(lsINFO) << getJson(); + terResult = terNO_LINE; } else @@ -3140,32 +3272,14 @@ TER PathState::pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint { // Previous is an account. - // Insert intermediary account if needed. + // Insert intermediary issuer account if needed. terResult = pushImply( - !!pnPrv.uCurrencyID ? ACCOUNT_ONE : ACCOUNT_XNS, + !!pnPrv.uCurrencyID + ? ACCOUNT_ONE // Rippling, but offer's don't have an account. + : ACCOUNT_XNS, pnPrv.uCurrencyID, pnPrv.uIssuerID); } - else - { - // Previous is an offer. - // XXX Need code if we don't do offer to offer. - nothing(); - } - - if (tesSUCCESS == terResult) - { - // Verify that previous is an account. - const PaymentNode& pnBck = vpnNodes.back(); - bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); - - if (bBckAccount) - { - Log(lsINFO) << "pushNode: previous must be account."; - - terResult = temBAD_PATH; - } - } if (tesSUCCESS == terResult) { @@ -3345,7 +3459,7 @@ TER TransactionEngine::calcNodeFwd(const unsigned int uIndex, const PathState::p ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); - if (tesSUCCESS == terResult && uIndex != pspCur->vpnNodes.size()) + if (tesSUCCESS == terResult && uIndex + 1 != pspCur->vpnNodes.size()) { terResult = calcNodeFwd(uIndex+1, pspCur, bMultiQuality); } @@ -3370,14 +3484,17 @@ TER TransactionEngine::calcNodeRev(const unsigned int uIndex, const PathState::p const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); TER terResult; - Log(lsINFO) << boost::str(boost::format("calcNodeRev> uIndex=%d") % uIndex); - // Do current node reverse. const uint160& uCurIssuerID = pnCur.uIssuerID; STAmount& saTransferRate = pnCur.saTransferRate; saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID)); + Log(lsINFO) << boost::str(boost::format("calcNodeRev> uIndex=%d uIssuerID=%s saTransferRate=%s") + % uIndex + % NewcoinAddress::createHumanAccountID(uCurIssuerID) + % saTransferRate.getFullText()); + terResult = bCurAccount ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index cb913dd44f..8d981253e6 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -200,8 +200,8 @@ class PathState protected: Ledger::pointer mLedger; - TER pushNode(int iType, uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID); - TER pushImply(uint160 uAccountID, uint160 uCurrencyID, uint160 uIssuerID); + 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 pointer; From dbbd03cad1e3f6b782ac575e973c76b311bc89ee Mon Sep 17 00:00:00 2001 From: jed Date: Fri, 7 Sep 2012 07:18:47 -0700 Subject: [PATCH 212/426] . --- src/Interpreter.cpp | 23 +++++++++++++++++++++++ src/Interpreter.h | 20 ++++++++++++++------ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp index 0b370683f9..1e3c4edc86 100644 --- a/src/Interpreter.cpp +++ b/src/Interpreter.cpp @@ -238,10 +238,28 @@ Interpreter::Interpreter() mFunctionTable[INT_OP]=new IntOp(); mFunctionTable[FLOAT_OP]=new FloatOp(); mFunctionTable[UINT160_OP]=new Uint160Op(); + mFunctionTable[BOOL_OP]=new Uint160Op(); mFunctionTable[ADD_OP]=new AddOp(); mFunctionTable[SUB_OP]=new SubOp(); + /*PATH_OP, + ADD_OP,SUB_OP,MUL_OP,DIV_OP,MOD_OP, + GTR_OP,LESS_OP,EQUAL_OP,NOT_EQUAL_OP, + AND_OP,OR_OP,NOT_OP, + JUMP_OP, JUMPIF_OP, + STOP_OP, CANCEL_OP, + + BLOCK_OP, BLOCK_END_OP, + SEND_XNS_OP,SEND_OP,REMOVE_CONTRACT_OP,FEE_OP,CHANGE_CONTRACT_OWNER_OP, + STOP_REMOVE_OP, + SET_DATA_OP,GET_DATA_OP, GET_NUM_DATA_OP, + SET_REGISTER_OP,GET_REGISTER_OP, + GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, GET_LEDGER_NUM_OP, GET_RAND_FLOAT_OP, + GET_XNS_ESCROWED_OP, GET_RIPPLE_ESCROWED_OP, GET_RIPPLE_ESCROWED_CURRENCY_OP, GET_RIPPLE_ESCROWED_ISSUER, + GET_ACCEPT_DATA_OP, GET_ACCEPTOR_ID_OP, GET_CONTRACT_ID_OP, + */ + } Data::pointer Interpreter::popStack() @@ -361,6 +379,11 @@ Data::pointer Interpreter::getContractData(int index) return(Data::pointer(new ErrorData())); } +bool Interpreter::canSign(uint160& signer) +{ + return(true); +} + diff --git a/src/Interpreter.h b/src/Interpreter.h index 5375c1b690..d09f6d2200 100644 --- a/src/Interpreter.h +++ b/src/Interpreter.h @@ -40,16 +40,24 @@ class Interpreter bool mBlockSuccess; public: + + enum { INT_OP,FLOAT_OP,UINT160_OP,BOOL_OP,PATH_OP, ADD_OP,SUB_OP,MUL_OP,DIV_OP,MOD_OP, GTR_OP,LESS_OP,EQUAL_OP,NOT_EQUAL_OP, AND_OP,OR_OP,NOT_OP, - BLOCK_OP, BLOCK_END_OP, JUMP_OP, JUMPIF_OP, - STOP_OP, - SET_DATA_OP,GET_DATA_OP, GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, - ACCEPT_DATA_OP, - SEND_XNS_OP, NUM_OF_OPS }; + STOP_OP, CANCEL_OP, + + BLOCK_OP, BLOCK_END_OP, + SEND_XNS_OP,SEND_OP,REMOVE_CONTRACT_OP,FEE_OP,CHANGE_CONTRACT_OWNER_OP, + STOP_REMOVE_OP, + SET_DATA_OP,GET_DATA_OP, GET_NUM_DATA_OP, + SET_REGISTER_OP,GET_REGISTER_OP, + GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, GET_LEDGER_NUM_OP, GET_RAND_FLOAT_OP, + GET_XNS_ESCROWED_OP, GET_RIPPLE_ESCROWED_OP, GET_RIPPLE_ESCROWED_CURRENCY_OP, GET_RIPPLE_ESCROWED_ISSUER, + GET_ACCEPT_DATA_OP, GET_ACCEPTOR_ID_OP, GET_CONTRACT_ID_OP, + NUM_OF_OPS }; Interpreter(); @@ -58,7 +66,7 @@ public: void stop(); - bool canSign(const uint160& signer); + bool canSign(uint160& signer); int getInstructionPointer(){ return(mInstructionPointer); } void setInstructionPointer(int n){ mInstructionPointer=n;} From 19c69cbb8264e7f81ba64f06c9707be77f8ef76f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 7 Sep 2012 10:46:58 -0700 Subject: [PATCH 213/426] Cosmetic. --- src/LedgerTiming.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index b19ee994bd..9ce760fc4d 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -27,7 +27,7 @@ bool ContinuousLedgerTiming::shouldClose( boost::str(boost::format("CLC::shouldClose range Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") % (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentMSeconds % previousMSeconds); - return true;; + return true; } if (!anyTransactions) From e5573950727a30cdc25c0a0f3f7af838203ccdb2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 7 Sep 2012 10:47:15 -0700 Subject: [PATCH 214/426] Fix the bug causing ledgers to close immediately even without transactions. Fix a bug that could cause the network to proceed without a consensus. --- src/LedgerConsensus.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index ebe2b08794..5130d398c5 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -491,7 +491,7 @@ void LedgerConsensus::statePreClose() } else { - sinceClose = theApp->getOPs().getLastCloseTime(); + sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - theApp->getOPs().getLastCloseTime()); idleInterval = LEDGER_IDLE_INTERVAL; } @@ -517,7 +517,7 @@ void LedgerConsensus::stateEstablish() if (haveConsensus()) Log(lsINFO) << "We have TX consensus but not CT consensus"; } - if (haveConsensus()) + else if (haveConsensus()) { Log(lsINFO) << "Converge cutoff (" << mPeerPositions.size() << " participants)"; mState = lcsFINISHED; @@ -638,7 +638,7 @@ void LedgerConsensus::updateOurPositions() for (std::map::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it) { - Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << " out of " << thresh; + Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << ", " << thresh << " required"; if (it->second > thresh) { Log(lsINFO) << "Close time consensus reached: " << it->first; From adf4ff998becf6b74fe8738761fb00315893d362 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 7 Sep 2012 11:23:06 -0700 Subject: [PATCH 215/426] Make it less likely that a node will get temporarily stuck in a stale consensus process. --- src/LedgerConsensus.cpp | 28 ++++++++++++++++++++++++++-- src/LedgerConsensus.h | 3 +++ src/LedgerProposal.cpp | 16 ++++++++++++++-- src/LedgerProposal.h | 2 ++ 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 5130d398c5..6500a1ff37 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -321,12 +321,19 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) BOOST_FOREACH(Peer::ref peer, peerList) mAcquiringLedger->peerHas(peer); } + if (mHaveCorrectLCL && mProposing) + { + Log(lsINFO) << "Bowing out of consensus"; + mOurPosition->bowOut(); + propose(); + } mHaveCorrectLCL = false; mProposing = false; mValidating = false; mCloseTimes.clear(); mPeerPositions.clear(); mDisputes.clear(); + mDeadNodes.clear(); return; } @@ -794,11 +801,18 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) { - LedgerProposal::pointer& currentPosition = mPeerPositions[newPosition->getPeerID()]; + uint160 peerID = newPosition->getPeerID(); + if (mDeadNodes.find(peerID) != mDeadNodes.end()) + { + Log(lsINFO) << "Position from dead node"; + return false; + } + + LedgerProposal::pointer& currentPosition = mPeerPositions[peerID]; if (currentPosition) { - assert(newPosition->getPeerID() == currentPosition->getPeerID()); + assert(peerID == currentPosition->getPeerID()); if (newPosition->getProposeSeq() <= currentPosition->getProposeSeq()) return false; } @@ -808,9 +822,19 @@ bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) Log(lsTRACE) << "Peer reports close time as " << newPosition->getCloseTime(); ++mCloseTimes[newPosition->getCloseTime()]; } + else if (newPosition->getProposeSeq() == LedgerProposal::seqLeave) + { + BOOST_FOREACH(u256_lct_pair& it, mDisputes) + it.second->unVote(peerID); + mPeerPositions.erase(peerID); + mDeadNodes.insert(peerID); + return true; + } + Log(lsINFO) << "Processing peer proposal " << newPosition->getProposeSeq() << "/" << newPosition->getCurrentHash(); currentPosition = newPosition; + SHAMap::pointer set = getTransactionTree(newPosition->getCurrentHash(), true); if (set) { diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 4e1db172dd..17aa02691d 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -115,6 +115,9 @@ protected: // deferred proposals (node ID -> proposals from that peer) boost::unordered_map< uint160, std::list > mDeferredProposals; + // nodes that have bowed out of this consensus process + boost::unordered_set mDeadNodes; + // final accept logic static void Saccept(boost::shared_ptr This, SHAMap::pointer txSet); void accept(const SHAMap::pointer& txSet); diff --git a/src/LedgerProposal.cpp b/src/LedgerProposal.cpp index d96b397434..5840c10372 100644 --- a/src/LedgerProposal.cpp +++ b/src/LedgerProposal.cpp @@ -62,6 +62,13 @@ void LedgerProposal::changePosition(const uint256& newPosition, uint32 closeTime ++mProposeSeq; } +void LedgerProposal::bowOut() +{ + mCurrentHash = uint256(); + mTime = boost::posix_time::second_clock::universal_time(); + mProposeSeq = seqLeave; +} + std::vector LedgerProposal::sign(void) { std::vector ret; @@ -78,9 +85,14 @@ Json::Value LedgerProposal::getJson() const { Json::Value ret = Json::objectValue; ret["previous_ledger"] = mPreviousLedger.GetHex(); - ret["transaction_hash"] = mCurrentHash.GetHex(); + + if (mProposeSeq != seqLeave) + { + ret["transaction_hash"] = mCurrentHash.GetHex(); + ret["propose_seq"] = mProposeSeq; + } + ret["close_time"] = mCloseTime; - ret["propose_seq"] = mProposeSeq; if (mPublicKey.isValid()) ret["peer_id"] = mPublicKey.humanNodePublic(); diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index 74d0f7c071..adaa557719 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -26,6 +26,7 @@ protected: boost::posix_time::ptime mTime; public: + static const uint32 seqLeave = 0xffffffff; // leaving the consensus process typedef boost::shared_ptr pointer; @@ -63,6 +64,7 @@ public: bool isStale(boost::posix_time::ptime cutoff) { return mTime <= cutoff; } void changePosition(const uint256& newPosition, uint32 newCloseTime); + void bowOut(); Json::Value getJson() const; }; From 9f6118b7955f355c384009a1421f931c0dd5a9d6 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 7 Sep 2012 11:25:20 -0700 Subject: [PATCH 216/426] Tiny cleanup --- src/LedgerConsensus.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 6500a1ff37..8ecccdcd87 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -839,7 +839,7 @@ bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) if (set) { BOOST_FOREACH(u256_lct_pair& it, mDisputes) - it.second->setVote(newPosition->getPeerID(), set->hasItem(it.first)); + it.second->setVote(peerID, set->hasItem(it.first)); } else Log(lsTRACE) << "Don't have that tx set"; From e12a6a7fc56d9d29f854587d31a465f47ee6eeca Mon Sep 17 00:00:00 2001 From: jed Date: Fri, 7 Sep 2012 14:04:02 -0700 Subject: [PATCH 217/426] changed contract --- newcoin.vcxproj | 2 + newcoin.vcxproj.filters | 6 + src/Interpreter.cpp | 276 +++++++--------------------------------- src/Interpreter.h | 15 +-- src/LedgerFormats.cpp | 32 ++--- 5 files changed, 70 insertions(+), 261 deletions(-) diff --git a/newcoin.vcxproj b/newcoin.vcxproj index 6f7548d105..0f21cebefa 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -124,6 +124,7 @@ + @@ -216,6 +217,7 @@ + diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index fcf37fc266..f569d1ac42 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -291,6 +291,9 @@ Source Files + + Source Files + @@ -542,6 +545,9 @@ Header Files + + Header Files + diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp index 1e3c4edc86..3c539cf307 100644 --- a/src/Interpreter.cpp +++ b/src/Interpreter.cpp @@ -1,4 +1,5 @@ #include "Interpreter.h" +#include "Operation.h" #include "Config.h" /* @@ -8,220 +9,6 @@ We also need to charge for each op namespace Script { - -////////////////////////////////////////////////////////////////////////// -/// Operations - -int Operation::getFee() -{ - return(theConfig.FEE_CONTRACT_OPERATION); -} - -// this is just an Int in the code -class IntOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - Data::pointer data=interpreter->getIntData(); - if(data->isInt32()) - { - interpreter->pushStack( data ); - return(true); - } - return(false); - } -}; - -class FloatOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - Data::pointer data=interpreter->getFloatData(); - if(data->isFloat()) - { - interpreter->pushStack( data ); - return(true); - } - return(false); - } -}; - -class Uint160Op : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - Data::pointer data=interpreter->getUint160Data(); - if(data->isUint160()) - { - interpreter->pushStack( data ); - return(true); - } - return(false); - } -}; - -class AddOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - Data::pointer data1=interpreter->popStack(); - Data::pointer data2=interpreter->popStack(); - if( (data1->isInt32() || data1->isFloat()) && - (data2->isInt32() || data2->isFloat()) ) - { - if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()+data2->getFloat()))); - else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()+data2->getInt()))); - return(true); - }else - { - return(false); - } - } -}; - -class SubOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - Data::pointer data1=interpreter->popStack(); - Data::pointer data2=interpreter->popStack(); - if( (data1->isInt32() || data1->isFloat()) && - (data2->isInt32() || data2->isFloat()) ) - { - if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()-data2->getFloat()))); - else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()-data2->getInt()))); - return(true); - }else - { - return(false); - } - } -}; - - -class StartBlockOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - Data::pointer offset=interpreter->getIntData(); - return(interpreter->startBlock(offset->getInt())); - } -}; - -class EndBlockOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - return(interpreter->endBlock()); - } -}; - -class StopOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - interpreter->stop(); - return(true); - } -}; - -class AcceptDataOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - Data::pointer data=interpreter->popStack(); - if(data->isInt32()) - { - interpreter->pushStack( interpreter->getAcceptData(data->getInt()) ); - return(true); - } - return(false); - } -}; - -class JumpIfOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - Data::pointer offset=interpreter->getIntData(); - Data::pointer cond=interpreter->popStack(); - if(cond->isBool() && offset->isInt32()) - { - if(cond->isTrue()) - { - return(interpreter->jumpTo(offset->getInt())); - } - return(true); - } - return(false); - } -}; - -class JumpOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - Data::pointer offset=interpreter->getIntData(); - if(offset->isInt32()) - { - return(interpreter->jumpTo(offset->getInt())); - } - return(false); - } -}; - -class SendXNSOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - Data::pointer sourceID=interpreter->popStack(); - Data::pointer destID=interpreter->popStack(); - Data::pointer amount=interpreter->popStack(); - if(sourceID->isUint160() && destID->isUint160() && amount->isInt32() && interpreter->canSign(sourceID->getUint160())) - { - // make sure: - // source is either, this contract, issuer, or acceptor - - // TODO do the send - //interpreter->pushStack( send result); - - return(true); - } - - return(false); - } -}; - -class GetDataOp : public Operation -{ -public: - bool work(Interpreter* interpreter) - { - Data::pointer index=interpreter->popStack(); - if(index->isInt32()) - { - interpreter->pushStack( interpreter->getContractData(index->getInt())); - return(true); - } - - return(false); - } -}; - -////////////////////////////////////////////////////////////////////////// - Interpreter::Interpreter() { mContract=NULL; @@ -234,32 +21,55 @@ Interpreter::Interpreter() mBlockJump=0; mFunctionTable.resize(NUM_OF_OPS); - + /* mFunctionTable[INT_OP]=new IntOp(); mFunctionTable[FLOAT_OP]=new FloatOp(); mFunctionTable[UINT160_OP]=new Uint160Op(); mFunctionTable[BOOL_OP]=new Uint160Op(); + mFunctionTable[PATH_OP]=new Uint160Op(); mFunctionTable[ADD_OP]=new AddOp(); mFunctionTable[SUB_OP]=new SubOp(); - - /*PATH_OP, - ADD_OP,SUB_OP,MUL_OP,DIV_OP,MOD_OP, - GTR_OP,LESS_OP,EQUAL_OP,NOT_EQUAL_OP, - AND_OP,OR_OP,NOT_OP, - JUMP_OP, JUMPIF_OP, - STOP_OP, CANCEL_OP, - - BLOCK_OP, BLOCK_END_OP, - SEND_XNS_OP,SEND_OP,REMOVE_CONTRACT_OP,FEE_OP,CHANGE_CONTRACT_OWNER_OP, - STOP_REMOVE_OP, - SET_DATA_OP,GET_DATA_OP, GET_NUM_DATA_OP, - SET_REGISTER_OP,GET_REGISTER_OP, - GET_ISSUER_ID_OP, GET_OWNER_ID_OP, GET_LEDGER_TIME_OP, GET_LEDGER_NUM_OP, GET_RAND_FLOAT_OP, - GET_XNS_ESCROWED_OP, GET_RIPPLE_ESCROWED_OP, GET_RIPPLE_ESCROWED_CURRENCY_OP, GET_RIPPLE_ESCROWED_ISSUER, - GET_ACCEPT_DATA_OP, GET_ACCEPTOR_ID_OP, GET_CONTRACT_ID_OP, - */ - + mFunctionTable[MUL_OP]=new MulOp(); + mFunctionTable[DIV_OP]=new DivOp(); + mFunctionTable[MOD_OP]=new ModOp(); + mFunctionTable[GTR_OP]=new GtrOp(); + mFunctionTable[LESS_OP]=new LessOp(); + mFunctionTable[EQUAL_OP]=new SubOp(); + mFunctionTable[NOT_EQUAL_OP]=new SubOp(); + mFunctionTable[AND_OP]=new SubOp(); + mFunctionTable[OR_OP]=new SubOp(); + mFunctionTable[NOT_OP]=new SubOp(); + mFunctionTable[JUMP_OP]=new SubOp(); + mFunctionTable[JUMPIF_OP]=new SubOp(); + mFunctionTable[STOP_OP]=new SubOp(); + mFunctionTable[CANCEL_OP]=new SubOp(); + mFunctionTable[BLOCK_OP]=new SubOp(); + mFunctionTable[BLOCK_END_OP]=new SubOp(); + mFunctionTable[SEND_XNS_OP]=new SendXNSOp(); + mFunctionTable[SEND_OP]=new SendOp(); + mFunctionTable[REMOVE_CONTRACT_OP]=new SubOp(); + mFunctionTable[FEE_OP]=new SubOp(); + mFunctionTable[CHANGE_CONTRACT_OWNER_OP]=new SubOp(); + mFunctionTable[STOP_REMOVE_OP]=new SubOp(); + mFunctionTable[SET_DATA_OP]=new SubOp(); + mFunctionTable[GET_DATA_OP]=new SubOp(); + mFunctionTable[GET_NUM_DATA_OP]=new SubOp(); + mFunctionTable[SET_REGISTER_OP]=new SubOp(); + mFunctionTable[GET_REGISTER_OP]=new SubOp(); + mFunctionTable[GET_ISSUER_ID_OP]=new SubOp(); + mFunctionTable[GET_OWNER_ID_OP]=new SubOp(); + mFunctionTable[GET_LEDGER_TIME_OP]=new SubOp(); + mFunctionTable[GET_LEDGER_NUM_OP]=new SubOp(); + mFunctionTable[GET_RAND_FLOAT_OP]=new SubOp(); + mFunctionTable[GET_XNS_ESCROWED_OP]=new SubOp(); + mFunctionTable[GET_RIPPLE_ESCROWED_OP]=new SubOp(); + mFunctionTable[GET_RIPPLE_ESCROWED_CURRENCY_OP]=new SubOp(); + mFunctionTable[GET_RIPPLE_ESCROWED_ISSUER]=new GetRippleEscrowedIssuerOp(); + mFunctionTable[GET_ACCEPT_DATA_OP]=new AcceptDataOp(); + mFunctionTable[GET_ACCEPTOR_ID_OP]=new GetAcceptorIDOp(); + mFunctionTable[GET_CONTRACT_ID_OP]=new GetContractIDOp(); + */ } Data::pointer Interpreter::popStack() diff --git a/src/Interpreter.h b/src/Interpreter.h index d09f6d2200..7a0c1d825a 100644 --- a/src/Interpreter.h +++ b/src/Interpreter.h @@ -10,20 +10,9 @@ namespace Script { -class Interpreter; - +class Operation; // Contracts are non typed have variable data types - -class Operation -{ -public: - // returns false if there was an error - virtual bool work(Interpreter* interpreter)=0; - - virtual int getFee(); -}; - class Interpreter { std::vector mFunctionTable; @@ -42,7 +31,7 @@ class Interpreter public: - enum { INT_OP,FLOAT_OP,UINT160_OP,BOOL_OP,PATH_OP, + enum { INT_OP=1,FLOAT_OP,UINT160_OP,BOOL_OP,PATH_OP, ADD_OP,SUB_OP,MUL_OP,DIV_OP,MOD_OP, GTR_OP,LESS_OP,EQUAL_OP,NOT_EQUAL_OP, AND_OP,OR_OP,NOT_OP, diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index e1376ea3af..79744a79e9 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -25,6 +25,23 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, + { "Contract", ltCONTRACT, { + { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, + { S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, + { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(Issuer), STI_ACCOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(Owner), STI_ACCOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(Expiration), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(BondAmount), STI_UINT32, SOE_REQUIRED, 0 }, + { S_FIELD(CreateCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, + { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + }, { "DirectoryNode", ltDIR_NODE, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Indexes), STI_VECTOR256, SOE_REQUIRED, 0 }, @@ -77,21 +94,6 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, - { "Contract", ltCONTRACT, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Issuer), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Owner), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Expiration), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(BondAmount), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(StampEscrow), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(RippleEscrow), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(CreateCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, { NULL, ltINVALID } }; From e0cfa2e12d440f9e0028b72e86c33093af152027 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 7 Sep 2012 14:08:25 -0700 Subject: [PATCH 218/426] Remove obsolete ledeger fields. --- src/LedgerFormats.cpp | 2 -- src/SerializedObject.h | 2 -- src/TransactionEngine.cpp | 9 +++------ 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index e1376ea3af..811f98106e 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -10,8 +10,6 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(LastReceive), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(LastSignedSeq), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_IFFLAG, 1 }, diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 3e36c07c9f..c8245d6d9d 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -68,8 +68,6 @@ enum SOE_Field sfInvoiceID, sfIssuer, sfLastNode, - sfLastReceive, - sfLastSignedSeq, sfLastTxnID, sfLastTxnSeq, sfLedgerHash, diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 455e618f8d..2b690bb422 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1,7 +1,5 @@ // // XXX Should make sure all fields and are recognized on a transactions. -// XXX Make sure fee is claimed for failed transactions. -// XXX Might uses an unordered set for vector. // #include "TransactionEngine.h" @@ -1276,7 +1274,6 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, if (tesSUCCESS == terResult) { - mTxnAccount->setIFieldU32(sfLastSignedSeq, mLedger->getLedgerSeq()); entryModify(mTxnAccount); switch (txn.getTxnType()) @@ -2572,15 +2569,15 @@ TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathS const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; // For bPrvAccount - const STAmount saPrvOwed = uIndex && bPrvAccount // Previous account is owed. + const STAmount saPrvOwed = bPrvAccount && uIndex // Previous account is owed. ? rippleOwed(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID, uCurAccountID); - const STAmount saPrvLimit = uIndex && bPrvAccount // Previous account may owe. + const STAmount saPrvLimit = bPrvAccount && uIndex // Previous account may owe. ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) : STAmount(uCurrencyID, uCurAccountID); - const STAmount saNxtOwed = uIndex != uLast && bNxtAccount // Next account is owed. + const STAmount saNxtOwed = bNxtAccount && uIndex != uLast // Next account is owed. ? rippleOwed(uCurAccountID, uNxtAccountID, uCurrencyID) : STAmount(uCurrencyID, uCurAccountID); From 8ffb303ab7c220c12639df28dfa0b79c7a397617 Mon Sep 17 00:00:00 2001 From: jed Date: Fri, 7 Sep 2012 14:23:01 -0700 Subject: [PATCH 219/426] missing files --- src/Operation.cpp | 17 ++++ src/Operation.h | 220 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 src/Operation.cpp create mode 100644 src/Operation.h diff --git a/src/Operation.cpp b/src/Operation.cpp new file mode 100644 index 0000000000..b0661f57a2 --- /dev/null +++ b/src/Operation.cpp @@ -0,0 +1,17 @@ +#include "Operation.h" +#include "Config.h" + +/* +We also need to charge for each op + +*/ + +namespace Script { + + +int Operation::getFee() +{ + return(theConfig.FEE_CONTRACT_OPERATION); +} + +} \ No newline at end of file diff --git a/src/Operation.h b/src/Operation.h new file mode 100644 index 0000000000..9fca2498c4 --- /dev/null +++ b/src/Operation.h @@ -0,0 +1,220 @@ +#include "Interpreter.h" + +namespace Script { + +// Contracts are non typed have variable data types + + +class Operation +{ +public: + // returns false if there was an error + virtual bool work(Interpreter* interpreter)=0; + + virtual int getFee(); +}; + +// this is just an Int in the code +class IntOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->getIntData(); + if(data->isInt32()) + { + interpreter->pushStack( data ); + return(true); + } + return(false); + } +}; + +class FloatOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->getFloatData(); + if(data->isFloat()) + { + interpreter->pushStack( data ); + return(true); + } + return(false); + } +}; + +class Uint160Op : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->getUint160Data(); + if(data->isUint160()) + { + interpreter->pushStack( data ); + return(true); + } + return(false); + } +}; + +class AddOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data1=interpreter->popStack(); + Data::pointer data2=interpreter->popStack(); + if( (data1->isInt32() || data1->isFloat()) && + (data2->isInt32() || data2->isFloat()) ) + { + if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()+data2->getFloat()))); + else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()+data2->getInt()))); + return(true); + }else + { + return(false); + } + } +}; + +class SubOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data1=interpreter->popStack(); + Data::pointer data2=interpreter->popStack(); + if( (data1->isInt32() || data1->isFloat()) && + (data2->isInt32() || data2->isFloat()) ) + { + if(data1->isFloat() || data2->isFloat()) interpreter->pushStack(Data::pointer(new FloatData(data1->getFloat()-data2->getFloat()))); + else interpreter->pushStack(Data::pointer(new IntData(data1->getInt()-data2->getInt()))); + return(true); + }else + { + return(false); + } + } +}; + + +class StartBlockOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer offset=interpreter->getIntData(); + return(interpreter->startBlock(offset->getInt())); + } +}; + +class EndBlockOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + return(interpreter->endBlock()); + } +}; + +class StopOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + interpreter->stop(); + return(true); + } +}; + +class AcceptDataOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer data=interpreter->popStack(); + if(data->isInt32()) + { + interpreter->pushStack( interpreter->getAcceptData(data->getInt()) ); + return(true); + } + return(false); + } +}; + +class JumpIfOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer offset=interpreter->getIntData(); + Data::pointer cond=interpreter->popStack(); + if(cond->isBool() && offset->isInt32()) + { + if(cond->isTrue()) + { + return(interpreter->jumpTo(offset->getInt())); + } + return(true); + } + return(false); + } +}; + +class JumpOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer offset=interpreter->getIntData(); + if(offset->isInt32()) + { + return(interpreter->jumpTo(offset->getInt())); + } + return(false); + } +}; + +class SendXNSOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer sourceID=interpreter->popStack(); + Data::pointer destID=interpreter->popStack(); + Data::pointer amount=interpreter->popStack(); + if(sourceID->isUint160() && destID->isUint160() && amount->isInt32() && interpreter->canSign(sourceID->getUint160())) + { + // make sure: + // source is either, this contract, issuer, or acceptor + + // TODO do the send + //interpreter->pushStack( send result); + + return(true); + } + + return(false); + } +}; + +class GetDataOp : public Operation +{ +public: + bool work(Interpreter* interpreter) + { + Data::pointer index=interpreter->popStack(); + if(index->isInt32()) + { + interpreter->pushStack( interpreter->getContractData(index->getInt())); + return(true); + } + + return(false); + } +}; + +} \ No newline at end of file From 43a3bcc155487e775b97a431687301a9f1dba89c Mon Sep 17 00:00:00 2001 From: jed Date: Fri, 7 Sep 2012 14:33:13 -0700 Subject: [PATCH 220/426] . --- src/Interpreter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Interpreter.h b/src/Interpreter.h index 7a0c1d825a..ad7d2cb855 100644 --- a/src/Interpreter.h +++ b/src/Interpreter.h @@ -55,7 +55,7 @@ public: void stop(); - bool canSign(uint160& signer); + bool canSign(const uint160& signer); int getInstructionPointer(){ return(mInstructionPointer); } void setInstructionPointer(int n){ mInstructionPointer=n;} From 90fb09340240029f7cac7abd58322c842f1e12c0 Mon Sep 17 00:00:00 2001 From: jed Date: Fri, 7 Sep 2012 14:33:56 -0700 Subject: [PATCH 221/426] . --- src/Interpreter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Interpreter.cpp b/src/Interpreter.cpp index 3c539cf307..c97b8780c9 100644 --- a/src/Interpreter.cpp +++ b/src/Interpreter.cpp @@ -189,7 +189,7 @@ Data::pointer Interpreter::getContractData(int index) return(Data::pointer(new ErrorData())); } -bool Interpreter::canSign(uint160& signer) +bool Interpreter::canSign(const uint160& signer) { return(true); } From a3ddb9b146169b5dae57241eacd6313569718861 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 7 Sep 2012 14:40:16 -0700 Subject: [PATCH 222/426] Remove unused variables. --- src/TransactionEngine.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 2b690bb422..1239776425 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -3956,9 +3956,7 @@ TER TransactionEngine::takeOffers( const uint256 uBookEnd = Ledger::getQualityNext(uBookBase); const uint64 uTakeQuality = STAmount::getRate(saTakerGets, saTakerPays); const uint160 uTakerPaysAccountID = saTakerPays.getIssuer(); - const uint160 uTakerPaysCurrency = saTakerPays.getCurrency(); const uint160 uTakerGetsAccountID = saTakerGets.getIssuer(); - const uint160 uTakerGetsCurrency = saTakerGets.getCurrency(); TER terResult = temUNCERTAIN; boost::unordered_set usOfferUnfundedFound; // Offers found unfunded. From 390e628f102e4ac0c09e490b7f23cdf283fba47f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 7 Sep 2012 15:06:25 -0700 Subject: [PATCH 223/426] Cmall cleanups and fixes. --- src/HashedObject.cpp | 6 ++---- src/Ledger.cpp | 2 +- src/LedgerConsensus.cpp | 8 +++----- src/SNTPClient.h | 4 +++- src/SerializedTypes.h | 5 ++++- src/TaggedCache.h | 2 +- src/TransactionEngine.cpp | 1 - src/TransactionEngine.h | 1 - 8 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp index f5717e879a..56f26e3d60 100644 --- a/src/HashedObject.cpp +++ b/src/HashedObject.cpp @@ -104,8 +104,6 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash) sql.append(hash.GetHex()); sql.append("';"); - std::string type; - uint32 index; std::vector data; { ScopedLock sl(theApp->getHashNodeDB()->getDBLock()); @@ -121,7 +119,7 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash) db->getStr("ObjType", type); if (type.size() == 0) return HashedObject::pointer(); - index = db->getBigInt("LedgerIndex"); + uint32 index = db->getBigInt("LedgerIndex"); int size = db->getBinary("Object", NULL, 0); data.resize(size); @@ -131,7 +129,7 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash) assert(Serializer::getSHA512Half(data) == hash); HashedObjectType htype = UNKNOWN; - switch(type[0]) + switch (type[0]) { case 'L': htype = LEDGER; break; case 'T': htype = TRANSACTION; break; diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 08fd23cd7a..0e558747c0 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -154,7 +154,7 @@ void Ledger::setAccepted(uint32 closeTime, int closeResolution, bool correctClos void Ledger::setAccepted() { // used when we acquired the ledger - assert(mClosed && (mCloseResolution != 0) && (mCloseResolution != 0)); + assert(mClosed && (mCloseTime != 0) && (mCloseResolution != 0)); mCloseTime -= mCloseTime % mCloseResolution; updateHash(); mAccepted = true; diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 8ecccdcd87..4fc94ad785 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -209,12 +209,10 @@ bool LCTransaction::updatePosition(int percentTime, bool proposing) } LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::ref previousLedger, uint32 closeTime) - : mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), - mPreviousLedger(previousLedger), mCurrentMSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false) + : mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger), + mValSeed(theConfig.VALIDATION_SEED), mCurrentMSeconds(0), mClosePercent(0), mHaveCloseTimeConsensus(false), + mConsensusStartTime(boost::posix_time::microsec_clock::universal_time()) { - mValSeed = theConfig.VALIDATION_SEED; - mConsensusStartTime = boost::posix_time::microsec_clock::universal_time(); - Log(lsDEBUG) << "Creating consensus object"; Log(lsTRACE) << "LCL:" << previousLedger->getHash() <<", ct=" << closeTime; mPreviousProposers = theApp->getOPs().getPreviousProposers(); diff --git a/src/SNTPClient.h b/src/SNTPClient.h index c2bf75ec63..ea01bcf7aa 100644 --- a/src/SNTPClient.h +++ b/src/SNTPClient.h @@ -9,12 +9,14 @@ #include #include +#include "types.h" + class SNTPQuery { public: bool mReceivedReply; time_t mLocalTimeSent; - int mQueryNonce; + uint32 mQueryNonce; SNTPQuery(time_t j = (time_t) -1) : mReceivedReply(false), mLocalTimeSent(j) { ; } }; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 98461f5444..17e79af3c1 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -582,7 +582,10 @@ public: const uint160& getIssuerID() const { return mIssuerID; } bool operator==(const STPathElement& t) const - { return mType == t.mType && mAccountID == t.mAccountID && mCurrencyID == t.mCurrencyID && mIssuerID == mIssuerID; } + { + return mType == t.mType && mAccountID == t.mAccountID && mCurrencyID == t.mCurrencyID && + mIssuerID == t.mIssuerID; + } }; class STPath diff --git a/src/TaggedCache.h b/src/TaggedCache.h index 92a122d017..fb31a157b5 100644 --- a/src/TaggedCache.h +++ b/src/TaggedCache.h @@ -111,7 +111,7 @@ template void TaggedCache::sweep if (mit->second->expired()) { typename boost::unordered_map::iterator tmp = mit++; - mMap.erase(mit); + mMap.erase(mit++); } else ++mit; diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 2b690bb422..ebb97d517d 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -961,7 +961,6 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, { Log(lsTRACE) << "applyTransaction>"; assert(mLedger); - mLedgerParentCloseTime = mLedger->getParentCloseTimeNC(); mNodes.init(txn.getTransactionID(), mLedger->getLedgerSeq()); #ifdef DEBUG diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 1f4d493d5e..7f7d653cca 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -295,7 +295,6 @@ private: protected: Ledger::pointer mLedger; - uint64 mLedgerParentCloseTime; uint160 mTxnAccountID; SLE::pointer mTxnAccount; From cbc758db6427f6af8ea83db91b77ef63e4f84e5d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 7 Sep 2012 15:25:47 -0700 Subject: [PATCH 224/426] Fix crash --- src/LedgerConsensus.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 4fc94ad785..bdba1c7da4 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -319,7 +319,7 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) BOOST_FOREACH(Peer::ref peer, peerList) mAcquiringLedger->peerHas(peer); } - if (mHaveCorrectLCL && mProposing) + if (mHaveCorrectLCL && mProposing && mOurPosition) { Log(lsINFO) << "Bowing out of consensus"; mOurPosition->bowOut(); From 0defc8d5abaee48a05f129fb55d9b5ada8e353ab Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 7 Sep 2012 15:50:07 -0700 Subject: [PATCH 225/426] Cleanups. --- src/UniqueNodeList.cpp | 8 ++++---- src/UniqueNodeList.h | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/UniqueNodeList.cpp b/src/UniqueNodeList.cpp index 708a4f5e94..05453b0128 100644 --- a/src/UniqueNodeList.cpp +++ b/src/UniqueNodeList.cpp @@ -779,7 +779,7 @@ int UniqueNodeList::processValidators(const std::string& strSite, const std::str } // Given a section with IPs, parse and persist it for a validator. -void UniqueNodeList::responseIps(const std::string& strSite, const NewcoinAddress& naNodePublic, const boost::system::error_code& err, const std::string strIpsFile) +void UniqueNodeList::responseIps(const std::string& strSite, const NewcoinAddress& naNodePublic, const boost::system::error_code& err, const std::string& strIpsFile) { if (!err) { @@ -819,7 +819,7 @@ void UniqueNodeList::getIpsUrl(const NewcoinAddress& naNodePublic, section secSi } // After fetching a newcoin.txt from a web site, given a section with validators, parse and persist it. -void UniqueNodeList::responseValidators(const std::string& strValidatorsUrl, const NewcoinAddress& naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, const std::string strValidatorsFile) +void UniqueNodeList::responseValidators(const std::string& strValidatorsUrl, const NewcoinAddress& naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, const std::string& strValidatorsFile) { if (!err) { @@ -858,7 +858,7 @@ void UniqueNodeList::getValidatorsUrl(const NewcoinAddress& naNodePublic, sectio } // Process a newcoin.txt. -void UniqueNodeList::processFile(const std::string strDomain, const NewcoinAddress& naNodePublic, section secSite) +void UniqueNodeList::processFile(const std::string& strDomain, const NewcoinAddress& naNodePublic, section secSite) { // // Process Validators @@ -885,7 +885,7 @@ void UniqueNodeList::processFile(const std::string strDomain, const NewcoinAddre } // Given a newcoin.txt, process it. -void UniqueNodeList::responseFetch(const std::string strDomain, const boost::system::error_code& err, const std::string strSiteFile) +void UniqueNodeList::responseFetch(const std::string& strDomain, const boost::system::error_code& err, const std::string& strSiteFile) { section secSite = ParseSection(strSiteFile, true); bool bGood = !err; diff --git a/src/UniqueNodeList.h b/src/UniqueNodeList.h index 1de853c960..667cbe92aa 100644 --- a/src/UniqueNodeList.h +++ b/src/UniqueNodeList.h @@ -95,7 +95,7 @@ private: bool scoreRound(std::vector& vsnNodes); - void responseFetch(const std::string strDomain, const boost::system::error_code& err, const std::string strSiteFile); + void responseFetch(const std::string& strDomain, const boost::system::error_code& err, const std::string& strSiteFile); boost::posix_time::ptime mtpScoreNext; // When to start scoring. boost::posix_time::ptime mtpScoreStart; // Time currently started scoring. @@ -119,13 +119,13 @@ private: void getValidatorsUrl(const NewcoinAddress& naNodePublic, section secSite); void getIpsUrl(const NewcoinAddress& naNodePublic, section secSite); - void responseIps(const std::string& strSite, const NewcoinAddress& naNodePublic, const boost::system::error_code& err, const std::string strIpsFile); - void responseValidators(const std::string& strValidatorsUrl, const NewcoinAddress& naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, const std::string strValidatorsFile); + void responseIps(const std::string& strSite, const NewcoinAddress& naNodePublic, const boost::system::error_code& err, const std::string& strIpsFile); + void responseValidators(const std::string& strValidatorsUrl, const NewcoinAddress& naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, const std::string& strValidatorsFile); void processIps(const std::string& strSite, const NewcoinAddress& naNodePublic, section::mapped_type* pmtVecStrIps); int processValidators(const std::string& strSite, const std::string& strValidatorsSrc, const NewcoinAddress& naNodePublic, validatorSource vsWhy, section::mapped_type* pmtVecStrValidators); - void processFile(const std::string strDomain, const NewcoinAddress& naNodePublic, section secSite); + void processFile(const std::string& strDomain, const NewcoinAddress& naNodePublic, section secSite); bool getSeedDomains(const std::string& strDomain, seedDomain& dstSeedDomain); void setSeedDomains(const seedDomain& dstSeedDomain, bool bNext); From 63921c975701b1b4357239185e8c3bb1e3410779 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 7 Sep 2012 22:21:07 -0700 Subject: [PATCH 226/426] Cleanups and fixes. --- src/HashedObject.cpp | 20 ++++++++++---------- src/HashedObject.h | 10 +++++----- src/Ledger.cpp | 4 ++-- src/LedgerAcquire.cpp | 2 +- src/SHAMapSync.h | 5 +++-- src/TransactionMeta.h | 2 +- src/UniqueNodeList.cpp | 11 ++++------- src/Wallet.cpp | 6 ++---- 8 files changed, 28 insertions(+), 32 deletions(-) diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp index 56f26e3d60..69e855ddc6 100644 --- a/src/HashedObject.cpp +++ b/src/HashedObject.cpp @@ -71,11 +71,11 @@ void HashedObjectStore::bulkWrite() char type; switch(it->getType()) { - case LEDGER: type = 'L'; break; - case TRANSACTION: type = 'T'; break; - case ACCOUNT_NODE: type = 'A'; break; - case TRANSACTION_NODE: type = 'N'; break; - default: type = 'U'; + case hotLEDGER: type= 'L'; break; + case hotTRANSACTION: type = 'T'; break; + case hotACCOUNT_NODE: type = 'A'; break; + case hotTRANSACTION_NODE: type = 'N'; break; + default: type = 'U'; } std::string rawData; db->escape(&(it->getData().front()), it->getData().size(), rawData); @@ -128,13 +128,13 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash) assert(Serializer::getSHA512Half(data) == hash); - HashedObjectType htype = UNKNOWN; + HashedObjectType htype = hotUNKNOWN; switch (type[0]) { - case 'L': htype = LEDGER; break; - case 'T': htype = TRANSACTION; break; - case 'A': htype = ACCOUNT_NODE; break; - case 'N': htype = TRANSACTION_NODE; break; + case 'L': htype = hotLEDGER; break; + case 'T': htype = hotTRANSACTION; break; + case 'A': htype = hotACCOUNT_NODE; break; + case 'N': htype = hotTRANSACTION_NODE; break; default: Log(lsERROR) << "Invalid hashed object"; return HashedObject::pointer(); diff --git a/src/HashedObject.h b/src/HashedObject.h index 0331cfa9b3..f403d5042a 100644 --- a/src/HashedObject.h +++ b/src/HashedObject.h @@ -10,11 +10,11 @@ enum HashedObjectType { - UNKNOWN = 0, - LEDGER = 1, - TRANSACTION = 2, - ACCOUNT_NODE = 3, - TRANSACTION_NODE = 4 + hotUNKNOWN = 0, + hotLEDGER = 1, + hotTRANSACTION = 2, + hotACCOUNT_NODE = 3, + hotTRANSACTION_NODE = 4 }; class HashedObject diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 0e558747c0..9b36e003b8 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -279,9 +279,9 @@ void Ledger::saveAcceptedLedger(Ledger::ref ledger) ledger->mAccountHash.GetHex() % ledger->mTransHash.GetHex())); // write out dirty nodes - while(ledger->mTransactionMap->flushDirty(256, TRANSACTION_NODE, ledger->mLedgerSeq)) + while(ledger->mTransactionMap->flushDirty(256, hotTRANSACTION_NODE, ledger->mLedgerSeq)) { ; } - while(ledger->mAccountStateMap->flushDirty(256, ACCOUNT_NODE, ledger->mLedgerSeq)) + while(ledger->mAccountStateMap->flushDirty(256, hotACCOUNT_NODE, ledger->mLedgerSeq)) { ; } ledger->disarmDirty(); diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 177dfa6dd6..a9a6263426 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -310,7 +310,7 @@ bool LedgerAcquire::takeBase(const std::string& data) Serializer s(data.size() + 4); s.add32(sHP_Ledger); s.addRaw(data); - theApp->getHashedObjectStore().store(LEDGER, mLedger->getLedgerSeq(), s.peekData(), mHash); + theApp->getHashedObjectStore().store(hotLEDGER, mLedger->getLedgerSeq(), s.peekData(), mHash); progress(); if (!mLedger->getTransHash()) diff --git a/src/SHAMapSync.h b/src/SHAMapSync.h index 2cd6ffc1e4..3d673e37a3 100644 --- a/src/SHAMapSync.h +++ b/src/SHAMapSync.h @@ -37,7 +37,7 @@ public: virtual void gotNode(const SHAMapNode& id, const uint256& nodeHash, const std::vector& nodeData, bool isLeaf) { - theApp->getHashedObjectStore().store(ACCOUNT_NODE, mLedgerSeq, nodeData, nodeHash); + theApp->getHashedObjectStore().store(hotACCOUNT_NODE, mLedgerSeq, nodeData, nodeHash); } virtual bool haveNode(const SHAMapNode& id, const uint256& nodeHash, std::vector& nodeData) { // fetchNodeExternal already tried @@ -58,7 +58,8 @@ public: virtual void gotNode(const SHAMapNode& id, const uint256& nodeHash, const std::vector& nodeData, bool isLeaf) { - theApp->getHashedObjectStore().store(isLeaf ? TRANSACTION : TRANSACTION_NODE, mLedgerSeq, nodeData, nodeHash); + theApp->getHashedObjectStore().store(isLeaf ? hotTRANSACTION : hotTRANSACTION_NODE, mLedgerSeq, + nodeData, nodeHash); } virtual bool haveNode(const SHAMapNode& id, const uint256& nodeHash, std::vector& nodeData) { // fetchNodeExternal already tried diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index eecc70bfb4..729a724808 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -71,7 +71,7 @@ protected: uint32 mPrevLgrSeq; public: - TMNEThread() : TransactionMetaNodeEntry(TMSThread) { ; } + TMNEThread() : TransactionMetaNodeEntry(TMSThread), mPrevLgrSeq(0) { ; } TMNEThread(uint256 prevTx, uint32 prevLgrSeq) : TransactionMetaNodeEntry(TMSThread), mPrevTxID(prevTx), mPrevLgrSeq(prevLgrSeq) { ; } diff --git a/src/UniqueNodeList.cpp b/src/UniqueNodeList.cpp index 05453b0128..b5b1d2c804 100644 --- a/src/UniqueNodeList.cpp +++ b/src/UniqueNodeList.cpp @@ -184,8 +184,6 @@ void UniqueNodeList::scoreCompute() Database* db=theApp->getWalletDB()->getDB(); - std::string strSql; - // For each entry in SeedDomains with a PublicKey: // - Add an entry in umPulicIdx, umDomainIdx, and vsnNodes. { @@ -389,7 +387,7 @@ void UniqueNodeList::scoreCompute() db->executeSQL("BEGIN;"); db->executeSQL("UPDATE TrustedNodes SET Score = 0 WHERE Score != 0;"); - if (vsnNodes.size()) + if (!vsnNodes.empty()) { // Load existing Seens from DB. std::vector vstrPublicKeys; @@ -410,7 +408,7 @@ void UniqueNodeList::scoreCompute() boost::unordered_set usUNL; - if (vsnNodes.size()) + if (!vsnNodes.empty()) { // Update the score old entries and add new entries as needed. std::vector vstrValues; @@ -446,7 +444,7 @@ void UniqueNodeList::scoreCompute() boost::unordered_map umValidators; - if (vsnNodes.size()) + if (!vsnNodes.empty()) { std::vector vstrPublicKeys; @@ -627,7 +625,7 @@ void UniqueNodeList::processIps(const std::string& strSite, const NewcoinAddress } // Add new referral entries. - if (pmtVecStrIps && pmtVecStrIps->size()) { + if (pmtVecStrIps && !pmtVecStrIps->empty()) { std::vector vstrValues; vstrValues.resize(MIN(pmtVecStrIps->size(), REFERRAL_IPS_MAX)); @@ -712,7 +710,6 @@ int UniqueNodeList::processValidators(const std::string& strSite, const std::str break; boost::smatch smMatch; - std::string strIP; // domain comment? // public_key comment? diff --git a/src/Wallet.cpp b/src/Wallet.cpp index 5d1ef4e8a7..f5670eda73 100644 --- a/src/Wallet.cpp +++ b/src/Wallet.cpp @@ -16,8 +16,8 @@ #include "Application.h" #include "utils.h" -Wallet::Wallet() : mLedger(0) { -} +Wallet::Wallet() : mDh512(NULL), mDh1024(NULL), mLedger(0) +{ ; } void Wallet::start() { @@ -136,8 +136,6 @@ bool Wallet::dataFetch(const std::string& strKey, std::string& strValue) if (db->executeSQL(str(boost::format("SELECT Value FROM RPCData WHERE Key=%s;") % db->escape(strKey))) && db->startIterRows()) { - std::string strPublicKey, strPrivateKey; - std::vector vucData = db->getBinary("Value"); strValue.assign(vucData.begin(), vucData.end()); From 1a1952ea7b3c8fe813fa92a505aad655c435ac66 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 8 Sep 2012 00:48:26 -0700 Subject: [PATCH 227/426] You can now create a LedgerEntrySet without a TransactionEngine. You can call all the various entry* functions on it directly. You can throw it out when you're done. The constructor is: LedgerEntrySet(Ledger::ref ledger) All the normal checkpointing, caching, and swapping will work. Of course, you cannot commit the results. The TransactionEngine::entry* functions now just directly call the corresponding functions on the LedgerEntrySet. You can call them in code that will only be used in the context of a transaction. --- src/LedgerEntrySet.cpp | 48 ++++++++++++++++++++++++++++---------- src/LedgerEntrySet.h | 18 ++++++++++---- src/TransactionEngine.cpp | 49 ++------------------------------------- src/TransactionEngine.h | 8 +++---- 4 files changed, 55 insertions(+), 68 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 2f31478bd2..5b5b703e66 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -2,9 +2,10 @@ #include -void LedgerEntrySet::init(const uint256& transactionID, uint32 ledgerID) +void LedgerEntrySet::init(Ledger::ref ledger, const uint256& transactionID, uint32 ledgerID) { mEntries.clear(); + mLedger = ledger; mSet.init(transactionID, ledgerID); mSeq = 0; } @@ -17,7 +18,7 @@ void LedgerEntrySet::clear() LedgerEntrySet LedgerEntrySet::duplicate() const { - return LedgerEntrySet(mEntries, mSet, mSeq + 1); + return LedgerEntrySet(mLedger, mEntries, mSet, mSeq + 1); } void LedgerEntrySet::setTo(const LedgerEntrySet& e) @@ -25,11 +26,13 @@ void LedgerEntrySet::setTo(const LedgerEntrySet& e) mEntries = e.mEntries; mSet = e.mSet; mSeq = e.mSeq; + mLedger = e.mLedger; } void LedgerEntrySet::swapWith(LedgerEntrySet& e) { std::swap(mSeq, e.mSeq); + std::swap(mLedger, e.mLedger); mSet.swap(e.mSet); mEntries.swap(e.mEntries); } @@ -53,6 +56,36 @@ SLE::pointer LedgerEntrySet::getEntry(const uint256& index, LedgerEntryAction& a return it->second.mEntry; } +SLE::pointer LedgerEntrySet::entryCreate(LedgerEntryType letType, const uint256& index) +{ + assert(index.isNonZero()); + SLE::pointer sleNew = boost::make_shared(letType); + sleNew->setIndex(index); + entryCreate(sleNew); + return sleNew; +} + +SLE::pointer LedgerEntrySet::entryCache(LedgerEntryType letType, const uint256& index) +{ + SLE::pointer sleEntry; + if (index.isNonZero()) + { + LedgerEntryAction action; + sleEntry = getEntry(index, action); + if (!sleEntry) + { + sleEntry = mLedger->getSLE(index); + if (sleEntry) + entryCache(sleEntry); + } + else if (action == taaDELETE) + { + assert(false); + } + } + return sleEntry; +} + LedgerEntryAction LedgerEntrySet::hasEntry(const uint256& index) const { boost::unordered_map::const_iterator it = mEntries.find(index); @@ -147,7 +180,7 @@ void LedgerEntrySet::entryModify(SLE::ref sle) } } -void LedgerEntrySet::entryDelete(SLE::ref sle, bool unfunded) +void LedgerEntrySet::entryDelete(SLE::ref sle) { boost::unordered_map::iterator it = mEntries.find(sle->getIndex()); if (it == mEntries.end()) @@ -166,15 +199,6 @@ void LedgerEntrySet::entryDelete(SLE::ref sle, bool unfunded) it->second.mSeq = mSeq; it->second.mEntry = sle; it->second.mAction = taaDELETE; - if (unfunded) - { - assert(sle->getType() == ltOFFER); // only offers can be unfunded -#if 0 - mSet.deleteUnfunded(sle->getIndex(), - sle->getIValueFieldAmount(sfTakerPays), - sle->getIValueFieldAmount(sfTakerGets)); -#endif - } break; case taaCREATE: diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 0ab19896b9..c840057c27 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -31,12 +31,13 @@ public: class LedgerEntrySet { protected: + Ledger::pointer mLedger; boost::unordered_map mEntries; TransactionMetaSet mSet; int mSeq; - LedgerEntrySet(const boost::unordered_map &e, const TransactionMetaSet& s, int m) : - mEntries(e), mSet(s), mSeq(m) { ; } + LedgerEntrySet(Ledger::ref ledger, const boost::unordered_map &e, + const TransactionMetaSet& s, int m) : mLedger(ledger), mEntries(e), mSet(s), mSeq(m) { ; } SLE::pointer getForMod(const uint256& node, Ledger::ref ledger, boost::unordered_map& newMods); @@ -51,6 +52,9 @@ protected: boost::unordered_map& newMods); public: + + LedgerEntrySet(Ledger::ref ledger) : mLedger(ledger), mSeq(0) { ; } + LedgerEntrySet() : mSeq(0) { ; } // set functions @@ -60,7 +64,7 @@ public: int getSeq() const { return mSeq; } void bumpSeq() { ++mSeq; } - void init(const uint256& transactionID, uint32 ledgerID); + void init(Ledger::ref ledger, const uint256& transactionID, uint32 ledgerID); void clear(); // basic entry functions @@ -68,14 +72,18 @@ public: LedgerEntryAction hasEntry(const uint256& index) const; void entryCache(SLE::ref); // Add this entry to the cache void entryCreate(SLE::ref); // This entry will be created - void entryDelete(SLE::ref, bool unfunded); + void entryDelete(SLE::ref); // This entry will be deleted void entryModify(SLE::ref); // This entry will be modified + // higher-level ledger functions + SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex); + SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex); + Json::Value getJson(int) const; void calcRawMeta(Serializer&, Ledger::ref originalLedger); // iterator functions - bool isEmpty() const { return mEntries.empty(); } + bool isEmpty() const { return mEntries.empty(); } boost::unordered_map::const_iterator begin() const { return mEntries.begin(); } boost::unordered_map::const_iterator end() const { return mEntries.end(); } boost::unordered_map::iterator begin() { return mEntries.begin(); } diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 74d5467ea5..4c57195192 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -865,50 +865,6 @@ TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMus return tesSUCCESS; } -SLE::pointer TransactionEngine::entryCache(LedgerEntryType letType, const uint256& uIndex) -{ - SLE::pointer sleEntry; - - if (!!uIndex) - { - LedgerEntryAction action; - sleEntry = mNodes.getEntry(uIndex, action); - if (!sleEntry) - { - sleEntry = mLedger->getSLE(uIndex); - if (sleEntry) - mNodes.entryCache(sleEntry); - } - else if (action == taaDELETE) - { - assert(false); - } - } - - return sleEntry; -} - -SLE::pointer TransactionEngine::entryCreate(LedgerEntryType letType, const uint256& uIndex) -{ - assert(!!uIndex); - - SLE::pointer sleNew = boost::make_shared(letType); - sleNew->setIndex(uIndex); - mNodes.entryCreate(sleNew); - - return sleNew; -} - -void TransactionEngine::entryDelete(SLE::pointer sleEntry, bool bUnfunded) -{ - mNodes.entryDelete(sleEntry, bUnfunded); -} - -void TransactionEngine::entryModify(SLE::pointer sleEntry) -{ - mNodes.entryModify(sleEntry); -} - void TransactionEngine::txnWrite() { // Write back the account states and add the transaction to the ledger @@ -956,12 +912,11 @@ void TransactionEngine::txnWrite() } } -TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, - TransactionEngineParams params) +TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, TransactionEngineParams params) { Log(lsTRACE) << "applyTransaction>"; assert(mLedger); - mNodes.init(txn.getTransactionID(), mLedger->getLedgerSeq()); + mNodes.init(mLedger, txn.getTransactionID(), mLedger->getLedgerSeq()); #ifdef DEBUG if (1) diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 7f7d653cca..b164ea2b01 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -308,10 +308,10 @@ protected: // If the transaction fails to meet some constraint, still need to delete unfunded offers. boost::unordered_set musUnfundedFound; // Offers that were found unfunded. - SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex); - SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex); - void entryDelete(SLE::pointer sleEntry, bool bUnfunded = false); - void entryModify(SLE::pointer sleEntry); + 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); From e2137ea5af8de50f66dce7047bb00c6e1dbac561 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 8 Sep 2012 03:49:12 -0700 Subject: [PATCH 228/426] Make our ledger a bit stickier to avoid the "check at the wrong time" problem (when you don't have enough validations for the latest ledger and so jump backwards when you shouldn't. This solves every known ledger consensus issue except the "stuck one ledger behind" issue. I'm working on that now. --- src/LedgerConsensus.cpp | 5 +---- src/NetworkOPs.cpp | 10 +++++----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index bdba1c7da4..802810f681 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -247,10 +247,7 @@ void LedgerConsensus::checkLCL() uint256 netLgr = mPrevLedgerHash; int netLgrCount = 0; - uint256 favorLedger; - if (mState != lcsPRE_CLOSE) - favorLedger = mPrevLedgerHash; - boost::unordered_map vals = theApp->getValidations().getCurrentValidations(favorLedger); + boost::unordered_map vals = theApp->getValidations().getCurrentValidations(mPrevLedgerHash); typedef std::pair u256_int_pair; BOOST_FOREACH(u256_int_pair& it, vals) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 7706cd7ac9..754559db83 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -446,18 +446,18 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis // node is using. THis is kind of fundamental. Log(lsTRACE) << "NetworkOPs::checkLastClosedLedger"; - boost::unordered_map ledgers; + Ledger::pointer ourClosed = mLedgerMaster->getClosedLedger(); + uint256 closedLedger = ourClosed->getHash(); + uint256 prevClosedLedger = ourClosed->getParentHash(); + boost::unordered_map ledgers; { - boost::unordered_map current = theApp->getValidations().getCurrentValidations(); + boost::unordered_map current = theApp->getValidations().getCurrentValidations(closedLedger); typedef std::pair u256_int_pair; BOOST_FOREACH(u256_int_pair& it, current) ledgers[it.first].trustedValidations += it.second; } - Ledger::pointer ourClosed = mLedgerMaster->getClosedLedger(); - uint256 closedLedger = ourClosed->getHash(); - uint256 prevClosedLedger = ourClosed->getParentHash(); ValidationCount& ourVC = ledgers[closedLedger]; if ((theConfig.LEDGER_CREATOR) && (mMode >= omTRACKING)) From 9222eee1df973db85be26596afeb9ee366a6ed42 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 8 Sep 2012 03:51:56 -0700 Subject: [PATCH 229/426] I believe this trivial change solves the "stuck one ledger behind" problem. If the ledger is open, there should be no significant number of proposals for a subsequent ledger. If there is, we are a ledger behind. --- src/LedgerConsensus.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 802810f681..5a4c27341c 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -247,6 +247,7 @@ void LedgerConsensus::checkLCL() uint256 netLgr = mPrevLedgerHash; int netLgrCount = 0; + uint256 favoredLedger = (mState == PRE_CLOSE) ? uint256() : mPrevLedgerHash; // Don't get stuck one ledger behind boost::unordered_map vals = theApp->getValidations().getCurrentValidations(mPrevLedgerHash); typedef std::pair u256_int_pair; From 18b18359c591b9efc90724995e20b9119785c46b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 8 Sep 2012 04:14:06 -0700 Subject: [PATCH 230/426] Be smarter about tracking which peers have which ledgers. --- src/Peer.cpp | 20 +++++++++++++++++++- src/Peer.h | 5 ++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index 27db8ff017..aec3ce31e2 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -649,7 +649,10 @@ void Peer::recvHello(newcoin::TMHello& packet) { memcpy(mClosedLedgerHash.begin(), packet.ledgerclosed().data(), 256 / 8); if ((packet.has_ledgerprevious()) && (packet.ledgerprevious().size() == (256 / 8))) + { memcpy(mPreviousLedgerHash.begin(), packet.ledgerprevious().data(), 256 / 8); + addLedger(mPreviousLedgerHash); + } else mPreviousLedgerHash.zero(); } @@ -915,6 +918,7 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet) if (packet.has_ledgerhash() && (packet.ledgerhash().size() == (256 / 8))) { // a peer has changed ledgers memcpy(mClosedLedgerHash.begin(), packet.ledgerhash().data(), 256 / 8); + addLedger(mClosedLedgerHash); Log(lsTRACE) << "peer LCL is " << mClosedLedgerHash << " " << getIP(); } else @@ -926,6 +930,7 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet) if (packet.has_ledgerhashprevious() && packet.ledgerhashprevious().size() == (256 / 8)) { memcpy(mPreviousLedgerHash.begin(), packet.ledgerhashprevious().data(), 256 / 8); + addLedger(mPreviousLedgerHash); } else mPreviousLedgerHash.zero(); } @@ -1134,7 +1139,20 @@ void Peer::recvLedger(newcoin::TMLedgerData& packet) bool Peer::hasLedger(const uint256& hash) const { - return (hash == mClosedLedgerHash) || (hash == mPreviousLedgerHash); + BOOST_FOREACH(const uint256& ledger, mRecentLedgers) + if (ledger == hash) + return true; + return false; +} + +void Peer::addLedger(const uint256& hash) +{ + BOOST_FOREACH(const uint256& ledger, mRecentLedgers) + if (ledger == hash) + return; + if (mRecentLedgers.size() == 16) + mRecentLedgers.pop_front(); + mRecentLedgers.push_back(hash); } // Get session information we can sign to prevent man in the middle attack. diff --git a/src/Peer.h b/src/Peer.h index 13c5fdb2de..ae4abf7307 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -44,7 +44,8 @@ private: ipPort mIpPortConnect; uint256 mCookieHash; - uint256 mClosedLedgerHash, mPreviousLedgerHash; + uint256 mClosedLedgerHash, mPreviousLedgerHash; + std::list mRecentLedgers; boost::asio::ssl::stream mSocketSsl; @@ -116,6 +117,8 @@ protected: void getSessionCookie(std::string& strDst); + void addLedger(const uint256& ledger); + public: //bool operator == (const Peer& other); From 3ab5b24226d140f665c5acf5713f8deec913eb71 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 8 Sep 2012 04:14:26 -0700 Subject: [PATCH 231/426] Trivial change. --- src/LedgerAcquire.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index a9a6263426..353b7d8872 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -405,7 +405,8 @@ LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash) assert(hash.isNonZero()); boost::mutex::scoped_lock sl(mLock); LedgerAcquire::pointer& ptr = mLedgers[hash]; - if (ptr) return ptr; + if (ptr) + return ptr; ptr = boost::make_shared(hash); assert(mLedgers[hash] == ptr); ptr->resetTimer(); // Cannot call in constructor @@ -417,7 +418,8 @@ LedgerAcquire::pointer LedgerAcquireMaster::find(const uint256& hash) assert(hash.isNonZero()); boost::mutex::scoped_lock sl(mLock); std::map::iterator it = mLedgers.find(hash); - if (it != mLedgers.end()) return it->second; + if (it != mLedgers.end()) + return it->second; return LedgerAcquire::pointer(); } From 4271a9d12d54cc4674dd45501b95f3ff45ed3252 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 8 Sep 2012 04:14:42 -0700 Subject: [PATCH 232/426] Improve comments. Fix a typo in previous commit. --- src/LedgerConsensus.cpp | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 5a4c27341c..ce064fe47c 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -59,7 +59,8 @@ void TransactionAcquire::trigger(Peer::ref peer, bool timer) } else { - std::vector nodeIDs; std::vector nodeHashes; + std::vector nodeIDs; + std::vector nodeHashes; ConsensusTransSetSF sf; mMap->getMissingNodes(nodeIDs, nodeHashes, 256, &sf); if (nodeIDs.empty()) @@ -68,6 +69,8 @@ void TransactionAcquire::trigger(Peer::ref peer, bool timer) mComplete = true; else mFailed = true; + done(); + return; } else { @@ -77,12 +80,9 @@ void TransactionAcquire::trigger(Peer::ref peer, bool timer) for (std::vector::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it) *(tmGL.add_nodeids()) = it->getRawString(); sendRequest(tmGL, peer); - return; } } - if (mComplete || mFailed) - done(); - else if (timer) + if (timer) resetTimer(); } @@ -128,7 +128,7 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, } void LCTransaction::setVote(const uint160& peer, bool votesYes) -{ +{ // Tracke a peer's yes/no vote on a particular disputed transaction std::pair::iterator, bool> res = mVotes.insert(std::make_pair(peer, votesYes)); @@ -162,7 +162,7 @@ void LCTransaction::setVote(const uint160& peer, bool votesYes) } void LCTransaction::unVote(const uint160& peer) -{ +{ // Remove a peer's vote on this disputed transasction boost::unordered_map::iterator it = mVotes.find(peer); if (it != mVotes.end()) { @@ -175,7 +175,7 @@ void LCTransaction::unVote(const uint160& peer) } bool LCTransaction::updatePosition(int percentTime, bool proposing) -{ // this many seconds after close, should our position change +{ if (mOurPosition && (mNays == 0)) return false; if (!mOurPosition && (mYays == 0)) @@ -247,29 +247,28 @@ void LedgerConsensus::checkLCL() uint256 netLgr = mPrevLedgerHash; int netLgrCount = 0; - uint256 favoredLedger = (mState == PRE_CLOSE) ? uint256() : mPrevLedgerHash; // Don't get stuck one ledger behind - boost::unordered_map vals = theApp->getValidations().getCurrentValidations(mPrevLedgerHash); + uint256 favoredLedger = (mState == lcsPRE_CLOSE) ? uint256() : mPrevLedgerHash; // Don't get stuck one ledger behind + boost::unordered_map vals = + theApp->getValidations().getCurrentValidations(favoredLedger); typedef std::pair u256_int_pair; BOOST_FOREACH(u256_int_pair& it, vals) - { if (it.second > netLgrCount) { netLgr = it.first; netLgrCount = it.second; } - } if (netLgr != mPrevLedgerHash) { // LCL change const char *status; switch (mState) { - case lcsPRE_CLOSE: status="PreClose"; break; - case lcsESTABLISH: status="Establish"; break; - case lcsFINISHED: status="Finised"; break; - case lcsACCEPTED: status="Accepted"; break; - default: status="unknown"; + case lcsPRE_CLOSE: status = "PreClose"; break; + case lcsESTABLISH: status = "Establish"; break; + case lcsFINISHED: status = "Finised"; break; + case lcsACCEPTED: status = "Accepted"; break; + default: status = "unknown"; } Log(lsWARNING) << "View of consensus changed during consensus (" << netLgrCount << ") status=" @@ -301,8 +300,10 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) else { Log(lsWARNING) << "Need consensus ledger " << mPrevLedgerHash; + mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash); std::vector peerList = theApp->getConnectionPool().getPeerVector(); + bool found = false; BOOST_FOREACH(Peer::ref peer, peerList) { @@ -312,11 +313,13 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) mAcquiringLedger->peerHas(peer); } } + if (!found) { BOOST_FOREACH(Peer::ref peer, peerList) mAcquiringLedger->peerHas(peer); } + if (mHaveCorrectLCL && mProposing && mOurPosition) { Log(lsINFO) << "Bowing out of consensus"; From 042a239c62dbeb97ee897bb15bcc6924115e0ddf Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 8 Sep 2012 11:32:51 -0700 Subject: [PATCH 233/426] Remove unused directories (test & Debug). --- Debug/newcoin.exe.embed.manifest.res | Bin 472 -> 0 bytes Debug/newcoin_manifest.rc | Bin 204 -> 0 bytes tests/client1/config.xml | 5 ----- tests/client1/nodes.xml | 4 ---- tests/client1/unl.xml | 9 --------- tests/client1/wallet.xml | 7 ------- tests/client2/config.xml | 6 ------ tests/client2/nodes.xml | 4 ---- tests/client2/unl.xml | 9 --------- tests/client2/wallet.xml | 7 ------- tests/setup.bat | 6 ------ 11 files changed, 57 deletions(-) delete mode 100644 Debug/newcoin.exe.embed.manifest.res delete mode 100644 Debug/newcoin_manifest.rc delete mode 100644 tests/client1/config.xml delete mode 100644 tests/client1/nodes.xml delete mode 100644 tests/client1/unl.xml delete mode 100644 tests/client1/wallet.xml delete mode 100644 tests/client2/config.xml delete mode 100644 tests/client2/nodes.xml delete mode 100644 tests/client2/unl.xml delete mode 100644 tests/client2/wallet.xml delete mode 100644 tests/setup.bat diff --git a/Debug/newcoin.exe.embed.manifest.res b/Debug/newcoin.exe.embed.manifest.res deleted file mode 100644 index 9c8df0e3c8e374037f6a16f24fed3e764becd3f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 472 zcma)2yG{c!5Hu1ENc5D}_LoaUgCgHW6d*;Spa6Qu*$Wna2(Ryy`w@PIf=}WT!t%IN zA{tg&YuB?g>#-0*NY35vC%HU`*P{VH=NWD|rsCvy82Wg7SBtH8vcp6+h6-krDM$<^ zu5H*<@Nj=qT!N&m!&t2d_+kREmZXD)pG@HWZB)B+1YtLdqi|e zoFg()h7``Fc%hP#TO~8~Ia4MdrBDgpT+d1re5Kd1DT!$jeFneW%*6kMuQT?mV#|#q hYwIMtv*S!H?#Lc?*p04=y|`iHt>z%Va3!Wqi#M>GAD#dJ diff --git a/tests/client1/config.xml b/tests/client1/config.xml deleted file mode 100644 index dfe441b032..0000000000 --- a/tests/client1/config.xml +++ /dev/null @@ -1,5 +0,0 @@ - - 4000 - 5001 - 30 - diff --git a/tests/client1/nodes.xml b/tests/client1/nodes.xml deleted file mode 100644 index 9754b37c4f..0000000000 --- a/tests/client1/nodes.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/tests/client1/unl.xml b/tests/client1/unl.xml deleted file mode 100644 index 553486b098..0000000000 --- a/tests/client1/unl.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/tests/client1/wallet.xml b/tests/client1/wallet.xml deleted file mode 100644 index 1c364ebb03..0000000000 --- a/tests/client1/wallet.xml +++ /dev/null @@ -1,7 +0,0 @@ - - -
- - -
-
\ No newline at end of file diff --git a/tests/client2/config.xml b/tests/client2/config.xml deleted file mode 100644 index d01e35c99f..0000000000 --- a/tests/client2/config.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - 5000 - 5002 - 30 - diff --git a/tests/client2/nodes.xml b/tests/client2/nodes.xml deleted file mode 100644 index 9754b37c4f..0000000000 --- a/tests/client2/nodes.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/tests/client2/unl.xml b/tests/client2/unl.xml deleted file mode 100644 index 553486b098..0000000000 --- a/tests/client2/unl.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/tests/client2/wallet.xml b/tests/client2/wallet.xml deleted file mode 100644 index 1c364ebb03..0000000000 --- a/tests/client2/wallet.xml +++ /dev/null @@ -1,7 +0,0 @@ - - -
- - -
-
\ No newline at end of file diff --git a/tests/setup.bat b/tests/setup.bat deleted file mode 100644 index 61304847bb..0000000000 --- a/tests/setup.bat +++ /dev/null @@ -1,6 +0,0 @@ -REM copy C:\code\newcoin\Release\newcoin.exe C:\code\newcoin\tests\client1 -REM copy C:\code\newcoin\Release\newcoin.exe C:\code\newcoin\tests\client2 - -copy d:\code\newcoin\Debug\newcoin.exe d:\code\newcoin\tests\client1 -copy d:\code\newcoin\Debug\newcoin.exe d:\code\newcoin\tests\client2 - From fe6c5d2b6085952df75bc563a3864d2f57ea53e6 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 8 Sep 2012 15:36:23 -0700 Subject: [PATCH 234/426] Comment out bad assert. --- src/Ledger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 9b36e003b8..71a82231dc 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -154,7 +154,7 @@ void Ledger::setAccepted(uint32 closeTime, int closeResolution, bool correctClos void Ledger::setAccepted() { // used when we acquired the ledger - assert(mClosed && (mCloseTime != 0) && (mCloseResolution != 0)); + // FIXME assert(mClosed && (mCloseTime != 0) && (mCloseResolution != 0)); mCloseTime -= mCloseTime % mCloseResolution; updateHash(); mAccepted = true; From 4adfce51a371a82031b9b0525f7c5e51accdd214 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 8 Sep 2012 15:37:22 -0700 Subject: [PATCH 235/426] Create TransactionErr.* and move dir functions to LedgerEntrySet. --- src/LedgerEntrySet.cpp | 328 ++++++++++++++++++++++++++++ src/LedgerEntrySet.h | 18 ++ src/TransactionEngine.cpp | 437 +------------------------------------- src/TransactionEngine.h | 126 +---------- src/TransactionErr.cpp | 91 ++++++++ src/TransactionErr.h | 118 ++++++++++ 6 files changed, 567 insertions(+), 551 deletions(-) create mode 100644 src/TransactionErr.cpp create mode 100644 src/TransactionErr.h diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 5b5b703e66..c5747b85b0 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -1,7 +1,13 @@ + #include "LedgerEntrySet.h" #include +#include "Log.h" + +// Small for testing, should likely be 32 or 64. +#define DIR_NODE_MAX 2 + void LedgerEntrySet::init(Ledger::ref ledger, const uint256& transactionID, uint32 ledgerID) { mEntries.clear(); @@ -428,4 +434,326 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger) mSet.addRaw(s); } +// <-- uNodeDir: For deletion, present to make dirDelete efficient. +// --> uRootIndex: The index of the base of the directory. Nodes are based off of this. +// --> uLedgerIndex: Value to add to directory. +// We only append. This allow for things that watch append only structure to just monitor from the last node on ward. +// Within a node with no deletions order of elements is sequential. Otherwise, order of elements is random. +TER LedgerEntrySet::dirAdd( + uint64& uNodeDir, + const uint256& uRootIndex, + const uint256& uLedgerIndex) +{ + SLE::pointer sleNode; + STVector256 svIndexes; + SLE::pointer sleRoot = entryCache(ltDIR_NODE, uRootIndex); + + if (!sleRoot) + { + // No root, make it. + sleRoot = entryCreate(ltDIR_NODE, uRootIndex); + + sleNode = sleRoot; + uNodeDir = 0; + } + else + { + uNodeDir = sleRoot->getIFieldU64(sfIndexPrevious); // Get index to last directory node. + + if (uNodeDir) + { + // Try adding to last node. + sleNode = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeDir)); + + assert(sleNode); + } + else + { + // Try adding to root. Didn't have a previous set to the last node. + sleNode = sleRoot; + } + + svIndexes = sleNode->getIFieldV256(sfIndexes); + + if (DIR_NODE_MAX != svIndexes.peekValue().size()) + { + // Add to current node. + entryModify(sleNode); + } + // Add to new node. + else if (!++uNodeDir) + { + return terDIR_FULL; + } + else + { + // Have old last point to new node, if it was not root. + if (uNodeDir == 1) + { + // Previous node is root node. + + sleRoot->setIFieldU64(sfIndexNext, uNodeDir); + } + else + { + // Previous node is not root node. + + SLE::pointer slePrevious = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeDir-1)); + + slePrevious->setIFieldU64(sfIndexNext, uNodeDir); + entryModify(slePrevious); + + sleNode->setIFieldU64(sfIndexPrevious, uNodeDir-1); + } + + // Have root point to new node. + sleRoot->setIFieldU64(sfIndexPrevious, uNodeDir); + entryModify(sleRoot); + + // Create the new node. + sleNode = entryCreate(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeDir)); + svIndexes = STVector256(); + } + } + + svIndexes.peekValue().push_back(uLedgerIndex); // Append entry. + sleNode->setIFieldV256(sfIndexes, svIndexes); // Save entry. + + Log(lsINFO) << "dirAdd: creating: root: " << uRootIndex.ToString(); + Log(lsINFO) << "dirAdd: appending: Entry: " << uLedgerIndex.ToString(); + Log(lsINFO) << "dirAdd: appending: Node: " << strHex(uNodeDir); + // Log(lsINFO) << "dirAdd: appending: PREV: " << svIndexes.peekValue()[0].ToString(); + + return tesSUCCESS; +} + +// Ledger must be in a state for this to work. +TER LedgerEntrySet::dirDelete( + const bool bKeepRoot, // --> True, if we never completely clean up, after we overflow the root node. + const uint64& uNodeDir, // --> Node containing entry. + const uint256& uRootIndex, // --> The index of the base of the directory. Nodes are based off of this. + const uint256& uLedgerIndex, // --> Value to add to directory. + const bool bStable) // --> True, not to change relative order of entries. +{ + uint64 uNodeCur = uNodeDir; + SLE::pointer sleNode = entryCache(ltDIR_NODE, uNodeCur ? Ledger::getDirNodeIndex(uRootIndex, uNodeCur) : uRootIndex); + + assert(sleNode); + + if (!sleNode) + { + Log(lsWARNING) << "dirDelete: no such node"; + + return tefBAD_LEDGER; + } + + STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes); + std::vector& vuiIndexes = svIndexes.peekValue(); + std::vector::iterator it; + + it = std::find(vuiIndexes.begin(), vuiIndexes.end(), uLedgerIndex); + + assert(vuiIndexes.end() != it); + if (vuiIndexes.end() == it) + { + assert(false); + + Log(lsWARNING) << "dirDelete: no such entry"; + + return tefBAD_LEDGER; + } + + // Remove the element. + if (vuiIndexes.size() > 1) + { + if (bStable) + { + vuiIndexes.erase(it); + } + else + { + *it = vuiIndexes[vuiIndexes.size()-1]; + vuiIndexes.resize(vuiIndexes.size()-1); + } + } + else + { + vuiIndexes.clear(); + } + + sleNode->setIFieldV256(sfIndexes, svIndexes); + entryModify(sleNode); + + if (vuiIndexes.empty()) + { + // May be able to delete nodes. + uint64 uNodePrevious = sleNode->getIFieldU64(sfIndexPrevious); + uint64 uNodeNext = sleNode->getIFieldU64(sfIndexNext); + + if (!uNodeCur) + { + // Just emptied root node. + + if (!uNodePrevious) + { + // Never overflowed the root node. Delete it. + entryDelete(sleNode); + } + // Root overflowed. + else if (bKeepRoot) + { + // If root overflowed and not allowed to delete overflowed root node. + + nothing(); + } + else if (uNodePrevious != uNodeNext) + { + // Have more than 2 nodes. Can't delete root node. + + nothing(); + } + else + { + // Have only a root node and a last node. + SLE::pointer sleLast = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeNext)); + + assert(sleLast); + + if (sleLast->getIFieldV256(sfIndexes).peekValue().empty()) + { + // Both nodes are empty. + + entryDelete(sleNode); // Delete root. + entryDelete(sleLast); // Delete last. + } + else + { + // Have an entry, can't delete root node. + + nothing(); + } + } + } + // Just emptied a non-root node. + else if (uNodeNext) + { + // Not root and not last node. Can delete node. + + SLE::pointer slePrevious = entryCache(ltDIR_NODE, uNodePrevious ? Ledger::getDirNodeIndex(uRootIndex, uNodePrevious) : uRootIndex); + + assert(slePrevious); + + SLE::pointer sleNext = entryCache(ltDIR_NODE, uNodeNext ? Ledger::getDirNodeIndex(uRootIndex, uNodeNext) : uRootIndex); + + assert(slePrevious); + assert(sleNext); + + if (!slePrevious) + { + Log(lsWARNING) << "dirDelete: previous node is missing"; + + return tefBAD_LEDGER; + } + + if (!sleNext) + { + Log(lsWARNING) << "dirDelete: next node is missing"; + + return tefBAD_LEDGER; + } + + // Fix previous to point to its new next. + slePrevious->setIFieldU64(sfIndexNext, uNodeNext); + entryModify(slePrevious); + + // Fix next to point to its new previous. + sleNext->setIFieldU64(sfIndexPrevious, uNodePrevious); + entryModify(sleNext); + } + // Last node. + else if (bKeepRoot || uNodePrevious) + { + // Not allowed to delete last node as root was overflowed. + // Or, have pervious entries preventing complete delete. + + nothing(); + } + else + { + // Last and only node besides the root. + SLE::pointer sleRoot = entryCache(ltDIR_NODE, uRootIndex); + + assert(sleRoot); + + if (sleRoot->getIFieldV256(sfIndexes).peekValue().empty()) + { + // Both nodes are empty. + + entryDelete(sleRoot); // Delete root. + entryDelete(sleNode); // Delete last. + } + else + { + // Root has an entry, can't delete. + + nothing(); + } + } + } + + return tesSUCCESS; +} + +// Return the first entry and advance uDirEntry. +// <-- true, if had a next entry. +bool LedgerEntrySet::dirFirst( + const uint256& uRootIndex, // --> Root of directory. + SLE::pointer& sleNode, // <-- current node + unsigned int& uDirEntry, // <-- next entry + uint256& uEntryIndex) // <-- The entry, if available. Otherwise, zero. +{ + sleNode = entryCache(ltDIR_NODE, uRootIndex); + uDirEntry = 0; + + assert(sleNode); // We never probe for directories. + + return LedgerEntrySet::dirNext(uRootIndex, sleNode, uDirEntry, uEntryIndex); +} + +// Return the current entry and advance uDirEntry. +// <-- true, if had a next entry. +bool LedgerEntrySet::dirNext( + const uint256& uRootIndex, // --> Root of directory + SLE::pointer& sleNode, // <-> current node + unsigned int& uDirEntry, // <-> next entry + uint256& uEntryIndex) // <-- The entry, if available. Otherwise, zero. +{ + STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes); + std::vector& vuiIndexes = svIndexes.peekValue(); + + if (uDirEntry == vuiIndexes.size()) + { + uint64 uNodeNext = sleNode->getIFieldU64(sfIndexNext); + + if (!uNodeNext) + { + uEntryIndex.zero(); + + return false; + } + else + { + sleNode = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeNext)); + uDirEntry = 0; + + return dirNext(uRootIndex, sleNode, uDirEntry, uEntryIndex); + } + } + + uEntryIndex = vuiIndexes[uDirEntry++]; +Log(lsINFO) << boost::str(boost::format("dirNext: uDirEntry=%d uEntryIndex=%s") % uDirEntry % uEntryIndex); + + return true; +} + // vim:ts=4 diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index c840057c27..256275b00e 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -6,6 +6,7 @@ #include "SerializedLedger.h" #include "TransactionMeta.h" #include "Ledger.h" +#include "TransactionErr.h" enum LedgerEntryAction { @@ -79,6 +80,23 @@ public: SLE::pointer entryCreate(LedgerEntryType letType, const uint256& uIndex); SLE::pointer entryCache(LedgerEntryType letType, const uint256& uIndex); + // Utility entry functions. + TER dirAdd( + uint64& uNodeDir, // Node of entry. + const uint256& uRootIndex, + const uint256& uLedgerIndex); + + TER dirDelete( + const bool bKeepRoot, + const uint64& uNodeDir, // Node item is mentioned in. + const uint256& uRootIndex, + const uint256& uLedgerIndex, // Item being deleted + const bool bStable); + + 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); + + Json::Value getJson(int) const; void calcRawMeta(Serializer&, Ledger::ref originalLedger); diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 4c57195192..f30ef3f4d6 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -18,8 +18,6 @@ #include "Interpreter.h" #include "Contract.h" -// Small for testing, should likely be 32 or 64. -#define DIR_NODE_MAX 2 #define RIPPLE_PATHS_MAX 3 static STAmount saZero(CURRENCY_ONE, ACCOUNT_ONE, 0); @@ -36,97 +34,6 @@ std::size_t hash_value(const aciSource& asValue) return seed; } -bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman) -{ - static struct { - TER terCode; - const char* cpToken; - const char* cpHuman; - } transResultInfoA[] = { - { tefALREADY, "tefALREADY", "The exact transaction was already in this ledger" }, - { tefBAD_ADD_AUTH, "tefBAD_ADD_AUTH", "Not authorized to add account." }, - { tefBAD_AUTH, "tefBAD_AUTH", "Transaction's public key is not authorized." }, - { tefBAD_CLAIM_ID, "tefBAD_CLAIM_ID", "Malformed." }, - { tefBAD_GEN_AUTH, "tefBAD_GEN_AUTH", "Not authorized to claim generator." }, - { tefBAD_LEDGER, "tefBAD_LEDGER", "Ledger in unexpected state." }, - { tefCLAIMED, "tefCLAIMED", "Can not claim a previously claimed account." }, - { tefEXCEPTION, "tefEXCEPTION", "Unexpected program state." }, - { tefCREATED, "tefCREATED", "Can't add an already created account." }, - { tefGEN_IN_USE, "tefGEN_IN_USE", "Generator already in use." }, - { tefPAST_SEQ, "tefPAST_SEQ", "This sequence number has already past" }, - - { telBAD_PATH_COUNT, "telBAD_PATH_COUNT", "Malformed: too many paths." }, - { telINSUF_FEE_P, "telINSUF_FEE_P", "Fee insufficient." }, - - { temBAD_AMOUNT, "temBAD_AMOUNT", "Can only send positive amounts." }, - { temBAD_AUTH_MASTER, "temBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." }, - { temBAD_EXPIRATION, "temBAD_EXPIRATION", "Malformed." }, - { temBAD_ISSUER, "temBAD_ISSUER", "Malformed." }, - { temBAD_OFFER, "temBAD_OFFER", "Malformed." }, - { temBAD_PATH, "temBAD_PATH", "Malformed." }, - { temBAD_PATH_LOOP, "temBAD_PATH_LOOP", "Malformed." }, - { temBAD_PUBLISH, "temBAD_PUBLISH", "Malformed: bad publish." }, - { temBAD_SET_ID, "temBAD_SET_ID", "Malformed." }, - { temCREATEXNS, "temCREATEXNS", "Can not specify non XNS for Create." }, - { temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." }, - { temDST_NEEDED, "temDST_NEEDED", "Destination not specified." }, - { temINSUF_FEE_P, "temINSUF_FEE_P", "Fee not allowed." }, - { temINVALID, "temINVALID", "The transaction is ill-formed" }, - { temREDUNDANT, "temREDUNDANT", "Sends same currency to self." }, - { temRIPPLE_EMPTY, "temRIPPLE_EMPTY", "PathSet with no paths." }, - { temUNCERTAIN, "temUNCERTAIN", "In process of determining result. Never returned." }, - { temUNKNOWN, "temUNKNOWN", "The transactions requires logic not implemented yet." }, - - { tepPATH_DRY, "tepPATH_DRY", "Path could not send partial amount." }, - { tepPATH_PARTIAL, "tepPATH_PARTIAL", "Path could not send full amount." }, - - { terDIR_FULL, "terDIR_FULL", "Can not add entry to full dir." }, - { terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." }, - { terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee." }, - { terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist." }, - { terNO_DST, "terNO_DST", "The destination does not exist" }, - { terNO_LINE, "terNO_LINE", "No such line." }, - { terNO_LINE_NO_ZERO, "terNO_LINE_NO_ZERO", "Can't zero non-existant line, destination might make it." }, - { terOFFER_NOT_FOUND, "terOFFER_NOT_FOUND", "Can not cancel offer." }, - { terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction" }, - { terSET_MISSING_DST, "terSET_MISSING_DST", "Can't set password, destination missing." }, - { terUNFUNDED, "terUNFUNDED", "Source account had insufficient balance for transaction." }, - - { tesSUCCESS, "tesSUCCESS", "The transaction was applied" }, - }; - - int iIndex = NUMBER(transResultInfoA); - - while (iIndex-- && transResultInfoA[iIndex].terCode != terCode) - ; - - if (iIndex >= 0) - { - strToken = transResultInfoA[iIndex].cpToken; - strHuman = transResultInfoA[iIndex].cpHuman; - } - - return iIndex >= 0; -} - -static std::string transToken(TER terCode) -{ - std::string strToken; - std::string strHuman; - - return transResultInfo(terCode, strToken, strHuman) ? strToken : "-"; -} - -#if 0 -static std::string transHuman(TER terCode) -{ - std::string strToken; - std::string strHuman; - - return transResultInfo(terCode, strToken, strHuman) ? strHuman : "-"; -} -#endif - // Returns amount owed by uToAccountID to uFromAccountID. // <-- $owed/uCurrencyID/uToAccountID: positive: uFromAccountID holds IOUs., negative: uFromAccountID owes IOUs. STAmount TransactionEngine::rippleOwed(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) @@ -468,14 +375,14 @@ void TransactionEngine::accountSend(const uint160& uSenderID, const uint160& uRe TER TransactionEngine::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); + TER terResult = mNodes.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); + terResult = mNodes.dirDelete(false, uBookNode, uDirectory, uOfferIndex, true); } entryDelete(sleOffer); @@ -491,328 +398,6 @@ TER TransactionEngine::offerDelete(const uint256& uOfferIndex) return offerDelete(sleOffer, uOfferIndex, uOwnerID); } -// <-- uNodeDir: For deletion, present to make dirDelete efficient. -// --> uRootIndex: The index of the base of the directory. Nodes are based off of this. -// --> uLedgerIndex: Value to add to directory. -// We only append. This allow for things that watch append only structure to just monitor from the last node on ward. -// Within a node with no deletions order of elements is sequential. Otherwise, order of elements is random. -TER TransactionEngine::dirAdd( - uint64& uNodeDir, - const uint256& uRootIndex, - const uint256& uLedgerIndex) -{ - SLE::pointer sleNode; - STVector256 svIndexes; - SLE::pointer sleRoot = entryCache(ltDIR_NODE, uRootIndex); - - if (!sleRoot) - { - // No root, make it. - sleRoot = entryCreate(ltDIR_NODE, uRootIndex); - - sleNode = sleRoot; - uNodeDir = 0; - } - else - { - uNodeDir = sleRoot->getIFieldU64(sfIndexPrevious); // Get index to last directory node. - - if (uNodeDir) - { - // Try adding to last node. - sleNode = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeDir)); - - assert(sleNode); - } - else - { - // Try adding to root. Didn't have a previous set to the last node. - sleNode = sleRoot; - } - - svIndexes = sleNode->getIFieldV256(sfIndexes); - - if (DIR_NODE_MAX != svIndexes.peekValue().size()) - { - // Add to current node. - entryModify(sleNode); - } - // Add to new node. - else if (!++uNodeDir) - { - return terDIR_FULL; - } - else - { - // Have old last point to new node, if it was not root. - if (uNodeDir == 1) - { - // Previous node is root node. - - sleRoot->setIFieldU64(sfIndexNext, uNodeDir); - } - else - { - // Previous node is not root node. - - SLE::pointer slePrevious = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeDir-1)); - - slePrevious->setIFieldU64(sfIndexNext, uNodeDir); - entryModify(slePrevious); - - sleNode->setIFieldU64(sfIndexPrevious, uNodeDir-1); - } - - // Have root point to new node. - sleRoot->setIFieldU64(sfIndexPrevious, uNodeDir); - entryModify(sleRoot); - - // Create the new node. - sleNode = entryCreate(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeDir)); - svIndexes = STVector256(); - } - } - - svIndexes.peekValue().push_back(uLedgerIndex); // Append entry. - sleNode->setIFieldV256(sfIndexes, svIndexes); // Save entry. - - Log(lsINFO) << "dirAdd: creating: root: " << uRootIndex.ToString(); - Log(lsINFO) << "dirAdd: appending: Entry: " << uLedgerIndex.ToString(); - Log(lsINFO) << "dirAdd: appending: Node: " << strHex(uNodeDir); - // Log(lsINFO) << "dirAdd: appending: PREV: " << svIndexes.peekValue()[0].ToString(); - - return tesSUCCESS; -} - -// Ledger must be in a state for this to work. -TER TransactionEngine::dirDelete( - const bool bKeepRoot, // --> True, if we never completely clean up, after we overflow the root node. - const uint64& uNodeDir, // --> Node containing entry. - const uint256& uRootIndex, // --> The index of the base of the directory. Nodes are based off of this. - const uint256& uLedgerIndex, // --> Value to add to directory. - const bool bStable) // --> True, not to change relative order of entries. -{ - uint64 uNodeCur = uNodeDir; - SLE::pointer sleNode = entryCache(ltDIR_NODE, uNodeCur ? Ledger::getDirNodeIndex(uRootIndex, uNodeCur) : uRootIndex); - - assert(sleNode); - - if (!sleNode) - { - Log(lsWARNING) << "dirDelete: no such node"; - - return tefBAD_LEDGER; - } - - STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes); - std::vector& vuiIndexes = svIndexes.peekValue(); - std::vector::iterator it; - - it = std::find(vuiIndexes.begin(), vuiIndexes.end(), uLedgerIndex); - - assert(vuiIndexes.end() != it); - if (vuiIndexes.end() == it) - { - assert(false); - - Log(lsWARNING) << "dirDelete: no such entry"; - - return tefBAD_LEDGER; - } - - // Remove the element. - if (vuiIndexes.size() > 1) - { - if (bStable) - { - vuiIndexes.erase(it); - } - else - { - *it = vuiIndexes[vuiIndexes.size()-1]; - vuiIndexes.resize(vuiIndexes.size()-1); - } - } - else - { - vuiIndexes.clear(); - } - - sleNode->setIFieldV256(sfIndexes, svIndexes); - entryModify(sleNode); - - if (vuiIndexes.empty()) - { - // May be able to delete nodes. - uint64 uNodePrevious = sleNode->getIFieldU64(sfIndexPrevious); - uint64 uNodeNext = sleNode->getIFieldU64(sfIndexNext); - - if (!uNodeCur) - { - // Just emptied root node. - - if (!uNodePrevious) - { - // Never overflowed the root node. Delete it. - entryDelete(sleNode); - } - // Root overflowed. - else if (bKeepRoot) - { - // If root overflowed and not allowed to delete overflowed root node. - - nothing(); - } - else if (uNodePrevious != uNodeNext) - { - // Have more than 2 nodes. Can't delete root node. - - nothing(); - } - else - { - // Have only a root node and a last node. - SLE::pointer sleLast = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeNext)); - - assert(sleLast); - - if (sleLast->getIFieldV256(sfIndexes).peekValue().empty()) - { - // Both nodes are empty. - - entryDelete(sleNode); // Delete root. - entryDelete(sleLast); // Delete last. - } - else - { - // Have an entry, can't delete root node. - - nothing(); - } - } - } - // Just emptied a non-root node. - else if (uNodeNext) - { - // Not root and not last node. Can delete node. - - SLE::pointer slePrevious = entryCache(ltDIR_NODE, uNodePrevious ? Ledger::getDirNodeIndex(uRootIndex, uNodePrevious) : uRootIndex); - - assert(slePrevious); - - SLE::pointer sleNext = entryCache(ltDIR_NODE, uNodeNext ? Ledger::getDirNodeIndex(uRootIndex, uNodeNext) : uRootIndex); - - assert(slePrevious); - assert(sleNext); - - if (!slePrevious) - { - Log(lsWARNING) << "dirDelete: previous node is missing"; - - return tefBAD_LEDGER; - } - - if (!sleNext) - { - Log(lsWARNING) << "dirDelete: next node is missing"; - - return tefBAD_LEDGER; - } - - // Fix previous to point to its new next. - slePrevious->setIFieldU64(sfIndexNext, uNodeNext); - entryModify(slePrevious); - - // Fix next to point to its new previous. - sleNext->setIFieldU64(sfIndexPrevious, uNodePrevious); - entryModify(sleNext); - } - // Last node. - else if (bKeepRoot || uNodePrevious) - { - // Not allowed to delete last node as root was overflowed. - // Or, have pervious entries preventing complete delete. - - nothing(); - } - else - { - // Last and only node besides the root. - SLE::pointer sleRoot = entryCache(ltDIR_NODE, uRootIndex); - - assert(sleRoot); - - if (sleRoot->getIFieldV256(sfIndexes).peekValue().empty()) - { - // Both nodes are empty. - - entryDelete(sleRoot); // Delete root. - entryDelete(sleNode); // Delete last. - } - else - { - // Root has an entry, can't delete. - - nothing(); - } - } - } - - return tesSUCCESS; -} - -// Return the first entry and advance uDirEntry. -// <-- true, if had a next entry. -bool TransactionEngine::dirFirst( - const uint256& uRootIndex, // --> Root of directory. - SLE::pointer& sleNode, // <-- current node - unsigned int& uDirEntry, // <-- next entry - uint256& uEntryIndex) // <-- The entry, if available. Otherwise, zero. -{ - sleNode = entryCache(ltDIR_NODE, uRootIndex); - uDirEntry = 0; - - assert(sleNode); // We never probe for directories. - - return TransactionEngine::dirNext(uRootIndex, sleNode, uDirEntry, uEntryIndex); -} - -// Return the current entry and advance uDirEntry. -// <-- true, if had a next entry. -bool TransactionEngine::dirNext( - const uint256& uRootIndex, // --> Root of directory - SLE::pointer& sleNode, // <-> current node - unsigned int& uDirEntry, // <-> next entry - uint256& uEntryIndex) // <-- The entry, if available. Otherwise, zero. -{ - STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes); - std::vector& vuiIndexes = svIndexes.peekValue(); - - if (uDirEntry == vuiIndexes.size()) - { - uint64 uNodeNext = sleNode->getIFieldU64(sfIndexNext); - - if (!uNodeNext) - { - uEntryIndex.zero(); - - return false; - } - else - { - sleNode = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeNext)); - uDirEntry = 0; - - return dirNext(uRootIndex, sleNode, uDirEntry, uEntryIndex); - } - } - - uEntryIndex = vuiIndexes[uDirEntry++]; -Log(lsINFO) << boost::str(boost::format("dirNext: uDirEntry=%d uEntryIndex=%s") % uDirEntry % uEntryIndex); - - return true; -} - // Set the authorized public key for an account. May also set the generator map. TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator) { @@ -1624,10 +1209,10 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) uint64 uSrcRef; // Ignored, dirs never delete. - terResult = dirAdd(uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex()); + terResult = mNodes.dirAdd(uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex()); if (tesSUCCESS == terResult) - terResult = dirAdd(uSrcRef, Ledger::getOwnerDirIndex(uDstAccountID), sleRippleState->getIndex()); + terResult = mNodes.dirAdd(uSrcRef, Ledger::getOwnerDirIndex(uDstAccountID), sleRippleState->getIndex()); } Log(lsINFO) << "doCreditSet<"; @@ -1846,7 +1431,7 @@ TER TransactionEngine::calcNodeAdvance( nothing(); } } - else if (!dirNext(uDirectTip, sleDirectDir, uEntry, uOfferIndex)) + else if (!mNodes.dirNext(uDirectTip, sleDirectDir, uEntry, uOfferIndex)) { // Failed to find an entry in directory. @@ -3965,7 +3550,7 @@ TER TransactionEngine::takeOffers( unsigned int uBookEntry; uint256 uOfferIndex; - dirFirst(uTipIndex, sleBookNode, uBookEntry, uOfferIndex); + mNodes.dirFirst(uTipIndex, sleBookNode, uBookEntry, uOfferIndex); SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); @@ -4255,7 +3840,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); // We need to place the remainder of the offer into its order book. // Add offer to owner's directory. - terResult = dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex); + terResult = mNodes.dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex); if (tesSUCCESS == terResult) { @@ -4271,7 +3856,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); uDirectory = Ledger::getQualityIndex(uBookBase, uRate); // Use original rate. // Add offer to order book. - terResult = dirAdd(uBookNode, uDirectory, uLedgerIndex); + terResult = mNodes.dirAdd(uBookNode, uDirectory, uLedgerIndex); } if (tesSUCCESS == terResult) @@ -4418,7 +4003,7 @@ void TransactionEngine::calcOfferBridgeNext( uint256 uOfferIndex; // Get uOfferIndex. - dirNext(uBookRoot, uBookEnd, uBookDirIndex, uBookDirNode, uBookDirEntry, uOfferIndex); + mNodes.dirNext(uBookRoot, uBookEnd, uBookDirIndex, uBookDirNode, uBookDirEntry, uOfferIndex); SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); @@ -4733,8 +4318,8 @@ TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) Log(lsWARNING) << "doContractAdd> " << txn.getJson(0); const uint32 expiration = txn.getITFieldU32(sfExpiration); - const uint32 bondAmount = txn.getITFieldU32(sfBondAmount); - const uint32 stampEscrow = txn.getITFieldU32(sfStampEscrow); +// const uint32 bondAmount = txn.getITFieldU32(sfBondAmount); +// const uint32 stampEscrow = txn.getITFieldU32(sfStampEscrow); STAmount rippleEscrow = txn.getITFieldAmount(sfRippleEscrow); std::vector createCode = txn.getITFieldVL(sfCreateCode); std::vector fundCode = txn.getITFieldVL(sfFundCode); diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index b164ea2b01..b57b76b89e 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -10,120 +10,11 @@ #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 TER // aka TransactionEngineResult -{ - // Note: Range is stable. Exact numbers are currently unstable. Use tokens. - - // -399 .. -300: L Local error (transaction fee inadequate, exceeds local limit) - // Only valid during non-consensus processing. - // Implications: - // - Not forwarded - // - No fee check - telLOCAL_ERROR = -399, - telBAD_PATH_COUNT, - telINSUF_FEE_P, - - // -299 .. -200: M Malformed (bad signature) - // Causes: - // - Transaction corrupt. - // Implications: - // - Not applied - // - Not forwarded - // - Reject - // - Can not succeed in any imagined ledger. - temMALFORMED = -299, - temBAD_AMOUNT, - temBAD_AUTH_MASTER, - temBAD_EXPIRATION, - temBAD_ISSUER, - temBAD_OFFER, - temBAD_PATH, - temBAD_PATH_LOOP, - temBAD_PUBLISH, - temBAD_SET_ID, - temCREATEXNS, - temDST_IS_SRC, - temDST_NEEDED, - temINSUF_FEE_P, - temINVALID, - temREDUNDANT, - temRIPPLE_EMPTY, - temUNCERTAIN, - temUNKNOWN, - - // -199 .. -100: F Failure (sequence number previously used) - // Causes: - // - Transaction cannot succeed because of ledger state. - // - Unexpected ledger state. - // - C++ exception. - // Implications: - // - Not applied - // - Not forwarded - // - Could succeed in an imagined ledger. - tefFAILURE = -199, - tefALREADY, - tefBAD_ADD_AUTH, - tefBAD_AUTH, - tefBAD_CLAIM_ID, - tefBAD_GEN_AUTH, - tefBAD_LEDGER, - tefCLAIMED, - tefCREATED, - tefEXCEPTION, - tefGEN_IN_USE, - tefPAST_SEQ, - - // -99 .. -1: R Retry (sequence too high, no funds for txn fee, originating account non-existent) - // Causes: - // - Priror application of another, possibly non-existant, transaction could allow this transaction to succeed. - // Implications: - // - Not applied - // - Not forwarded - // - Might succeed later - // - Hold - terRETRY = -99, - terDIR_FULL, - terFUNDS_SPENT, - terINSUF_FEE_B, - terNO_ACCOUNT, - terNO_DST, - terNO_LINE, - terNO_LINE_NO_ZERO, - terOFFER_NOT_FOUND, // XXX If we check sequence first this could be hard failure. - terPRE_SEQ, - terSET_MISSING_DST, - terUNFUNDED, - - // 0: S Success (success) - // Causes: - // - Success. - // Implications: - // - Applied - // - Forwarded - tesSUCCESS = 0, - - // 100 .. P Partial success (SR) (ripple transaction with no good paths, pay to non-existent account) - // Causes: - // - Success, but does not achieve optimal result. - // Implications: - // - Applied - // - Forwarded - // Only allowed as a return code of appliedTransaction when !tapRetry. Otherwise, treated as terRETRY. - tepPARTIAL = 100, - tepPATH_DRY, - tepPATH_PARTIAL, -}; - -#define isTemMalformed(x) ((x) >= temMALFORMED && (x) < tefFAILURE) -#define isTefFailure(x) ((x) >= tefFAILURE && (x) < terRETRY) -#define isTepPartial(x) ((x) >= tepPATH_PARTIAL) - -bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman); - enum TransactionEngineParams { tapNONE = 0x00, @@ -266,21 +157,6 @@ class TransactionEngine private: LedgerEntrySet mNodes; - TER dirAdd( - uint64& uNodeDir, // Node of entry. - const uint256& uRootIndex, - const uint256& uLedgerIndex); - - TER dirDelete( - const bool bKeepRoot, - const uint64& uNodeDir, // Node item is mentioned in. - const uint256& uRootIndex, - const uint256& uLedgerIndex, // Item being deleted - const bool bStable); - - 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); - TER setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator); TER takeOffers( diff --git a/src/TransactionErr.cpp b/src/TransactionErr.cpp new file mode 100644 index 0000000000..878d7cd1cd --- /dev/null +++ b/src/TransactionErr.cpp @@ -0,0 +1,91 @@ +#include "TransactionErr.h" +#include "utils.h" + +bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman) +{ + static struct { + TER terCode; + const char* cpToken; + const char* cpHuman; + } transResultInfoA[] = { + { tefALREADY, "tefALREADY", "The exact transaction was already in this ledger" }, + { tefBAD_ADD_AUTH, "tefBAD_ADD_AUTH", "Not authorized to add account." }, + { tefBAD_AUTH, "tefBAD_AUTH", "Transaction's public key is not authorized." }, + { tefBAD_CLAIM_ID, "tefBAD_CLAIM_ID", "Malformed." }, + { tefBAD_GEN_AUTH, "tefBAD_GEN_AUTH", "Not authorized to claim generator." }, + { tefBAD_LEDGER, "tefBAD_LEDGER", "Ledger in unexpected state." }, + { tefCLAIMED, "tefCLAIMED", "Can not claim a previously claimed account." }, + { tefEXCEPTION, "tefEXCEPTION", "Unexpected program state." }, + { tefCREATED, "tefCREATED", "Can't add an already created account." }, + { tefGEN_IN_USE, "tefGEN_IN_USE", "Generator already in use." }, + { tefPAST_SEQ, "tefPAST_SEQ", "This sequence number has already past" }, + + { telBAD_PATH_COUNT, "telBAD_PATH_COUNT", "Malformed: too many paths." }, + { telINSUF_FEE_P, "telINSUF_FEE_P", "Fee insufficient." }, + + { temBAD_AMOUNT, "temBAD_AMOUNT", "Can only send positive amounts." }, + { temBAD_AUTH_MASTER, "temBAD_AUTH_MASTER", "Auth for unclaimed account needs correct master key." }, + { temBAD_EXPIRATION, "temBAD_EXPIRATION", "Malformed." }, + { temBAD_ISSUER, "temBAD_ISSUER", "Malformed." }, + { temBAD_OFFER, "temBAD_OFFER", "Malformed." }, + { temBAD_PATH, "temBAD_PATH", "Malformed." }, + { temBAD_PATH_LOOP, "temBAD_PATH_LOOP", "Malformed." }, + { temBAD_PUBLISH, "temBAD_PUBLISH", "Malformed: bad publish." }, + { temBAD_SET_ID, "temBAD_SET_ID", "Malformed." }, + { temCREATEXNS, "temCREATEXNS", "Can not specify non XNS for Create." }, + { temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." }, + { temDST_NEEDED, "temDST_NEEDED", "Destination not specified." }, + { temINSUF_FEE_P, "temINSUF_FEE_P", "Fee not allowed." }, + { temINVALID, "temINVALID", "The transaction is ill-formed" }, + { temREDUNDANT, "temREDUNDANT", "Sends same currency to self." }, + { temRIPPLE_EMPTY, "temRIPPLE_EMPTY", "PathSet with no paths." }, + { temUNCERTAIN, "temUNCERTAIN", "In process of determining result. Never returned." }, + { temUNKNOWN, "temUNKNOWN", "The transactions requires logic not implemented yet." }, + + { tepPATH_DRY, "tepPATH_DRY", "Path could not send partial amount." }, + { tepPATH_PARTIAL, "tepPATH_PARTIAL", "Path could not send full amount." }, + + { terDIR_FULL, "terDIR_FULL", "Can not add entry to full dir." }, + { terFUNDS_SPENT, "terFUNDS_SPENT", "Can't set password, password set funds already spent." }, + { terINSUF_FEE_B, "terINSUF_FEE_B", "Account balance can't pay fee." }, + { terNO_ACCOUNT, "terNO_ACCOUNT", "The source account does not exist." }, + { terNO_DST, "terNO_DST", "The destination does not exist" }, + { terNO_LINE, "terNO_LINE", "No such line." }, + { terNO_LINE_NO_ZERO, "terNO_LINE_NO_ZERO", "Can't zero non-existant line, destination might make it." }, + { terOFFER_NOT_FOUND, "terOFFER_NOT_FOUND", "Can not cancel offer." }, + { terPRE_SEQ, "terPRE_SEQ", "Missing/inapplicable prior transaction" }, + { terSET_MISSING_DST, "terSET_MISSING_DST", "Can't set password, destination missing." }, + { terUNFUNDED, "terUNFUNDED", "Source account had insufficient balance for transaction." }, + + { tesSUCCESS, "tesSUCCESS", "The transaction was applied" }, + }; + + int iIndex = NUMBER(transResultInfoA); + + while (iIndex-- && transResultInfoA[iIndex].terCode != terCode) + ; + + if (iIndex >= 0) + { + strToken = transResultInfoA[iIndex].cpToken; + strHuman = transResultInfoA[iIndex].cpHuman; + } + + return iIndex >= 0; +} + +std::string transToken(TER terCode) +{ + std::string strToken; + std::string strHuman; + + return transResultInfo(terCode, strToken, strHuman) ? strToken : "-"; +} + +std::string transHuman(TER terCode) +{ + std::string strToken; + std::string strHuman; + + return transResultInfo(terCode, strToken, strHuman) ? strHuman : "-"; +} diff --git a/src/TransactionErr.h b/src/TransactionErr.h new file mode 100644 index 0000000000..4f0d5a7994 --- /dev/null +++ b/src/TransactionErr.h @@ -0,0 +1,118 @@ +#ifndef _TRANSACTION_ERR_ +#define _TRANSACTION_ERR_ + +#include + +enum TER // aka TransactionEngineResult +{ + // Note: Range is stable. Exact numbers are currently unstable. Use tokens. + + // -399 .. -300: L Local error (transaction fee inadequate, exceeds local limit) + // Only valid during non-consensus processing. + // Implications: + // - Not forwarded + // - No fee check + telLOCAL_ERROR = -399, + telBAD_PATH_COUNT, + telINSUF_FEE_P, + + // -299 .. -200: M Malformed (bad signature) + // Causes: + // - Transaction corrupt. + // Implications: + // - Not applied + // - Not forwarded + // - Reject + // - Can not succeed in any imagined ledger. + temMALFORMED = -299, + temBAD_AMOUNT, + temBAD_AUTH_MASTER, + temBAD_EXPIRATION, + temBAD_ISSUER, + temBAD_OFFER, + temBAD_PATH, + temBAD_PATH_LOOP, + temBAD_PUBLISH, + temBAD_SET_ID, + temCREATEXNS, + temDST_IS_SRC, + temDST_NEEDED, + temINSUF_FEE_P, + temINVALID, + temREDUNDANT, + temRIPPLE_EMPTY, + temUNCERTAIN, + temUNKNOWN, + + // -199 .. -100: F Failure (sequence number previously used) + // Causes: + // - Transaction cannot succeed because of ledger state. + // - Unexpected ledger state. + // - C++ exception. + // Implications: + // - Not applied + // - Not forwarded + // - Could succeed in an imagined ledger. + tefFAILURE = -199, + tefALREADY, + tefBAD_ADD_AUTH, + tefBAD_AUTH, + tefBAD_CLAIM_ID, + tefBAD_GEN_AUTH, + tefBAD_LEDGER, + tefCLAIMED, + tefCREATED, + tefEXCEPTION, + tefGEN_IN_USE, + tefPAST_SEQ, + + // -99 .. -1: R Retry (sequence too high, no funds for txn fee, originating account non-existent) + // Causes: + // - Priror application of another, possibly non-existant, transaction could allow this transaction to succeed. + // Implications: + // - Not applied + // - Not forwarded + // - Might succeed later + // - Hold + terRETRY = -99, + terDIR_FULL, + terFUNDS_SPENT, + terINSUF_FEE_B, + terNO_ACCOUNT, + terNO_DST, + terNO_LINE, + terNO_LINE_NO_ZERO, + terOFFER_NOT_FOUND, // XXX If we check sequence first this could be hard failure. + terPRE_SEQ, + terSET_MISSING_DST, + terUNFUNDED, + + // 0: S Success (success) + // Causes: + // - Success. + // Implications: + // - Applied + // - Forwarded + tesSUCCESS = 0, + + // 100 .. P Partial success (SR) (ripple transaction with no good paths, pay to non-existent account) + // Causes: + // - Success, but does not achieve optimal result. + // Implications: + // - Applied + // - Forwarded + // Only allowed as a return code of appliedTransaction when !tapRetry. Otherwise, treated as terRETRY. + tepPARTIAL = 100, + tepPATH_DRY, + tepPATH_PARTIAL, +}; + +#define isTemMalformed(x) ((x) >= temMALFORMED && (x) < tefFAILURE) +#define isTefFailure(x) ((x) >= tefFAILURE && (x) < terRETRY) +#define isTepPartial(x) ((x) >= tepPATH_PARTIAL) + +bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman); +std::string transToken(TER terCode); +std::string transHuman(TER terCode); + +#endif From b7f3baee15434483de8c1bb5f3cfa2a42f07cfcb Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sun, 9 Sep 2012 19:54:46 -0700 Subject: [PATCH 236/426] Split up TransactionEngine, part 1. --- src/LedgerEntrySet.cpp | 362 +++++ src/LedgerEntrySet.h | 26 +- src/RippleCalc.cpp | 2400 +++++++++++++++++++++++++++++++ src/RippleCalc.h | 190 +++ src/SerializedTypes.cpp | 3 + src/SerializedTypes.h | 3 + src/TransactionEngine.cpp | 2809 +------------------------------------ src/TransactionEngine.h | 186 +-- 8 files changed, 3027 insertions(+), 2952 deletions(-) create mode 100644 src/RippleCalc.cpp create mode 100644 src/RippleCalc.h diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index c5747b85b0..3c5adc432a 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -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 diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 256275b00e..6abef7cab3 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -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); diff --git a/src/RippleCalc.cpp b/src/RippleCalc.cpp new file mode 100644 index 0000000000..7b88303bc9 --- /dev/null +++ b/src/RippleCalc.cpp @@ -0,0 +1,2400 @@ + +#include +#include +#include + +#include "RippleCalc.h" +#include "Log.h" + +#include "../json/writer.h" + +std::size_t hash_value(const aciSource& asValue) +{ + std::size_t seed = 0; + + asValue.get<0>().hash_combine(seed); + asValue.get<1>().hash_combine(seed); + asValue.get<2>().hash_combine(seed); + + return seed; +} + +// If needed, advance to next funded offer. +// - Automatically advances to first offer. +// - Set bEntryAdvance to advance to next entry. +// <-- uOfferIndex : 0=end of list. +TER RippleCalc::calcNodeAdvance( + const unsigned int uIndex, // 0 < uIndex < uLast + const PathState::pointer& pspCur, + const bool bMultiQuality, + const bool bReverse) +{ + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + + const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; + const uint160& uPrvIssuerID = pnPrv.uIssuerID; + const uint160& uCurCurrencyID = pnCur.uCurrencyID; + const uint160& uCurIssuerID = pnCur.uIssuerID; + + uint256& uDirectTip = pnCur.uDirectTip; + uint256 uDirectEnd = pnCur.uDirectEnd; + bool& bDirectAdvance = pnCur.bDirectAdvance; + SLE::pointer& sleDirectDir = pnCur.sleDirectDir; + STAmount& saOfrRate = pnCur.saOfrRate; + + bool& bEntryAdvance = pnCur.bEntryAdvance; + unsigned int& uEntry = pnCur.uEntry; + uint256& uOfferIndex = pnCur.uOfferIndex; + SLE::pointer& sleOffer = pnCur.sleOffer; + uint160& uOfrOwnerID = pnCur.uOfrOwnerID; + STAmount& saOfferFunds = pnCur.saOfferFunds; + STAmount& saTakerPays = pnCur.saTakerPays; + STAmount& saTakerGets = pnCur.saTakerGets; + bool& bFundsDirty = pnCur.bFundsDirty; + + TER terResult = tesSUCCESS; + + do + { + bool bDirectDirDirty = false; + + if (!uDirectEnd) + { + // Need to initialize current node. + + uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); + uDirectEnd = Ledger::getQualityNext(uDirectTip); + sleDirectDir = lesActive.entryCache(ltDIR_NODE, uDirectTip); + bDirectAdvance = !sleDirectDir; + bDirectDirDirty = true; + + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: Initialize node: uDirectTip=%s uDirectEnd=%s bDirectAdvance=%d") % uDirectTip % uDirectEnd % bDirectAdvance); + } + + if (bDirectAdvance) + { + // Get next quality. + uDirectTip = lesActive.getLedger()->getNextLedgerIndex(uDirectTip, uDirectEnd); + bDirectDirDirty = true; + bDirectAdvance = false; + + if (!!uDirectTip) + { + // Have another quality directory. + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: Quality advance: uDirectTip=%s") % uDirectTip); + + sleDirectDir = lesActive.entryCache(ltDIR_NODE, uDirectTip); + } + else if (bReverse) + { + Log(lsINFO) << "calcNodeAdvance: No more offers."; + + uOfferIndex = 0; + break; + } + else + { + // No more offers. Should be done rather than fall off end of book. + Log(lsINFO) << "calcNodeAdvance: Unreachable: Fell off end of order book."; + assert(false); + + terResult = tefEXCEPTION; + } + } + + if (bDirectDirDirty) + { + saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio + uEntry = 0; + bEntryAdvance = true; + + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: directory dirty: saOfrRate=%s") % saOfrRate); + } + + if (!bEntryAdvance) + { + if (bFundsDirty) + { + saTakerPays = sleOffer->getIValueFieldAmount(sfTakerPays); + saTakerGets = sleOffer->getIValueFieldAmount(sfTakerGets); + + saOfferFunds = lesActive.accountFunds(uOfrOwnerID, saTakerGets); // Funds left. + bFundsDirty = false; + + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: directory dirty: saOfrRate=%s") % saOfrRate); + } + else + { + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: as is")); + nothing(); + } + } + else if (!lesActive.dirNext(uDirectTip, sleDirectDir, uEntry, uOfferIndex)) + { + // Failed to find an entry in directory. + + uOfferIndex = 0; + + // Do another cur directory iff bMultiQuality + if (bMultiQuality) + { + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: next quality")); + bDirectAdvance = true; + } + else if (!bReverse) + { + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: unreachable: ran out of offers")); + assert(false); // Can't run out of offers in forward direction. + terResult = tefEXCEPTION; + } + } + else + { + // Got a new offer. + sleOffer = lesActive.entryCache(ltOFFER, uOfferIndex); + uOfrOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + + const aciSource asLine = boost::make_tuple(uOfrOwnerID, uCurCurrencyID, uCurIssuerID); + + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: uOfrOwnerID=%s") % NewcoinAddress::createHumanAccountID(uOfrOwnerID)); + + if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= lesActive.getLedger()->getParentCloseTimeNC()) + { + // Offer is expired. + Log(lsINFO) << "calcNodeAdvance: expired offer"; + + assert(musUnfundedFound.find(uOfferIndex) != musUnfundedFound.end()); // Verify reverse found it too. + bEntryAdvance = true; + continue; + } + + // Allowed to access source from this node? + // XXX This can get called multiple times for same source in a row, caching result would be nice. + curIssuerNodeConstIterator itForward = pspCur->umForward.find(asLine); + const bool bFoundForward = itForward != pspCur->umForward.end(); + + if (bFoundForward && itForward->second != uIndex) + { + // Temporarily unfunded. Another node uses this source, ignore in this offer. + Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (forward)"; + + bEntryAdvance = true; + continue; + } + + curIssuerNodeConstIterator itPast = mumSource.find(asLine); + bool bFoundPast = itPast != mumSource.end(); + + if (bFoundPast && itPast->second != uIndex) + { + // Temporarily unfunded. Another node uses this source, ignore in this offer. + Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (past)"; + + bEntryAdvance = true; + continue; + } + + curIssuerNodeConstIterator itReverse = pspCur->umReverse.find(asLine); + bool bFoundReverse = itReverse != pspCur->umReverse.end(); + + if (bFoundReverse && itReverse->second != uIndex) + { + // Temporarily unfunded. Another node uses this source, ignore in this offer. + Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (reverse)"; + + bEntryAdvance = true; + continue; + } + + saTakerPays = sleOffer->getIValueFieldAmount(sfTakerPays); + saTakerGets = sleOffer->getIValueFieldAmount(sfTakerGets); + + saOfferFunds = lesActive.accountFunds(uOfrOwnerID, saTakerGets); // Funds left. + + if (!saOfferFunds.isPositive()) + { + // Offer is unfunded. + Log(lsINFO) << "calcNodeAdvance: unfunded offer"; + + if (bReverse && !bFoundReverse && !bFoundPast) + { + // Never mentioned before: found unfunded. + musUnfundedFound.insert(uOfferIndex); // Mark offer for always deletion. + } + + // YYY Could verify offer is correct place for unfundeds. + bEntryAdvance = true; + continue; + } + + if (bReverse // Need to remember reverse mention. + && !bFoundPast // Not mentioned in previous passes. + && !bFoundReverse) // Not mentioned for pass. + { + // Consider source mentioned by current path state. + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: remember=%s/%s/%s") + % NewcoinAddress::createHumanAccountID(uOfrOwnerID) + % STAmount::createHumanCurrency(uCurCurrencyID) + % NewcoinAddress::createHumanAccountID(uCurIssuerID)); + + pspCur->umReverse.insert(std::make_pair(asLine, uIndex)); + } + + bFundsDirty = false; + bEntryAdvance = false; + } + } + while (tesSUCCESS == terResult && (bEntryAdvance || bDirectAdvance)); + + if (tesSUCCESS == terResult) + { + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: uOfferIndex=%s") % uOfferIndex); + } + else + { + Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: terResult=%s") % transToken(terResult)); + } + + return terResult; +} + +// Between offer nodes, the fee charged may vary. Therefore, process one inbound offer at a time. +// Propagate the inbound offer's requirements to the previous node. The previous node adjusts the amount output and the +// amount spent on fees. +// Continue process till request is satisified while we the rate does not increase past the initial rate. +TER RippleCalc::calcNodeDeliverRev( + const unsigned int uIndex, // 0 < uIndex < uLast + const PathState::pointer& pspCur, + const bool bMultiQuality, + const uint160& uOutAccountID, // --> Output owner's account. + const STAmount& saOutReq, // --> Funds wanted. + STAmount& saOutAct) // <-- Funds delivered. +{ + TER terResult = tesSUCCESS; + + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + + const uint160& uCurIssuerID = pnCur.uIssuerID; + const uint160& uPrvAccountID = pnPrv.uAccountID; + const STAmount& saTransferRate = pnCur.saTransferRate; + + STAmount& saPrvDlvReq = pnPrv.saRevDeliver; // To be adjusted. + + saOutAct = 0; + + while (saOutAct != saOutReq) // Did not deliver limit. + { + bool& bEntryAdvance = pnCur.bEntryAdvance; + STAmount& saOfrRate = pnCur.saOfrRate; + uint256& uOfferIndex = pnCur.uOfferIndex; + SLE::pointer& sleOffer = pnCur.sleOffer; + const uint160& uOfrOwnerID = pnCur.uOfrOwnerID; + bool& bFundsDirty = pnCur.bFundsDirty; + STAmount& saOfferFunds = pnCur.saOfferFunds; + STAmount& saTakerPays = pnCur.saTakerPays; + STAmount& saTakerGets = pnCur.saTakerGets; + STAmount& saRateMax = pnCur.saRateMax; + + terResult = calcNodeAdvance(uIndex, pspCur, bMultiQuality, true); // If needed, advance to next funded offer. + + if (tesSUCCESS != terResult || !uOfferIndex) + { + // Error or out of offers. + break; + } + + const STAmount saOutFeeRate = uOfrOwnerID == uCurIssuerID || uOutAccountID == uCurIssuerID // Issuer receiving or sending. + ? saOne // No fee. + : saTransferRate; // Transfer rate of issuer. + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: uOfrOwnerID=%s uOutAccountID=%s uCurIssuerID=%s saTransferRate=%s saOutFeeRate=%s") + % NewcoinAddress::createHumanAccountID(uOfrOwnerID) + % NewcoinAddress::createHumanAccountID(uOutAccountID) + % NewcoinAddress::createHumanAccountID(uCurIssuerID) + % saTransferRate.getFullText() + % saOutFeeRate.getFullText()); + + if (!saRateMax) + { + // Set initial rate. + saRateMax = saOutFeeRate; + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Set initial rate: saRateMax=%s saOutFeeRate=%s") + % saRateMax + % saOutFeeRate); + } + else if (saRateMax < saOutFeeRate) + { + // Offer exceeds initial rate. + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Offer exceeds initial rate: saRateMax=%s saOutFeeRate=%s") + % saRateMax + % saOutFeeRate); + + nothing(); + break; + } + else if (saOutFeeRate < saRateMax) + { + // Reducing rate. + + saRateMax = saOutFeeRate; + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Reducing rate: saRateMax=%s") + % saRateMax); + } + + STAmount saOutPass = std::min(std::min(saOfferFunds, saTakerGets), saOutReq-saOutAct); // Offer maximum out - assuming no out fees. + STAmount saOutPlusFees = STAmount::multiply(saOutPass, saOutFeeRate); // Offer out with fees. + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: saOutReq=%s saOutAct=%s saTakerGets=%s saOutPass=%s saOutPlusFees=%s saOfferFunds=%s") + % saOutReq + % saOutAct + % saTakerGets + % saOutPass + % saOutPlusFees + % saOfferFunds); + + if (saOutPlusFees > saOfferFunds) + { + // Offer owner can not cover all fees, compute saOutPass based on saOfferFunds. + + saOutPlusFees = saOfferFunds; + saOutPass = STAmount::divide(saOutPlusFees, saOutFeeRate); + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Total exceeds fees: saOutPass=%s saOutPlusFees=%s saOfferFunds=%s") + % saOutPass + % saOutPlusFees + % saOfferFunds); + } + + // Compute portion of input needed to cover output. + + STAmount saInPassReq = STAmount::multiply(saOutPass, saOfrRate, saTakerPays); + STAmount saInPassAct; + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: saInPassReq=%s saOfrRate=%s saOutPass=%s saOutPlusFees=%s") + % saInPassReq + % saOfrRate + % saOutPass + % saOutPlusFees); + + // Find out input amount actually available at current rate. + if (!!uPrvAccountID) + { + // account --> OFFER --> ? + // Previous is the issuer and receiver is an offer, so no fee or quality. + // Previous is the issuer and has unlimited funds. + // Offer owner is obtaining IOUs via an offer, so credit line limits are ignored. + // As limits are ignored, don't need to adjust previous account's balance. + + saInPassAct = saInPassReq; + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: account --> OFFER --> ? : saInPassAct=%s") + % saPrvDlvReq); + } + else + { + // offer --> OFFER --> ? + + terResult = calcNodeDeliverRev( + uIndex-1, + pspCur, + bMultiQuality, + uOfrOwnerID, + saInPassReq, + saInPassAct); + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: offer --> OFFER --> ? : saInPassAct=%s") + % saInPassAct); + } + + if (tesSUCCESS != terResult) + break; + + if (saInPassAct != saInPassReq) + { + // Adjust output to conform to limited input. + saOutPass = STAmount::divide(saInPassAct, saOfrRate, saTakerGets); + saOutPlusFees = STAmount::multiply(saOutPass, saOutFeeRate); + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: adjusted: saOutPass=%s saOutPlusFees=%s") + % saOutPass + % saOutPlusFees); + } + + // Funds were spent. + bFundsDirty = true; + + // Deduct output, don't actually need to send. + lesActive.accountSend(uOfrOwnerID, uCurIssuerID, saOutPass); + + // Adjust offer + sleOffer->setIFieldAmount(sfTakerGets, saTakerGets - saOutPass); + sleOffer->setIFieldAmount(sfTakerPays, saTakerPays - saInPassAct); + + lesActive.entryModify(sleOffer); + + if (saOutPass == saTakerGets) + { + // Offer became unfunded. + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: offer became unfunded.")); + + bEntryAdvance = true; + } + + saOutAct += saOutPass; + saPrvDlvReq += saInPassAct; + } + + if (!saOutAct) + terResult = tepPATH_DRY; + + return terResult; +} + +// Deliver maximum amount of funds from previous node. +// Goal: Make progress consuming the offer. +TER RippleCalc::calcNodeDeliverFwd( + const unsigned int uIndex, // 0 < uIndex < uLast + const PathState::pointer& 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. + STAmount& saInAct, // <-- Amount delivered. + STAmount& saInFees) // <-- Fees charged. +{ + TER terResult = tesSUCCESS; + + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; + + const uint160& uNxtAccountID = pnNxt.uAccountID; + const uint160& uCurIssuerID = pnCur.uIssuerID; + const uint160& uPrvIssuerID = pnPrv.uIssuerID; + const STAmount& saTransferRate = pnPrv.saTransferRate; + + saInAct = 0; + saInFees = 0; + + while (tesSUCCESS == terResult + && saInAct != saInReq // Did not deliver limit. + && saInAct + saInFees != saInFunds) // Did not deliver all funds. + { + terResult = calcNodeAdvance(uIndex, pspCur, bMultiQuality, false); // If needed, advance to next funded offer. + + if (tesSUCCESS == terResult) + { + bool& bEntryAdvance = pnCur.bEntryAdvance; + STAmount& saOfrRate = pnCur.saOfrRate; + uint256& uOfferIndex = pnCur.uOfferIndex; + SLE::pointer& sleOffer = pnCur.sleOffer; + const uint160& uOfrOwnerID = pnCur.uOfrOwnerID; + bool& bFundsDirty = pnCur.bFundsDirty; + STAmount& saOfferFunds = pnCur.saOfferFunds; + 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. + + // + // First calculate assuming no output fees. + // XXX Make sure derived in does not exceed actual saTakerPays due to rounding. + + 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 saInPassAct = STAmount::divide(saInSum, saInFeeRate); // In without fees. + STAmount saOutPassMax = STAmount::divide(saInPassAct, saOfrRate, saOutFunded); // Out. + + STAmount saInPassFees; + STAmount saOutPassAct; + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: saOutFunded=%s saInFunded=%s saInTotal=%s saInSum=%s saInPassAct=%s saOutPassMax=%s") + % saOutFunded + % saInFunded + % saInTotal + % saInSum + % saInPassAct + % saOutPassMax); + + if (!!uNxtAccountID) + { + // ? --> 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); + + saOutPassAct = saOutPassMax; + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: ? --> OFFER --> account: saOutPassAct=%s") + % saOutPassAct); + } + else + { + // ? --> OFFER --> offer + STAmount saOutPassFees; + + terResult = RippleCalc::calcNodeDeliverFwd( + uIndex+1, + pspCur, + bMultiQuality, + uOfrOwnerID, + saOutPassMax, + saOutPassMax, + saOutPassAct, // <-- Amount delivered. + saOutPassFees); // <-- Fees charged. + + if (tesSUCCESS != terResult) + break; + + // Offer maximum in limited by next payout. + saInPassAct = STAmount::multiply(saOutPassAct, saOfrRate); + saInPassFees = STAmount::multiply(saInFunded, saInFeeRate)-saInPassAct; + } + + Log(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: saTakerGets=%s saTakerPays=%s saInPassAct=%s saOutPassAct=%s") + % saTakerGets.getFullText() + % saTakerPays.getFullText() + % saInPassAct.getFullText() + % saOutPassAct.getFullText()); + + // Funds were spent. + bFundsDirty = true; + + // Credit issuer transfer fees. + lesActive.accountSend(uInAccountID, uOfrOwnerID, saInPassFees); + + // Credit offer owner from offer. + lesActive.accountSend(uInAccountID, uOfrOwnerID, saInPassAct); + + // Adjust offer + sleOffer->setIFieldAmount(sfTakerGets, saTakerGets - saOutPassAct); + sleOffer->setIFieldAmount(sfTakerPays, saTakerPays - saInPassAct); + + lesActive.entryModify(sleOffer); + + if (saOutPassAct == saTakerGets) + { + // Offer became unfunded. + pspCur->vUnfundedBecame.push_back(uOfferIndex); + bEntryAdvance = true; + } + + saInAct += saInPassAct; + saInFees += saInPassFees; + } + } + + return terResult; +} + +// Called to drive from the last offer node in a chain. +TER RippleCalc::calcNodeOfferRev( + const unsigned int uIndex, // 0 < uIndex < uLast + const PathState::pointer& pspCur, + const bool bMultiQuality) +{ + TER terResult; + + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; + + if (!!pnNxt.uAccountID) + { + // Next is an account node, resolve current offer node's deliver. + STAmount saDeliverAct; + + terResult = calcNodeDeliverRev( + uIndex, + pspCur, + bMultiQuality, + + pnNxt.uAccountID, + pnCur.saRevDeliver, + saDeliverAct); + } + else + { + // Next is an offer. Deliver has already been resolved. + terResult = tesSUCCESS; + } + + return terResult; +} + +// Called to drive the from the first offer node in a chain. +// - Offer input is limbo. +// - Current offers consumed. +// - Current offer owners debited. +// - Transfer fees credited to issuer. +// - Payout to issuer or limbo. +// - Deliver is set without transfer fees. +TER RippleCalc::calcNodeOfferFwd( + const unsigned int uIndex, // 0 < uIndex < uLast + const PathState::pointer& pspCur, + const bool bMultiQuality + ) +{ + TER terResult; + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; + + if (!!pnPrv.uAccountID) + { + // Previous is an account node, resolve its deliver. + STAmount saInAct; + STAmount saInFees; + + terResult = calcNodeDeliverFwd( + uIndex, + pspCur, + bMultiQuality, + pnPrv.uAccountID, + pnPrv.saFwdDeliver, + pnPrv.saFwdDeliver, + saInAct, + saInFees); + + assert(tesSUCCESS != terResult || pnPrv.saFwdDeliver == saInAct+saInFees); + } + else + { + // Previous is an offer. Deliver has already been resolved. + terResult = tesSUCCESS; + } + + return terResult; + +} + +// Cur is the driver and will be filled exactly. +// uQualityIn -> uQualityOut +// saPrvReq -> saCurReq +// sqPrvAct -> saCurAct +// This is a minimizing routine: moving in reverse it propagates the send limit to the sender, moving forward it propagates the +// actual send toward the receiver. +// This routine works backwards as it calculates previous wants based on previous credit limits and current wants. +// This routine works forwards as it calculates current deliver based on previous delivery limits and current wants. +// XXX Deal with uQualityIn or uQualityOut = 0 +void RippleCalc::calcNodeRipple( + const uint32 uQualityIn, + const uint32 uQualityOut, + const STAmount& saPrvReq, // --> in limit including fees, <0 = unlimited + const STAmount& saCurReq, // --> out limit (driver) + STAmount& saPrvAct, // <-> in limit including achieved + STAmount& saCurAct, // <-> out limit achieved. + uint64& uRateMax) +{ + Log(lsINFO) << boost::str(boost::format("calcNodeRipple> uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s") + % uQualityIn + % uQualityOut + % saPrvReq.getFullText() + % saCurReq.getFullText() + % saPrvAct.getFullText() + % saCurAct.getFullText()); + + assert(saPrvReq.getCurrency() == saCurReq.getCurrency()); + + const bool bPrvUnlimited = saPrvReq.isNegative(); + const STAmount saPrv = bPrvUnlimited ? STAmount(saPrvReq) : saPrvReq-saPrvAct; + const STAmount saCur = saCurReq-saCurAct; + +#if 0 + Log(lsINFO) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCur=%s") + % bPrvUnlimited + % saPrv.getFullText() + % saCur.getFullText()); +#endif + + if (uQualityIn >= uQualityOut) + { + // No fee. + Log(lsINFO) << boost::str(boost::format("calcNodeRipple: No fees")); + + if (!uRateMax || STAmount::uRateOne <= uRateMax) + { + STAmount saTransfer = bPrvUnlimited ? saCur : std::min(saPrv, saCur); + + saPrvAct += saTransfer; + saCurAct += saTransfer; + + if (!uRateMax) + uRateMax = STAmount::uRateOne; + } + } + else + { + // Fee. + Log(lsINFO) << boost::str(boost::format("calcNodeRipple: Fee")); + + uint64 uRate = STAmount::getRate(STAmount(uQualityIn), STAmount(uQualityOut)); + + if (!uRateMax || uRate <= uRateMax) + { + const uint160 uCurrencyID = saCur.getCurrency(); + const uint160 uCurIssuerID = saCur.getIssuer(); + const uint160 uPrvIssuerID = saPrv.getIssuer(); + + STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID, uCurIssuerID), uQualityIn, uCurrencyID, uCurIssuerID); + + Log(lsINFO) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCurIn=%s") % bPrvUnlimited % saPrv.getFullText() % saCurIn.getFullText()); + if (bPrvUnlimited || saCurIn <= saPrv) + { + // All of cur. Some amount of prv. + saCurAct += saCur; + saPrvAct += saCurIn; + Log(lsINFO) << boost::str(boost::format("calcNodeRipple:3c: saCurReq=%s saPrvAct=%s") % saCurReq.getFullText() % saPrvAct.getFullText()); + } + else + { + // A part of cur. All of prv. (cur as driver) + STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID, uCurIssuerID), uQualityOut, uCurrencyID, uCurIssuerID); + Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.getFullText()); + + saCurAct += saCurOut; + saPrvAct = saPrvReq; + + if (!uRateMax) + uRateMax = uRate; + } + } + } + + Log(lsINFO) << boost::str(boost::format("calcNodeRipple< uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s") + % uQualityIn + % uQualityOut + % saPrvReq.getFullText() + % saCurReq.getFullText() + % saPrvAct.getFullText() + % saCurAct.getFullText()); +} + +// Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver from saCur... +// <-- tesSUCCESS or tepPATH_DRY +TER RippleCalc::calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) +{ + TER terResult = tesSUCCESS; + const unsigned int uLast = pspCur->vpnNodes.size() - 1; + + uint64 uRateMax = 0; + + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; + + // Current is allowed to redeem to next. + const bool bPrvAccount = !uIndex || isSetBit(pnPrv.uFlags, STPathElement::typeAccount); + const bool bNxtAccount = uIndex == uLast || isSetBit(pnNxt.uFlags, STPathElement::typeAccount); + + const uint160& uCurAccountID = pnCur.uAccountID; + const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; + const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. + + const uint160& uCurrencyID = pnCur.uCurrencyID; + + const uint32 uQualityIn = uIndex ? lesActive.rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; + const uint32 uQualityOut = uIndex != uLast ? lesActive.rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; + + // For bPrvAccount + const STAmount saPrvOwed = bPrvAccount && uIndex // Previous account is owed. + ? lesActive.rippleOwed(uCurAccountID, uPrvAccountID, uCurrencyID) + : STAmount(uCurrencyID, uCurAccountID); + + const STAmount saPrvLimit = bPrvAccount && uIndex // Previous account may owe. + ? lesActive.rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) + : STAmount(uCurrencyID, uCurAccountID); + + const STAmount saNxtOwed = bNxtAccount && uIndex != uLast // Next account is owed. + ? lesActive.rippleOwed(uCurAccountID, uNxtAccountID, uCurrencyID) + : STAmount(uCurrencyID, uCurAccountID); + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s") + % uIndex + % uLast + % NewcoinAddress::createHumanAccountID(uPrvAccountID) + % NewcoinAddress::createHumanAccountID(uCurAccountID) + % NewcoinAddress::createHumanAccountID(uNxtAccountID) + % STAmount::createHumanCurrency(uCurrencyID) + % uQualityIn + % uQualityOut + % saPrvOwed.getFullText() + % saPrvLimit.getFullText()); + + // Previous can redeem the owed IOUs it holds. + const STAmount saPrvRedeemReq = saPrvOwed.isPositive() ? saPrvOwed : STAmount(uCurrencyID, 0); + STAmount& saPrvRedeemAct = pnPrv.saRevRedeem; + + // Previous can issue up to limit minus whatever portion of limit already used (not including redeemable amount). + const STAmount saPrvIssueReq = saPrvOwed.isNegative() ? saPrvLimit+saPrvOwed : saPrvLimit; + STAmount& saPrvIssueAct = pnPrv.saRevIssue; + + // For !bPrvAccount + const STAmount saPrvDeliverReq = STAmount::saFromSigned(uCurrencyID, uCurAccountID, -1); // Unlimited. + STAmount& saPrvDeliverAct = pnPrv.saRevDeliver; + + // For bNxtAccount + const STAmount& saCurRedeemReq = pnCur.saRevRedeem; + STAmount saCurRedeemAct(saCurRedeemReq.getCurrency(), saCurRedeemReq.getIssuer()); + + const STAmount& saCurIssueReq = pnCur.saRevIssue; + STAmount saCurIssueAct(saCurIssueReq.getCurrency(), saCurIssueReq.getIssuer()); // Track progress. + + // For !bNxtAccount + const STAmount& saCurDeliverReq = pnCur.saRevDeliver; + STAmount saCurDeliverAct(saCurDeliverReq.getCurrency(), saCurDeliverReq.getIssuer()); + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurRedeemReq=%s saNxtOwed=%s") + % saPrvRedeemReq.getFullText() + % saPrvIssueReq.getFullText() + % saCurRedeemReq.getFullText() + % saNxtOwed.getFullText()); + + Log(lsINFO) << pspCur->getJson(); + + assert(!saCurRedeemReq || (-saNxtOwed) >= saCurRedeemReq); // Current redeem req can't be more than IOUs on hand. + assert(!saCurIssueReq || !saNxtOwed.isPositive() || saNxtOwed == saCurRedeemReq); // If issue req, then redeem req must consume all owed. + + if (bPrvAccount && bNxtAccount) + { + if (!uIndex) + { + // ^ --> ACCOUNT --> account|offer + // Nothing to do, there is no previous to adjust. + nothing(); + } + else if (uIndex == uLast) + { + // account --> ACCOUNT --> $ + // Overall deliverable. + const STAmount& saCurWantedReq = bPrvAccount + ? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $ : saCurWantedReq=%s") + % saCurWantedReq.getFullText()); + + // Calculate redeem + if (saPrvRedeemReq) // Previous has IOUs to redeem. + { + // Redeem at 1:1 + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Redeem at 1:1")); + + saCurWantedAct = std::min(saPrvRedeemReq, saCurWantedReq); + saPrvRedeemAct = saCurWantedAct; + + uRateMax = STAmount::uRateOne; + } + + // Calculate issuing. + if (saCurWantedReq != saCurWantedAct // Need more. + && saPrvIssueReq) // Will accept IOUs from prevous. + { + // Rate: quality in : 1.0 + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); + + // If we previously redeemed and this has a poorer rate, this won't be included the current increment. + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurWantedReq, saPrvIssueAct, saCurWantedAct, uRateMax); + } + + if (!saCurWantedAct) + { + // Must have processed something. + terResult = tepPATH_DRY; + } + } + else + { + // ^|account --> ACCOUNT --> account + + // redeem (part 1) -> redeem + if (saCurRedeemReq // Next wants IOUs redeemed. + && saPrvRedeemReq) // Previous has IOUs to redeem. + { + // Rate : 1.0 : quality out + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : quality out")); + + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax); + } + + // issue (part 1) -> redeem + if (saCurRedeemReq != saCurRedeemAct // Next wants more IOUs redeemed. + && saPrvRedeemAct == saPrvRedeemReq) // Previous has no IOUs to redeem remaining. + { + // Rate: quality in : quality out + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : quality out")); + + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct, uRateMax); + } + + // redeem (part 2) -> issue. + if (saCurIssueReq // Next wants IOUs issued. + && saCurRedeemAct == saCurRedeemReq // Can only issue if completed redeeming. + && saPrvRedeemAct != saPrvRedeemReq) // Did not complete redeeming previous IOUs. + { + // Rate : 1.0 : transfer_rate + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : transfer_rate")); + + calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax); + } + + // issue (part 2) -> issue + if (saCurIssueReq != saCurIssueAct // Need wants more IOUs issued. + && saCurRedeemAct == saCurRedeemReq // Can only issue if completed redeeming. + && saPrvRedeemReq == saPrvRedeemAct) // Previously redeemed all owed IOUs. + { + // Rate: quality in : 1.0 + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); + + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax); + } + + if (!saCurRedeemAct && !saCurIssueAct) + { + // Must want something. + terResult = tepPATH_DRY; + } + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : saCurRedeemReq=%s saCurIssueReq=%s saPrvOwed=%s saCurRedeemAct=%s saCurIssueAct=%s") + % saCurRedeemReq.getFullText() + % saCurIssueReq.getFullText() + % saPrvOwed.getFullText() + % saCurRedeemAct.getFullText() + % saCurIssueAct.getFullText()); + } + } + else if (bPrvAccount && !bNxtAccount) + { + // account --> ACCOUNT --> offer + // Note: deliver is always issue as ACCOUNT is the issuer for the offer input. + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> offer")); + + // redeem -> deliver/issue. + if (saPrvOwed.isPositive() // Previous has IOUs to redeem. + && saCurDeliverReq) // Need some issued. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct, uRateMax); + } + + // issue -> deliver/issue + if (saPrvRedeemReq == saPrvRedeemAct // Previously redeemed all owed. + && saCurDeliverReq != saCurDeliverAct) // Still need some issued. + { + // Rate: quality in : 1.0 + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurDeliverReq, saPrvIssueAct, saCurDeliverAct, uRateMax); + } + + if (!saCurDeliverAct) + { + // Must want something. + terResult = tepPATH_DRY; + } + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saCurDeliverReq=%s saCurDeliverAct=%s saPrvOwed=%s") + % saCurDeliverReq.getFullText() + % saCurDeliverAct.getFullText() + % saPrvOwed.getFullText()); + } + else if (!bPrvAccount && bNxtAccount) + { + if (uIndex == uLast) + { + // offer --> ACCOUNT --> $ + const STAmount& saCurWantedReq = bPrvAccount + ? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. + : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. + STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $ : saCurWantedReq=%s") + % saCurWantedReq.getFullText()); + + // Rate: quality in : 1.0 + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct, uRateMax); + + if (!saCurWantedAct) + { + // Must have processed something. + terResult = tepPATH_DRY; + } + } + else + { + // offer --> ACCOUNT --> account + // Note: offer is always delivering(redeeming) as account is issuer. + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> account")); + + // deliver -> redeem + if (saCurRedeemReq) // Next wants us to redeem. + { + // Rate : 1.0 : quality out + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct, uRateMax); + } + + // deliver -> issue. + if (saCurRedeemReq == saCurRedeemAct // Can only issue if previously redeemed all. + && saCurIssueReq) // Need some issued. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct, uRateMax); + } + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saCurRedeemReq=%s saCurIssueAct=%s saCurIssueReq=%s saPrvDeliverAct=%s") + % saCurRedeemReq.getFullText() + % saCurRedeemAct.getFullText() + % saCurIssueReq.getFullText() + % saPrvDeliverAct.getFullText()); + + if (!saPrvDeliverAct) + { + // Must want something. + terResult = tepPATH_DRY; + } + } + } + else + { + // offer --> ACCOUNT --> offer + // deliver/redeem -> deliver/issue. + Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> offer")); + + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct, uRateMax); + + if (!saCurDeliverAct) + { + // Must want something. + terResult = tepPATH_DRY; + } + } + + return terResult; +} + +// Perfrom balance adjustments between previous and current node. +// - The previous node: specifies what to push through to current. +// - All of previous output is consumed. +// Then, compute 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. +TER RippleCalc::calcNodeAccountFwd( + const unsigned int uIndex, // 0 <= uIndex <= uLast + const PathState::pointer& pspCur, + const bool bMultiQuality) +{ + TER terResult = tesSUCCESS; + const unsigned int uLast = pspCur->vpnNodes.size() - 1; + + uint64 uRateMax = 0; + + PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; + + const bool bPrvAccount = isSetBit(pnPrv.uFlags, STPathElement::typeAccount); + const bool bNxtAccount = isSetBit(pnNxt.uFlags, STPathElement::typeAccount); + + const uint160& uCurAccountID = pnCur.uAccountID; + const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; + const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. + + const uint160& uCurrencyID = pnCur.uCurrencyID; + + uint32 uQualityIn = uIndex ? lesActive.rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; + uint32 uQualityOut = uIndex == uLast ? lesActive.rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; + + // For bNxtAccount + const STAmount& saPrvRedeemReq = pnPrv.saFwdRedeem; + STAmount saPrvRedeemAct(saPrvRedeemReq.getCurrency(), saPrvRedeemReq.getIssuer()); + + const STAmount& saPrvIssueReq = pnPrv.saFwdIssue; + STAmount saPrvIssueAct(saPrvIssueReq.getCurrency(), saPrvIssueReq.getIssuer()); + + // For !bPrvAccount + const STAmount& saPrvDeliverReq = pnPrv.saRevDeliver; + STAmount saPrvDeliverAct(saPrvDeliverReq.getCurrency(), saPrvDeliverReq.getIssuer()); + + // For bNxtAccount + const STAmount& saCurRedeemReq = pnCur.saRevRedeem; + STAmount& saCurRedeemAct = pnCur.saFwdRedeem; + + const STAmount& saCurIssueReq = pnCur.saRevIssue; + STAmount& saCurIssueAct = pnCur.saFwdIssue; + + // For !bNxtAccount + const STAmount& saCurDeliverReq = pnCur.saRevDeliver; + STAmount& saCurDeliverAct = pnCur.saFwdDeliver; + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uIndex=%d/%d saPrvRedeemReq=%s saPrvIssueReq=%s saPrvDeliverReq=%s saCurRedeemReq=%s saCurIssueReq=%s saCurDeliverReq=%s") + % uIndex + % uLast + % saPrvRedeemReq.getFullText() + % saPrvIssueReq.getFullText() + % saPrvDeliverReq.getFullText() + % saCurRedeemReq.getFullText() + % saCurIssueReq.getFullText() + % saCurDeliverReq.getFullText()); + + // Ripple through account. + + if (bPrvAccount && bNxtAccount) + { + if (!uIndex) + { + // ^ --> ACCOUNT --> account + + // First node, calculate amount to send. + // XXX Use stamp/ripple balance + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + + const STAmount& saCurRedeemReq = pnCur.saRevRedeem; + STAmount& saCurRedeemAct = pnCur.saFwdRedeem; + const STAmount& saCurIssueReq = pnCur.saRevIssue; + STAmount& saCurIssueAct = pnCur.saFwdIssue; + + const STAmount& saCurSendMaxReq = pspCur->saInReq; // Negative for no limit, doing a calculation. + STAmount& saCurSendMaxAct = pspCur->saInAct; // Report to user how much this sends. + + if (saCurRedeemReq) + { + // Redeem requested. + saCurRedeemAct = saCurRedeemReq.isNegative() + ? saCurRedeemReq + : std::min(saCurRedeemReq, saCurSendMaxReq); + } + else + { + saCurRedeemAct = STAmount(saCurRedeemReq); + } + saCurSendMaxAct = saCurRedeemAct; + + if (saCurIssueReq && (saCurSendMaxReq.isNegative() || saCurSendMaxReq != saCurRedeemAct)) + { + // Issue requested and not over budget. + saCurIssueAct = saCurSendMaxReq.isNegative() + ? saCurIssueReq + : std::min(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); + } + else + { + saCurIssueAct = STAmount(saCurIssueReq); + } + saCurSendMaxAct += saCurIssueAct; + + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s") + % saCurSendMaxReq.getFullText() + % saCurRedeemAct.getFullText() + % saCurIssueReq.getFullText() + % saCurIssueAct.getFullText()); + } + else if (uIndex == uLast) + { + // account --> ACCOUNT --> $ + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> $ : uPrvAccountID=%s uCurAccountID=%s saPrvRedeemReq=%s saPrvIssueReq=%s") + % NewcoinAddress::createHumanAccountID(uPrvAccountID) + % NewcoinAddress::createHumanAccountID(uCurAccountID) + % saPrvRedeemReq.getFullText() + % saPrvIssueReq.getFullText()); + + // Last node. Accept all funds. Calculate amount actually to credit. + + STAmount& saCurReceive = pspCur->saOutAct; + + STAmount saIssueCrd = uQualityIn >= QUALITY_ONE + ? saPrvIssueReq // No fee. + : STAmount::multiply(saPrvIssueReq, uQualityIn, uCurrencyID, saPrvIssueReq.getIssuer()); // Fee. + + // Amount to credit. + saCurReceive = saPrvRedeemReq+saIssueCrd; + + // Actually receive. + lesActive.rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq+saPrvIssueReq, false); + } + else + { + // account --> ACCOUNT --> account + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> account")); + + // Previous redeem part 1: redeem -> redeem + if (saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. + { + // Rate : 1.0 : quality out + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax); + } + + // Previous issue part 1: issue -> redeem + if (saPrvIssueReq != saPrvIssueAct // Previous wants to issue. + && saCurRedeemReq != saCurRedeemAct) // Current has more to redeem to next. + { + // Rate: quality in : quality out + calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct, uRateMax); + } + + // Previous redeem part 2: redeem -> issue. + // wants to redeem and current would and can issue. + // If redeeming cur to next is done, this implies can issue. + if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem. + && saCurRedeemReq == saCurRedeemAct // Current has no more to redeem to next. + && saCurIssueReq) + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax); + } + + // Previous issue part 2 : issue -> issue + if (saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. + { + // Rate: quality in : 1.0 + calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax); + } + + // Adjust prv --> cur balance : take all inbound + // XXX Currency must be in amount. + lesActive.rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false); + } + } + else if (bPrvAccount && !bNxtAccount) + { + // account --> ACCOUNT --> offer + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> offer")); + + // 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. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct, uRateMax); + } + + // issue -> issue + 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 + // XXX Currency must be in amount. + lesActive.rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false); + } + else if (!bPrvAccount && bNxtAccount) + { + if (uIndex == uLast) + { + // offer --> ACCOUNT --> $ + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $")); + + STAmount& saCurReceive = pspCur->saOutAct; + + // Amount to credit. + saCurReceive = saPrvDeliverAct; + + // No income balance adjustments necessary. The paying side inside the offer paid to this account. + } + else + { + // offer --> ACCOUNT --> account + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> account")); + + // deliver -> redeem + if (saPrvDeliverReq) // Previous wants to deliver. + { + // Rate : 1.0 : quality out + calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct, uRateMax); + } + + // deliver -> issue + // Wants to redeem and current would and can issue. + if (saPrvDeliverReq != saPrvDeliverAct // Previous still wants to deliver. + && saCurRedeemReq == saCurRedeemAct // Current has more to redeem to next. + && saCurIssueReq) // Current wants issue. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct, uRateMax); + } + + // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. + } + } + else + { + // offer --> ACCOUNT --> offer + // deliver/redeem -> deliver/issue. + Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> offer")); + + if (saPrvDeliverReq // Previous wants to deliver + && saCurIssueReq) // Current wants issue. + { + // Rate : 1.0 : transfer_rate + calcNodeRipple(QUALITY_ONE, lesActive.rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct, uRateMax); + } + + // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. + } + + return terResult; +} + +// Return true, iff lhs has less priority than rhs. +bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs) +{ + if (lhs->uQuality != rhs->uQuality) + return lhs->uQuality > rhs->uQuality; // Bigger is worse. + + // Best quanity is second rank. + if (lhs->saOutAct != rhs->saOutAct) + return lhs->saOutAct < rhs->saOutAct; // Smaller is worse. + + // Path index is third rank. + return lhs->mIndex > rhs->mIndex; // Bigger is worse. +} + +// Make sure the path delivers to uAccountID: uCurrencyID from uIssuerID. +// +// Rules: +// - Currencies must be converted via an offer. +// - A node names it's output. +// - A ripple nodes output issuer must be the node's account or the next node's account. +// - Offers can only go directly to another offer if the currency and issuer are an exact match. +TER PathState::pushImply( + const uint160& uAccountID, // --> Delivering to this account. + const uint160& uCurrencyID, // --> Delivering this currency. + const uint160& uIssuerID) // --> Delivering this issuer. +{ + const PaymentNode& pnPrv = vpnNodes.back(); + TER terResult = tesSUCCESS; + + Log(lsINFO) << "pushImply> " + << NewcoinAddress::createHumanAccountID(uAccountID) + << " " << STAmount::createHumanCurrency(uCurrencyID) + << " " << NewcoinAddress::createHumanAccountID(uIssuerID); + + if (pnPrv.uCurrencyID != uCurrencyID) + { + // Currency is different, need to convert via an offer. + + terResult = pushNode( + STPathElement::typeCurrency // Offer. + | STPathElement::typeIssuer, + ACCOUNT_ONE, // Placeholder for offers. + uCurrencyID, // The offer's output is what is now wanted. + uIssuerID); + + } + + // For ripple, non-stamps, ensure the issuer is on at least one side of the transaction. + if (tesSUCCESS == terResult + && !!uCurrencyID // Not stamps. + && (pnPrv.uAccountID != uIssuerID // Previous is not issuing own IOUs. + && uAccountID != uIssuerID)) // Current is not receiving own IOUs. + { + // Need to ripple through uIssuerID's account. + + terResult = pushNode( + STPathElement::typeAccount, + uIssuerID, // Intermediate account is the needed issuer. + uCurrencyID, + uIssuerID); + } + + Log(lsINFO) << "pushImply< " << terResult; + + return terResult; +} + +// Append a node and insert before it any implied nodes. +// <-- terResult: tesSUCCESS, temBAD_PATH, terNO_LINE +TER PathState::pushNode( + const int iType, + const uint160& uAccountID, + const uint160& uCurrencyID, + const uint160& uIssuerID) +{ + Log(lsINFO) << "pushNode> " + << NewcoinAddress::createHumanAccountID(uAccountID) + << " " << STAmount::createHumanCurrency(uCurrencyID) + << "/" << NewcoinAddress::createHumanAccountID(uIssuerID); + PaymentNode pnCur; + const bool bFirst = vpnNodes.empty(); + const PaymentNode& pnPrv = bFirst ? PaymentNode() : vpnNodes.back(); + // true, iff node is a ripple account. false, iff node is an offer node. + const bool bAccount = isSetBit(iType, STPathElement::typeAccount); + // true, iff currency supplied. + // Currency is specified for the output of the current node. + const bool bCurrency = isSetBit(iType, STPathElement::typeCurrency); + // Issuer is specified for the output of the current node. + const bool bIssuer = isSetBit(iType, STPathElement::typeIssuer); + TER terResult = tesSUCCESS; + + pnCur.uFlags = iType; + + if (iType & ~STPathElement::typeValidBits) + { + Log(lsINFO) << "pushNode: bad bits."; + + terResult = temBAD_PATH; + } + else if (bAccount) + { + // Account link + + pnCur.uAccountID = uAccountID; + pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; + pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; + pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID); + pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID); + + if (!bFirst) + { + // Add required intermediate nodes to deliver to current account. + terResult = pushImply( + pnCur.uAccountID, // Current account. + pnCur.uCurrencyID, // Wanted currency. + !!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as issuer. + } + + if (tesSUCCESS == terResult && !vpnNodes.empty()) + { + const PaymentNode& pnBck = vpnNodes.back(); + bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); + + if (bBckAccount) + { + SLE::pointer sleRippleState = mLedger->getSLE(Ledger::getRippleStateIndex(pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID)); + + if (!sleRippleState) + { + Log(lsINFO) << "pushNode: No credit line between " + << NewcoinAddress::createHumanAccountID(pnBck.uAccountID) + << " and " + << NewcoinAddress::createHumanAccountID(pnCur.uAccountID) + << " for " + << STAmount::createHumanCurrency(pnPrv.uCurrencyID) + << "." ; + + Log(lsINFO) << getJson(); + + terResult = terNO_LINE; + } + else + { + Log(lsINFO) << "pushNode: Credit line found between " + << NewcoinAddress::createHumanAccountID(pnBck.uAccountID) + << " and " + << NewcoinAddress::createHumanAccountID(pnCur.uAccountID) + << " for " + << STAmount::createHumanCurrency(pnPrv.uCurrencyID) + << "." ; + } + } + } + + if (tesSUCCESS == terResult) + vpnNodes.push_back(pnCur); + } + else + { + // Offer link + // Offers bridge a change in currency & issuer or just a change in issuer. + pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; + pnCur.uIssuerID = bIssuer ? uIssuerID : pnCur.uAccountID; + pnCur.saRateMax = saZero; + + if (!!pnPrv.uAccountID) + { + // Previous is an account. + + // Insert intermediary issuer account if needed. + terResult = pushImply( + !!pnPrv.uCurrencyID + ? ACCOUNT_ONE // Rippling, but offer's don't have an account. + : ACCOUNT_XNS, + pnPrv.uCurrencyID, + pnPrv.uIssuerID); + } + + if (tesSUCCESS == terResult) + { + vpnNodes.push_back(pnCur); + } + } + Log(lsINFO) << "pushNode< " << terResult; + + return terResult; +} + +PathState::PathState( + const int iIndex, + const LedgerEntrySet& lesSource, + const STPath& spSourcePath, + const uint160& uReceiverID, + const uint160& uSenderID, + const STAmount& saSend, + const STAmount& saSendMax + ) + : mLedger(lesSource.getLedgerRef()), mIndex(iIndex), uQuality(0) +{ + const uint160 uInCurrencyID = saSendMax.getCurrency(); + const uint160 uOutCurrencyID = saSend.getCurrency(); + const uint160 uInIssuerID = !!uInCurrencyID ? saSendMax.getIssuer() : ACCOUNT_XNS; + const uint160 uOutIssuerID = !!uOutCurrencyID ? saSend.getIssuer() : ACCOUNT_XNS; + + lesEntries = lesSource.duplicate(); + + saInReq = saSendMax; + saOutReq = saSend; + + // Push sending node. + terStatus = pushNode( + STPathElement::typeAccount + | STPathElement::typeCurrency + | STPathElement::typeIssuer, + uSenderID, + uInCurrencyID, + uInIssuerID); + + BOOST_FOREACH(const STPathElement& speElement, spSourcePath) + { + if (tesSUCCESS == terStatus) + terStatus = pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID()); + } + + if (tesSUCCESS == terStatus) + { + // Create receiver node. + + terStatus = pushImply(uReceiverID, uOutCurrencyID, uOutIssuerID); + if (tesSUCCESS == terStatus) + { + terStatus = pushNode( + STPathElement::typeAccount // Last node is always an account. + | STPathElement::typeCurrency + | STPathElement::typeIssuer, + uReceiverID, // Receive to output + uOutCurrencyID, // Desired currency + uOutIssuerID); + } + } + + if (tesSUCCESS == terStatus) + { + // Look for first mention of source in nodes and detect loops. + // Note: The output is not allowed to be a source. + + const unsigned int uNodes = vpnNodes.size(); + + for (unsigned int uIndex = 0; tesSUCCESS == terStatus && uIndex != uNodes; ++uIndex) + { + const PaymentNode& pnCur = vpnNodes[uIndex]; + + if (!!pnCur.uAccountID) + { + // Source is a ripple line + nothing(); + } + else if (!umForward.insert(std::make_pair(boost::make_tuple(pnCur.uAccountID, pnCur.uCurrencyID, pnCur.uIssuerID), uIndex)).second) + { + // Failed to insert. Have a loop. + Log(lsINFO) << boost::str(boost::format("PathState: loop detected: %s") + % getJson()); + + terStatus = temBAD_PATH_LOOP; + } + } + } + + Log(lsINFO) << boost::str(boost::format("PathState: in=%s/%s out=%s/%s %s") + % STAmount::createHumanCurrency(uInCurrencyID) + % NewcoinAddress::createHumanAccountID(uInIssuerID) + % STAmount::createHumanCurrency(uOutCurrencyID) + % NewcoinAddress::createHumanAccountID(uOutIssuerID) + % getJson()); +} + +Json::Value PathState::getJson() const +{ + Json::Value jvPathState(Json::objectValue); + Json::Value jvNodes(Json::arrayValue); + + BOOST_FOREACH(const PaymentNode& pnNode, vpnNodes) + { + Json::Value jvNode(Json::objectValue); + + Json::Value jvFlags(Json::arrayValue); + + if (pnNode.uFlags & STPathElement::typeAccount) + jvFlags.append("account"); + + jvNode["flags"] = jvFlags; + + if (pnNode.uFlags & STPathElement::typeAccount) + jvNode["account"] = NewcoinAddress::createHumanAccountID(pnNode.uAccountID); + + if (!!pnNode.uCurrencyID) + jvNode["currency"] = STAmount::createHumanCurrency(pnNode.uCurrencyID); + + if (!!pnNode.uIssuerID) + jvNode["issuer"] = NewcoinAddress::createHumanAccountID(pnNode.uIssuerID); + + // if (pnNode.saRevRedeem) + jvNode["rev_redeem"] = pnNode.saRevRedeem.getFullText(); + + // if (pnNode.saRevIssue) + jvNode["rev_issue"] = pnNode.saRevIssue.getFullText(); + + // if (pnNode.saRevDeliver) + jvNode["rev_deliver"] = pnNode.saRevDeliver.getFullText(); + + // if (pnNode.saFwdRedeem) + jvNode["fwd_redeem"] = pnNode.saFwdRedeem.getFullText(); + + // if (pnNode.saFwdIssue) + jvNode["fwd_issue"] = pnNode.saFwdIssue.getFullText(); + + // if (pnNode.saFwdDeliver) + jvNode["fwd_deliver"] = pnNode.saFwdDeliver.getFullText(); + + jvNodes.append(jvNode); + } + + jvPathState["status"] = terStatus; + jvPathState["index"] = mIndex; + jvPathState["nodes"] = jvNodes; + + if (saInReq) + jvPathState["in_req"] = saInReq.getJson(0); + + if (saInAct) + jvPathState["in_act"] = saInAct.getJson(0); + + if (saOutReq) + jvPathState["out_req"] = saOutReq.getJson(0); + + if (saOutAct) + jvPathState["out_act"] = saOutAct.getJson(0); + + if (uQuality) + jvPathState["uQuality"] = Json::Value::UInt(uQuality); + + return jvPathState; +} + +TER RippleCalc::calcNodeFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) +{ + const PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); + + Log(lsINFO) << boost::str(boost::format("calcNodeFwd> uIndex=%d") % uIndex); + + TER terResult = bCurAccount + ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) + : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); + + if (tesSUCCESS == terResult && uIndex + 1 != pspCur->vpnNodes.size()) + { + terResult = calcNodeFwd(uIndex+1, pspCur, bMultiQuality); + } + + Log(lsINFO) << boost::str(boost::format("calcNodeFwd< uIndex=%d terResult=%d") % uIndex % terResult); + + return terResult; +} + +// Calculate a node and its previous nodes. +// From the destination work in reverse towards the source calculating how much must be asked for. +// Then work forward, figuring out how much can actually be delivered. +// <-- terResult: tesSUCCESS or tepPATH_DRY +// <-> pnNodes: +// --> [end]saWanted.mAmount +// --> [all]saWanted.mCurrency +// --> [all]saAccount +// <-> [0]saWanted.mAmount : --> limit, <-- actual +TER RippleCalc::calcNodeRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) +{ + PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; + const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); + TER terResult; + + // Do current node reverse. + const uint160& uCurIssuerID = pnCur.uIssuerID; + STAmount& saTransferRate = pnCur.saTransferRate; + + saTransferRate = STAmount::saFromRate(lesActive.rippleTransferRate(uCurIssuerID)); + + Log(lsINFO) << boost::str(boost::format("calcNodeRev> uIndex=%d uIssuerID=%s saTransferRate=%s") + % uIndex + % NewcoinAddress::createHumanAccountID(uCurIssuerID) + % saTransferRate.getFullText()); + + terResult = bCurAccount + ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) + : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); + + // Do previous. + if (tesSUCCESS != terResult) + { + // Error, don't continue. + nothing(); + } + else if (uIndex) + { + // Continue in reverse. + + terResult = calcNodeRev(uIndex-1, pspCur, bMultiQuality); + } + + Log(lsINFO) << boost::str(boost::format("calcNodeRev< uIndex=%d terResult=%s/%d") % uIndex % transToken(terResult) % terResult); + + return terResult; +} + +// Calculate the next increment of a path. +// The increment is what can satisfy a portion or all of the requested output at the best quality. +// <-- pspCur->uQuality +void RippleCalc::pathNext(const PathState::pointer& pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint, LedgerEntrySet& lesCurrent) +{ + // The next state is what is available in preference order. + // This is calculated when referenced accounts changed. + const bool bMultiQuality = iPaths == 1; + const unsigned int uLast = pspCur->vpnNodes.size() - 1; + + Log(lsINFO) << "Path In: " << pspCur->getJson(); + + assert(pspCur->vpnNodes.size() >= 2); + + pspCur->vUnfundedBecame.clear(); + pspCur->umReverse.clear(); + + lesCurrent = lesCheckpoint; // Restore from checkpoint. + lesCurrent.bumpSeq(); // Begin ledger varance. + + pspCur->terStatus = calcNodeRev(uLast, pspCur, bMultiQuality); + + Log(lsINFO) << "Path after reverse: " << pspCur->getJson(); + + if (tesSUCCESS == pspCur->terStatus) + { + // Do forward. + lesCurrent = lesCheckpoint; // Restore from checkpoint. + lesCurrent.bumpSeq(); // Begin ledger varance. + + pspCur->terStatus = calcNodeFwd(0, pspCur, bMultiQuality); + + pspCur->uQuality = tesSUCCESS == pspCur->terStatus + ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. + : 0; // Mark path as inactive. + + Log(lsINFO) << "Path after forward: " << pspCur->getJson(); + } +} + +// XXX Stand alone calculation not implemented, does not calculate required input. +TER RippleCalc::rippleCalc( + LedgerEntrySet& lesActive, // <-> --> = Fee applied to src balance. + STAmount& saMaxAmountAct, // <-- The computed input amount. + STAmount& saDstAmountAct, // <-- The computed output amount. + const STAmount& saMaxAmountReq, // --> -1 = no limit. + const STAmount& saDstAmountReq, + const uint160& uDstAccountID, + const uint160& uSrcAccountID, + const STPathSet& spsPaths, + const bool bPartialPayment, + const bool bLimitQuality, + const bool bNoRippleDirect + ) +{ + RippleCalc rc(lesActive); + + TER terResult = temUNCERTAIN; + + // YYY Might do basic checks on src and dst validity as per doPayment. + + if (bNoRippleDirect && spsPaths.isEmpty()) + { + Log(lsINFO) << "doPayment: Invalid transaction: No paths and direct ripple not allowed."; + + return temRIPPLE_EMPTY; + } + + // Incrementally search paths. + std::vector vpsPaths; + + if (!bNoRippleDirect) + { + // Direct path. + // XXX Might also make a stamp bridge by default. + Log(lsINFO) << "doPayment: Build direct:"; + + PathState::pointer pspDirect = PathState::createPathState( + vpsPaths.size(), + lesActive, + STPath(), + uDstAccountID, + uSrcAccountID, + saDstAmountReq, + saMaxAmountReq); + + if (pspDirect) + { + // Return if malformed. + if (pspDirect->terStatus >= temMALFORMED && pspDirect->terStatus < tefFAILURE) + return pspDirect->terStatus; + + if (tesSUCCESS == pspDirect->terStatus) + { + // Had a success. + terResult = tesSUCCESS; + + vpsPaths.push_back(pspDirect); + } + } + } + + Log(lsINFO) << "doPayment: Paths in set: " << spsPaths.getPathCount(); + + BOOST_FOREACH(const STPath& spPath, spsPaths) + { + Log(lsINFO) << "doPayment: Build path:"; + + PathState::pointer pspExpanded = PathState::createPathState( + vpsPaths.size(), + lesActive, + spPath, + uDstAccountID, + uSrcAccountID, + saDstAmountReq, + saMaxAmountReq); + + if (pspExpanded) + { + // Return if malformed. + if (pspExpanded->terStatus >= temMALFORMED && pspExpanded->terStatus < tefFAILURE) + return pspExpanded->terStatus; + + if (tesSUCCESS == pspExpanded->terStatus) + { + // Had a success. + terResult = tesSUCCESS; + } + + vpsPaths.push_back(pspExpanded); + } + } + + if (vpsPaths.empty()) + { + return tefEXCEPTION; + } + else if (tesSUCCESS != terResult) + { + // No path successes. + + return vpsPaths[0]->terStatus; + } + else + { + terResult = temUNCERTAIN; + } + + STAmount saPaid; + STAmount saWanted; + const LedgerEntrySet lesBase = lesActive; // Checkpoint with just fees paid. + const uint64 uQualityLimit = bLimitQuality ? STAmount::getRate(saDstAmountReq, saMaxAmountReq) : 0; + // When processing, don't want to complicate directory walking with deletion. + std::vector vuUnfundedBecame; // Offers that became unfunded. + + while (temUNCERTAIN == terResult) + { + PathState::pointer pspBest; + const LedgerEntrySet lesCheckpoint = lesActive; + + // Find the best path. + BOOST_FOREACH(PathState::pointer& pspCur, vpsPaths) + { + rc.pathNext(pspCur, vpsPaths.size(), lesCheckpoint, lesActive); // Compute increment. + + if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality. + || !pspBest // Best is not yet set. + || (pspCur->uQuality && PathState::lessPriority(pspBest, pspCur))) // Current is better than set. + { + lesActive.swapWith(pspCur->lesEntries); // For the path, save ledger state. + pspBest = pspCur; + } + } + + if (pspBest) + { + // Apply best path. + + // Record best pass' offers that became unfunded for deletion on success. + vuUnfundedBecame.insert(vuUnfundedBecame.end(), pspBest->vUnfundedBecame.begin(), pspBest->vUnfundedBecame.end()); + + // Record best pass' LedgerEntrySet to build off of and potentially return. + lesActive.swapWith(pspBest->lesEntries); + + // Figure out if done. + if (temUNCERTAIN == terResult && saPaid == saWanted) + { + terResult = tesSUCCESS; + } + else + { + // Prepare for next pass. + + // Merge best pass' umReverse. + rc.mumSource.insert(pspBest->umReverse.begin(), pspBest->umReverse.end()); + } + } + // Not done and ran out of paths. + else if (!bPartialPayment) + { + // Partial payment not allowed. + terResult = tepPATH_PARTIAL; + lesActive = lesBase; // Revert to just fees charged. + } + // Partial payment ok. + else if (!saPaid) + { + // No payment at all. + terResult = tepPATH_DRY; + lesActive = lesBase; // Revert to just fees charged. + } + else + { + terResult = tesSUCCESS; + } + } + + if (tesSUCCESS == terResult) + { + // Delete became unfunded offers. + BOOST_FOREACH(const uint256& uOfferIndex, vuUnfundedBecame) + { + if (tesSUCCESS == terResult) + terResult = lesActive.offerDelete(uOfferIndex); + } + } + + // Delete found unfunded offers. + BOOST_FOREACH(const uint256& uOfferIndex, rc.musUnfundedFound) + { + if (tesSUCCESS == terResult) + terResult = lesActive.offerDelete(uOfferIndex); + } + + return terResult; +} + +#if 0 +// XXX Need to adjust for fees. +// Find offers to satisfy pnDst. +// - Does not adjust any balances as there is at least a forward pass to come. +// --> pnDst.saWanted: currency and amount wanted +// --> pnSrc.saIOURedeem.mCurrency: use this before saIOUIssue, limit to use. +// --> pnSrc.saIOUIssue.mCurrency: use this after saIOURedeem, limit to use. +// <-- pnDst.saReceive +// <-- pnDst.saIOUForgive +// <-- pnDst.saIOUAccept +// <-- terResult : tesSUCCESS = no error and if !bAllowPartial complelely satisfied wanted. +// <-> usOffersDeleteAlways: +// <-> usOffersDeleteOnSuccess: +TER calcOfferFill(PaymentNode& pnSrc, PaymentNode& pnDst, bool bAllowPartial) +{ + TER terResult; + + if (pnDst.saWanted.isNative()) + { + // Transfer stamps. + + STAmount saSrcFunds = pnSrc.saAccount->accountHolds(pnSrc.saAccount, uint160(0), uint160(0)); + + if (saSrcFunds && (bAllowPartial || saSrcFunds > pnDst.saWanted)) + { + pnSrc.saSend = min(saSrcFunds, pnDst.saWanted); + pnDst.saReceive = pnSrc.saSend; + } + else + { + terResult = terINSUF_PATH; + } + } + else + { + // Ripple funds. + + // Redeem to limit. + terResult = calcOfferFill( + accountHolds(pnSrc.saAccount, pnDst.saWanted.getCurrency(), pnDst.saWanted.getIssuer()), + pnSrc.saIOURedeem, + pnDst.saIOUForgive, + bAllowPartial); + + if (tesSUCCESS == terResult) + { + // Issue to wanted. + terResult = calcOfferFill( + pnDst.saWanted, // As much as wanted is available, limited by credit limit. + pnSrc.saIOUIssue, + pnDst.saIOUAccept, + bAllowPartial); + } + + if (tesSUCCESS == terResult && !bAllowPartial) + { + STAmount saTotal = pnDst.saIOUForgive + pnSrc.saIOUAccept; + + if (saTotal != saWanted) + terResult = terINSUF_PATH; + } + } + + return terResult; +} +#endif + +#if 0 +// Get the next offer limited by funding. +// - Stop when becomes unfunded. +void TransactionEngine::calcOfferBridgeNext( + const uint256& uBookRoot, // --> Which order book to look in. + const uint256& uBookEnd, // --> Limit of how far to look. + uint256& uBookDirIndex, // <-> Current directory. <-- 0 = no offer available. + uint64& uBookDirNode, // <-> Which node. 0 = first. + unsigned int& uBookDirEntry, // <-> Entry in node. 0 = first. + STAmount& saOfferIn, // <-- How much to pay in, fee inclusive, to get saOfferOut out. + STAmount& saOfferOut // <-- How much offer pays out. + ) +{ + saOfferIn = 0; // XXX currency & issuer + saOfferOut = 0; // XXX currency & issuer + + bool bDone = false; + + while (!bDone) + { + uint256 uOfferIndex; + + // Get uOfferIndex. + mNodes.dirNext(uBookRoot, uBookEnd, uBookDirIndex, uBookDirNode, uBookDirEntry, uOfferIndex); + + SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); + + uint160 uOfferOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); + STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); + + if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + { + // Offer is expired. + Log(lsINFO) << "calcOfferFirst: encountered expired offer"; + } + else + { + STAmount saOfferFunds = accountFunds(uOfferOwnerID, saOfferPays); + // Outbound fees are paid by offer owner. + // XXX Calculate outbound fee rate. + + if (saOfferPays.isNative()) + { + // No additional fees for stamps. + + nothing(); + } + else if (saOfferPays.getIssuer() == uOfferOwnerID) + { + // Offerer is issue own IOUs. + // No fees at this exact point, XXX receiving node may charge a fee. + // XXX Make sure has a credit line with receiver, limit by credit line. + + nothing(); + // XXX Broken - could be issuing or redeeming or both. + } + else + { + // Offer must be redeeming IOUs. + + // No additional + // XXX Broken + } + + if (!saOfferFunds.isPositive()) + { + // Offer is unfunded. + Log(lsINFO) << "calcOfferFirst: offer unfunded: delete"; + } + else if (saOfferFunds >= saOfferPays) + { + // Offer fully funded. + + // Account transfering funds in to offer always pays inbound fees. + + saOfferIn = saOfferGets; // XXX Add in fees? + + saOfferOut = saOfferPays; + + bDone = true; + } + else + { + // Offer partially funded. + + // saOfferIn/saOfferFunds = saOfferGets/saOfferPays + // XXX Round such that all saOffer funds are exhausted. + saOfferIn = (saOfferFunds*saOfferGets)/saOfferPays; // XXX Add in fees? + saOfferOut = saOfferFunds; + + bDone = true; + } + } + + if (!bDone) + { + // musUnfundedFound.insert(uOfferIndex); + } + } + while (bNext); +} +#endif + +#if 0 +// If either currency is not stamps, then also calculates vs stamp bridge. +// --> saWanted: Limit of how much is wanted out. +// <-- saPay: How much to pay into the offer. +// <-- saGot: How much to the offer pays out. Never more than saWanted. +// Given two value's enforce a minimum: +// - reverse: prv is maximum to pay in (including fee) - cur is what is wanted: generally, minimizing prv +// - forward: prv is actual amount to pay in (including fee) - cur is what is wanted: generally, minimizing cur +// Value in is may be rippled or credited from limbo. Value out is put in limbo. +// If next is an offer, the amount needed is in cur reedem. +// XXX What about account mentioned multiple times via offers? +void TransactionEngine::calcNodeOffer( + bool bForward, + bool bMultiQuality, // True, if this is the only active path: we can do multiple qualities in this pass. + const uint160& uPrvAccountID, // If 0, then funds from previous offer's limbo + const uint160& uPrvCurrencyID, + const uint160& uPrvIssuerID, + const uint160& uCurCurrencyID, + const uint160& uCurIssuerID, + + const STAmount& uPrvRedeemReq, // --> In limit. + STAmount& uPrvRedeemAct, // <-> In limit achived. + const STAmount& uCurRedeemReq, // --> Out limit. Driver when uCurIssuerID == uNxtIssuerID (offer would redeem to next) + STAmount& uCurRedeemAct, // <-> Out limit achived. + + const STAmount& uCurIssueReq, // --> In limit. + STAmount& uCurIssueAct, // <-> In limit achived. + const STAmount& uCurIssueReq, // --> Out limit. Driver when uCurIssueReq != uNxtIssuerID (offer would effectively issue or transfer to next) + STAmount& uCurIssueAct, // <-> Out limit achived. + + STAmount& saPay, + STAmount& saGot + ) const +{ + TER terResult = temUNKNOWN; + + // Direct: not bridging via XNS + bool bDirectNext = true; // True, if need to load. + uint256 uDirectQuality; + uint256 uDirectTip = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); + uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); + + // Bridging: bridging via XNS + bool bBridge = true; // True, if bridging active. False, missing an offer. + uint256 uBridgeQuality; + STAmount saBridgeIn; // Amount available. + STAmount saBridgeOut; + + bool bInNext = true; // True, if need to load. + STAmount saInIn; // Amount available. Consumed in loop. Limited by offer funding. + STAmount saInOut; + uint256 uInTip; // Current entry. + uint256 uInEnd; + unsigned int uInEntry; + + bool bOutNext = true; + STAmount saOutIn; + STAmount saOutOut; + uint256 uOutTip; + uint256 uOutEnd; + unsigned int uOutEntry; + + saPay.zero(); + saPay.setCurrency(uPrvCurrencyID); + saPay.setIssuer(uPrvIssuerID); + + saNeed = saWanted; + + if (!uCurCurrencyID && !uPrvCurrencyID) + { + // Bridging: Neither currency is XNS. + uInTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, CURRENCY_XNS, ACCOUNT_XNS); + uInEnd = Ledger::getQualityNext(uInTip); + uOutTip = Ledger::getBookBase(CURRENCY_XNS, ACCOUNT_XNS, uCurCurrencyID, uCurIssuerID); + uOutEnd = Ledger::getQualityNext(uInTip); + } + + // Find our head offer. + + bool bRedeeming = false; + bool bIssuing = false; + + // The price varies as we change between issuing and transfering, so unless bMultiQuality, we must stick with a mode once it + // is determined. + + if (bBridge && (bInNext || bOutNext)) + { + // Bridging and need to calculate next bridge rate. + // A bridge can consist of multiple offers. As offer's are consumed, the effective rate changes. + + if (bInNext) + { +// sleInDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uInIndex, uInEnd)); + // Get the next funded offer. + offerBridgeNext(uInIndex, uInEnd, uInEntry, saInIn, saInOut); // Get offer limited by funding. + bInNext = false; + } + + if (bOutNext) + { +// sleOutDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uOutIndex, uOutEnd)); + offerNext(uOutIndex, uOutEnd, uOutEntry, saOutIn, saOutOut); + bOutNext = false; + } + + if (!uInIndex || !uOutIndex) + { + bBridge = false; // No more offers to bridge. + } + else + { + // Have bridge in and out entries. + // Calculate bridge rate. Out offer pay ripple fee. In offer fee is added to in cost. + + saBridgeOut.zero(); + + if (saInOut < saOutIn) + { + // Limit by in. + + // XXX Need to include fees in saBridgeIn. + saBridgeIn = saInIn; // All of in + // Limit bridge out: saInOut/saBridgeOut = saOutIn/saOutOut + // Round such that we would take all of in offer, otherwise would have leftovers. + saBridgeOut = (saInOut * saOutOut) / saOutIn; + } + else if (saInOut > saOutIn) + { + // Limit by out, if at all. + + // XXX Need to include fees in saBridgeIn. + // Limit bridge in:saInIn/saInOuts = aBridgeIn/saOutIn + // Round such that would take all of out offer. + saBridgeIn = (saInIn * saOutIn) / saInOuts; + saBridgeOut = saOutOut; // All of out. + } + else + { + // Entries match, + + // XXX Need to include fees in saBridgeIn. + saBridgeIn = saInIn; // All of in + saBridgeOut = saOutOut; // All of out. + } + + uBridgeQuality = STAmount::getRate(saBridgeIn, saBridgeOut); // Inclusive of fees. + } + } + + if (bBridge) + { + bUseBridge = !uDirectTip || (uBridgeQuality < uDirectQuality) + } + else if (!!uDirectTip) + { + bUseBridge = false + } + else + { + // No more offers. Declare success, even if none returned. + saGot = saWanted-saNeed; + terResult = tesSUCCESS; + } + + if (tesSUCCESS != terResult) + { + STAmount& saAvailIn = bUseBridge ? saBridgeIn : saDirectIn; + STAmount& saAvailOut = bUseBridge ? saBridgeOut : saDirectOut; + + if (saAvailOut > saNeed) + { + // Consume part of offer. Done. + + saNeed = 0; + saPay += (saNeed*saAvailIn)/saAvailOut; // Round up, prefer to pay more. + } + else + { + // Consume entire offer. + + saNeed -= saAvailOut; + saPay += saAvailIn; + + if (bUseBridge) + { + // Consume bridge out. + if (saOutOut == saAvailOut) + { + // Consume all. + saOutOut = 0; + saOutIn = 0; + bOutNext = true; + } + else + { + // Consume portion of bridge out, must be consuming all of bridge in. + // saOutIn/saOutOut = saSpent/saAvailOut + // Round? + saOutIn -= (saOutIn*saAvailOut)/saOutOut; + saOutOut -= saAvailOut; + } + + // Consume bridge in. + if (saOutIn == saAvailIn) + { + // Consume all. + saInOut = 0; + saInIn = 0; + bInNext = true; + } + else + { + // Consume portion of bridge in, must be consuming all of bridge out. + // saInIn/saInOut = saAvailIn/saPay + // Round? + saInOut -= (saInOut*saAvailIn)/saInIn; + saInIn -= saAvailIn; + } + } + else + { + bDirectNext = true; + } + } + } +} +#endif + +// vim:ts=4 diff --git a/src/RippleCalc.h b/src/RippleCalc.h new file mode 100644 index 0000000000..673393b5d5 --- /dev/null +++ b/src/RippleCalc.h @@ -0,0 +1,190 @@ +#ifndef __RIPPLE_CALC__ +#define __RIPPLE_CALC__ + +#include + +#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 aciSource; +typedef boost::unordered_map curIssuerNode; // Map of currency, issuer to node index. +typedef boost::unordered_map::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 pointer; + + TER terStatus; + std::vector vpnNodes; + + // When processing, don't want to complicate directory walking with deletion. + std::vector 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(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 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 diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 4684345496..3bd54dc34a 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -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; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 17e79af3c1..3a6417986e 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -395,6 +395,9 @@ public: Json::Value getJson(int) const; }; +extern STAmount saZero; +extern STAmount saOne; + class STHash128 : public SerializedType { protected: diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index f30ef3f4d6..526716ec81 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -17,387 +17,10 @@ #include "utils.h" #include "Interpreter.h" #include "Contract.h" +#include "RippleCalc.h" #define RIPPLE_PATHS_MAX 3 -static STAmount saZero(CURRENCY_ONE, ACCOUNT_ONE, 0); -static STAmount saOne(CURRENCY_ONE, ACCOUNT_ONE, 1); - -std::size_t hash_value(const aciSource& asValue) -{ - std::size_t seed = 0; - - asValue.get<0>().hash_combine(seed); - asValue.get<1>().hash_combine(seed); - asValue.get<2>().hash_combine(seed); - - return seed; -} - -// Returns amount owed by uToAccountID to uFromAccountID. -// <-- $owed/uCurrencyID/uToAccountID: positive: uFromAccountID holds IOUs., negative: uFromAccountID owes IOUs. -STAmount TransactionEngine::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 TransactionEngine::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 TransactionEngine::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 TransactionEngine::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 TransactionEngine::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 TransactionEngine::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 TransactionEngine::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 TransactionEngine::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 TransactionEngine::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 TransactionEngine::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 TransactionEngine::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); - } -} - -TER TransactionEngine::offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID) -{ - uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode); - TER terResult = mNodes.dirDelete(false, uOwnerNode, Ledger::getOwnerDirIndex(uOwnerID), uOfferIndex, false); - - if (tesSUCCESS == terResult) - { - uint256 uDirectory = sleOffer->getIFieldH256(sfBookDirectory); - uint64 uBookNode = sleOffer->getIFieldU64(sfBookNode); - - terResult = mNodes.dirDelete(false, uBookNode, uDirectory, uOfferIndex, true); - } - - entryDelete(sleOffer); - - return terResult; -} - -TER TransactionEngine::offerDelete(const uint256& uOfferIndex) -{ - SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - const uint160 uOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); - - return offerDelete(sleOffer, uOfferIndex, uOwnerID); -} - // Set the authorized public key for an account. May also set the generator map. TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator) { @@ -859,7 +482,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa break; case ttPAYMENT: - terResult = doPayment(txn); + terResult = doPayment(txn, params); break; case ttWALLET_ADD: @@ -910,7 +533,6 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa mTxnAccount = SLE::pointer(); mNodes.clear(); - musUnfundedFound.clear(); if (!isSetBit(params, tapOPEN_LEDGER) && (isTemMalformed(terResult) || isTefFailure(terResult))) @@ -922,7 +544,6 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa } - TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { Log(lsINFO) << "doAccountSet>"; @@ -1320,1791 +941,9 @@ TER TransactionEngine::doPasswordSet(const SerializedTransaction& txn) return terResult; } -// If needed, advance to next funded offer. -// - Automatically advances to first offer. -// - Set bEntryAdvance to advance to next entry. -// <-- uOfferIndex : 0=end of list. -TER TransactionEngine::calcNodeAdvance( - const unsigned int uIndex, // 0 < uIndex < uLast - const PathState::pointer& pspCur, - const bool bMultiQuality, - const bool bReverse) -{ - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - - const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; - const uint160& uPrvIssuerID = pnPrv.uIssuerID; - const uint160& uCurCurrencyID = pnCur.uCurrencyID; - const uint160& uCurIssuerID = pnCur.uIssuerID; - - uint256& uDirectTip = pnCur.uDirectTip; - uint256 uDirectEnd = pnCur.uDirectEnd; - bool& bDirectAdvance = pnCur.bDirectAdvance; - SLE::pointer& sleDirectDir = pnCur.sleDirectDir; - STAmount& saOfrRate = pnCur.saOfrRate; - - bool& bEntryAdvance = pnCur.bEntryAdvance; - unsigned int& uEntry = pnCur.uEntry; - uint256& uOfferIndex = pnCur.uOfferIndex; - SLE::pointer& sleOffer = pnCur.sleOffer; - uint160& uOfrOwnerID = pnCur.uOfrOwnerID; - STAmount& saOfferFunds = pnCur.saOfferFunds; - STAmount& saTakerPays = pnCur.saTakerPays; - STAmount& saTakerGets = pnCur.saTakerGets; - bool& bFundsDirty = pnCur.bFundsDirty; - - TER terResult = tesSUCCESS; - - do - { - bool bDirectDirDirty = false; - - if (!uDirectEnd) - { - // Need to initialize current node. - - uDirectTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, uCurCurrencyID, uCurIssuerID); - uDirectEnd = Ledger::getQualityNext(uDirectTip); - sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); - bDirectAdvance = !sleDirectDir; - bDirectDirDirty = true; - - Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: Initialize node: uDirectTip=%s uDirectEnd=%s bDirectAdvance=%d") % uDirectTip % uDirectEnd % bDirectAdvance); - } - - if (bDirectAdvance) - { - // Get next quality. - uDirectTip = mLedger->getNextLedgerIndex(uDirectTip, uDirectEnd); - bDirectDirDirty = true; - bDirectAdvance = false; - - if (!!uDirectTip) - { - // Have another quality directory. - Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: Quality advance: uDirectTip=%s") % uDirectTip); - - sleDirectDir = entryCache(ltDIR_NODE, uDirectTip); - } - else if (bReverse) - { - Log(lsINFO) << "calcNodeAdvance: No more offers."; - - uOfferIndex = 0; - break; - } - else - { - // No more offers. Should be done rather than fall off end of book. - Log(lsINFO) << "calcNodeAdvance: Unreachable: Fell off end of order book."; - assert(false); - - terResult = tefEXCEPTION; - } - } - - if (bDirectDirDirty) - { - saOfrRate = STAmount::setRate(Ledger::getQuality(uDirectTip)); // For correct ratio - uEntry = 0; - bEntryAdvance = true; - - Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: directory dirty: saOfrRate=%s") % saOfrRate); - } - - if (!bEntryAdvance) - { - if (bFundsDirty) - { - saTakerPays = sleOffer->getIValueFieldAmount(sfTakerPays); - saTakerGets = sleOffer->getIValueFieldAmount(sfTakerGets); - - saOfferFunds = accountFunds(uOfrOwnerID, saTakerGets); // Funds left. - bFundsDirty = false; - - Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: directory dirty: saOfrRate=%s") % saOfrRate); - } - else - { - Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: as is")); - nothing(); - } - } - else if (!mNodes.dirNext(uDirectTip, sleDirectDir, uEntry, uOfferIndex)) - { - // Failed to find an entry in directory. - - uOfferIndex = 0; - - // Do another cur directory iff bMultiQuality - if (bMultiQuality) - { - Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: next quality")); - bDirectAdvance = true; - } - else if (!bReverse) - { - Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: unreachable: ran out of offers")); - assert(false); // Can't run out of offers in forward direction. - terResult = tefEXCEPTION; - } - } - else - { - // Got a new offer. - sleOffer = entryCache(ltOFFER, uOfferIndex); - uOfrOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); - - const aciSource asLine = boost::make_tuple(uOfrOwnerID, uCurCurrencyID, uCurIssuerID); - - Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: uOfrOwnerID=%s") % NewcoinAddress::createHumanAccountID(uOfrOwnerID)); - - if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) - { - // Offer is expired. - Log(lsINFO) << "calcNodeAdvance: expired offer"; - - assert(musUnfundedFound.find(uOfferIndex) != musUnfundedFound.end()); // Verify reverse found it too. - bEntryAdvance = true; - continue; - } - - // Allowed to access source from this node? - // XXX This can get called multiple times for same source in a row, caching result would be nice. - curIssuerNodeConstIterator itForward = pspCur->umForward.find(asLine); - const bool bFoundForward = itForward != pspCur->umForward.end(); - - if (bFoundForward && itForward->second != uIndex) - { - // Temporarily unfunded. Another node uses this source, ignore in this offer. - Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (forward)"; - - bEntryAdvance = true; - continue; - } - - curIssuerNodeConstIterator itPast = mumSource.find(asLine); - bool bFoundPast = itPast != mumSource.end(); - - if (bFoundPast && itPast->second != uIndex) - { - // Temporarily unfunded. Another node uses this source, ignore in this offer. - Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (past)"; - - bEntryAdvance = true; - continue; - } - - curIssuerNodeConstIterator itReverse = pspCur->umReverse.find(asLine); - bool bFoundReverse = itReverse != pspCur->umReverse.end(); - - if (bFoundReverse && itReverse->second != uIndex) - { - // Temporarily unfunded. Another node uses this source, ignore in this offer. - Log(lsINFO) << "calcNodeAdvance: temporarily unfunded offer (reverse)"; - - bEntryAdvance = true; - continue; - } - - saTakerPays = sleOffer->getIValueFieldAmount(sfTakerPays); - saTakerGets = sleOffer->getIValueFieldAmount(sfTakerGets); - - saOfferFunds = accountFunds(uOfrOwnerID, saTakerGets); // Funds left. - - if (!saOfferFunds.isPositive()) - { - // Offer is unfunded. - Log(lsINFO) << "calcNodeAdvance: unfunded offer"; - - if (bReverse && !bFoundReverse && !bFoundPast) - { - // Never mentioned before: found unfunded. - musUnfundedFound.insert(uOfferIndex); // Mark offer for always deletion. - } - - // YYY Could verify offer is correct place for unfundeds. - bEntryAdvance = true; - continue; - } - - if (bReverse // Need to remember reverse mention. - && !bFoundPast // Not mentioned in previous passes. - && !bFoundReverse) // Not mentioned for pass. - { - // Consider source mentioned by current path state. - Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: remember=%s/%s/%s") - % NewcoinAddress::createHumanAccountID(uOfrOwnerID) - % STAmount::createHumanCurrency(uCurCurrencyID) - % NewcoinAddress::createHumanAccountID(uCurIssuerID)); - - pspCur->umReverse.insert(std::make_pair(asLine, uIndex)); - } - - bFundsDirty = false; - bEntryAdvance = false; - } - } - while (tesSUCCESS == terResult && (bEntryAdvance || bDirectAdvance)); - - if (tesSUCCESS == terResult) - { - Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: uOfferIndex=%s") % uOfferIndex); - } - else - { - Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: terResult=%s") % transToken(terResult)); - } - - return terResult; -} - -// Between offer nodes, the fee charged may vary. Therefore, process one inbound offer at a time. -// Propagate the inbound offer's requirements to the previous node. The previous node adjusts the amount output and the -// amount spent on fees. -// Continue process till request is satisified while we the rate does not increase past the initial rate. -TER TransactionEngine::calcNodeDeliverRev( - const unsigned int uIndex, // 0 < uIndex < uLast - const PathState::pointer& pspCur, - const bool bMultiQuality, - const uint160& uOutAccountID, // --> Output owner's account. - const STAmount& saOutReq, // --> Funds wanted. - STAmount& saOutAct) // <-- Funds delivered. -{ - TER terResult = tesSUCCESS; - - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - - const uint160& uCurIssuerID = pnCur.uIssuerID; - const uint160& uPrvAccountID = pnPrv.uAccountID; - const STAmount& saTransferRate = pnCur.saTransferRate; - - STAmount& saPrvDlvReq = pnPrv.saRevDeliver; // To be adjusted. - - saOutAct = 0; - - while (saOutAct != saOutReq) // Did not deliver limit. - { - bool& bEntryAdvance = pnCur.bEntryAdvance; - STAmount& saOfrRate = pnCur.saOfrRate; - uint256& uOfferIndex = pnCur.uOfferIndex; - SLE::pointer& sleOffer = pnCur.sleOffer; - const uint160& uOfrOwnerID = pnCur.uOfrOwnerID; - bool& bFundsDirty = pnCur.bFundsDirty; - STAmount& saOfferFunds = pnCur.saOfferFunds; - STAmount& saTakerPays = pnCur.saTakerPays; - STAmount& saTakerGets = pnCur.saTakerGets; - STAmount& saRateMax = pnCur.saRateMax; - - terResult = calcNodeAdvance(uIndex, pspCur, bMultiQuality, true); // If needed, advance to next funded offer. - - if (tesSUCCESS != terResult || !uOfferIndex) - { - // Error or out of offers. - break; - } - - const STAmount saOutFeeRate = uOfrOwnerID == uCurIssuerID || uOutAccountID == uCurIssuerID // Issuer receiving or sending. - ? saOne // No fee. - : saTransferRate; // Transfer rate of issuer. - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: uOfrOwnerID=%s uOutAccountID=%s uCurIssuerID=%s saTransferRate=%s saOutFeeRate=%s") - % NewcoinAddress::createHumanAccountID(uOfrOwnerID) - % NewcoinAddress::createHumanAccountID(uOutAccountID) - % NewcoinAddress::createHumanAccountID(uCurIssuerID) - % saTransferRate.getFullText() - % saOutFeeRate.getFullText()); - - if (!saRateMax) - { - // Set initial rate. - saRateMax = saOutFeeRate; - - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Set initial rate: saRateMax=%s saOutFeeRate=%s") - % saRateMax - % saOutFeeRate); - } - else if (saRateMax < saOutFeeRate) - { - // Offer exceeds initial rate. - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Offer exceeds initial rate: saRateMax=%s saOutFeeRate=%s") - % saRateMax - % saOutFeeRate); - - nothing(); - break; - } - else if (saOutFeeRate < saRateMax) - { - // Reducing rate. - - saRateMax = saOutFeeRate; - - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Reducing rate: saRateMax=%s") - % saRateMax); - } - - STAmount saOutPass = std::min(std::min(saOfferFunds, saTakerGets), saOutReq-saOutAct); // Offer maximum out - assuming no out fees. - STAmount saOutPlusFees = STAmount::multiply(saOutPass, saOutFeeRate); // Offer out with fees. - - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: saOutReq=%s saOutAct=%s saTakerGets=%s saOutPass=%s saOutPlusFees=%s saOfferFunds=%s") - % saOutReq - % saOutAct - % saTakerGets - % saOutPass - % saOutPlusFees - % saOfferFunds); - - if (saOutPlusFees > saOfferFunds) - { - // Offer owner can not cover all fees, compute saOutPass based on saOfferFunds. - - saOutPlusFees = saOfferFunds; - saOutPass = STAmount::divide(saOutPlusFees, saOutFeeRate); - - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: Total exceeds fees: saOutPass=%s saOutPlusFees=%s saOfferFunds=%s") - % saOutPass - % saOutPlusFees - % saOfferFunds); - } - - // Compute portion of input needed to cover output. - - STAmount saInPassReq = STAmount::multiply(saOutPass, saOfrRate, saTakerPays); - STAmount saInPassAct; - - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: saInPassReq=%s saOfrRate=%s saOutPass=%s saOutPlusFees=%s") - % saInPassReq - % saOfrRate - % saOutPass - % saOutPlusFees); - - // Find out input amount actually available at current rate. - if (!!uPrvAccountID) - { - // account --> OFFER --> ? - // Previous is the issuer and receiver is an offer, so no fee or quality. - // Previous is the issuer and has unlimited funds. - // Offer owner is obtaining IOUs via an offer, so credit line limits are ignored. - // As limits are ignored, don't need to adjust previous account's balance. - - saInPassAct = saInPassReq; - - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: account --> OFFER --> ? : saInPassAct=%s") - % saPrvDlvReq); - } - else - { - // offer --> OFFER --> ? - - terResult = calcNodeDeliverRev( - uIndex-1, - pspCur, - bMultiQuality, - uOfrOwnerID, - saInPassReq, - saInPassAct); - - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: offer --> OFFER --> ? : saInPassAct=%s") - % saInPassAct); - } - - if (tesSUCCESS != terResult) - break; - - if (saInPassAct != saInPassReq) - { - // Adjust output to conform to limited input. - saOutPass = STAmount::divide(saInPassAct, saOfrRate, saTakerGets); - saOutPlusFees = STAmount::multiply(saOutPass, saOutFeeRate); - - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: adjusted: saOutPass=%s saOutPlusFees=%s") - % saOutPass - % saOutPlusFees); - } - - // Funds were spent. - bFundsDirty = true; - - // Deduct output, don't actually need to send. - accountSend(uOfrOwnerID, uCurIssuerID, saOutPass); - - // Adjust offer - sleOffer->setIFieldAmount(sfTakerGets, saTakerGets - saOutPass); - sleOffer->setIFieldAmount(sfTakerPays, saTakerPays - saInPassAct); - - entryModify(sleOffer); - - if (saOutPass == saTakerGets) - { - // Offer became unfunded. - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverRev: offer became unfunded.")); - - bEntryAdvance = true; - } - - saOutAct += saOutPass; - saPrvDlvReq += saInPassAct; - } - - if (!saOutAct) - terResult = tepPATH_DRY; - - return terResult; -} - -// Deliver maximum amount of funds from previous node. -// Goal: Make progress consuming the offer. -TER TransactionEngine::calcNodeDeliverFwd( - const unsigned int uIndex, // 0 < uIndex < uLast - const PathState::pointer& 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. - STAmount& saInAct, // <-- Amount delivered. - STAmount& saInFees) // <-- Fees charged. -{ - TER terResult = tesSUCCESS; - - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; - - const uint160& uNxtAccountID = pnNxt.uAccountID; - const uint160& uCurIssuerID = pnCur.uIssuerID; - const uint160& uPrvIssuerID = pnPrv.uIssuerID; - const STAmount& saTransferRate = pnPrv.saTransferRate; - - saInAct = 0; - saInFees = 0; - - while (tesSUCCESS == terResult - && saInAct != saInReq // Did not deliver limit. - && saInAct + saInFees != saInFunds) // Did not deliver all funds. - { - terResult = calcNodeAdvance(uIndex, pspCur, bMultiQuality, false); // If needed, advance to next funded offer. - - if (tesSUCCESS == terResult) - { - bool& bEntryAdvance = pnCur.bEntryAdvance; - STAmount& saOfrRate = pnCur.saOfrRate; - uint256& uOfferIndex = pnCur.uOfferIndex; - SLE::pointer& sleOffer = pnCur.sleOffer; - const uint160& uOfrOwnerID = pnCur.uOfrOwnerID; - bool& bFundsDirty = pnCur.bFundsDirty; - STAmount& saOfferFunds = pnCur.saOfferFunds; - 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. - - // - // First calculate assuming no output fees. - // XXX Make sure derived in does not exceed actual saTakerPays due to rounding. - - 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 saInPassAct = STAmount::divide(saInSum, saInFeeRate); // In without fees. - STAmount saOutPassMax = STAmount::divide(saInPassAct, saOfrRate, saOutFunded); // Out. - - STAmount saInPassFees; - STAmount saOutPassAct; - - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: saOutFunded=%s saInFunded=%s saInTotal=%s saInSum=%s saInPassAct=%s saOutPassMax=%s") - % saOutFunded - % saInFunded - % saInTotal - % saInSum - % saInPassAct - % saOutPassMax); - - if (!!uNxtAccountID) - { - // ? --> 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. - accountSend(uOfrOwnerID, uCurIssuerID, saOutPassMax); - - saOutPassAct = saOutPassMax; - - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: ? --> OFFER --> account: saOutPassAct=%s") - % saOutPassAct); - } - else - { - // ? --> OFFER --> offer - STAmount saOutPassFees; - - terResult = TransactionEngine::calcNodeDeliverFwd( - uIndex+1, - pspCur, - bMultiQuality, - uOfrOwnerID, - saOutPassMax, - saOutPassMax, - saOutPassAct, // <-- Amount delivered. - saOutPassFees); // <-- Fees charged. - - if (tesSUCCESS != terResult) - break; - - // Offer maximum in limited by next payout. - saInPassAct = STAmount::multiply(saOutPassAct, saOfrRate); - saInPassFees = STAmount::multiply(saInFunded, saInFeeRate)-saInPassAct; - } - - Log(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: saTakerGets=%s saTakerPays=%s saInPassAct=%s saOutPassAct=%s") - % saTakerGets.getFullText() - % saTakerPays.getFullText() - % saInPassAct.getFullText() - % saOutPassAct.getFullText()); - - // Funds were spent. - bFundsDirty = true; - - // Credit issuer transfer fees. - accountSend(uInAccountID, uOfrOwnerID, saInPassFees); - - // Credit offer owner from offer. - accountSend(uInAccountID, uOfrOwnerID, saInPassAct); - - // Adjust offer - sleOffer->setIFieldAmount(sfTakerGets, saTakerGets - saOutPassAct); - sleOffer->setIFieldAmount(sfTakerPays, saTakerPays - saInPassAct); - - entryModify(sleOffer); - - if (saOutPassAct == saTakerGets) - { - // Offer became unfunded. - pspCur->vUnfundedBecame.push_back(uOfferIndex); - bEntryAdvance = true; - } - - saInAct += saInPassAct; - saInFees += saInPassFees; - } - } - - return terResult; -} - -// Called to drive from the last offer node in a chain. -TER TransactionEngine::calcNodeOfferRev( - const unsigned int uIndex, // 0 < uIndex < uLast - const PathState::pointer& pspCur, - const bool bMultiQuality) -{ - TER terResult; - - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - PaymentNode& pnNxt = pspCur->vpnNodes[uIndex+1]; - - if (!!pnNxt.uAccountID) - { - // Next is an account node, resolve current offer node's deliver. - STAmount saDeliverAct; - - terResult = calcNodeDeliverRev( - uIndex, - pspCur, - bMultiQuality, - - pnNxt.uAccountID, - pnCur.saRevDeliver, - saDeliverAct); - } - else - { - // Next is an offer. Deliver has already been resolved. - terResult = tesSUCCESS; - } - - return terResult; -} - -// Called to drive the from the first offer node in a chain. -// - Offer input is limbo. -// - Current offers consumed. -// - Current offer owners debited. -// - Transfer fees credited to issuer. -// - Payout to issuer or limbo. -// - Deliver is set without transfer fees. -TER TransactionEngine::calcNodeOfferFwd( - const unsigned int uIndex, // 0 < uIndex < uLast - const PathState::pointer& pspCur, - const bool bMultiQuality - ) -{ - TER terResult; - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex-1]; - - if (!!pnPrv.uAccountID) - { - // Previous is an account node, resolve its deliver. - STAmount saInAct; - STAmount saInFees; - - terResult = calcNodeDeliverFwd( - uIndex, - pspCur, - bMultiQuality, - pnPrv.uAccountID, - pnPrv.saFwdDeliver, - pnPrv.saFwdDeliver, - saInAct, - saInFees); - - assert(tesSUCCESS != terResult || pnPrv.saFwdDeliver == saInAct+saInFees); - } - else - { - // Previous is an offer. Deliver has already been resolved. - terResult = tesSUCCESS; - } - - return terResult; - -} - -// Cur is the driver and will be filled exactly. -// uQualityIn -> uQualityOut -// saPrvReq -> saCurReq -// sqPrvAct -> saCurAct -// This is a minimizing routine: moving in reverse it propagates the send limit to the sender, moving forward it propagates the -// actual send toward the receiver. -// This routine works backwards as it calculates previous wants based on previous credit limits and current wants. -// This routine works forwards as it calculates current deliver based on previous delivery limits and current wants. -// XXX Deal with uQualityIn or uQualityOut = 0 -void TransactionEngine::calcNodeRipple( - const uint32 uQualityIn, - const uint32 uQualityOut, - const STAmount& saPrvReq, // --> in limit including fees, <0 = unlimited - const STAmount& saCurReq, // --> out limit (driver) - STAmount& saPrvAct, // <-> in limit including achieved - STAmount& saCurAct, // <-> out limit achieved. - uint64& uRateMax) -{ - Log(lsINFO) << boost::str(boost::format("calcNodeRipple> uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s") - % uQualityIn - % uQualityOut - % saPrvReq.getFullText() - % saCurReq.getFullText() - % saPrvAct.getFullText() - % saCurAct.getFullText()); - - assert(saPrvReq.getCurrency() == saCurReq.getCurrency()); - - const bool bPrvUnlimited = saPrvReq.isNegative(); - const STAmount saPrv = bPrvUnlimited ? STAmount(saPrvReq) : saPrvReq-saPrvAct; - const STAmount saCur = saCurReq-saCurAct; - -#if 0 - Log(lsINFO) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCur=%s") - % bPrvUnlimited - % saPrv.getFullText() - % saCur.getFullText()); -#endif - - if (uQualityIn >= uQualityOut) - { - // No fee. - Log(lsINFO) << boost::str(boost::format("calcNodeRipple: No fees")); - - if (!uRateMax || STAmount::uRateOne <= uRateMax) - { - STAmount saTransfer = bPrvUnlimited ? saCur : std::min(saPrv, saCur); - - saPrvAct += saTransfer; - saCurAct += saTransfer; - - if (!uRateMax) - uRateMax = STAmount::uRateOne; - } - } - else - { - // Fee. - Log(lsINFO) << boost::str(boost::format("calcNodeRipple: Fee")); - - uint64 uRate = STAmount::getRate(STAmount(uQualityIn), STAmount(uQualityOut)); - - if (!uRateMax || uRate <= uRateMax) - { - const uint160 uCurrencyID = saCur.getCurrency(); - const uint160 uCurIssuerID = saCur.getIssuer(); - const uint160 uPrvIssuerID = saPrv.getIssuer(); - - STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID, uCurIssuerID), uQualityIn, uCurrencyID, uCurIssuerID); - - Log(lsINFO) << boost::str(boost::format("calcNodeRipple: bPrvUnlimited=%d saPrv=%s saCurIn=%s") % bPrvUnlimited % saPrv.getFullText() % saCurIn.getFullText()); - if (bPrvUnlimited || saCurIn <= saPrv) - { - // All of cur. Some amount of prv. - saCurAct += saCur; - saPrvAct += saCurIn; - Log(lsINFO) << boost::str(boost::format("calcNodeRipple:3c: saCurReq=%s saPrvAct=%s") % saCurReq.getFullText() % saPrvAct.getFullText()); - } - else - { - // A part of cur. All of prv. (cur as driver) - STAmount saCurOut = STAmount::divide(STAmount::multiply(saPrv, uQualityIn, uCurrencyID, uCurIssuerID), uQualityOut, uCurrencyID, uCurIssuerID); - Log(lsINFO) << boost::str(boost::format("calcNodeRipple:4: saCurReq=%s") % saCurReq.getFullText()); - - saCurAct += saCurOut; - saPrvAct = saPrvReq; - - if (!uRateMax) - uRateMax = uRate; - } - } - } - - Log(lsINFO) << boost::str(boost::format("calcNodeRipple< uQualityIn=%d uQualityOut=%d saPrvReq=%s saCurReq=%s saPrvAct=%s saCurAct=%s") - % uQualityIn - % uQualityOut - % saPrvReq.getFullText() - % saCurReq.getFullText() - % saPrvAct.getFullText() - % saCurAct.getFullText()); -} - -// Calculate saPrvRedeemReq, saPrvIssueReq, saPrvDeliver from saCur... -// <-- tesSUCCESS or tepPATH_DRY -TER TransactionEngine::calcNodeAccountRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) -{ - TER terResult = tesSUCCESS; - const unsigned int uLast = pspCur->vpnNodes.size() - 1; - - uint64 uRateMax = 0; - - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - - // Current is allowed to redeem to next. - const bool bPrvAccount = !uIndex || isSetBit(pnPrv.uFlags, STPathElement::typeAccount); - const bool bNxtAccount = uIndex == uLast || isSetBit(pnNxt.uFlags, STPathElement::typeAccount); - - const uint160& uCurAccountID = pnCur.uAccountID; - const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; - const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. - - const uint160& uCurrencyID = pnCur.uCurrencyID; - - const uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; - const uint32 uQualityOut = uIndex != uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; - - // For bPrvAccount - const STAmount saPrvOwed = bPrvAccount && uIndex // Previous account is owed. - ? rippleOwed(uCurAccountID, uPrvAccountID, uCurrencyID) - : STAmount(uCurrencyID, uCurAccountID); - - const STAmount saPrvLimit = bPrvAccount && uIndex // Previous account may owe. - ? rippleLimit(uCurAccountID, uPrvAccountID, uCurrencyID) - : STAmount(uCurrencyID, uCurAccountID); - - const STAmount saNxtOwed = bNxtAccount && uIndex != uLast // Next account is owed. - ? rippleOwed(uCurAccountID, uNxtAccountID, uCurrencyID) - : STAmount(uCurrencyID, uCurAccountID); - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev> uIndex=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s") - % uIndex - % uLast - % NewcoinAddress::createHumanAccountID(uPrvAccountID) - % NewcoinAddress::createHumanAccountID(uCurAccountID) - % NewcoinAddress::createHumanAccountID(uNxtAccountID) - % STAmount::createHumanCurrency(uCurrencyID) - % uQualityIn - % uQualityOut - % saPrvOwed.getFullText() - % saPrvLimit.getFullText()); - - // Previous can redeem the owed IOUs it holds. - const STAmount saPrvRedeemReq = saPrvOwed.isPositive() ? saPrvOwed : STAmount(uCurrencyID, 0); - STAmount& saPrvRedeemAct = pnPrv.saRevRedeem; - - // Previous can issue up to limit minus whatever portion of limit already used (not including redeemable amount). - const STAmount saPrvIssueReq = saPrvOwed.isNegative() ? saPrvLimit+saPrvOwed : saPrvLimit; - STAmount& saPrvIssueAct = pnPrv.saRevIssue; - - // For !bPrvAccount - const STAmount saPrvDeliverReq = STAmount::saFromSigned(uCurrencyID, uCurAccountID, -1); // Unlimited. - STAmount& saPrvDeliverAct = pnPrv.saRevDeliver; - - // For bNxtAccount - const STAmount& saCurRedeemReq = pnCur.saRevRedeem; - STAmount saCurRedeemAct(saCurRedeemReq.getCurrency(), saCurRedeemReq.getIssuer()); - - const STAmount& saCurIssueReq = pnCur.saRevIssue; - STAmount saCurIssueAct(saCurIssueReq.getCurrency(), saCurIssueReq.getIssuer()); // Track progress. - - // For !bNxtAccount - const STAmount& saCurDeliverReq = pnCur.saRevDeliver; - STAmount saCurDeliverAct(saCurDeliverReq.getCurrency(), saCurDeliverReq.getIssuer()); - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurRedeemReq=%s saNxtOwed=%s") - % saPrvRedeemReq.getFullText() - % saPrvIssueReq.getFullText() - % saCurRedeemReq.getFullText() - % saNxtOwed.getFullText()); - - Log(lsINFO) << pspCur->getJson(); - - assert(!saCurRedeemReq || (-saNxtOwed) >= saCurRedeemReq); // Current redeem req can't be more than IOUs on hand. - assert(!saCurIssueReq || !saNxtOwed.isPositive() || saNxtOwed == saCurRedeemReq); // If issue req, then redeem req must consume all owed. - - if (bPrvAccount && bNxtAccount) - { - if (!uIndex) - { - // ^ --> ACCOUNT --> account|offer - // Nothing to do, there is no previous to adjust. - nothing(); - } - else if (uIndex == uLast) - { - // account --> ACCOUNT --> $ - // Overall deliverable. - const STAmount& saCurWantedReq = bPrvAccount - ? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. - : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. - STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> $ : saCurWantedReq=%s") - % saCurWantedReq.getFullText()); - - // Calculate redeem - if (saPrvRedeemReq) // Previous has IOUs to redeem. - { - // Redeem at 1:1 - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Redeem at 1:1")); - - saCurWantedAct = std::min(saPrvRedeemReq, saCurWantedReq); - saPrvRedeemAct = saCurWantedAct; - - uRateMax = STAmount::uRateOne; - } - - // Calculate issuing. - if (saCurWantedReq != saCurWantedAct // Need more. - && saPrvIssueReq) // Will accept IOUs from prevous. - { - // Rate: quality in : 1.0 - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); - - // If we previously redeemed and this has a poorer rate, this won't be included the current increment. - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurWantedReq, saPrvIssueAct, saCurWantedAct, uRateMax); - } - - if (!saCurWantedAct) - { - // Must have processed something. - terResult = tepPATH_DRY; - } - } - else - { - // ^|account --> ACCOUNT --> account - - // redeem (part 1) -> redeem - if (saCurRedeemReq // Next wants IOUs redeemed. - && saPrvRedeemReq) // Previous has IOUs to redeem. - { - // Rate : 1.0 : quality out - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : quality out")); - - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax); - } - - // issue (part 1) -> redeem - if (saCurRedeemReq != saCurRedeemAct // Next wants more IOUs redeemed. - && saPrvRedeemAct == saPrvRedeemReq) // Previous has no IOUs to redeem remaining. - { - // Rate: quality in : quality out - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : quality out")); - - calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct, uRateMax); - } - - // redeem (part 2) -> issue. - if (saCurIssueReq // Next wants IOUs issued. - && saCurRedeemAct == saCurRedeemReq // Can only issue if completed redeeming. - && saPrvRedeemAct != saPrvRedeemReq) // Did not complete redeeming previous IOUs. - { - // Rate : 1.0 : transfer_rate - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate : 1.0 : transfer_rate")); - - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax); - } - - // issue (part 2) -> issue - if (saCurIssueReq != saCurIssueAct // Need wants more IOUs issued. - && saCurRedeemAct == saCurRedeemReq // Can only issue if completed redeeming. - && saPrvRedeemReq == saPrvRedeemAct) // Previously redeemed all owed IOUs. - { - // Rate: quality in : 1.0 - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: Rate: quality in : 1.0")); - - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax); - } - - if (!saCurRedeemAct && !saCurIssueAct) - { - // Must want something. - terResult = tepPATH_DRY; - } - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: ^|account --> ACCOUNT --> account : saCurRedeemReq=%s saCurIssueReq=%s saPrvOwed=%s saCurRedeemAct=%s saCurIssueAct=%s") - % saCurRedeemReq.getFullText() - % saCurIssueReq.getFullText() - % saPrvOwed.getFullText() - % saCurRedeemAct.getFullText() - % saCurIssueAct.getFullText()); - } - } - else if (bPrvAccount && !bNxtAccount) - { - // account --> ACCOUNT --> offer - // Note: deliver is always issue as ACCOUNT is the issuer for the offer input. - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: account --> ACCOUNT --> offer")); - - // redeem -> deliver/issue. - if (saPrvOwed.isPositive() // Previous has IOUs to redeem. - && saCurDeliverReq) // Need some issued. - { - // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct, uRateMax); - } - - // issue -> deliver/issue - if (saPrvRedeemReq == saPrvRedeemAct // Previously redeemed all owed. - && saCurDeliverReq != saCurDeliverAct) // Still need some issued. - { - // Rate: quality in : 1.0 - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurDeliverReq, saPrvIssueAct, saCurDeliverAct, uRateMax); - } - - if (!saCurDeliverAct) - { - // Must want something. - terResult = tepPATH_DRY; - } - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saCurDeliverReq=%s saCurDeliverAct=%s saPrvOwed=%s") - % saCurDeliverReq.getFullText() - % saCurDeliverAct.getFullText() - % saPrvOwed.getFullText()); - } - else if (!bPrvAccount && bNxtAccount) - { - if (uIndex == uLast) - { - // offer --> ACCOUNT --> $ - const STAmount& saCurWantedReq = bPrvAccount - ? std::min(pspCur->saOutReq, saPrvLimit+saPrvOwed) // If previous is an account, limit. - : pspCur->saOutReq; // Previous is an offer, no limit: redeem own IOUs. - STAmount saCurWantedAct(saCurWantedReq.getCurrency(), saCurWantedReq.getIssuer()); - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> $ : saCurWantedReq=%s") - % saCurWantedReq.getFullText()); - - // Rate: quality in : 1.0 - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvDeliverReq, saCurWantedReq, saPrvDeliverAct, saCurWantedAct, uRateMax); - - if (!saCurWantedAct) - { - // Must have processed something. - terResult = tepPATH_DRY; - } - } - else - { - // offer --> ACCOUNT --> account - // Note: offer is always delivering(redeeming) as account is issuer. - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> account")); - - // deliver -> redeem - if (saCurRedeemReq) // Next wants us to redeem. - { - // Rate : 1.0 : quality out - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct, uRateMax); - } - - // deliver -> issue. - if (saCurRedeemReq == saCurRedeemAct // Can only issue if previously redeemed all. - && saCurIssueReq) // Need some issued. - { - // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct, uRateMax); - } - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: saCurRedeemReq=%s saCurIssueAct=%s saCurIssueReq=%s saPrvDeliverAct=%s") - % saCurRedeemReq.getFullText() - % saCurRedeemAct.getFullText() - % saCurIssueReq.getFullText() - % saPrvDeliverAct.getFullText()); - - if (!saPrvDeliverAct) - { - // Must want something. - terResult = tepPATH_DRY; - } - } - } - else - { - // offer --> ACCOUNT --> offer - // deliver/redeem -> deliver/issue. - Log(lsINFO) << boost::str(boost::format("calcNodeAccountRev: offer --> ACCOUNT --> offer")); - - // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct, uRateMax); - - if (!saCurDeliverAct) - { - // Must want something. - terResult = tepPATH_DRY; - } - } - - return terResult; -} - -// Perfrom balance adjustments between previous and current node. -// - The previous node: specifies what to push through to current. -// - All of previous output is consumed. -// Then, compute 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. -TER TransactionEngine::calcNodeAccountFwd( - const unsigned int uIndex, // 0 <= uIndex <= uLast - const PathState::pointer& pspCur, - const bool bMultiQuality) -{ - TER terResult = tesSUCCESS; - const unsigned int uLast = pspCur->vpnNodes.size() - 1; - - uint64 uRateMax = 0; - - PaymentNode& pnPrv = pspCur->vpnNodes[uIndex ? uIndex-1 : 0]; - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - PaymentNode& pnNxt = pspCur->vpnNodes[uIndex == uLast ? uLast : uIndex+1]; - - const bool bPrvAccount = isSetBit(pnPrv.uFlags, STPathElement::typeAccount); - const bool bNxtAccount = isSetBit(pnNxt.uFlags, STPathElement::typeAccount); - - const uint160& uCurAccountID = pnCur.uAccountID; - const uint160& uPrvAccountID = bPrvAccount ? pnPrv.uAccountID : uCurAccountID; - const uint160& uNxtAccountID = bNxtAccount ? pnNxt.uAccountID : uCurAccountID; // Offers are always issue. - - const uint160& uCurrencyID = pnCur.uCurrencyID; - - uint32 uQualityIn = uIndex ? rippleQualityIn(uCurAccountID, uPrvAccountID, uCurrencyID) : QUALITY_ONE; - uint32 uQualityOut = uIndex == uLast ? rippleQualityOut(uCurAccountID, uNxtAccountID, uCurrencyID) : QUALITY_ONE; - - // For bNxtAccount - const STAmount& saPrvRedeemReq = pnPrv.saFwdRedeem; - STAmount saPrvRedeemAct(saPrvRedeemReq.getCurrency(), saPrvRedeemReq.getIssuer()); - - const STAmount& saPrvIssueReq = pnPrv.saFwdIssue; - STAmount saPrvIssueAct(saPrvIssueReq.getCurrency(), saPrvIssueReq.getIssuer()); - - // For !bPrvAccount - const STAmount& saPrvDeliverReq = pnPrv.saRevDeliver; - STAmount saPrvDeliverAct(saPrvDeliverReq.getCurrency(), saPrvDeliverReq.getIssuer()); - - // For bNxtAccount - const STAmount& saCurRedeemReq = pnCur.saRevRedeem; - STAmount& saCurRedeemAct = pnCur.saFwdRedeem; - - const STAmount& saCurIssueReq = pnCur.saRevIssue; - STAmount& saCurIssueAct = pnCur.saFwdIssue; - - // For !bNxtAccount - const STAmount& saCurDeliverReq = pnCur.saRevDeliver; - STAmount& saCurDeliverAct = pnCur.saFwdDeliver; - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd> uIndex=%d/%d saPrvRedeemReq=%s saPrvIssueReq=%s saPrvDeliverReq=%s saCurRedeemReq=%s saCurIssueReq=%s saCurDeliverReq=%s") - % uIndex - % uLast - % saPrvRedeemReq.getFullText() - % saPrvIssueReq.getFullText() - % saPrvDeliverReq.getFullText() - % saCurRedeemReq.getFullText() - % saCurIssueReq.getFullText() - % saCurDeliverReq.getFullText()); - - // Ripple through account. - - if (bPrvAccount && bNxtAccount) - { - if (!uIndex) - { - // ^ --> ACCOUNT --> account - - // First node, calculate amount to send. - // XXX Use stamp/ripple balance - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - - const STAmount& saCurRedeemReq = pnCur.saRevRedeem; - STAmount& saCurRedeemAct = pnCur.saFwdRedeem; - const STAmount& saCurIssueReq = pnCur.saRevIssue; - STAmount& saCurIssueAct = pnCur.saFwdIssue; - - const STAmount& saCurSendMaxReq = pspCur->saInReq; // Negative for no limit, doing a calculation. - STAmount& saCurSendMaxAct = pspCur->saInAct; // Report to user how much this sends. - - if (saCurRedeemReq) - { - // Redeem requested. - saCurRedeemAct = saCurRedeemReq.isNegative() - ? saCurRedeemReq - : std::min(saCurRedeemReq, saCurSendMaxReq); - } - else - { - saCurRedeemAct = STAmount(saCurRedeemReq); - } - saCurSendMaxAct = saCurRedeemAct; - - if (saCurIssueReq && (saCurSendMaxReq.isNegative() || saCurSendMaxReq != saCurRedeemAct)) - { - // Issue requested and not over budget. - saCurIssueAct = saCurSendMaxReq.isNegative() - ? saCurIssueReq - : std::min(saCurSendMaxReq-saCurRedeemAct, saCurIssueReq); - } - else - { - saCurIssueAct = STAmount(saCurIssueReq); - } - saCurSendMaxAct += saCurIssueAct; - - Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: ^ --> ACCOUNT --> account : saCurSendMaxReq=%s saCurRedeemAct=%s saCurIssueReq=%s saCurIssueAct=%s") - % saCurSendMaxReq.getFullText() - % saCurRedeemAct.getFullText() - % saCurIssueReq.getFullText() - % saCurIssueAct.getFullText()); - } - else if (uIndex == uLast) - { - // account --> ACCOUNT --> $ - Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> $ : uPrvAccountID=%s uCurAccountID=%s saPrvRedeemReq=%s saPrvIssueReq=%s") - % NewcoinAddress::createHumanAccountID(uPrvAccountID) - % NewcoinAddress::createHumanAccountID(uCurAccountID) - % saPrvRedeemReq.getFullText() - % saPrvIssueReq.getFullText()); - - // Last node. Accept all funds. Calculate amount actually to credit. - - STAmount& saCurReceive = pspCur->saOutAct; - - STAmount saIssueCrd = uQualityIn >= QUALITY_ONE - ? saPrvIssueReq // No fee. - : STAmount::multiply(saPrvIssueReq, uQualityIn, uCurrencyID, saPrvIssueReq.getIssuer()); // Fee. - - // Amount to credit. - saCurReceive = saPrvRedeemReq+saIssueCrd; - - // Actually receive. - rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq+saPrvIssueReq, false); - } - else - { - // account --> ACCOUNT --> account - Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> account")); - - // Previous redeem part 1: redeem -> redeem - if (saPrvRedeemReq != saPrvRedeemAct) // Previous wants to redeem. To next must be ok. - { - // Rate : 1.0 : quality out - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvRedeemReq, saCurRedeemReq, saPrvRedeemAct, saCurRedeemAct, uRateMax); - } - - // Previous issue part 1: issue -> redeem - if (saPrvIssueReq != saPrvIssueAct // Previous wants to issue. - && saCurRedeemReq != saCurRedeemAct) // Current has more to redeem to next. - { - // Rate: quality in : quality out - calcNodeRipple(uQualityIn, uQualityOut, saPrvIssueReq, saCurRedeemReq, saPrvIssueAct, saCurRedeemAct, uRateMax); - } - - // Previous redeem part 2: redeem -> issue. - // wants to redeem and current would and can issue. - // If redeeming cur to next is done, this implies can issue. - if (saPrvRedeemReq != saPrvRedeemAct // Previous still wants to redeem. - && saCurRedeemReq == saCurRedeemAct // Current has no more to redeem to next. - && saCurIssueReq) - { - // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurIssueReq, saPrvRedeemAct, saCurIssueAct, uRateMax); - } - - // Previous issue part 2 : issue -> issue - if (saPrvIssueReq != saPrvIssueAct) // Previous wants to issue. To next must be ok. - { - // Rate: quality in : 1.0 - calcNodeRipple(uQualityIn, QUALITY_ONE, saPrvIssueReq, saCurIssueReq, saPrvIssueAct, saCurIssueAct, uRateMax); - } - - // Adjust prv --> cur balance : take all inbound - // XXX Currency must be in amount. - rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false); - } - } - else if (bPrvAccount && !bNxtAccount) - { - // account --> ACCOUNT --> offer - Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: account --> ACCOUNT --> offer")); - - // 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. - { - // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvRedeemReq, saCurDeliverReq, saPrvRedeemAct, saCurDeliverAct, uRateMax); - } - - // issue -> issue - 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 - // XXX Currency must be in amount. - rippleCredit(uPrvAccountID, uCurAccountID, saPrvRedeemReq + saPrvIssueReq, false); - } - else if (!bPrvAccount && bNxtAccount) - { - if (uIndex == uLast) - { - // offer --> ACCOUNT --> $ - Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> $")); - - STAmount& saCurReceive = pspCur->saOutAct; - - // Amount to credit. - saCurReceive = saPrvDeliverAct; - - // No income balance adjustments necessary. The paying side inside the offer paid to this account. - } - else - { - // offer --> ACCOUNT --> account - Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> account")); - - // deliver -> redeem - if (saPrvDeliverReq) // Previous wants to deliver. - { - // Rate : 1.0 : quality out - calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct, uRateMax); - } - - // deliver -> issue - // Wants to redeem and current would and can issue. - if (saPrvDeliverReq != saPrvDeliverAct // Previous still wants to deliver. - && saCurRedeemReq == saCurRedeemAct // Current has more to redeem to next. - && saCurIssueReq) // Current wants issue. - { - // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurIssueReq, saPrvDeliverAct, saCurIssueAct, uRateMax); - } - - // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. - } - } - else - { - // offer --> ACCOUNT --> offer - // deliver/redeem -> deliver/issue. - Log(lsINFO) << boost::str(boost::format("calcNodeAccountFwd: offer --> ACCOUNT --> offer")); - - if (saPrvDeliverReq // Previous wants to deliver - && saCurIssueReq) // Current wants issue. - { - // Rate : 1.0 : transfer_rate - calcNodeRipple(QUALITY_ONE, rippleTransferRate(uCurAccountID), saPrvDeliverReq, saCurDeliverReq, saPrvDeliverAct, saCurDeliverAct, uRateMax); - } - - // No income balance adjustments necessary. The paying side inside the offer paid and the next link will receive. - } - - return terResult; -} - -// Return true, iff lhs has less priority than rhs. -bool PathState::lessPriority(const PathState::pointer& lhs, const PathState::pointer& rhs) -{ - if (lhs->uQuality != rhs->uQuality) - return lhs->uQuality > rhs->uQuality; // Bigger is worse. - - // Best quanity is second rank. - if (lhs->saOutAct != rhs->saOutAct) - return lhs->saOutAct < rhs->saOutAct; // Smaller is worse. - - // Path index is third rank. - return lhs->mIndex > rhs->mIndex; // Bigger is worse. -} - -// Make sure the path delivers to uAccountID: uCurrencyID from uIssuerID. -// -// Rules: -// - Currencies must be converted via an offer. -// - A node names it's output. -// - A ripple nodes output issuer must be the node's account or the next node's account. -// - Offers can only go directly to another offer if the currency and issuer are an exact match. -TER PathState::pushImply( - const uint160& uAccountID, // --> Delivering to this account. - const uint160& uCurrencyID, // --> Delivering this currency. - const uint160& uIssuerID) // --> Delivering this issuer. -{ - const PaymentNode& pnPrv = vpnNodes.back(); - TER terResult = tesSUCCESS; - - Log(lsINFO) << "pushImply> " - << NewcoinAddress::createHumanAccountID(uAccountID) - << " " << STAmount::createHumanCurrency(uCurrencyID) - << " " << NewcoinAddress::createHumanAccountID(uIssuerID); - - if (pnPrv.uCurrencyID != uCurrencyID) - { - // Currency is different, need to convert via an offer. - - terResult = pushNode( - STPathElement::typeCurrency // Offer. - | STPathElement::typeIssuer, - ACCOUNT_ONE, // Placeholder for offers. - uCurrencyID, // The offer's output is what is now wanted. - uIssuerID); - - } - - // For ripple, non-stamps, ensure the issuer is on at least one side of the transaction. - if (tesSUCCESS == terResult - && !!uCurrencyID // Not stamps. - && (pnPrv.uAccountID != uIssuerID // Previous is not issuing own IOUs. - && uAccountID != uIssuerID)) // Current is not receiving own IOUs. - { - // Need to ripple through uIssuerID's account. - - terResult = pushNode( - STPathElement::typeAccount, - uIssuerID, // Intermediate account is the needed issuer. - uCurrencyID, - uIssuerID); - } - - Log(lsINFO) << "pushImply< " << terResult; - - return terResult; -} - -// Append a node and insert before it any implied nodes. -// <-- terResult: tesSUCCESS, temBAD_PATH, terNO_LINE -TER PathState::pushNode( - const int iType, - const uint160& uAccountID, - const uint160& uCurrencyID, - const uint160& uIssuerID) -{ - Log(lsINFO) << "pushNode> " - << NewcoinAddress::createHumanAccountID(uAccountID) - << " " << STAmount::createHumanCurrency(uCurrencyID) - << "/" << NewcoinAddress::createHumanAccountID(uIssuerID); - PaymentNode pnCur; - const bool bFirst = vpnNodes.empty(); - const PaymentNode& pnPrv = bFirst ? PaymentNode() : vpnNodes.back(); - // true, iff node is a ripple account. false, iff node is an offer node. - const bool bAccount = isSetBit(iType, STPathElement::typeAccount); - // true, iff currency supplied. - // Currency is specified for the output of the current node. - const bool bCurrency = isSetBit(iType, STPathElement::typeCurrency); - // Issuer is specified for the output of the current node. - const bool bIssuer = isSetBit(iType, STPathElement::typeIssuer); - TER terResult = tesSUCCESS; - - pnCur.uFlags = iType; - - if (iType & ~STPathElement::typeValidBits) - { - Log(lsINFO) << "pushNode: bad bits."; - - terResult = temBAD_PATH; - } - else if (bAccount) - { - // Account link - - pnCur.uAccountID = uAccountID; - pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; - pnCur.uIssuerID = bIssuer ? uIssuerID : uAccountID; - pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID); - pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID); - - if (!bFirst) - { - // Add required intermediate nodes to deliver to current account. - terResult = pushImply( - pnCur.uAccountID, // Current account. - pnCur.uCurrencyID, // Wanted currency. - !!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as issuer. - } - - if (tesSUCCESS == terResult && !vpnNodes.empty()) - { - const PaymentNode& pnBck = vpnNodes.back(); - bool bBckAccount = isSetBit(pnBck.uFlags, STPathElement::typeAccount); - - if (bBckAccount) - { - SLE::pointer sleRippleState = mLedger->getSLE(Ledger::getRippleStateIndex(pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID)); - - if (!sleRippleState) - { - Log(lsINFO) << "pushNode: No credit line between " - << NewcoinAddress::createHumanAccountID(pnBck.uAccountID) - << " and " - << NewcoinAddress::createHumanAccountID(pnCur.uAccountID) - << " for " - << STAmount::createHumanCurrency(pnPrv.uCurrencyID) - << "." ; - - Log(lsINFO) << getJson(); - - terResult = terNO_LINE; - } - else - { - Log(lsINFO) << "pushNode: Credit line found between " - << NewcoinAddress::createHumanAccountID(pnBck.uAccountID) - << " and " - << NewcoinAddress::createHumanAccountID(pnCur.uAccountID) - << " for " - << STAmount::createHumanCurrency(pnPrv.uCurrencyID) - << "." ; - } - } - } - - if (tesSUCCESS == terResult) - vpnNodes.push_back(pnCur); - } - else - { - // Offer link - // Offers bridge a change in currency & issuer or just a change in issuer. - pnCur.uCurrencyID = bCurrency ? uCurrencyID : pnPrv.uCurrencyID; - pnCur.uIssuerID = bIssuer ? uIssuerID : pnCur.uAccountID; - pnCur.saRateMax = saZero; - - if (!!pnPrv.uAccountID) - { - // Previous is an account. - - // Insert intermediary issuer account if needed. - terResult = pushImply( - !!pnPrv.uCurrencyID - ? ACCOUNT_ONE // Rippling, but offer's don't have an account. - : ACCOUNT_XNS, - pnPrv.uCurrencyID, - pnPrv.uIssuerID); - } - - if (tesSUCCESS == terResult) - { - vpnNodes.push_back(pnCur); - } - } - Log(lsINFO) << "pushNode< " << terResult; - - return terResult; -} - -PathState::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 - ) - : mLedger(lpLedger), mIndex(iIndex), uQuality(0) -{ - const uint160 uInCurrencyID = saSendMax.getCurrency(); - const uint160 uOutCurrencyID = saSend.getCurrency(); - const uint160 uInIssuerID = !!uInCurrencyID ? saSendMax.getIssuer() : ACCOUNT_XNS; - const uint160 uOutIssuerID = !!uOutCurrencyID ? saSend.getIssuer() : ACCOUNT_XNS; - - lesEntries = lesSource.duplicate(); - - saInReq = saSendMax; - saOutReq = saSend; - - // Push sending node. - terStatus = pushNode( - STPathElement::typeAccount - | STPathElement::typeCurrency - | STPathElement::typeIssuer, - uSenderID, - uInCurrencyID, - uInIssuerID); - - BOOST_FOREACH(const STPathElement& speElement, spSourcePath) - { - if (tesSUCCESS == terStatus) - terStatus = pushNode(speElement.getNodeType(), speElement.getAccountID(), speElement.getCurrency(), speElement.getIssuerID()); - } - - if (tesSUCCESS == terStatus) - { - // Create receiver node. - - terStatus = pushImply(uReceiverID, uOutCurrencyID, uOutIssuerID); - if (tesSUCCESS == terStatus) - { - terStatus = pushNode( - STPathElement::typeAccount // Last node is always an account. - | STPathElement::typeCurrency - | STPathElement::typeIssuer, - uReceiverID, // Receive to output - uOutCurrencyID, // Desired currency - uOutIssuerID); - } - } - - if (tesSUCCESS == terStatus) - { - // Look for first mention of source in nodes and detect loops. - // Note: The output is not allowed to be a source. - - const unsigned int uNodes = vpnNodes.size(); - - for (unsigned int uIndex = 0; tesSUCCESS == terStatus && uIndex != uNodes; ++uIndex) - { - const PaymentNode& pnCur = vpnNodes[uIndex]; - - if (!!pnCur.uAccountID) - { - // Source is a ripple line - nothing(); - } - else if (!umForward.insert(std::make_pair(boost::make_tuple(pnCur.uAccountID, pnCur.uCurrencyID, pnCur.uIssuerID), uIndex)).second) - { - // Failed to insert. Have a loop. - Log(lsINFO) << boost::str(boost::format("PathState: loop detected: %s") - % getJson()); - - terStatus = temBAD_PATH_LOOP; - } - } - } - - Log(lsINFO) << boost::str(boost::format("PathState: in=%s/%s out=%s/%s %s") - % STAmount::createHumanCurrency(uInCurrencyID) - % NewcoinAddress::createHumanAccountID(uInIssuerID) - % STAmount::createHumanCurrency(uOutCurrencyID) - % NewcoinAddress::createHumanAccountID(uOutIssuerID) - % getJson()); -} - -Json::Value PathState::getJson() const -{ - Json::Value jvPathState(Json::objectValue); - Json::Value jvNodes(Json::arrayValue); - - BOOST_FOREACH(const PaymentNode& pnNode, vpnNodes) - { - Json::Value jvNode(Json::objectValue); - - Json::Value jvFlags(Json::arrayValue); - - if (pnNode.uFlags & STPathElement::typeAccount) - jvFlags.append("account"); - - jvNode["flags"] = jvFlags; - - if (pnNode.uFlags & STPathElement::typeAccount) - jvNode["account"] = NewcoinAddress::createHumanAccountID(pnNode.uAccountID); - - if (!!pnNode.uCurrencyID) - jvNode["currency"] = STAmount::createHumanCurrency(pnNode.uCurrencyID); - - if (!!pnNode.uIssuerID) - jvNode["issuer"] = NewcoinAddress::createHumanAccountID(pnNode.uIssuerID); - - // if (pnNode.saRevRedeem) - jvNode["rev_redeem"] = pnNode.saRevRedeem.getFullText(); - - // if (pnNode.saRevIssue) - jvNode["rev_issue"] = pnNode.saRevIssue.getFullText(); - - // if (pnNode.saRevDeliver) - jvNode["rev_deliver"] = pnNode.saRevDeliver.getFullText(); - - // if (pnNode.saFwdRedeem) - jvNode["fwd_redeem"] = pnNode.saFwdRedeem.getFullText(); - - // if (pnNode.saFwdIssue) - jvNode["fwd_issue"] = pnNode.saFwdIssue.getFullText(); - - // if (pnNode.saFwdDeliver) - jvNode["fwd_deliver"] = pnNode.saFwdDeliver.getFullText(); - - jvNodes.append(jvNode); - } - - jvPathState["status"] = terStatus; - jvPathState["index"] = mIndex; - jvPathState["nodes"] = jvNodes; - - if (saInReq) - jvPathState["in_req"] = saInReq.getJson(0); - - if (saInAct) - jvPathState["in_act"] = saInAct.getJson(0); - - if (saOutReq) - jvPathState["out_req"] = saOutReq.getJson(0); - - if (saOutAct) - jvPathState["out_act"] = saOutAct.getJson(0); - - if (uQuality) - jvPathState["uQuality"] = Json::Value::UInt(uQuality); - - return jvPathState; -} - -TER TransactionEngine::calcNodeFwd(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) -{ - const PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); - - Log(lsINFO) << boost::str(boost::format("calcNodeFwd> uIndex=%d") % uIndex); - - TER terResult = bCurAccount - ? calcNodeAccountFwd(uIndex, pspCur, bMultiQuality) - : calcNodeOfferFwd(uIndex, pspCur, bMultiQuality); - - if (tesSUCCESS == terResult && uIndex + 1 != pspCur->vpnNodes.size()) - { - terResult = calcNodeFwd(uIndex+1, pspCur, bMultiQuality); - } - - Log(lsINFO) << boost::str(boost::format("calcNodeFwd< uIndex=%d terResult=%d") % uIndex % terResult); - - return terResult; -} - -// Calculate a node and its previous nodes. -// From the destination work in reverse towards the source calculating how much must be asked for. -// Then work forward, figuring out how much can actually be delivered. -// <-- terResult: tesSUCCESS or tepPATH_DRY -// <-> pnNodes: -// --> [end]saWanted.mAmount -// --> [all]saWanted.mCurrency -// --> [all]saAccount -// <-> [0]saWanted.mAmount : --> limit, <-- actual -TER TransactionEngine::calcNodeRev(const unsigned int uIndex, const PathState::pointer& pspCur, const bool bMultiQuality) -{ - PaymentNode& pnCur = pspCur->vpnNodes[uIndex]; - const bool bCurAccount = isSetBit(pnCur.uFlags, STPathElement::typeAccount); - TER terResult; - - // Do current node reverse. - const uint160& uCurIssuerID = pnCur.uIssuerID; - STAmount& saTransferRate = pnCur.saTransferRate; - - saTransferRate = STAmount::saFromRate(rippleTransferRate(uCurIssuerID)); - - Log(lsINFO) << boost::str(boost::format("calcNodeRev> uIndex=%d uIssuerID=%s saTransferRate=%s") - % uIndex - % NewcoinAddress::createHumanAccountID(uCurIssuerID) - % saTransferRate.getFullText()); - - terResult = bCurAccount - ? calcNodeAccountRev(uIndex, pspCur, bMultiQuality) - : calcNodeOfferRev(uIndex, pspCur, bMultiQuality); - - // Do previous. - if (tesSUCCESS != terResult) - { - // Error, don't continue. - nothing(); - } - else if (uIndex) - { - // Continue in reverse. - - terResult = calcNodeRev(uIndex-1, pspCur, bMultiQuality); - } - - Log(lsINFO) << boost::str(boost::format("calcNodeRev< uIndex=%d terResult=%s/%d") % uIndex % transToken(terResult) % terResult); - - return terResult; -} - -// Calculate the next increment of a path. -// The increment is what can satisfy a portion or all of the requested output at the best quality. -// <-- pspCur->uQuality -void TransactionEngine::pathNext(const PathState::pointer& pspCur, const int iPaths, const LedgerEntrySet& lesCheckpoint) -{ - // The next state is what is available in preference order. - // This is calculated when referenced accounts changed. - const bool bMultiQuality = iPaths == 1; - const unsigned int uLast = pspCur->vpnNodes.size() - 1; - - Log(lsINFO) << "Path In: " << pspCur->getJson(); - - assert(pspCur->vpnNodes.size() >= 2); - - pspCur->vUnfundedBecame.clear(); - pspCur->umReverse.clear(); - - mNodes = lesCheckpoint; // Restore from checkpoint. - mNodes.bumpSeq(); // Begin ledger varance. - - pspCur->terStatus = calcNodeRev(uLast, pspCur, bMultiQuality); - - Log(lsINFO) << "Path after reverse: " << pspCur->getJson(); - - if (tesSUCCESS == pspCur->terStatus) - { - // Do forward. - mNodes = lesCheckpoint; // Restore from checkpoint. - mNodes.bumpSeq(); // Begin ledger varance. - - pspCur->terStatus = calcNodeFwd(0, pspCur, bMultiQuality); - - pspCur->uQuality = tesSUCCESS == pspCur->terStatus - ? STAmount::getRate(pspCur->saOutAct, pspCur->saInAct) // Calculate relative quality. - : 0; // Mark path as inactive. - - Log(lsINFO) << "Path after forward: " << pspCur->getJson(); - } -} // XXX Need to audit for things like setting accountID not having memory. -TER TransactionEngine::doPayment(const SerializedTransaction& txn) +TER TransactionEngine::doPayment(const SerializedTransaction& txn, const TransactionEngineParams params) { // Ripple if source or destination is non-native or if there are paths. const uint32 uTxFlags = txn.getFlags(); @@ -3184,12 +1023,37 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) entryModify(sleDst); } + TER terResult; // XXX Should bMax be sufficient to imply ripple? - const bool bRipple = bPaths || bMax || !saDstAmount.isNative(); + const bool bRipple = bPaths || bMax || !saDstAmount.isNative(); - if (!bRipple) + if (bRipple) + { + // Ripple payment + + STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); + STAmount saMaxAmountAct; + STAmount saDstAmountAct; + + terResult = isSetBit(params, tapOPEN_LEDGER) && spsPaths.getPathCount() > RIPPLE_PATHS_MAX + ? telBAD_PATH_COUNT + : RippleCalc::rippleCalc( + mNodes, + saMaxAmountAct, + saDstAmountAct, + saMaxAmount, + saDstAmount, + uDstAccountID, + mTxnAccountID, + spsPaths, + bPartialPayment, + bLimitQuality, + bNoRippleDirect); + } + else { // Direct XNS payment. + STAmount saSrcXNSBalance = mTxnAccount->getIValueFieldAmount(sfBalance); if (saSrcXNSBalance < saDstAmount) @@ -3197,202 +1061,17 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn) // Transaction might succeed, if applied in a different order. Log(lsINFO) << "doPayment: Delay transaction: Insufficent funds."; - return terUNFUNDED; - } - - mTxnAccount->setIFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); - sleDst->setIFieldAmount(sfBalance, sleDst->getIValueFieldAmount(sfBalance) + saDstAmount); - - return tesSUCCESS; - } - - // - // Ripple payment - // - - STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); - - if (bNoRippleDirect && spsPaths.isEmpty()) - { - Log(lsINFO) << "doPayment: Invalid transaction: No paths and direct ripple not allowed."; - - return temRIPPLE_EMPTY; - } - - // XXX Skip check if final processing. - if (spsPaths.getPathCount() > RIPPLE_PATHS_MAX) - { - return telBAD_PATH_COUNT; - } - - // Incrementally search paths. - std::vector vpsPaths; - - TER terResult = temUNCERTAIN; - - if (!bNoRippleDirect) - { - // Direct path. - // XXX Might also make a stamp bridge by default. - Log(lsINFO) << "doPayment: Build direct:"; - - PathState::pointer pspDirect = PathState::createPathState( - mLedger, - vpsPaths.size(), - mNodes, - STPath(), - uDstAccountID, - mTxnAccountID, - saDstAmount, - saMaxAmount); - - if (pspDirect) - { - // Return if malformed. - if (pspDirect->terStatus >= temMALFORMED && pspDirect->terStatus < tefFAILURE) - return pspDirect->terStatus; - - if (tesSUCCESS == pspDirect->terStatus) - { - // Had a success. - terResult = tesSUCCESS; - - vpsPaths.push_back(pspDirect); - } - } - } - - Log(lsINFO) << "doPayment: Paths in set: " << spsPaths.getPathCount(); - - BOOST_FOREACH(const STPath& spPath, spsPaths) - { - Log(lsINFO) << "doPayment: Build path:"; - - PathState::pointer pspExpanded = PathState::createPathState( - mLedger, - vpsPaths.size(), - mNodes, - spPath, - uDstAccountID, - mTxnAccountID, - saDstAmount, - saMaxAmount); - - if (pspExpanded) - { - // Return if malformed. - if (pspExpanded->terStatus >= temMALFORMED && pspExpanded->terStatus < tefFAILURE) - return pspExpanded->terStatus; - - if (tesSUCCESS == pspExpanded->terStatus) - { - // Had a success. - terResult = tesSUCCESS; - } - - vpsPaths.push_back(pspExpanded); - } - } - - if (vpsPaths.empty()) - { - return tefEXCEPTION; - } - else if (tesSUCCESS != terResult) - { - // No path successes. - - return vpsPaths[0]->terStatus; - } - else - { - terResult = temUNCERTAIN; - } - - STAmount saPaid; - STAmount saWanted; - const LedgerEntrySet lesBase = mNodes; // Checkpoint with just fees paid. - const uint64 uQualityLimit = bLimitQuality ? STAmount::getRate(saDstAmount, saMaxAmount) : 0; - - while (temUNCERTAIN == terResult) - { - PathState::pointer pspBest; - const LedgerEntrySet lesCheckpoint = mNodes; - - // Find the best path. - BOOST_FOREACH(PathState::pointer& pspCur, vpsPaths) - { - pathNext(pspCur, vpsPaths.size(), lesCheckpoint); // Compute increment. - - if ((!bLimitQuality || pspCur->uQuality <= uQualityLimit) // Quality is not limted or increment has allowed quality. - || !pspBest // Best is not yet set. - || (pspCur->uQuality && PathState::lessPriority(pspBest, pspCur))) // Current is better than set. - { - mNodes.swapWith(pspCur->lesEntries); // For the path, save ledger state. - pspBest = pspCur; - } - } - - if (pspBest) - { - // Apply best path. - - // Record best pass' offers that became unfunded for deletion on success. - mvUnfundedBecame.insert(mvUnfundedBecame.end(), pspBest->vUnfundedBecame.begin(), pspBest->vUnfundedBecame.end()); - - // Record best pass' LedgerEntrySet to build off of and potentially return. - mNodes.swapWith(pspBest->lesEntries); - - // Figure out if done. - if (temUNCERTAIN == terResult && saPaid == saWanted) - { - terResult = tesSUCCESS; - } - else - { - // Prepare for next pass. - - // Merge best pass' umReverse. - mumSource.insert(pspBest->umReverse.begin(), pspBest->umReverse.end()); - } - } - // Not done and ran out of paths. - else if (!bPartialPayment) - { - // Partial payment not allowed. - terResult = tepPATH_PARTIAL; - mNodes = lesBase; // Revert to just fees charged. - } - // Partial payment ok. - else if (!saPaid) - { - // No payment at all. - terResult = tepPATH_DRY; - mNodes = lesBase; // Revert to just fees charged. + terResult = terUNFUNDED; } else { + mTxnAccount->setIFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); + sleDst->setIFieldAmount(sfBalance, sleDst->getIValueFieldAmount(sfBalance) + saDstAmount); + terResult = tesSUCCESS; } } - if (tesSUCCESS == terResult) - { - // Delete became unfunded offers. - BOOST_FOREACH(const uint256& uOfferIndex, mvUnfundedBecame) - { - if (tesSUCCESS == terResult) - terResult = offerDelete(uOfferIndex); - } - } - - // Delete found unfunded offers. - BOOST_FOREACH(const uint256& uOfferIndex, musUnfundedFound) - { - if (tesSUCCESS == terResult) - terResult = offerDelete(uOfferIndex); - } - std::string strToken; std::string strHuman; @@ -3580,8 +1259,8 @@ TER TransactionEngine::takeOffers( Log(lsINFO) << "takeOffers: saOfferPays=" << saOfferPays.getFullText(); - STAmount saOfferFunds = accountFunds(uOfferOwnerID, saOfferPays); - STAmount saTakerFunds = accountFunds(uTakerAccountID, saTakerPays); + STAmount saOfferFunds = mNodes.accountFunds(uOfferOwnerID, saOfferPays); + STAmount saTakerFunds = mNodes.accountFunds(uTakerAccountID, saTakerPays); SLE::pointer sleOfferAccount; // Owner of offer. if (!saOfferFunds.isPositive()) @@ -3660,14 +1339,14 @@ TER TransactionEngine::takeOffers( // Offer owner pays taker. saSubTakerGot.setIssuer(uTakerGetsAccountID); // XXX Move this earlier? - accountSend(uOfferOwnerID, uTakerAccountID, saSubTakerGot); + mNodes.accountSend(uOfferOwnerID, uTakerAccountID, saSubTakerGot); saTakerGot += saSubTakerGot; // Taker pays offer owner. saSubTakerPaid.setIssuer(uTakerPaysAccountID); - accountSend(uTakerAccountID, uOfferOwnerID, saSubTakerPaid); + mNodes.accountSend(uTakerAccountID, uOfferOwnerID, saSubTakerPaid); saTakerPaid += saSubTakerPaid; } @@ -3680,7 +1359,7 @@ TER TransactionEngine::takeOffers( { BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedFound) { - terResult = offerDelete(uOfferIndex); + terResult = mNodes.offerDelete(uOfferIndex); if (tesSUCCESS != terResult) break; } @@ -3691,7 +1370,7 @@ TER TransactionEngine::takeOffers( // On success, delete offers that became unfunded. BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedBecame) { - terResult = offerDelete(uOfferIndex); + terResult = mNodes.offerDelete(uOfferIndex); if (tesSUCCESS != terResult) break; } @@ -3766,7 +1445,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); terResult = temBAD_ISSUER; } - else if (!accountFunds(mTxnAccountID, saTakerGets).isPositive()) + else if (!mNodes.accountFunds(mTxnAccountID, saTakerGets).isPositive()) { Log(lsWARNING) << "doOfferCreate: delay: Offers must be at least partially funded."; @@ -3827,7 +1506,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()); Log(lsWARNING) << "doOfferCreate: takeOffers: mTxnAccountID=" << NewcoinAddress::createHumanAccountID(mTxnAccountID); - Log(lsWARNING) << "doOfferCreate: takeOffers: funds=" << accountFunds(mTxnAccountID, saTakerGets).getFullText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: funds=" << mNodes.accountFunds(mTxnAccountID, saTakerGets).getFullText(); // Log(lsWARNING) << "doOfferCreate: takeOffers: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); // Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); @@ -3835,7 +1514,7 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); if (tesSUCCESS == terResult && saTakerPays // Still wanting something. && saTakerGets // Still offering something. - && accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded. + && mNodes.accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded. { // We need to place the remainder of the offer into its order book. @@ -3898,7 +1577,7 @@ TER TransactionEngine::doOfferCancel(const SerializedTransaction& txn) { Log(lsWARNING) << "doOfferCancel: uSequence=" << uSequence; - terResult = offerDelete(sleOffer, uOfferIndex, mTxnAccountID); + terResult = mNodes.offerDelete(sleOffer, uOfferIndex, mTxnAccountID); } else { @@ -3913,406 +1592,6 @@ TER TransactionEngine::doOfferCancel(const SerializedTransaction& txn) return terResult; } -#if 0 -// XXX Need to adjust for fees. -// Find offers to satisfy pnDst. -// - Does not adjust any balances as there is at least a forward pass to come. -// --> pnDst.saWanted: currency and amount wanted -// --> pnSrc.saIOURedeem.mCurrency: use this before saIOUIssue, limit to use. -// --> pnSrc.saIOUIssue.mCurrency: use this after saIOURedeem, limit to use. -// <-- pnDst.saReceive -// <-- pnDst.saIOUForgive -// <-- pnDst.saIOUAccept -// <-- terResult : tesSUCCESS = no error and if !bAllowPartial complelely satisfied wanted. -// <-> usOffersDeleteAlways: -// <-> usOffersDeleteOnSuccess: -TER calcOfferFill(PaymentNode& pnSrc, PaymentNode& pnDst, bool bAllowPartial) -{ - TER terResult; - - if (pnDst.saWanted.isNative()) - { - // Transfer stamps. - - STAmount saSrcFunds = pnSrc.saAccount->accountHolds(pnSrc.saAccount, uint160(0), uint160(0)); - - if (saSrcFunds && (bAllowPartial || saSrcFunds > pnDst.saWanted)) - { - pnSrc.saSend = min(saSrcFunds, pnDst.saWanted); - pnDst.saReceive = pnSrc.saSend; - } - else - { - terResult = terINSUF_PATH; - } - } - else - { - // Ripple funds. - - // Redeem to limit. - terResult = calcOfferFill( - accountHolds(pnSrc.saAccount, pnDst.saWanted.getCurrency(), pnDst.saWanted.getIssuer()), - pnSrc.saIOURedeem, - pnDst.saIOUForgive, - bAllowPartial); - - if (tesSUCCESS == terResult) - { - // Issue to wanted. - terResult = calcOfferFill( - pnDst.saWanted, // As much as wanted is available, limited by credit limit. - pnSrc.saIOUIssue, - pnDst.saIOUAccept, - bAllowPartial); - } - - if (tesSUCCESS == terResult && !bAllowPartial) - { - STAmount saTotal = pnDst.saIOUForgive + pnSrc.saIOUAccept; - - if (saTotal != saWanted) - terResult = terINSUF_PATH; - } - } - - return terResult; -} -#endif - -#if 0 -// Get the next offer limited by funding. -// - Stop when becomes unfunded. -void TransactionEngine::calcOfferBridgeNext( - const uint256& uBookRoot, // --> Which order book to look in. - const uint256& uBookEnd, // --> Limit of how far to look. - uint256& uBookDirIndex, // <-> Current directory. <-- 0 = no offer available. - uint64& uBookDirNode, // <-> Which node. 0 = first. - unsigned int& uBookDirEntry, // <-> Entry in node. 0 = first. - STAmount& saOfferIn, // <-- How much to pay in, fee inclusive, to get saOfferOut out. - STAmount& saOfferOut // <-- How much offer pays out. - ) -{ - saOfferIn = 0; // XXX currency & issuer - saOfferOut = 0; // XXX currency & issuer - - bool bDone = false; - - while (!bDone) - { - uint256 uOfferIndex; - - // Get uOfferIndex. - mNodes.dirNext(uBookRoot, uBookEnd, uBookDirIndex, uBookDirNode, uBookDirEntry, uOfferIndex); - - SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - - uint160 uOfferOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); - STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); - STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); - - if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) - { - // Offer is expired. - Log(lsINFO) << "calcOfferFirst: encountered expired offer"; - } - else - { - STAmount saOfferFunds = accountFunds(uOfferOwnerID, saOfferPays); - // Outbound fees are paid by offer owner. - // XXX Calculate outbound fee rate. - - if (saOfferPays.isNative()) - { - // No additional fees for stamps. - - nothing(); - } - else if (saOfferPays.getIssuer() == uOfferOwnerID) - { - // Offerer is issue own IOUs. - // No fees at this exact point, XXX receiving node may charge a fee. - // XXX Make sure has a credit line with receiver, limit by credit line. - - nothing(); - // XXX Broken - could be issuing or redeeming or both. - } - else - { - // Offer must be redeeming IOUs. - - // No additional - // XXX Broken - } - - if (!saOfferFunds.isPositive()) - { - // Offer is unfunded. - Log(lsINFO) << "calcOfferFirst: offer unfunded: delete"; - } - else if (saOfferFunds >= saOfferPays) - { - // Offer fully funded. - - // Account transfering funds in to offer always pays inbound fees. - - saOfferIn = saOfferGets; // XXX Add in fees? - - saOfferOut = saOfferPays; - - bDone = true; - } - else - { - // Offer partially funded. - - // saOfferIn/saOfferFunds = saOfferGets/saOfferPays - // XXX Round such that all saOffer funds are exhausted. - saOfferIn = (saOfferFunds*saOfferGets)/saOfferPays; // XXX Add in fees? - saOfferOut = saOfferFunds; - - bDone = true; - } - } - - if (!bDone) - { - // musUnfundedFound.insert(uOfferIndex); - } - } - while (bNext); -} -#endif - -#if 0 -// If either currency is not stamps, then also calculates vs stamp bridge. -// --> saWanted: Limit of how much is wanted out. -// <-- saPay: How much to pay into the offer. -// <-- saGot: How much to the offer pays out. Never more than saWanted. -// Given two value's enforce a minimum: -// - reverse: prv is maximum to pay in (including fee) - cur is what is wanted: generally, minimizing prv -// - forward: prv is actual amount to pay in (including fee) - cur is what is wanted: generally, minimizing cur -// Value in is may be rippled or credited from limbo. Value out is put in limbo. -// If next is an offer, the amount needed is in cur reedem. -// XXX What about account mentioned multiple times via offers? -void TransactionEngine::calcNodeOffer( - bool bForward, - bool bMultiQuality, // True, if this is the only active path: we can do multiple qualities in this pass. - const uint160& uPrvAccountID, // If 0, then funds from previous offer's limbo - const uint160& uPrvCurrencyID, - const uint160& uPrvIssuerID, - const uint160& uCurCurrencyID, - const uint160& uCurIssuerID, - - const STAmount& uPrvRedeemReq, // --> In limit. - STAmount& uPrvRedeemAct, // <-> In limit achived. - const STAmount& uCurRedeemReq, // --> Out limit. Driver when uCurIssuerID == uNxtIssuerID (offer would redeem to next) - STAmount& uCurRedeemAct, // <-> Out limit achived. - - const STAmount& uCurIssueReq, // --> In limit. - STAmount& uCurIssueAct, // <-> In limit achived. - const STAmount& uCurIssueReq, // --> Out limit. Driver when uCurIssueReq != uNxtIssuerID (offer would effectively issue or transfer to next) - STAmount& uCurIssueAct, // <-> Out limit achived. - - STAmount& saPay, - STAmount& saGot - ) const -{ - TER terResult = temUNKNOWN; - - // Direct: not bridging via XNS - bool bDirectNext = true; // True, if need to load. - uint256 uDirectQuality; - uint256 uDirectTip = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); - uint256 uDirectEnd = Ledger::getQualityNext(uDirectTip); - - // Bridging: bridging via XNS - bool bBridge = true; // True, if bridging active. False, missing an offer. - uint256 uBridgeQuality; - STAmount saBridgeIn; // Amount available. - STAmount saBridgeOut; - - bool bInNext = true; // True, if need to load. - STAmount saInIn; // Amount available. Consumed in loop. Limited by offer funding. - STAmount saInOut; - uint256 uInTip; // Current entry. - uint256 uInEnd; - unsigned int uInEntry; - - bool bOutNext = true; - STAmount saOutIn; - STAmount saOutOut; - uint256 uOutTip; - uint256 uOutEnd; - unsigned int uOutEntry; - - saPay.zero(); - saPay.setCurrency(uPrvCurrencyID); - saPay.setIssuer(uPrvIssuerID); - - saNeed = saWanted; - - if (!uCurCurrencyID && !uPrvCurrencyID) - { - // Bridging: Neither currency is XNS. - uInTip = Ledger::getBookBase(uPrvCurrencyID, uPrvIssuerID, CURRENCY_XNS, ACCOUNT_XNS); - uInEnd = Ledger::getQualityNext(uInTip); - uOutTip = Ledger::getBookBase(CURRENCY_XNS, ACCOUNT_XNS, uCurCurrencyID, uCurIssuerID); - uOutEnd = Ledger::getQualityNext(uInTip); - } - - // Find our head offer. - - bool bRedeeming = false; - bool bIssuing = false; - - // The price varies as we change between issuing and transfering, so unless bMultiQuality, we must stick with a mode once it - // is determined. - - if (bBridge && (bInNext || bOutNext)) - { - // Bridging and need to calculate next bridge rate. - // A bridge can consist of multiple offers. As offer's are consumed, the effective rate changes. - - if (bInNext) - { -// sleInDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uInIndex, uInEnd)); - // Get the next funded offer. - offerBridgeNext(uInIndex, uInEnd, uInEntry, saInIn, saInOut); // Get offer limited by funding. - bInNext = false; - } - - if (bOutNext) - { -// sleOutDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uOutIndex, uOutEnd)); - offerNext(uOutIndex, uOutEnd, uOutEntry, saOutIn, saOutOut); - bOutNext = false; - } - - if (!uInIndex || !uOutIndex) - { - bBridge = false; // No more offers to bridge. - } - else - { - // Have bridge in and out entries. - // Calculate bridge rate. Out offer pay ripple fee. In offer fee is added to in cost. - - saBridgeOut.zero(); - - if (saInOut < saOutIn) - { - // Limit by in. - - // XXX Need to include fees in saBridgeIn. - saBridgeIn = saInIn; // All of in - // Limit bridge out: saInOut/saBridgeOut = saOutIn/saOutOut - // Round such that we would take all of in offer, otherwise would have leftovers. - saBridgeOut = (saInOut * saOutOut) / saOutIn; - } - else if (saInOut > saOutIn) - { - // Limit by out, if at all. - - // XXX Need to include fees in saBridgeIn. - // Limit bridge in:saInIn/saInOuts = aBridgeIn/saOutIn - // Round such that would take all of out offer. - saBridgeIn = (saInIn * saOutIn) / saInOuts; - saBridgeOut = saOutOut; // All of out. - } - else - { - // Entries match, - - // XXX Need to include fees in saBridgeIn. - saBridgeIn = saInIn; // All of in - saBridgeOut = saOutOut; // All of out. - } - - uBridgeQuality = STAmount::getRate(saBridgeIn, saBridgeOut); // Inclusive of fees. - } - } - - if (bBridge) - { - bUseBridge = !uDirectTip || (uBridgeQuality < uDirectQuality) - } - else if (!!uDirectTip) - { - bUseBridge = false - } - else - { - // No more offers. Declare success, even if none returned. - saGot = saWanted-saNeed; - terResult = tesSUCCESS; - } - - if (tesSUCCESS != terResult) - { - STAmount& saAvailIn = bUseBridge ? saBridgeIn : saDirectIn; - STAmount& saAvailOut = bUseBridge ? saBridgeOut : saDirectOut; - - if (saAvailOut > saNeed) - { - // Consume part of offer. Done. - - saNeed = 0; - saPay += (saNeed*saAvailIn)/saAvailOut; // Round up, prefer to pay more. - } - else - { - // Consume entire offer. - - saNeed -= saAvailOut; - saPay += saAvailIn; - - if (bUseBridge) - { - // Consume bridge out. - if (saOutOut == saAvailOut) - { - // Consume all. - saOutOut = 0; - saOutIn = 0; - bOutNext = true; - } - else - { - // Consume portion of bridge out, must be consuming all of bridge in. - // saOutIn/saOutOut = saSpent/saAvailOut - // Round? - saOutIn -= (saOutIn*saAvailOut)/saOutOut; - saOutOut -= saAvailOut; - } - - // Consume bridge in. - if (saOutIn == saAvailIn) - { - // Consume all. - saInOut = 0; - saInIn = 0; - bInNext = true; - } - else - { - // Consume portion of bridge in, must be consuming all of bridge out. - // saInIn/saInOut = saAvailIn/saPay - // Round? - saInOut -= (saInOut*saAvailIn)/saInIn; - saInIn -= saAvailIn; - } - } - else - { - bDirectNext = true; - } - } - } -} -#endif - - TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) { Log(lsWARNING) << "doContractAdd> " << txn.getJson(0); diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index b57b76b89e..70d464b7ae 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -1,8 +1,6 @@ #ifndef __TRANSACTIONENGINE__ #define __TRANSACTIONENGINE__ -#include -#include #include #include @@ -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 aciSource; -typedef boost::unordered_map curIssuerNode; // Map of currency, issuer to node index. -typedef boost::unordered_map::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 pointer; - - TER terStatus; - std::vector vpnNodes; - - // When processing, don't want to complicate directory walking with deletion. - std::vector 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(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 mvUnfundedBecame; // Offers that became unfunded. - - // If the transaction fails to meet some constraint, still need to delete unfunded offers. - boost::unordered_set 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); From cc467bf1d32d46b313b81d7154181c7d347980b3 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 10 Sep 2012 12:51:56 -0700 Subject: [PATCH 237/426] Move TransactionEngine do* to TransactionAction.cpp --- src/TransactionAction.cpp | 1171 +++++++++++++++++++++++++++++++++++++ src/TransactionEngine.cpp | 1162 +----------------------------------- 2 files changed, 1174 insertions(+), 1159 deletions(-) create mode 100644 src/TransactionAction.cpp diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp new file mode 100644 index 0000000000..f60ae0af57 --- /dev/null +++ b/src/TransactionAction.cpp @@ -0,0 +1,1171 @@ +// +// XXX Make sure all fields are recognized in transactions. +// + +#include +#include +#include +#include + +#include "TransactionEngine.h" + +#include "../json/writer.h" + +#include "Config.h" +#include "Contract.h" +#include "Interpreter.h" +#include "Log.h" +#include "RippleCalc.h" +#include "TransactionFormats.h" +#include "utils.h" + +#define RIPPLE_PATHS_MAX 3 + +// Set the authorized public key for an account. May also set the generator map. +TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator) +{ + // + // Verify that submitter knows the private key for the generator. + // Otherwise, people could deny access to generators. + // + + std::vector vucCipher = txn.getITFieldVL(sfGenerator); + std::vector vucPubKey = txn.getITFieldVL(sfPubKey); + std::vector vucSignature = txn.getITFieldVL(sfSignature); + NewcoinAddress naAccountPublic = NewcoinAddress::createAccountPublic(vucPubKey); + + if (!naAccountPublic.accountPublicVerify(Serializer::getSHA512Half(vucCipher), vucSignature)) + { + Log(lsWARNING) << "createGenerator: bad signature unauthorized generator claim"; + + return tefBAD_GEN_AUTH; + } + + // Create generator. + uint160 hGeneratorID = naAccountPublic.getAccountID(); + + SLE::pointer sleGen = entryCache(ltGENERATOR_MAP, Ledger::getGeneratorIndex(hGeneratorID)); + if (!sleGen) + { + // Create the generator. + Log(lsTRACE) << "createGenerator: creating generator"; + + sleGen = entryCreate(ltGENERATOR_MAP, Ledger::getGeneratorIndex(hGeneratorID)); + + sleGen->setIFieldVL(sfGenerator, vucCipher); + } + else if (bMustSetGenerator) + { + // Doing a claim. Must set generator. + // Generator is already in use. Regular passphrases limited to one wallet. + Log(lsWARNING) << "createGenerator: generator already in use"; + + return tefGEN_IN_USE; + } + + // Set the public key needed to use the account. + uint160 uAuthKeyID = bMustSetGenerator + ? hGeneratorID // Claim + : txn.getITFieldAccount(sfAuthorizedKey); // PasswordSet + + mTxnAccount->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); + + return tesSUCCESS; +} + +TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) +{ + Log(lsINFO) << "doAccountSet>"; + + // + // EmailHash + // + + if (txn.getITFieldPresent(sfEmailHash)) + { + uint128 uHash = txn.getITFieldH128(sfEmailHash); + + if (!uHash) + { + Log(lsINFO) << "doAccountSet: unset email hash"; + + mTxnAccount->makeIFieldAbsent(sfEmailHash); + } + else + { + Log(lsINFO) << "doAccountSet: set email hash"; + + mTxnAccount->setIFieldH128(sfEmailHash, uHash); + } + } + + // + // WalletLocator + // + + if (txn.getITFieldPresent(sfWalletLocator)) + { + uint256 uHash = txn.getITFieldH256(sfWalletLocator); + + if (!uHash) + { + Log(lsINFO) << "doAccountSet: unset wallet locator"; + + mTxnAccount->makeIFieldAbsent(sfEmailHash); + } + else + { + Log(lsINFO) << "doAccountSet: set wallet locator"; + + mTxnAccount->setIFieldH256(sfWalletLocator, uHash); + } + } + + // + // MessageKey + // + + if (!txn.getITFieldPresent(sfMessageKey)) + { + nothing(); + } + else + { + Log(lsINFO) << "doAccountSet: set message key"; + + mTxnAccount->setIFieldVL(sfMessageKey, txn.getITFieldVL(sfMessageKey)); + } + + // + // Domain + // + + if (txn.getITFieldPresent(sfDomain)) + { + std::vector vucDomain = txn.getITFieldVL(sfDomain); + + if (vucDomain.empty()) + { + Log(lsINFO) << "doAccountSet: unset domain"; + + mTxnAccount->makeIFieldAbsent(sfDomain); + } + else + { + Log(lsINFO) << "doAccountSet: set domain"; + + mTxnAccount->setIFieldVL(sfDomain, vucDomain); + } + } + + // + // TransferRate + // + + if (txn.getITFieldPresent(sfTransferRate)) + { + uint32 uRate = txn.getITFieldU32(sfTransferRate); + + if (!uRate) + { + Log(lsINFO) << "doAccountSet: unset transfer rate"; + + mTxnAccount->makeIFieldAbsent(sfTransferRate); + } + else + { + Log(lsINFO) << "doAccountSet: set transfer rate"; + + mTxnAccount->setIFieldU32(sfTransferRate, uRate); + } + } + + // + // PublishHash && PublishSize + // + + bool bPublishHash = txn.getITFieldPresent(sfPublishHash); + bool bPublishSize = txn.getITFieldPresent(sfPublishSize); + + if (bPublishHash ^ bPublishSize) + { + Log(lsINFO) << "doAccountSet: bad publish"; + + return temBAD_PUBLISH; + } + else if (bPublishHash && bPublishSize) + { + uint256 uHash = txn.getITFieldH256(sfPublishHash); + uint32 uSize = txn.getITFieldU32(sfPublishSize); + + if (!uHash) + { + Log(lsINFO) << "doAccountSet: unset publish"; + + mTxnAccount->makeIFieldAbsent(sfPublishHash); + mTxnAccount->makeIFieldAbsent(sfPublishSize); + } + else + { + Log(lsINFO) << "doAccountSet: set publish"; + + mTxnAccount->setIFieldH256(sfPublishHash, uHash); + mTxnAccount->setIFieldU32(sfPublishSize, uSize); + } + } + + Log(lsINFO) << "doAccountSet<"; + + return tesSUCCESS; +} + +TER TransactionEngine::doClaim(const SerializedTransaction& txn) +{ + Log(lsINFO) << "doClaim>"; + + TER terResult = setAuthorized(txn, true); + + Log(lsINFO) << "doClaim<"; + + return terResult; +} + +TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) +{ + TER terResult = tesSUCCESS; + Log(lsINFO) << "doCreditSet>"; + + // Check if destination makes sense. + uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); + + if (!uDstAccountID) + { + Log(lsINFO) << "doCreditSet: Invalid transaction: Destination account not specifed."; + + return temDST_NEEDED; + } + else if (mTxnAccountID == uDstAccountID) + { + Log(lsINFO) << "doCreditSet: Invalid transaction: Can not extend credit to self."; + + return temDST_IS_SRC; + } + + SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); + if (!sleDst) + { + Log(lsINFO) << "doCreditSet: Delay transaction: Destination account does not exist."; + + return terNO_DST; + } + + const bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest. + const bool bLimitAmount = txn.getITFieldPresent(sfLimitAmount); + const STAmount saLimitAmount = bLimitAmount ? txn.getITFieldAmount(sfLimitAmount) : STAmount(); + const bool bQualityIn = txn.getITFieldPresent(sfQualityIn); + const uint32 uQualityIn = bQualityIn ? txn.getITFieldU32(sfQualityIn) : 0; + const bool bQualityOut = txn.getITFieldPresent(sfQualityOut); + const uint32 uQualityOut = bQualityIn ? txn.getITFieldU32(sfQualityOut) : 0; + const uint160 uCurrencyID = saLimitAmount.getCurrency(); + bool bDelIndex = false; + + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); + if (sleRippleState) + { + // A line exists in one or more directions. +#if 0 + if (!saLimitAmount) + { + // Zeroing line. + uint160 uLowID = sleRippleState->getIValueFieldAccount(sfLowID).getAccountID(); + uint160 uHighID = sleRippleState->getIValueFieldAccount(sfHighID).getAccountID(); + bool bLow = uLowID == uSrcAccountID; + bool bHigh = uLowID == uDstAccountID; + bool bBalanceZero = !sleRippleState->getIValueFieldAmount(sfBalance); + STAmount saDstLimit = sleRippleState->getIValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit); + bool bDstLimitZero = !saDstLimit; + + assert(bLow || bHigh); + + if (bBalanceZero && bDstLimitZero) + { + // Zero balance and eliminating last limit. + + bDelIndex = true; + terResult = dirDelete(false, uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex(), false); + } + } +#endif + + if (!bDelIndex) + { + if (bLimitAmount) + sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit , saLimitAmount); + + if (!bQualityIn) + { + nothing(); + } + else if (uQualityIn) + { + sleRippleState->setIFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn); + } + else + { + sleRippleState->makeIFieldAbsent(bFlipped ? sfLowQualityIn : sfHighQualityIn); + } + + if (!bQualityOut) + { + nothing(); + } + else if (uQualityOut) + { + sleRippleState->setIFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut); + } + else + { + sleRippleState->makeIFieldAbsent(bFlipped ? sfLowQualityOut : sfHighQualityOut); + } + + entryModify(sleRippleState); + } + + Log(lsINFO) << "doCreditSet: Modifying ripple line: bDelIndex=" << bDelIndex; + } + // Line does not exist. + else if (!saLimitAmount) + { + Log(lsINFO) << "doCreditSet: Redundant: Setting non-existant ripple line to 0."; + + return terNO_LINE_NO_ZERO; + } + else + { + // Create a new ripple line. + sleRippleState = entryCreate(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); + + Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString(); + + sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency. + sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAmount); + sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, ACCOUNT_ONE)); + sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, mTxnAccountID); + sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uDstAccountID); + if (uQualityIn) + sleRippleState->setIFieldU32(bFlipped ? sfHighQualityIn : sfLowQualityIn, uQualityIn); + if (uQualityOut) + sleRippleState->setIFieldU32(bFlipped ? sfHighQualityOut : sfLowQualityOut, uQualityOut); + + uint64 uSrcRef; // Ignored, dirs never delete. + + terResult = mNodes.dirAdd(uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex()); + + if (tesSUCCESS == terResult) + terResult = mNodes.dirAdd(uSrcRef, Ledger::getOwnerDirIndex(uDstAccountID), sleRippleState->getIndex()); + } + + Log(lsINFO) << "doCreditSet<"; + + return terResult; +} + +TER TransactionEngine::doNicknameSet(const SerializedTransaction& txn) +{ + std::cerr << "doNicknameSet>" << std::endl; + + const uint256 uNickname = txn.getITFieldH256(sfNickname); + const bool bMinOffer = txn.getITFieldPresent(sfMinimumOffer); + const STAmount saMinOffer = bMinOffer ? txn.getITFieldAmount(sfAmount) : STAmount(); + + SLE::pointer sleNickname = entryCache(ltNICKNAME, uNickname); + + if (sleNickname) + { + // Edit old entry. + sleNickname->setIFieldAccount(sfAccount, mTxnAccountID); + + if (bMinOffer && saMinOffer) + { + sleNickname->setIFieldAmount(sfMinimumOffer, saMinOffer); + } + else + { + sleNickname->makeIFieldAbsent(sfMinimumOffer); + } + + entryModify(sleNickname); + } + else + { + // Make a new entry. + // XXX Need to include authorization limiting for first year. + + sleNickname = entryCreate(ltNICKNAME, Ledger::getNicknameIndex(uNickname)); + + std::cerr << "doNicknameSet: Creating nickname node: " << sleNickname->getIndex().ToString() << std::endl; + + sleNickname->setIFieldAccount(sfAccount, mTxnAccountID); + + if (bMinOffer && saMinOffer) + sleNickname->setIFieldAmount(sfMinimumOffer, saMinOffer); + } + + std::cerr << "doNicknameSet<" << std::endl; + + return tesSUCCESS; +} + +TER TransactionEngine::doPasswordFund(const SerializedTransaction& txn) +{ + std::cerr << "doPasswordFund>" << std::endl; + + const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); + SLE::pointer sleDst = mTxnAccountID == uDstAccountID + ? mTxnAccount + : entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); + if (!sleDst) + { + // Destination account does not exist. + std::cerr << "doPasswordFund: Delay transaction: Destination account does not exist." << std::endl; + + return terSET_MISSING_DST; + } + + if (sleDst->getFlags() & lsfPasswordSpent) + { + sleDst->clearFlag(lsfPasswordSpent); + + std::cerr << "doPasswordFund: Clearing spent." << sleDst->getFlags() << std::endl; + + if (mTxnAccountID != uDstAccountID) { + std::cerr << "doPasswordFund: Destination modified." << std::endl; + + entryModify(sleDst); + } + } + + std::cerr << "doPasswordFund<" << std::endl; + + return tesSUCCESS; +} + +TER TransactionEngine::doPasswordSet(const SerializedTransaction& txn) +{ + std::cerr << "doPasswordSet>" << std::endl; + + if (mTxnAccount->getFlags() & lsfPasswordSpent) + { + std::cerr << "doPasswordSet: Delay transaction: Funds already spent." << std::endl; + + return terFUNDS_SPENT; + } + + mTxnAccount->setFlag(lsfPasswordSpent); + + TER terResult = setAuthorized(txn, false); + + std::cerr << "doPasswordSet<" << std::endl; + + return terResult; +} + + +// XXX Need to audit for things like setting accountID not having memory. +TER TransactionEngine::doPayment(const SerializedTransaction& txn, const TransactionEngineParams params) +{ + // Ripple if source or destination is non-native or if there are paths. + const uint32 uTxFlags = txn.getFlags(); + const bool bCreate = isSetBit(uTxFlags, tfCreateAccount); + const bool bPartialPayment = isSetBit(uTxFlags, tfPartialPayment); + const bool bLimitQuality = isSetBit(uTxFlags, tfLimitQuality); + const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect); + const bool bPaths = txn.getITFieldPresent(sfPaths); + const bool bMax = txn.getITFieldPresent(sfSendMax); + const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); + const STAmount saDstAmount = txn.getITFieldAmount(sfAmount); + const STAmount saMaxAmount = bMax ? txn.getITFieldAmount(sfSendMax) : saDstAmount; + const uint160 uSrcCurrency = saMaxAmount.getCurrency(); + const uint160 uDstCurrency = saDstAmount.getCurrency(); + + Log(lsINFO) << boost::str(boost::format("doPayment> saMaxAmount=%s saDstAmount=%s") + % saMaxAmount.getFullText() + % saDstAmount.getFullText()); + + if (!uDstAccountID) + { + Log(lsINFO) << "doPayment: Invalid transaction: Payment destination account not specifed."; + + return temDST_NEEDED; + } + else if (!saDstAmount.isPositive()) + { + Log(lsINFO) << "doPayment: Invalid transaction: bad amount: " << saDstAmount.getHumanCurrency() << " " << saDstAmount.getText(); + + return temBAD_AMOUNT; + } + else if (mTxnAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths) + { + Log(lsINFO) << boost::str(boost::format("doPayment: Invalid transaction: Redunant transaction: src=%s, dst=%s, src_cur=%s, dst_cur=%s") + % mTxnAccountID.ToString() + % uDstAccountID.ToString() + % uSrcCurrency.ToString() + % uDstCurrency.ToString()); + + return temREDUNDANT; + } + else if (bMax + && ((saMaxAmount == saDstAmount && saMaxAmount.getCurrency() == saDstAmount.getCurrency()) + || (saDstAmount.isNative() && saMaxAmount.isNative()))) + { + Log(lsINFO) << "doPayment: Invalid transaction: bad SendMax."; + + return temINVALID; + } + + SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); + if (!sleDst) + { + // Destination account does not exist. + if (bCreate && !saDstAmount.isNative()) + { + // This restriction could be relaxed. + Log(lsINFO) << "doPayment: Invalid transaction: Create account may only fund XNS."; + + return temCREATEXNS; + } + else if (!bCreate) + { + Log(lsINFO) << "doPayment: Delay transaction: Destination account does not exist."; + + return terNO_DST; + } + + // Create the account. + sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); + + sleDst->setIFieldAccount(sfAccount, uDstAccountID); + sleDst->setIFieldU32(sfSequence, 1); + } + else + { + entryModify(sleDst); + } + + TER terResult; + // XXX Should bMax be sufficient to imply ripple? + const bool bRipple = bPaths || bMax || !saDstAmount.isNative(); + + if (bRipple) + { + // Ripple payment + + STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); + STAmount saMaxAmountAct; + STAmount saDstAmountAct; + + terResult = isSetBit(params, tapOPEN_LEDGER) && spsPaths.getPathCount() > RIPPLE_PATHS_MAX + ? telBAD_PATH_COUNT + : RippleCalc::rippleCalc( + mNodes, + saMaxAmountAct, + saDstAmountAct, + saMaxAmount, + saDstAmount, + uDstAccountID, + mTxnAccountID, + spsPaths, + bPartialPayment, + bLimitQuality, + bNoRippleDirect); + } + else + { + // Direct XNS payment. + + STAmount saSrcXNSBalance = mTxnAccount->getIValueFieldAmount(sfBalance); + + if (saSrcXNSBalance < saDstAmount) + { + // Transaction might succeed, if applied in a different order. + Log(lsINFO) << "doPayment: Delay transaction: Insufficent funds."; + + terResult = terUNFUNDED; + } + else + { + mTxnAccount->setIFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); + sleDst->setIFieldAmount(sfBalance, sleDst->getIValueFieldAmount(sfBalance) + saDstAmount); + + terResult = tesSUCCESS; + } + } + + std::string strToken; + std::string strHuman; + + if (transResultInfo(terResult, strToken, strHuman)) + { + Log(lsINFO) << boost::str(boost::format("doPayment: %s: %s") % strToken % strHuman); + } + else + { + assert(false); + } + + return terResult; +} + +TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn) +{ + std::cerr << "WalletAdd>" << std::endl; + + const std::vector vucPubKey = txn.getITFieldVL(sfPubKey); + const std::vector vucSignature = txn.getITFieldVL(sfSignature); + const uint160 uAuthKeyID = txn.getITFieldAccount(sfAuthorizedKey); + const NewcoinAddress naMasterPubKey = NewcoinAddress::createAccountPublic(vucPubKey); + const uint160 uDstAccountID = naMasterPubKey.getAccountID(); + + if (!naMasterPubKey.accountPublicVerify(Serializer::getSHA512Half(uAuthKeyID.begin(), uAuthKeyID.size()), vucSignature)) + { + std::cerr << "WalletAdd: unauthorized: bad signature " << std::endl; + + return tefBAD_ADD_AUTH; + } + + SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); + + if (sleDst) + { + std::cerr << "WalletAdd: account already created" << std::endl; + + return tefCREATED; + } + + STAmount saAmount = txn.getITFieldAmount(sfAmount); + STAmount saSrcBalance = mTxnAccount->getIValueFieldAmount(sfBalance); + + if (saSrcBalance < saAmount) + { + std::cerr + << boost::str(boost::format("WalletAdd: Delay transaction: insufficent balance: balance=%s amount=%s") + % saSrcBalance.getText() + % saAmount.getText()) + << std::endl; + + return terUNFUNDED; + } + + // Deduct initial balance from source account. + mTxnAccount->setIFieldAmount(sfBalance, saSrcBalance-saAmount); + + // Create the account. + sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); + + sleDst->setIFieldAccount(sfAccount, uDstAccountID); + sleDst->setIFieldU32(sfSequence, 1); + sleDst->setIFieldAmount(sfBalance, saAmount); + sleDst->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); + + std::cerr << "WalletAdd<" << std::endl; + + return tesSUCCESS; +} + +TER TransactionEngine::doInvoice(const SerializedTransaction& txn) +{ + return temUNKNOWN; +} + +// Take as much as possible. Adjusts account balances. Charges fees on top to taker. +// --> uBookBase: The order book to take against. +// --> saTakerPays: What the taker offers (w/ issuer) +// --> saTakerGets: What the taker wanted (w/ issuer) +// <-- saTakerPaid: What taker paid not including fees. To reduce an offer. +// <-- saTakerGot: What taker got not including fees. To reduce an offer. +// <-- terResult: tesSUCCESS or terNO_ACCOUNT +// XXX: Fees should be paid by the source of the currency. +TER TransactionEngine::takeOffers( + bool bPassive, + const uint256& uBookBase, + const uint160& uTakerAccountID, + const SLE::pointer& sleTakerAccount, + const STAmount& saTakerPays, + const STAmount& saTakerGets, + STAmount& saTakerPaid, + STAmount& saTakerGot) +{ + assert(saTakerPays && saTakerGets); + + Log(lsINFO) << "takeOffers: against book: " << uBookBase.ToString(); + + uint256 uTipIndex = uBookBase; + const uint256 uBookEnd = Ledger::getQualityNext(uBookBase); + const uint64 uTakeQuality = STAmount::getRate(saTakerGets, saTakerPays); + const uint160 uTakerPaysAccountID = saTakerPays.getIssuer(); + const uint160 uTakerGetsAccountID = saTakerGets.getIssuer(); + TER terResult = temUNCERTAIN; + + boost::unordered_set usOfferUnfundedFound; // Offers found unfunded. + boost::unordered_set usOfferUnfundedBecame; // Offers that became unfunded. + boost::unordered_set usAccountTouched; // Accounts touched. + + saTakerPaid = 0; + saTakerGot = 0; + + while (temUNCERTAIN == terResult) + { + SLE::pointer sleOfferDir; + uint64 uTipQuality; + + // Figure out next offer to take, if needed. + if (saTakerGets != saTakerGot && saTakerPays != saTakerPaid) + { + // Taker has needs. + + sleOfferDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uTipIndex, uBookEnd)); + if (sleOfferDir) + { + Log(lsINFO) << "takeOffers: possible counter offer found"; + + uTipIndex = sleOfferDir->getIndex(); + uTipQuality = Ledger::getQuality(uTipIndex); + } + else + { + Log(lsINFO) << "takeOffers: counter offer book is empty: " + << uTipIndex.ToString() + << " ... " + << uBookEnd.ToString(); + } + } + + if (!sleOfferDir // No offer directory to take. + || uTakeQuality < uTipQuality // No offer's of sufficient quality available. + || (bPassive && uTakeQuality == uTipQuality)) + { + // Done. + Log(lsINFO) << "takeOffers: done"; + + terResult = tesSUCCESS; + } + else + { + // Have an offer directory to consider. + Log(lsINFO) << "takeOffers: considering dir : " << sleOfferDir->getJson(0); + + SLE::pointer sleBookNode; + unsigned int uBookEntry; + uint256 uOfferIndex; + + mNodes.dirFirst(uTipIndex, sleBookNode, uBookEntry, uOfferIndex); + + SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); + + Log(lsINFO) << "takeOffers: considering offer : " << sleOffer->getJson(0); + + const uint160 uOfferOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); + STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); + + if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + { + // Offer is expired. Expired offers are considered unfunded. Delete it. + Log(lsINFO) << "takeOffers: encountered expired offer"; + + usOfferUnfundedFound.insert(uOfferIndex); + } + else if (uOfferOwnerID == uTakerAccountID) + { + // Would take own offer. Consider old offer expired. Delete it. + Log(lsINFO) << "takeOffers: encountered taker's own old offer"; + + usOfferUnfundedFound.insert(uOfferIndex); + } + else + { + // Get offer funds available. + + Log(lsINFO) << "takeOffers: saOfferPays=" << saOfferPays.getFullText(); + + STAmount saOfferFunds = mNodes.accountFunds(uOfferOwnerID, saOfferPays); + STAmount saTakerFunds = mNodes.accountFunds(uTakerAccountID, saTakerPays); + SLE::pointer sleOfferAccount; // Owner of offer. + + if (!saOfferFunds.isPositive()) + { + // Offer is unfunded, possibly due to previous balance action. + Log(lsINFO) << "takeOffers: offer unfunded: delete"; + + boost::unordered_set::iterator account = usAccountTouched.find(uOfferOwnerID); + if (account != usAccountTouched.end()) + { + // Previously touched account. + usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success. + } + else + { + // Never touched source account. + usOfferUnfundedFound.insert(uOfferIndex); // Delete found unfunded offer when possible. + } + } + else + { + STAmount saPay = saTakerPays - saTakerPaid; + if (saTakerFunds < saPay) + saPay = saTakerFunds; + STAmount saSubTakerPaid; + STAmount saSubTakerGot; + + Log(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText(); + Log(lsINFO) << "takeOffers: applyOffer: saTakerPaid: " << saTakerPaid.getFullText(); + Log(lsINFO) << "takeOffers: applyOffer: saTakerFunds: " << saTakerFunds.getFullText(); + Log(lsINFO) << "takeOffers: applyOffer: saOfferFunds: " << saOfferFunds.getFullText(); + Log(lsINFO) << "takeOffers: applyOffer: saPay: " << saPay.getFullText(); + Log(lsINFO) << "takeOffers: applyOffer: saOfferPays: " << saOfferPays.getFullText(); + Log(lsINFO) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText(); + Log(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText(); + Log(lsINFO) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText(); + + bool bOfferDelete = STAmount::applyOffer( + saOfferFunds, + saPay, // Driver XXX need to account for fees. + saOfferPays, + saOfferGets, + saTakerPays, + saTakerGets, + saSubTakerPaid, + saSubTakerGot); + + Log(lsINFO) << "takeOffers: applyOffer: saSubTakerPaid: " << saSubTakerPaid.getFullText(); + Log(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText(); + + // Adjust offer + + // Offer owner will pay less. Subtract what taker just got. + sleOffer->setIFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot); + + // Offer owner will get less. Subtract what owner just paid. + sleOffer->setIFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid); + + entryModify(sleOffer); + + if (bOfferDelete) + { + // Offer now fully claimed or now unfunded. + Log(lsINFO) << "takeOffers: offer claimed: delete"; + + usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success. + + // Offer owner's account is no longer pristine. + usAccountTouched.insert(uOfferOwnerID); + } + else + { + Log(lsINFO) << "takeOffers: offer partial claim."; + } + + // Offer owner pays taker. + saSubTakerGot.setIssuer(uTakerGetsAccountID); // XXX Move this earlier? + + mNodes.accountSend(uOfferOwnerID, uTakerAccountID, saSubTakerGot); + + saTakerGot += saSubTakerGot; + + // Taker pays offer owner. + saSubTakerPaid.setIssuer(uTakerPaysAccountID); + + mNodes.accountSend(uTakerAccountID, uOfferOwnerID, saSubTakerPaid); + + saTakerPaid += saSubTakerPaid; + } + } + } + } + + // On storing meta data, delete offers that were found unfunded to prevent encountering them in future. + if (tesSUCCESS == terResult) + { + BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedFound) + { + terResult = mNodes.offerDelete(uOfferIndex); + if (tesSUCCESS != terResult) + break; + } + } + + if (tesSUCCESS == terResult) + { + // On success, delete offers that became unfunded. + BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedBecame) + { + terResult = mNodes.offerDelete(uOfferIndex); + if (tesSUCCESS != terResult) + break; + } + } + + return terResult; +} + +TER TransactionEngine::doOfferCreate(const SerializedTransaction& txn) +{ +Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); + const uint32 txFlags = txn.getFlags(); + const bool bPassive = isSetBit(txFlags, tfPassive); + STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); + STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); +Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText(); +Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); + const uint160 uPaysIssuerID = saTakerPays.getIssuer(); + const uint160 uGetsIssuerID = saTakerGets.getIssuer(); + const uint32 uExpiration = txn.getITFieldU32(sfExpiration); + const bool bHaveExpiration = txn.getITFieldPresent(sfExpiration); + const uint32 uSequence = txn.getSequence(); + + const uint256 uLedgerIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); + SLE::pointer sleOffer = entryCreate(ltOFFER, uLedgerIndex); + + Log(lsINFO) << "doOfferCreate: Creating offer node: " << uLedgerIndex.ToString() << " uSequence=" << uSequence; + + const uint160 uPaysCurrency = saTakerPays.getCurrency(); + const uint160 uGetsCurrency = saTakerGets.getCurrency(); + const uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays); + + TER terResult = tesSUCCESS; + uint256 uDirectory; // Delete hints. + uint64 uOwnerNode; + uint64 uBookNode; + + if (bHaveExpiration && !uExpiration) + { + Log(lsWARNING) << "doOfferCreate: Malformed offer: bad expiration"; + + terResult = temBAD_EXPIRATION; + } + else if (bHaveExpiration && mLedger->getParentCloseTimeNC() >= uExpiration) + { + Log(lsWARNING) << "doOfferCreate: Expired transaction: offer expired"; + + // XXX CHARGE FEE ONLY. + terResult = tesSUCCESS; + } + else if (saTakerPays.isNative() && saTakerGets.isNative()) + { + Log(lsWARNING) << "doOfferCreate: Malformed offer: XNS for XNS"; + + terResult = temBAD_OFFER; + } + else if (!saTakerPays || !saTakerGets) + { + Log(lsWARNING) << "doOfferCreate: Malformed offer: bad amount"; + + terResult = temBAD_OFFER; + } + else if (uPaysCurrency == uGetsCurrency && uPaysIssuerID == uGetsIssuerID) + { + Log(lsWARNING) << "doOfferCreate: Malformed offer: redundant offer"; + + terResult = temREDUNDANT; + } + else if (saTakerPays.isNative() != !uPaysIssuerID || saTakerGets.isNative() != !uGetsIssuerID) + { + Log(lsWARNING) << "doOfferCreate: Malformed offer: bad issuer"; + + terResult = temBAD_ISSUER; + } + else if (!mNodes.accountFunds(mTxnAccountID, saTakerGets).isPositive()) + { + Log(lsWARNING) << "doOfferCreate: delay: Offers must be at least partially funded."; + + terResult = terUNFUNDED; + } + + if (tesSUCCESS == terResult && !saTakerPays.isNative()) + { + SLE::pointer sleTakerPays = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uPaysIssuerID)); + + if (!sleTakerPays) + { + Log(lsWARNING) << "doOfferCreate: delay: can't receive IOUs from non-existant issuer: " << NewcoinAddress::createHumanAccountID(uPaysIssuerID); + + terResult = terNO_ACCOUNT; + } + } + + if (tesSUCCESS == terResult) + { + STAmount saOfferPaid; + STAmount saOfferGot; + const uint256 uTakeBookBase = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); + + Log(lsINFO) << boost::str(boost::format("doOfferCreate: take against book: %s : %s/%s -> %s/%s") + % uTakeBookBase.ToString() + % saTakerGets.getHumanCurrency() + % NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()) + % saTakerPays.getHumanCurrency() + % NewcoinAddress::createHumanAccountID(saTakerPays.getIssuer())); + + // Take using the parameters of the offer. + terResult = takeOffers( + bPassive, + uTakeBookBase, + mTxnAccountID, + mTxnAccount, + saTakerGets, + saTakerPays, + saOfferPaid, // How much was spent. + saOfferGot // How much was got. + ); + + Log(lsWARNING) << "doOfferCreate: takeOffers=" << terResult; + Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferPaid=" << saOfferPaid.getFullText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferGot=" << saOfferGot.getFullText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText(); + + if (tesSUCCESS == terResult) + { + saTakerPays -= saOfferGot; // Reduce payin from takers by what offer just got. + saTakerGets -= saOfferPaid; // Reduce payout to takers by what srcAccount just paid. + } + } + + Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()); + Log(lsWARNING) << "doOfferCreate: takeOffers: mTxnAccountID=" << NewcoinAddress::createHumanAccountID(mTxnAccountID); + Log(lsWARNING) << "doOfferCreate: takeOffers: funds=" << mNodes.accountFunds(mTxnAccountID, saTakerGets).getFullText(); + + // Log(lsWARNING) << "doOfferCreate: takeOffers: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); + // Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); + + if (tesSUCCESS == terResult + && saTakerPays // Still wanting something. + && saTakerGets // Still offering something. + && mNodes.accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded. + { + // We need to place the remainder of the offer into its order book. + + // Add offer to owner's directory. + terResult = mNodes.dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex); + + if (tesSUCCESS == terResult) + { + uint256 uBookBase = Ledger::getBookBase(uPaysCurrency, uPaysIssuerID, uGetsCurrency, uGetsIssuerID); + + Log(lsINFO) << boost::str(boost::format("doOfferCreate: adding to book: %s : %s/%s -> %s/%s") + % uBookBase.ToString() + % saTakerPays.getHumanCurrency() + % NewcoinAddress::createHumanAccountID(saTakerPays.getIssuer()) + % saTakerGets.getHumanCurrency() + % NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer())); + + uDirectory = Ledger::getQualityIndex(uBookBase, uRate); // Use original rate. + + // Add offer to order book. + terResult = mNodes.dirAdd(uBookNode, uDirectory, uLedgerIndex); + } + + if (tesSUCCESS == terResult) + { + // Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); + // Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); + // Log(lsWARNING) << "doOfferCreate: saTakerPays.isNative()=" << saTakerPays.isNative(); + // Log(lsWARNING) << "doOfferCreate: saTakerGets.isNative()=" << saTakerGets.isNative(); + // Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency(); + // Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency(); + + sleOffer->setIFieldAccount(sfAccount, mTxnAccountID); + sleOffer->setIFieldU32(sfSequence, uSequence); + sleOffer->setIFieldH256(sfBookDirectory, uDirectory); + sleOffer->setIFieldAmount(sfTakerPays, saTakerPays); + sleOffer->setIFieldAmount(sfTakerGets, saTakerGets); + sleOffer->setIFieldU64(sfOwnerNode, uOwnerNode); + sleOffer->setIFieldU64(sfBookNode, uBookNode); + + if (uExpiration) + sleOffer->setIFieldU32(sfExpiration, uExpiration); + + if (bPassive) + sleOffer->setFlag(lsfPassive); + } + } + + return terResult; +} + +TER TransactionEngine::doOfferCancel(const SerializedTransaction& txn) +{ + TER terResult; + const uint32 uSequence = txn.getITFieldU32(sfOfferSequence); + const uint256 uOfferIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); + SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); + + if (sleOffer) + { + Log(lsWARNING) << "doOfferCancel: uSequence=" << uSequence; + + terResult = mNodes.offerDelete(sleOffer, uOfferIndex, mTxnAccountID); + } + else + { + Log(lsWARNING) << "doOfferCancel: offer not found: " + << NewcoinAddress::createHumanAccountID(mTxnAccountID) + << " : " << uSequence + << " : " << uOfferIndex.ToString(); + + terResult = terOFFER_NOT_FOUND; + } + + return terResult; +} + +TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) +{ + Log(lsWARNING) << "doContractAdd> " << txn.getJson(0); + + const uint32 expiration = txn.getITFieldU32(sfExpiration); +// const uint32 bondAmount = txn.getITFieldU32(sfBondAmount); +// const uint32 stampEscrow = txn.getITFieldU32(sfStampEscrow); + STAmount rippleEscrow = txn.getITFieldAmount(sfRippleEscrow); + std::vector createCode = txn.getITFieldVL(sfCreateCode); + std::vector fundCode = txn.getITFieldVL(sfFundCode); + std::vector removeCode = txn.getITFieldVL(sfRemoveCode); + std::vector expireCode = txn.getITFieldVL(sfExpireCode); + + // make sure + // expiration hasn't passed + // bond amount is enough + // they have the stamps for the bond + + // place contract in ledger + // run create code + + + if (mLedger->getParentCloseTimeNC() >= expiration) + { + Log(lsWARNING) << "doContractAdd: Expired transaction: offer expired"; + return(tefALREADY); + } + //TODO: check bond + //if( txn.getSourceAccount() ) + + Contract contract; + Script::Interpreter interpreter; + TER terResult=interpreter.interpret(&contract,txn,createCode); + if(tesSUCCESS != terResult) + { + + } + + return(terResult); +} + +TER TransactionEngine::doContractRemove(const SerializedTransaction& txn) +{ + // TODO: + return(tesSUCCESS); +} + +// vim:ts=4 diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 526716ec81..2e5e22bd88 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -1,77 +1,17 @@ // -// XXX Should make sure all fields and are recognized on a transactions. +// XXX Make sure all fields are recognized in transactions. // +#include + #include "TransactionEngine.h" -#include -#include -#include -#include - #include "../json/writer.h" #include "Config.h" #include "Log.h" #include "TransactionFormats.h" #include "utils.h" -#include "Interpreter.h" -#include "Contract.h" -#include "RippleCalc.h" - -#define RIPPLE_PATHS_MAX 3 - -// Set the authorized public key for an account. May also set the generator map. -TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMustSetGenerator) -{ - // - // Verify that submitter knows the private key for the generator. - // Otherwise, people could deny access to generators. - // - - std::vector vucCipher = txn.getITFieldVL(sfGenerator); - std::vector vucPubKey = txn.getITFieldVL(sfPubKey); - std::vector vucSignature = txn.getITFieldVL(sfSignature); - NewcoinAddress naAccountPublic = NewcoinAddress::createAccountPublic(vucPubKey); - - if (!naAccountPublic.accountPublicVerify(Serializer::getSHA512Half(vucCipher), vucSignature)) - { - Log(lsWARNING) << "createGenerator: bad signature unauthorized generator claim"; - - return tefBAD_GEN_AUTH; - } - - // Create generator. - uint160 hGeneratorID = naAccountPublic.getAccountID(); - - SLE::pointer sleGen = entryCache(ltGENERATOR_MAP, Ledger::getGeneratorIndex(hGeneratorID)); - if (!sleGen) - { - // Create the generator. - Log(lsTRACE) << "createGenerator: creating generator"; - - sleGen = entryCreate(ltGENERATOR_MAP, Ledger::getGeneratorIndex(hGeneratorID)); - - sleGen->setIFieldVL(sfGenerator, vucCipher); - } - else if (bMustSetGenerator) - { - // Doing a claim. Must set generator. - // Generator is already in use. Regular passphrases limited to one wallet. - Log(lsWARNING) << "createGenerator: generator already in use"; - - return tefGEN_IN_USE; - } - - // Set the public key needed to use the account. - uint160 uAuthKeyID = bMustSetGenerator - ? hGeneratorID // Claim - : txn.getITFieldAccount(sfAuthorizedKey); // PasswordSet - - mTxnAccount->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); - - return tesSUCCESS; -} void TransactionEngine::txnWrite() { @@ -543,1100 +483,4 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa return terResult; } - -TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) -{ - Log(lsINFO) << "doAccountSet>"; - - // - // EmailHash - // - - if (txn.getITFieldPresent(sfEmailHash)) - { - uint128 uHash = txn.getITFieldH128(sfEmailHash); - - if (!uHash) - { - Log(lsINFO) << "doAccountSet: unset email hash"; - - mTxnAccount->makeIFieldAbsent(sfEmailHash); - } - else - { - Log(lsINFO) << "doAccountSet: set email hash"; - - mTxnAccount->setIFieldH128(sfEmailHash, uHash); - } - } - - // - // WalletLocator - // - - if (txn.getITFieldPresent(sfWalletLocator)) - { - uint256 uHash = txn.getITFieldH256(sfWalletLocator); - - if (!uHash) - { - Log(lsINFO) << "doAccountSet: unset wallet locator"; - - mTxnAccount->makeIFieldAbsent(sfEmailHash); - } - else - { - Log(lsINFO) << "doAccountSet: set wallet locator"; - - mTxnAccount->setIFieldH256(sfWalletLocator, uHash); - } - } - - // - // MessageKey - // - - if (!txn.getITFieldPresent(sfMessageKey)) - { - nothing(); - } - else - { - Log(lsINFO) << "doAccountSet: set message key"; - - mTxnAccount->setIFieldVL(sfMessageKey, txn.getITFieldVL(sfMessageKey)); - } - - // - // Domain - // - - if (txn.getITFieldPresent(sfDomain)) - { - std::vector vucDomain = txn.getITFieldVL(sfDomain); - - if (vucDomain.empty()) - { - Log(lsINFO) << "doAccountSet: unset domain"; - - mTxnAccount->makeIFieldAbsent(sfDomain); - } - else - { - Log(lsINFO) << "doAccountSet: set domain"; - - mTxnAccount->setIFieldVL(sfDomain, vucDomain); - } - } - - // - // TransferRate - // - - if (txn.getITFieldPresent(sfTransferRate)) - { - uint32 uRate = txn.getITFieldU32(sfTransferRate); - - if (!uRate) - { - Log(lsINFO) << "doAccountSet: unset transfer rate"; - - mTxnAccount->makeIFieldAbsent(sfTransferRate); - } - else - { - Log(lsINFO) << "doAccountSet: set transfer rate"; - - mTxnAccount->setIFieldU32(sfTransferRate, uRate); - } - } - - // - // PublishHash && PublishSize - // - - bool bPublishHash = txn.getITFieldPresent(sfPublishHash); - bool bPublishSize = txn.getITFieldPresent(sfPublishSize); - - if (bPublishHash ^ bPublishSize) - { - Log(lsINFO) << "doAccountSet: bad publish"; - - return temBAD_PUBLISH; - } - else if (bPublishHash && bPublishSize) - { - uint256 uHash = txn.getITFieldH256(sfPublishHash); - uint32 uSize = txn.getITFieldU32(sfPublishSize); - - if (!uHash) - { - Log(lsINFO) << "doAccountSet: unset publish"; - - mTxnAccount->makeIFieldAbsent(sfPublishHash); - mTxnAccount->makeIFieldAbsent(sfPublishSize); - } - else - { - Log(lsINFO) << "doAccountSet: set publish"; - - mTxnAccount->setIFieldH256(sfPublishHash, uHash); - mTxnAccount->setIFieldU32(sfPublishSize, uSize); - } - } - - Log(lsINFO) << "doAccountSet<"; - - return tesSUCCESS; -} - -TER TransactionEngine::doClaim(const SerializedTransaction& txn) -{ - Log(lsINFO) << "doClaim>"; - - TER terResult = setAuthorized(txn, true); - - Log(lsINFO) << "doClaim<"; - - return terResult; -} - -TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) -{ - TER terResult = tesSUCCESS; - Log(lsINFO) << "doCreditSet>"; - - // Check if destination makes sense. - uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); - - if (!uDstAccountID) - { - Log(lsINFO) << "doCreditSet: Invalid transaction: Destination account not specifed."; - - return temDST_NEEDED; - } - else if (mTxnAccountID == uDstAccountID) - { - Log(lsINFO) << "doCreditSet: Invalid transaction: Can not extend credit to self."; - - return temDST_IS_SRC; - } - - SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - if (!sleDst) - { - Log(lsINFO) << "doCreditSet: Delay transaction: Destination account does not exist."; - - return terNO_DST; - } - - const bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest. - const bool bLimitAmount = txn.getITFieldPresent(sfLimitAmount); - const STAmount saLimitAmount = bLimitAmount ? txn.getITFieldAmount(sfLimitAmount) : STAmount(); - const bool bQualityIn = txn.getITFieldPresent(sfQualityIn); - const uint32 uQualityIn = bQualityIn ? txn.getITFieldU32(sfQualityIn) : 0; - const bool bQualityOut = txn.getITFieldPresent(sfQualityOut); - const uint32 uQualityOut = bQualityIn ? txn.getITFieldU32(sfQualityOut) : 0; - const uint160 uCurrencyID = saLimitAmount.getCurrency(); - bool bDelIndex = false; - - SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); - if (sleRippleState) - { - // A line exists in one or more directions. -#if 0 - if (!saLimitAmount) - { - // Zeroing line. - uint160 uLowID = sleRippleState->getIValueFieldAccount(sfLowID).getAccountID(); - uint160 uHighID = sleRippleState->getIValueFieldAccount(sfHighID).getAccountID(); - bool bLow = uLowID == uSrcAccountID; - bool bHigh = uLowID == uDstAccountID; - bool bBalanceZero = !sleRippleState->getIValueFieldAmount(sfBalance); - STAmount saDstLimit = sleRippleState->getIValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit); - bool bDstLimitZero = !saDstLimit; - - assert(bLow || bHigh); - - if (bBalanceZero && bDstLimitZero) - { - // Zero balance and eliminating last limit. - - bDelIndex = true; - terResult = dirDelete(false, uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex(), false); - } - } -#endif - - if (!bDelIndex) - { - if (bLimitAmount) - sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit , saLimitAmount); - - if (!bQualityIn) - { - nothing(); - } - else if (uQualityIn) - { - sleRippleState->setIFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn); - } - else - { - sleRippleState->makeIFieldAbsent(bFlipped ? sfLowQualityIn : sfHighQualityIn); - } - - if (!bQualityOut) - { - nothing(); - } - else if (uQualityOut) - { - sleRippleState->setIFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut); - } - else - { - sleRippleState->makeIFieldAbsent(bFlipped ? sfLowQualityOut : sfHighQualityOut); - } - - entryModify(sleRippleState); - } - - Log(lsINFO) << "doCreditSet: Modifying ripple line: bDelIndex=" << bDelIndex; - } - // Line does not exist. - else if (!saLimitAmount) - { - Log(lsINFO) << "doCreditSet: Redundant: Setting non-existant ripple line to 0."; - - return terNO_LINE_NO_ZERO; - } - else - { - // Create a new ripple line. - sleRippleState = entryCreate(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); - - Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString(); - - sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency. - sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAmount); - sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, ACCOUNT_ONE)); - sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, mTxnAccountID); - sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uDstAccountID); - if (uQualityIn) - sleRippleState->setIFieldU32(bFlipped ? sfHighQualityIn : sfLowQualityIn, uQualityIn); - if (uQualityOut) - sleRippleState->setIFieldU32(bFlipped ? sfHighQualityOut : sfLowQualityOut, uQualityOut); - - uint64 uSrcRef; // Ignored, dirs never delete. - - terResult = mNodes.dirAdd(uSrcRef, Ledger::getOwnerDirIndex(mTxnAccountID), sleRippleState->getIndex()); - - if (tesSUCCESS == terResult) - terResult = mNodes.dirAdd(uSrcRef, Ledger::getOwnerDirIndex(uDstAccountID), sleRippleState->getIndex()); - } - - Log(lsINFO) << "doCreditSet<"; - - return terResult; -} - -TER TransactionEngine::doNicknameSet(const SerializedTransaction& txn) -{ - std::cerr << "doNicknameSet>" << std::endl; - - const uint256 uNickname = txn.getITFieldH256(sfNickname); - const bool bMinOffer = txn.getITFieldPresent(sfMinimumOffer); - const STAmount saMinOffer = bMinOffer ? txn.getITFieldAmount(sfAmount) : STAmount(); - - SLE::pointer sleNickname = entryCache(ltNICKNAME, uNickname); - - if (sleNickname) - { - // Edit old entry. - sleNickname->setIFieldAccount(sfAccount, mTxnAccountID); - - if (bMinOffer && saMinOffer) - { - sleNickname->setIFieldAmount(sfMinimumOffer, saMinOffer); - } - else - { - sleNickname->makeIFieldAbsent(sfMinimumOffer); - } - - entryModify(sleNickname); - } - else - { - // Make a new entry. - // XXX Need to include authorization limiting for first year. - - sleNickname = entryCreate(ltNICKNAME, Ledger::getNicknameIndex(uNickname)); - - std::cerr << "doNicknameSet: Creating nickname node: " << sleNickname->getIndex().ToString() << std::endl; - - sleNickname->setIFieldAccount(sfAccount, mTxnAccountID); - - if (bMinOffer && saMinOffer) - sleNickname->setIFieldAmount(sfMinimumOffer, saMinOffer); - } - - std::cerr << "doNicknameSet<" << std::endl; - - return tesSUCCESS; -} - -TER TransactionEngine::doPasswordFund(const SerializedTransaction& txn) -{ - std::cerr << "doPasswordFund>" << std::endl; - - const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); - SLE::pointer sleDst = mTxnAccountID == uDstAccountID - ? mTxnAccount - : entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - if (!sleDst) - { - // Destination account does not exist. - std::cerr << "doPasswordFund: Delay transaction: Destination account does not exist." << std::endl; - - return terSET_MISSING_DST; - } - - if (sleDst->getFlags() & lsfPasswordSpent) - { - sleDst->clearFlag(lsfPasswordSpent); - - std::cerr << "doPasswordFund: Clearing spent." << sleDst->getFlags() << std::endl; - - if (mTxnAccountID != uDstAccountID) { - std::cerr << "doPasswordFund: Destination modified." << std::endl; - - entryModify(sleDst); - } - } - - std::cerr << "doPasswordFund<" << std::endl; - - return tesSUCCESS; -} - -TER TransactionEngine::doPasswordSet(const SerializedTransaction& txn) -{ - std::cerr << "doPasswordSet>" << std::endl; - - if (mTxnAccount->getFlags() & lsfPasswordSpent) - { - std::cerr << "doPasswordSet: Delay transaction: Funds already spent." << std::endl; - - return terFUNDS_SPENT; - } - - mTxnAccount->setFlag(lsfPasswordSpent); - - TER terResult = setAuthorized(txn, false); - - std::cerr << "doPasswordSet<" << std::endl; - - return terResult; -} - - -// XXX Need to audit for things like setting accountID not having memory. -TER TransactionEngine::doPayment(const SerializedTransaction& txn, const TransactionEngineParams params) -{ - // Ripple if source or destination is non-native or if there are paths. - const uint32 uTxFlags = txn.getFlags(); - const bool bCreate = isSetBit(uTxFlags, tfCreateAccount); - const bool bPartialPayment = isSetBit(uTxFlags, tfPartialPayment); - const bool bLimitQuality = isSetBit(uTxFlags, tfLimitQuality); - const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect); - const bool bPaths = txn.getITFieldPresent(sfPaths); - const bool bMax = txn.getITFieldPresent(sfSendMax); - const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); - const STAmount saDstAmount = txn.getITFieldAmount(sfAmount); - const STAmount saMaxAmount = bMax ? txn.getITFieldAmount(sfSendMax) : saDstAmount; - const uint160 uSrcCurrency = saMaxAmount.getCurrency(); - const uint160 uDstCurrency = saDstAmount.getCurrency(); - - Log(lsINFO) << boost::str(boost::format("doPayment> saMaxAmount=%s saDstAmount=%s") - % saMaxAmount.getFullText() - % saDstAmount.getFullText()); - - if (!uDstAccountID) - { - Log(lsINFO) << "doPayment: Invalid transaction: Payment destination account not specifed."; - - return temDST_NEEDED; - } - else if (!saDstAmount.isPositive()) - { - Log(lsINFO) << "doPayment: Invalid transaction: bad amount: " << saDstAmount.getHumanCurrency() << " " << saDstAmount.getText(); - - return temBAD_AMOUNT; - } - else if (mTxnAccountID == uDstAccountID && uSrcCurrency == uDstCurrency && !bPaths) - { - Log(lsINFO) << boost::str(boost::format("doPayment: Invalid transaction: Redunant transaction: src=%s, dst=%s, src_cur=%s, dst_cur=%s") - % mTxnAccountID.ToString() - % uDstAccountID.ToString() - % uSrcCurrency.ToString() - % uDstCurrency.ToString()); - - return temREDUNDANT; - } - else if (bMax - && ((saMaxAmount == saDstAmount && saMaxAmount.getCurrency() == saDstAmount.getCurrency()) - || (saDstAmount.isNative() && saMaxAmount.isNative()))) - { - Log(lsINFO) << "doPayment: Invalid transaction: bad SendMax."; - - return temINVALID; - } - - SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - if (!sleDst) - { - // Destination account does not exist. - if (bCreate && !saDstAmount.isNative()) - { - // This restriction could be relaxed. - Log(lsINFO) << "doPayment: Invalid transaction: Create account may only fund XNS."; - - return temCREATEXNS; - } - else if (!bCreate) - { - Log(lsINFO) << "doPayment: Delay transaction: Destination account does not exist."; - - return terNO_DST; - } - - // Create the account. - sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - - sleDst->setIFieldAccount(sfAccount, uDstAccountID); - sleDst->setIFieldU32(sfSequence, 1); - } - else - { - entryModify(sleDst); - } - - TER terResult; - // XXX Should bMax be sufficient to imply ripple? - const bool bRipple = bPaths || bMax || !saDstAmount.isNative(); - - if (bRipple) - { - // Ripple payment - - STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); - STAmount saMaxAmountAct; - STAmount saDstAmountAct; - - terResult = isSetBit(params, tapOPEN_LEDGER) && spsPaths.getPathCount() > RIPPLE_PATHS_MAX - ? telBAD_PATH_COUNT - : RippleCalc::rippleCalc( - mNodes, - saMaxAmountAct, - saDstAmountAct, - saMaxAmount, - saDstAmount, - uDstAccountID, - mTxnAccountID, - spsPaths, - bPartialPayment, - bLimitQuality, - bNoRippleDirect); - } - else - { - // Direct XNS payment. - - STAmount saSrcXNSBalance = mTxnAccount->getIValueFieldAmount(sfBalance); - - if (saSrcXNSBalance < saDstAmount) - { - // Transaction might succeed, if applied in a different order. - Log(lsINFO) << "doPayment: Delay transaction: Insufficent funds."; - - terResult = terUNFUNDED; - } - else - { - mTxnAccount->setIFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); - sleDst->setIFieldAmount(sfBalance, sleDst->getIValueFieldAmount(sfBalance) + saDstAmount); - - terResult = tesSUCCESS; - } - } - - std::string strToken; - std::string strHuman; - - if (transResultInfo(terResult, strToken, strHuman)) - { - Log(lsINFO) << boost::str(boost::format("doPayment: %s: %s") % strToken % strHuman); - } - else - { - assert(false); - } - - return terResult; -} - -TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn) -{ - std::cerr << "WalletAdd>" << std::endl; - - const std::vector vucPubKey = txn.getITFieldVL(sfPubKey); - const std::vector vucSignature = txn.getITFieldVL(sfSignature); - const uint160 uAuthKeyID = txn.getITFieldAccount(sfAuthorizedKey); - const NewcoinAddress naMasterPubKey = NewcoinAddress::createAccountPublic(vucPubKey); - const uint160 uDstAccountID = naMasterPubKey.getAccountID(); - - if (!naMasterPubKey.accountPublicVerify(Serializer::getSHA512Half(uAuthKeyID.begin(), uAuthKeyID.size()), vucSignature)) - { - std::cerr << "WalletAdd: unauthorized: bad signature " << std::endl; - - return tefBAD_ADD_AUTH; - } - - SLE::pointer sleDst = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - - if (sleDst) - { - std::cerr << "WalletAdd: account already created" << std::endl; - - return tefCREATED; - } - - STAmount saAmount = txn.getITFieldAmount(sfAmount); - STAmount saSrcBalance = mTxnAccount->getIValueFieldAmount(sfBalance); - - if (saSrcBalance < saAmount) - { - std::cerr - << boost::str(boost::format("WalletAdd: Delay transaction: insufficent balance: balance=%s amount=%s") - % saSrcBalance.getText() - % saAmount.getText()) - << std::endl; - - return terUNFUNDED; - } - - // Deduct initial balance from source account. - mTxnAccount->setIFieldAmount(sfBalance, saSrcBalance-saAmount); - - // Create the account. - sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - - sleDst->setIFieldAccount(sfAccount, uDstAccountID); - sleDst->setIFieldU32(sfSequence, 1); - sleDst->setIFieldAmount(sfBalance, saAmount); - sleDst->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); - - std::cerr << "WalletAdd<" << std::endl; - - return tesSUCCESS; -} - -TER TransactionEngine::doInvoice(const SerializedTransaction& txn) -{ - return temUNKNOWN; -} - -// Take as much as possible. Adjusts account balances. Charges fees on top to taker. -// --> uBookBase: The order book to take against. -// --> saTakerPays: What the taker offers (w/ issuer) -// --> saTakerGets: What the taker wanted (w/ issuer) -// <-- saTakerPaid: What taker paid not including fees. To reduce an offer. -// <-- saTakerGot: What taker got not including fees. To reduce an offer. -// <-- terResult: tesSUCCESS or terNO_ACCOUNT -// XXX: Fees should be paid by the source of the currency. -TER TransactionEngine::takeOffers( - bool bPassive, - const uint256& uBookBase, - const uint160& uTakerAccountID, - const SLE::pointer& sleTakerAccount, - const STAmount& saTakerPays, - const STAmount& saTakerGets, - STAmount& saTakerPaid, - STAmount& saTakerGot) -{ - assert(saTakerPays && saTakerGets); - - Log(lsINFO) << "takeOffers: against book: " << uBookBase.ToString(); - - uint256 uTipIndex = uBookBase; - const uint256 uBookEnd = Ledger::getQualityNext(uBookBase); - const uint64 uTakeQuality = STAmount::getRate(saTakerGets, saTakerPays); - const uint160 uTakerPaysAccountID = saTakerPays.getIssuer(); - const uint160 uTakerGetsAccountID = saTakerGets.getIssuer(); - TER terResult = temUNCERTAIN; - - boost::unordered_set usOfferUnfundedFound; // Offers found unfunded. - boost::unordered_set usOfferUnfundedBecame; // Offers that became unfunded. - boost::unordered_set usAccountTouched; // Accounts touched. - - saTakerPaid = 0; - saTakerGot = 0; - - while (temUNCERTAIN == terResult) - { - SLE::pointer sleOfferDir; - uint64 uTipQuality; - - // Figure out next offer to take, if needed. - if (saTakerGets != saTakerGot && saTakerPays != saTakerPaid) - { - // Taker has needs. - - sleOfferDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uTipIndex, uBookEnd)); - if (sleOfferDir) - { - Log(lsINFO) << "takeOffers: possible counter offer found"; - - uTipIndex = sleOfferDir->getIndex(); - uTipQuality = Ledger::getQuality(uTipIndex); - } - else - { - Log(lsINFO) << "takeOffers: counter offer book is empty: " - << uTipIndex.ToString() - << " ... " - << uBookEnd.ToString(); - } - } - - if (!sleOfferDir // No offer directory to take. - || uTakeQuality < uTipQuality // No offer's of sufficient quality available. - || (bPassive && uTakeQuality == uTipQuality)) - { - // Done. - Log(lsINFO) << "takeOffers: done"; - - terResult = tesSUCCESS; - } - else - { - // Have an offer directory to consider. - Log(lsINFO) << "takeOffers: considering dir : " << sleOfferDir->getJson(0); - - SLE::pointer sleBookNode; - unsigned int uBookEntry; - uint256 uOfferIndex; - - mNodes.dirFirst(uTipIndex, sleBookNode, uBookEntry, uOfferIndex); - - SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - - Log(lsINFO) << "takeOffers: considering offer : " << sleOffer->getJson(0); - - const uint160 uOfferOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); - STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); - STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); - - if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) - { - // Offer is expired. Expired offers are considered unfunded. Delete it. - Log(lsINFO) << "takeOffers: encountered expired offer"; - - usOfferUnfundedFound.insert(uOfferIndex); - } - else if (uOfferOwnerID == uTakerAccountID) - { - // Would take own offer. Consider old offer expired. Delete it. - Log(lsINFO) << "takeOffers: encountered taker's own old offer"; - - usOfferUnfundedFound.insert(uOfferIndex); - } - else - { - // Get offer funds available. - - Log(lsINFO) << "takeOffers: saOfferPays=" << saOfferPays.getFullText(); - - STAmount saOfferFunds = mNodes.accountFunds(uOfferOwnerID, saOfferPays); - STAmount saTakerFunds = mNodes.accountFunds(uTakerAccountID, saTakerPays); - SLE::pointer sleOfferAccount; // Owner of offer. - - if (!saOfferFunds.isPositive()) - { - // Offer is unfunded, possibly due to previous balance action. - Log(lsINFO) << "takeOffers: offer unfunded: delete"; - - boost::unordered_set::iterator account = usAccountTouched.find(uOfferOwnerID); - if (account != usAccountTouched.end()) - { - // Previously touched account. - usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success. - } - else - { - // Never touched source account. - usOfferUnfundedFound.insert(uOfferIndex); // Delete found unfunded offer when possible. - } - } - else - { - STAmount saPay = saTakerPays - saTakerPaid; - if (saTakerFunds < saPay) - saPay = saTakerFunds; - STAmount saSubTakerPaid; - STAmount saSubTakerGot; - - Log(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText(); - Log(lsINFO) << "takeOffers: applyOffer: saTakerPaid: " << saTakerPaid.getFullText(); - Log(lsINFO) << "takeOffers: applyOffer: saTakerFunds: " << saTakerFunds.getFullText(); - Log(lsINFO) << "takeOffers: applyOffer: saOfferFunds: " << saOfferFunds.getFullText(); - Log(lsINFO) << "takeOffers: applyOffer: saPay: " << saPay.getFullText(); - Log(lsINFO) << "takeOffers: applyOffer: saOfferPays: " << saOfferPays.getFullText(); - Log(lsINFO) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText(); - Log(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText(); - Log(lsINFO) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText(); - - bool bOfferDelete = STAmount::applyOffer( - saOfferFunds, - saPay, // Driver XXX need to account for fees. - saOfferPays, - saOfferGets, - saTakerPays, - saTakerGets, - saSubTakerPaid, - saSubTakerGot); - - Log(lsINFO) << "takeOffers: applyOffer: saSubTakerPaid: " << saSubTakerPaid.getFullText(); - Log(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText(); - - // Adjust offer - - // Offer owner will pay less. Subtract what taker just got. - sleOffer->setIFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot); - - // Offer owner will get less. Subtract what owner just paid. - sleOffer->setIFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid); - - entryModify(sleOffer); - - if (bOfferDelete) - { - // Offer now fully claimed or now unfunded. - Log(lsINFO) << "takeOffers: offer claimed: delete"; - - usOfferUnfundedBecame.insert(uOfferIndex); // Delete unfunded offer on success. - - // Offer owner's account is no longer pristine. - usAccountTouched.insert(uOfferOwnerID); - } - else - { - Log(lsINFO) << "takeOffers: offer partial claim."; - } - - // Offer owner pays taker. - saSubTakerGot.setIssuer(uTakerGetsAccountID); // XXX Move this earlier? - - mNodes.accountSend(uOfferOwnerID, uTakerAccountID, saSubTakerGot); - - saTakerGot += saSubTakerGot; - - // Taker pays offer owner. - saSubTakerPaid.setIssuer(uTakerPaysAccountID); - - mNodes.accountSend(uTakerAccountID, uOfferOwnerID, saSubTakerPaid); - - saTakerPaid += saSubTakerPaid; - } - } - } - } - - // On storing meta data, delete offers that were found unfunded to prevent encountering them in future. - if (tesSUCCESS == terResult) - { - BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedFound) - { - terResult = mNodes.offerDelete(uOfferIndex); - if (tesSUCCESS != terResult) - break; - } - } - - if (tesSUCCESS == terResult) - { - // On success, delete offers that became unfunded. - BOOST_FOREACH(const uint256& uOfferIndex, usOfferUnfundedBecame) - { - terResult = mNodes.offerDelete(uOfferIndex); - if (tesSUCCESS != terResult) - break; - } - } - - return terResult; -} - -TER TransactionEngine::doOfferCreate(const SerializedTransaction& txn) -{ -Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); - const uint32 txFlags = txn.getFlags(); - const bool bPassive = isSetBit(txFlags, tfPassive); - STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); - STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); -Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText(); -Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); - const uint160 uPaysIssuerID = saTakerPays.getIssuer(); - const uint160 uGetsIssuerID = saTakerGets.getIssuer(); - const uint32 uExpiration = txn.getITFieldU32(sfExpiration); - const bool bHaveExpiration = txn.getITFieldPresent(sfExpiration); - const uint32 uSequence = txn.getSequence(); - - const uint256 uLedgerIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); - SLE::pointer sleOffer = entryCreate(ltOFFER, uLedgerIndex); - - Log(lsINFO) << "doOfferCreate: Creating offer node: " << uLedgerIndex.ToString() << " uSequence=" << uSequence; - - const uint160 uPaysCurrency = saTakerPays.getCurrency(); - const uint160 uGetsCurrency = saTakerGets.getCurrency(); - const uint64 uRate = STAmount::getRate(saTakerGets, saTakerPays); - - TER terResult = tesSUCCESS; - uint256 uDirectory; // Delete hints. - uint64 uOwnerNode; - uint64 uBookNode; - - if (bHaveExpiration && !uExpiration) - { - Log(lsWARNING) << "doOfferCreate: Malformed offer: bad expiration"; - - terResult = temBAD_EXPIRATION; - } - else if (bHaveExpiration && mLedger->getParentCloseTimeNC() >= uExpiration) - { - Log(lsWARNING) << "doOfferCreate: Expired transaction: offer expired"; - - // XXX CHARGE FEE ONLY. - terResult = tesSUCCESS; - } - else if (saTakerPays.isNative() && saTakerGets.isNative()) - { - Log(lsWARNING) << "doOfferCreate: Malformed offer: XNS for XNS"; - - terResult = temBAD_OFFER; - } - else if (!saTakerPays || !saTakerGets) - { - Log(lsWARNING) << "doOfferCreate: Malformed offer: bad amount"; - - terResult = temBAD_OFFER; - } - else if (uPaysCurrency == uGetsCurrency && uPaysIssuerID == uGetsIssuerID) - { - Log(lsWARNING) << "doOfferCreate: Malformed offer: redundant offer"; - - terResult = temREDUNDANT; - } - else if (saTakerPays.isNative() != !uPaysIssuerID || saTakerGets.isNative() != !uGetsIssuerID) - { - Log(lsWARNING) << "doOfferCreate: Malformed offer: bad issuer"; - - terResult = temBAD_ISSUER; - } - else if (!mNodes.accountFunds(mTxnAccountID, saTakerGets).isPositive()) - { - Log(lsWARNING) << "doOfferCreate: delay: Offers must be at least partially funded."; - - terResult = terUNFUNDED; - } - - if (tesSUCCESS == terResult && !saTakerPays.isNative()) - { - SLE::pointer sleTakerPays = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uPaysIssuerID)); - - if (!sleTakerPays) - { - Log(lsWARNING) << "doOfferCreate: delay: can't receive IOUs from non-existant issuer: " << NewcoinAddress::createHumanAccountID(uPaysIssuerID); - - terResult = terNO_ACCOUNT; - } - } - - if (tesSUCCESS == terResult) - { - STAmount saOfferPaid; - STAmount saOfferGot; - const uint256 uTakeBookBase = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); - - Log(lsINFO) << boost::str(boost::format("doOfferCreate: take against book: %s : %s/%s -> %s/%s") - % uTakeBookBase.ToString() - % saTakerGets.getHumanCurrency() - % NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()) - % saTakerPays.getHumanCurrency() - % NewcoinAddress::createHumanAccountID(saTakerPays.getIssuer())); - - // Take using the parameters of the offer. - terResult = takeOffers( - bPassive, - uTakeBookBase, - mTxnAccountID, - mTxnAccount, - saTakerGets, - saTakerPays, - saOfferPaid, // How much was spent. - saOfferGot // How much was got. - ); - - Log(lsWARNING) << "doOfferCreate: takeOffers=" << terResult; - Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferPaid=" << saOfferPaid.getFullText(); - Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferGot=" << saOfferGot.getFullText(); - Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText(); - Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText(); - - if (tesSUCCESS == terResult) - { - saTakerPays -= saOfferGot; // Reduce payin from takers by what offer just got. - saTakerGets -= saOfferPaid; // Reduce payout to takers by what srcAccount just paid. - } - } - - Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText(); - Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText(); - Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()); - Log(lsWARNING) << "doOfferCreate: takeOffers: mTxnAccountID=" << NewcoinAddress::createHumanAccountID(mTxnAccountID); - Log(lsWARNING) << "doOfferCreate: takeOffers: funds=" << mNodes.accountFunds(mTxnAccountID, saTakerGets).getFullText(); - - // Log(lsWARNING) << "doOfferCreate: takeOffers: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); - // Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); - - if (tesSUCCESS == terResult - && saTakerPays // Still wanting something. - && saTakerGets // Still offering something. - && mNodes.accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded. - { - // We need to place the remainder of the offer into its order book. - - // Add offer to owner's directory. - terResult = mNodes.dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex); - - if (tesSUCCESS == terResult) - { - uint256 uBookBase = Ledger::getBookBase(uPaysCurrency, uPaysIssuerID, uGetsCurrency, uGetsIssuerID); - - Log(lsINFO) << boost::str(boost::format("doOfferCreate: adding to book: %s : %s/%s -> %s/%s") - % uBookBase.ToString() - % saTakerPays.getHumanCurrency() - % NewcoinAddress::createHumanAccountID(saTakerPays.getIssuer()) - % saTakerGets.getHumanCurrency() - % NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer())); - - uDirectory = Ledger::getQualityIndex(uBookBase, uRate); // Use original rate. - - // Add offer to order book. - terResult = mNodes.dirAdd(uBookNode, uDirectory, uLedgerIndex); - } - - if (tesSUCCESS == terResult) - { - // Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); - // Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); - // Log(lsWARNING) << "doOfferCreate: saTakerPays.isNative()=" << saTakerPays.isNative(); - // Log(lsWARNING) << "doOfferCreate: saTakerGets.isNative()=" << saTakerGets.isNative(); - // Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency(); - // Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency(); - - sleOffer->setIFieldAccount(sfAccount, mTxnAccountID); - sleOffer->setIFieldU32(sfSequence, uSequence); - sleOffer->setIFieldH256(sfBookDirectory, uDirectory); - sleOffer->setIFieldAmount(sfTakerPays, saTakerPays); - sleOffer->setIFieldAmount(sfTakerGets, saTakerGets); - sleOffer->setIFieldU64(sfOwnerNode, uOwnerNode); - sleOffer->setIFieldU64(sfBookNode, uBookNode); - - if (uExpiration) - sleOffer->setIFieldU32(sfExpiration, uExpiration); - - if (bPassive) - sleOffer->setFlag(lsfPassive); - } - } - - return terResult; -} - -TER TransactionEngine::doOfferCancel(const SerializedTransaction& txn) -{ - TER terResult; - const uint32 uSequence = txn.getITFieldU32(sfOfferSequence); - const uint256 uOfferIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); - SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - - if (sleOffer) - { - Log(lsWARNING) << "doOfferCancel: uSequence=" << uSequence; - - terResult = mNodes.offerDelete(sleOffer, uOfferIndex, mTxnAccountID); - } - else - { - Log(lsWARNING) << "doOfferCancel: offer not found: " - << NewcoinAddress::createHumanAccountID(mTxnAccountID) - << " : " << uSequence - << " : " << uOfferIndex.ToString(); - - terResult = terOFFER_NOT_FOUND; - } - - return terResult; -} - -TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) -{ - Log(lsWARNING) << "doContractAdd> " << txn.getJson(0); - - const uint32 expiration = txn.getITFieldU32(sfExpiration); -// const uint32 bondAmount = txn.getITFieldU32(sfBondAmount); -// const uint32 stampEscrow = txn.getITFieldU32(sfStampEscrow); - STAmount rippleEscrow = txn.getITFieldAmount(sfRippleEscrow); - std::vector createCode = txn.getITFieldVL(sfCreateCode); - std::vector fundCode = txn.getITFieldVL(sfFundCode); - std::vector removeCode = txn.getITFieldVL(sfRemoveCode); - std::vector expireCode = txn.getITFieldVL(sfExpireCode); - - // make sure - // expiration hasn't passed - // bond amount is enough - // they have the stamps for the bond - - // place contract in ledger - // run create code - - - if (mLedger->getParentCloseTimeNC() >= expiration) - { - Log(lsWARNING) << "doContractAdd: Expired transaction: offer expired"; - return(tefALREADY); - } - //TODO: check bond - //if( txn.getSourceAccount() ) - - Contract contract; - Script::Interpreter interpreter; - TER terResult=interpreter.interpret(&contract,txn,createCode); - if(tesSUCCESS != terResult) - { - - } - - return(terResult); -} - -TER TransactionEngine::doContractRemove(const SerializedTransaction& txn) -{ - // TODO: - return(tesSUCCESS); -} - // vim:ts=4 From 4faad381120f2bae2cee8dccc7e6347598589e95 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 10 Sep 2012 16:29:42 -0700 Subject: [PATCH 238/426] Base classes used polymorphically whose child classes have data members or destructors must themselves have virtual destructors or Bad Things(TM) happen. --- src/Operation.h | 2 ++ src/ScriptData.h | 2 ++ src/TransactionMeta.h | 1 + 3 files changed, 5 insertions(+) diff --git a/src/Operation.h b/src/Operation.h index 9fca2498c4..11c37d38f3 100644 --- a/src/Operation.h +++ b/src/Operation.h @@ -12,6 +12,8 @@ public: virtual bool work(Interpreter* interpreter)=0; virtual int getFee(); + + virtual ~Operation() { ; } }; // this is just an Int in the code diff --git a/src/ScriptData.h b/src/ScriptData.h index af9ce45c0e..66fe2ed3e4 100644 --- a/src/ScriptData.h +++ b/src/ScriptData.h @@ -9,6 +9,8 @@ class Data public: typedef boost::shared_ptr pointer; + virtual ~Data(){ ; } + virtual bool isInt32(){ return(false); } virtual bool isFloat(){ return(false); } virtual bool isUint160(){ return(false); } diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index 729a724808..b62f9f3617 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -46,6 +46,7 @@ protected: public: TransactionMetaNodeEntry(int type) : mType(type) { ; } + virtual ~TransactionMetaNodeEntry() { ; } int getType() const { return mType; } virtual Json::Value getJson(int) const = 0; From 2c2d9cf8f50348e543d19a36f8266722f8fd50c9 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 10 Sep 2012 16:30:25 -0700 Subject: [PATCH 239/426] Small cleanups. --- src/SerializedTransaction.h | 2 +- src/bignum.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index 59f1650ca1..ee4ffb3ea4 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -28,7 +28,7 @@ protected: TransactionType mType; STVariableLength mSignature; STObject mMiddleTxn, mInnerTxn; - TransactionFormat* mFormat; + const TransactionFormat* mFormat; SerializedTransaction* duplicate() const { return new SerializedTransaction(*this); } diff --git a/src/bignum.h b/src/bignum.h index 78bce87609..a9a08eda2d 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -27,7 +27,7 @@ private: protected: BN_CTX* pctx; - BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; } + CAutoBN_CTX& operator=(BN_CTX* pnew) { pctx = pnew; return *this; } public: CAutoBN_CTX() From 81cd4cf82017ff2507efcb720d1bb8cbd6ac7fbc Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 11 Sep 2012 11:56:41 -0700 Subject: [PATCH 240/426] Start of code to track network state, track overwhelmed nodes, and adjust transaction fees. --- src/LedgerConsensus.cpp | 2 +- src/LedgerTiming.h | 4 ++++ src/ValidationCollection.cpp | 27 ++++++++++++++++++++++++--- src/ValidationCollection.h | 4 +++- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index ce064fe47c..73bc3e6821 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -688,7 +688,7 @@ bool LedgerConsensus::haveConsensus() else ++disagree; } - int currentValidations = theApp->getValidations().getCurrentValidationCount(mPreviousLedger->getCloseTimeNC()); + int currentValidations = theApp->getValidations().getNodesAfter(mPrevLedgerHash); return ContinuousLedgerTiming::haveConsensus(mPreviousProposers, agree + disagree, agree, currentValidations, mPreviousMSeconds, mCurrentMSeconds); } diff --git a/src/LedgerTiming.h b/src/LedgerTiming.h index 80e89b30f4..551c9bfce6 100644 --- a/src/LedgerTiming.h +++ b/src/LedgerTiming.h @@ -28,6 +28,10 @@ // How often we check state or change positions (in milliseconds) # define LEDGER_GRANULARITY 1000 +// The percentage of active trusted validators that must be able to +// keep up with the network or we consider the network overloaded +# define LEDGER_NET_RATIO 70 + // How long we consider a proposal fresh # define PROPOSE_FRESHNESS 20 diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index b11b38b633..e4d1117549 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -116,19 +116,40 @@ int ValidationCollection::getTrustedValidationCount(const uint256& ledger) return trusted; } -int ValidationCollection::getCurrentValidationCount(uint32 afterTime) -{ +int ValidationCollection::getNodesAfter(const uint256& ledger) +{ // Number of trusted nodes that have moved past this ledger int count = 0; boost::mutex::scoped_lock sl(mValidationLock); for (boost::unordered_map::iterator it = mCurrentValidations.begin(), end = mCurrentValidations.end(); it != end; ++it) { - if (it->second->isTrusted() && (it->second->getSignTime() > afterTime)) + if (it->second->isTrusted() && it->second->isPreviousHash(ledger)) ++count; } return count; } +int ValidationCollection::getLoadRatio(bool overLoaded) +{ // how many trusted nodes are able to keep up, higher is better + int goodNodes = overLoaded ? 1 : 0; + int badNodes = overLoaded ? 0 : 1; + { + boost::mutex::scoped_lock sl(mValidationLock); + for (boost::unordered_map::iterator it = mCurrentValidations.begin(), + end = mCurrentValidations.end(); it != end; ++it) + { + if (it->second->isTrusted()) + { + if (it->second->isFull()) + ++goodNodes; + else + ++badNodes; + } + } + } + return (goodNodes * 100) / (goodNodes + badNodes); +} + boost::unordered_map ValidationCollection::getCurrentValidations(uint256 currentLedger) { uint32 cutoff = theApp->getOPs().getNetworkTimeNC() - LEDGER_VAL_INTERVAL; diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index 1972b7b63e..95cd4592e0 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -34,7 +34,9 @@ public: void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted); int getTrustedValidationCount(const uint256& ledger); - int getCurrentValidationCount(uint32 afterTime); + + int getNodesAfter(const uint256& ledger); + int getLoadRatio(bool overLoaded); boost::unordered_map getCurrentValidations(uint256 currentLedger = uint256()); From ca1436ac2593957c8ecbb102678f1e6841b238d5 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 11 Sep 2012 14:51:13 -0700 Subject: [PATCH 241/426] Remove some dead code that was in my way. --- src/LedgerMaster.cpp | 3 +-- src/LedgerMaster.h | 3 +-- src/NetworkOPs.cpp | 6 ++---- src/NetworkOPs.h | 3 +-- src/Peer.cpp | 8 +------- src/SerializedObject.h | 1 - src/Transaction.h | 1 - src/newcoin.proto | 3 --- 8 files changed, 6 insertions(+), 22 deletions(-) diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp index a3cc5a1475..abdbf12e99 100644 --- a/src/LedgerMaster.cpp +++ b/src/LedgerMaster.cpp @@ -80,8 +80,7 @@ Ledger::pointer LedgerMaster::closeLedger() return closingLedger; } -TER LedgerMaster::doTransaction(const SerializedTransaction& txn, uint32 targetLedger, - TransactionEngineParams params) +TER LedgerMaster::doTransaction(const SerializedTransaction& txn, TransactionEngineParams params) { TER result = mEngine.applyTransaction(txn, params); theApp->getOPs().pubTransaction(mEngine.getLedger(), txn, result); diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h index 8db6f34490..37db69c5c2 100644 --- a/src/LedgerMaster.h +++ b/src/LedgerMaster.h @@ -45,8 +45,7 @@ public: void runStandAlone() { mFinalizedLedger = mCurrentLedger; } - TER doTransaction(const SerializedTransaction& txn, uint32 targetLedger, - TransactionEngineParams params); + TER doTransaction(const SerializedTransaction& txn, TransactionEngineParams params); void pushLedger(Ledger::ref newLedger); void pushLedger(Ledger::ref newLCL, Ledger::ref newOL); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 754559db83..cf3873ba89 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -93,7 +93,7 @@ Transaction::pointer NetworkOPs::submitTransaction(const Transaction::pointer& t return tpTransNew; } -Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, uint32 tgtLedger, Peer* source) +Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, Peer* source) { Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true); if (dbtx) return dbtx; @@ -105,7 +105,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, return trans; } - TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, tapOPEN_LEDGER); + TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tapOPEN_LEDGER); if (r == tefFAILURE) throw Fault(IO_ERROR); if (r == terPRE_SEQ) @@ -140,7 +140,6 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, tx.set_rawtransaction(&s.getData().front(), s.getLength()); tx.set_status(newcoin::tsCURRENT); tx.set_receivetimestamp(getNetworkTimeNC()); - tx.set_ledgerindexpossible(trans->getLedger()); PackedMessage::pointer packet = boost::make_shared(tx, newcoin::mtTRANSACTION); theApp->getConnectionPool().relayMessage(source, packet); @@ -157,7 +156,6 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, tx.set_rawtransaction(&s.getData().front(), s.getLength()); tx.set_status(newcoin::tsCURRENT); tx.set_receivetimestamp(getNetworkTimeNC()); - tx.set_ledgerindexpossible(tgtLedger); PackedMessage::pointer packet = boost::make_shared(tx, newcoin::mtTRANSACTION); theApp->getConnectionPool().relayMessage(source, packet); } diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 401d33baee..04f4e731ae 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -116,8 +116,7 @@ public: // Transaction::pointer submitTransaction(const Transaction::pointer& tpTrans); - Transaction::pointer processTransaction(Transaction::pointer transaction, uint32 targetLedger = 0, - Peer* source = NULL); + Transaction::pointer processTransaction(Transaction::pointer transaction, Peer* source = NULL); Transaction::pointer findTransactionByID(const uint256& transactionID); int findTransactionsBySource(const uint256& uLedger, std::list&, const NewcoinAddress& sourceAccount, uint32 minSeq, uint32 maxSeq); diff --git a/src/Peer.cpp b/src/Peer.cpp index aec3ce31e2..ea27e06c81 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -702,13 +702,7 @@ void Peer::recvTransaction(newcoin::TMTransaction& packet) } #endif - uint32 targetLedger = 0; - if (packet.has_ledgerindexfinal()) - targetLedger = packet.ledgerindexfinal(); - else if (packet.has_ledgerindexpossible()) - targetLedger = packet.ledgerindexpossible(); - - tx = theApp->getOPs().processTransaction(tx, targetLedger, this); + tx = theApp->getOPs().processTransaction(tx, this); if(tx->getStatus() != INCLUDED) { // transaction wasn't accepted into ledger diff --git a/src/SerializedObject.h b/src/SerializedObject.h index c8245d6d9d..08377304c1 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -106,7 +106,6 @@ enum SOE_Field sfTakerGets, sfTakerPays, sfTarget, - sfTargetLedger, sfTransferRate, sfVersion, sfWalletLocator, diff --git a/src/Transaction.h b/src/Transaction.h index 1ae8c0aa43..abe612853f 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -281,7 +281,6 @@ public: STAmount getAmount() const { return mTransaction->getITFieldU64(sfAmount); } STAmount getFee() const { return mTransaction->getTransactionFee(); } uint32 getFromAccountSeq() const { return mTransaction->getSequence(); } - uint32 getSourceLedger() const { return mTransaction->getITFieldU32(sfTargetLedger); } uint32 getIdent() const { return mTransaction->getITFieldU32(sfSourceTag); } std::vector getSignature() const { return mTransaction->getSignature(); } uint32 getLedger() const { return mInLedger; } diff --git a/src/newcoin.proto b/src/newcoin.proto index 2426f16ece..cd33de9f0f 100644 --- a/src/newcoin.proto +++ b/src/newcoin.proto @@ -69,9 +69,6 @@ message TMTransaction { required bytes rawTransaction = 1; required TransactionStatus status = 2; optional uint64 receiveTimestamp = 3; - optional uint32 ledgerIndexPossible = 4; // the node may not know - optional uint32 ledgerIndexFinal = 5; - optional bytes conflictingTransaction = 6; } From b5da6c22a52dc875c801b30300175be992984652 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 11 Sep 2012 15:35:23 -0700 Subject: [PATCH 242/426] Missing piece for TX metadata. --- src/SHAMapNodes.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/SHAMapNodes.cpp b/src/SHAMapNodes.cpp index 65514ad95f..746176aba3 100644 --- a/src/SHAMapNodes.cpp +++ b/src/SHAMapNodes.cpp @@ -296,8 +296,9 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector(txID, s.peekData()); mType = tnTRANSACTION_MD; } From ca6e9cf764a8247845368a89a079f025dc6cab9c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 11 Sep 2012 21:36:23 -0700 Subject: [PATCH 243/426] Fix a case where we can get stuck in the wrong consensus window and have to wait for it to timeout. --- src/LedgerConsensus.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 73bc3e6821..515722b408 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -333,6 +333,7 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) mPeerPositions.clear(); mDisputes.clear(); mDeadNodes.clear(); + playbackProposals(); return; } From 30cd0e197d9611f4bcaa21c8cbf94ff926d7ae7c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 12 Sep 2012 09:18:03 -0700 Subject: [PATCH 244/426] Remove dead code that's in my way. --- src/Ledger.cpp | 12 ------------ src/Ledger.h | 1 - 2 files changed, 13 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 71a82231dc..1885439f29 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -211,18 +211,6 @@ RippleState::pointer Ledger::accessRippleState(const uint256& uNode) return boost::make_shared(sle); } -bool Ledger::addTransaction(const Transaction::pointer& trans) -{ // low-level - just add to table - assert(!mAccepted); - assert(trans->getID().isNonZero()); - Serializer s; - trans->getSTransaction()->add(s); - SHAMapItem::pointer item = boost::make_shared(trans->getID(), s.peekData()); - if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata - return false; - return true; -} - bool Ledger::addTransaction(const uint256& txID, const Serializer& txn) { // low-level - just add to table SHAMapItem::pointer item = boost::make_shared(txID, txn.peekData()); diff --git a/src/Ledger.h b/src/Ledger.h index c671a57bf2..a0a274e94e 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -82,7 +82,6 @@ private: protected: - bool addTransaction(const Transaction::pointer&); bool addTransaction(const uint256& id, const Serializer& txn); static Ledger::pointer getSQL(const std::string& sqlStatement); From 1ba5b02f141ce043d09e7385b8e78bee88fab5ab Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 12 Sep 2012 09:18:10 -0700 Subject: [PATCH 245/426] Don't track metadata for directory nodes. --- src/LedgerEntrySet.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 3c5adc432a..6196a3a802 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -350,8 +350,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger) nType = TMNCreatedNode; break; - default: - // ignore these + default: // ignore these break; } @@ -359,6 +358,9 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger) continue; SLE::pointer origNode = origLedger->getSLE(it->first); + if (origNode->getType() == ltDIR_NODE) // No metadata for dir nodes + continue; + SLE::pointer curNode = it->second.mEntry; TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType); From d2336e3eea2d9d27e417d9aae1efef6c52d944ff Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 12 Sep 2012 18:40:16 -0700 Subject: [PATCH 246/426] Ledger functions to handle transaction metadata. --- src/Ledger.cpp | 49 +++++++++++++++++++++++++++++++++++++++++-- src/Ledger.h | 7 +++++-- src/SHAMap.cpp | 10 +++++++++ src/SHAMap.h | 1 + src/TransactionMeta.h | 3 +++ 5 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 1885439f29..00b647c8b6 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -214,7 +214,18 @@ RippleState::pointer Ledger::accessRippleState(const uint256& uNode) bool Ledger::addTransaction(const uint256& txID, const Serializer& txn) { // low-level - just add to table SHAMapItem::pointer item = boost::make_shared(txID, txn.peekData()); - if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata + if (!mTransactionMap->addGiveItem(item, true, false)) + return false; + return true; +} + +bool Ledger::addTransaction(const uint256& txID, const Serializer& txn, const Serializer& md) +{ // low-level - just add to table + Serializer s(txn.getDataLength() + md.getDataLength() + 64); + s.addVL(txn.peekData()); + s.addVL(md.peekData()); + SHAMapItem::pointer item = boost::make_shared(txID, s.peekData()); + if (!mTransactionMap->addGiveItem(item, true, true)) return false; return true; } @@ -225,7 +236,8 @@ Transaction::pointer Ledger::getTransaction(const uint256& transID) const if (!item) return Transaction::pointer(); Transaction::pointer txn = theApp->getMasterTransaction().fetch(transID, false); - if (txn) return txn; + if (txn) + return txn; txn = Transaction::sharedTransaction(item->getData(), true); if (txn->getStatus() == NEW) @@ -235,6 +247,39 @@ Transaction::pointer Ledger::getTransaction(const uint256& transID) const return txn; } +bool Ledger::getTransaction(const uint256& txID, Transaction::pointer& txn, TransactionMetaSet::pointer& meta) +{ + SHAMapTreeNode::TNType type; + SHAMapItem::pointer item = mTransactionMap->peekItem(txID, type); + if (!item) + return false; + + if (type == SHAMapTreeNode::tnTRANSACTION_NM) + { // in tree with no metadata + txn = theApp->getMasterTransaction().fetch(txID, false); + meta = TransactionMetaSet::pointer(); + if (!txn) + txn = Transaction::sharedTransaction(item->getData(), true); + } + else if (type == SHAMapTreeNode::tnTRANSACTION_MD) + { // in tree with metadata + SerializerIterator it(item->getData()); + txn = theApp->getMasterTransaction().fetch(txID, false); + if (!txn) + txn = Transaction::sharedTransaction(it.getVL(), true); + else + it.getVL(); // skip transaction + meta = boost::make_shared(mLedgerSeq, it.getVL()); + } + else + return false; + + if (txn->getStatus() == NEW) + txn->setStatus(mClosed ? COMMITTED : INCLUDED, mLedgerSeq); + theApp->getMasterTransaction().canonicalize(txn, false); + return true; +} + bool Ledger::unitTest() { return true; diff --git a/src/Ledger.h b/src/Ledger.h index a0a274e94e..d059f01581 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -11,6 +11,7 @@ #include "../json/value.h" #include "Transaction.h" +#include "TransactionMeta.h" #include "AccountState.h" #include "RippleState.h" #include "NicknameState.h" @@ -56,7 +57,7 @@ public: TR_PASTASEQ = 6, // account is past this transaction TR_PREASEQ = 7, // account is missing transactions before this TR_BADLSEQ = 8, // ledger too early - TR_TOOSMALL = 9, // amount is less than Tx fee + TR_TOOSMALL = 9, // amount is less than Tx fee }; // ledger close flags @@ -82,7 +83,6 @@ private: protected: - bool addTransaction(const uint256& id, const Serializer& txn); static Ledger::pointer getSQL(const std::string& sqlStatement); @@ -151,8 +151,11 @@ public: bool isAcquiringAS(void); // Transaction Functions + bool addTransaction(const uint256& id, const Serializer& txn); + bool addTransaction(const uint256& id, const Serializer& txn, const Serializer& metaData); bool hasTransaction(const uint256& TransID) const { return mTransactionMap->hasItem(TransID); } Transaction::pointer getTransaction(const uint256& transID) const; + bool getTransaction(const uint256& transID, Transaction::pointer& txn, TransactionMetaSet::pointer& txMeta); // high-level functions AccountState::pointer getAccountState(const NewcoinAddress& acctID); diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 8ae69c405e..8a232ec547 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -421,6 +421,16 @@ SHAMapItem::pointer SHAMap::peekItem(const uint256& id) return leaf->peekItem(); } +SHAMapItem::pointer SHAMap::peekItem(const uint256& id, SHAMapTreeNode::TNType& type) +{ + boost::recursive_mutex::scoped_lock sl(mLock); + SHAMapTreeNode* leaf = walkToPointer(id); + if (!leaf) + return SHAMapItem::pointer(); + type = leaf->getType(); + return leaf->peekItem(); +} + bool SHAMap::hasItem(const uint256& id) { // does the tree have an item with this ID boost::recursive_mutex::scoped_lock sl(mLock); diff --git a/src/SHAMap.h b/src/SHAMap.h index b84dcb7272..0f7061d71a 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -318,6 +318,7 @@ public: // save a copy if you only need a temporary SHAMapItem::pointer peekItem(const uint256& id); + SHAMapItem::pointer peekItem(const uint256& id, SHAMapTreeNode::TNType& type); // traverse functions SHAMapItem::pointer peekFirstItem(); diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index b62f9f3617..10423aeda9 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -168,6 +168,9 @@ public: class TransactionMetaSet { +public: + typedef boost::shared_ptr pointer; + protected: uint256 mTransactionID; uint32 mLedger; From 953f0ad63faf2d2f7ee058a5638dfadfd0a6f7a0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 01:01:40 -0700 Subject: [PATCH 247/426] Don't charge for transactions twice. Have the "old" getTransaction handle metadata sanely. Fix calcRawMeta to fit the new model where an LES holds a reference to its ledger Don't put metadata in open ledger txn sets to avoid breaking the proposal mechanism. --- src/Ledger.cpp | 20 ++++++++++++++++++-- src/LedgerEntrySet.cpp | 10 +++++----- src/LedgerEntrySet.h | 2 +- src/TransactionEngine.cpp | 23 ++++++++++++++++------- 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 00b647c8b6..f106297d4d 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -232,14 +232,30 @@ bool Ledger::addTransaction(const uint256& txID, const Serializer& txn, const Se Transaction::pointer Ledger::getTransaction(const uint256& transID) const { - SHAMapItem::pointer item = mTransactionMap->peekItem(transID); + SHAMapTreeNode::TNType type; + SHAMapItem::pointer item = mTransactionMap->peekItem(transID, type); if (!item) return Transaction::pointer(); Transaction::pointer txn = theApp->getMasterTransaction().fetch(transID, false); if (txn) return txn; - txn = Transaction::sharedTransaction(item->getData(), true); + if (type == SHAMapTreeNode::tnTRANSACTION_NM) + txn = Transaction::sharedTransaction(item->getData(), true); + else if (type == SHAMapTreeNode::tnTRANSACTION_MD) + { + std::vector txnData; + int txnLength; + if (!item->peekSerializer().getVL(txnData, 0, txnLength)) + return Transaction::pointer(); + txn = Transaction::sharedTransaction(txnData, false); + } + else + { + assert(false); + return Transaction::pointer(); + } + if (txn->getStatus() == NEW) txn->setStatus(mClosed ? COMMITTED : INCLUDED, mLedgerSeq); diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 6196a3a802..5c3f16f732 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -325,7 +325,7 @@ bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::ref node, return false; } -void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger) +void LedgerEntrySet::calcRawMeta(Serializer& s) { // calculate the raw meta data and return it. This must be called before the set is committed // Entries modified only as a result of building the transaction metadata @@ -357,7 +357,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger) if (nType == TMNEndOfMetadata) continue; - SLE::pointer origNode = origLedger->getSLE(it->first); + SLE::pointer origNode = mLedger->getSLE(it->first); if (origNode->getType() == ltDIR_NODE) // No metadata for dir nodes continue; @@ -366,7 +366,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger) if (nType == TMNDeletedNode) { - threadOwners(metaNode, origNode, origLedger, newMod); + threadOwners(metaNode, origNode, mLedger, newMod); if (origNode->getIFieldPresent(sfAmount)) { // node has an amount, covers ripple state nodes @@ -398,12 +398,12 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger) } if (nType == TMNCreatedNode) // if created, thread to owner(s) - threadOwners(metaNode, curNode, origLedger, newMod); + threadOwners(metaNode, curNode, mLedger, newMod); if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode)) { if (curNode->isThreadedType()) // always thread to self - threadTx(metaNode, curNode, origLedger, newMod); + threadTx(metaNode, curNode, mLedger, newMod); } if (nType == TMNModifiedNode) diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 6abef7cab3..92d96294e9 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -120,7 +120,7 @@ public: STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault); Json::Value getJson(int) const; - void calcRawMeta(Serializer&, Ledger::ref originalLedger); + void calcRawMeta(Serializer&); // iterator functions bool isEmpty() const { return mEntries.empty(); } diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 2e5e22bd88..1cf9379753 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -430,10 +430,10 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa break; case ttCONTRACT: - terResult= doContractAdd(txn); + terResult = doContractAdd(txn); break; case ttCONTRACT_REMOVE: - terResult=doContractRemove(txn); + terResult = doContractRemove(txn); break; default: @@ -461,14 +461,23 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa txnWrite(); Serializer s; - txn.add(s); - if (!mLedger->addTransaction(txID, s)) - assert(false); + if (isSetBit(params, tapOPEN_LEDGER)) + { + if (!mLedger->addTransaction(txID, s)) + assert(false); + } + else + { + Serializer m; + mNodes.calcRawMeta(m); + if (!mLedger->addTransaction(txID, s, m)) + assert(false); - // Charge whatever fee they specified. - mLedger->destroyCoins(saPaid.getNValue()); + // Charge whatever fee they specified. + mLedger->destroyCoins(saPaid.getNValue()); + } } mTxnAccount = SLE::pointer(); From 34dcb993704aa2fa1545e1032ce7d3c33478bd97 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 01:29:04 -0700 Subject: [PATCH 248/426] New functions to pass tree node types to callers. --- src/SHAMap.cpp | 71 ++++++++++++++++++++++++++++++++++++-------------- src/SHAMap.h | 6 +++-- 2 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 8a232ec547..4525769dba 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -238,7 +238,7 @@ SHAMapItem::SHAMapItem(const uint256& tag, const Serializer& data) : mTag(tag), mData(data.peekData()) { ; } -SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node) +SHAMapTreeNode* SHAMap::firstBelow(SHAMapTreeNode* node) { // Return the first item below this node #ifdef ST_DEBUG @@ -246,7 +246,7 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node) #endif do { // Walk down the tree - if (node->hasItem()) return node->peekItem(); + if (node->hasItem()) return node; bool foundNode = false; for (int i = 0; i < 16; ++i) @@ -261,11 +261,12 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node) foundNode = true; break; } - if (!foundNode) return SHAMapItem::pointer(); + if (!foundNode) + return NULL; } while (true); } -SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node) +SHAMapTreeNode* SHAMap::lastBelow(SHAMapTreeNode* node) { #ifdef DEBUG std::cerr << "lastBelow(" << *node << ")" << std::endl; @@ -273,7 +274,8 @@ SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node) do { // Walk down the tree - if (node->hasItem()) return node->peekItem(); + if (node->hasItem()) + return node; bool foundNode = false; for (int i = 15; i >= 0; ++i) @@ -283,7 +285,8 @@ SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node) foundNode = true; break; } - if (!foundNode) return SHAMapItem::pointer(); + if (!foundNode) + return NULL; } while (true); } @@ -345,16 +348,39 @@ void SHAMap::eraseChildren(SHAMapTreeNode::pointer node) SHAMapItem::pointer SHAMap::peekFirstItem() { boost::recursive_mutex::scoped_lock sl(mLock); - return firstBelow(root.get()); + SHAMapTreeNode *node = firstBelow(root.get()); + if (!node) + return SHAMapItem::pointer(); + return node->peekItem(); +} + +SHAMapItem::pointer SHAMap::peekFirstItem(SHAMapTreeNode::TNType& type) +{ + boost::recursive_mutex::scoped_lock sl(mLock); + SHAMapTreeNode *node = firstBelow(root.get()); + if (!node) + return SHAMapItem::pointer(); + type = node->getType(); + return node->peekItem(); } SHAMapItem::pointer SHAMap::peekLastItem() { boost::recursive_mutex::scoped_lock sl(mLock); - return lastBelow(root.get()); + SHAMapTreeNode *node = lastBelow(root.get()); + if (!node) + return SHAMapItem::pointer(); + return node->peekItem(); } SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id) +{ + SHAMapTreeNode::TNType type; + return peekNextItem(id, type); +} + + +SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id, SHAMapTreeNode::TNType& type) { // Get a pointer to the next item in the tree after a given item - item must be in tree boost::recursive_mutex::scoped_lock sl(mLock); @@ -367,17 +393,24 @@ SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id) if (node->isLeaf()) { if (node->peekItem()->getTag() > id) - return node->peekItem(); - } - else for (int i = node->selectBranch(id) + 1; i < 16; ++i) - if (!node->isEmptyBranch(i)) { - node = getNode(node->getChildNodeID(i), node->getChildHash(i), false); - SHAMapItem::pointer item = firstBelow(node.get()); - if (!item) - throw std::runtime_error("missing node"); - return item; + type = node->getType(); + return node->peekItem(); } + } + else + for (int i = node->selectBranch(id) + 1; i < 16; ++i) + if (!node->isEmptyBranch(i)) + { + SHAMapTreeNode *firstNode = getNodePointer(node->getChildNodeID(i), node->getChildHash(i)); + if (!firstNode) + throw std::runtime_error("missing node"); + firstNode = firstBelow(firstNode); + if (!firstNode) + throw std::runtime_error("missing node"); + type = firstNode->getType(); + return firstNode->peekItem(); + } } // must be last item return SHAMapItem::pointer(); @@ -402,10 +435,10 @@ SHAMapItem::pointer SHAMap::peekPrevItem(const uint256& id) if (!node->isEmptyBranch(i)) { node = getNode(node->getChildNodeID(i), node->getChildHash(i), false); - SHAMapItem::pointer item = firstBelow(node.get()); + SHAMapTreeNode* item = firstBelow(node.get()); if (!item) throw std::runtime_error("missing node"); - return item; + return item->peekItem(); } } // must be last item diff --git a/src/SHAMap.h b/src/SHAMap.h index 0f7061d71a..09ccefe738 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -280,9 +280,9 @@ protected: SHAMapTreeNode::pointer getNode(const SHAMapNode& id); SHAMapTreeNode::pointer getNode(const SHAMapNode& id, const uint256& hash, bool modify); SHAMapTreeNode* getNodePointer(const SHAMapNode& id, const uint256& hash); + SHAMapTreeNode* firstBelow(SHAMapTreeNode*); + SHAMapTreeNode* lastBelow(SHAMapTreeNode*); - SHAMapItem::pointer firstBelow(SHAMapTreeNode*); - SHAMapItem::pointer lastBelow(SHAMapTreeNode*); SHAMapItem::pointer onlyBelow(SHAMapTreeNode*); void eraseChildren(SHAMapTreeNode::pointer); @@ -322,8 +322,10 @@ public: // traverse functions SHAMapItem::pointer peekFirstItem(); + SHAMapItem::pointer peekFirstItem(SHAMapTreeNode::TNType& type); SHAMapItem::pointer peekLastItem(); SHAMapItem::pointer peekNextItem(const uint256&); + SHAMapItem::pointer peekNextItem(const uint256&, SHAMapTreeNode::TNType& type); SHAMapItem::pointer peekPrevItem(const uint256&); // comparison/sync functions From 4e957a5efd7146c7c7d364adb9bd6e5df9dcc31f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 01:29:14 -0700 Subject: [PATCH 249/426] This version is incompatible with the previous versions --- src/Version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Version.h b/src/Version.h index df42303f00..d7cd3a02aa 100644 --- a/src/Version.h +++ b/src/Version.h @@ -5,7 +5,7 @@ // #define SERVER_VERSION_MAJOR 0 -#define SERVER_VERSION_MINOR 4 +#define SERVER_VERSION_MINOR 5 #define SERVER_VERSION_SUB "-a" #define SERVER_NAME "NewCoin" @@ -16,11 +16,11 @@ // Version we prefer to speak: #define PROTO_VERSION_MAJOR 0 -#define PROTO_VERSION_MINOR 6 +#define PROTO_VERSION_MINOR 7 // Version we will speak to: #define MIN_PROTO_MAJOR 0 -#define MIN_PROTO_MINOR 6 +#define MIN_PROTO_MINOR 7 #define MAKE_VERSION_INT(maj,min) ((maj << 16) | min) #define GET_VERSION_MAJOR(ver) (ver >> 16) From 66338e4a0aaacf6b33f2dccfe819062dbcbe1b31 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 01:29:27 -0700 Subject: [PATCH 250/426] Add metadata to some JSON outputs. --- src/Ledger.cpp | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index f106297d4d..2348ef63ec 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -489,14 +489,38 @@ void Ledger::addJson(Json::Value& ret, int options) if (mTransactionMap && (full || ((options & LEDGER_JSON_DUMP_TXNS) != 0))) { Json::Value txns(Json::arrayValue); - for (SHAMapItem::pointer item = mTransactionMap->peekFirstItem(); !!item; - item = mTransactionMap->peekNextItem(item->getTag())) + SHAMapTreeNode::TNType type; + for (SHAMapItem::pointer item = mTransactionMap->peekFirstItem(type); !!item; + item = mTransactionMap->peekNextItem(item->getTag(), type)) { if (full) { - SerializerIterator sit(item->peekSerializer()); - SerializedTransaction txn(sit); - txns.append(txn.getJson(0)); + if (type == SHAMapTreeNode::tnTRANSACTION_NM) + { + SerializerIterator sit(item->peekSerializer()); + SerializedTransaction txn(sit); + txns.append(txn.getJson(0)); + } + else if (type == SHAMapTreeNode::tnTRANSACTION_MD) + { + SerializerIterator sit(item->peekSerializer()); + Serializer sTxn(sit.getVL()); + Serializer sMeta(sit.getVL()); + + SerializerIterator tsit(sTxn); + SerializedTransaction txn(tsit); + + TransactionMetaSet meta(mLedgerSeq, sit.getVL()); + Json::Value txJson = txn.getJson(0); + txJson["metaData"] = meta.getJson(0); + txns.append(txJson); + } + else + { + Json::Value error = Json::objectValue; + error[item->getTag().GetHex()] = type; + txns.append(error); + } } else txns.append(item->getTag().GetHex()); } From 50190b2c35d3622c50afaf125a9865d278917238 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 01:31:51 -0700 Subject: [PATCH 251/426] Fix threading bug. --- src/SerializedLedger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 5796952368..41c4bc7fb8 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -102,7 +102,7 @@ bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint25 if (oldPrevTxID == txID) return false; prevTxID = oldPrevTxID; - prevLedgerID = getIFieldU32(sfLastTxnID); + prevLedgerID = getIFieldU32(sfLastTxnSeq); assert(prevTxID != txID); setIFieldH256(sfLastTxnID, txID); setIFieldU32(sfLastTxnSeq, ledgerSeq); From db85d87ff25d77e2630712e025b513846985068f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 01:39:03 -0700 Subject: [PATCH 252/426] Must modify nodes. --- src/LedgerEntrySet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 5c3f16f732..2e5a83c172 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -431,7 +431,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) // add any new modified nodes to the modification set for (boost::unordered_map::iterator it = newMod.begin(), end = newMod.end(); it != end; ++it) - entryCache(it->second); + entryModify(it->second); mSet.addRaw(s); } From aa35b33b198717573fb824319fe9de0dbd2309d8 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 01:39:14 -0700 Subject: [PATCH 253/426] Must calculated metadata before applying LES> --- src/TransactionEngine.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 1cf9379753..3dc45c7c15 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -15,7 +15,7 @@ void TransactionEngine::txnWrite() { - // Write back the account states and add the transaction to the ledger + // Write back the account states for (boost::unordered_map::iterator it = mNodes.begin(), end = mNodes.end(); it != end; ++it) { @@ -458,6 +458,9 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa if (tesSUCCESS == terResult || isTepPartial(terResult)) { // Transaction succeeded fully or (retries are not allowed and the transaction succeeded partially). + Serializer m; + mNodes.calcRawMeta(m); + txnWrite(); Serializer s; @@ -470,8 +473,6 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa } else { - Serializer m; - mNodes.calcRawMeta(m); if (!mLedger->addTransaction(txID, s, m)) assert(false); From 38dd9f3f88076720a863b56ddd47298e3f99ce0b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 12:29:06 -0700 Subject: [PATCH 254/426] Add metadata JSON to set JSON. Fix a bug where we try to access the existing node when we're creating a node. Extra asserts to catch original node mishandlig. --- src/LedgerEntrySet.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 2e5a83c172..0c09282c3a 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -257,6 +257,8 @@ Json::Value LedgerEntrySet::getJson(int) const } ret["nodes" ] = nodes; + ret["metaData"] = mSet.getJson(0); + return ret; } @@ -358,7 +360,8 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) continue; SLE::pointer origNode = mLedger->getSLE(it->first); - if (origNode->getType() == ltDIR_NODE) // No metadata for dir nodes + + if (origNode && (origNode->getType() == ltDIR_NODE)) // No metadata for dir nodes continue; SLE::pointer curNode = it->second.mEntry; @@ -366,6 +369,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) if (nType == TMNDeletedNode) { + assert(origNode); threadOwners(metaNode, origNode, mLedger, newMod); if (origNode->getIFieldPresent(sfAmount)) @@ -398,7 +402,10 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) } if (nType == TMNCreatedNode) // if created, thread to owner(s) + { + assert(!origNode); threadOwners(metaNode, curNode, mLedger, newMod); + } if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode)) { @@ -408,6 +415,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) if (nType == TMNModifiedNode) { + assert(origNode); if (origNode->getIFieldPresent(sfAmount)) { // node has an amount, covers account root nodes and ripple nodes STAmount amount = origNode->getIValueFieldAmount(sfAmount); From 093ab0955777074cc6da223d55519a76b98d9d89 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 13:08:33 -0700 Subject: [PATCH 255/426] An empty node is legal. For example, a created node. --- src/TransactionMeta.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index 8a14cbbf14..d43e55e343 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -160,11 +160,6 @@ TransactionMetaNode::TransactionMetaNode(int type, const uint256& node, Serializ void TransactionMetaNode::addRaw(Serializer& s) { - if (mEntries.empty()) - { // ack, an empty node - assert(false); - return; - } s.add8(mType); s.add256(mNode); mEntries.sort(); From 4831588c33531be2fbc714cc463edcb007fe0e14 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 13:11:29 -0700 Subject: [PATCH 256/426] Clean up JSON logging. --- src/AccountState.cpp | 6 ++---- src/SerializedObject.cpp | 5 +++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/AccountState.cpp b/src/AccountState.cpp index 774e4247db..85ad825fed 100644 --- a/src/AccountState.cpp +++ b/src/AccountState.cpp @@ -9,6 +9,7 @@ #include "Ledger.h" #include "Serializer.h" +#include "Log.h" AccountState::AccountState(const NewcoinAddress& naAccountID) : mAccountID(naAccountID), mValid(false) { @@ -59,11 +60,8 @@ void AccountState::addJson(Json::Value& val) void AccountState::dump() { Json::Value j(Json::objectValue); - addJson(j); - - Json::StyledStreamWriter ssw; - ssw.write(std::cerr, j); + Log(lsINFO) << j; } // vim:ts=4 diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 7600d803b7..af4210f3d1 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -6,6 +6,8 @@ #include "../json/writer.h" +#include "Log.h" + std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, const char *name) { switch(id) @@ -713,8 +715,7 @@ void STObject::unitTest() copy.setValueFieldU32(sfTest3, 1); if (object1.getSerializer() == copy.getSerializer()) throw std::runtime_error("STObject error"); #ifdef DEBUG - Json::StyledStreamWriter ssw; - ssw.write(std::cerr, copy.getJson(0)); + Log(lsDEBUG) << copy.getJson(0); #endif for (int i = 0; i < 1000; i++) From e6411a6afc56faba5082f461c20d14c208d1de0c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 13:11:34 -0700 Subject: [PATCH 257/426] Ensure we don't get json/value.h without json/writer.h --- src/Log.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Log.h b/src/Log.h index 42c8bb00c9..7153012226 100644 --- a/src/Log.h +++ b/src/Log.h @@ -6,6 +6,9 @@ #include #include +// Ensure that we don't get value.h without writer.h +#include "../json/json.h" + enum LogSeverity { lsTRACE = 0, From 499d9b553674c98ea755804587a325e4c4b9eb12 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 13:12:21 -0700 Subject: [PATCH 258/426] Log metadata in debug builds. --- src/LedgerEntrySet.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 0c09282c3a..305051ef37 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -441,6 +441,10 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) it != end; ++it) entryModify(it->second); +#ifdef DEBUG + Log(lsINFO) << "Metadata:" << mSet.getJson(0); +#endif + mSet.addRaw(s); } From 9cdcf50c0773a21b82a09bc9a62c3d23353b28f5 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 14:08:41 -0700 Subject: [PATCH 259/426] Mark a caution with this code. Cleanups. --- src/SHAMapDiff.cpp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/SHAMapDiff.cpp b/src/SHAMapDiff.cpp index 4bef1f73d1..b425c1e7e6 100644 --- a/src/SHAMapDiff.cpp +++ b/src/SHAMapDiff.cpp @@ -95,13 +95,16 @@ bool SHAMap::compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, i { // compare two hash trees, add up to maxCount differences to the difference table // return value: true=complete table of differences given, false=too many differences // throws on corrupt tables or missing nodes + // CAUTION: otherMap is not locked and must be immutable std::stack nodeStack; // track nodes we've pushed - ScopedLock sl(Lock()); - if (getHash() == otherMap->getHash()) return true; - nodeStack.push(SHAMapDiffNode(SHAMapNode(), getHash(), otherMap->getHash())); + boost::recursive_mutex::scoped_lock sl(mLock); + if (getHash() == otherMap->getHash()) + return true; + + nodeStack.push(SHAMapDiffNode(SHAMapNode(), getHash(), otherMap->getHash())); while (!nodeStack.empty()) { SHAMapDiffNode dNode(nodeStack.top()); @@ -118,17 +121,20 @@ bool SHAMap::compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, i { differences.insert(std::make_pair(ourNode->getTag(), std::make_pair(ourNode->getItem(), otherNode->getItem()))); - if (--maxCount <= 0) return false; + if (--maxCount <= 0) + return false; } } else { differences.insert(std::make_pair(ourNode->getTag(), std::make_pair(ourNode->getItem(), SHAMapItem::pointer()))); - if (--maxCount <= 0) return false; + if (--maxCount <= 0) + return false; differences.insert(std::make_pair(otherNode->getTag(), std::make_pair(SHAMapItem::pointer(), otherNode->getItem()))); - if (--maxCount <= 0) return false; + if (--maxCount <= 0) + return false; } } else if (ourNode->isInner() && otherNode->isLeaf()) @@ -164,7 +170,8 @@ bool SHAMap::compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, i ourNode->getChildHash(i), otherNode->getChildHash(i))); } } - else assert(false); + else + assert(false); } return true; From de8288d4d59e60d7a2e1283cdcf5083a3eeab043 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 15:21:08 -0700 Subject: [PATCH 260/426] Cleanup transaction set sync map creation. Remove a passthrough to NetworkOPs that doesn't make much sense. --- src/LedgerConsensus.cpp | 18 ++++++++++-------- src/NetworkOPs.cpp | 6 ------ src/NetworkOPs.h | 1 - 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 515722b408..3d450295d1 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -25,8 +25,7 @@ typedef std::pair u256_lct_pair; TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false) { - mMap = boost::make_shared(); - mMap->setSynching(); + mMap = boost::make_shared(hash); } void TransactionAcquire::done() @@ -34,10 +33,10 @@ void TransactionAcquire::done() if (mFailed) { Log(lsWARNING) << "Failed to acqiure TXs " << mHash; - theApp->getOPs().mapComplete(mHash, SHAMap::pointer()); + mapComplete(mHash, SHAMap::pointer(), true); } else - theApp->getOPs().mapComplete(mHash, mMap); + mapComplete(mHash, mMap, true); } boost::weak_ptr TransactionAcquire::pmDowncast() @@ -376,7 +375,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) } void LedgerConsensus::createDisputes(const SHAMap::pointer& m1, const SHAMap::pointer& m2) -{ +{ // m2 must be immutable SHAMap::SHAMapDiff differences; m1->compare(m2, differences, 16384); for (SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos) @@ -419,7 +418,8 @@ void LedgerConsensus::mapComplete(const uint256& hash, const SHAMap::pointer& ma assert((it2->first == mOurPosition->getCurrentHash()) && it2->second); createDisputes(it2->second, map); } - else assert(false); // We don't have our own position?! + else + assert(false); // We don't have our own position?! } mComplete[map->getHash()] = map; @@ -868,8 +868,10 @@ bool LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { boost::unordered_map::iterator acq = mAcquiring.find(setHash); - if (acq == mAcquiring.end()) return false; - return acq->second->takeNodes(nodeIDs, nodeData, peer); + if (acq == mAcquiring.end()) + return false; + return + acq->second->takeNodes(nodeIDs, nodeData, peer); } void LedgerConsensus::beginAccept() diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index cf3873ba89..1ecfdfae2e 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -712,12 +712,6 @@ bool NetworkOPs::hasTXSet(const boost::shared_ptr& peer, const uint256& se return mConsensus->peerHasSet(peer, set, status); } -void NetworkOPs::mapComplete(const uint256& hash, const SHAMap::pointer& map) -{ - if (mConsensus) - mConsensus->mapComplete(hash, map, true); -} - void NetworkOPs::endConsensus(bool correctLCL) { uint256 deadLedger = theApp->getMasterLedger().getClosedLedger()->getParentHash(); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 04f4e731ae..e41a8dc6df 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -171,7 +171,6 @@ public: bool recvValidation(const SerializedValidation::pointer& val); SHAMap::pointer getTXMap(const uint256& hash); bool hasTXSet(const boost::shared_ptr& peer, const uint256& set, newcoin::TxSetStatus status); - void mapComplete(const uint256& hash, const SHAMap::pointer& map); // network state machine void checkState(const boost::system::error_code& result); From ec2dded961a9a2634a0458cf29a8796b2ff9d2c1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 15:23:55 -0700 Subject: [PATCH 261/426] Revert "Cleanup transaction set sync map creation." This reverts commit de8288d4d59e60d7a2e1283cdcf5083a3eeab043. --- src/LedgerConsensus.cpp | 18 ++++++++---------- src/NetworkOPs.cpp | 6 ++++++ src/NetworkOPs.h | 1 + 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 3d450295d1..515722b408 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -25,7 +25,8 @@ typedef std::pair u256_lct_pair; TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false) { - mMap = boost::make_shared(hash); + mMap = boost::make_shared(); + mMap->setSynching(); } void TransactionAcquire::done() @@ -33,10 +34,10 @@ void TransactionAcquire::done() if (mFailed) { Log(lsWARNING) << "Failed to acqiure TXs " << mHash; - mapComplete(mHash, SHAMap::pointer(), true); + theApp->getOPs().mapComplete(mHash, SHAMap::pointer()); } else - mapComplete(mHash, mMap, true); + theApp->getOPs().mapComplete(mHash, mMap); } boost::weak_ptr TransactionAcquire::pmDowncast() @@ -375,7 +376,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) } void LedgerConsensus::createDisputes(const SHAMap::pointer& m1, const SHAMap::pointer& m2) -{ // m2 must be immutable +{ SHAMap::SHAMapDiff differences; m1->compare(m2, differences, 16384); for (SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos) @@ -418,8 +419,7 @@ void LedgerConsensus::mapComplete(const uint256& hash, const SHAMap::pointer& ma assert((it2->first == mOurPosition->getCurrentHash()) && it2->second); createDisputes(it2->second, map); } - else - assert(false); // We don't have our own position?! + else assert(false); // We don't have our own position?! } mComplete[map->getHash()] = map; @@ -868,10 +868,8 @@ bool LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { boost::unordered_map::iterator acq = mAcquiring.find(setHash); - if (acq == mAcquiring.end()) - return false; - return - acq->second->takeNodes(nodeIDs, nodeData, peer); + if (acq == mAcquiring.end()) return false; + return acq->second->takeNodes(nodeIDs, nodeData, peer); } void LedgerConsensus::beginAccept() diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 1ecfdfae2e..cf3873ba89 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -712,6 +712,12 @@ bool NetworkOPs::hasTXSet(const boost::shared_ptr& peer, const uint256& se return mConsensus->peerHasSet(peer, set, status); } +void NetworkOPs::mapComplete(const uint256& hash, const SHAMap::pointer& map) +{ + if (mConsensus) + mConsensus->mapComplete(hash, map, true); +} + void NetworkOPs::endConsensus(bool correctLCL) { uint256 deadLedger = theApp->getMasterLedger().getClosedLedger()->getParentHash(); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index e41a8dc6df..04f4e731ae 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -171,6 +171,7 @@ public: bool recvValidation(const SerializedValidation::pointer& val); SHAMap::pointer getTXMap(const uint256& hash); bool hasTXSet(const boost::shared_ptr& peer, const uint256& set, newcoin::TxSetStatus status); + void mapComplete(const uint256& hash, const SHAMap::pointer& map); // network state machine void checkState(const boost::system::error_code& result); From 7ba143b4df9d311b3aa5d2c3e53ab3dcb69075bc Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 15:29:47 -0700 Subject: [PATCH 262/426] Revert "Cleanup transaction set sync map creation." This reverts commit de8288d4d59e60d7a2e1283cdcf5083a3eeab043. --- src/LedgerConsensus.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 515722b408..31f5812015 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -25,8 +25,7 @@ typedef std::pair u256_lct_pair; TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false) { - mMap = boost::make_shared(); - mMap->setSynching(); + mMap = boost::make_shared(hash); } void TransactionAcquire::done() From f8e107a4bebf69d1486c5403b419523fb1ae2abb Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 15:30:21 -0700 Subject: [PATCH 263/426] Extra debug. --- src/LedgerEntrySet.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 305051ef37..4dbef407b1 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -294,9 +294,13 @@ SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::ref ledger, bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::ref ledger, boost::unordered_map& newMods) { + Log(lsTRACE) << "Thread to " << threadTo.getAccountID(); SLE::pointer sle = getForMod(Ledger::getAccountRootIndex(threadTo.getAccountID()), ledger, newMods); if (!sle) + { + assert(false); return false; + } return threadTx(metaNode, sle, ledger, newMods); } From 7c7a4bd3e0670064a7318149c5e0852fc3893466 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 15:32:30 -0700 Subject: [PATCH 264/426] Make a field for transaction metadata. --- src/DBInit.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/DBInit.cpp b/src/DBInit.cpp index e968ddf3c0..c0f7086b78 100644 --- a/src/DBInit.cpp +++ b/src/DBInit.cpp @@ -14,6 +14,7 @@ const char *TxnDBInit[] = { LedgerSeq BIGINT UNSIGNED, \ Status CHARACTER(1), \ RawTxn BLOB \ + TxnMeta BLOB \ );", "CREATE TABLE PubKeys ( \ ID CHARACTER(35) PRIMARY KEY, \ From 6c016039c2d7c55fa7809a7002d0ebea98bfe74d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 15:36:56 -0700 Subject: [PATCH 265/426] Get rid of all "const SHAMap::pointer&" -> SHAMap::ref --- src/LedgerConsensus.cpp | 10 +++++----- src/LedgerConsensus.h | 10 +++++----- src/NetworkOPs.cpp | 2 +- src/NetworkOPs.h | 2 +- src/SHAMap.h | 6 ++++-- src/SHAMapDiff.cpp | 2 +- 6 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 31f5812015..5e10b5f78f 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -374,7 +374,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) propose(); } -void LedgerConsensus::createDisputes(const SHAMap::pointer& m1, const SHAMap::pointer& m2) +void LedgerConsensus::createDisputes(SHAMap::ref m1, SHAMap::ref m2) { SHAMap::SHAMapDiff differences; m1->compare(m2, differences, 16384); @@ -394,7 +394,7 @@ void LedgerConsensus::createDisputes(const SHAMap::pointer& m1, const SHAMap::po } } -void LedgerConsensus::mapComplete(const uint256& hash, const SHAMap::pointer& map, bool acquired) +void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::ref map, bool acquired) { if (acquired) Log(lsINFO) << "We have acquired TXS " << hash; @@ -446,7 +446,7 @@ void LedgerConsensus::sendHaveTxSet(const uint256& hash, bool direct) theApp->getConnectionPool().relayMessage(NULL, packet); } -void LedgerConsensus::adjustCount(const SHAMap::pointer& map, const std::vector& peers) +void LedgerConsensus::adjustCount(SHAMap::ref map, const std::vector& peers) { // Adjust the counts on all disputed transactions based on the set of peers taking this position BOOST_FOREACH(u256_lct_pair& it, mDisputes) { @@ -954,7 +954,7 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, const Serializ #endif } -void LedgerConsensus::applyTransactions(const SHAMap::pointer& set, Ledger::ref applyLedger, +void LedgerConsensus::applyTransactions(SHAMap::ref set, Ledger::ref applyLedger, Ledger::ref checkLedger, CanonicalTXSet& failedTransactions, bool openLgr) { TransactionEngineParams parms = openLgr ? tapOPEN_LEDGER : tapNONE; @@ -1016,7 +1016,7 @@ uint32 LedgerConsensus::roundCloseTime(uint32 closeTime) return closeTime - (closeTime % mCloseResolution); } -void LedgerConsensus::accept(const SHAMap::pointer& set) +void LedgerConsensus::accept(SHAMap::ref set) { assert(set->getHash() == mOurPosition->getCurrentHash()); diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 17aa02691d..fcec2205a5 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -120,21 +120,21 @@ protected: // final accept logic static void Saccept(boost::shared_ptr This, SHAMap::pointer txSet); - void accept(const SHAMap::pointer& txSet); + void accept(SHAMap::ref txSet); void weHave(const uint256& id, Peer::ref avoidPeer); void startAcquiring(const TransactionAcquire::pointer&); SHAMap::pointer find(const uint256& hash); - void createDisputes(const SHAMap::pointer&, const SHAMap::pointer&); + void createDisputes(SHAMap::ref, SHAMap::ref); void addDisputedTransaction(const uint256&, const std::vector& transaction); - void adjustCount(const SHAMap::pointer& map, const std::vector& peers); + void adjustCount(SHAMap::ref map, const std::vector& peers); void propose(); void addPosition(LedgerProposal&, bool ours); void removePosition(LedgerProposal&, bool ours); void sendHaveTxSet(const uint256& set, bool direct); - void applyTransactions(const SHAMap::pointer& transactionSet, Ledger::ref targetLedger, + void applyTransactions(SHAMap::ref transactionSet, Ledger::ref targetLedger, Ledger::ref checkLedger, CanonicalTXSet& failedTransactions, bool openLgr); void applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn, Ledger::ref targetLedger, CanonicalTXSet& failedTransactions, bool openLgr); @@ -162,7 +162,7 @@ public: SHAMap::pointer getTransactionTree(const uint256& hash, bool doAcquire); TransactionAcquire::pointer getAcquiring(const uint256& hash); - void mapComplete(const uint256& hash, const SHAMap::pointer& map, bool acquired); + void mapComplete(const uint256& hash, SHAMap::ref map, bool acquired); void checkLCL(); void handleLCL(const uint256& lclHash); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index cf3873ba89..159a7a2d69 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -712,7 +712,7 @@ bool NetworkOPs::hasTXSet(const boost::shared_ptr& peer, const uint256& se return mConsensus->peerHasSet(peer, set, status); } -void NetworkOPs::mapComplete(const uint256& hash, const SHAMap::pointer& map) +void NetworkOPs::mapComplete(const uint256& hash, SHAMap::ref map) { if (mConsensus) mConsensus->mapComplete(hash, map, true); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 04f4e731ae..970a27c633 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -171,7 +171,7 @@ public: bool recvValidation(const SerializedValidation::pointer& val); SHAMap::pointer getTXMap(const uint256& hash); bool hasTXSet(const boost::shared_ptr& peer, const uint256& set, newcoin::TxSetStatus status); - void mapComplete(const uint256& hash, const SHAMap::pointer& map); + void mapComplete(const uint256& hash, SHAMap::ref& map); // network state machine void checkState(const boost::system::error_code& result); diff --git a/src/SHAMap.h b/src/SHAMap.h index 09ccefe738..08712611f7 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -24,7 +24,8 @@ class SHAMap; class SHAMapNode { // Identifies a node in a SHA256 hash public: - typedef boost::shared_ptr pointer; + typedef boost::shared_ptr pointer; + typedef const boost::shared_ptr& ref; private: static uint256 smMasks[65]; // AND with hash to get node id @@ -255,6 +256,7 @@ class SHAMap { public: typedef boost::shared_ptr pointer; + typedef const boost::shared_ptr& ref; typedef std::map > SHAMapDiff; private: @@ -350,7 +352,7 @@ public: // caution: otherMap must be accessed only by this function // return value: true=successfully completed, false=too different - bool compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, int maxCount); + bool compare(SHAMap::ref otherMap, SHAMapDiff& differences, int maxCount); void armDirty(); int flushDirty(int maxNodes, HashedObjectType t, uint32 seq); diff --git a/src/SHAMapDiff.cpp b/src/SHAMapDiff.cpp index b425c1e7e6..9c147ac80e 100644 --- a/src/SHAMapDiff.cpp +++ b/src/SHAMapDiff.cpp @@ -91,7 +91,7 @@ bool SHAMap::walkBranch(SHAMapTreeNode* node, SHAMapItem::pointer otherMapItem, return true; } -bool SHAMap::compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, int maxCount) +bool SHAMap::compare(SHAMap::ref otherMap, SHAMapDiff& differences, int maxCount) { // compare two hash trees, add up to maxCount differences to the difference table // return value: true=complete table of differences given, false=too many differences // throws on corrupt tables or missing nodes From 58befb406e7aa2b12dcaaf6c7b78b1591d6bd74d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 15:37:48 -0700 Subject: [PATCH 266/426] Typo. --- src/NetworkOPs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 970a27c633..ed6e7f0471 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -171,7 +171,7 @@ public: bool recvValidation(const SerializedValidation::pointer& val); SHAMap::pointer getTXMap(const uint256& hash); bool hasTXSet(const boost::shared_ptr& peer, const uint256& set, newcoin::TxSetStatus status); - void mapComplete(const uint256& hash, SHAMap::ref& map); + void mapComplete(const uint256& hash, SHAMap::ref map); // network state machine void checkState(const boost::system::error_code& result); From 1faa8ccda6eb0d1dedac64a93d19a87f47e42cf4 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 19:26:40 -0700 Subject: [PATCH 267/426] Some less confusing names. --- src/LedgerConsensus.cpp | 69 ++++++++++++++++++++++------------------- src/LedgerConsensus.h | 12 +++---- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 5e10b5f78f..f7fa15de13 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -173,18 +173,18 @@ void LCTransaction::unVote(const uint160& peer) } } -bool LCTransaction::updatePosition(int percentTime, bool proposing) +bool LCTransaction::updateVote(int percentTime, bool proposing) { - if (mOurPosition && (mNays == 0)) + if (mOurVote && (mNays == 0)) return false; - if (!mOurPosition && (mYays == 0)) + if (!mOurVote && (mYays == 0)) return false; bool newPosition; if (proposing) // give ourselves full weight { // This is basically the percentage of nodes voting 'yes' (including us) - int weight = (mYays * 100 + (mOurPosition ? 100 : 0)) / (mNays + mYays + 1); + int weight = (mYays * 100 + (mOurVote ? 100 : 0)) / (mNays + mYays + 1); // To prevent avalanche stalls, we increase the needed weight slightly over time if (percentTime < AV_MID_CONSENSUS_TIME) newPosition = weight > AV_INIT_CONSENSUS_PCT; @@ -194,16 +194,16 @@ bool LCTransaction::updatePosition(int percentTime, bool proposing) else // don't let us outweight a proposing node, just recognize consensus newPosition = mYays > mNays; - if (newPosition == mOurPosition) + if (newPosition == mOurVote) { #ifdef LC_DEBUG - Log(lsTRACE) << "No change (" << (mOurPosition ? "YES" : "NO") << ") : weight " + Log(lsTRACE) << "No change (" << (mOurVote ? "YES" : "NO") << ") : weight " << weight << ", percent " << percentTime; #endif return false; } - mOurPosition = newPosition; - Log(lsTRACE) << "We now vote " << (mOurPosition ? "YES" : "NO") << " on " << mTransactionID; + mOurVote = newPosition; + Log(lsTRACE) << "We now vote " << (mOurVote ? "YES" : "NO") << " on " << mTransactionID; return true; } @@ -357,9 +357,9 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) { uint256 set = it.second->getCurrentHash(); if (found.insert(set).second) - { - boost::unordered_map::iterator iit = mComplete.find(set); - if (iit != mComplete.end()) + { // OPTIMIZEME: Don't process the same set more than once + boost::unordered_map::iterator iit = mAcquired.find(set); + if (iit != mAcquired.end()) createDisputes(initialSet, iit->second); } } @@ -402,25 +402,27 @@ void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::ref map, bool acq if (!map) { // this is an invalid/corrupt map - mComplete[hash] = map; + mAcquired[hash] = map; Log(lsWARNING) << "A trusted node directed us to acquire an invalid TXN map"; return; } + assert(hash == map->getHash()); - if (mComplete.find(hash) != mComplete.end()) + if (mAcquired.find(hash) != mAcquired.end()) return; // we already have this map - if (mOurPosition && (map->getHash() != mOurPosition->getCurrentHash())) + if (mOurPosition && (hash != mOurPosition->getCurrentHash())) { // this could create disputed transactions - boost::unordered_map::iterator it2 = mComplete.find(mOurPosition->getCurrentHash()); - if (it2 != mComplete.end()) + boost::unordered_map::iterator it2 = mAcquired.find(mOurPosition->getCurrentHash()); + if (it2 != mAcquired.end()) { assert((it2->first == mOurPosition->getCurrentHash()) && it2->second); createDisputes(it2->second, map); } - else assert(false); // We don't have our own position?! + else + assert(false); // We don't have our own position?! } - mComplete[map->getHash()] = map; + mAcquired[hash] = map; // Adjust tracking for each peer that takes this position std::vector peers; @@ -594,14 +596,15 @@ void LedgerConsensus::updateOurPositions() BOOST_FOREACH(u256_lct_pair& it, mDisputes) { - if (it.second->updatePosition(mClosePercent, mProposing)) + if (it.second->updateVote(mClosePercent, mProposing)) { if (!changes) { - ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); + ourPosition = mAcquired[mOurPosition->getCurrentHash()]->snapShot(true); + assert(ourPosition); changes = true; } - if (it.second->getOurPosition()) // now a yes + if (it.second->getOurVote()) // now a yes { ourPosition->addItem(SHAMapItem(it.first, it.second->peekTransaction()), true, false); // addedTx.push_back(it.first); @@ -662,18 +665,19 @@ void LedgerConsensus::updateOurPositions() ((closeTime != (roundCloseTime(mOurPosition->getCloseTime()))) || (mOurPosition->isStale(ourCutoff)))) { // close time changed or our position is stale - ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); + ourPosition = mAcquired[mOurPosition->getCurrentHash()]->snapShot(true); + assert(ourPosition); changes = true; } if (changes) { uint256 newHash = ourPosition->getHash(); + Log(lsINFO) << "Position change: CTime " << closeTime << ", tx " << newHash; mOurPosition->changePosition(newHash, closeTime); if (mProposing) propose(); mapComplete(newHash, ourPosition, false); - Log(lsINFO) << "Position change: CTime " << closeTime << ", tx " << newHash; } } @@ -695,8 +699,8 @@ bool LedgerConsensus::haveConsensus() SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool doAcquire) { - boost::unordered_map::iterator it = mComplete.find(hash); - if (it == mComplete.end()) + boost::unordered_map::iterator it = mAcquired.find(hash); + if (it == mAcquired.end()) { // we have not completed acquiring this ledger if (mState == lcsPRE_CLOSE) @@ -780,10 +784,11 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec bool ourPosition = false; if (mOurPosition) { - boost::unordered_map::iterator mit = mComplete.find(mOurPosition->getCurrentHash()); - if (mit != mComplete.end()) + boost::unordered_map::iterator mit = mAcquired.find(mOurPosition->getCurrentHash()); + if (mit != mAcquired.end()) ourPosition = mit->second->hasItem(txID); - else assert(false); // We don't have our own position? + else + assert(false); // We don't have our own position? } LCTransaction::pointer txn = boost::make_shared(txID, tx, ourPosition); @@ -792,8 +797,8 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec BOOST_FOREACH(u160_prop_pair& pit, mPeerPositions) { boost::unordered_map::const_iterator cit = - mComplete.find(pit.second->getCurrentHash()); - if (cit != mComplete.end() && cit->second) + mAcquired.find(pit.second->getCurrentHash()); + if (cit != mAcquired.end() && cit->second) txn->setVote(pit.first, cit->second->hasItem(txID)); } } @@ -873,7 +878,7 @@ bool LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash, void LedgerConsensus::beginAccept() { - SHAMap::pointer consensusSet = mComplete[mOurPosition->getCurrentHash()]; + SHAMap::pointer consensusSet = mAcquired[mOurPosition->getCurrentHash()]; if (!consensusSet) { Log(lsFATAL) << "We don't have a consensus set"; @@ -1070,7 +1075,7 @@ void LedgerConsensus::accept(SHAMap::ref set) TransactionEngine engine(newOL); BOOST_FOREACH(u256_lct_pair& it, mDisputes) { - if (!it.second->getOurPosition()) + if (!it.second->getOurVote()) { // we voted NO try { diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index fcec2205a5..a24a57565a 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -49,24 +49,24 @@ class LCTransaction protected: uint256 mTransactionID; int mYays, mNays; - bool mOurPosition; + bool mOurVote; Serializer transaction; boost::unordered_map mVotes; public: typedef boost::shared_ptr pointer; - LCTransaction(const uint256 &txID, const std::vector& tx, bool ourPosition) : - mTransactionID(txID), mYays(0), mNays(0), mOurPosition(ourPosition), transaction(tx) { ; } + LCTransaction(const uint256 &txID, const std::vector& tx, bool ourVote) : + mTransactionID(txID), mYays(0), mNays(0), mOurVote(ourVote), transaction(tx) { ; } const uint256& getTransactionID() const { return mTransactionID; } - bool getOurPosition() const { return mOurPosition; } + bool getOurVote() const { return mOurVote; } Serializer& peekTransaction() { return transaction; } void setVote(const uint160& peer, bool votesYes); void unVote(const uint160& peer); - bool updatePosition(int percentTime, bool proposing); + bool updateVote(int percentTime, bool proposing); }; enum LCState @@ -100,7 +100,7 @@ protected: boost::unordered_map mPeerPositions; // Transaction Sets, indexed by hash of transaction tree - boost::unordered_map mComplete; + boost::unordered_map mAcquired; boost::unordered_map mAcquiring; // Peer sets From b35f87564a737e20cb68e6c8b289022a6e6bf24c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 19:32:44 -0700 Subject: [PATCH 268/426] Fix a bug triggered by a acquiring a transaction set after having bowed out of the consensus process. --- src/LedgerConsensus.cpp | 12 +++++++----- src/LedgerProposal.cpp | 7 +++++-- src/LedgerProposal.h | 3 ++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index f7fa15de13..71dca921ca 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -411,7 +411,7 @@ void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::ref map, bool acq if (mAcquired.find(hash) != mAcquired.end()) return; // we already have this map - if (mOurPosition && (hash != mOurPosition->getCurrentHash())) + if (mOurPosition && (!mOurPosition->isBowOut()) && (hash != mOurPosition->getCurrentHash())) { // this could create disputed transactions boost::unordered_map::iterator it2 = mAcquired.find(mOurPosition->getCurrentHash()); if (it2 != mAcquired.end()) @@ -674,10 +674,12 @@ void LedgerConsensus::updateOurPositions() { uint256 newHash = ourPosition->getHash(); Log(lsINFO) << "Position change: CTime " << closeTime << ", tx " << newHash; - mOurPosition->changePosition(newHash, closeTime); - if (mProposing) - propose(); - mapComplete(newHash, ourPosition, false); + if (mOurPosition->changePosition(newHash, closeTime)) + { + if (mProposing) + propose(); + mapComplete(newHash, ourPosition, false); + } } } diff --git a/src/LedgerProposal.cpp b/src/LedgerProposal.cpp index 5840c10372..a334a612f7 100644 --- a/src/LedgerProposal.cpp +++ b/src/LedgerProposal.cpp @@ -54,17 +54,20 @@ bool LedgerProposal::checkSign(const std::string& signature, const uint256& sign return mPublicKey.verifyNodePublic(signingHash, signature); } -void LedgerProposal::changePosition(const uint256& newPosition, uint32 closeTime) +bool LedgerProposal::changePosition(const uint256& newPosition, uint32 closeTime) { + if (mProposeSeq == seqLeave) + return false; + mCurrentHash = newPosition; mCloseTime = closeTime; mTime = boost::posix_time::second_clock::universal_time(); ++mProposeSeq; + return true; } void LedgerProposal::bowOut() { - mCurrentHash = uint256(); mTime = boost::posix_time::second_clock::universal_time(); mProposeSeq = seqLeave; } diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index adaa557719..fb7df34309 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -59,11 +59,12 @@ public: void setSignature(const std::string& signature) { mSignature = signature; } bool hasSignature() { return !mSignature.empty(); } bool isPrevLedger(const uint256& pl) { return mPreviousLedger == pl; } + bool isBowOut() { return mProposeSeq == seqLeave; } const boost::posix_time::ptime getCreateTime() { return mTime; } bool isStale(boost::posix_time::ptime cutoff) { return mTime <= cutoff; } - void changePosition(const uint256& newPosition, uint32 newCloseTime); + bool changePosition(const uint256& newPosition, uint32 newCloseTime); void bowOut(); Json::Value getJson() const; }; From 0efe8b48929769038d0b1f9141fad2536ff543cf Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 20:41:25 -0700 Subject: [PATCH 269/426] Cleanups. --- src/LedgerAcquire.cpp | 5 ++--- src/LedgerAcquire.h | 1 + src/LedgerConsensus.cpp | 8 +++++--- src/LedgerConsensus.h | 4 ++-- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 353b7d8872..45c5ff6d4f 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -84,9 +84,8 @@ void PeerSet::TimerEntry(boost::weak_ptr wptr, const boost::system::err if (result == boost::asio::error::operation_aborted) return; boost::shared_ptr ptr = wptr.lock(); - if (!ptr) - return; - ptr->invokeOnTimer(); + if (ptr) + ptr->invokeOnTimer(); } LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE_TIMEOUT), diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index 6781eddf88..b589618299 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -78,6 +78,7 @@ protected: public: LedgerAcquire(const uint256& hash); + virtual ~LedgerAcquire() { ; } bool isBase() const { return mHaveBase; } bool isAcctStComplete() const { return mHaveState; } diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 71dca921ca..70895ff4f0 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -32,7 +32,7 @@ void TransactionAcquire::done() { if (mFailed) { - Log(lsWARNING) << "Failed to acqiure TXs " << mHash; + Log(lsWARNING) << "Failed to acquire TXs " << mHash; theApp->getOPs().mapComplete(mHash, SHAMap::pointer()); } else @@ -108,7 +108,8 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, } if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE)) return false; - else mHaveRoot = true; + else + mHaveRoot = true; } else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait, &sf)) return false; @@ -874,7 +875,8 @@ bool LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { boost::unordered_map::iterator acq = mAcquiring.find(setHash); - if (acq == mAcquiring.end()) return false; + if (acq == mAcquiring.end()) + return false; return acq->second->takeNodes(nodeIDs, nodeData, peer); } diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index a24a57565a..3833c300b3 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -37,11 +37,11 @@ protected: public: TransactionAcquire(const uint256& hash); + virtual ~TransactionAcquire() { ; } SHAMap::pointer getMap() { return mMap; } - bool takeNodes(const std::list& IDs, const std::list< std::vector >& data, - Peer::ref); + bool takeNodes(const std::list& IDs, const std::list< std::vector >& data, Peer::ref); }; class LCTransaction From bbddef85726fb49fd5ee2cda4d85c3bd62376294 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 20:49:36 -0700 Subject: [PATCH 270/426] Throw on missing node in SHAMapDiff code. --- src/SHAMapDiff.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/SHAMapDiff.cpp b/src/SHAMapDiff.cpp index 9c147ac80e..0eecbb95ec 100644 --- a/src/SHAMapDiff.cpp +++ b/src/SHAMapDiff.cpp @@ -112,6 +112,11 @@ bool SHAMap::compare(SHAMap::ref otherMap, SHAMapDiff& differences, int maxCount SHAMapTreeNode* ourNode = getNodePointer(dNode.mNodeID, dNode.mOurHash); SHAMapTreeNode* otherNode = otherMap->getNodePointer(dNode.mNodeID, dNode.mOtherHash); + if (!ourNode || !otherNode) + { + assert(false); + throw SHAMapMissingNode(dNode.mNodeID, uint256()); + } if (ourNode->isLeaf() && otherNode->isLeaf()) { // two leaves From f7e68cfc51abb694e1180ed06c5c79df41057038 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 13 Sep 2012 20:49:48 -0700 Subject: [PATCH 271/426] Fix SHAMap state when tx sync completes. --- src/LedgerConsensus.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 70895ff4f0..d507d9fee6 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -36,7 +36,10 @@ void TransactionAcquire::done() theApp->getOPs().mapComplete(mHash, SHAMap::pointer()); } else + { + mMap->setImmutable(); theApp->getOPs().mapComplete(mHash, mMap); + } } boost::weak_ptr TransactionAcquire::pmDowncast() From 205f5e4a632cb29d6d4a84f6c2dafa56f157717c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 14 Sep 2012 07:07:44 -0700 Subject: [PATCH 272/426] Call to get the auxiliary I/O service --- src/Application.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Application.h b/src/Application.h index 79ffb8cf34..6511d0f566 100644 --- a/src/Application.h +++ b/src/Application.h @@ -78,6 +78,7 @@ public: NetworkOPs& getOPs() { return mNetOps; } boost::asio::io_service& getIOService() { return mIOService; } + boost::asio::io_service& getAuxService() { return mAuxService; } LedgerMaster& getMasterLedger() { return mMasterLedger; } LedgerAcquireMaster& getMasterLedgerAcquire() { return mMasterLedgerAcquire; } From a4f41edf7a579694e7b0d60a5c5ffbd548f7d299 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 14 Sep 2012 07:08:01 -0700 Subject: [PATCH 273/426] Cleanup shared polymorphic downcast. --- src/LedgerAcquire.cpp | 2 +- src/LedgerConsensus.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 45c5ff6d4f..bbfd67063b 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -108,7 +108,7 @@ void LedgerAcquire::onTimer() boost::weak_ptr LedgerAcquire::pmDowncast() { - return boost::shared_polymorphic_downcast(shared_from_this()); + return boost::shared_polymorphic_downcast(shared_from_this()); } void LedgerAcquire::done() diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index d507d9fee6..f223f7742b 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -44,7 +44,7 @@ void TransactionAcquire::done() boost::weak_ptr TransactionAcquire::pmDowncast() { - return boost::shared_polymorphic_downcast(shared_from_this()); + return boost::shared_polymorphic_downcast(shared_from_this()); } void TransactionAcquire::trigger(Peer::ref peer, bool timer) From 72f94171490eb45d98066feb40d315ac2065085a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 14 Sep 2012 07:08:16 -0700 Subject: [PATCH 274/426] Add an assert. --- src/SHAMapDiff.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/SHAMapDiff.cpp b/src/SHAMapDiff.cpp index 0eecbb95ec..3f5adb3e0d 100644 --- a/src/SHAMapDiff.cpp +++ b/src/SHAMapDiff.cpp @@ -97,6 +97,8 @@ bool SHAMap::compare(SHAMap::ref otherMap, SHAMapDiff& differences, int maxCount // throws on corrupt tables or missing nodes // CAUTION: otherMap is not locked and must be immutable + assert(isValid() && otherMap && otherMap->isValid()); + std::stack nodeStack; // track nodes we've pushed boost::recursive_mutex::scoped_lock sl(mLock); From 72b2478a7b5dea5fbf40d512b86e322dfca90366 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 14 Sep 2012 07:08:27 -0700 Subject: [PATCH 275/426] Rename SHAMap states. --- src/SHAMap.cpp | 14 +++++++------- src/SHAMap.h | 30 ++++++++++++++++++------------ 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 4525769dba..652326f177 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -39,14 +39,14 @@ std::size_t hash_value(const uint160& u) } -SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(Modifying) +SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(smsModifying) { root = boost::make_shared(mSeq, SHAMapNode(0, uint256())); root->makeInner(); mTNByID[*root] = root; } -SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(Synching) +SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(smsSynching) { // FIXME: Need to acquire root node root = boost::make_shared(mSeq, SHAMapNode(0, uint256())); root->makeInner(); @@ -62,7 +62,7 @@ SHAMap::pointer SHAMap::snapShot(bool isMutable) newMap.mTNByID = mTNByID; newMap.root = root; if (!isMutable) - newMap.mState = Immutable; + newMap.mState = smsImmutable; return ret; } @@ -105,7 +105,7 @@ void SHAMap::dirtyUp(std::stack& stack, const uint256& { // walk the tree up from through the inner nodes to the root // update linking hashes and add nodes to dirty list - assert((mState != Synching) && (mState != Immutable)); + assert((mState != smsSynching) && (mState != smsImmutable)); while (!stack.empty()) { @@ -475,7 +475,7 @@ bool SHAMap::hasItem(const uint256& id) bool SHAMap::delItem(const uint256& id) { // delete the item with this ID boost::recursive_mutex::scoped_lock sl(mLock); - assert(mState != Immutable); + assert(mState != smsImmutable); std::stack stack = getStack(id, true, false); if (stack.empty()) @@ -552,7 +552,7 @@ bool SHAMap::addGiveItem(const SHAMapItem::pointer& item, bool isTransaction, bo (hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD : SHAMapTreeNode::tnTRANSACTION_NM); boost::recursive_mutex::scoped_lock sl(mLock); - assert(mState != Immutable); + assert(mState != smsImmutable); std::stack stack = getStack(tag, true, false); if (stack.empty()) @@ -644,7 +644,7 @@ bool SHAMap::updateGiveItem(const SHAMapItem::pointer& item, bool isTransaction, uint256 tag = item->getTag(); boost::recursive_mutex::scoped_lock sl(mLock); - assert(mState != Immutable); + assert(mState != smsImmutable); std::stack stack = getStack(tag, true, false); if (stack.empty()) throw std::runtime_error("missing node"); diff --git a/src/SHAMap.h b/src/SHAMap.h index 08712611f7..e308cc800e 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -217,11 +217,11 @@ public: enum SHAMapState { - Modifying = 0, // Objects can be added and removed (like an open ledger) - Immutable = 1, // Map cannot be changed (like a closed ledger) - Synching = 2, // Map's hash is locked in, valid nodes can be added (like a peer's closing ledger) - Floating = 3, // Map is free to change hash (like a synching open ledger) - Invalid = 4, // Map is known not to be valid (usually synching a corrupt ledger) + smsModifying = 0, // Objects can be added and removed (like an open ledger) + smsImmutable = 1, // Map cannot be changed (like a closed ledger) + smsSynching = 2, // Map's hash is locked in, valid nodes can be added (like a peer's closing ledger) + smsFloating = 3, // Map is free to change hash (like a synching open ledger) + smsInvalid = 4, // Map is known not to be valid (usually synching a corrupt ledger) }; class SHAMapSyncFilter @@ -229,9 +229,11 @@ class SHAMapSyncFilter public: SHAMapSyncFilter() { ; } virtual ~SHAMapSyncFilter() { ; } + virtual void gotNode(const SHAMapNode& id, const uint256& nodeHash, const std::vector& nodeData, bool isLeaf) { ; } + virtual bool haveNode(const SHAMapNode& id, const uint256& nodeHash, std::vector& nodeData) { return false; } }; @@ -248,6 +250,7 @@ public: { ; } virtual ~SHAMapMissingNode() throw() { ; } + const SHAMapNode& getNodeID() const { return mNodeID; } const uint256& getNodeHash() const { return mNodeHash; } }; @@ -257,6 +260,7 @@ class SHAMap public: typedef boost::shared_ptr pointer; typedef const boost::shared_ptr& ref; + typedef std::map > SHAMapDiff; private: @@ -297,6 +301,8 @@ public: SHAMap(uint32 seq = 0); SHAMap(const uint256& hash); + ~SHAMap() { mState = smsInvalid; } + // Returns a new map that's a snapshot of this one. Force CoW SHAMap::pointer snapShot(bool isMutable); @@ -342,13 +348,13 @@ public: SHAMapSyncFilter* filter); // status functions - void setImmutable(void) { assert(mState != Invalid); mState = Immutable; } - void clearImmutable(void) { mState = Modifying; } - bool isSynching(void) const { return (mState == Floating) || (mState == Synching); } - void setSynching(void) { mState = Synching; } - void setFloating(void) { mState = Floating; } - void clearSynching(void) { mState = Modifying; } - bool isValid(void) { return mState != Invalid; } + void setImmutable(void) { assert(mState != smsInvalid); mState = smsImmutable; } + void clearImmutable(void) { mState = smsModifying; } + bool isSynching(void) const { return (mState == smsFloating) || (mState == smsSynching); } + void setSynching(void) { mState = smsSynching; } + void setFloating(void) { mState = smsFloating; } + void clearSynching(void) { mState = smsModifying; } + bool isValid(void) { return mState != smsInvalid; } // caution: otherMap must be accessed only by this function // return value: true=successfully completed, false=too different From c9a44e4a1af8b03ab6a74904a21440dba0e0eb76 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 14 Sep 2012 08:40:55 -0700 Subject: [PATCH 276/426] We have to make sure someone holds a strong pointer to the acquiring set when we move it from acquring to acquired. --- src/LedgerConsensus.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index f223f7742b..652b70265d 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -880,7 +880,8 @@ bool LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash, boost::unordered_map::iterator acq = mAcquiring.find(setHash); if (acq == mAcquiring.end()) return false; - return acq->second->takeNodes(nodeIDs, nodeData, peer); + TransactionAcquire::pointer set = acq->second; // We must keep the set around during the function + return set->takeNodes(nodeIDs, nodeData, peer); } void LedgerConsensus::beginAccept() From faece188f4d37aa51f4658ff251f4b3ff880a29f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 14 Sep 2012 08:41:59 -0700 Subject: [PATCH 277/426] Belt and suspenders. Fix on both sides. --- src/LedgerConsensus.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 652b70265d..066c22e6e6 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -402,11 +402,11 @@ void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::ref map, bool acq { if (acquired) Log(lsINFO) << "We have acquired TXS " << hash; - mAcquiring.erase(hash); if (!map) { // this is an invalid/corrupt map mAcquired[hash] = map; + mAcquiring.erase(hash); Log(lsWARNING) << "A trusted node directed us to acquire an invalid TXN map"; return; } @@ -427,6 +427,7 @@ void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::ref map, bool acq assert(false); // We don't have our own position?! } mAcquired[hash] = map; + mAcquiring.erase(hash); // Adjust tracking for each peer that takes this position std::vector peers; From 3a786b911c17d50bd5cf93870ae40d58fb4c8382 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 14 Sep 2012 08:42:21 -0700 Subject: [PATCH 278/426] Don't crash if we can't find the ledger for the generator --- src/NetworkOPs.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 159a7a2d69..0433892263 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -211,7 +211,11 @@ SLE::pointer NetworkOPs::getGenerator(const uint256& uLedger, const uint160& uGe { LedgerStateParms qry = lepNONE; - return mLedgerMaster->getLedgerByHash(uLedger)->getGenerator(qry, uGeneratorID); + Ledger::pointer ledger = mLedgerMaster->getLedgerByHash(uLedger); + if (!ledger) + return SLE::pointer(); + else + return ledger->getGenerator(qry, uGeneratorID); } // From b69a0b14bf507ef7079adfb4ec22a10e2d71bf4f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 14 Sep 2012 08:42:39 -0700 Subject: [PATCH 279/426] Style change. --- src/SHAMap.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/SHAMap.h b/src/SHAMap.h index e308cc800e..e7f5046d5c 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -348,13 +348,13 @@ public: SHAMapSyncFilter* filter); // status functions - void setImmutable(void) { assert(mState != smsInvalid); mState = smsImmutable; } - void clearImmutable(void) { mState = smsModifying; } - bool isSynching(void) const { return (mState == smsFloating) || (mState == smsSynching); } - void setSynching(void) { mState = smsSynching; } - void setFloating(void) { mState = smsFloating; } - void clearSynching(void) { mState = smsModifying; } - bool isValid(void) { return mState != smsInvalid; } + void setImmutable() { assert(mState != smsInvalid); mState = smsImmutable; } + void clearImmutable() { mState = smsModifying; } + bool isSynching() const { return (mState == smsFloating) || (mState == smsSynching); } + void setSynching() { mState = smsSynching; } + void setFloating() { mState = smsFloating; } + void clearSynching() { mState = smsModifying; } + bool isValid() { return mState != smsInvalid; } // caution: otherMap must be accessed only by this function // return value: true=successfully completed, false=too different From 22f9a1a2582e4f7f2945f62abd916ecb9be2ae78 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 14 Sep 2012 09:58:51 -0700 Subject: [PATCH 280/426] Don't let bow outs count as agreeing/disagreeing for consensus determination --- src/LedgerConsensus.cpp | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 066c22e6e6..9cfa4fd23a 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -185,18 +185,22 @@ bool LCTransaction::updateVote(int percentTime, bool proposing) return false; bool newPosition; + int weight; if (proposing) // give ourselves full weight { // This is basically the percentage of nodes voting 'yes' (including us) - int weight = (mYays * 100 + (mOurVote ? 100 : 0)) / (mNays + mYays + 1); + weight = (mYays * 100 + (mOurVote ? 100 : 0)) / (mNays + mYays + 1); // To prevent avalanche stalls, we increase the needed weight slightly over time if (percentTime < AV_MID_CONSENSUS_TIME) newPosition = weight > AV_INIT_CONSENSUS_PCT; else if (percentTime < AV_LATE_CONSENSUS_TIME) newPosition = weight > AV_MID_CONSENSUS_PCT; else newPosition = weight > AV_LATE_CONSENSUS_PCT; } - else // don't let us outweight a proposing node, just recognize consensus + else // don't let us outweigh a proposing node, just recognize consensus + { + weight = -1; newPosition = mYays > mNays; + } if (newPosition == mOurVote) { @@ -689,17 +693,26 @@ void LedgerConsensus::updateOurPositions() } bool LedgerConsensus::haveConsensus() -{ +{ // FIXME: Should check for a supermajority on each disputed transaction + // counting unacquired TX sets as disagreeing int agree = 0, disagree = 0; uint256 ourPosition = mOurPosition->getCurrentHash(); BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) { - if (it.second->getCurrentHash() == ourPosition) - ++agree; - else - ++disagree; + if (!it.second->isBowOut()) + { + if (it.second->getCurrentHash() == ourPosition) + ++agree; + else + ++disagree; + } } int currentValidations = theApp->getValidations().getNodesAfter(mPrevLedgerHash); + +#ifdef LC_DEBUG + Log(lsINFO) << "Checking for TX consensus: agree=" << agree << ", disagree=" << disagree; +#endif + return ContinuousLedgerTiming::haveConsensus(mPreviousProposers, agree + disagree, agree, currentValidations, mPreviousMSeconds, mCurrentMSeconds); } From d147b61530a6019ad7cb7adb751b330d2a9a857e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 14 Sep 2012 10:06:23 -0700 Subject: [PATCH 281/426] The ledger accept process calls functions like ConnectionPool::relayMessage and so must be called in the main I/O thread, at least for now. --- src/LedgerConsensus.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 9cfa4fd23a..aff9f7bdaf 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -909,8 +909,7 @@ void LedgerConsensus::beginAccept() } theApp->getOPs().newLCL(mPeerPositions.size(), mCurrentMSeconds, mNewLedgerHash); - boost::thread thread(boost::bind(&LedgerConsensus::Saccept, shared_from_this(), consensusSet)); - thread.detach(); + theApp->getIOService().post(boost::bind(&LedgerConsensus::Saccept, shared_from_this(), consensusSet)); } void LedgerConsensus::Saccept(boost::shared_ptr This, SHAMap::pointer txSet) From b8f2b6c0dcafcbe342e8d16b945576bf786b8acc Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 15 Sep 2012 14:37:21 -0700 Subject: [PATCH 282/426] Initial check in of testing scripts. --- .gitignore | 3 +- test/buster.js | 9 +++ test/server.js | 35 +++++++++++ test/standalone-test.js | 17 ++++++ test/utils.js | 129 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 test/buster.js create mode 100644 test/server.js create mode 100644 test/standalone-test.js create mode 100644 test/utils.js diff --git a/.gitignore b/.gitignore index 2530f7eb82..ec0acfa4ff 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ *.o obj/* bin/newcoind - newcoind +# Ignore locally installed node_modules +node_modules diff --git a/test/buster.js b/test/buster.js new file mode 100644 index 0000000000..5dd49ec7cc --- /dev/null +++ b/test/buster.js @@ -0,0 +1,9 @@ +var config = module.exports; + +config["Newcoin tests"] = { + rootPath: "../", + environment: "node", + tests: [ + "test/*-test.js" + ] +} diff --git a/test/server.js b/test/server.js new file mode 100644 index 0000000000..c0e735b8af --- /dev/null +++ b/test/server.js @@ -0,0 +1,35 @@ +// Manage test servers + +// Provide servers +// +// Servers are created in tmp/server/$server +// + +console.log("server.js>"); + +var utils = require("./utils.js"); + +// var child = require("child"); + +var serverPath = function(name) { + return "tmp/server/" + name; +}; + +var makeBase = function(name, done) { + var path = serverPath(name); + + console.log("start> %s: %s", name, path); + + // Remove the existing dir. + utils.resetPath(path, parseInt('0777', 8), done); + + console.log("start< %s", name); +}; + +var start = function(name, done) { + makeBase(name, done); +}; + +exports.start = start; + +console.log("server.js<"); diff --git a/test/standalone-test.js b/test/standalone-test.js new file mode 100644 index 0000000000..3f6c1c8d58 --- /dev/null +++ b/test/standalone-test.js @@ -0,0 +1,17 @@ +// console.log("standalone-test.js>"); + +var fs = require("fs"); +var buster = require("buster"); + +var server = require("./server.js"); + +buster.testCase("Check standalone server startup", { + "Start": function (done) { + server.start("alpha", function(e) { + buster.refute(e); + done(); + }); + } +}); + +// console.log("standalone-test.js<"); diff --git a/test/utils.js b/test/utils.js new file mode 100644 index 0000000000..c755f02b38 --- /dev/null +++ b/test/utils.js @@ -0,0 +1,129 @@ + +var fs = require("fs"); +var path = require("path"); + +var filterErr = function(code, done) { + return function (e) { + done(e.code !== code ? e : undefined); + } +}; + +var throwErr = function(done) { + return function (e) { + if (e) + throw e; + + done(); + }; +}; + +// apply function to elements of array. Return first true value to done or undefined. +var mapOr = function(func, array, done) { + if (array.length) { + func(array[array.length-1], function (v) { + if (v) { + done(v); + } + else { + array.length -= 1; + mapOr(func, array, done); + } + }); + } + else { + done(); + } +}; + +// Make a directory and sub-directories. +var mkPath = function(dirPath, mode, done) { + fs.mkdir(dirPath, mode, function (e) { + if (e && e.code === "EEXIST") { + // Already exists, done. + done(); + } + else if (e.code === "ENOENT") { + // Missing sub dir. + + mkPath(path.dirname(dirPath), mode, function(e) { + if (e) { + throw e; + } + else { + mkPath(dirPath, mode, done); + } + }); + } + else { + throw e; + } + }); +}; + +// Empty a directory. +var emptyPath = function(dirPath, done) { + fs.readdir(dirPath, function (err, files) { + if (err) { + done(err); + } + else { + mapOr(rmPath, files.map(function(f) { return path.join(dirPath, f); }), done); + } + }); +}; + +// Remove path recursively. +var rmPath = function(dirPath, done) { +// console.log("rmPath: %s", dirPath); + + fs.lstat(dirPath, function (err, stats) { + if (err && err.code == "ENOENT") { + done(); + } + if (err) { + done(err); + } + else if (stats.isDirectory()) { + emptyPath(dirPath, function (e) { + if (e) { + done(e); + } + else { +// console.log("rmdir: %s", dirPath); done(); + fs.rmdir(dirPath, done); + } + }); + } + else { +// console.log("unlink: %s", dirPath); done(); + fs.unlink(dirPath, done); + } + }); +}; + +// Create directory if needed and empty if needed. +var resetPath = function(dirPath, mode, done) { + mkPath(dirPath, mode, function (e) { + if (e) { + done(e); + } + else { + emptyPath(dirPath, done); + } + }); +}; + +var trace = function(comment, func) { + return function() { + console.log("%s: %s", trace, arguments.toString); + func(arguments); + }; +}; + +exports.emptyPath = emptyPath; +exports.mapOr = mapOr; +exports.mkPath = mkPath; +exports.resetPath = resetPath; +exports.rmPath = rmPath; +exports.trace = trace; + From f45886cc6de27f1d3ab409eac2ccc310ef57d03c Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 15 Sep 2012 14:56:15 -0700 Subject: [PATCH 283/426] Cosmetic (tabbing). --- test/server.js | 1 + test/standalone-test.js | 11 ++-- test/utils.js | 123 ++++++++++++++++++++-------------------- 3 files changed, 69 insertions(+), 66 deletions(-) diff --git a/test/server.js b/test/server.js index c0e735b8af..3c7b54d398 100644 --- a/test/server.js +++ b/test/server.js @@ -33,3 +33,4 @@ var start = function(name, done) { exports.start = start; console.log("server.js<"); +// vim:ts=4 diff --git a/test/standalone-test.js b/test/standalone-test.js index 3f6c1c8d58..81221d7d19 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -7,11 +7,12 @@ var server = require("./server.js"); buster.testCase("Check standalone server startup", { "Start": function (done) { - server.start("alpha", function(e) { - buster.refute(e); - done(); - }); - } + server.start("alpha", function(e) { + buster.refute(e); + done(); + }); + } }); // console.log("standalone-test.js<"); +// vim:ts=4 diff --git a/test/utils.js b/test/utils.js index c755f02b38..c840431213 100644 --- a/test/utils.js +++ b/test/utils.js @@ -4,34 +4,34 @@ var path = require("path"); var filterErr = function(code, done) { return function (e) { - done(e.code !== code ? e : undefined); - } + done(e.code !== code ? e : undefined); + }; }; var throwErr = function(done) { return function (e) { - if (e) - throw e; - - done(); - }; + if (e) + throw e; + + done(); + }; }; // apply function to elements of array. Return first true value to done or undefined. var mapOr = function(func, array, done) { if (array.length) { - func(array[array.length-1], function (v) { - if (v) { - done(v); - } - else { - array.length -= 1; - mapOr(func, array, done); - } - }); + func(array[array.length-1], function (v) { + if (v) { + done(v); + } + else { + array.length -= 1; + mapOr(func, array, done); + } + }); } else { - done(); + done(); } }; @@ -39,23 +39,23 @@ var mapOr = function(func, array, done) { var mkPath = function(dirPath, mode, done) { fs.mkdir(dirPath, mode, function (e) { if (e && e.code === "EEXIST") { - // Already exists, done. - done(); + // Already exists, done. + done(); } else if (e.code === "ENOENT") { - // Missing sub dir. + // Missing sub dir. - mkPath(path.dirname(dirPath), mode, function(e) { - if (e) { - throw e; - } - else { - mkPath(dirPath, mode, done); - } - }); + mkPath(path.dirname(dirPath), mode, function(e) { + if (e) { + throw e; + } + else { + mkPath(dirPath, mode, done); + } + }); } else { - throw e; + throw e; } }); }; @@ -74,50 +74,50 @@ var emptyPath = function(dirPath, done) { // Remove path recursively. var rmPath = function(dirPath, done) { -// console.log("rmPath: %s", dirPath); + console.log("rmPath: %s", dirPath); fs.lstat(dirPath, function (err, stats) { - if (err && err.code == "ENOENT") { - done(); - } - if (err) { - done(err); - } - else if (stats.isDirectory()) { - emptyPath(dirPath, function (e) { - if (e) { - done(e); - } - else { -// console.log("rmdir: %s", dirPath); done(); - fs.rmdir(dirPath, done); - } + if (err && err.code == "ENOENT") { + done(); + } + if (err) { + done(err); + } + else if (stats.isDirectory()) { + emptyPath(dirPath, function (e) { + if (e) { + done(e); + } + else { +// console.log("rmdir: %s", dirPath); done(); + fs.rmdir(dirPath, done); + } + }); + } + else { +// console.log("unlink: %s", dirPath); done(); + fs.unlink(dirPath, done); + } }); - } - else { -// console.log("unlink: %s", dirPath); done(); - fs.unlink(dirPath, done); - } - }); }; // Create directory if needed and empty if needed. var resetPath = function(dirPath, mode, done) { mkPath(dirPath, mode, function (e) { - if (e) { - done(e); - } - else { - emptyPath(dirPath, done); - } - }); + if (e) { + done(e); + } + else { + emptyPath(dirPath, done); + } + }); }; var trace = function(comment, func) { return function() { - console.log("%s: %s", trace, arguments.toString); - func(arguments); - }; + console.log("%s: %s", trace, arguments.toString); + func(arguments); + }; }; exports.emptyPath = emptyPath; @@ -127,3 +127,4 @@ exports.resetPath = resetPath; exports.rmPath = rmPath; exports.trace = trace; +// vim:ts=4 From 6865e575cb46d57798c45238057170029e50df84 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 15 Sep 2012 15:45:33 -0700 Subject: [PATCH 284/426] Build testing newcoind.cfg as needed. --- .gitignore | 3 +++ test/server.js | 28 ++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index ec0acfa4ff..92eb7bb785 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ newcoind # Ignore locally installed node_modules node_modules + +# Ignore tmp directory. +tmp diff --git a/test/server.js b/test/server.js index 3c7b54d398..404df4060c 100644 --- a/test/server.js +++ b/test/server.js @@ -7,21 +7,45 @@ console.log("server.js>"); +var config = require("./config.js"); var utils = require("./utils.js"); +var fs = require("fs"); +var path = require("path"); +var util = require("util"); // var child = require("child"); var serverPath = function(name) { return "tmp/server/" + name; }; +// Return a server's newcoind.cfg as string. +var serverConfig = function(name) { + var cfg = config.servers[name]; + + return Object.keys(cfg).map(function (o) { + return util.format("[%s]\n%s\n", o, cfg[o]); + }).join(""); +}; + +var writeConfig = function(name, done) { + fs.writeFile(path.join(serverPath(name), "newcoind.cfg"), serverConfig(name), 'utf8', done); +}; + var makeBase = function(name, done) { var path = serverPath(name); console.log("start> %s: %s", name, path); - // Remove the existing dir. - utils.resetPath(path, parseInt('0777', 8), done); + // Reset the server directory, build it if needed. + utils.resetPath(path, parseInt('0777', 8), function (e) { + if (e) { + throw e; + } + else { + writeConfig(name, done); + } + }); console.log("start< %s", name); }; From 7744f7c11111956860ddc331d952c93134dbd338 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 16 Sep 2012 20:58:38 -0700 Subject: [PATCH 285/426] Cleanups and improved comments. Fix a race condition if a peer ledger comes in before we take our initial position. --- src/LedgerConsensus.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index aff9f7bdaf..48b26bdc12 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -359,6 +359,13 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) uint256 txSet = initialSet->getHash(); Log(lsINFO) << "initial position " << txSet; + if (mValidating) + mOurPosition = boost::make_shared + (mValSeed, initialLedger.getParentHash(), txSet, mCloseTime); + else + mOurPosition = boost::make_shared(initialLedger.getParentHash(), txSet, mCloseTime); + mapComplete(txSet, initialSet, false); + // if any peers have taken a contrary position, process disputes boost::unordered_set found; BOOST_FOREACH(u160_prop_pair& it, mPeerPositions) @@ -372,12 +379,6 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) } } - if (mValidating) - mOurPosition = boost::make_shared - (mValSeed, initialLedger.getParentHash(), txSet, mCloseTime); - else - mOurPosition = boost::make_shared(initialLedger.getParentHash(), txSet, mCloseTime); - mapComplete(txSet, initialSet, false); if (mProposing) propose(); } @@ -389,16 +390,17 @@ void LedgerConsensus::createDisputes(SHAMap::ref m1, SHAMap::ref m2) for (SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos) { // create disputed transactions (from the ledger that has them) if (pos->second.first) - { + { // transaction is in first map assert(!pos->second.second); addDisputedTransaction(pos->first, pos->second.first->peekData()); } else if (pos->second.second) - { + { // transaction is in second map assert(!pos->second.first); addDisputedTransaction(pos->first, pos->second.second->peekData()); } - else assert(false); + else // No other disagreement over a transaction should be possible + assert(false); } } @@ -417,7 +419,10 @@ void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::ref map, bool acq assert(hash == map->getHash()); if (mAcquired.find(hash) != mAcquired.end()) + { + mAcquiring.erase(hash); return; // we already have this map + } if (mOurPosition && (!mOurPosition->isBowOut()) && (hash != mOurPosition->getCurrentHash())) { // this could create disputed transactions @@ -799,19 +804,20 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec { Log(lsTRACE) << "Transaction " << txID << " is disputed"; boost::unordered_map::iterator it = mDisputes.find(txID); - if (it != mDisputes.end()) return; + if (it != mDisputes.end()) + return; - bool ourPosition = false; + bool ourVote = false; if (mOurPosition) { boost::unordered_map::iterator mit = mAcquired.find(mOurPosition->getCurrentHash()); if (mit != mAcquired.end()) - ourPosition = mit->second->hasItem(txID); + ourVote = mit->second->hasItem(txID); else assert(false); // We don't have our own position? } - LCTransaction::pointer txn = boost::make_shared(txID, tx, ourPosition); + LCTransaction::pointer txn = boost::make_shared(txID, tx, ourVote); mDisputes[txID] = txn; BOOST_FOREACH(u160_prop_pair& pit, mPeerPositions) From 89518e23cc8cfd00c8fbfd140f5f4cec7d420148 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 17 Sep 2012 00:38:47 -0700 Subject: [PATCH 286/426] Fix two more race conditions involving us taking our position late. Remove an incorrect comment. --- src/LedgerConsensus.cpp | 9 +++++++-- src/LedgerConsensus.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 48b26bdc12..0745329de7 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -358,13 +358,18 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) SHAMap::pointer initialSet = initialLedger.peekTransactionMap()->snapShot(false); uint256 txSet = initialSet->getHash(); Log(lsINFO) << "initial position " << txSet; + mapComplete(txSet, initialSet, false); if (mValidating) mOurPosition = boost::make_shared (mValSeed, initialLedger.getParentHash(), txSet, mCloseTime); else mOurPosition = boost::make_shared(initialLedger.getParentHash(), txSet, mCloseTime); - mapComplete(txSet, initialSet, false); + + BOOST_FOREACH(u256_lct_pair& it, mDisputes) + { + it.second->setOurVote(initialLedger.hasTransaction(it.first)); + } // if any peers have taken a contrary position, process disputes boost::unordered_set found; @@ -372,7 +377,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) { uint256 set = it.second->getCurrentHash(); if (found.insert(set).second) - { // OPTIMIZEME: Don't process the same set more than once + { boost::unordered_map::iterator iit = mAcquired.find(set); if (iit != mAcquired.end()) createDisputes(initialSet, iit->second); diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 3833c300b3..44b4db409f 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -62,6 +62,7 @@ public: const uint256& getTransactionID() const { return mTransactionID; } bool getOurVote() const { return mOurVote; } Serializer& peekTransaction() { return transaction; } + void setOurVote(bool o) { mOurVote = o; } void setVote(const uint160& peer, bool votesYes); void unVote(const uint160& peer); From 92fbff0efc05fcf0fd466be005c188a3a22ec307 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 17 Sep 2012 00:54:48 -0700 Subject: [PATCH 287/426] If a new transaction is discovered in the consensus process and we have not relayed it recently, do so. This is not the perfect solution, it would be better to relay it when we accept the new ledger, relaying only if it fits in the consensus ledger. --- src/LedgerConsensus.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 0745329de7..2b2af08a78 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -832,6 +832,16 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec if (cit != mAcquired.end() && cit->second) txn->setVote(pit.first, cit->second->hasItem(txID)); } + + if (!ourVote && theApp->isNew(txID)) + { + newcoin::TMTransaction msg; + msg.set_rawtransaction(&(tx.front()), tx.size()); + msg.set_status(newcoin::tsNEW); + msg.set_receivetimestamp(theApp->getOPs().getNetworkTimeNC()); + PackedMessage::pointer packet = boost::make_shared(msg, newcoin::mtTRANSACTION); + theApp->getConnectionPool().relayMessage(NULL, packet); + } } bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) From 86700c30bb9fb51665ba564c36a495690897db1a Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 15 Sep 2012 15:45:33 -0700 Subject: [PATCH 288/426] Build testing newcoind.cfg as needed. --- .gitignore | 3 +++ test/config.js | 15 +++++++++++++++ test/server.js | 29 +++++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 test/config.js diff --git a/.gitignore b/.gitignore index ec0acfa4ff..92eb7bb785 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ newcoind # Ignore locally installed node_modules node_modules + +# Ignore tmp directory. +tmp diff --git a/test/config.js b/test/config.js new file mode 100644 index 0000000000..004767c158 --- /dev/null +++ b/test/config.js @@ -0,0 +1,15 @@ +// +// Configuration for unit tests +// + +exports.servers = { + alpha : { + "peer_ip" : "0.0.0.0", + "peer_port" : 51235, + "websocket_ip" : "127.0.0.1", + "websocket_port" : 5005, + "validation_seed" : "shhDFVsmS2GSu5vUyZSPXYfj1r79h", + "validators" : "n9L8LZZCwsdXzKUN9zoVxs4YznYXZ9hEhsQZY7aVpxtFaSceiyDZ beta" + } +}; +// vim:ts=4 diff --git a/test/server.js b/test/server.js index 3c7b54d398..11313b553b 100644 --- a/test/server.js +++ b/test/server.js @@ -7,21 +7,46 @@ console.log("server.js>"); +var config = require("./config.js"); var utils = require("./utils.js"); +var fs = require("fs"); +var path = require("path"); +var util = require("util"); // var child = require("child"); var serverPath = function(name) { return "tmp/server/" + name; }; +// Return a server's newcoind.cfg as string. +var serverConfig = function(name) { + var cfg = config.servers[name]; + + return Object.keys(cfg).map(function (o) { + return util.format("[%s]\n%s\n", o, cfg[o]); + }).join(""); +}; + +// Write a server's newcoind.cfg. +var writeConfig = function(name, done) { + fs.writeFile(path.join(serverPath(name), "newcoind.cfg"), serverConfig(name), 'utf8', done); +}; + var makeBase = function(name, done) { var path = serverPath(name); console.log("start> %s: %s", name, path); - // Remove the existing dir. - utils.resetPath(path, parseInt('0777', 8), done); + // Reset the server directory, build it if needed. + utils.resetPath(path, parseInt('0777', 8), function (e) { + if (e) { + throw e; + } + else { + writeConfig(name, done); + } + }); console.log("start< %s", name); }; From d0d8fb419509fc6c78b7512565e58b1cd5f3acfc Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 17 Sep 2012 12:34:35 -0700 Subject: [PATCH 289/426] Make UT mkPath take strings as mode. --- test/server.js | 2 +- test/utils.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/server.js b/test/server.js index 11313b553b..36389818b6 100644 --- a/test/server.js +++ b/test/server.js @@ -39,7 +39,7 @@ var makeBase = function(name, done) { console.log("start> %s: %s", name, path); // Reset the server directory, build it if needed. - utils.resetPath(path, parseInt('0777', 8), function (e) { + utils.resetPath(path, '0777', function (e) { if (e) { throw e; } diff --git a/test/utils.js b/test/utils.js index c840431213..1f706e7a72 100644 --- a/test/utils.js +++ b/test/utils.js @@ -37,7 +37,7 @@ var mapOr = function(func, array, done) { // Make a directory and sub-directories. var mkPath = function(dirPath, mode, done) { - fs.mkdir(dirPath, mode, function (e) { + fs.mkdir(dirPath, typeof mode === "string" ? parseInt(mode, 8) : mode, function (e) { if (e && e.code === "EEXIST") { // Already exists, done. done(); From ca14e129bbe872ba4f9a6387eb599b89298b021a Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 17 Sep 2012 12:48:30 -0700 Subject: [PATCH 290/426] Cosmetic. --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 444231ba3a..b9154261d1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -96,7 +96,7 @@ int main(int argc, char* argv[]) ("standalone,a", "Run with no peers.") ("test,t", "Perform unit tests.") ("parameters", po::value< vector >(), "Specify comma separated parameters.") - ("verbose,v", "Increase log level") + ("verbose,v", "Increase log level.") ; // Interpret positional arguments as --parameters. From 1d686a15d85b31d70c8a3e5f500db9978a0ff6ea Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 17 Sep 2012 12:57:24 -0700 Subject: [PATCH 291/426] Move --conf documentation to man page. --- newcoind.cfg | 27 ++------------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/newcoind.cfg b/newcoind.cfg index 774a32129d..ac87d7aa8d 100644 --- a/newcoind.cfg +++ b/newcoind.cfg @@ -5,31 +5,8 @@ # or Mac style end of lines. Blank lines and lines beginning with '#' are # ignored. Undefined sections are reserved. No escapes are currently defined. # -# When you launch newcoind, it will attempt to find this file. -# -# --conf=: -# You may specify the location of this file with --conf=. The config -# directory is the directory containing this file. The data directory is a -# the subdirectory named "dbs". -# -# Windows and no --conf: -# The config directory is the same directory as the newcoind program. The -# data directory is a the subdirectory named "dbs". -# -# Other OSes and no --conf: -# This file will be looked for in these places in the following order: -# ./newcoind.cfg -# $XDG_CONFIG_HOME/newcoin/newcoind.cfg -# -# If newcoind.cfg, is found in the current working directory, the directory -# will be used as the config directory. The data directory is a the -# subdirectory named "dbs". -# -# Otherwise, the data directory data is: -# $XDG_DATA_HOME/newcoin/ -# -# Note: $XDG_CONFIG_HOME defaults to $HOME/.config -# $XDG_DATA_HOME defaults to $HOME/.local/share +# When you launch newcoind, it will attempt to find this file. For details, +# refer to the manual page for --conf command line option. # # [debug_logfile] # Specifies were a debug logfile is kept. By default, no debug log is kept From 6847aaace50dff71334d5cb32021f6726110085c Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 17 Sep 2012 15:35:07 -0700 Subject: [PATCH 292/426] Have UT start and stop a server. --- test/config.js | 12 +++++-- test/server.js | 78 ++++++++++++++++++++++++++++++++++------- test/standalone-test.js | 10 ++++-- test/utils.js | 2 +- 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/test/config.js b/test/config.js index 004767c158..7cacb41a8c 100644 --- a/test/config.js +++ b/test/config.js @@ -2,12 +2,18 @@ // Configuration for unit tests // +// Where to find the binary. +exports.newcoind = "./newcoind"; + +// Configuration for servers. exports.servers = { alpha : { - "peer_ip" : "0.0.0.0", - "peer_port" : 51235, + // "peer_ip" : "0.0.0.0", + // "peer_port" : 51235, + "rpc_ip" : "0.0.0.0", + "rpc_port" : 5005, "websocket_ip" : "127.0.0.1", - "websocket_port" : 5005, + "websocket_port" : 6005, "validation_seed" : "shhDFVsmS2GSu5vUyZSPXYfj1r79h", "validators" : "n9L8LZZCwsdXzKUN9zoVxs4YznYXZ9hEhsQZY7aVpxtFaSceiyDZ beta" } diff --git a/test/server.js b/test/server.js index 36389818b6..585315546f 100644 --- a/test/server.js +++ b/test/server.js @@ -5,22 +5,22 @@ // Servers are created in tmp/server/$server // -console.log("server.js>"); - var config = require("./config.js"); var utils = require("./utils.js"); var fs = require("fs"); var path = require("path"); var util = require("util"); -// var child = require("child"); +var child = require("child_process"); + +var servers = {}; var serverPath = function(name) { return "tmp/server/" + name; }; // Return a server's newcoind.cfg as string. -var serverConfig = function(name) { +var configContent = function(name) { var cfg = config.servers[name]; return Object.keys(cfg).map(function (o) { @@ -28,16 +28,45 @@ var serverConfig = function(name) { }).join(""); }; +var configPath = function(name) { + return path.join(serverPath(name), "newcoind.cfg"); + +}; + // Write a server's newcoind.cfg. var writeConfig = function(name, done) { - fs.writeFile(path.join(serverPath(name), "newcoind.cfg"), serverConfig(name), 'utf8', done); + fs.writeFile(configPath(name), configContent(name), 'utf8', done); +}; + +var serverSpawnSync = function(name) { + // Spawn in standalone mode for now. + var server = child.spawn( + config.newcoind, + [ + "-a", + "--conf=" + configPath(name) + ], + { + env : process.env, + stdio : 'inherit' + }); + + servers[name] = server; + console.log("server: %s: %s -a --conf=%s", server.pid, config.newcoind, configPath(name)); + console.log("sever: start: servers = %s", Object.keys(servers).toString()); + + server.on('exit', function (code, signal) { + // If could not exec: code=127, signal=null + // If regular exit: code=0, signal=null + console.log("sever: spawn: server exited code=%s: signal=%s", code, signal); + delete servers[name]; + }); + }; var makeBase = function(name, done) { var path = serverPath(name); - console.log("start> %s: %s", name, path); - // Reset the server directory, build it if needed. utils.resetPath(path, '0777', function (e) { if (e) { @@ -47,15 +76,38 @@ var makeBase = function(name, done) { writeConfig(name, done); } }); - - console.log("start< %s", name); }; -var start = function(name, done) { - makeBase(name, done); +// Prepare the working directory and spawn the server. +exports.start = function(name, done) { + makeBase(name, function (e) { + if (e) { + throw e; + } + else { + serverSpawnSync(name); + done(); + } + }); }; -exports.start = start; +exports.stop = function(name, done) { + console.log("sever: stop: servers = %s", Object.keys(servers).toString()); + var server = servers[name]; + + if (server) { + server.on('exit', function (code, signal) { + console.log("sever: stop: server exited"); + delete servers[name]; + done(); + }); + server.kill(); + } + else + { + console.log("sever: stop: no such server"); + done(); + } +}; -console.log("server.js<"); // vim:ts=4 diff --git a/test/standalone-test.js b/test/standalone-test.js index 81221d7d19..a3a7a561a2 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -6,10 +6,14 @@ var buster = require("buster"); var server = require("./server.js"); buster.testCase("Check standalone server startup", { - "Start": function (done) { - server.start("alpha", function(e) { + "server start and stop": function (done) { + server.start("alpha", + function (e) { buster.refute(e); - done(); + server.stop("alpha", function (e) { + buster.refute(e); + done(); + }); }); } }); diff --git a/test/utils.js b/test/utils.js index 1f706e7a72..5596b38668 100644 --- a/test/utils.js +++ b/test/utils.js @@ -74,7 +74,7 @@ var emptyPath = function(dirPath, done) { // Remove path recursively. var rmPath = function(dirPath, done) { - console.log("rmPath: %s", dirPath); +// console.log("rmPath: %s", dirPath); fs.lstat(dirPath, function (err, stats) { if (err && err.code == "ENOENT") { From b6771dcae9c99f87f971946bc05f8997c5161ae1 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 17 Sep 2012 15:45:04 -0700 Subject: [PATCH 293/426] Fix JS mkPath. --- test/utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/utils.js b/test/utils.js index 5596b38668..0bf10b18ea 100644 --- a/test/utils.js +++ b/test/utils.js @@ -38,8 +38,8 @@ var mapOr = function(func, array, done) { // Make a directory and sub-directories. var mkPath = function(dirPath, mode, done) { fs.mkdir(dirPath, typeof mode === "string" ? parseInt(mode, 8) : mode, function (e) { - if (e && e.code === "EEXIST") { - // Already exists, done. + if (!e || e.code === "EEXIST") { + // Created or already exists, done. done(); } else if (e.code === "ENOENT") { From 333da36c19019eebe92aa368496e0bcb8c65a0f3 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 17 Sep 2012 15:45:44 -0700 Subject: [PATCH 294/426] UT: Set the cwd for the servers. --- test/config.js | 4 +++- test/server.js | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/test/config.js b/test/config.js index 7cacb41a8c..6b320f248f 100644 --- a/test/config.js +++ b/test/config.js @@ -2,8 +2,10 @@ // Configuration for unit tests // +var path = require("path"); + // Where to find the binary. -exports.newcoind = "./newcoind"; +exports.newcoind = path.join(process.cwd(), "newcoind"); // Configuration for servers. exports.servers = { diff --git a/test/server.js b/test/server.js index 585315546f..0be028cc59 100644 --- a/test/server.js +++ b/test/server.js @@ -30,7 +30,6 @@ var configContent = function(name) { var configPath = function(name) { return path.join(serverPath(name), "newcoind.cfg"); - }; // Write a server's newcoind.cfg. @@ -44,11 +43,12 @@ var serverSpawnSync = function(name) { config.newcoind, [ "-a", - "--conf=" + configPath(name) + "--conf=newcoind.cfg" ], { - env : process.env, - stdio : 'inherit' + cwd: serverPath(name), + env: process.env, + stdio: 'inherit' }); servers[name] = server; From d28bb9f771416c3f6c4507028907a937a85cfc9c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 18 Sep 2012 12:23:14 -0700 Subject: [PATCH 295/426] Ugly workaround for Boost I/O service weirdness. I/O service unconditionally terminates if it has no work to do and cannot be used to wait around for 'post' calls. --- src/Application.cpp | 11 ++++++++++- src/Application.h | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 45adfccf43..c78427d7b2 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -35,8 +35,14 @@ DatabaseCon::~DatabaseCon() delete mDatabase; } +static void resetTimer(boost::asio::deadline_timer* timer) +{ // ugly workaround for Boost IO service weirdness + timer->expires_from_now(boost::posix_time::hours(24)); + timer->async_wait(boost::bind(resetTimer, timer)); +} + Application::Application() : - mUNL(mIOService), + mIOTimer(mIOService), mAuxTimer(mAuxService), mUNL(mIOService), mNetOps(mIOService, &mMasterLedger), mTempNodeCache(16384, 90), mHashedObjectStore(16384, 300), mSNTPClient(mAuxService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), @@ -44,6 +50,9 @@ Application::Application() : { RAND_bytes(mNonce256.begin(), mNonce256.size()); RAND_bytes(reinterpret_cast(&mNonceST), sizeof(mNonceST)); + + resetTimer(&mIOTimer); + resetTimer(&mAuxTimer); } extern const char *RpcDBInit[], *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], *HashNodeDBInit[], *NetNodeDBInit[]; diff --git a/src/Application.h b/src/Application.h index 6511d0f566..78fc2e425c 100644 --- a/src/Application.h +++ b/src/Application.h @@ -39,7 +39,8 @@ public: class Application { - boost::asio::io_service mIOService, mAuxService; + boost::asio::io_service mIOService, mAuxService; + boost::asio::deadline_timer mIOTimer, mAuxTimer; Wallet mWallet; UniqueNodeList mUNL; From 77c06a1ca0864a1543b21976a9964a3c55363401 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 18 Sep 2012 12:24:09 -0700 Subject: [PATCH 296/426] Allow SNTP in standalone mode. It was partially disabled before. --- src/SNTPClient.cpp | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index bb1daa098b..cdafc0698f 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -47,16 +47,13 @@ static uint8_t SNTPQueryData[48] = SNTPClient::SNTPClient(boost::asio::io_service& service) : mSocket(service), mTimer(service), mResolver(service), mOffset(0), mLastOffsetUpdate((time_t) -1), mReceiveBuffer(256) { - if (!theConfig.RUN_STANDALONE) - { - mSocket.open(boost::asio::ip::udp::v4()); - mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint, - boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error, - boost::asio::placeholders::bytes_transferred)); + mSocket.open(boost::asio::ip::udp::v4()); + mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint, + boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); - mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY)); - mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error)); - } + mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY)); + mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error)); } void SNTPClient::resolveComplete(const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator it) From 73c5b6addbbca2faa2e1791ce1d9d3f85ec790a9 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 18 Sep 2012 13:21:07 -0700 Subject: [PATCH 297/426] There's a proper way to workaround the silliness, io_service::work --- src/Application.cpp | 13 ++----------- src/Application.h | 4 ++-- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index c78427d7b2..00aea956aa 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -35,14 +35,8 @@ DatabaseCon::~DatabaseCon() delete mDatabase; } -static void resetTimer(boost::asio::deadline_timer* timer) -{ // ugly workaround for Boost IO service weirdness - timer->expires_from_now(boost::posix_time::hours(24)); - timer->async_wait(boost::bind(resetTimer, timer)); -} - Application::Application() : - mIOTimer(mIOService), mAuxTimer(mAuxService), mUNL(mIOService), + mIOWork(mIOService), mAuxWork(mAuxService), mUNL(mIOService), mNetOps(mIOService, &mMasterLedger), mTempNodeCache(16384, 90), mHashedObjectStore(16384, 300), mSNTPClient(mAuxService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), @@ -50,9 +44,6 @@ Application::Application() : { RAND_bytes(mNonce256.begin(), mNonce256.size()); RAND_bytes(reinterpret_cast(&mNonceST), sizeof(mNonceST)); - - resetTimer(&mIOTimer); - resetTimer(&mAuxTimer); } extern const char *RpcDBInit[], *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], *HashNodeDBInit[], *NetNodeDBInit[]; @@ -60,10 +51,10 @@ extern int RpcDBCount, TxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount void Application::stop() { - mAuxService.stop(); mIOService.stop(); mHashedObjectStore.bulkWrite(); mValidations.flush(); + mAuxService.stop(); Log(lsINFO) << "Stopped: " << mIOService.stopped(); } diff --git a/src/Application.h b/src/Application.h index 78fc2e425c..8ab7f83ed2 100644 --- a/src/Application.h +++ b/src/Application.h @@ -39,8 +39,8 @@ public: class Application { - boost::asio::io_service mIOService, mAuxService; - boost::asio::deadline_timer mIOTimer, mAuxTimer; + boost::asio::io_service mIOService, mAuxService; + boost::asio::io_service::work mIOWork, mAuxWork; Wallet mWallet; UniqueNodeList mUNL; From 908d797e7ae19bdeb7bab2d3020df4ce31fe44e1 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 18 Sep 2012 15:43:58 -0700 Subject: [PATCH 298/426] UT start adding WS support. --- test/server.js | 11 ++++++++++- test/utils.js | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/test/server.js b/test/server.js index 0be028cc59..9a939f0147 100644 --- a/test/server.js +++ b/test/server.js @@ -12,6 +12,7 @@ var fs = require("fs"); var path = require("path"); var util = require("util"); var child = require("child_process"); +var WebSocket = require("ws"); var servers = {}; @@ -78,6 +79,14 @@ var makeBase = function(name, done) { }); }; +var wsOpen = function(done) { + var socket = new WebSocket(util.format("ws:://%s:%s", server.websocket_ip, server.websocket_port)); + + socket.on('open') { + done(); + }); +}; + // Prepare the working directory and spawn the server. exports.start = function(name, done) { makeBase(name, function (e) { @@ -86,7 +95,7 @@ exports.start = function(name, done) { } else { serverSpawnSync(name); - done(); + wsOpen(done); } }); }; diff --git a/test/utils.js b/test/utils.js index 0bf10b18ea..e15052294a 100644 --- a/test/utils.js +++ b/test/utils.js @@ -4,7 +4,7 @@ var path = require("path"); var filterErr = function(code, done) { return function (e) { - done(e.code !== code ? e : undefined); + done(e && e.code === code ? undefined : e); }; }; @@ -38,7 +38,7 @@ var mapOr = function(func, array, done) { // Make a directory and sub-directories. var mkPath = function(dirPath, mode, done) { fs.mkdir(dirPath, typeof mode === "string" ? parseInt(mode, 8) : mode, function (e) { - if (!e || e.code === "EEXIST") { + if (!e || e.code === "EEXIST") { // Created or already exists, done. done(); } From 958ea8a6cd5744dbf031a6ca1a4bfa81401348ee Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 18 Sep 2012 15:44:25 -0700 Subject: [PATCH 299/426] Checking sketch of JS libs. --- js/ledger.js | 34 ++++++++++++++++++++++++++++++++++ js/serializer.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ js/transaction.js | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 js/ledger.js create mode 100644 js/serializer.js create mode 100644 js/transaction.js diff --git a/js/ledger.js b/js/ledger.js new file mode 100644 index 0000000000..42c04fc156 --- /dev/null +++ b/js/ledger.js @@ -0,0 +1,34 @@ +// +// Tools for working with ledger entries. +// +// Fundamentally, we work in the more strict case of not trusting the ledger as presented. If we have a server we trust, then the +// burden of verify the ledger entries is left to the server. But, we work in the same fundamental units of information, ledger +// entries, to keep the code orthagonal. +// + +var serializer = require("./serializer"); + +exports.getLedgerEntry = function(key, done) { + var id = (ws.id += 1); + + ws.response[id] = done; + + ws.send({ + 'command': 'getLedgerEntry', + 'id': id, + 'ledger': ledger, + 'account': accountId, + 'proof': false // Eventually, we will want proof if the server is untrusted. + }); +}; + +exports.getAccountRootNode = function(ledger, accountId, done) { + var s = new Serializer(); + + s.addUInt16('a'); + s.addUInt160(accountId); + + getLedgerEntry(s.getSHA512Half(), done); +}; + +// vim:ts=4 diff --git a/js/serializer.js b/js/serializer.js new file mode 100644 index 0000000000..00f9e070b5 --- /dev/null +++ b/js/serializer.js @@ -0,0 +1,44 @@ +// + +var serializer = {}; + +serializer.addUInt16 = function(value) { + switch (typeof value) { + case 'string': + addUInt16(value.charCodeAt(0)); + break; + + case 'integer': + for (i = 16/8; i; i -=1) { + raw.push(value & 255); + value >>= 8; + } + break; + + default: + throw 'UNEXPECTED_TYPE'; + } +}; + +serializer.addUInt160 = function(value) { + switch (typeof value) { + case 'array': + raw.concat(value); + break; + + case 'integer': + for (i = 160/8; i; i -=1) { + raw.push(value & 255); + value >>= 8; + } + break; + + default: + throw 'UNEXPECTED_TYPE'; + } +}; + +serializer.getSHA512Half = function() { +}; + +// vim:ts=4 diff --git a/js/transaction.js b/js/transaction.js new file mode 100644 index 0000000000..3706a24a1c --- /dev/null +++ b/js/transaction.js @@ -0,0 +1,38 @@ +// Work with transactions. +// +// This works for both trusted and untrusted servers. +// +// For untrusted servers: +// - We never send a secret to an untrusted server. +// - Convert transactions to and from JSON. +// - Sign and verify signatures. +// - Encrypt and decrypt. +// +// For trusted servers: +// - We need a websocket way of working with transactions as JSON. +// - This allows us to not need to port the transaction tools to so many +// languages. +// + +var commands = {}; + +commands.buildSend = function(params) { + var srcAccountID = params.srcAccountID; + var fee = params.fee; + var dstAccountID = params.dstAccountID; + var amount = params.amount; + var sendMax = params.sendMax; + var partial = params.partial; + var limit = params.limit; +}; + + +exports.trustedCreate = function() { + +}; + +exports.untrustedCreate = function() { + +}; + +// vim:ts=4 From 8c354f46b784c69b3940bf74542d8793a1402fe6 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 19 Sep 2012 23:41:06 -0700 Subject: [PATCH 300/426] Fix the bug Jed reported. --- src/Ledger.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 2348ef63ec..b419a493fc 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -505,7 +505,6 @@ void Ledger::addJson(Json::Value& ret, int options) { SerializerIterator sit(item->peekSerializer()); Serializer sTxn(sit.getVL()); - Serializer sMeta(sit.getVL()); SerializerIterator tsit(sTxn); SerializedTransaction txn(tsit); From 02b3bcb089c57dbda8616028c83453490f06c718 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 20 Sep 2012 00:15:48 -0700 Subject: [PATCH 301/426] Put the threading in the correct owner node for unthreaded nodes. Add some additional debug to threading. --- src/LedgerEntrySet.cpp | 37 ++++++++++++++++++++++--------------- src/LedgerEntrySet.h | 8 +++----- src/SerializedLedger.cpp | 2 ++ src/TransactionMeta.cpp | 6 +++++- src/TransactionMeta.h | 3 ++- 5 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 4dbef407b1..5408a4dca8 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -291,7 +291,7 @@ SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::ref ledger, } -bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::ref ledger, +bool LedgerEntrySet::threadTx(const NewcoinAddress& threadTo, Ledger::ref ledger, boost::unordered_map& newMods) { Log(lsTRACE) << "Thread to " << threadTo.getAccountID(); @@ -301,32 +301,36 @@ bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddres assert(false); return false; } - return threadTx(metaNode, sle, ledger, newMods); + return threadTx(sle, ledger, newMods); } -bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, SLE::ref threadTo, Ledger::ref ledger, - boost::unordered_map& newMods) +bool LedgerEntrySet::threadTx(SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map& newMods) { // node = the node that was modified/deleted/created // threadTo = the node that needs to know uint256 prevTxID; uint32 prevLgrID; if (!threadTo->thread(mSet.getTxID(), mSet.getLgrSeq(), prevTxID, prevLgrID)) return false; - if (metaNode.thread(prevTxID, prevLgrID)) + if (mSet.getAffectedNode(threadTo->getIndex(), TMNModifiedNode, false).thread(prevTxID, prevLgrID)) return true; assert(false); return false; } -bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::ref node, Ledger::ref ledger, - boost::unordered_map& newMods) +bool LedgerEntrySet::threadOwners(SLE::ref node, Ledger::ref ledger, boost::unordered_map& newMods) { // thread new or modified node to owner or owners if (node->hasOneOwner()) // thread to owner's account - return threadTx(metaNode, node->getOwner(), ledger, newMods); - else if (node->hasTwoOwners()) // thread to owner's accounts + { + Log(lsTRACE) << "Thread to single owner"; + return threadTx(node->getOwner(), ledger, newMods); + } + else if (node->hasTwoOwners()) // thread to owner's accounts] + { + Log(lsTRACE) << "Thread to two owners"; return - threadTx(metaNode, node->getFirstOwner(), ledger, newMods) || - threadTx(metaNode, node->getSecondOwner(), ledger, newMods); + threadTx(node->getFirstOwner(), ledger, newMods) && + threadTx(node->getSecondOwner(), ledger, newMods); + } else return false; } @@ -369,12 +373,12 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) continue; SLE::pointer curNode = it->second.mEntry; - TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType); + TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType, true); if (nType == TMNDeletedNode) { assert(origNode); - threadOwners(metaNode, origNode, mLedger, newMod); + threadOwners(origNode, mLedger, newMod); if (origNode->getIFieldPresent(sfAmount)) { // node has an amount, covers ripple state nodes @@ -408,13 +412,16 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) if (nType == TMNCreatedNode) // if created, thread to owner(s) { assert(!origNode); - threadOwners(metaNode, curNode, mLedger, newMod); + threadOwners(curNode, mLedger, newMod); } if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode)) { if (curNode->isThreadedType()) // always thread to self - threadTx(metaNode, curNode, mLedger, newMod); + { + Log(lsTRACE) << "Thread to self"; + threadTx(curNode, mLedger, newMod); + } } if (nType == TMNModifiedNode) diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 92d96294e9..150a5ae891 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -42,14 +42,12 @@ protected: SLE::pointer getForMod(const uint256& node, Ledger::ref ledger, boost::unordered_map& newMods); - bool threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::ref ledger, + bool threadTx(const NewcoinAddress& threadTo, Ledger::ref ledger, boost::unordered_map& newMods); - bool threadTx(TransactionMetaNode& metaNode, SLE::ref threadTo, Ledger::ref ledger, - boost::unordered_map& newMods); + bool threadTx(SLE::ref threadTo, Ledger::ref ledger, boost::unordered_map& newMods); - bool threadOwners(TransactionMetaNode& metaNode, SLE::ref node, Ledger::ref ledger, - boost::unordered_map& newMods); + bool threadOwners(SLE::ref node, Ledger::ref ledger, boost::unordered_map& newMods); public: diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 41c4bc7fb8..0353df8b69 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -3,6 +3,7 @@ #include #include "Ledger.h" +#include "Log.h" SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint256& index) : SerializedType("LedgerEntry"), mIndex(index) @@ -99,6 +100,7 @@ uint32 SerializedLedgerEntry::getThreadedLedger() bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID) { uint256 oldPrevTxID = getIFieldH256(sfLastTxnID); + Log(lsTRACE) << "Thread Tx:" << txID << " prev:" << oldPrevTxID; if (oldPrevTxID == txID) return false; prevTxID = oldPrevTxID; diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index d43e55e343..4c179f0b70 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -294,11 +294,15 @@ bool TransactionMetaSet::isNodeAffected(const uint256& node) const return mNodes.find(node) != mNodes.end(); } -TransactionMetaNode& TransactionMetaSet::getAffectedNode(const uint256& node, int type) +TransactionMetaNode& TransactionMetaSet::getAffectedNode(const uint256& node, int type, bool overrideType) { std::map::iterator it = mNodes.find(node); if (it != mNodes.end()) + { + if (overrideType) + it->second.setType(type); return it->second; + } return mNodes.insert(std::make_pair(node, TransactionMetaNode(node, type))).first->second; } diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index 10423aeda9..e3ac3b6cd4 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -158,6 +158,7 @@ public: TransactionMetaNode(int type, const uint256& node, SerializerIterator&); void addRaw(Serializer&); + void setType(int t) { mType = t; } Json::Value getJson(int) const; bool addAmount(int nodeType, const STAmount& amount); @@ -189,7 +190,7 @@ public: uint32 getLgrSeq() { return mLedger; } bool isNodeAffected(const uint256&) const; - TransactionMetaNode& getAffectedNode(const uint256&, int type); + TransactionMetaNode& getAffectedNode(const uint256&, int type, bool overrideType); const TransactionMetaNode& peekAffectedNode(const uint256&) const; Json::Value getJson(int) const; From 169f0f487a47627ae1928bd12863a27bdee1c2ef Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 21 Sep 2012 14:37:16 -0700 Subject: [PATCH 302/426] UT: Rework server module to provide an object. --- {test => js}/utils.js | 23 +++++--- test/server.js | 122 ++++++++++++++++++++++++++-------------- test/standalone-test.js | 7 +-- 3 files changed, 98 insertions(+), 54 deletions(-) rename {test => js}/utils.js (83%) diff --git a/test/utils.js b/js/utils.js similarity index 83% rename from test/utils.js rename to js/utils.js index 0bf10b18ea..6bb4ae7a2d 100644 --- a/test/utils.js +++ b/js/utils.js @@ -1,15 +1,22 @@ +// YYY Should probably have two versions: node vs browser var fs = require("fs"); var path = require("path"); +Function.prototype.method = function(name,func) { + this.prototype[name] = func; + + return this; +}; + var filterErr = function(code, done) { - return function (e) { + return function(e) { done(e.code !== code ? e : undefined); }; }; var throwErr = function(done) { - return function (e) { + return function(e) { if (e) throw e; @@ -20,7 +27,7 @@ var throwErr = function(done) { // apply function to elements of array. Return first true value to done or undefined. var mapOr = function(func, array, done) { if (array.length) { - func(array[array.length-1], function (v) { + func(array[array.length-1], function(v) { if (v) { done(v); } @@ -37,7 +44,7 @@ var mapOr = function(func, array, done) { // Make a directory and sub-directories. var mkPath = function(dirPath, mode, done) { - fs.mkdir(dirPath, typeof mode === "string" ? parseInt(mode, 8) : mode, function (e) { + fs.mkdir(dirPath, typeof mode === "string" ? parseInt(mode, 8) : mode, function(e) { if (!e || e.code === "EEXIST") { // Created or already exists, done. done(); @@ -62,7 +69,7 @@ var mkPath = function(dirPath, mode, done) { // Empty a directory. var emptyPath = function(dirPath, done) { - fs.readdir(dirPath, function (err, files) { + fs.readdir(dirPath, function(err, files) { if (err) { done(err); } @@ -76,7 +83,7 @@ var emptyPath = function(dirPath, done) { var rmPath = function(dirPath, done) { // console.log("rmPath: %s", dirPath); - fs.lstat(dirPath, function (err, stats) { + fs.lstat(dirPath, function(err, stats) { if (err && err.code == "ENOENT") { done(); } @@ -84,7 +91,7 @@ var rmPath = function(dirPath, done) { done(err); } else if (stats.isDirectory()) { - emptyPath(dirPath, function (e) { + emptyPath(dirPath, function(e) { if (e) { done(e); } @@ -103,7 +110,7 @@ var rmPath = function(dirPath, done) { // Create directory if needed and empty if needed. var resetPath = function(dirPath, mode, done) { - mkPath(dirPath, mode, function (e) { + mkPath(dirPath, mode, function(e) { if (e) { done(e); } diff --git a/test/server.js b/test/server.js index 0be028cc59..0bd0f582c3 100644 --- a/test/server.js +++ b/test/server.js @@ -6,7 +6,7 @@ // var config = require("./config.js"); -var utils = require("./utils.js"); +var utils = require("../js/utils.js"); var fs = require("fs"); var path = require("path"); @@ -15,99 +15,137 @@ var child = require("child_process"); var servers = {}; -var serverPath = function(name) { - return "tmp/server/" + name; +// Create a server object +var Server = function(name) { + this.name = name; }; // Return a server's newcoind.cfg as string. -var configContent = function(name) { - var cfg = config.servers[name]; +Server.method('configContent', function() { + var cfg = config.servers[this.name]; - return Object.keys(cfg).map(function (o) { + return Object.keys(cfg).map(function(o) { return util.format("[%s]\n%s\n", o, cfg[o]); }).join(""); -}; +}); -var configPath = function(name) { - return path.join(serverPath(name), "newcoind.cfg"); -}; +Server.method('serverPath', function() { + return "tmp/server/" + this.name; +}); + +Server.method('configPath', function() { + return path.join(this.serverPath(), "newcoind.cfg"); +}); // Write a server's newcoind.cfg. -var writeConfig = function(name, done) { - fs.writeFile(configPath(name), configContent(name), 'utf8', done); -}; +Server.method('writeConfig', function(done) { + fs.writeFile(this.configPath(), this.configContent(), 'utf8', done); +}); -var serverSpawnSync = function(name) { +// Spawn the server. +Server.method('serverSpawnSync', function() { // Spawn in standalone mode for now. - var server = child.spawn( + this.child = child.spawn( config.newcoind, [ "-a", "--conf=newcoind.cfg" ], { - cwd: serverPath(name), + cwd: this.serverPath(), env: process.env, stdio: 'inherit' }); - servers[name] = server; - console.log("server: %s: %s -a --conf=%s", server.pid, config.newcoind, configPath(name)); - console.log("sever: start: servers = %s", Object.keys(servers).toString()); + console.log("server: start %s: %s -a --conf=%s", this.child.pid, config.newcoind, this.configPath()); - server.on('exit', function (code, signal) { + // By default, just log exits. + this.child.on('exit', function(code, signal) { // If could not exec: code=127, signal=null // If regular exit: code=0, signal=null - console.log("sever: spawn: server exited code=%s: signal=%s", code, signal); - delete servers[name]; + console.log("server: spawn: server exited code=%s: signal=%s", code, signal); }); -}; +}); -var makeBase = function(name, done) { - var path = serverPath(name); +// Prepare server's working directory. +Server.method('makeBase', function(done) { + var path = this.serverPath(); + var self = this; // Reset the server directory, build it if needed. - utils.resetPath(path, '0777', function (e) { + utils.resetPath(path, '0777', function(e) { if (e) { throw e; } else { - writeConfig(name, done); + self.writeConfig(done); } }); -}; +}); +// Create a standalone server. // Prepare the working directory and spawn the server. -exports.start = function(name, done) { - makeBase(name, function (e) { +Server.method('start', function(done) { + var self = this; + + this.makeBase(function(e) { if (e) { throw e; } else { - serverSpawnSync(name); + self.serverSpawnSync(); done(); } }); -}; +}); -exports.stop = function(name, done) { - console.log("sever: stop: servers = %s", Object.keys(servers).toString()); - var server = servers[name]; - - if (server) { - server.on('exit', function (code, signal) { - console.log("sever: stop: server exited"); - delete servers[name]; +// Stop a standalone server. +Server.method('stop', function(done) { + if (this.child) { + // Update the on exit to invoke done. + this.child.on('exit', function(code, signal) { + console.log("server: stop: server exited"); done(); }); - server.kill(); + this.child.kill(); } else { - console.log("sever: stop: no such server"); + console.log("server: stop: no such server"); done(); } +}); + +// Start the named server. +exports.start = function(name, done) { + if (servers[name]) + { + console.log("server: start: server already started."); + } + else + { + var server = new Server(name); + + servers[name] = server; + + console.log("server: start: %s", JSON.stringify(server)); + + server.start(done); + } }; +// Delete the named server. +exports.stop = function(name, done) { + console.log("server: stop: %s of %s", name, Object.keys(servers).toString()); + + var server = servers[name]; + if (server) { + server.stop(done); + delete servers[name]; + } +}; + +exports.Server = Server; + // vim:ts=4 diff --git a/test/standalone-test.js b/test/standalone-test.js index a3a7a561a2..d707baeca3 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -6,11 +6,11 @@ var buster = require("buster"); var server = require("./server.js"); buster.testCase("Check standalone server startup", { - "server start and stop": function (done) { + "server start and stop": function(done) { server.start("alpha", - function (e) { + function(e) { buster.refute(e); - server.stop("alpha", function (e) { + server.stop("alpha", function(e) { buster.refute(e); done(); }); @@ -18,5 +18,4 @@ buster.testCase("Check standalone server startup", { } }); -// console.log("standalone-test.js<"); // vim:ts=4 From a4070de73eddb1c54414b5e1d38d4b828b7bb7c1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 13:04:24 -0700 Subject: [PATCH 303/426] Some work on the new binary formats that doesn't break current code. --- src/FieldNames.cpp | 98 ++++++++++++++++++++++++++++++++++++++ src/FieldNames.h | 15 ++++++ src/LedgerEntrySet.cpp | 3 ++ src/SerializedObject.h | 13 ++++- src/SerializedTypes.h | 37 +++++++------- src/Transaction.cpp | 6 +-- src/TransactionAction.cpp | 4 +- src/TransactionFormats.cpp | 6 +-- 8 files changed, 156 insertions(+), 26 deletions(-) create mode 100644 src/FieldNames.cpp create mode 100644 src/FieldNames.h diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp new file mode 100644 index 0000000000..5f1ff6130c --- /dev/null +++ b/src/FieldNames.cpp @@ -0,0 +1,98 @@ + +#include "FieldNames.h" + +#define S_FIELD(x) sf##x, #x + +FieldName FieldNames[]= +{ + + // 8-bit integers + { S_FIELD(CloseResolution), STI_UINT8, 1 }, + + // 32-bit integers (common) + { S_FIELD(Flags), STI_UINT32, 1 }, + { S_FIELD(SourceTag), STI_UINT32, 2 }, + { S_FIELD(Sequence), STI_UINT32, 3 }, + { S_FIELD(LastTxnSeq), STI_UINT32, 4 }, + { S_FIELD(LedgerSequence), STI_UINT32, 5 }, + { S_FIELD(CloseTime), STI_UINT32, 6 }, + { S_FIELD(ParentCloseTime), STI_UINT32, 7 }, + { S_FIELD(SigningTime), STI_UINT32, 8 }, + { S_FIELD(Expiration), STI_UINT32, 9 }, + { S_FIELD(TransferRate), STI_UINT32, 10 }, + { S_FIELD(PublishSize), STI_UINT32, 11 }, + + // 32-bit integers (rare) + { S_FIELD(HighQualityIn), STI_UINT32, 16 }, + { S_FIELD(HighQualityOut), STI_UINT32, 17 }, + { S_FIELD(LowQualityIn), STI_UINT32, 18 }, + { S_FIELD(LowQualityOut), STI_UINT32, 19 }, + { S_FIELD(QualityIn), STI_UINT32, 20 }, + { S_FIELD(QualityOut), STI_UINT32, 21 }, + { S_FIELD(StampEscrow), STI_UINT32, 22 }, + { S_FIELD(BondAmount), STI_UINT32, 23 }, + { S_FIELD(LoadFee), STI_UINT32, 24 }, + + // 64-bit integers + { S_FIELD(IndexNext), STI_UINT64, 1 }, + { S_FIELD(IndexPrevious), STI_UINT64, 2 }, + { S_FIELD(BookNode), STI_UINT64, 3 }, + { S_FIELD(OwnerNode), STI_UINT64, 4 }, + { S_FIELD(BaseFee), STI_UINT64, 5 }, + + // 128-bit + { S_FIELD(PublishSize), STI_HASH128, 1 }, + { S_FIELD(EmailHash), STI_HASH128, 2 }, + + // 256-bit + { S_FIELD(LedgerHash), STI_HASH256, 1 }, + { S_FIELD(ParentHash), STI_HASH256, 2 }, + { S_FIELD(TransactionHash), STI_HASH256, 3 }, + { S_FIELD(AccountHash), STI_HASH256, 4 }, + { S_FIELD(LastTxnID), STI_HASH256, 5 }, + { S_FIELD(WalletLocator), STI_HASH256, 6 }, + { S_FIELD(PublishHash), STI_HASH256, 7 }, + { S_FIELD(Nickname), STI_HASH256, 8 }, + + // currency amount + { S_FIELD(Amount), STI_AMOUNT, 1 }, + { S_FIELD(Balance), STI_AMOUNT, 2 }, + { S_FIELD(LimitAmount), STI_AMOUNT, 3 }, + { S_FIELD(TakerPays), STI_AMOUNT, 4 }, + { S_FIELD(TakerGets), STI_AMOUNT, 5 }, + { S_FIELD(LowLimit), STI_AMOUNT, 6 }, + { S_FIELD(HighLimit), STI_AMOUNT, 7 }, + { S_FIELD(MinimumOffer), STI_AMOUNT, 8 }, + + // variable length + { S_FIELD(PublicKey), STI_VL, 1 }, + { S_FIELD(MessageKey), STI_VL, 2 }, + { S_FIELD(SigningKey), STI_VL, 3 }, + { S_FIELD(Signature), STI_VL, 4 }, + { S_FIELD(Generator), STI_VL, 5 }, + { S_FIELD(Domain), STI_VL, 6 }, + + // account + { S_FIELD(Account), STI_ACCOUNT, 1 }, + { S_FIELD(Owner), STI_ACCOUNT, 2 }, + { S_FIELD(Destination), STI_ACCOUNT, 3 }, + { S_FIELD(Issuer), STI_ACCOUNT, 4 }, + { S_FIELD(HighID), STI_ACCOUNT, 5 }, + { S_FIELD(LowID), STI_ACCOUNT, 6 }, + { S_FIELD(Target), STI_ACCOUNT, 7 }, + + // path set + { S_FIELD(Paths), STI_PATHSET, 1 }, + + // vector of 256-bit + { S_FIELD(Indexes), STI_VECTOR256, 1 }, + + // inner object + { S_FIELD(MiddleTransaction), STI_OBJECT, 1 }, + { S_FIELD(InnerTransaction), STI_OBJECT, 2 }, + // OBJECT/15 is reserved for end of object + + // array of objects + { S_FIELD(SigningAccounts), STI_ARRAY, 1 }, + // ARRAY/15 is reserved for end of array +}; diff --git a/src/FieldNames.h b/src/FieldNames.h new file mode 100644 index 0000000000..5d4979a302 --- /dev/null +++ b/src/FieldNames.h @@ -0,0 +1,15 @@ +#ifndef __FIELDNAMES__ +#define __FIELDNAMES__ + +#include "SerializedTypes.h" +#include "SerializedObject.h" + +struct FieldName +{ + SOE_Field field; + const char *fieldName; + SerializedTypeID fieldType; + int fieldValue; +}; + +#endif diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 5408a4dca8..59bc7359a2 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -349,14 +349,17 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) switch (it->second.mAction) { case taaMODIFY: + Log(lsTRACE) << "Modified Node " << it->first; nType = TMNModifiedNode; break; case taaDELETE: + Log(lsTRACE) << "Deleted Node " << it->first; nType = TMNDeletedNode; break; case taaCREATE: + Log(lsTRACE) << "Created Node " << it->first; nType = TMNCreatedNode; break; diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 08377304c1..e46bf479aa 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -30,9 +30,11 @@ enum SOE_Field sfAcceptRate, sfAcceptStart, sfAccount, + sfAccountHash, sfAmount, sfAuthorizedKey, sfBalance, + sfBaseFee, sfBondAmount, sfBookDirectory, sfBookNode, @@ -42,6 +44,7 @@ enum SOE_Field sfBorrower, sfCreateCode, sfCloseTime, + sfCloseResolution, sfCurrency, sfCurrencyIn, sfCurrencyOut, @@ -65,18 +68,22 @@ enum SOE_Field sfIndexes, sfIndexNext, sfIndexPrevious, + sfInnerTransaction, sfInvoiceID, sfIssuer, sfLastNode, sfLastTxnID, sfLastTxnSeq, sfLedgerHash, + sfLedgerSequence, sfLimitAmount, + sfLoadFee, sfLowID, sfLowLimit, sfLowQualityIn, sfLowQualityOut, sfMessageKey, + sfMiddleTransaction, sfMinimumOffer, sfNextAcceptExpire, sfNextAcceptRate, @@ -88,8 +95,10 @@ enum SOE_Field sfOfferSequence, sfOwner, sfOwnerNode, + sfParentCloseTime, + sfParentHash, sfPaths, - sfPubKey, + sfPublicKey, sfPublishHash, sfPublishSize, sfQualityIn, @@ -99,6 +108,7 @@ enum SOE_Field sfSendMax, sfSequence, sfSignature, + sfSigningAccounts, sfSigningKey, sfSigningTime, sfSourceTag, @@ -107,6 +117,7 @@ enum SOE_Field sfTakerPays, sfTarget, sfTransferRate, + sfTransactionHash, sfVersion, sfWalletLocator, diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 3a6417986e..e7735bfc8e 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -15,25 +15,28 @@ enum SerializedTypeID STI_DONE = -1, STI_NOTPRESENT = 0, - // standard types - STI_OBJECT = 1, - STI_UINT8 = 2, - STI_UINT16 = 3, - STI_UINT32 = 4, - STI_UINT64 = 5, - STI_HASH128 = 6, - STI_HASH160 = 7, - STI_HASH256 = 8, - STI_VL = 9, - STI_TL = 10, - STI_AMOUNT = 11, - STI_PATHSET = 12, - STI_VECTOR256 = 13, + // common types + STI_UINT32 = 1, + STI_UINT64 = 2, + STI_HASH128 = 3, + STI_HASH256 = 4, + STI_TL = 5, + STI_AMOUNT = 6, + STI_VL = 7, + STI_ACCOUNT = 8, + STI_OBJECT = 14, + STI_ARRAY = 15, + + // uncommon types + STI_UINT8 = 16, + STI_UINT16 = 17, + STI_HASH160 = 18, + STI_PATHSET = 19, + STI_VECTOR256 = 20, // high level types - STI_ACCOUNT = 100, - STI_TRANSACTION = 101, - STI_LEDGERENTRY = 102 + STI_TRANSACTION = 100001, + STI_LEDGERENTRY = 100002 }; enum PathFlags diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 00988712d9..526f433bf1 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -194,7 +194,7 @@ Transaction::pointer Transaction::setClaim( const std::vector& vucSignature) { mTransaction->setITFieldVL(sfGenerator, vucGenerator); - mTransaction->setITFieldVL(sfPubKey, vucPubKey); + mTransaction->setITFieldVL(sfPublicKey, vucPubKey); mTransaction->setITFieldVL(sfSignature, vucSignature); sign(naPrivateKey); @@ -455,7 +455,7 @@ Transaction::pointer Transaction::setPasswordSet( { mTransaction->setITFieldAccount(sfAuthorizedKey, naAuthKeyID); mTransaction->setITFieldVL(sfGenerator, vucGenerator); - mTransaction->setITFieldVL(sfPubKey, vucPubKey); + mTransaction->setITFieldVL(sfPublicKey, vucPubKey); mTransaction->setITFieldVL(sfSignature, vucSignature); sign(naPrivateKey); @@ -542,7 +542,7 @@ Transaction::pointer Transaction::setWalletAdd( { mTransaction->setITFieldAmount(sfAmount, saAmount); mTransaction->setITFieldAccount(sfAuthorizedKey, naAuthKeyID); - mTransaction->setITFieldVL(sfPubKey, naNewPubKey.getAccountPublic()); + mTransaction->setITFieldVL(sfPublicKey, naNewPubKey.getAccountPublic()); mTransaction->setITFieldVL(sfSignature, vucSignature); sign(naPrivateKey); diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index f60ae0af57..19db581da2 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -30,7 +30,7 @@ TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMus // std::vector vucCipher = txn.getITFieldVL(sfGenerator); - std::vector vucPubKey = txn.getITFieldVL(sfPubKey); + std::vector vucPubKey = txn.getITFieldVL(sfPublicKey); std::vector vucSignature = txn.getITFieldVL(sfSignature); NewcoinAddress naAccountPublic = NewcoinAddress::createAccountPublic(vucPubKey); @@ -620,7 +620,7 @@ TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn) { std::cerr << "WalletAdd>" << std::endl; - const std::vector vucPubKey = txn.getITFieldVL(sfPubKey); + const std::vector vucPubKey = txn.getITFieldVL(sfPublicKey); const std::vector vucSignature = txn.getITFieldVL(sfSignature); const uint160 uAuthKeyID = txn.getITFieldAccount(sfAuthorizedKey); const NewcoinAddress naMasterPubKey = NewcoinAddress::createAccountPublic(vucPubKey); diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index de18524c7c..542e2683c5 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -21,7 +21,7 @@ TransactionFormat InnerTxnFormats[]= { "Claim", ttCLAIM, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(PubKey), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, @@ -85,7 +85,7 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(PubKey), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, @@ -106,7 +106,7 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Amount), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(PubKey), STI_VL, SOE_REQUIRED, 0 }, + { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, From 8f88575b8e2fec3321d1b309ad68330b2142fa2e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 13:19:28 -0700 Subject: [PATCH 304/426] Low-level serializer functions for new type/name field. --- src/Serializer.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++ src/Serializer.h | 5 ++++ 2 files changed, 67 insertions(+) diff --git a/src/Serializer.cpp b/src/Serializer.cpp index 51fd734668..cd7e0d6a8e 100644 --- a/src/Serializer.cpp +++ b/src/Serializer.cpp @@ -154,6 +154,57 @@ uint256 Serializer::get256(int offset) const return ret; } +int Serializer::addFieldID(int type, int name) +{ + int ret = mData.size(); + assert((type > 0) && (type < 256) && (name > 0) && (name < 256)); + if (type < 16) + { + if (name < 16) // common type, common name + mData.push_back(static_cast((type << 4) | name)); + else + { // common type, uncommon name + mData.push_back(static_cast(type << 4)); + mData.push_back(static_cast(name)); + } + } + else if (name < 16) + { // uncommon type, common name + mData.push_back(static_cast(name)); + mData.push_back(static_cast(type)); + } + else + { // uncommon type, uncommon name + mData.push_back(static_cast(0)); + mData.push_back(static_cast(type)); + mData.push_back(static_cast(name)); + } + return ret; +} + +bool Serializer::getFieldID(int& type, int & name, int offset) const +{ + if (!get8(type, offset)) + return false; + name = type & 15; + type >>= 4; + if (type == 0) + { // uncommon type + if (!get8(type, ++offset)) + return false; + if ((type == 0) || (type < 16)) + return false; + } + if (name == 0) + { // uncommon name + if (!get8(name, ++offset)) + return false; + if ((name == 0) || (name < 16)) + return false; + } + return true; +} + int Serializer::add8(unsigned char byte) { int ret = mData.size(); @@ -535,6 +586,17 @@ int SerializerIterator::getBytesLeft() return mSerializer.size() - mPos; } +void SerializerIterator::getFieldID(int& type, int& field) +{ + if (!mSerializer.getFieldID(type, field, mPos)) + throw std::runtime_error("invalid serializer getFieldID"); + ++mPos; + if (type >= 16) + ++mPos; + if (field >= 16) + ++mPos; +} + unsigned char SerializerIterator::get8() { int val; diff --git a/src/Serializer.h b/src/Serializer.h index 5c687e2984..e1c251508c 100644 --- a/src/Serializer.h +++ b/src/Serializer.h @@ -67,6 +67,9 @@ public: bool getTaggedList(std::list&, int offset, int& length) const; bool getTaggedList(std::vector&, int offset, int& length) const; + bool getFieldID(int& type, int& name, int offset) const; + int addFieldID(int type, int name); + // normal hash functions uint160 getRIPEMD160(int size=-1) const; uint256 getSHA256(int size=-1) const; @@ -156,6 +159,8 @@ public: uint160 get160(); uint256 get256(); + void getFieldID(int& type, int& field); + std::vector getRaw(int iLength); std::vector getVL(); From 3c5ea7020f995696a3231c52165060148ac73777 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 14:30:24 -0700 Subject: [PATCH 305/426] Start of STAmount issuer fixes. --- src/Amount.cpp | 24 ++++++++++++++++++------ src/SerializedTypes.h | 12 +++++++----- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 4c35c46a06..9fc46089e3 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -359,19 +359,16 @@ STAmount* STAmount::construct(SerializerIterator& sit, const char *name) if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset)) throw std::runtime_error("invalid currency value"); - sapResult = new STAmount(name, uCurrencyID, value, offset, isNegative); + sapResult = new STAmount(name, uCurrencyID, uIssuerID, value, offset, isNegative); } else { if (offset != 512) throw std::runtime_error("invalid currency value"); - sapResult = new STAmount(name, uCurrencyID); + sapResult = new STAmount(name, uCurrencyID, uIssuerID); } - if (sapResult) - sapResult->setIssuer(uIssuerID); - return sapResult; } @@ -522,7 +519,22 @@ STAmount& STAmount::operator-=(const STAmount& a) STAmount STAmount::operator-(void) const { if (mValue == 0) return *this; - return STAmount(name, mCurrency, mValue, mOffset, mIsNative, !mIsNegative); + return STAmount(name, mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative); +} + +STAmount& STAmount::operator=(const STAmount &a) +{ + if (name == NULL) + name = a.name; + + mCurrency = a.mCurrency; + mIssuer = a.mIssuer; + mValue = a.mValue; + mOffset = a.mOffset; + mIsNative = a.mIsNative; + mIsNegative = a.mIsNegative; + + return *this; } STAmount& STAmount::operator=(uint64 v) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index e7735bfc8e..fef6664123 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -250,9 +250,9 @@ protected: STAmount(const char *name, uint64 value, bool isNegative) : SerializedType(name), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative) { ; } - STAmount(const char *n, const uint160& cur, uint64 val, int off, bool isNative, bool isNegative) - : SerializedType(n), mCurrency(cur), mValue(val), mOffset(off), mIsNative(isNative), mIsNegative(isNegative) - { ; } + STAmount(const char *n, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg) + : SerializedType(n), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off), + mIsNative(isNat), mIsNegative(isNeg) { ; } uint64 toUInt64() const; static uint64 muldiv(uint64, uint64, uint64); @@ -272,8 +272,9 @@ public: { canonicalize(); } // YYY This should probably require issuer too. - STAmount(const char* n, const uint160& currency, uint64 v = 0, int off = 0, bool isNeg = false) : - SerializedType(n), mCurrency(currency), mValue(v), mOffset(off), mIsNegative(isNeg) + STAmount(const char* n, const uint160& currency, const uint160& issuer, + uint64 v = 0, int off = 0, bool isNeg = false) : + SerializedType(n), mCurrency(currency), mIssuer(issuer), mValue(v), mOffset(off), mIsNegative(isNeg) { canonicalize(); } STAmount(const char* n, int64 v); @@ -347,6 +348,7 @@ public: STAmount operator-(uint64) const; STAmount operator-(void) const; + STAmount& operator=(const STAmount&); STAmount& operator+=(const STAmount&); STAmount& operator-=(const STAmount&); STAmount& operator+=(uint64); From 7ef8001505eec94bcef5c7843e1e71675f8e1a7c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 14:36:48 -0700 Subject: [PATCH 306/426] Audit all construction cases, fix broken ones. --- src/Amount.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 9fc46089e3..ebd2597a99 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -632,9 +632,9 @@ STAmount operator+(const STAmount& v1, const STAmount& v2) int64 fv = vv1 + vv2; if (fv >= 0) - return STAmount(v1.name, v1.mCurrency, fv, ov1, false); + return STAmount(v1.name, v1.mCurrency, v1.mIssuer, fv, ov1, false); else - return STAmount(v1.name, v1.mCurrency, -fv, ov1, true); + return STAmount(v1.name, v1.mCurrency, v1.mIssuer, -fv, ov1, true); } STAmount operator-(const STAmount& v1, const STAmount& v2) @@ -664,9 +664,9 @@ STAmount operator-(const STAmount& v1, const STAmount& v2) int64 fv = vv1 - vv2; if (fv >= 0) - return STAmount(v1.name, v1.mCurrency, fv, ov1, false); + return STAmount(v1.name, v1.mCurrency, v1.mIssuer, fv, ov1, false); else - return STAmount(v1.name, v1.mCurrency, -fv, ov1, true); + return STAmount(v1.name, v1.mCurrency, v1.mIssuer, -fv, ov1, true); } STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& uCurrencyID, const uint160& uIssuerID) From 9432d35f14a862dca021672569a1b1b49d2d824f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 14:45:44 -0700 Subject: [PATCH 307/426] You don't need to customize operator=(const&) since the base class does it for you. --- src/Amount.cpp | 15 --------------- src/SerializedTypes.h | 1 - 2 files changed, 16 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index ebd2597a99..f0692f2af7 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -522,21 +522,6 @@ STAmount STAmount::operator-(void) const return STAmount(name, mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative); } -STAmount& STAmount::operator=(const STAmount &a) -{ - if (name == NULL) - name = a.name; - - mCurrency = a.mCurrency; - mIssuer = a.mIssuer; - mValue = a.mValue; - mOffset = a.mOffset; - mIsNative = a.mIsNative; - mIsNegative = a.mIsNegative; - - return *this; -} - STAmount& STAmount::operator=(uint64 v) { // does not copy name, does not change currency type mOffset = 0; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index fef6664123..6c9099df50 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -348,7 +348,6 @@ public: STAmount operator-(uint64) const; STAmount operator-(void) const; - STAmount& operator=(const STAmount&); STAmount& operator+=(const STAmount&); STAmount& operator-=(const STAmount&); STAmount& operator+=(uint64); From 173b6ce5581e5c7e78dc5d7137fb58ebc48f0834 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 16:21:40 -0700 Subject: [PATCH 308/426] More changes to the new serialization format that don't break compatibility. --- src/FieldNames.cpp | 97 ++-------------------------- src/FieldNames.h | 1 + src/LedgerFormats.cpp | 7 --- src/SerializeProto.h | 125 +++++++++++++++++++++++++++++++++++++ src/SerializedObject.h | 100 ++--------------------------- src/TransactionFormats.cpp | 13 ---- 6 files changed, 137 insertions(+), 206 deletions(-) create mode 100644 src/SerializeProto.h diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index 5f1ff6130c..3053c2c960 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -1,98 +1,13 @@ #include "FieldNames.h" -#define S_FIELD(x) sf##x, #x +#define FIELD(name, type, index) { sf##name, #name, STI_##type, index }, +#define TYPE(type, index) FieldName FieldNames[]= { - - // 8-bit integers - { S_FIELD(CloseResolution), STI_UINT8, 1 }, - - // 32-bit integers (common) - { S_FIELD(Flags), STI_UINT32, 1 }, - { S_FIELD(SourceTag), STI_UINT32, 2 }, - { S_FIELD(Sequence), STI_UINT32, 3 }, - { S_FIELD(LastTxnSeq), STI_UINT32, 4 }, - { S_FIELD(LedgerSequence), STI_UINT32, 5 }, - { S_FIELD(CloseTime), STI_UINT32, 6 }, - { S_FIELD(ParentCloseTime), STI_UINT32, 7 }, - { S_FIELD(SigningTime), STI_UINT32, 8 }, - { S_FIELD(Expiration), STI_UINT32, 9 }, - { S_FIELD(TransferRate), STI_UINT32, 10 }, - { S_FIELD(PublishSize), STI_UINT32, 11 }, - - // 32-bit integers (rare) - { S_FIELD(HighQualityIn), STI_UINT32, 16 }, - { S_FIELD(HighQualityOut), STI_UINT32, 17 }, - { S_FIELD(LowQualityIn), STI_UINT32, 18 }, - { S_FIELD(LowQualityOut), STI_UINT32, 19 }, - { S_FIELD(QualityIn), STI_UINT32, 20 }, - { S_FIELD(QualityOut), STI_UINT32, 21 }, - { S_FIELD(StampEscrow), STI_UINT32, 22 }, - { S_FIELD(BondAmount), STI_UINT32, 23 }, - { S_FIELD(LoadFee), STI_UINT32, 24 }, - - // 64-bit integers - { S_FIELD(IndexNext), STI_UINT64, 1 }, - { S_FIELD(IndexPrevious), STI_UINT64, 2 }, - { S_FIELD(BookNode), STI_UINT64, 3 }, - { S_FIELD(OwnerNode), STI_UINT64, 4 }, - { S_FIELD(BaseFee), STI_UINT64, 5 }, - - // 128-bit - { S_FIELD(PublishSize), STI_HASH128, 1 }, - { S_FIELD(EmailHash), STI_HASH128, 2 }, - - // 256-bit - { S_FIELD(LedgerHash), STI_HASH256, 1 }, - { S_FIELD(ParentHash), STI_HASH256, 2 }, - { S_FIELD(TransactionHash), STI_HASH256, 3 }, - { S_FIELD(AccountHash), STI_HASH256, 4 }, - { S_FIELD(LastTxnID), STI_HASH256, 5 }, - { S_FIELD(WalletLocator), STI_HASH256, 6 }, - { S_FIELD(PublishHash), STI_HASH256, 7 }, - { S_FIELD(Nickname), STI_HASH256, 8 }, - - // currency amount - { S_FIELD(Amount), STI_AMOUNT, 1 }, - { S_FIELD(Balance), STI_AMOUNT, 2 }, - { S_FIELD(LimitAmount), STI_AMOUNT, 3 }, - { S_FIELD(TakerPays), STI_AMOUNT, 4 }, - { S_FIELD(TakerGets), STI_AMOUNT, 5 }, - { S_FIELD(LowLimit), STI_AMOUNT, 6 }, - { S_FIELD(HighLimit), STI_AMOUNT, 7 }, - { S_FIELD(MinimumOffer), STI_AMOUNT, 8 }, - - // variable length - { S_FIELD(PublicKey), STI_VL, 1 }, - { S_FIELD(MessageKey), STI_VL, 2 }, - { S_FIELD(SigningKey), STI_VL, 3 }, - { S_FIELD(Signature), STI_VL, 4 }, - { S_FIELD(Generator), STI_VL, 5 }, - { S_FIELD(Domain), STI_VL, 6 }, - - // account - { S_FIELD(Account), STI_ACCOUNT, 1 }, - { S_FIELD(Owner), STI_ACCOUNT, 2 }, - { S_FIELD(Destination), STI_ACCOUNT, 3 }, - { S_FIELD(Issuer), STI_ACCOUNT, 4 }, - { S_FIELD(HighID), STI_ACCOUNT, 5 }, - { S_FIELD(LowID), STI_ACCOUNT, 6 }, - { S_FIELD(Target), STI_ACCOUNT, 7 }, - - // path set - { S_FIELD(Paths), STI_PATHSET, 1 }, - - // vector of 256-bit - { S_FIELD(Indexes), STI_VECTOR256, 1 }, - - // inner object - { S_FIELD(MiddleTransaction), STI_OBJECT, 1 }, - { S_FIELD(InnerTransaction), STI_OBJECT, 2 }, - // OBJECT/15 is reserved for end of object - - // array of objects - { S_FIELD(SigningAccounts), STI_ARRAY, 1 }, - // ARRAY/15 is reserved for end of array +#include "SerializeProto.h" }; + +#undef FIELD +#undef TYPE diff --git a/src/FieldNames.h b/src/FieldNames.h index 5d4979a302..af760127f6 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -10,6 +10,7 @@ struct FieldName const char *fieldName; SerializedTypeID fieldType; int fieldValue; + int fieldID; }; #endif diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index ef991c9f62..1db310a4c1 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -20,7 +20,6 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Domain), STI_VL, SOE_IFFLAG, 32 }, { S_FIELD(PublishHash), STI_HASH256, SOE_IFFLAG, 64 }, { S_FIELD(PublishSize), STI_UINT32, SOE_IFFLAG, 128 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Contract", ltCONTRACT, { @@ -37,7 +36,6 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "DirectoryNode", ltDIR_NODE, { @@ -45,20 +43,17 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(Indexes), STI_VECTOR256, SOE_REQUIRED, 0 }, { S_FIELD(IndexNext), STI_UINT64, SOE_IFFLAG, 1 }, { S_FIELD(IndexPrevious), STI_UINT64, SOE_IFFLAG, 2 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "GeneratorMap", ltGENERATOR_MAP, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Nickname", ltNICKNAME, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(MinimumOffer), STI_AMOUNT, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Offer", ltOFFER, { @@ -73,7 +68,6 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "RippleState", ltRIPPLE_STATE, { @@ -89,7 +83,6 @@ LedgerEntryFormat LedgerFormats[]= { S_FIELD(LowQualityOut), STI_UINT32, SOE_IFFLAG, 2 }, { S_FIELD(HighQualityIn), STI_UINT32, SOE_IFFLAG, 4 }, { S_FIELD(HighQualityOut), STI_UINT32, SOE_IFFLAG, 8 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x01000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { NULL, ltINVALID } diff --git a/src/SerializeProto.h b/src/SerializeProto.h new file mode 100644 index 0000000000..fc02af1d12 --- /dev/null +++ b/src/SerializeProto.h @@ -0,0 +1,125 @@ +// This is not really a header file, but it can be used as one with +// appropriate #define statements. + + // types (common) + TYPE(UINT32, 1) + TYPE(UINT64, 2) + TYPE(HASH128, 3) + TYPE(HASH256, 4) + // 5 is reserved + TYPE(AMOUNT, 6) + TYPE(VL, 7) + TYPE(ACCOUNT, 8) + // 9-13 are reserved + TYPE(OBJECT, 14) + TYPE(ARRAY, 15) + + // types (uncommon) + TYPE(UINT8, 16) + TYPE(UINT16, 17) + TYPE(HASH160, 18) + TYPE(PATHSET, 19) + TYPE(VECTOR256, 20) + + // 8-bit integers + FIELD(CloseResolution, UINT8, 1) + + // 32-bit integers (common) + FIELD(Flags, UINT32, 1) + FIELD(SourceTag, UINT32, 2) + FIELD(Sequence, UINT32, 3) + FIELD(LastTxnSeq, UINT32, 4) + FIELD(LedgerSequence, UINT32, 5) + FIELD(CloseTime, UINT32, 6) + FIELD(ParentCloseTime, UINT32, 7) + FIELD(SigningTime, UINT32, 8) + FIELD(Expiration, UINT32, 9) + FIELD(TransferRate, UINT32, 10) + FIELD(PublishSize, UINT32, 11) + + // 32-bit integers (uncommon) + FIELD(HighQualityIn, UINT32, 16) + FIELD(HighQualityOut, UINT32, 17) + FIELD(LowQualityIn, UINT32, 18) + FIELD(LowQualityOut, UINT32, 19) + FIELD(QualityIn, UINT32, 20) + FIELD(QualityOut, UINT32, 21) + FIELD(StampEscrow, UINT32, 22) + FIELD(BondAmount, UINT32, 23) + FIELD(LoadFee, UINT32, 24) + FIELD(OfferSequence, UINT32, 25) + + // 64-bit integers + FIELD(IndexNext, UINT64, 1) + FIELD(IndexPrevious, UINT64, 2) + FIELD(BookNode, UINT64, 3) + FIELD(OwnerNode, UINT64, 4) + FIELD(BaseFee, UINT64, 5) + + // 128-bit + FIELD(EmailHash, HASH128, 2) + + // 256-bit (common) + FIELD(LedgerHash, HASH256, 1) + FIELD(ParentHash, HASH256, 2) + FIELD(TransactionHash, HASH256, 3) + FIELD(AccountHash, HASH256, 4) + FIELD(LastTxnID, HASH256, 5) + FIELD(WalletLocator, HASH256, 6) + FIELD(PublishHash, HASH256, 7) + + // 256-bit (uncommon) + FIELD(BookDirectory, HASH256, 16) + FIELD(InvoiceID, HASH256, 17) + FIELD(Nickname, HASH256, 18) + + // currency amount (common) + FIELD(Amount, AMOUNT, 1) + FIELD(Balance, AMOUNT, 2) + FIELD(LimitAmount, AMOUNT, 3) + FIELD(TakerPays, AMOUNT, 4) + FIELD(TakerGets, AMOUNT, 5) + FIELD(LowLimit, AMOUNT, 6) + FIELD(HighLimit, AMOUNT, 7) + FIELD(SendMax, AMOUNT, 9) + + // current amount (uncommon) + FIELD(MinimumOffer, AMOUNT, 16) + FIELD(RippleEscrow, AMOUNT, 17) + + // variable length + FIELD(PublicKey, VL, 1) + FIELD(MessageKey, VL, 2) + FIELD(SigningKey, VL, 3) + FIELD(Signature, VL, 4) + FIELD(Generator, VL, 5) + FIELD(Domain, VL, 6) + FIELD(FundCode, VL, 7) + FIELD(RemoveCode, VL, 8) + FIELD(ExpireCode, VL, 9) + FIELD(CreateCode, VL, 10) + + // account + FIELD(Account, ACCOUNT, 1) + FIELD(Owner, ACCOUNT, 2) + FIELD(Destination, ACCOUNT, 3) + FIELD(Issuer, ACCOUNT, 4) + FIELD(HighID, ACCOUNT, 5) + FIELD(LowID, ACCOUNT, 6) + FIELD(Target, ACCOUNT, 7) + FIELD(AuthorizedKey, ACCOUNT, 8) + + // path set + FIELD(Paths, PATHSET, 1) + + // vector of 256-bit + FIELD(Indexes, VECTOR256, 1) + + // inner object + // OBJECT/1 is reserved for end of object + FIELD(MiddleTransaction, OBJECT, 2) + FIELD(InnerTransaction, OBJECT, 3) + + // array of objects + // ARRAY/1 is reserved for end of array + FIELD(SigningAccounts, ARRAY, 2) diff --git a/src/SerializedObject.h b/src/SerializedObject.h index e46bf479aa..b0e0b5e4b4 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -25,101 +25,11 @@ enum SOE_Field sfInvalid = -1, sfGeneric = 0, - // common fields - sfAcceptExpire, - sfAcceptRate, - sfAcceptStart, - sfAccount, - sfAccountHash, - sfAmount, - sfAuthorizedKey, - sfBalance, - sfBaseFee, - sfBondAmount, - sfBookDirectory, - sfBookNode, - sfBorrowExpire, - sfBorrowRate, - sfBorrowStart, - sfBorrower, - sfCreateCode, - sfCloseTime, - sfCloseResolution, - sfCurrency, - sfCurrencyIn, - sfCurrencyOut, - sfDestination, - sfDomain, - sfEmailHash, - sfExpiration, - sfExpireCode, - sfExtensions, - sfFirstNode, - sfFlags, - sfFundCode, - sfGenerator, - sfGeneratorID, - sfHash, - sfHighID, - sfHighLimit, - sfHighQualityIn, - sfHighQualityOut, - sfIdentifier, - sfIndexes, - sfIndexNext, - sfIndexPrevious, - sfInnerTransaction, - sfInvoiceID, - sfIssuer, - sfLastNode, - sfLastTxnID, - sfLastTxnSeq, - sfLedgerHash, - sfLedgerSequence, - sfLimitAmount, - sfLoadFee, - sfLowID, - sfLowLimit, - sfLowQualityIn, - sfLowQualityOut, - sfMessageKey, - sfMiddleTransaction, - sfMinimumOffer, - sfNextAcceptExpire, - sfNextAcceptRate, - sfNextAcceptStart, - sfNextTransitExpire, - sfNextTransitRate, - sfNextTransitStart, - sfNickname, - sfOfferSequence, - sfOwner, - sfOwnerNode, - sfParentCloseTime, - sfParentHash, - sfPaths, - sfPublicKey, - sfPublishHash, - sfPublishSize, - sfQualityIn, - sfQualityOut, - sfRemoveCode, - sfRippleEscrow, - sfSendMax, - sfSequence, - sfSignature, - sfSigningAccounts, - sfSigningKey, - sfSigningTime, - sfSourceTag, - sfStampEscrow, - sfTakerGets, - sfTakerPays, - sfTarget, - sfTransferRate, - sfTransactionHash, - sfVersion, - sfWalletLocator, +#define FIELD(name, type, index) sf##name, +#define TYPE(name, index) +#include "SerializeProto.h" +#undef FIELD +#undef TYPE // test fields sfTest1, sfTest2, sfTest3, sfTest4 diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 542e2683c5..3ab00f7dea 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -15,7 +15,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(TransferRate), STI_UINT32, SOE_IFFLAG, 32 }, { S_FIELD(PublishHash), STI_HASH256, SOE_IFFLAG, 64 }, { S_FIELD(PublishSize), STI_UINT32, SOE_IFFLAG, 128 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Claim", ttCLAIM, { @@ -24,7 +23,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "CreditSet", ttCREDIT_SET, { @@ -34,7 +32,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(LimitAmount), STI_AMOUNT, SOE_IFFLAG, 2 }, { S_FIELD(QualityIn), STI_UINT32, SOE_IFFLAG, 4 }, { S_FIELD(QualityOut), STI_UINT32, SOE_IFFLAG, 8 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, /* @@ -45,7 +42,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 2 }, { S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 4 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, */ @@ -55,7 +51,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(MinimumOffer), STI_AMOUNT, SOE_IFFLAG, 1 }, { S_FIELD(Signature), STI_VL, SOE_IFFLAG, 2 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 4 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "OfferCreate", ttOFFER_CREATE, { @@ -64,21 +59,18 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(TakerGets), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 2 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "OfferCancel", ttOFFER_CANCEL, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(OfferSequence), STI_UINT32, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "PasswordFund", ttPASSWORD_FUND, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "PasswordSet", ttPASSWORD_SET, { @@ -88,7 +80,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Payment", ttPAYMENT, { @@ -99,7 +90,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(Paths), STI_PATHSET, SOE_IFFLAG, 2 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 4 }, { S_FIELD(InvoiceID), STI_HASH256, SOE_IFFLAG, 8 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "WalletAdd", ttWALLET_ADD, { @@ -109,7 +99,6 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Contract", ttCONTRACT, { @@ -122,13 +111,11 @@ TransactionFormat InnerTxnFormats[]= { S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 }, { S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { "Contract", ttCONTRACT_REMOVE, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Extensions), STI_TL, SOE_IFFLAG, 0x02000000 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, { NULL, ttINVALID } From 8d633bf065f85f542dc0ef97bf8daaec2a62aa37 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 16:23:09 -0700 Subject: [PATCH 309/426] Remove a FIXME since it's fixed. --- src/SerializedObject.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/SerializedObject.h b/src/SerializedObject.h index b0e0b5e4b4..89732a063d 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -18,8 +18,6 @@ enum SOE_Type SOE_IFNFLAG = 3 // present if flag not set }; -// JED: seems like there would be a better way to do this -// maybe something that inherits from SerializedTransaction enum SOE_Field { sfInvalid = -1, From 19ee517d9f2a0f64d6874a6dfccbbc1b07b6e56b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 16:28:08 -0700 Subject: [PATCH 310/426] Neaten this up a bit. --- src/FieldNames.cpp | 2 +- src/SerializeProto.h | 30 ++++++++++++++++-------------- src/SerializedObject.h | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index 3053c2c960..a65ce1bc93 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -2,7 +2,7 @@ #include "FieldNames.h" #define FIELD(name, type, index) { sf##name, #name, STI_##type, index }, -#define TYPE(type, index) +#define TYPE(name, type, index) FieldName FieldNames[]= { diff --git a/src/SerializeProto.h b/src/SerializeProto.h index fc02af1d12..d2336e8971 100644 --- a/src/SerializeProto.h +++ b/src/SerializeProto.h @@ -2,24 +2,26 @@ // appropriate #define statements. // types (common) - TYPE(UINT32, 1) - TYPE(UINT64, 2) - TYPE(HASH128, 3) - TYPE(HASH256, 4) + TYPE("Int32", UINT32, 1) + TYPE("Int64", UINT64, 2) + TYPE("Hash128", HASH128, 3) + TYPE("Hash256", HASH256, 4) // 5 is reserved - TYPE(AMOUNT, 6) - TYPE(VL, 7) - TYPE(ACCOUNT, 8) + TYPE("Amount", AMOUNT, 6) + TYPE("VariableLength", VL, 7) + TYPE("Account", ACCOUNT, 8) // 9-13 are reserved - TYPE(OBJECT, 14) - TYPE(ARRAY, 15) + TYPE("Object", OBJECT, 14) + TYPE("Array", ARRAY, 15) // types (uncommon) - TYPE(UINT8, 16) - TYPE(UINT16, 17) - TYPE(HASH160, 18) - TYPE(PATHSET, 19) - TYPE(VECTOR256, 20) + TYPE("Int8", UINT8, 16) + TYPE("Int16", UINT16, 17) + TYPE("Hash160", HASH160, 18) + TYPE("PathSet", PATHSET, 19) + TYPE("Vector256", VECTOR256, 20) + + // 8-bit integers FIELD(CloseResolution, UINT8, 1) diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 89732a063d..3ff352a793 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -24,7 +24,7 @@ enum SOE_Field sfGeneric = 0, #define FIELD(name, type, index) sf##name, -#define TYPE(name, index) +#define TYPE(name, type, index) #include "SerializeProto.h" #undef FIELD #undef TYPE From 8cc760ad8d671ac217f6289a67bbbaaf8271b422 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 24 Sep 2012 19:50:57 -0700 Subject: [PATCH 311/426] Clean up offer processing. --- src/LedgerEntrySet.cpp | 37 +++++++++------------------- src/TransactionAction.cpp | 52 +++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 5408a4dca8..c1f4919fde 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -938,24 +938,19 @@ STAmount LedgerEntrySet::accountHolds(const uint160& uAccountID, const uint160& if (!uCurrencyID) { - SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uAccountID)); + 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); } + Log(lsINFO) << boost::str(boost::format("accountHolds: uAccountID=%s saAmount=%s") + % NewcoinAddress::createHumanAccountID(uAccountID) + % saAmount.getFullText()); + return saAmount; } @@ -968,30 +963,22 @@ STAmount LedgerEntrySet::accountFunds(const uint160& uAccountID, const STAmount& { 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(); + Log(lsINFO) << boost::str(boost::format("accountFunds: uAccountID=%s saDefault=%s SELF-FUNDED") + % NewcoinAddress::createHumanAccountID(uAccountID) + % saDefault.getFullText()); } 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()); + Log(lsINFO) << boost::str(boost::format("accountFunds: uAccountID=%s saDefault=%s saFunds=%s") + % NewcoinAddress::createHumanAccountID(uAccountID) + % saDefault.getFullText() + % saFunds.getFullText()); } return saFunds; diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index f60ae0af57..2862a1d427 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -710,8 +710,8 @@ TER TransactionEngine::takeOffers( boost::unordered_set usOfferUnfundedBecame; // Offers that became unfunded. boost::unordered_set usAccountTouched; // Accounts touched. - saTakerPaid = 0; - saTakerGot = 0; + saTakerPaid = STAmount(saTakerPays.getCurrency(), saTakerPays.getIssuer()); + saTakerGot = STAmount(saTakerGets.getCurrency(), saTakerGets.getIssuer()); while (temUNCERTAIN == terResult) { @@ -915,8 +915,11 @@ Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); const bool bPassive = isSetBit(txFlags, tfPassive); STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); -Log(lsWARNING) << "doOfferCreate: saTakerPays=" << saTakerPays.getFullText(); -Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); + +Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGets=%s") + % saTakerPays.getFullText() + % saTakerGets.getFullText()); + const uint160 uPaysIssuerID = saTakerPays.getIssuer(); const uint160 uGetsIssuerID = saTakerGets.getIssuer(); const uint32 uExpiration = txn.getITFieldU32(sfExpiration); @@ -999,14 +1002,14 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); STAmount saOfferGot; const uint256 uTakeBookBase = Ledger::getBookBase(uGetsCurrency, uGetsIssuerID, uPaysCurrency, uPaysIssuerID); - Log(lsINFO) << boost::str(boost::format("doOfferCreate: take against book: %s : %s/%s -> %s/%s") + Log(lsINFO) << boost::str(boost::format("doOfferCreate: take against book: %s for %s -> %s") % uTakeBookBase.ToString() - % saTakerGets.getHumanCurrency() - % NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()) - % saTakerPays.getHumanCurrency() - % NewcoinAddress::createHumanAccountID(saTakerPays.getIssuer())); + % saTakerGets.getFullText() + % saTakerPays.getFullText()); // Take using the parameters of the offer. +#if 1 + Log(lsWARNING) << "doOfferCreate: takeOffers: BEFORE saTakerGets=" << saTakerGets.getFullText(); terResult = takeOffers( bPassive, uTakeBookBase, @@ -1017,12 +1020,14 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); saOfferPaid, // How much was spent. saOfferGot // How much was got. ); - +#else + terResult = tesSUCCESS; +#endif Log(lsWARNING) << "doOfferCreate: takeOffers=" << terResult; Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferPaid=" << saOfferPaid.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saOfferGot=" << saOfferGot.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText(); - Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: AFTER saTakerGets=" << saTakerGets.getFullText(); if (tesSUCCESS == terResult) { @@ -1033,19 +1038,21 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerPays=" << saTakerPays.getFullText(); Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << saTakerGets.getFullText(); - Log(lsWARNING) << "doOfferCreate: takeOffers: saTakerGets=" << NewcoinAddress::createHumanAccountID(saTakerGets.getIssuer()); Log(lsWARNING) << "doOfferCreate: takeOffers: mTxnAccountID=" << NewcoinAddress::createHumanAccountID(mTxnAccountID); - Log(lsWARNING) << "doOfferCreate: takeOffers: funds=" << mNodes.accountFunds(mTxnAccountID, saTakerGets).getFullText(); + Log(lsWARNING) << "doOfferCreate: takeOffers: FUNDS=" << mNodes.accountFunds(mTxnAccountID, saTakerGets).getFullText(); // Log(lsWARNING) << "doOfferCreate: takeOffers: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); // Log(lsWARNING) << "doOfferCreate: takeOffers: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); if (tesSUCCESS == terResult - && saTakerPays // Still wanting something. - && saTakerGets // Still offering something. + && saTakerPays // Still wanting something. + && saTakerGets // Still offering something. && mNodes.accountFunds(mTxnAccountID, saTakerGets).isPositive()) // Still funded. { // We need to place the remainder of the offer into its order book. + Log(lsINFO) << boost::str(boost::format("doOfferCreate: offer not fully consumed: saTakerPays=%s saTakerGets=%s") + % saTakerPays.getFullText() + % saTakerGets.getFullText()); // Add offer to owner's directory. terResult = mNodes.dirAdd(uOwnerNode, Ledger::getOwnerDirIndex(mTxnAccountID), uLedgerIndex); @@ -1069,12 +1076,13 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); if (tesSUCCESS == terResult) { - // Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); - // Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); - // Log(lsWARNING) << "doOfferCreate: saTakerPays.isNative()=" << saTakerPays.isNative(); - // Log(lsWARNING) << "doOfferCreate: saTakerGets.isNative()=" << saTakerGets.isNative(); - // Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency(); - // Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency(); + Log(lsWARNING) << "doOfferCreate: sfAccount=" << NewcoinAddress::createHumanAccountID(mTxnAccountID); + Log(lsWARNING) << "doOfferCreate: uPaysIssuerID=" << NewcoinAddress::createHumanAccountID(uPaysIssuerID); + Log(lsWARNING) << "doOfferCreate: uGetsIssuerID=" << NewcoinAddress::createHumanAccountID(uGetsIssuerID); + Log(lsWARNING) << "doOfferCreate: saTakerPays.isNative()=" << saTakerPays.isNative(); + Log(lsWARNING) << "doOfferCreate: saTakerGets.isNative()=" << saTakerGets.isNative(); + Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency(); + Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency(); sleOffer->setIFieldAccount(sfAccount, mTxnAccountID); sleOffer->setIFieldU32(sfSequence, uSequence); @@ -1092,6 +1100,8 @@ Log(lsWARNING) << "doOfferCreate: saTakerGets=" << saTakerGets.getFullText(); } } + Log(lsINFO) << "doOfferCreate: final sleOffer=" << sleOffer->getJson(0); + return terResult; } From 195cd9eadec95a4ed881a73d9bb8429474009d1c Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 24 Sep 2012 20:07:31 -0700 Subject: [PATCH 312/426] Report IP when do an RPC call. --- src/CallRPC.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CallRPC.cpp b/src/CallRPC.cpp index 38f697a1e7..50896b858c 100644 --- a/src/CallRPC.cpp +++ b/src/CallRPC.cpp @@ -112,7 +112,8 @@ Json::Value callRPC(const std::string& strMethod, const Json::Value& params) "If the file does not exist, create it with owner-readable-only file permissions."); // Connect to localhost - std::cout << "Connecting to port:" << theConfig.RPC_PORT << std::endl; + std::cout << "Connecting to: " << theConfig.RPC_IP << ":" << theConfig.RPC_PORT << std::endl; + boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(theConfig.RPC_IP), theConfig.RPC_PORT); boost::asio::ip::tcp::iostream stream; From 6c17c0270b935cfa65d77e22f52df5d8d6d2e717 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 24 Sep 2012 23:25:27 -0700 Subject: [PATCH 313/426] Remove dead code. Use the protocol file to generate the STI_* constants. --- src/SerializedObject.cpp | 27 ----------------- src/SerializedTypes.cpp | 45 ----------------------------- src/SerializedTypes.h | 62 ++++------------------------------------ 3 files changed, 5 insertions(+), 129 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index af4210f3d1..eaf7ec4006 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -42,9 +42,6 @@ std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, c case STI_VL: return std::auto_ptr(new STVariableLength(name)); - case STI_TL: - return std::auto_ptr(new STTaggedList(name)); - case STI_ACCOUNT: return std::auto_ptr(new STAccount(name)); @@ -91,9 +88,6 @@ std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID case STI_VL: return STVariableLength::deserialize(sit, name); - case STI_TL: - return STTaggedList::deserialize(sit, name); - case STI_ACCOUNT: return STAccount::deserialize(sit, name); @@ -476,17 +470,6 @@ std::vector STObject::getValueFieldVL(SOE_Field field) const return cf->getValue(); } -std::vector STObject::getValueFieldTL(SOE_Field field) const -{ - const SerializedType* rf = peekAtPField(field); - if (!rf) throw std::runtime_error("Field not found"); - SerializedTypeID id = rf->getSType(); - if (id == STI_NOTPRESENT) return std::vector(); // optional field not present - const STTaggedList *cf = dynamic_cast(rf); - if (!cf) throw std::runtime_error("Wrong field type"); - return cf->getValue(); -} - STAmount STObject::getValueFieldAmount(SOE_Field field) const { const SerializedType* rf = peekAtPField(field); @@ -620,16 +603,6 @@ void STObject::setValueFieldVL(SOE_Field field, const std::vector cf->setValue(v); } -void STObject::setValueFieldTL(SOE_Field field, const std::vector& v) -{ - SerializedType* rf = getPField(field); - if (!rf) throw std::runtime_error("Field not found"); - if (rf->getSType() == STI_NOTPRESENT) rf = makeFieldPresent(field); - STTaggedList* cf = dynamic_cast(rf); - if (!cf) throw std::runtime_error("Wrong field type"); - cf->setValue(v); -} - void STObject::setValueFieldAmount(SOE_Field field, const STAmount &v) { SerializedType* rf = getPField(field); diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 3bd54dc34a..dde47265c0 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -255,51 +255,6 @@ void STAccount::setValueNCA(const NewcoinAddress& nca) setValueH160(nca.getAccountID()); } -std::string STTaggedList::getText() const -{ - std::string ret; - for (std::vector::const_iterator it=value.begin(); it!=value.end(); ++it) - { - ret += boost::lexical_cast(it->first); - ret += ","; - ret += strHex(it->second); - } - return ret; -} - -Json::Value STTaggedList::getJson(int) const -{ - Json::Value ret(Json::arrayValue); - - for (std::vector::const_iterator it=value.begin(); it!=value.end(); ++it) - { - Json::Value elem(Json::arrayValue); - elem.append(it->first); - elem.append(strHex(it->second)); - ret.append(elem); - } - - return ret; -} - -STTaggedList* STTaggedList::construct(SerializerIterator& u, const char *name) -{ - return new STTaggedList(name, u.getTaggedList()); -} - -int STTaggedList::getLength() const -{ - int ret = Serializer::getTaggedListLength(value); - if (ret<0) throw std::overflow_error("bad TL length"); - return ret; -} - -bool STTaggedList::isEquivalent(const SerializedType& t) const -{ - const STTaggedList* v = dynamic_cast(&t); - return v && (value == v->value); -} - STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) { std::vector paths; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 6c9099df50..28a3063677 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -15,24 +15,11 @@ enum SerializedTypeID STI_DONE = -1, STI_NOTPRESENT = 0, - // common types - STI_UINT32 = 1, - STI_UINT64 = 2, - STI_HASH128 = 3, - STI_HASH256 = 4, - STI_TL = 5, - STI_AMOUNT = 6, - STI_VL = 7, - STI_ACCOUNT = 8, - STI_OBJECT = 14, - STI_ARRAY = 15, - - // uncommon types - STI_UINT8 = 16, - STI_UINT16 = 17, - STI_HASH160 = 18, - STI_PATHSET = 19, - STI_VECTOR256 = 20, +#define TYPE(name, field, value) STI_##field = value, +#define FIELD(name, field, value) +#include "SerializeProto.h" +#undef TYPE +#undef FIELD // high level types STI_TRANSACTION = 100001, @@ -730,45 +717,6 @@ namespace boost }; } -class STTaggedList : public SerializedType -{ -protected: - std::vector value; - - STTaggedList* duplicate() const { return new STTaggedList(name, value); } - static STTaggedList* construct(SerializerIterator&, const char* name = NULL); - -public: - - STTaggedList() { ; } - STTaggedList(const char* n) : SerializedType(n) { ; } - STTaggedList(const std::vector& v) : value(v) { ; } - STTaggedList(const char* n, const std::vector& v) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) - { return std::auto_ptr(construct(sit, name)); } - - int getLength() const; - SerializedTypeID getSType() const { return STI_TL; } - std::string getText() const; - void add(Serializer& s) const { if (s.addTaggedList(value) < 0) throw(0); } - - const std::vector& peekValue() const { return value; } - std::vector& peekValue() { return value; } - std::vector getValue() const { return value; } - virtual Json::Value getJson(int) const; - - void setValue(const std::vector& v) { value=v; } - - int getItemCount() const { return value.size(); } - bool isEmpty() const { return value.empty(); } - - void clear() { value.erase(value.begin(), value.end()); } - void addItem(const TaggedListItem& v) { value.push_back(v); } - - operator std::vector() const { return value; } - virtual bool isEquivalent(const SerializedType& t) const; -}; - class STVector256 : public SerializedType { protected: From 04f0b12a13529a7b2251a876cb3e0c371e41e86f Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 15:14:27 -0700 Subject: [PATCH 314/426] UT: Initial tests of creating and connecting to a standalone store. --- test/config.js | 14 ++++++++------ test/standalone-test.js | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/test/config.js b/test/config.js index 6b320f248f..0610373db9 100644 --- a/test/config.js +++ b/test/config.js @@ -9,15 +9,17 @@ exports.newcoind = path.join(process.cwd(), "newcoind"); // Configuration for servers. exports.servers = { + // A local test server. alpha : { + 'trusted' : true, // "peer_ip" : "0.0.0.0", // "peer_port" : 51235, - "rpc_ip" : "0.0.0.0", - "rpc_port" : 5005, - "websocket_ip" : "127.0.0.1", - "websocket_port" : 6005, - "validation_seed" : "shhDFVsmS2GSu5vUyZSPXYfj1r79h", - "validators" : "n9L8LZZCwsdXzKUN9zoVxs4YznYXZ9hEhsQZY7aVpxtFaSceiyDZ beta" + 'rpc_ip' : "0.0.0.0", + 'rpc_port' : 5005, + 'websocket_ip' : "127.0.0.1", + 'websocket_port' : 6005, + 'validation_seed' : "shhDFVsmS2GSu5vUyZSPXYfj1r79h", + 'validators' : "n9L8LZZCwsdXzKUN9zoVxs4YznYXZ9hEhsQZY7aVpxtFaSceiyDZ beta" } }; // vim:ts=4 diff --git a/test/standalone-test.js b/test/standalone-test.js index d707baeca3..c50e50154a 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -4,6 +4,7 @@ var fs = require("fs"); var buster = require("buster"); var server = require("./server.js"); +var remote = require("../js/remote.js"); buster.testCase("Check standalone server startup", { "server start and stop": function(done) { @@ -18,4 +19,44 @@ buster.testCase("Check standalone server startup", { } }); +buster.testCase("Check websocket connection", { + 'setUp' : + function(done) { + server.start("alpha", + function(e) { + buster.refute(e); + done(); + }); + }, + + 'tearDown' : + function(done) { + server.stop("alpha", function(e) { + buster.refute(e); + done(); + }); + }, + + "websocket connect and disconnect" : + function(done) { + var alpha = remote.remoteConfig("alpha"); + + alpha.connect(function(stat) { + buster.assert(1 == stat); // OPEN + + alpha.disconnect(function(stat) { + buster.assert(3 == stat); // CLOSED + done(); + }); + }); + }, +}); + +buster.testCase("Check assert", { + "assert" : + function() { + buster.assert(true); + } +}); + // vim:ts=4 From bf71b7b1bf0602117e4fceaf7d7567ae6d197bb0 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 15:15:45 -0700 Subject: [PATCH 315/426] js: create a websocket connection. --- js/remote.js | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 js/remote.js diff --git a/js/remote.js b/js/remote.js new file mode 100644 index 0000000000..8903c87472 --- /dev/null +++ b/js/remote.js @@ -0,0 +1,123 @@ +// Remote access to a server. +// - We never send binary data. +// - We use the W3C interface for node and browser compatibility: +// http://www.w3.org/TR/websockets/#the-websocket-interface +// +// YYY Will later provide a network access which use multiple instances of this. +// + +var util = require('util'); + +var WebSocket = require('ws'); + +// YYY This is wrong should not use anything in test directory. +var config = require("../test/config.js"); + +// --> trusted: truthy, if remote is trusted +var Remote = function(trusted, websocket_ip, websocket_port) { + this.trusted = trusted; + this.websocket_ip = websocket_ip; + this.websocket_port = websocket_port; + this.id = 0; +}; + +var remoteConfig = function(server) { + var serverConfig = config.servers[server]; + + return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port); +}; + +// Target state is connectted. +// done(readyState): +// --> readyState: OPEN, CLOSED +Remote.method('connect', function(done, onmessage) { + var url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port); + + console.log("remote: connect: %s", url); + + this.ws = new WebSocket(url); + + var ws = this.ws; + + ws.onopen = function() { + console.log("remote: onopen: %s", ws.readyState); + ws.onclose = undefined; + done(ws.readyState); + }; + + // Also covers failure to open. + ws.onclose = function() { + console.log("remote: onclose: %s", ws.readyState); + done(ws.readyState); + }; + + if (onmessage) { + ws.onmessage = onmessage; + } +}); + +// Target stated is disconnected. +Remote.method('disconnect', function(done) { + var ws = this.ws; + + ws.onclose = function() { + console.log("remote: onclose: %s", ws.readyState); + done(ws.readyState); + }; + + ws.close(); +}); + +// Send a command. The comman should lack the id. +// <-> command: what to send, consumed. +Remote.method('request', function(command, done) { + this.id += 1; // Advance id. + + var ws = this.ws; + + command.id = this.id; + + ws.response[command.id] = done; + + ws.send(command); +}); + +// Request the current ledger. +// done(index) +// index: undefined = error +Remote.method('ledger', function(done) { + +}); + + +// Submit a json transaction. +// done(value) +// <-> value: { 'status', status, 'result' : result, ... } +// done may be called up to 3 times. +Remote.method('submit', function(json, done) { +// this.request(..., function() { +// }); +}); + +// ==> entry_spec +Remote.method('ledger_entry', function(entry_spec, done) { + entry_spec.command = 'ledger_entry'; + + this.request(entry_spec, function() { + }); +}); + +// done(value) +// --> value: { 'status', status, 'result' : result, ... } +// done may be called up to 3 times. +Remote.method('account_root', function(account_id, done) { + this.request({ + 'command' : 'ledger_entry', + }, function() { + }); +}); + +exports.Remote = Remote; +exports.remoteConfig = remoteConfig; + +// vim:ts=4 From c757d363afe2efd3eb224d7894d2bd82178297de Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 25 Sep 2012 16:48:24 -0700 Subject: [PATCH 316/426] Parts of the new serialization code. Does not compile yet. --- src/Amount.cpp | 6 +- src/FieldNames.cpp | 40 ++++++ src/FieldNames.h | 48 +++++++- src/LedgerFormats.cpp | 134 ++++++++++---------- src/LedgerFormats.h | 6 +- src/SerializeProto.h | 23 ++-- src/SerializedLedger.h | 1 - src/SerializedObject.cpp | 92 +++++--------- src/SerializedObject.h | 102 ++++++++++------ src/SerializedTypes.cpp | 45 +++---- src/SerializedTypes.h | 174 ++++++++++++-------------- src/TransactionFormats.cpp | 242 ++++++++++++++++++------------------- src/TransactionFormats.h | 6 +- 13 files changed, 478 insertions(+), 441 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index f0692f2af7..56b0104a3b 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -298,7 +298,7 @@ void STAmount::add(Serializer& s) const } } -STAmount::STAmount(const char* name, int64 value) : SerializedType(name), mOffset(0), mIsNative(true) +STAmount::STAmount(FieldName* name, int64 value) : SerializedType(name), mOffset(0), mIsNative(true) { if (value >= 0) { @@ -330,7 +330,7 @@ uint64 STAmount::toUInt64() const return mValue | (static_cast(mOffset + 256 + 97) << (64 - 10)); } -STAmount* STAmount::construct(SerializerIterator& sit, const char *name) +STAmount* STAmount::construct(SerializerIterator& sit, FieldName* name) { uint64 value = sit.get64(); @@ -883,7 +883,7 @@ uint64 STAmount::convertToDisplayAmount(const STAmount& internalAmount, uint64 t } STAmount STAmount::convertToInternalAmount(uint64 displayAmount, uint64 totalNow, uint64 totalInit, - const char *name) + FieldName* name) { // Convert a display/request currency amount to an internal amount return STAmount(name, muldiv(displayAmount, totalNow, totalInit)); } diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index a65ce1bc93..72589d0004 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -1,13 +1,53 @@ #include "FieldNames.h" +#include + +#include + #define FIELD(name, type, index) { sf##name, #name, STI_##type, index }, #define TYPE(name, type, index) FieldName FieldNames[]= { #include "SerializeProto.h" + + { sfInvalid, 0, STI_DONE, 0 } }; #undef FIELD #undef TYPE + +static std::map unknownFieldMap; +static boost::mutex unknownFieldMutex; + +FieldName* getFieldName(SOE_Field f) +{ // OPTIMIZEME + for (FieldName* n = FieldNames; n->fieldName != 0; ++n) + if (n->field == f) + return n; + return NULL; +} + +FieldName* getFieldName(int type, int field) +{ // OPTIMIZEME + int f = (type << 16) | field; + for (FieldName* n = FieldNames; n->fieldName != 0; ++n) + if (n->field == f) + return n; + if ((type <= 0) || (type >= 256) || (field <= 0) || (field >= 256 + return NULL; + + boost::mutex::scoped_lock sl(unknownFieldMutex); + std::map it = unknownFieldMap.Find(f); + if (it != unknownFieldMap.end()) + return it->second; + + FieldName* n = new FieldName(); + n->field = f; + n->fieldName = "unknown"; + n->fieldType = static_cast(type); + n->fieldNum = field; + unknownFieldMap[f] = n; + return n; +} diff --git a/src/FieldNames.h b/src/FieldNames.h index af760127f6..b056b237fb 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -1,16 +1,56 @@ #ifndef __FIELDNAMES__ #define __FIELDNAMES__ -#include "SerializedTypes.h" -#include "SerializedObject.h" +enum SerializedTypeID +{ + // special types + STI_DONE = -1, + STI_NOTPRESENT = 0, + +#define TYPE(name, field, value) STI_##field = value, +#define FIELD(name, field, value) +#include "SerializeProto.h" +#undef TYPE +#undef FIELD + + // high level types + STI_TRANSACTION = 100001, + STI_LEDGERENTRY = 100002, + STI_VALIDATION = 100003, +}; + +enum SOE_Flags +{ + SOE_END = -1, // marks end of object + SOE_REQUIRED = 0, // required + SOE_OPTIONAL = 1, // optional +}; + +enum SOE_Field +{ + sfInvalid = -1, + sfGeneric = 0, + +#define FIELD(name, type, index) sf##name = (STI_##type << 16) | index, +#define TYPE(name, type, index) +#include "SerializeProto.h" +#undef FIELD +#undef TYPE + + // test fields + sfTest1=100000, sfTest2, sfTest3, sfTest4 +}; struct FieldName { SOE_Field field; const char *fieldName; SerializedTypeID fieldType; - int fieldValue; - int fieldID; + int fieldNum; }; +extern FieldName FieldNames[]; +extern FieldName* getFieldName(SOE_Field); +extern FieldName* getFieldName(int type, int field); + #endif diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 1db310a4c1..37cc7906e4 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -1,89 +1,87 @@ #include "LedgerFormats.h" -#define S_FIELD(x) sf##x, #x - LedgerEntryFormat LedgerFormats[]= { { "AccountRoot", ltACCOUNT_ROOT, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, - { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_IFFLAG, 1 }, - { S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 2 }, - { S_FIELD(WalletLocator), STI_HASH256, SOE_IFFLAG, 4 }, - { S_FIELD(MessageKey), STI_VL, SOE_IFFLAG, 8 }, - { S_FIELD(TransferRate), STI_UINT32, SOE_IFFLAG, 16 }, - { S_FIELD(Domain), STI_VL, SOE_IFFLAG, 32 }, - { S_FIELD(PublishHash), STI_HASH256, SOE_IFFLAG, 64 }, - { S_FIELD(PublishSize), STI_UINT32, SOE_IFFLAG, 128 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + { sfFlags, SOE_REQUIRED }, + { sfAccount, SOE_REQUIRED }, + { sfSequence, SOE_REQUIRED }, + { sfBalance, SOE_REQUIRED }, + { sfLastTxnID, SOE_REQUIRED }, + { sfLastTxnSeq, SOE_REQUIRED }, + { sfAuthorizedKey, SOE_OPTIONAL }, + { sfEmailHash, SOE_OPTIONAL }, + { sfWalletLocator, SOE_OPTIONAL }, + { sfMessageKey, SOE_OPTIONAL }, + { sfTransferRate, SOE_OPTIONAL }, + { sfDomain, SOE_OPTIONAL }, + { sfPublishHash, SOE_OPTIONAL }, + { sfPublishSize, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } }, { "Contract", ltCONTRACT, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, - { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(Issuer), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Owner), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Expiration), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(BondAmount), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(CreateCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + { sfFlags, SOE_REQUIRED }, + { sfAccount, SOE_REQUIRED }, + { sfBalance, SOE_REQUIRED }, + { sfLastTxnID, SOE_REQUIRED }, + { sfLastTxnSeq, SOE_REQUIRED }, + { sfIssuer, SOE_REQUIRED }, + { sfOwner, SOE_REQUIRED }, + { sfExpiration, SOE_REQUIRED }, + { sfBondAmount, SOE_REQUIRED }, + { sfCreateCode, SOE_REQUIRED }, + { sfFundCode, SOE_REQUIRED }, + { sfRemoveCode, SOE_REQUIRED }, + { sfExpireCode, SOE_REQUIRED }, + { sfInvalid, SOE_END } } }, { "DirectoryNode", ltDIR_NODE, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Indexes), STI_VECTOR256, SOE_REQUIRED, 0 }, - { S_FIELD(IndexNext), STI_UINT64, SOE_IFFLAG, 1 }, - { S_FIELD(IndexPrevious), STI_UINT64, SOE_IFFLAG, 2 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + { sfFlags, SOE_REQUIRED }, + { sfIndexes, SOE_REQUIRED }, + { sfIndexNext, SOE_OPTIONAL }, + { sfIndexPrevious, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } }, { "GeneratorMap", ltGENERATOR_MAP, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + { sfFlags, SOE_REQUIRED }, + { sfGenerator, SOE_REQUIRED }, + { sfInvalid, SOE_END } } }, { "Nickname", ltNICKNAME, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(MinimumOffer), STI_AMOUNT, SOE_IFFLAG, 1 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + { sfFlags, SOE_REQUIRED }, + { sfAccount, SOE_REQUIRED }, + { sfMinimumOffer, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } }, { "Offer", ltOFFER, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Account), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Sequence), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(TakerPays), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(TakerGets), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(BookDirectory), STI_HASH256, SOE_REQUIRED, 0 }, - { S_FIELD(BookNode), STI_UINT64, SOE_REQUIRED, 0 }, - { S_FIELD(OwnerNode), STI_UINT64, SOE_REQUIRED, 0 }, - { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, - { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 1 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + { sfFlags, SOE_REQUIRED }, + { sfAccount, SOE_REQUIRED }, + { sfSequence, SOE_REQUIRED }, + { sfTakerPays, SOE_REQUIRED }, + { sfTakerGets, SOE_REQUIRED }, + { sfBookDirectory, SOE_REQUIRED }, + { sfBookNode, SOE_REQUIRED }, + { sfOwnerNode, SOE_REQUIRED }, + { sfLastTxnID, SOE_REQUIRED }, + { sfLastTxnSeq, SOE_REQUIRED }, + { sfExpiration, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } }, { "RippleState", ltRIPPLE_STATE, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(LowID), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(LowLimit), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(HighID), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(HighLimit), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, - { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(LowQualityIn), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(LowQualityOut), STI_UINT32, SOE_IFFLAG, 2 }, - { S_FIELD(HighQualityIn), STI_UINT32, SOE_IFFLAG, 4 }, - { S_FIELD(HighQualityOut), STI_UINT32, SOE_IFFLAG, 8 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } + { sfFlags, SOE_REQUIRED }, + { sfBalance, SOE_REQUIRED }, + { sfLowID, SOE_REQUIRED }, + { sfLowLimit, SOE_REQUIRED }, + { sfHighID, SOE_REQUIRED }, + { sfHighLimit, SOE_REQUIRED }, + { sfLastTxnID, SOE_REQUIRED }, + { sfLastTxnSeq, SOE_REQUIRED }, + { sfLowQualityIn, SOE_OPTIONAL }, + { sfLowQualityOut, SOE_OPTIONAL }, + { sfHighQualityIn, SOE_OPTIONAL }, + { sfHighQualityOut, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } }, { NULL, ltINVALID } }; diff --git a/src/LedgerFormats.h b/src/LedgerFormats.h index c1cdc505b6..82221ca31d 100644 --- a/src/LedgerFormats.h +++ b/src/LedgerFormats.h @@ -41,9 +41,9 @@ enum LedgerSpecificFlags struct LedgerEntryFormat { - const char *t_name; - LedgerEntryType t_type; - SOElement elements[20]; + const char * t_name; + LedgerEntryType t_type; + SOElement elements[24]; }; extern LedgerEntryFormat LedgerFormats[]; diff --git a/src/SerializeProto.h b/src/SerializeProto.h index d2336e8971..bf60039fb8 100644 --- a/src/SerializeProto.h +++ b/src/SerializeProto.h @@ -27,17 +27,18 @@ FIELD(CloseResolution, UINT8, 1) // 32-bit integers (common) - FIELD(Flags, UINT32, 1) - FIELD(SourceTag, UINT32, 2) - FIELD(Sequence, UINT32, 3) - FIELD(LastTxnSeq, UINT32, 4) - FIELD(LedgerSequence, UINT32, 5) - FIELD(CloseTime, UINT32, 6) - FIELD(ParentCloseTime, UINT32, 7) - FIELD(SigningTime, UINT32, 8) - FIELD(Expiration, UINT32, 9) - FIELD(TransferRate, UINT32, 10) - FIELD(PublishSize, UINT32, 11) + FIELD(ObjectType, UINT32, 1) + FIELD(Flags, UINT32, 2) + FIELD(SourceTag, UINT32, 3) + FIELD(Sequence, UINT32, 4) + FIELD(LastTxnSeq, UINT32, 5) + FIELD(LedgerSequence, UINT32, 6) + FIELD(CloseTime, UINT32, 7) + FIELD(ParentCloseTime, UINT32, 8) + FIELD(SigningTime, UINT32, 9) + FIELD(Expiration, UINT32, 10) + FIELD(TransferRate, UINT32, 11) + FIELD(PublishSize, UINT32, 12) // 32-bit integers (uncommon) FIELD(HighQualityIn, UINT32, 16) diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index 1069887cc2..e60662d2db 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -25,7 +25,6 @@ public: SerializedLedgerEntry(SerializerIterator& sit, const uint256& index); SerializedLedgerEntry(LedgerEntryType type); - int getLength() const { return mVersion.getLength() + mObject.getLength(); } SerializedTypeID getSType() const { return STI_LEDGERENTRY; } std::string getFullText() const; std::string getText() const; diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index eaf7ec4006..c1167a6d62 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -8,7 +8,7 @@ #include "Log.h" -std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, const char *name) +std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, FieldName* name) { switch(id) { @@ -53,8 +53,8 @@ std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, c } } -std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID id, const char *name, - SerializerIterator& sit) +std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID id, FieldName* name, + SerializerIterator& sit, int depth) { switch(id) { @@ -94,6 +94,12 @@ std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID case STI_PATHSET: return STPathSet::deserialize(sit, name); + case STI_ARRAY: + return STArray::deserialize(sit, name); + + case STI_OBJECT: + return STObject::deserialize(sit, name); + default: throw std::runtime_error("Unknown object type"); } @@ -103,13 +109,11 @@ void STObject::set(const SOElement* elem) { mData.empty(); mType.empty(); - mFlagIdx = -1; - while (elem->e_id != STI_DONE) + while (elem->flags != SOE_END) { - if (elem->e_type == SOE_FLAGS) mFlagIdx = mType.size(); mType.push_back(elem); - if (elem->e_type == SOE_IFFLAG) + if (elem->flags == SOE_OPTIONAL) giveObject(makeDefaultObject(STI_NOTPRESENT, elem->e_name)); else giveObject(makeDefaultObject(elem->e_id, elem->e_name)); @@ -117,55 +121,30 @@ void STObject::set(const SOElement* elem) } } -STObject::STObject(const SOElement* elem, const char *name) : SerializedType(name) +STObject::STObject(const SOElement* elem, FieldName* name) : SerializedType(name) { set(elem); } -void STObject::set(const SOElement* elem, SerializerIterator& sit) +void STObject::set(FieldName* name, SerializerIterator& sit, int depth = 0) { mData.empty(); mType.empty(); - mFlagIdx = -1; - int flags = -1; - while (elem->e_id != STI_DONE) + fName = name; + + while(1) { - mType.push_back(elem); - bool done = false; - if (elem->e_type == SOE_IFFLAG) - { - assert(flags >= 0); - if ((flags&elem->e_flags) == 0) - { - done = true; - giveObject(makeDefaultObject(STI_NOTPRESENT, elem->e_name)); - } - } - else if (elem->e_type == SOE_IFNFLAG) - { - assert(flags >= 0); - if ((flags&elem->e_flags) != 0) - { - done = true; - giveObject(makeDefaultObject(elem->e_id, elem->e_name)); - } - } - else if (elem->e_type == SOE_FLAGS) - { - assert(elem->e_id == STI_UINT32); - flags = sit.get32(); - mFlagIdx = giveObject(new STUInt32(elem->e_name, flags)); - done = true; - } - if (!done) - giveObject(makeDeserializedObject(elem->e_id, elem->e_name, sit)); - elem++; + int type, field. + sit.getFieldID(type, field); + if ((type == STI_ARRAY) && (field == 1)) + return; + FieldName* fn = getFieldName(type, field); + giveObject(makeDeserializedObject(static_cast type, fn, sit, depth + 1); } } -STObject::STObject(const SOElement* elem, SerializerIterator& sit, const char *name) - : SerializedType(name), mFlagIdx(-1) +STObject::STObject(const SOElement* elem, SerializerIterator& sit, FieldName*name) : SerializedType(name) { set(elem, sit); } @@ -193,14 +172,6 @@ std::string STObject::getFullText() const return ret; } -int STObject::getLength() const -{ - int ret = 0; - BOOST_FOREACH(const SerializedType& it, mData) - ret += it.getLength(); - return ret; -} - void STObject::add(Serializer& s) const { BOOST_FOREACH(const SerializedType& it, mData) @@ -295,9 +266,9 @@ bool STObject::isFieldPresent(SOE_Field field) const bool STObject::setFlag(uint32 f) { - if (mFlagIdx < 0) return false; - STUInt32* t = dynamic_cast(getPIndex(mFlagIdx)); - assert(t); + STUInt32* t = dynamic_cast(getPField(sfFlags)); + if (!t) + return false; t->setValue(t->getValue() | f); return true; } @@ -305,17 +276,18 @@ bool STObject::setFlag(uint32 f) bool STObject::clearFlag(uint32 f) { if (mFlagIdx < 0) return false; - STUInt32* t = dynamic_cast(getPIndex(mFlagIdx)); - assert(t); + STUInt32* t = dynamic_cast(getPField(sfFlags)); + if (!t) + return false; t->setValue(t->getValue() & ~f); return true; } uint32 STObject::getFlags(void) const { - if (mFlagIdx < 0) return 0; - const STUInt32* t = dynamic_cast(peekAtPIndex(mFlagIdx)); - assert(t); + const STUInt32* t = dynamic_cast(peekAtPField(mFlagIdx)); + if (!t) + return 0; return t->getValue(); } diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 3ff352a793..f4f372ac5d 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -9,56 +9,30 @@ #include "SerializedTypes.h" -enum SOE_Type -{ - SOE_NEVER = -1, // never occurs (marks end of object) - SOE_REQUIRED = 0, // required - SOE_FLAGS = 1, // flags field - SOE_IFFLAG = 2, // present if flag set - SOE_IFNFLAG = 3 // present if flag not set -}; - -enum SOE_Field -{ - sfInvalid = -1, - sfGeneric = 0, - -#define FIELD(name, type, index) sf##name, -#define TYPE(name, type, index) -#include "SerializeProto.h" -#undef FIELD -#undef TYPE - - // test fields - sfTest1, sfTest2, sfTest3, sfTest4 -}; +// Serializable object/array types struct SOElement { // An element in the description of a serialized object SOE_Field e_field; - const char *e_name; - SerializedTypeID e_id; - SOE_Type e_type; - int e_flags; + SOE_Flags flags; }; class STObject : public SerializedType { protected: - int mFlagIdx; // the offset to the flags object, -1 if none boost::ptr_vector mData; std::vector mType; STObject* duplicate() const { return new STObject(*this); } public: - STObject(const char *n = NULL) : SerializedType(n), mFlagIdx(-1) { ; } - STObject(const SOElement *t, const char *n = NULL); - STObject(const SOElement *t, SerializerIterator& u, const char *n = NULL); + STObject(FieldName *n = NULL) : SerializedType(n) { ; } + STObject(const SOElement *t, FieldName *n = NULL); + STObject(const SOElement *t, SerializerIterator& u, FieldName *n = NULL); virtual ~STObject() { ; } void set(const SOElement* t); - void set(const SOElement* t, SerializerIterator& u); + void set(const SOElement* t, SerializerIterator& u, int depth = 0); int getLength() const; virtual SerializedTypeID getSType() const { return STI_OBJECT; } @@ -133,13 +107,71 @@ public: SerializedType* makeFieldPresent(SOE_Field field); void makeFieldAbsent(SOE_Field field); - static std::auto_ptr makeDefaultObject(SerializedTypeID id, const char *name); - static std::auto_ptr makeDeserializedObject(SerializedTypeID id, const char *name, - SerializerIterator&); + static std::auto_ptr makeDefaultObject(SerializedTypeID id, FieldName *name); + static std::auto_ptr makeDeserializedObject(SerializedTypeID id, FieldName *name, + SerializerIterator&, int depth); static void unitTest(); }; +class STArray : public SerializedType +{ +public: + typedef std::vector vector; + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + typedef std::vector::reverse_iterator reverse_iterator; + typedef std::vector::const_reverse_iterator const_reverse_iterator; + typedef std::vector::size_type size_type; + +protected: + + vector value; + + STArray* duplicate() const { return new STArray(fName, value); } + static STArray* construct(SerializerIterator&, FieldName* name = NULL); + +public: + + STArray() { ; } + STArray(FieldName* f, const vector& v) : SerializedType(f), value(v) { ; } + STArray(vector& v) : value(v) { ; } + + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + { return std::auto_ptr(construct(sit, name)); } + + const vector& getValue() const { return value; } + vector& getValue() { return value; } + + // vector-like functions + void push_back(const STObject& object) { value.push_back(object); } + STObject& operator[](int j) { return value[j]; } + const STObject& operator[](int j) const { return value[j]; } + iterator begin() { return value.begin(); } + const_iterator begin() const { return value.begin(); } + iterator end() { return value.end(); } + const_iterator end() const { return value.end(); } + size_type size() const { return value.size(); } + reverse_iterator rbegin() { return value.rbegin(); } + const_reverse_iterator rbegin() const { return value.rbegin(); } + reverse_iterator rend() { return value.rend(); } + const_reverse_iterator rend() const { return value.rend(); } + iterator erase(iterator pos) { return value.erase(pos); } + void pop_back() { value.pop_back(); } + bool empty() const { return value.empty(); } + void clear() { value.clear(); } + + virtual std::string getFullText() const; + virtual std::string getText() const; + virtual Json::Value getJson(int) const; + virtual void add(Serializer& s) const; + + bool operator==(const STArray &s) { return value == s.value; } + bool operator!=(const STArray &s) { return value != s.value; } + + virtual SerializedTypeID getSType() const { return STI_ARRAY; } + virtual bool isEquivalent(const SerializedType& t) const; +}; #endif // vim:ts=4 diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index dde47265c0..25339b92e7 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -17,9 +17,9 @@ std::string SerializedType::getFullText() const std::string ret; if (getSType() != STI_NOTPRESENT) { - if(name != NULL) + if(fName != NULL) { - ret = name; + ret = fName->fieldName; ret += " = "; } ret += getText(); @@ -27,7 +27,7 @@ std::string SerializedType::getFullText() const return ret; } -STUInt8* STUInt8::construct(SerializerIterator& u, const char *name) +STUInt8* STUInt8::construct(SerializerIterator& u, FieldName* name) { return new STUInt8(name, u.get8()); } @@ -43,7 +43,7 @@ bool STUInt8::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STUInt16* STUInt16::construct(SerializerIterator& u, const char *name) +STUInt16* STUInt16::construct(SerializerIterator& u, FieldName* name) { return new STUInt16(name, u.get16()); } @@ -59,7 +59,7 @@ bool STUInt16::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STUInt32* STUInt32::construct(SerializerIterator& u, const char *name) +STUInt32* STUInt32::construct(SerializerIterator& u, FieldName* name) { return new STUInt32(name, u.get32()); } @@ -75,7 +75,7 @@ bool STUInt32::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STUInt64* STUInt64::construct(SerializerIterator& u, const char *name) +STUInt64* STUInt64::construct(SerializerIterator& u, FieldName* name) { return new STUInt64(name, u.get64()); } @@ -91,7 +91,7 @@ bool STUInt64::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STHash128* STHash128::construct(SerializerIterator& u, const char *name) +STHash128* STHash128::construct(SerializerIterator& u, FieldName* name) { return new STHash128(name, u.get128()); } @@ -107,7 +107,7 @@ bool STHash128::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STHash160* STHash160::construct(SerializerIterator& u, const char *name) +STHash160* STHash160::construct(SerializerIterator& u, FieldName* name) { return new STHash160(name, u.get160()); } @@ -123,7 +123,7 @@ bool STHash160::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STHash256* STHash256::construct(SerializerIterator& u, const char *name) +STHash256* STHash256::construct(SerializerIterator& u, FieldName* name) { return new STHash256(name, u.get256()); } @@ -139,7 +139,7 @@ bool STHash256::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STVariableLength::STVariableLength(SerializerIterator& st, const char *name) : SerializedType(name) +STVariableLength::STVariableLength(SerializerIterator& st, FieldName* name) : SerializedType(name) { value = st.getVL(); } @@ -149,16 +149,11 @@ std::string STVariableLength::getText() const return strHex(value); } -STVariableLength* STVariableLength::construct(SerializerIterator& u, const char *name) +STVariableLength* STVariableLength::construct(SerializerIterator& u, FieldName* name) { return new STVariableLength(name, u.getVL()); } -int STVariableLength::getLength() const -{ - return Serializer::encodeLengthLength(value.size()) + value.size(); -} - bool STVariableLength::isEquivalent(const SerializedType& t) const { const STVariableLength* v = dynamic_cast(&t); @@ -176,7 +171,7 @@ std::string STAccount::getText() const return a.humanAccountID(); } -STAccount* STAccount::construct(SerializerIterator& u, const char *name) +STAccount* STAccount::construct(SerializerIterator& u, FieldName* name) { return new STAccount(name, u.getVL()); } @@ -186,7 +181,7 @@ STAccount* STAccount::construct(SerializerIterator& u, const char *name) // // Return a new object from a SerializerIterator. -STVector256* STVector256::construct(SerializerIterator& u, const char *name) +STVector256* STVector256::construct(SerializerIterator& u, FieldName* name) { std::vector data = u.getVL(); std::vector value; @@ -255,7 +250,7 @@ void STAccount::setValueNCA(const NewcoinAddress& nca) setValueH160(nca.getAccountID()); } -STPathSet* STPathSet::construct(SerializerIterator& s, const char *name) +STPathSet* STPathSet::construct(SerializerIterator& s, FieldName* name) { std::vector paths; std::vector path; @@ -342,18 +337,6 @@ int STPath::getSerializeSize() const return iBytes; } -int STPathSet::getLength() const -{ - int iBytes = 0; - - BOOST_FOREACH(const STPath& spPath, value) - { - iBytes += spPath.getSerializeSize(); - } - - return iBytes ? iBytes : 1; -} - Json::Value STPath::getJson(int) const { Json::Value ret(Json::arrayValue); diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 28a3063677..f31a468d85 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -8,28 +8,13 @@ #include "uint256.h" #include "Serializer.h" +#include "FieldNames.h" -enum SerializedTypeID -{ - // special types - STI_DONE = -1, - STI_NOTPRESENT = 0, - -#define TYPE(name, field, value) STI_##field = value, -#define FIELD(name, field, value) -#include "SerializeProto.h" -#undef TYPE -#undef FIELD - - // high level types - STI_TRANSACTION = 100001, - STI_LEDGERENTRY = 100002 -}; enum PathFlags { PF_END = 0x00, // End of current path & path list. - PF_BOUNDRY = 0xFF, // End of current path & new path follows. + PF_BOUNDARY = 0xFF, // End of current path & new path follows. PF_ACCOUNT = 0x01, PF_OFFER = 0x02, @@ -48,24 +33,24 @@ enum PathFlags class SerializedType { protected: - const char* name; + FieldName* fName; - virtual SerializedType* duplicate() const { return new SerializedType(name); } + virtual SerializedType* duplicate() const { return new SerializedType(fName); } public: - SerializedType() : name(NULL) { ; } - SerializedType(const char* n) : name(n) { ; } - SerializedType(const SerializedType& n) : name(n.name) { ; } + SerializedType() : fName(NULL) { ; } + SerializedType(FieldName* n) : fName(n) { ; } + SerializedType(const SerializedType& n) : fName(n.fName) { ; } virtual ~SerializedType() { ; } - static std::auto_ptr deserialize(const char* name) + static std::auto_ptr deserialize(FieldName* name) { return std::auto_ptr(new SerializedType(name)); } - void setName(const char* n) { name=n; } - const char *getName() const { return name; } + void setFName(FieldName* n) { fName=n; } + FieldName* getFName() { return fName; } + const char *getName() const { return (fName != NULL) ? fName->fieldName : NULL; } - virtual int getLength() const { return 0; } virtual SerializedTypeID getSType() const { return STI_NOTPRESENT; } std::auto_ptr clone() const { return std::auto_ptr(duplicate()); } @@ -81,7 +66,7 @@ public: { assert(getSType() == STI_NOTPRESENT); return t.getSType() == STI_NOTPRESENT; } SerializedType& operator=(const SerializedType& t) - { name = (name == NULL) ? t.name : name; return *this; } + { if (fName == NULL) fName = t.fName; return *this; } bool operator==(const SerializedType& t) const { return (getSType() == t.getSType()) && isEquivalent(t); } bool operator!=(const SerializedType& t) const @@ -97,23 +82,22 @@ class STUInt8 : public SerializedType protected: unsigned char value; - STUInt8* duplicate() const { return new STUInt8(name, value); } - static STUInt8* construct(SerializerIterator&, const char* name = NULL); + STUInt8* duplicate() const { return new STUInt8(fName, value); } + static STUInt8* construct(SerializerIterator&, FieldName* name = NULL); public: STUInt8(unsigned char v=0) : value(v) { ; } - STUInt8(const char* n, unsigned char v=0) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + STUInt8(FieldName* n, unsigned char v=0) : SerializedType(n), value(v) { ; } + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } - int getLength() const { return 1; } SerializedTypeID getSType() const { return STI_UINT8; } std::string getText() const; void add(Serializer& s) const { s.add8(value); } unsigned char getValue() const { return value; } - void setValue(unsigned char v) { value=v; } + void setValue(unsigned char v) { value = v; } operator unsigned char() const { return value; } virtual bool isEquivalent(const SerializedType& t) const; @@ -124,17 +108,16 @@ class STUInt16 : public SerializedType protected: uint16 value; - STUInt16* duplicate() const { return new STUInt16(name, value); } - static STUInt16* construct(SerializerIterator&, const char* name = NULL); + STUInt16* duplicate() const { return new STUInt16(fName, value); } + static STUInt16* construct(SerializerIterator&, FieldName* name = NULL); public: STUInt16(uint16 v=0) : value(v) { ; } - STUInt16(const char* n, uint16 v=0) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + STUInt16(FieldName* n, uint16 v=0) : SerializedType(n), value(v) { ; } + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } - int getLength() const { return 2; } SerializedTypeID getSType() const { return STI_UINT16; } std::string getText() const; void add(Serializer& s) const { s.add16(value); } @@ -151,17 +134,16 @@ class STUInt32 : public SerializedType protected: uint32 value; - STUInt32* duplicate() const { return new STUInt32(name, value); } - static STUInt32* construct(SerializerIterator&, const char* name = NULL); + STUInt32* duplicate() const { return new STUInt32(fName, value); } + static STUInt32* construct(SerializerIterator&, FieldName* name = NULL); public: STUInt32(uint32 v=0) : value(v) { ; } - STUInt32(const char* n, uint32 v=0) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + STUInt32(FieldName* n, uint32 v=0) : SerializedType(n), value(v) { ; } + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } - int getLength() const { return 4; } SerializedTypeID getSType() const { return STI_UINT32; } std::string getText() const; void add(Serializer& s) const { s.add32(value); } @@ -178,17 +160,16 @@ class STUInt64 : public SerializedType protected: uint64 value; - STUInt64* duplicate() const { return new STUInt64(name, value); } - static STUInt64* construct(SerializerIterator&, const char* name = NULL); + STUInt64* duplicate() const { return new STUInt64(fName, value); } + static STUInt64* construct(SerializerIterator&, FieldName* name = NULL); public: STUInt64(uint64 v=0) : value(v) { ; } - STUInt64(const char* n, uint64 v=0) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + STUInt64(FieldName* n, uint64 v=0) : SerializedType(n), value(v) { ; } + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } - int getLength() const { return 8; } SerializedTypeID getSType() const { return STI_UINT64; } std::string getText() const; void add(Serializer& s) const { s.add64(value); } @@ -224,7 +205,7 @@ protected: void canonicalize(); STAmount* duplicate() const { return new STAmount(*this); } - static STAmount* construct(SerializerIterator&, const char* name = NULL); + static STAmount* construct(SerializerIterator&, FieldName* name = NULL); static const int cMinOffset = -96, cMaxOffset = 80; static const uint64 cMinValue = 1000000000000000ull, cMaxValue = 9999999999999999ull; @@ -234,10 +215,10 @@ protected: STAmount(bool isNeg, uint64 value) : mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNeg) { ; } - STAmount(const char *name, uint64 value, bool isNegative) - : SerializedType(name), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative) + STAmount(FieldName *name, uint64 value, bool isNegative) + : SerializedType(fName), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative) { ; } - STAmount(const char *n, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg) + STAmount(FieldName *n, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg) : SerializedType(n), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off), mIsNative(isNat), mIsNegative(isNeg) { ; } @@ -250,7 +231,7 @@ public: STAmount(uint64 v = 0, bool isNeg = false) : mValue(v), mOffset(0), mIsNative(true), mIsNegative(isNeg) { if (v==0) mIsNegative = false; } - STAmount(const char* n, uint64 v = 0) + STAmount(FieldName* n, uint64 v = 0) : SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false) { ; } @@ -259,14 +240,14 @@ public: { canonicalize(); } // YYY This should probably require issuer too. - STAmount(const char* n, const uint160& currency, const uint160& issuer, + STAmount(FieldName* n, const uint160& currency, const uint160& issuer, uint64 v = 0, int off = 0, bool isNeg = false) : SerializedType(n), mCurrency(currency), mIssuer(issuer), mValue(v), mOffset(off), mIsNegative(isNeg) { canonicalize(); } - STAmount(const char* n, int64 v); + STAmount(FieldName* n, int64 v); - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } static STAmount saFromRate(uint64 uRate = 0) @@ -279,7 +260,6 @@ public: return STAmount(uCurrencyID, uIssuerID, iV < 0 ? -iV : iV, iOff, iV < 0); } - int getLength() const { return mIsNative ? 8 : 28; } SerializedTypeID getSType() const { return STI_AMOUNT; } std::string getText() const; std::string getRaw() const; @@ -377,7 +357,7 @@ public: // Native currency conversions, to/from display format static uint64 convertToDisplayAmount(const STAmount& internalAmount, uint64 totalNow, uint64 totalInit); static STAmount convertToInternalAmount(uint64 displayAmount, uint64 totalNow, uint64 totalInit, - const char* name = NULL); + FieldName* name = NULL); static std::string createHumanCurrency(const uint160& uCurrency); static STAmount deserialize(SerializerIterator&); @@ -394,19 +374,18 @@ class STHash128 : public SerializedType protected: uint128 value; - STHash128* duplicate() const { return new STHash128(name, value); } - static STHash128* construct(SerializerIterator&, const char* name = NULL); + STHash128* duplicate() const { return new STHash128(fName, value); } + static STHash128* construct(SerializerIterator&, FieldName* name = NULL); public: STHash128(const uint128& v) : value(v) { ; } - STHash128(const char* n, const uint128& v) : SerializedType(n), value(v) { ; } - STHash128(const char* n) : SerializedType(n) { ; } + STHash128(FieldName* n, const uint128& v) : SerializedType(n), value(v) { ; } + STHash128(FieldName* n) : SerializedType(n) { ; } STHash128() { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } - int getLength() const { return 20; } SerializedTypeID getSType() const { return STI_HASH128; } virtual std::string getText() const; void add(Serializer& s) const { s.add128(value); } @@ -423,19 +402,18 @@ class STHash160 : public SerializedType protected: uint160 value; - STHash160* duplicate() const { return new STHash160(name, value); } - static STHash160* construct(SerializerIterator&, const char* name = NULL); + STHash160* duplicate() const { return new STHash160(fName, value); } + static STHash160* construct(SerializerIterator&, FieldName* name = NULL); public: STHash160(const uint160& v) : value(v) { ; } - STHash160(const char* n, const uint160& v) : SerializedType(n), value(v) { ; } - STHash160(const char* n) : SerializedType(n) { ; } + STHash160(FieldName* n, const uint160& v) : SerializedType(n), value(v) { ; } + STHash160(FieldName* n) : SerializedType(n) { ; } STHash160() { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } - int getLength() const { return 20; } SerializedTypeID getSType() const { return STI_HASH160; } virtual std::string getText() const; void add(Serializer& s) const { s.add160(value); } @@ -452,19 +430,18 @@ class STHash256 : public SerializedType protected: uint256 value; - STHash256* duplicate() const { return new STHash256(name, value); } - static STHash256* construct(SerializerIterator&, const char* name = NULL); + STHash256* duplicate() const { return new STHash256(fName, value); } + static STHash256* construct(SerializerIterator&, FieldName* name = NULL); public: STHash256(const uint256& v) : value(v) { ; } - STHash256(const char* n, const uint256& v) : SerializedType(n), value(v) { ; } - STHash256(const char* n) : SerializedType(n) { ; } + STHash256(FieldName* n, const uint256& v) : SerializedType(n), value(v) { ; } + STHash256(FieldName* n) : SerializedType(n) { ; } STHash256() { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } - int getLength() const { return 32; } SerializedTypeID getSType() const { return STI_HASH256; } std::string getText() const; void add(Serializer& s) const { s.add256(value); } @@ -481,20 +458,19 @@ class STVariableLength : public SerializedType protected: std::vector value; - virtual STVariableLength* duplicate() const { return new STVariableLength(name, value); } - static STVariableLength* construct(SerializerIterator&, const char* name = NULL); + virtual STVariableLength* duplicate() const { return new STVariableLength(fName, value); } + static STVariableLength* construct(SerializerIterator&, FieldName* name = NULL); public: STVariableLength(const std::vector& v) : value(v) { ; } - STVariableLength(const char* n, const std::vector& v) : SerializedType(n), value(v) { ; } - STVariableLength(const char* n) : SerializedType(n) { ; } - STVariableLength(SerializerIterator&, const char* name = NULL); + STVariableLength(FieldName* n, const std::vector& v) : SerializedType(n), value(v) { ; } + STVariableLength(FieldName* n) : SerializedType(n) { ; } + STVariableLength(SerializerIterator&, FieldName* name = NULL); STVariableLength() { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } - int getLength() const; virtual SerializedTypeID getSType() const { return STI_VL; } virtual std::string getText() const; void add(Serializer& s) const { s.addVL(value); } @@ -511,16 +487,16 @@ public: class STAccount : public STVariableLength { protected: - virtual STAccount* duplicate() const { return new STAccount(name, value); } - static STAccount* construct(SerializerIterator&, const char* name = NULL); + virtual STAccount* duplicate() const { return new STAccount(fName, value); } + static STAccount* construct(SerializerIterator&, FieldName* name = NULL); public: STAccount(const std::vector& v) : STVariableLength(v) { ; } - STAccount(const char* n, const std::vector& v) : STVariableLength(n, v) { ; } - STAccount(const char* n) : STVariableLength(n) { ; } + STAccount(FieldName* n, const std::vector& v) : STVariableLength(n, v) { ; } + STAccount(FieldName* n) : STVariableLength(n) { ; } STAccount() { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } SerializedTypeID getSType() const { return STI_ACCOUNT; } @@ -649,19 +625,18 @@ class STPathSet : public SerializedType protected: std::vector value; - STPathSet* duplicate() const { return new STPathSet(name, value); } - static STPathSet* construct(SerializerIterator&, const char* name = NULL); + STPathSet* duplicate() const { return new STPathSet(fName, value); } + static STPathSet* construct(SerializerIterator&, FieldName* name = NULL); public: STPathSet() { ; } - STPathSet(const char* n) : SerializedType(n) { ; } + STPathSet(FieldName* n) : SerializedType(n) { ; } STPathSet(const std::vector& v) : value(v) { ; } - STPathSet(const char* n, const std::vector& v) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + STPathSet(FieldName* n, const std::vector& v) : SerializedType(n), value(v) { ; } + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } - int getLength() const; // std::string getText() const; void add(Serializer& s) const; virtual Json::Value getJson(int) const; @@ -722,20 +697,19 @@ class STVector256 : public SerializedType protected: std::vector mValue; - STVector256* duplicate() const { return new STVector256(name, mValue); } - static STVector256* construct(SerializerIterator&, const char* name = NULL); + STVector256* duplicate() const { return new STVector256(fName, mValue); } + static STVector256* construct(SerializerIterator&, FieldName* name = NULL); public: STVector256() { ; } - STVector256(const char* n) : SerializedType(n) { ; } - STVector256(const char* n, const std::vector& v) : SerializedType(n), mValue(v) { ; } + STVector256(FieldName* n) : SerializedType(n) { ; } + STVector256(FieldName* n, const std::vector& v) : SerializedType(n), mValue(v) { ; } STVector256(const std::vector& vector) : mValue(vector) { ; } SerializedTypeID getSType() const { return STI_VECTOR256; } - int getLength() const { return Serializer::lengthVL(mValue.size() * (256 / 8)); } void add(Serializer& s) const; - static std::auto_ptr deserialize(SerializerIterator& sit, const char* name) + static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) { return std::auto_ptr(construct(sit, name)); } const std::vector& peekValue() const { return mValue; } diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 3ab00f7dea..a23d82320c 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -1,134 +1,132 @@ -#include "TransactionFormats.h" +#include "TransactionFormats.h" -#define S_FIELD(x) sf##x, #x - -TransactionFormat InnerTxnFormats[]= +TransactionFormat InnerTxnFormats[]= { - { "AccountSet", ttACCOUNT_SET, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(EmailHash), STI_HASH128, SOE_IFFLAG, 2 }, - { S_FIELD(WalletLocator), STI_HASH256, SOE_IFFLAG, 4 }, - { S_FIELD(MessageKey), STI_VL, SOE_IFFLAG, 8 }, - { S_FIELD(Domain), STI_VL, SOE_IFFLAG, 16 }, - { S_FIELD(TransferRate), STI_UINT32, SOE_IFFLAG, 32 }, - { S_FIELD(PublishHash), STI_HASH256, SOE_IFFLAG, 64 }, - { S_FIELD(PublishSize), STI_UINT32, SOE_IFFLAG, 128 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, - { "Claim", ttCLAIM, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, - { "CreditSet", ttCREDIT_SET, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(LimitAmount), STI_AMOUNT, SOE_IFFLAG, 2 }, - { S_FIELD(QualityIn), STI_UINT32, SOE_IFFLAG, 4 }, - { S_FIELD(QualityOut), STI_UINT32, SOE_IFFLAG, 8 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, + { "AccountSet", ttACCOUNT_SET, { + { sfFlags, SOE_REQUIRED }, + { sfSourceTag, SOE_OPTIONAL }, + { sfEmailHash, SOE_OPTIONAL }, + { sfWalletLocator, SOE_OPTIONAL }, + { sfMessageKey, SOE_OPTIONAL }, + { sfDomain, SOE_OPTIONAL }, + { sfTransferRate, SOE_OPTIONAL }, + { sfPublishHash, SOE_OPTIONAL }, + { sfPublishSize, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, + { "Claim", ttCLAIM, { + { sfFlags, SOE_REQUIRED }, + { sfGenerator, SOE_REQUIRED }, + { sfPublicKey, SOE_REQUIRED }, + { sfSignature, SOE_REQUIRED }, + { sfSourceTag, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, + { "CreditSet", ttCREDIT_SET, { + { sfFlags, SOE_REQUIRED }, + { sfDestination, SOE_REQUIRED }, + { sfSourceTag, SOE_OPTIONAL }, + { sfLimitAmount, SOE_OPTIONAL }, + { sfQualityIn, SOE_OPTIONAL }, + { sfQualityOut, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, /* - { "Invoice", ttINVOICE, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Amount), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Destination), STI_ACCOUNT, SOE_IFFLAG, 2 }, - { S_FIELD(Identifier), STI_VL, SOE_IFFLAG, 4 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, + { "Invoice", ttINVOICE, { + { sfFlags, SOE_REQUIRED }, + { sfTarget, SOE_REQUIRED }, + { sfAmount, SOE_REQUIRED }, + { sfSourceTag, SOE_OPTIONAL }, + { sfDestination, SOE_OPTIONAL }, + { sfIdentifier, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, */ - { "NicknameSet", ttNICKNAME_SET, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Nickname), STI_HASH256, SOE_REQUIRED, 0 }, - { S_FIELD(MinimumOffer), STI_AMOUNT, SOE_IFFLAG, 1 }, - { S_FIELD(Signature), STI_VL, SOE_IFFLAG, 2 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 4 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, - { "OfferCreate", ttOFFER_CREATE, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(TakerPays), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(TakerGets), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(Expiration), STI_UINT32, SOE_IFFLAG, 2 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, - { "OfferCancel", ttOFFER_CANCEL, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(OfferSequence), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, - { "PasswordFund", ttPASSWORD_FUND, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, - { "PasswordSet", ttPASSWORD_SET, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Generator), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, - { "Payment", ttPAYMENT, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(Amount), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(SendMax), STI_AMOUNT, SOE_IFFLAG, 1 }, - { S_FIELD(Paths), STI_PATHSET, SOE_IFFLAG, 2 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 4 }, - { S_FIELD(InvoiceID), STI_HASH256, SOE_IFFLAG, 8 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, - { "WalletAdd", ttWALLET_ADD, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Amount), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(AuthorizedKey), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(PublicKey), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(Signature), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, - { "Contract", ttCONTRACT, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Expiration), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(BondAmount), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(StampEscrow), STI_UINT32, SOE_REQUIRED, 0 }, - { S_FIELD(RippleEscrow), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(CreateCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(FundCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(RemoveCode), STI_VL, SOE_REQUIRED, 0 }, - { S_FIELD(ExpireCode), STI_VL, SOE_REQUIRED, 0 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, - { "Contract", ttCONTRACT_REMOVE, { - { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Target), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } - }, + { "NicknameSet", ttNICKNAME_SET, { + { sfFlags, SOE_REQUIRED }, + { sfNickname, SOE_REQUIRED }, + { sfMinimumOffer, SOE_OPTIONAL }, + { sfSignature, SOE_OPTIONAL }, + { sfSourceTag, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, + { "OfferCreate", ttOFFER_CREATE, { + { sfFlags, SOE_REQUIRED}, + { sfTakerPays, SOE_REQUIRED }, + { sfTakerGets, SOE_REQUIRED }, + { sfSourceTag, SOE_OPTIONAL }, + { sfExpiration, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, + { "OfferCancel", ttOFFER_CANCEL, { + { sfFlags, SOE_REQUIRED }, + { sfOfferSequence, SOE_REQUIRED }, + { sfSourceTag, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, + { "PasswordFund", ttPASSWORD_FUND, { + { sfFlags, SOE_REQUIRED }, + { sfDestination, SOE_REQUIRED }, + { sfSourceTag, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, + { "PasswordSet", ttPASSWORD_SET, { + { sfFlags, SOE_REQUIRED }, + { sfAuthorizedKey, SOE_REQUIRED }, + { sfGenerator, SOE_REQUIRED }, + { sfPublicKey, SOE_REQUIRED }, + { sfSignature, SOE_REQUIRED }, + { sfSourceTag, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, + { "Payment", ttPAYMENT, { + { sfFlags, SOE_REQUIRED }, + { sfDestination, SOE_REQUIRED }, + { sfAmount, SOE_REQUIRED }, + { sfSendMax, SOE_OPTIONAL }, + { sfPaths, SOE_OPTIONAL }, + { sfSourceTag, SOE_OPTIONAL }, + { sfInvoiceID, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, + { "WalletAdd", ttWALLET_ADD, { + { sfFlags, SOE_REQUIRED }, + { sfAmount, SOE_REQUIRED }, + { sfAuthorizedKey, SOE_REQUIRED }, + { sfPublicKey, SOE_REQUIRED }, + { sfSignature, SOE_REQUIRED }, + { sfSourceTag, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, + { "Contract", ttCONTRACT, { + { sfFlags, SOE_REQUIRED }, + { sfExpiration, SOE_REQUIRED }, + { sfBondAmount, SOE_REQUIRED }, + { sfStampEscrow, SOE_REQUIRED }, + { sfRippleEscrow, SOE_REQUIRED }, + { sfCreateCode, SOE_OPTIONAL }, + { sfFundCode, SOE_OPTIONAL }, + { sfRemoveCode, SOE_OPTIONAL }, + { sfExpireCode, SOE_OPTIONAL }, + { sfInvalid, SOE_END } } + }, + { "RemoveContract", ttCONTRACT_REMOVE, { + { sfFlags, SOE_REQUIRED }, + { sfTarget, SOE_REQUIRED }, + { sfInvalid, SOE_END } } + }, { NULL, ttINVALID } }; -TransactionFormat* getTxnFormat(TransactionType t) +TransactionFormat* getTxnFormat(TransactionType t) { - TransactionFormat* f = InnerTxnFormats; - while (f->t_name != NULL) + TransactionFormat* f = InnerTxnFormats; + while (f->t_name != NULL) { - if (f->t_type == t) return f; + if (f->t_type == t) return f; ++f; - } - return NULL; + } + return NULL; } -// vim:ts=4 +// vim:ts=4 diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index 72ff3f6e3f..0efaf03397 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -23,9 +23,9 @@ enum TransactionType struct TransactionFormat { - const char *t_name; - TransactionType t_type; - SOElement elements[16]; + const char * t_name; + TransactionType t_type; + SOElement elements[24]; }; const int TransactionISigningPubKey = 0; From 93364999505406755bdb3b9e719f2180498a5c5d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 18:30:27 -0700 Subject: [PATCH 317/426] Cosmetic. --- src/NetworkOPs.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index ed6e7f0471..43b7da9f4e 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -134,8 +134,8 @@ public: // Directory functions // - STVector256 getDirNodeInfo(const uint256& uLedger, const uint256& uRootIndex, - uint64& uNodePrevious, uint64& uNodeNext); + STVector256 getDirNodeInfo(const uint256& uLedger, const uint256& uRootIndex, + uint64& uNodePrevious, uint64& uNodeNext); // // Nickname functions @@ -150,7 +150,6 @@ public: Json::Value getOwnerInfo(const uint256& uLedger, const NewcoinAddress& naAccount); Json::Value getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddress& naAccount); - // raw object operations bool findRawLedger(const uint256& ledgerHash, std::vector& rawLedger); bool findRawTransaction(const uint256& transactionHash, std::vector& rawTransaction); From ab4458ccb0c07fc841e38a3233dedacb599df5a0 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 18:30:49 -0700 Subject: [PATCH 318/426] WS: add ledger_current command. --- src/WSDoor.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index b4394fb956..bea4e7ed27 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -75,7 +75,10 @@ public: Json::Value invokeCommand(const Json::Value& jvRequest); boost::unordered_set parseAccountIds(const Json::Value& jvArray); - // Commands + // Request-Response Commands + void doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest); + + // Streaming Commands void doAccountInfoSubscribe(Json::Value& jvResult, const Json::Value& jvRequest); void doAccountInfoUnsubscribe(Json::Value& jvResult, const Json::Value& jvRequest); void doAccountTransactionSubscribe(Json::Value& jvResult, const Json::Value& jvRequest); @@ -293,6 +296,10 @@ Json::Value WSConnection::invokeCommand(const Json::Value& jvRequest) const char* pCommand; doFuncPtr dfpFunc; } commandsA[] = { + // Request-Response Commands: + { "ledger_current", &WSConnection::doLedgerCurrent }, + + // Streaming commands: { "account_info_subscribe", &WSConnection::doAccountInfoSubscribe }, { "account_info_unsubscribe", &WSConnection::doAccountInfoUnsubscribe }, { "account_transaction_subscribe", &WSConnection::doAccountTransactionSubscribe }, @@ -541,6 +548,11 @@ void WSConnection::doLedgerAccountsUnsubscribe(Json::Value& jvResult, const Json } } +void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest) +{ + jvResult["ledger"] = theApp->getOPs().getCurrentLedgerID(); +} + void WSConnection::doTransactionSubcribe(Json::Value& jvResult, const Json::Value& jvRequest) { if (!theApp->getOPs().subTransaction(this)) From dfd55c15637b696531fd38a6b152b747b7609bf2 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 18:31:56 -0700 Subject: [PATCH 319/426] UT: Add timeout to WS connecting. --- js/remote.js | 115 +++++++++++++++++++++++++++++++--------- test/server.js | 3 ++ test/standalone-test.js | 63 +++++++++++++++++----- 3 files changed, 144 insertions(+), 37 deletions(-) diff --git a/js/remote.js b/js/remote.js index 8903c87472..016679718e 100644 --- a/js/remote.js +++ b/js/remote.js @@ -4,65 +4,132 @@ // http://www.w3.org/TR/websockets/#the-websocket-interface // // YYY Will later provide a network access which use multiple instances of this. +// YYY A better model might be to allow requesting a target state: keep connected or not. // var util = require('util'); var WebSocket = require('ws'); -// YYY This is wrong should not use anything in test directory. -var config = require("../test/config.js"); - // --> trusted: truthy, if remote is trusted -var Remote = function(trusted, websocket_ip, websocket_port) { +var Remote = function(trusted, websocket_ip, websocket_port, trace) { this.trusted = trusted; this.websocket_ip = websocket_ip; this.websocket_port = websocket_port; this.id = 0; + this.trace = trace; }; -var remoteConfig = function(server) { +var remoteConfig = function(config, server) { var serverConfig = config.servers[server]; return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port); }; -// Target state is connectted. -// done(readyState): -// --> readyState: OPEN, CLOSED -Remote.method('connect', function(done, onmessage) { - var url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port); +Remote.method('connect_helper', function() { + var self = this; - console.log("remote: connect: %s", url); + if (this.trace) + console.log("remote: connect: %s", this.url); - this.ws = new WebSocket(url); + this.ws = new WebSocket(this.url); var ws = this.ws; - ws.onopen = function() { - console.log("remote: onopen: %s", ws.readyState); - ws.onclose = undefined; - done(ws.readyState); + ws.onopen = function() { + if (this.trace) + console.log("remote: onopen: %s", ws.readyState); + + ws.onclose = undefined; + ws.onerror = undefined; + + self.done(ws.readyState); }; - // Also covers failure to open. - ws.onclose = function() { - console.log("remote: onclose: %s", ws.readyState); - done(ws.readyState); + ws.onerror = function() { + if (this.trace) + console.log("remote: onerror: %s", ws.readyState); + + ws.onclose = undefined; + + if (self.expire) { + if (this.trace) + console.log("remote: was expired"); + + self.done(ws.readyState); + } + else + { + // Delay and retry. + setTimeout(function() { + if (this.trace) + console.log("remote: retry"); + + self.connect_helper(); + }, 50); // Retry rate 50ms. + } }; - if (onmessage) { - ws.onmessage = onmessage; + // Covers failure to open. + ws.onclose = function() { + if (this.trace) + console.log("remote: onclose: %s", ws.readyState); + + ws.onerror = undefined; + + self.done(ws.readyState); + }; + + if (this.onmessage) { + ws.onmessage = this.onmessage; } }); +// Target state is connectted. +// done(readyState): +// --> readyState: OPEN, CLOSED +Remote.method('connect', function(done, onmessage, timeout) { + var self = this; + + this.url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port); + this.done = done; + + if (onmessage) + this.onmessage = onmessage; + + if (timeout) { + if (this.trace) + console.log("remote: expire: false"); + + this.expire = false; + + setTimeout(function () { + if (this.trace) + console.log("remote: expire: timeout"); + + self.expire = true; + }, timeout); + } + else { + if (this.trace) + console.log("remote: expire: false"); + + this.expire = true; + } + + this.connect_helper(); + +}); + // Target stated is disconnected. Remote.method('disconnect', function(done) { var ws = this.ws; ws.onclose = function() { - console.log("remote: onclose: %s", ws.readyState); - done(ws.readyState); + if (this.trace) + console.log("remote: onclose: %s", ws.readyState); + + done(ws.readyState); }; ws.close(); diff --git a/test/server.js b/test/server.js index 0bd0f582c3..9e20569a58 100644 --- a/test/server.js +++ b/test/server.js @@ -1,4 +1,7 @@ // Manage test servers +// +// YYY Would be nice to be able to hide server output. +// // Provide servers // diff --git a/test/standalone-test.js b/test/standalone-test.js index c50e50154a..b36929eb44 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -5,8 +5,15 @@ var buster = require("buster"); var server = require("./server.js"); var remote = require("../js/remote.js"); +var config = require("./config.js"); -buster.testCase("Check standalone server startup", { +// How long to wait for server to start. +var serverDelay = 1500; + +buster.testRunner.timeout = 5000; + + +buster.testCase("Standalone server startup", { "server start and stop": function(done) { server.start("alpha", function(e) { @@ -19,14 +26,15 @@ buster.testCase("Check standalone server startup", { } }); -buster.testCase("Check websocket connection", { +buster.testCase("WebSocket connection", { 'setUp' : function(done) { server.start("alpha", function(e) { buster.refute(e); done(); - }); + } + ); }, 'tearDown' : @@ -39,24 +47,53 @@ buster.testCase("Check websocket connection", { "websocket connect and disconnect" : function(done) { - var alpha = remote.remoteConfig("alpha"); + var alpha = remote.remoteConfig(config, "alpha"); alpha.connect(function(stat) { - buster.assert(1 == stat); // OPEN + buster.assert(1 == stat); // OPEN alpha.disconnect(function(stat) { - buster.assert(3 == stat); // CLOSED + buster.assert(3 == stat); // CLOSED done(); }); - }); + }, undefined, serverDelay); }, }); -buster.testCase("Check assert", { - "assert" : - function() { - buster.assert(true); - } -}); +// var alpha = remote.remoteConfig("alpha"); +// +// buster.testCase("Websocket commands", { +// 'setUp' : +// function(done) { +// server.start("alpha", +// function(e) { +// buster.refute(e); +// +// alpha.connect(function(stat) { +// buster.assert(1 == stat); // OPEN +// +// done(); +// }); +// }); +// }, +// +// 'tearDown' : +// function(done) { +// alpha.disconnect(function(stat) { +// buster.assert(3 == stat); // CLOSED +// +// server.stop("alpha", function(e) { +// buster.refute(e); +// +// done(); +// }); +// }); +// }, +// +// "assert" : +// function() { +// buster.assert(true); +// } +// }); // vim:ts=4 From 2446db0bbe362c2e1f1575fbb024b5e858d66635 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 25 Sep 2012 19:27:09 -0700 Subject: [PATCH 320/426] More serialization work. --- src/Amount.cpp | 7 +- src/FieldNames.cpp | 50 ++++--------- src/FieldNames.h | 57 +++++++++----- src/LedgerEntrySet.h | 3 +- src/SerializedLedger.h | 66 ++++++++--------- src/SerializedObject.cpp | 16 ++-- src/SerializedObject.h | 100 +++++++++++++------------ src/SerializedTransaction.h | 64 ++++++++-------- src/SerializedTypes.cpp | 24 +++--- src/SerializedTypes.h | 143 ++++++++++++++++++------------------ src/TransactionMeta.cpp | 2 +- 11 files changed, 266 insertions(+), 266 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 56b0104a3b..c9e3e4475c 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -298,7 +298,7 @@ void STAmount::add(Serializer& s) const } } -STAmount::STAmount(FieldName* name, int64 value) : SerializedType(name), mOffset(0), mIsNative(true) +STAmount::STAmount(SField::ref name, int64 value) : SerializedType(name), mOffset(0), mIsNative(true) { if (value >= 0) { @@ -330,7 +330,7 @@ uint64 STAmount::toUInt64() const return mValue | (static_cast(mOffset + 256 + 97) << (64 - 10)); } -STAmount* STAmount::construct(SerializerIterator& sit, FieldName* name) +STAmount* STAmount::construct(SerializerIterator& sit, SField::ref name) { uint64 value = sit.get64(); @@ -882,8 +882,7 @@ uint64 STAmount::convertToDisplayAmount(const STAmount& internalAmount, uint64 t return muldiv(internalAmount.getNValue(), totalInit, totalNow); } -STAmount STAmount::convertToInternalAmount(uint64 displayAmount, uint64 totalNow, uint64 totalInit, - FieldName* name) +STAmount STAmount::convertToInternalAmount(uint64 displayAmount, uint64 totalNow, uint64 totalInit, SField::ref name) { // Convert a display/request currency amount to an internal amount return STAmount(name, muldiv(displayAmount, totalNow, totalInit)); } diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index 72589d0004..c8388ad02d 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -5,49 +5,27 @@ #include -#define FIELD(name, type, index) { sf##name, #name, STI_##type, index }, + +SField sfInvalid(-1), sfGeneric(0); + +#define FIELD(name, type, index) SField sf##name(FIELD_CODE(STI_##type, index), STI_##type, index, naem); #define TYPE(name, type, index) - -FieldName FieldNames[]= -{ #include "SerializeProto.h" - - { sfInvalid, 0, STI_DONE, 0 } -}; - #undef FIELD #undef TYPE -static std::map unknownFieldMap; -static boost::mutex unknownFieldMutex; +static std::map SField::codeToField; +static boost::mutex SField::mapMutex; -FieldName* getFieldName(SOE_Field f) -{ // OPTIMIZEME - for (FieldName* n = FieldNames; n->fieldName != 0; ++n) - if (n->field == f) - return n; - return NULL; -} - -FieldName* getFieldName(int type, int field) -{ // OPTIMIZEME - int f = (type << 16) | field; - for (FieldName* n = FieldNames; n->fieldName != 0; ++n) - if (n->field == f) - return n; +SField::ref SField::getField(int code); +{ if ((type <= 0) || (type >= 256) || (field <= 0) || (field >= 256 - return NULL; + return sfInvalid; + boost::mutex::scoped_lock sl(mapMutex); - boost::mutex::scoped_lock sl(unknownFieldMutex); - std::map it = unknownFieldMap.Find(f); - if (it != unknownFieldMap.end()) - return it->second; + std::map it = unknownFieldMap.Find(code); + if (it != codeToField.end()) + return *(it->second); - FieldName* n = new FieldName(); - n->field = f; - n->fieldName = "unknown"; - n->fieldType = static_cast(type); - n->fieldNum = field; - unknownFieldMap[f] = n; - return n; + return *(new SField(code, static_cast(code>>16), code&0xffff, NULL)); } diff --git a/src/FieldNames.h b/src/FieldNames.h index b056b237fb..db29e0ebdf 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -1,9 +1,14 @@ #ifndef __FIELDNAMES__ #define __FIELDNAMES__ +#include + +#define FIELD_CODE(type, index) ((static_cast(type) << 16) | index) + enum SerializedTypeID { // special types + STI_UNKNOWN = -2, STI_DONE = -1, STI_NOTPRESENT = 0, @@ -26,31 +31,43 @@ enum SOE_Flags SOE_OPTIONAL = 1, // optional }; -enum SOE_Field +class SField { - sfInvalid = -1, - sfGeneric = 0, +public: + typedef const SField& ref; + typedef SField const * ptr; -#define FIELD(name, type, index) sf##name = (STI_##type << 16) | index, +protected: + static std::map codeToField; + static boost::mutex mapMutex; + +public: + + const int fieldCode; // (type<<16)|index + const SerializedTypeID fieldType; // STI_* + const int fieldValue; // Code number for protocol + const char* fieldName; + + SField(int fc, SerializedTypeID tid, int fv, const char* fn) : + fieldCode(fc), fieldType(tid), fieldValue(fv), fieldName(fn) + { codeToField[fc] = this; } + + SField(int fc) : fieldCode(fc), fieldType(STI_UNKNOWN), fieldValue(0), fieldName(NULL) { ; } + + static SField::ref getField(int fieldCode); + static SField::ref getField(SerializedTypeID type, int value) { return getField(FIELD_CODE(type, value)); } + + bool isGeneric() const { return fieldCode == 0; } + bool isInvalid() const { return fieldCode == -1; } + bool isKnown() const { return fieldType != STI_UNKNOWN; } +}; + +extern SField sfInvalid, sfGeneric; + +#define FIELD(name, type, index) extern SField sf##name; #define TYPE(name, type, index) #include "SerializeProto.h" #undef FIELD #undef TYPE - // test fields - sfTest1=100000, sfTest2, sfTest3, sfTest4 -}; - -struct FieldName -{ - SOE_Field field; - const char *fieldName; - SerializedTypeID fieldType; - int fieldNum; -}; - -extern FieldName FieldNames[]; -extern FieldName* getFieldName(SOE_Field); -extern FieldName* getFieldName(int type, int field); - #endif diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 150a5ae891..8a7c926c4e 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -104,7 +104,8 @@ public: 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 rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, + SField::ref sfLow = sfLowQualityIn, SField::ref sfHigh = sfHighQualityIn); uint32 rippleQualityOut(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID) { return rippleQualityIn(uToAccountID, uFromAccountID, uCurrencyID, sfLowQualityOut, sfHighQualityOut); } diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index e60662d2db..813e4dccb9 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -43,25 +43,25 @@ public: uint16 getVersion() const { return mVersion.getValue(); } const LedgerEntryFormat* getFormat() { return mFormat; } - int getIFieldIndex(SOE_Field field) const { return mObject.getFieldIndex(field); } + int getIFieldIndex(SField::ref field) const { return mObject.getFieldIndex(field); } int getIFieldCount() const { return mObject.getCount(); } - const SerializedType& peekIField(SOE_Field field) const { return mObject.peekAtField(field); } - SerializedType& getIField(SOE_Field field) { return mObject.getField(field); } - SOE_Field getIFieldSType(int index) { return mObject.getFieldSType(index); } + const SerializedType& peekIField(SField::ref field) const { return mObject.peekAtField(field); } + SerializedType& getIField(SField::ref field) { return mObject.getField(field); } + SField::ref getIFieldSType(int index) { return mObject.getFieldSType(index); } - std::string getIFieldString(SOE_Field field) const { return mObject.getFieldString(field); } - unsigned char getIFieldU8(SOE_Field field) const { return mObject.getValueFieldU8(field); } - uint16 getIFieldU16(SOE_Field field) const { return mObject.getValueFieldU16(field); } - uint32 getIFieldU32(SOE_Field field) const { return mObject.getValueFieldU32(field); } - uint64 getIFieldU64(SOE_Field field) const { return mObject.getValueFieldU64(field); } - uint128 getIFieldH128(SOE_Field field) const { return mObject.getValueFieldH128(field); } - uint160 getIFieldH160(SOE_Field field) const { return mObject.getValueFieldH160(field); } - uint256 getIFieldH256(SOE_Field field) const { return mObject.getValueFieldH256(field); } - std::vector getIFieldVL(SOE_Field field) const { return mObject.getValueFieldVL(field); } - std::vector getIFieldTL(SOE_Field field) const { return mObject.getValueFieldTL(field); } - NewcoinAddress getIValueFieldAccount(SOE_Field field) const { return mObject.getValueFieldAccount(field); } - STAmount getIValueFieldAmount(SOE_Field field) const { return mObject.getValueFieldAmount(field); } - STVector256 getIFieldV256(SOE_Field field) { return mObject.getValueFieldV256(field); } + std::string getIFieldString(SField::ref field) const { return mObject.getFieldString(field); } + unsigned char getIFieldU8(SField::ref field) const { return mObject.getValueFieldU8(field); } + uint16 getIFieldU16(SField::ref field) const { return mObject.getValueFieldU16(field); } + uint32 getIFieldU32(SField::ref field) const { return mObject.getValueFieldU32(field); } + uint64 getIFieldU64(SField::ref field) const { return mObject.getValueFieldU64(field); } + uint128 getIFieldH128(SField::ref field) const { return mObject.getValueFieldH128(field); } + uint160 getIFieldH160(SField::ref field) const { return mObject.getValueFieldH160(field); } + uint256 getIFieldH256(SField::ref field) const { return mObject.getValueFieldH256(field); } + std::vector getIFieldVL(SField::ref field) const { return mObject.getValueFieldVL(field); } + std::vector getIFieldTL(SField::ref field) const { return mObject.getValueFieldTL(field); } + NewcoinAddress getIValueFieldAccount(SField::ref field) const { return mObject.getValueFieldAccount(field); } + STAmount getIValueFieldAmount(SField::ref field) const { return mObject.getValueFieldAmount(field); } + STVector256 getIFieldV256(SField::ref field) { return mObject.getValueFieldV256(field); } bool isThreadedType(); // is this a ledger entry that can be threaded bool isThreaded(); // is this ledger entry actually threaded @@ -75,28 +75,28 @@ public: bool thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID); std::vector getOwners(); // nodes notified if this node is deleted - void setIFieldU8(SOE_Field field, unsigned char v) { return mObject.setValueFieldU8(field, v); } - void setIFieldU16(SOE_Field field, uint16 v) { return mObject.setValueFieldU16(field, v); } - void setIFieldU32(SOE_Field field, uint32 v) { return mObject.setValueFieldU32(field, v); } - void setIFieldU64(SOE_Field field, uint64 v) { return mObject.setValueFieldU64(field, v); } - void setIFieldH128(SOE_Field field, const uint128& v) { return mObject.setValueFieldH128(field, v); } - void setIFieldH160(SOE_Field field, const uint160& v) { return mObject.setValueFieldH160(field, v); } - void setIFieldH256(SOE_Field field, const uint256& v) { return mObject.setValueFieldH256(field, v); } - void setIFieldVL(SOE_Field field, const std::vector& v) + void setIFieldU8(SField::ref field, unsigned char v) { return mObject.setValueFieldU8(field, v); } + void setIFieldU16(SField::ref field, uint16 v) { return mObject.setValueFieldU16(field, v); } + void setIFieldU32(SField::ref field, uint32 v) { return mObject.setValueFieldU32(field, v); } + void setIFieldU64(SField::ref field, uint64 v) { return mObject.setValueFieldU64(field, v); } + void setIFieldH128(SField::ref field, const uint128& v) { return mObject.setValueFieldH128(field, v); } + void setIFieldH160(SField::ref field, const uint160& v) { return mObject.setValueFieldH160(field, v); } + void setIFieldH256(SField::ref field, const uint256& v) { return mObject.setValueFieldH256(field, v); } + void setIFieldVL(SField::ref field, const std::vector& v) { return mObject.setValueFieldVL(field, v); } - void setIFieldTL(SOE_Field field, const std::vector& v) + void setIFieldTL(SField::ref field, const std::vector& v) { return mObject.setValueFieldTL(field, v); } - void setIFieldAccount(SOE_Field field, const uint160& account) + void setIFieldAccount(SField::ref field, const uint160& account) { return mObject.setValueFieldAccount(field, account); } - void setIFieldAccount(SOE_Field field, const NewcoinAddress& account) + void setIFieldAccount(SField::ref field, const NewcoinAddress& account) { return mObject.setValueFieldAccount(field, account); } - void setIFieldAmount(SOE_Field field, const STAmount& amount) + void setIFieldAmount(SField::ref field, const STAmount& amount) { return mObject.setValueFieldAmount(field, amount); } - void setIFieldV256(SOE_Field field, const STVector256& v) { return mObject.setValueFieldV256(field, v); } + void setIFieldV256(SField::ref field, const STVector256& v) { return mObject.setValueFieldV256(field, v); } - bool getIFieldPresent(SOE_Field field) const { return mObject.isFieldPresent(field); } - void makeIFieldPresent(SOE_Field field) { mObject.makeFieldPresent(field); } - void makeIFieldAbsent(SOE_Field field) { return mObject.makeFieldAbsent(field); } + bool getIFieldPresent(SField::ref field) const { return mObject.isFieldPresent(field); } + void makeIFieldPresent(SField::ref field) { mObject.makeFieldPresent(field); } + void makeIFieldAbsent(SField::ref field) { return mObject.makeFieldAbsent(field); } }; typedef SerializedLedgerEntry SLE; diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index c1167a6d62..d935022cb9 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -8,7 +8,7 @@ #include "Log.h" -std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, FieldName* name) +std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, SField::ref name) { switch(id) { @@ -53,7 +53,7 @@ std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, F } } -std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID id, FieldName* name, +std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID id, SField::ref name, SerializerIterator& sit, int depth) { switch(id) @@ -114,19 +114,19 @@ void STObject::set(const SOElement* elem) { mType.push_back(elem); if (elem->flags == SOE_OPTIONAL) - giveObject(makeDefaultObject(STI_NOTPRESENT, elem->e_name)); + giveObject(makeDefaultObject(STI_NOTPRESENT, elem)); else - giveObject(makeDefaultObject(elem->e_id, elem->e_name)); + giveObject(makeDefaultObject(elem->e_field, elem)); ++elem; } } -STObject::STObject(const SOElement* elem, FieldName* name) : SerializedType(name) +STObject::STObject(const SOElement* elem, SField::ref name) : SerializedType(name) { set(elem); } -void STObject::set(FieldName* name, SerializerIterator& sit, int depth = 0) +void STObject::set(SField::ref name, SerializerIterator& sit, int depth = 0) { mData.empty(); mType.empty(); @@ -139,12 +139,12 @@ void STObject::set(FieldName* name, SerializerIterator& sit, int depth = 0) sit.getFieldID(type, field); if ((type == STI_ARRAY) && (field == 1)) return; - FieldName* fn = getFieldName(type, field); + SField::ref fn = SField::getField(type, field); giveObject(makeDeserializedObject(static_cast type, fn, sit, depth + 1); } } -STObject::STObject(const SOElement* elem, SerializerIterator& sit, FieldName*name) : SerializedType(name) +STObject::STObject(const SOElement* elem, SerializerIterator& sit, SField::refname) : SerializedType(name) { set(elem, sit); } diff --git a/src/SerializedObject.h b/src/SerializedObject.h index f4f372ac5d..491e85a599 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -13,7 +13,7 @@ struct SOElement { // An element in the description of a serialized object - SOE_Field e_field; + SField::ref e_field; SOE_Flags flags; }; @@ -24,13 +24,17 @@ protected: std::vector mType; STObject* duplicate() const { return new STObject(*this); } + static STObject* construct(SerializerIterator&, SField::ref); public: - STObject(FieldName *n = NULL) : SerializedType(n) { ; } - STObject(const SOElement *t, FieldName *n = NULL); - STObject(const SOElement *t, SerializerIterator& u, FieldName *n = NULL); + STObject(SField *n = NULL) : SerializedType(n) { ; } + STObject(const SOElement *t, SField *n = NULL); + STObject(const SOElement *t, SerializerIterator& u, SField *n = NULL); virtual ~STObject() { ; } + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) + { return std::auto_ptr(construct(sit, name)); } + void set(const SOElement* t); void set(const SOElement* t, SerializerIterator& u, int depth = 0); @@ -61,54 +65,54 @@ public: const SerializedType* peekAtPIndex(int offset) const { return &(mData[offset]); } SerializedType* getPIndex(int offset) { return &(mData[offset]); } - int getFieldIndex(SOE_Field field) const; - SOE_Field getFieldSType(int index) const; + int getFieldIndex(SField::ref field) const; + SField::ref getFieldSType(int index) const; - const SerializedType& peekAtField(SOE_Field field) const; - SerializedType& getField(SOE_Field field); - const SerializedType* peekAtPField(SOE_Field field) const; - SerializedType* getPField(SOE_Field field); - const SOElement* getFieldType(SOE_Field field) const; + const SerializedType& peekAtField(SField::ref field) const; + SerializedType& getField(SField::ref field); + const SerializedType* peekAtPField(SField::ref field) const; + SerializedType* getPField(SField::ref field); + const SOElement* getFieldType(SField::ref field) const; // these throw if the field type doesn't match, or return default values if the // field is optional but not present - std::string getFieldString(SOE_Field field) const; - unsigned char getValueFieldU8(SOE_Field field) const; - uint16 getValueFieldU16(SOE_Field field) const; - uint32 getValueFieldU32(SOE_Field field) const; - uint64 getValueFieldU64(SOE_Field field) const; - uint128 getValueFieldH128(SOE_Field field) const; - uint160 getValueFieldH160(SOE_Field field) const; - uint256 getValueFieldH256(SOE_Field field) const; - NewcoinAddress getValueFieldAccount(SOE_Field field) const; - std::vector getValueFieldVL(SOE_Field field) const; - std::vector getValueFieldTL(SOE_Field field) const; - STAmount getValueFieldAmount(SOE_Field field) const; - STPathSet getValueFieldPathSet(SOE_Field field) const; - STVector256 getValueFieldV256(SOE_Field field) const; + std::string getFieldString(SField::ref field) const; + unsigned char getValueFieldU8(SField::ref field) const; + uint16 getValueFieldU16(SField::ref field) const; + uint32 getValueFieldU32(SField::ref field) const; + uint64 getValueFieldU64(SField::ref field) const; + uint128 getValueFieldH128(SField::ref field) const; + uint160 getValueFieldH160(SField::ref field) const; + uint256 getValueFieldH256(SField::ref field) const; + NewcoinAddress getValueFieldAccount(SField::ref field) const; + std::vector getValueFieldVL(SField::ref field) const; + std::vector getValueFieldTL(SField::ref field) const; + STAmount getValueFieldAmount(SField::ref field) const; + STPathSet getValueFieldPathSet(SField::ref field) const; + STVector256 getValueFieldV256(SField::ref field) const; - void setValueFieldU8(SOE_Field field, unsigned char); - void setValueFieldU16(SOE_Field field, uint16); - void setValueFieldU32(SOE_Field field, uint32); - void setValueFieldU64(SOE_Field field, uint64); - void setValueFieldH128(SOE_Field field, const uint128&); - void setValueFieldH160(SOE_Field field, const uint160&); - void setValueFieldH256(SOE_Field field, const uint256&); - void setValueFieldVL(SOE_Field field, const std::vector&); - void setValueFieldTL(SOE_Field field, const std::vector&); - void setValueFieldAccount(SOE_Field field, const uint160&); - void setValueFieldAccount(SOE_Field field, const NewcoinAddress& addr) + void setValueFieldU8(SField::ref field, unsigned char); + void setValueFieldU16(SField::ref field, uint16); + void setValueFieldU32(SField::ref field, uint32); + void setValueFieldU64(SField::ref field, uint64); + void setValueFieldH128(SField::ref field, const uint128&); + void setValueFieldH160(SField::ref field, const uint160&); + void setValueFieldH256(SField::ref field, const uint256&); + void setValueFieldVL(SField::ref field, const std::vector&); + void setValueFieldTL(SField::ref field, const std::vector&); + void setValueFieldAccount(SField::ref field, const uint160&); + void setValueFieldAccount(SField::ref field, const NewcoinAddress& addr) { setValueFieldAccount(field, addr.getAccountID()); } - void setValueFieldAmount(SOE_Field field, const STAmount&); - void setValueFieldPathSet(SOE_Field field, const STPathSet&); - void setValueFieldV256(SOE_Field field, const STVector256& v); + void setValueFieldAmount(SField::ref field, const STAmount&); + void setValueFieldPathSet(SField::ref field, const STPathSet&); + void setValueFieldV256(SField::ref field, const STVector256& v); - bool isFieldPresent(SOE_Field field) const; - SerializedType* makeFieldPresent(SOE_Field field); - void makeFieldAbsent(SOE_Field field); + bool isFieldPresent(SField::ref field) const; + SerializedType* makeFieldPresent(SField::ref field); + void makeFieldAbsent(SField::ref field); - static std::auto_ptr makeDefaultObject(SerializedTypeID id, FieldName *name); - static std::auto_ptr makeDeserializedObject(SerializedTypeID id, FieldName *name, + static std::auto_ptr makeDefaultObject(SerializedTypeID id, SField *name); + static std::auto_ptr makeDeserializedObject(SerializedTypeID id, SField *name, SerializerIterator&, int depth); static void unitTest(); @@ -128,16 +132,16 @@ protected: vector value; - STArray* duplicate() const { return new STArray(fName, value); } - static STArray* construct(SerializerIterator&, FieldName* name = NULL); + STArray* duplicate() const { return new STArray(*this); } + static STArray* construct(SerializerIterator&, SField::ref); public: STArray() { ; } - STArray(FieldName* f, const vector& v) : SerializedType(f), value(v) { ; } + STArray(SField::ref f, const vector& v) : SerializedType(f), value(v) { ; } STArray(vector& v) : value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } const vector& getValue() const { return value; } diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index ee4ffb3ea4..d1278b8645 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -71,50 +71,50 @@ public: void setSequence(uint32); // inner transaction field functions - int getITFieldIndex(SOE_Field field) const; + int getITFieldIndex(SField::ref field) const; int getITFieldCount() const; - const SerializedType& peekITField(SOE_Field field) const; - SerializedType& getITField(SOE_Field field); + const SerializedType& peekITField(SField::ref field) const; + SerializedType& getITField(SField::ref field); // inner transaction field value functions - std::string getITFieldString(SOE_Field field) const { return mInnerTxn.getFieldString(field); } - unsigned char getITFieldU8(SOE_Field field) const { return mInnerTxn.getValueFieldU8(field); } - uint16 getITFieldU16(SOE_Field field) const { return mInnerTxn.getValueFieldU16(field); } - uint32 getITFieldU32(SOE_Field field) const { return mInnerTxn.getValueFieldU32(field); } - uint64 getITFieldU64(SOE_Field field) const { return mInnerTxn.getValueFieldU64(field); } - uint128 getITFieldH128(SOE_Field field) const { return mInnerTxn.getValueFieldH128(field); } - uint160 getITFieldH160(SOE_Field field) const { return mInnerTxn.getValueFieldH160(field); } - uint160 getITFieldAccount(SOE_Field field) const; - uint256 getITFieldH256(SOE_Field field) const { return mInnerTxn.getValueFieldH256(field); } - std::vector getITFieldVL(SOE_Field field) const { return mInnerTxn.getValueFieldVL(field); } - std::vector getITFieldTL(SOE_Field field) const { return mInnerTxn.getValueFieldTL(field); } - STAmount getITFieldAmount(SOE_Field field) const { return mInnerTxn.getValueFieldAmount(field); } - STPathSet getITFieldPathSet(SOE_Field field) const { return mInnerTxn.getValueFieldPathSet(field); } + std::string getITFieldString(SField::ref field) const { return mInnerTxn.getFieldString(field); } + unsigned char getITFieldU8(SField::ref field) const { return mInnerTxn.getValueFieldU8(field); } + uint16 getITFieldU16(SField::ref field) const { return mInnerTxn.getValueFieldU16(field); } + uint32 getITFieldU32(SField::ref field) const { return mInnerTxn.getValueFieldU32(field); } + uint64 getITFieldU64(SField::ref field) const { return mInnerTxn.getValueFieldU64(field); } + uint128 getITFieldH128(SField::ref field) const { return mInnerTxn.getValueFieldH128(field); } + uint160 getITFieldH160(SField::ref field) const { return mInnerTxn.getValueFieldH160(field); } + uint160 getITFieldAccount(SField::ref field) const; + uint256 getITFieldH256(SField::ref field) const { return mInnerTxn.getValueFieldH256(field); } + std::vector getITFieldVL(SField::ref field) const { return mInnerTxn.getValueFieldVL(field); } + std::vector getITFieldTL(SField::ref field) const { return mInnerTxn.getValueFieldTL(field); } + STAmount getITFieldAmount(SField::ref field) const { return mInnerTxn.getValueFieldAmount(field); } + STPathSet getITFieldPathSet(SField::ref field) const { return mInnerTxn.getValueFieldPathSet(field); } - void setITFieldU8(SOE_Field field, unsigned char v) { return mInnerTxn.setValueFieldU8(field, v); } - void setITFieldU16(SOE_Field field, uint16 v) { return mInnerTxn.setValueFieldU16(field, v); } - void setITFieldU32(SOE_Field field, uint32 v) { return mInnerTxn.setValueFieldU32(field, v); } - void setITFieldU64(SOE_Field field, uint32 v) { return mInnerTxn.setValueFieldU64(field, v); } - void setITFieldH128(SOE_Field field, const uint128& v) { return mInnerTxn.setValueFieldH128(field, v); } - void setITFieldH160(SOE_Field field, const uint160& v) { return mInnerTxn.setValueFieldH160(field, v); } - void setITFieldH256(SOE_Field field, const uint256& v) { return mInnerTxn.setValueFieldH256(field, v); } - void setITFieldVL(SOE_Field field, const std::vector& v) + void setITFieldU8(SField::ref field, unsigned char v) { return mInnerTxn.setValueFieldU8(field, v); } + void setITFieldU16(SField::ref field, uint16 v) { return mInnerTxn.setValueFieldU16(field, v); } + void setITFieldU32(SField::ref field, uint32 v) { return mInnerTxn.setValueFieldU32(field, v); } + void setITFieldU64(SField::ref field, uint32 v) { return mInnerTxn.setValueFieldU64(field, v); } + void setITFieldH128(SField::ref field, const uint128& v) { return mInnerTxn.setValueFieldH128(field, v); } + void setITFieldH160(SField::ref field, const uint160& v) { return mInnerTxn.setValueFieldH160(field, v); } + void setITFieldH256(SField::ref field, const uint256& v) { return mInnerTxn.setValueFieldH256(field, v); } + void setITFieldVL(SField::ref field, const std::vector& v) { return mInnerTxn.setValueFieldVL(field, v); } - void setITFieldTL(SOE_Field field, const std::vector& v) + void setITFieldTL(SField::ref field, const std::vector& v) { return mInnerTxn.setValueFieldTL(field, v); } - void setITFieldAccount(SOE_Field field, const uint160& v) + void setITFieldAccount(SField::ref field, const uint160& v) { return mInnerTxn.setValueFieldAccount(field, v); } - void setITFieldAccount(SOE_Field field, const NewcoinAddress& v) + void setITFieldAccount(SField::ref field, const NewcoinAddress& v) { return mInnerTxn.setValueFieldAccount(field, v); } - void setITFieldAmount(SOE_Field field, const STAmount& v) + void setITFieldAmount(SField::ref field, const STAmount& v) { return mInnerTxn.setValueFieldAmount(field, v); } - void setITFieldPathSet(SOE_Field field, const STPathSet& v) + void setITFieldPathSet(SField::ref field, const STPathSet& v) { return mInnerTxn.setValueFieldPathSet(field, v); } // optional field functions - bool getITFieldPresent(SOE_Field field) const; - void makeITFieldPresent(SOE_Field field); - void makeITFieldAbsent(SOE_Field field); + bool getITFieldPresent(SField::ref field) const; + void makeITFieldPresent(SField::ref field); + void makeITFieldAbsent(SField::ref field); std::vector getAffectedAccounts() const; diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 25339b92e7..6eeb0c9120 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -27,7 +27,7 @@ std::string SerializedType::getFullText() const return ret; } -STUInt8* STUInt8::construct(SerializerIterator& u, FieldName* name) +STUInt8* STUInt8::construct(SerializerIterator& u, SField::ref name) { return new STUInt8(name, u.get8()); } @@ -43,7 +43,7 @@ bool STUInt8::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STUInt16* STUInt16::construct(SerializerIterator& u, FieldName* name) +STUInt16* STUInt16::construct(SerializerIterator& u, SField::ref name) { return new STUInt16(name, u.get16()); } @@ -59,7 +59,7 @@ bool STUInt16::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STUInt32* STUInt32::construct(SerializerIterator& u, FieldName* name) +STUInt32* STUInt32::construct(SerializerIterator& u, SField::ref name) { return new STUInt32(name, u.get32()); } @@ -75,7 +75,7 @@ bool STUInt32::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STUInt64* STUInt64::construct(SerializerIterator& u, FieldName* name) +STUInt64* STUInt64::construct(SerializerIterator& u, SField::ref name) { return new STUInt64(name, u.get64()); } @@ -91,7 +91,7 @@ bool STUInt64::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STHash128* STHash128::construct(SerializerIterator& u, FieldName* name) +STHash128* STHash128::construct(SerializerIterator& u, SField::ref name) { return new STHash128(name, u.get128()); } @@ -107,7 +107,7 @@ bool STHash128::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STHash160* STHash160::construct(SerializerIterator& u, FieldName* name) +STHash160* STHash160::construct(SerializerIterator& u, SField::ref name) { return new STHash160(name, u.get160()); } @@ -123,7 +123,7 @@ bool STHash160::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STHash256* STHash256::construct(SerializerIterator& u, FieldName* name) +STHash256* STHash256::construct(SerializerIterator& u, SField::ref name) { return new STHash256(name, u.get256()); } @@ -139,7 +139,7 @@ bool STHash256::isEquivalent(const SerializedType& t) const return v && (value == v->value); } -STVariableLength::STVariableLength(SerializerIterator& st, FieldName* name) : SerializedType(name) +STVariableLength::STVariableLength(SerializerIterator& st, SField::ref name) : SerializedType(name) { value = st.getVL(); } @@ -149,7 +149,7 @@ std::string STVariableLength::getText() const return strHex(value); } -STVariableLength* STVariableLength::construct(SerializerIterator& u, FieldName* name) +STVariableLength* STVariableLength::construct(SerializerIterator& u, SField::ref name) { return new STVariableLength(name, u.getVL()); } @@ -171,7 +171,7 @@ std::string STAccount::getText() const return a.humanAccountID(); } -STAccount* STAccount::construct(SerializerIterator& u, FieldName* name) +STAccount* STAccount::construct(SerializerIterator& u, SField::ref name) { return new STAccount(name, u.getVL()); } @@ -181,7 +181,7 @@ STAccount* STAccount::construct(SerializerIterator& u, FieldName* name) // // Return a new object from a SerializerIterator. -STVector256* STVector256::construct(SerializerIterator& u, FieldName* name) +STVector256* STVector256::construct(SerializerIterator& u, SField::ref name) { std::vector data = u.getVL(); std::vector value; @@ -250,7 +250,7 @@ void STAccount::setValueNCA(const NewcoinAddress& nca) setValueH160(nca.getAccountID()); } -STPathSet* STPathSet::construct(SerializerIterator& s, FieldName* name) +STPathSet* STPathSet::construct(SerializerIterator& s, SField::ref name) { std::vector paths; std::vector path; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index f31a468d85..2085ab38ac 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -33,23 +33,24 @@ enum PathFlags class SerializedType { protected: - FieldName* fName; + SField::ptr fName; - virtual SerializedType* duplicate() const { return new SerializedType(fName); } + virtual SerializedType* duplicate() const { return new SerializedType(*fName); } + SerializedType(SField::ptr n) : fName(n) { assert(fName); } public: - SerializedType() : fName(NULL) { ; } - SerializedType(FieldName* n) : fName(n) { ; } + SerializedType() : fName(&sfGeneric) { ; } + SerializedType(SField::ref n) : fName(&n) { assert(fName); } SerializedType(const SerializedType& n) : fName(n.fName) { ; } virtual ~SerializedType() { ; } - static std::auto_ptr deserialize(FieldName* name) + static std::auto_ptr deserialize(SField::ref name) { return std::auto_ptr(new SerializedType(name)); } - void setFName(FieldName* n) { fName=n; } - FieldName* getFName() { return fName; } - const char *getName() const { return (fName != NULL) ? fName->fieldName : NULL; } + void setFName(SField::ref n) { fName = &n; assert(fName); } + SField::ref getFName() { return *fName; } + const char *getName() const { return fName->fieldName; } virtual SerializedTypeID getSType() const { return STI_NOTPRESENT; } std::auto_ptr clone() const { return std::auto_ptr(duplicate()); } @@ -66,7 +67,7 @@ public: { assert(getSType() == STI_NOTPRESENT); return t.getSType() == STI_NOTPRESENT; } SerializedType& operator=(const SerializedType& t) - { if (fName == NULL) fName = t.fName; return *this; } + { if (!fName->fieldCode) fName = t.fName; return *this; } bool operator==(const SerializedType& t) const { return (getSType() == t.getSType()) && isEquivalent(t); } bool operator!=(const SerializedType& t) const @@ -82,14 +83,14 @@ class STUInt8 : public SerializedType protected: unsigned char value; - STUInt8* duplicate() const { return new STUInt8(fName, value); } - static STUInt8* construct(SerializerIterator&, FieldName* name = NULL); + STUInt8* duplicate() const { return new STUInt8(*this); } + static STUInt8* construct(SerializerIterator&, SField::ref f); public: - STUInt8(unsigned char v=0) : value(v) { ; } - STUInt8(FieldName* n, unsigned char v=0) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + STUInt8(unsigned char v = 0) : value(v) { ; } + STUInt8(SField::ref n, unsigned char v=0) : SerializedType(n), value(v) { ; } + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } SerializedTypeID getSType() const { return STI_UINT8; } @@ -108,14 +109,14 @@ class STUInt16 : public SerializedType protected: uint16 value; - STUInt16* duplicate() const { return new STUInt16(fName, value); } - static STUInt16* construct(SerializerIterator&, FieldName* name = NULL); + STUInt16* duplicate() const { return new STUInt16(*this); } + static STUInt16* construct(SerializerIterator&, SField::ref name); public: STUInt16(uint16 v=0) : value(v) { ; } - STUInt16(FieldName* n, uint16 v=0) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + STUInt16(SField::ref n, uint16 v=0) : SerializedType(n), value(v) { ; } + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } SerializedTypeID getSType() const { return STI_UINT16; } @@ -134,14 +135,14 @@ class STUInt32 : public SerializedType protected: uint32 value; - STUInt32* duplicate() const { return new STUInt32(fName, value); } - static STUInt32* construct(SerializerIterator&, FieldName* name = NULL); + STUInt32* duplicate() const { return new STUInt32(*this); } + static STUInt32* construct(SerializerIterator&, SField::ref name); public: - STUInt32(uint32 v=0) : value(v) { ; } - STUInt32(FieldName* n, uint32 v=0) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + STUInt32(uint32 v = 0) : value(v) { ; } + STUInt32(SField::ref n, uint32 v=0) : SerializedType(n), value(v) { ; } + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } SerializedTypeID getSType() const { return STI_UINT32; } @@ -160,14 +161,14 @@ class STUInt64 : public SerializedType protected: uint64 value; - STUInt64* duplicate() const { return new STUInt64(fName, value); } - static STUInt64* construct(SerializerIterator&, FieldName* name = NULL); + STUInt64* duplicate() const { return new STUInt64(*this); } + static STUInt64* construct(SerializerIterator&, SField::ref name); public: STUInt64(uint64 v=0) : value(v) { ; } - STUInt64(FieldName* n, uint64 v=0) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + STUInt64(SField::ref n, uint64 v=0) : SerializedType(n), value(v) { ; } + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } SerializedTypeID getSType() const { return STI_UINT64; } @@ -205,7 +206,7 @@ protected: void canonicalize(); STAmount* duplicate() const { return new STAmount(*this); } - static STAmount* construct(SerializerIterator&, FieldName* name = NULL); + static STAmount* construct(SerializerIterator&, SField::ref name); static const int cMinOffset = -96, cMaxOffset = 80; static const uint64 cMinValue = 1000000000000000ull, cMaxValue = 9999999999999999ull; @@ -215,10 +216,10 @@ protected: STAmount(bool isNeg, uint64 value) : mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNeg) { ; } - STAmount(FieldName *name, uint64 value, bool isNegative) + STAmount(SField *name, uint64 value, bool isNegative) : SerializedType(fName), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative) { ; } - STAmount(FieldName *n, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg) + STAmount(SField *n, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg) : SerializedType(n), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off), mIsNative(isNat), mIsNegative(isNeg) { ; } @@ -231,7 +232,7 @@ public: STAmount(uint64 v = 0, bool isNeg = false) : mValue(v), mOffset(0), mIsNative(true), mIsNegative(isNeg) { if (v==0) mIsNegative = false; } - STAmount(FieldName* n, uint64 v = 0) + STAmount(SField::ref n, uint64 v = 0) : SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false) { ; } @@ -240,14 +241,14 @@ public: { canonicalize(); } // YYY This should probably require issuer too. - STAmount(FieldName* n, const uint160& currency, const uint160& issuer, + STAmount(SField::ref n, const uint160& currency, const uint160& issuer, uint64 v = 0, int off = 0, bool isNeg = false) : SerializedType(n), mCurrency(currency), mIssuer(issuer), mValue(v), mOffset(off), mIsNegative(isNeg) { canonicalize(); } - STAmount(FieldName* n, int64 v); + STAmount(SField::ref n, int64 v); - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } static STAmount saFromRate(uint64 uRate = 0) @@ -357,7 +358,7 @@ public: // Native currency conversions, to/from display format static uint64 convertToDisplayAmount(const STAmount& internalAmount, uint64 totalNow, uint64 totalInit); static STAmount convertToInternalAmount(uint64 displayAmount, uint64 totalNow, uint64 totalInit, - FieldName* name = NULL); + SField::ref name = sfGeneric); static std::string createHumanCurrency(const uint160& uCurrency); static STAmount deserialize(SerializerIterator&); @@ -374,16 +375,16 @@ class STHash128 : public SerializedType protected: uint128 value; - STHash128* duplicate() const { return new STHash128(fName, value); } - static STHash128* construct(SerializerIterator&, FieldName* name = NULL); + STHash128* duplicate() const { return new STHash128(*this); } + static STHash128* construct(SerializerIterator&, SField::ref name); public: STHash128(const uint128& v) : value(v) { ; } - STHash128(FieldName* n, const uint128& v) : SerializedType(n), value(v) { ; } - STHash128(FieldName* n) : SerializedType(n) { ; } + STHash128(SField::ref n, const uint128& v) : SerializedType(n), value(v) { ; } + STHash128(SField::ref n) : SerializedType(n) { ; } STHash128() { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } SerializedTypeID getSType() const { return STI_HASH128; } @@ -402,16 +403,16 @@ class STHash160 : public SerializedType protected: uint160 value; - STHash160* duplicate() const { return new STHash160(fName, value); } - static STHash160* construct(SerializerIterator&, FieldName* name = NULL); + STHash160* duplicate() const { return new STHash160(*this); } + static STHash160* construct(SerializerIterator&, SField::ref name); public: STHash160(const uint160& v) : value(v) { ; } - STHash160(FieldName* n, const uint160& v) : SerializedType(n), value(v) { ; } - STHash160(FieldName* n) : SerializedType(n) { ; } + STHash160(SField::ref n, const uint160& v) : SerializedType(n), value(v) { ; } + STHash160(SField::ref n) : SerializedType(n) { ; } STHash160() { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } SerializedTypeID getSType() const { return STI_HASH160; } @@ -430,16 +431,16 @@ class STHash256 : public SerializedType protected: uint256 value; - STHash256* duplicate() const { return new STHash256(fName, value); } - static STHash256* construct(SerializerIterator&, FieldName* name = NULL); + STHash256* duplicate() const { return new STHash256(*this); } + static STHash256* construct(SerializerIterator&, SField::ref); public: STHash256(const uint256& v) : value(v) { ; } - STHash256(FieldName* n, const uint256& v) : SerializedType(n), value(v) { ; } - STHash256(FieldName* n) : SerializedType(n) { ; } + STHash256(SField::ref n, const uint256& v) : SerializedType(n), value(v) { ; } + STHash256(SField::ref n) : SerializedType(n) { ; } STHash256() { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } SerializedTypeID getSType() const { return STI_HASH256; } @@ -458,17 +459,17 @@ class STVariableLength : public SerializedType protected: std::vector value; - virtual STVariableLength* duplicate() const { return new STVariableLength(fName, value); } - static STVariableLength* construct(SerializerIterator&, FieldName* name = NULL); + virtual STVariableLength* duplicate() const { return new STVariableLength(*this); } + static STVariableLength* construct(SerializerIterator&, SField::ref); public: STVariableLength(const std::vector& v) : value(v) { ; } - STVariableLength(FieldName* n, const std::vector& v) : SerializedType(n), value(v) { ; } - STVariableLength(FieldName* n) : SerializedType(n) { ; } - STVariableLength(SerializerIterator&, FieldName* name = NULL); + STVariableLength(SField::ref n, const std::vector& v) : SerializedType(n), value(v) { ; } + STVariableLength(SField::ref n) : SerializedType(n) { ; } + STVariableLength(SerializerIterator&, SField::ref name = sfGeneric); STVariableLength() { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } virtual SerializedTypeID getSType() const { return STI_VL; } @@ -487,16 +488,16 @@ public: class STAccount : public STVariableLength { protected: - virtual STAccount* duplicate() const { return new STAccount(fName, value); } - static STAccount* construct(SerializerIterator&, FieldName* name = NULL); + virtual STAccount* duplicate() const { return new STAccount(*this); } + static STAccount* construct(SerializerIterator&, SField::ref); public: STAccount(const std::vector& v) : STVariableLength(v) { ; } - STAccount(FieldName* n, const std::vector& v) : STVariableLength(n, v) { ; } - STAccount(FieldName* n) : STVariableLength(n) { ; } + STAccount(SField::ref n, const std::vector& v) : STVariableLength(n, v) { ; } + STAccount(SField::ref n) : STVariableLength(n) { ; } STAccount() { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } SerializedTypeID getSType() const { return STI_ACCOUNT; } @@ -625,16 +626,16 @@ class STPathSet : public SerializedType protected: std::vector value; - STPathSet* duplicate() const { return new STPathSet(fName, value); } - static STPathSet* construct(SerializerIterator&, FieldName* name = NULL); + STPathSet* duplicate() const { return new STPathSet(*this); } + static STPathSet* construct(SerializerIterator&, SField::ref); public: STPathSet() { ; } - STPathSet(FieldName* n) : SerializedType(n) { ; } + STPathSet(SField::ref n) : SerializedType(n) { ; } STPathSet(const std::vector& v) : value(v) { ; } - STPathSet(FieldName* n, const std::vector& v) : SerializedType(n), value(v) { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + STPathSet(SField::ref n, const std::vector& v) : SerializedType(n), value(v) { ; } + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } // std::string getText() const; @@ -697,19 +698,19 @@ class STVector256 : public SerializedType protected: std::vector mValue; - STVector256* duplicate() const { return new STVector256(fName, mValue); } - static STVector256* construct(SerializerIterator&, FieldName* name = NULL); + STVector256* duplicate() const { return new STVector256(*this); } + static STVector256* construct(SerializerIterator&, SField::ref); public: STVector256() { ; } - STVector256(FieldName* n) : SerializedType(n) { ; } - STVector256(FieldName* n, const std::vector& v) : SerializedType(n), mValue(v) { ; } + STVector256(SField::ref n) : SerializedType(n) { ; } + STVector256(SField::ref n, const std::vector& v) : SerializedType(n), mValue(v) { ; } STVector256(const std::vector& vector) : mValue(vector) { ; } SerializedTypeID getSType() const { return STI_VECTOR256; } void add(Serializer& s) const; - static std::auto_ptr deserialize(SerializerIterator& sit, FieldName* name) + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } const std::vector& peekValue() const { return mValue; } diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index 4c179f0b70..3f687897c1 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -66,7 +66,7 @@ Json::Value TMNEThread::getJson(int) const TMNEAmount::TMNEAmount(int type, SerializerIterator& sit) : TransactionMetaNodeEntry(type) { - mAmount = *dynamic_cast(STAmount::deserialize(sit, NULL).get()); // Ouch + mAmount = *dynamic_cast(STAmount::deserialize(sit, sfAmount).get()); // Ouch } void TMNEAmount::addRaw(Serializer& s) const From 2e5189f276553cd6aaae8c5a35a400e7842ce172 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 19:36:38 -0700 Subject: [PATCH 321/426] JS: Get request-respons and ledger_current working. --- js/remote.js | 56 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/js/remote.js b/js/remote.js index 016679718e..d1fa4430cc 100644 --- a/js/remote.js +++ b/js/remote.js @@ -20,10 +20,10 @@ var Remote = function(trusted, websocket_ip, websocket_port, trace) { this.trace = trace; }; -var remoteConfig = function(config, server) { +var remoteConfig = function(config, server, trace) { var serverConfig = config.servers[server]; - return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port); + return new Remote(serverConfig.trusted, serverConfig.websocket_ip, serverConfig.websocket_port, trace); }; Remote.method('connect_helper', function() { @@ -36,6 +36,8 @@ Remote.method('connect_helper', function() { var ws = this.ws; + ws.response = {}; + ws.onopen = function() { if (this.trace) console.log("remote: onopen: %s", ws.readyState); @@ -80,23 +82,36 @@ Remote.method('connect_helper', function() { self.done(ws.readyState); }; - if (this.onmessage) { - ws.onmessage = this.onmessage; - } + // XXX Why doesn't onmessage work? + ws.on('message', function(json, flags) { + var message = JSON.parse(json); + // console.log("message: %s", json); + + if (message.type !== 'response') { + console.log("unexpected message: %s", json); + + } else { + var done = ws.response[message.id]; + + if (done) { + done(message); + + } else { + console.log("unexpected message id: %s", json); + } + } + }); }); // Target state is connectted. // done(readyState): // --> readyState: OPEN, CLOSED -Remote.method('connect', function(done, onmessage, timeout) { +Remote.method('connect', function(done, timeout) { var self = this; this.url = util.format("ws://%s:%s", this.websocket_ip, this.websocket_port); this.done = done; - if (onmessage) - this.onmessage = onmessage; - if (timeout) { if (this.trace) console.log("remote: expire: false"); @@ -146,14 +161,15 @@ Remote.method('request', function(command, done) { ws.response[command.id] = done; - ws.send(command); + if (this.trace) + console.log("remote: send: %s", JSON.stringify(command)); + + ws.send(JSON.stringify(command)); }); -// Request the current ledger. -// done(index) -// index: undefined = error -Remote.method('ledger', function(done) { - +// Get the current ledger entry (may be live or not). +Remote.method('ledger_current', function(done) { + this.request({ 'command' : 'ledger_current' }, done); }); @@ -166,20 +182,12 @@ Remote.method('submit', function(json, done) { // }); }); -// ==> entry_spec -Remote.method('ledger_entry', function(entry_spec, done) { - entry_spec.command = 'ledger_entry'; - - this.request(entry_spec, function() { - }); -}); - // done(value) // --> value: { 'status', status, 'result' : result, ... } // done may be called up to 3 times. Remote.method('account_root', function(account_id, done) { this.request({ - 'command' : 'ledger_entry', + 'command' : 'ledger_current', }, function() { }); }); From 5a49b696ad1ae6395d04f8300fc37a5fe4bba554 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 25 Sep 2012 19:37:15 -0700 Subject: [PATCH 322/426] UT: Get WS ledger_current test working. --- test/standalone-test.js | 81 ++++++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 37 deletions(-) diff --git a/test/standalone-test.js b/test/standalone-test.js index b36929eb44..2a725dffac 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -12,7 +12,6 @@ var serverDelay = 1500; buster.testRunner.timeout = 5000; - buster.testCase("Standalone server startup", { "server start and stop": function(done) { server.start("alpha", @@ -56,44 +55,52 @@ buster.testCase("WebSocket connection", { buster.assert(3 == stat); // CLOSED done(); }); - }, undefined, serverDelay); + }, serverDelay); }, }); -// var alpha = remote.remoteConfig("alpha"); -// -// buster.testCase("Websocket commands", { -// 'setUp' : -// function(done) { -// server.start("alpha", -// function(e) { -// buster.refute(e); -// -// alpha.connect(function(stat) { -// buster.assert(1 == stat); // OPEN -// -// done(); -// }); -// }); -// }, -// -// 'tearDown' : -// function(done) { -// alpha.disconnect(function(stat) { -// buster.assert(3 == stat); // CLOSED -// -// server.stop("alpha", function(e) { -// buster.refute(e); -// -// done(); -// }); -// }); -// }, -// -// "assert" : -// function() { -// buster.assert(true); -// } -// }); +// XXX Figure out a way to stuff this into the test case. +var alpha; + +buster.testCase("Websocket commands", { + 'setUp' : + function(done) { + server.start("alpha", + function(e) { + buster.refute(e); + + alpha = remote.remoteConfig(config, "alpha"); + + alpha.connect(function(stat) { + buster.assert(1 == stat); // OPEN + + done(); + }, serverDelay); + }); + }, + + 'tearDown' : + function(done) { + alpha.disconnect(function(stat) { + buster.assert(3 == stat); // CLOSED + + server.stop("alpha", function(e) { + buster.refute(e); + + done(); + }); + }); + }, + + "ledger_current" : + function(done) { + alpha.ledger_current(function (r) { + console.log(r); + + buster.assert(r.ledger === 2); + done(); + }); + } +}); // vim:ts=4 From 8a5a9e09258496d73740a7c4dd25fd3cd6fb8958 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 25 Sep 2012 22:47:40 -0700 Subject: [PATCH 323/426] Small fixes. --- src/Serializer.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Serializer.h b/src/Serializer.h index e1c251508c..30dfe1ceb8 100644 --- a/src/Serializer.h +++ b/src/Serializer.h @@ -92,7 +92,7 @@ public: int getDataLength() const { return mData.size(); } const void* getDataPtr() const { return &mData.front(); } void* getDataPtr() { return &mData.front(); } - int getLength() { return mData.size(); } + int getLength() const { return mData.size(); } const std::vector& peekData() const { return mData; } std::vector getData() const { return mData; } std::string getString() const { return std::string(static_cast(getDataPtr()), size()); } @@ -143,11 +143,12 @@ protected: public: SerializerIterator(const Serializer& s) : mSerializer(s), mPos(0) { ; } - void reset(void) { mPos=0; } + void reset(void) { mPos = 0; } void setPos(int p) { mPos = p; } const Serializer& operator*(void) { return mSerializer; } int getPos(void) { return mPos; } + bool empty() { return mPos == mSerializer.getLength(); } int getBytesLeft(); // get functions throw on error From e0587a44b85ef7093232eb412ddffc6057be6174 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 25 Sep 2012 22:47:59 -0700 Subject: [PATCH 324/426] More work on new serializer code. --- src/FieldNames.cpp | 36 ++++++++++++++- src/FieldNames.h | 9 ++++ src/SerializedObject.cpp | 87 +++++++++++++++++++++++++++---------- src/SerializedObject.h | 37 +++++++++++----- src/SerializedTransaction.h | 1 - src/SerializedTypes.h | 2 +- 6 files changed, 134 insertions(+), 38 deletions(-) diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index c8388ad02d..14827bf7f2 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -4,6 +4,7 @@ #include #include +#include SField sfInvalid(-1), sfGeneric(0); @@ -19,13 +20,46 @@ static boost::mutex SField::mapMutex; SField::ref SField::getField(int code); { + int type = code >> 16; + int field = code % 0xffff; + if ((type <= 0) || (type >= 256) || (field <= 0) || (field >= 256 return sfInvalid; + boost::mutex::scoped_lock sl(mapMutex); std::map it = unknownFieldMap.Find(code); if (it != codeToField.end()) return *(it->second); - return *(new SField(code, static_cast(code>>16), code&0xffff, NULL)); + switch(type) + { // types we are willing to dynamically extend + +#define FIELD(name, type, index) +#define TYPE(name, type, index) case sf##name: +#include "SerializeProto.h" +#undef FIELD +#undef TYPE + + break; + default: + return sfInvalid; + } + + return *(new SField(code, static_cast(type), field, NULL)); +} + +SField::ref SField::getField(int type, int value) +{ + return getField(FIELD_CODE(type, value)); +} + +std::string SField::getName() cosnt +{ + if (fieldName != NULL) + return fieldName; + if (fieldValue == 0) + return ""; + return boost::lexical_cast(static_cast(fieldType)) + "/" + + boost::lexical_cast(fieldValue); } diff --git a/src/FieldNames.h b/src/FieldNames.h index db29e0ebdf..4432320447 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -1,6 +1,8 @@ #ifndef __FIELDNAMES__ #define __FIELDNAMES__ +#include + #include #define FIELD_CODE(type, index) ((static_cast(type) << 16) | index) @@ -55,11 +57,18 @@ public: SField(int fc) : fieldCode(fc), fieldType(STI_UNKNOWN), fieldValue(0), fieldName(NULL) { ; } static SField::ref getField(int fieldCode); + static SField::ref getField(int fieldType, int fieldValue); static SField::ref getField(SerializedTypeID type, int value) { return getField(FIELD_CODE(type, value)); } + std::string getName() const; + bool hasName() const { return (fieldName != NULL) || (fieldValue != 0); } + bool isGeneric() const { return fieldCode == 0; } bool isInvalid() const { return fieldCode == -1; } bool isKnown() const { return fieldType != STI_UNKNOWN; } + + bool operator==(const SField& f) const { return fieldCode == f.fieldCode; } + bool operator!=(const SField& f) const { return fieldCode != f.fieldCode; } }; extern SField sfInvalid, sfGeneric; diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index d935022cb9..5ec0c8ad49 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -10,6 +10,8 @@ std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, SField::ref name) { + assert((id == STI_NOTPRESENT) || (id == name.fieldType)); + switch(id) { case STI_NOTPRESENT: @@ -48,6 +50,12 @@ std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, S case STI_PATHSET: return std::auto_ptr(new STPathSet(name)); + case STI_OBJECT: + return std::auto_ptr(new STObject(name)); + + case STI_ARRAY: + return std::auto_ptr(new STArray(name)); + default: throw std::runtime_error("Unknown object type"); } @@ -105,7 +113,7 @@ std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID } } -void STObject::set(const SOElement* elem) +void STObject::set(SOElement::ptr elem) { mData.empty(); mType.empty(); @@ -114,39 +122,70 @@ void STObject::set(const SOElement* elem) { mType.push_back(elem); if (elem->flags == SOE_OPTIONAL) - giveObject(makeDefaultObject(STI_NOTPRESENT, elem)); + giveObject(makeDefaultObject(STI_NOTPRESENT, elem->e_field)); else - giveObject(makeDefaultObject(elem->e_field, elem)); + giveObject(makeDefaultObject(elem->e_field.fieldType, elem->e_field)); ++elem; } } -STObject::STObject(const SOElement* elem, SField::ref name) : SerializedType(name) -{ - set(elem); -} - -void STObject::set(SField::ref name, SerializerIterator& sit, int depth = 0) +void STObject::setType(SOElement::ptrList t) { mData.empty(); - mType.empty(); - - fName = name; - - while(1) - { - int type, field. - sit.getFieldID(type, field); - if ((type == STI_ARRAY) && (field == 1)) - return; - SField::ref fn = SField::getField(type, field); - giveObject(makeDeserializedObject(static_cast type, fn, sit, depth + 1); - } + while (t->flags != SOE_END) + mType.push_back(t++); } -STObject::STObject(const SOElement* elem, SerializerIterator& sit, SField::refname) : SerializedType(name) +bool STObject::isValidForType() { - set(elem, sit); + BOOST_FOREACH(SOElement::ptr elem, mType) + { // are any required elemnents missing + if ((elem->flags == SOE_REQUIRED) && (getPField(elem->e_field) == NULL)) + { + Log(lsWARNING) << getName() << " missing required element " << elem->e_field.fieldName; + return false; + } + } + + BOOST_FOREACH(const SerializedType& elem, mData) + { // are any non-permitted elements present + if (!isFieldAllowed(elem.getFName())) + { + Log(lsWARNING) << getName() << " has non-permitted element " << elem.getName(); + return false; + } + } + + return true; +} + +bool STObject::isFieldAllowed(SField::ref field) +{ + BOOST_FOREACH(SOElement::ptr elem, mType) + { // are any required elemnents missing + if (elem->e_field == field) + return true; + } + return false; +} + +bool STObject::set(SOElement::ptrList elem, SerializerIterator& sit, int depth) +{ // return true = terminated with end-of-object + setType(elem); + + mData.empty(); + while (!sit.empty()) + { + int type, field; + sit.getFieldID(type, field); + if ((type == STI_OBJECT) && (field == 1)) // end of object indicator + return true; + SField::ref fn = SField::getField(type, field); + if (fn.isInvalid()) + throw std::runtime_error("Unknown field"); + giveObject(makeDeserializedObject(fn.fieldType, fn, sit, depth + 1)); + } + return false; } std::string STObject::getFullText() const diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 491e85a599..47e0d9639e 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -11,34 +11,48 @@ // Serializable object/array types -struct SOElement +class SOElement { // An element in the description of a serialized object +public: + typedef SOElement const * ptr; // used to point to one element + typedef SOElement const * ptrList; // used to point to a terminated list of elements + SField::ref e_field; - SOE_Flags flags; + const SOE_Flags flags; }; class STObject : public SerializedType { protected: boost::ptr_vector mData; - std::vector mType; + std::vector mType; STObject* duplicate() const { return new STObject(*this); } static STObject* construct(SerializerIterator&, SField::ref); public: - STObject(SField *n = NULL) : SerializedType(n) { ; } - STObject(const SOElement *t, SField *n = NULL); - STObject(const SOElement *t, SerializerIterator& u, SField *n = NULL); + STObject() { ; } + + STObject(SField::ref name) : SerializedType(name) { ; } + + STObject(SOElement::ptrList type, SField::ref name) : SerializedType(name) + { set(type); } + + STObject(SOElement::ptrList type, SerializerIterator& sit, SField::ref name) : SerializedType(name) + { set(type, sit); } + virtual ~STObject() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } - void set(const SOElement* t); - void set(const SOElement* t, SerializerIterator& u, int depth = 0); + void setType(SOElement const * t); + bool isValidForType(); + bool isFieldAllowed(SField::ref); + + void set(SOElement::ptrList); + bool set(SOElement::ptrList, SerializerIterator& u, int depth = 0); - int getLength() const; virtual SerializedTypeID getSType() const { return STI_OBJECT; } virtual bool isEquivalent(const SerializedType& t) const; @@ -111,8 +125,8 @@ public: SerializedType* makeFieldPresent(SField::ref field); void makeFieldAbsent(SField::ref field); - static std::auto_ptr makeDefaultObject(SerializedTypeID id, SField *name); - static std::auto_ptr makeDeserializedObject(SerializedTypeID id, SField *name, + static std::auto_ptr makeDefaultObject(SerializedTypeID id, SField::ref name); + static std::auto_ptr makeDeserializedObject(SerializedTypeID id, SField::ref name, SerializerIterator&, int depth); static void unitTest(); @@ -138,6 +152,7 @@ protected: public: STArray() { ; } + STArray(SField::ref f) : SerializedType(f) { ; } STArray(SField::ref f, const vector& v) : SerializedType(f), value(v) { ; } STArray(vector& v) : value(v) { ; } diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index d1278b8645..ce997b5b8c 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -37,7 +37,6 @@ public: SerializedTransaction(TransactionType type); // STObject functions - int getLength() const; SerializedTypeID getSType() const { return STI_TRANSACTION; } std::string getFullText() const; std::string getText() const; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 2085ab38ac..d9bc627abb 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -49,7 +49,7 @@ public: { return std::auto_ptr(new SerializedType(name)); } void setFName(SField::ref n) { fName = &n; assert(fName); } - SField::ref getFName() { return *fName; } + SField::ref getFName() const { return *fName; } const char *getName() const { return fName->fieldName; } virtual SerializedTypeID getSType() const { return STI_NOTPRESENT; } From fbb0baaca04d2350cdbee806ee4ba73cb2a4d0f1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 00:28:58 -0700 Subject: [PATCH 325/426] Cleanups. --- src/FieldNames.cpp | 14 ++++++++++++++ src/FieldNames.h | 2 ++ src/SerializedObject.cpp | 11 +++++++++-- src/SerializedObject.h | 3 ++- src/SerializedTypes.h | 2 ++ src/Serializer.h | 2 ++ 6 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index 14827bf7f2..57f823de3e 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -49,6 +49,20 @@ SField::ref SField::getField(int code); return *(new SField(code, static_cast(type), field, NULL)); } +int SField::compare(SField::ref f1, SField::ref f2) +{ // -1 = f1 comes before f2, 0 = illegal combination, 1 = f1 comes after f2 + if ((f1.fieldCode <= 0) || (f2.fieldCode <= 0)) + return 0; + + if (f1.fieldCode < f2.fieldCode) + return -1; + + if (f2.fieldCode < f1.fieldCode) + return 1; + + return 0; +} + SField::ref SField::getField(int type, int value) { return getField(FIELD_CODE(type, value)); diff --git a/src/FieldNames.h b/src/FieldNames.h index 4432320447..cd035f1330 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -69,6 +69,8 @@ public: bool operator==(const SField& f) const { return fieldCode == f.fieldCode; } bool operator!=(const SField& f) const { return fieldCode != f.fieldCode; } + + static int compare(SField::ref f1, SField::ref f2); }; extern SField sfInvalid, sfGeneric; diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 5ec0c8ad49..c5713494d2 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -192,9 +192,9 @@ std::string STObject::getFullText() const { std::string ret; bool first = true; - if (name != NULL) + if (fName->hasName()) { - ret = name; + ret = fName->getName(); ret += " = {"; } else ret = "{"; @@ -213,6 +213,13 @@ std::string STObject::getFullText() const void STObject::add(Serializer& s) const { + addFieldID(s); + addRaw(s); + s.addFieldID(STI_OBJECT, 1); +} + +void STObject::addRaw(Serializer& s) const +{ // FIXME: need to add in sorted order BOOST_FOREACH(const SerializedType& it, mData) it.add(s); } diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 47e0d9639e..3242802fe0 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -56,7 +56,8 @@ public: virtual SerializedTypeID getSType() const { return STI_OBJECT; } virtual bool isEquivalent(const SerializedType& t) const; - void add(Serializer& s) const; + void add(Serializer& s) const; // with start/end of object + virtual void addRaw(Serializer& s) const; // just inner elements Serializer getSerializer() const { Serializer s; add(s); return s; } std::string getFullText() const; std::string getText() const; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index d9bc627abb..64dae0d73b 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -66,6 +66,8 @@ public: virtual bool isEquivalent(const SerializedType& t) const { assert(getSType() == STI_NOTPRESENT); return t.getSType() == STI_NOTPRESENT; } + void addFieldID(Serializer& s) const { s.addFieldID(fName->fieldType, fName->fieldValue); } + SerializedType& operator=(const SerializedType& t) { if (!fName->fieldCode) fName = t.fName; return *this; } bool operator==(const SerializedType& t) const diff --git a/src/Serializer.h b/src/Serializer.h index 30dfe1ceb8..ec762e52c7 100644 --- a/src/Serializer.h +++ b/src/Serializer.h @@ -9,6 +9,7 @@ #include "key.h" #include "uint256.h" +#include "FieldNames.h" typedef std::pair > TaggedListItem; @@ -69,6 +70,7 @@ public: bool getFieldID(int& type, int& name, int offset) const; int addFieldID(int type, int name); + int addFieldID(SerializedTypeID type, int name); // normal hash functions uint160 getRIPEMD160(int size=-1) const; From 96eef8388ffe97d60b8b14dadbed9d3f180076e4 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 12:46:53 -0700 Subject: [PATCH 326/426] Remove a line of dead code. Add two convenience functions. --- src/SerializedObject.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 3242802fe0..58914bfb78 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -87,7 +87,6 @@ public: SerializedType& getField(SField::ref field); const SerializedType* peekAtPField(SField::ref field) const; SerializedType* getPField(SField::ref field); - const SOElement* getFieldType(SField::ref field) const; // these throw if the field type doesn't match, or return default values if the // field is optional but not present @@ -130,6 +129,11 @@ public: static std::auto_ptr makeDeserializedObject(SerializedTypeID id, SField::ref name, SerializerIterator&, int depth); + static std::auto_ptr makeNonPresentObject(SField::ref name) + { return makeDefaultObject(STI_NOTPRESENT, name); } + static std::auto_ptr makeDefaultObject(SField::ref name) + { return makeDefaultObject(name.fieldType, name); } + static void unitTest(); }; From 19b9facdef8dc85c6520b0ef8e6c1c2a445415ed Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 12:47:17 -0700 Subject: [PATCH 327/426] name -> fName --- src/Amount.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index c9e3e4475c..7af2d28e71 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -519,7 +519,7 @@ STAmount& STAmount::operator-=(const STAmount& a) STAmount STAmount::operator-(void) const { if (mValue == 0) return *this; - return STAmount(name, mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative); + return STAmount(fName, mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative); } STAmount& STAmount::operator=(uint64 v) @@ -572,12 +572,12 @@ bool STAmount::operator>=(uint64 v) const STAmount STAmount::operator+(uint64 v) const { - return STAmount(name, getSNValue() + static_cast(v)); + return STAmount(fName, getSNValue() + static_cast(v)); } STAmount STAmount::operator-(uint64 v) const { - return STAmount(name, getSNValue() - static_cast(v)); + return STAmount(fName, getSNValue() - static_cast(v)); } STAmount::operator double() const @@ -595,7 +595,7 @@ STAmount operator+(const STAmount& v1, const STAmount& v2) v1.throwComparable(v2); if (v1.mIsNative) - return STAmount(v1.name, v1.getSNValue() + v2.getSNValue()); + return STAmount(v1.fName, v1.getSNValue() + v2.getSNValue()); int ov1 = v1.mOffset, ov2 = v2.mOffset; @@ -617,9 +617,9 @@ STAmount operator+(const STAmount& v1, const STAmount& v2) int64 fv = vv1 + vv2; if (fv >= 0) - return STAmount(v1.name, v1.mCurrency, v1.mIssuer, fv, ov1, false); + return STAmount(v1.fName, v1.mCurrency, v1.mIssuer, fv, ov1, false); else - return STAmount(v1.name, v1.mCurrency, v1.mIssuer, -fv, ov1, true); + return STAmount(v1.fName, v1.mCurrency, v1.mIssuer, -fv, ov1, true); } STAmount operator-(const STAmount& v1, const STAmount& v2) @@ -628,7 +628,7 @@ STAmount operator-(const STAmount& v1, const STAmount& v2) v1.throwComparable(v2); if (v2.mIsNative) - return STAmount(v1.name, v1.getSNValue() - v2.getSNValue()); + return STAmount(v1.fName, v1.getSNValue() - v2.getSNValue()); int ov1 = v1.mOffset, ov2 = v2.mOffset; int64 vv1 = static_cast(v1.mValue), vv2 = static_cast(v2.mValue); @@ -649,9 +649,9 @@ STAmount operator-(const STAmount& v1, const STAmount& v2) int64 fv = vv1 - vv2; if (fv >= 0) - return STAmount(v1.name, v1.mCurrency, v1.mIssuer, fv, ov1, false); + return STAmount(v1.fName, v1.mCurrency, v1.mIssuer, fv, ov1, false); else - return STAmount(v1.name, v1.mCurrency, v1.mIssuer, -fv, ov1, true); + return STAmount(v1.fName, v1.mCurrency, v1.mIssuer, -fv, ov1, true); } STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& uCurrencyID, const uint160& uIssuerID) @@ -703,7 +703,7 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16 return STAmount(uCurrencyID, uIssuerID); if (v1.mIsNative && v2.mIsNative) // FIXME: overflow - return STAmount(v1.name, v1.getSNValue() * v2.getSNValue()); + return STAmount(v1.fName, v1.getSNValue() * v2.getSNValue()); uint64 value1 = v1.mValue, value2 = v2.mValue; int offset1 = v1.mOffset, offset2 = v2.mOffset; From 0c0069f77c0b79fc68535a8c1ba4e3de88c54e41 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 12:47:28 -0700 Subject: [PATCH 328/426] Small bugfixes. --- src/FieldNames.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index 57f823de3e..483694c2d2 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -9,34 +9,34 @@ SField sfInvalid(-1), sfGeneric(0); -#define FIELD(name, type, index) SField sf##name(FIELD_CODE(STI_##type, index), STI_##type, index, naem); +#define FIELD(name, type, index) SField sf##name(FIELD_CODE(STI_##type, index), STI_##type, index, #name); #define TYPE(name, type, index) #include "SerializeProto.h" #undef FIELD #undef TYPE -static std::map SField::codeToField; -static boost::mutex SField::mapMutex; +std::map SField::codeToField; +boost::mutex SField::mapMutex; -SField::ref SField::getField(int code); +SField::ref SField::getField(int code) { int type = code >> 16; int field = code % 0xffff; - if ((type <= 0) || (type >= 256) || (field <= 0) || (field >= 256 + if ((type <= 0) || (type >= 256) || (field <= 0) || (field >= 256)) return sfInvalid; boost::mutex::scoped_lock sl(mapMutex); - std::map it = unknownFieldMap.Find(code); + std::map it = codeToField.find(code); if (it != codeToField.end()) return *(it->second); switch(type) { // types we are willing to dynamically extend -#define FIELD(name, type, index) -#define TYPE(name, type, index) case sf##name: +#define FIELD(name, type, index) case sf##name: +#define TYPE(name, type, index) #include "SerializeProto.h" #undef FIELD #undef TYPE From 6d58bd52b14e0b901190f8cf7a45e5a852a9702a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 12:47:42 -0700 Subject: [PATCH 329/426] Missing from SField::ref commit. --- src/LedgerEntrySet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index dbb364ebca..682f17d4d9 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -877,7 +877,7 @@ uint32 LedgerEntrySet::rippleTransferRate(const uint160& uIssuerID) } // 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 LedgerEntrySet::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, SField::ref sfLow, SField::ref sfHigh) { uint32 uQuality = QUALITY_ONE; SLE::pointer sleRippleState; @@ -892,7 +892,7 @@ uint32 LedgerEntrySet::rippleQualityIn(const uint160& uToAccountID, const uint16 if (sleRippleState) { - SOE_Field sfField = uToAccountID < uFromAccountID ? sfLow: sfHigh; + SField::ref sfField = uToAccountID < uFromAccountID ? sfLow: sfHigh; uQuality = sleRippleState->getIFieldPresent(sfField) ? sleRippleState->getIFieldU32(sfField) From ba77d3e438134e09e22b67abc3bf362e52520c2d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 12:47:55 -0700 Subject: [PATCH 330/426] Make it compile. --- src/SerializedObject.cpp | 106 ++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 57 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index c5713494d2..d7f360b962 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -122,9 +122,9 @@ void STObject::set(SOElement::ptr elem) { mType.push_back(elem); if (elem->flags == SOE_OPTIONAL) - giveObject(makeDefaultObject(STI_NOTPRESENT, elem->e_field)); + giveObject(makeNonPresentObject(elem->e_field)); else - giveObject(makeDefaultObject(elem->e_field.fieldType, elem->e_field)); + giveObject(makeDefaultObject(elem->e_field)); ++elem; } } @@ -257,7 +257,7 @@ bool STObject::isEquivalent(const SerializedType& t) const return (it1 == end1) && (it2 == end2); } -int STObject::getFieldIndex(SOE_Field field) const +int STObject::getFieldIndex(SField::ref field) const { int i = 0; for (std::vector::const_iterator it = mType.begin(), end = mType.end(); it != end; ++it, ++i) @@ -265,7 +265,7 @@ int STObject::getFieldIndex(SOE_Field field) const return -1; } -const SerializedType& STObject::peekAtField(SOE_Field field) const +const SerializedType& STObject::peekAtField(SField::ref field) const { int index = getFieldIndex(field); if (index == -1) @@ -273,7 +273,7 @@ const SerializedType& STObject::peekAtField(SOE_Field field) const return peekAtIndex(index); } -SerializedType& STObject::getField(SOE_Field field) +SerializedType& STObject::getField(SField::ref field) { int index = getFieldIndex(field); if (index == -1) @@ -281,12 +281,12 @@ SerializedType& STObject::getField(SOE_Field field) return getIndex(index); } -SOE_Field STObject::getFieldSType(int index) const +SField::ref STObject::getFieldSType(int index) const { return mType[index]->e_field; } -const SerializedType* STObject::peekAtPField(SOE_Field field) const +const SerializedType* STObject::peekAtPField(SField::ref field) const { int index = getFieldIndex(field); if (index == -1) @@ -294,7 +294,7 @@ const SerializedType* STObject::peekAtPField(SOE_Field field) const return peekAtPIndex(index); } -SerializedType* STObject::getPField(SOE_Field field) +SerializedType* STObject::getPField(SField::ref field) { int index = getFieldIndex(field); if (index == -1) @@ -302,7 +302,7 @@ SerializedType* STObject::getPField(SOE_Field field) return getPIndex(index); } -bool STObject::isFieldPresent(SOE_Field field) const +bool STObject::isFieldPresent(SField::ref field) const { int index = getFieldIndex(field); if (index == -1) @@ -321,7 +321,6 @@ bool STObject::setFlag(uint32 f) bool STObject::clearFlag(uint32 f) { - if (mFlagIdx < 0) return false; STUInt32* t = dynamic_cast(getPField(sfFlags)); if (!t) return false; @@ -331,58 +330,47 @@ bool STObject::clearFlag(uint32 f) uint32 STObject::getFlags(void) const { - const STUInt32* t = dynamic_cast(peekAtPField(mFlagIdx)); + const STUInt32* t = dynamic_cast(peekAtPField(sfFlags)); if (!t) return 0; return t->getValue(); } -SerializedType* STObject::makeFieldPresent(SOE_Field field) +SerializedType* STObject::makeFieldPresent(SField::ref field) { int index = getFieldIndex(field); if (index == -1) throw std::runtime_error("Field not found"); - if ((mType[index]->e_type != SOE_IFFLAG) && (mType[index]->e_type != SOE_IFNFLAG)) - throw std::runtime_error("field is not optional"); SerializedType* f = getPIndex(index); - if (f->getSType() != STI_NOTPRESENT) return f; - mData.replace(index, makeDefaultObject(mType[index]->e_id, mType[index]->e_name)); - f = getPIndex(index); - - if (mType[index]->e_type == SOE_IFFLAG) - setFlag(mType[index]->e_flags); - else if (mType[index]->e_type == SOE_IFNFLAG) - clearFlag(mType[index]->e_flags); - - return f; + if (f->getSType() != STI_NOTPRESENT) + return f; + mData.replace(index, makeDefaultObject(mType[index]->e_field)); + return getPIndex(index); } -void STObject::makeFieldAbsent(SOE_Field field) +void STObject::makeFieldAbsent(SField::ref field) { int index = getFieldIndex(field); if (index == -1) throw std::runtime_error("Field not found"); - if ((mType[index]->e_type != SOE_IFFLAG) && (mType[index]->e_type != SOE_IFNFLAG)) + if (mType[index]->flags != SOE_OPTIONAL) throw std::runtime_error("field is not optional"); - if (peekAtIndex(index).getSType() == STI_NOTPRESENT) return; - mData.replace(index, new SerializedType(mType[index]->e_name)); + if (peekAtIndex(index).getSType() == STI_NOTPRESENT) + return; - if (mType[index]->e_type == SOE_IFFLAG) - clearFlag(mType[index]->e_flags); - else if (mType[index]->e_type == SOE_IFNFLAG) - setFlag(mType[index]->e_flags); + mData.replace(index, makeDefaultObject(mType[index]->e_field)); } -std::string STObject::getFieldString(SOE_Field field) const +std::string STObject::getFieldString(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); return rf->getText(); } -unsigned char STObject::getValueFieldU8(SOE_Field field) const +unsigned char STObject::getValueFieldU8(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -393,7 +381,7 @@ unsigned char STObject::getValueFieldU8(SOE_Field field) const return cf->getValue(); } -uint16 STObject::getValueFieldU16(SOE_Field field) const +uint16 STObject::getValueFieldU16(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -404,7 +392,7 @@ uint16 STObject::getValueFieldU16(SOE_Field field) const return cf->getValue(); } -uint32 STObject::getValueFieldU32(SOE_Field field) const +uint32 STObject::getValueFieldU32(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -415,7 +403,7 @@ uint32 STObject::getValueFieldU32(SOE_Field field) const return cf->getValue(); } -uint64 STObject::getValueFieldU64(SOE_Field field) const +uint64 STObject::getValueFieldU64(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -426,7 +414,7 @@ uint64 STObject::getValueFieldU64(SOE_Field field) const return cf->getValue(); } -uint128 STObject::getValueFieldH128(SOE_Field field) const +uint128 STObject::getValueFieldH128(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -437,7 +425,7 @@ uint128 STObject::getValueFieldH128(SOE_Field field) const return cf->getValue(); } -uint160 STObject::getValueFieldH160(SOE_Field field) const +uint160 STObject::getValueFieldH160(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -448,7 +436,7 @@ uint160 STObject::getValueFieldH160(SOE_Field field) const return cf->getValue(); } -uint256 STObject::getValueFieldH256(SOE_Field field) const +uint256 STObject::getValueFieldH256(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -459,7 +447,7 @@ uint256 STObject::getValueFieldH256(SOE_Field field) const return cf->getValue(); } -NewcoinAddress STObject::getValueFieldAccount(SOE_Field field) const +NewcoinAddress STObject::getValueFieldAccount(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) @@ -477,7 +465,7 @@ NewcoinAddress STObject::getValueFieldAccount(SOE_Field field) const return cf->getValueNCA(); } -std::vector STObject::getValueFieldVL(SOE_Field field) const +std::vector STObject::getValueFieldVL(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -488,7 +476,7 @@ std::vector STObject::getValueFieldVL(SOE_Field field) const return cf->getValue(); } -STAmount STObject::getValueFieldAmount(SOE_Field field) const +STAmount STObject::getValueFieldAmount(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -499,7 +487,7 @@ STAmount STObject::getValueFieldAmount(SOE_Field field) const return *cf; } -STPathSet STObject::getValueFieldPathSet(SOE_Field field) const +STPathSet STObject::getValueFieldPathSet(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -510,7 +498,7 @@ STPathSet STObject::getValueFieldPathSet(SOE_Field field) const return *cf; } -STVector256 STObject::getValueFieldV256(SOE_Field field) const +STVector256 STObject::getValueFieldV256(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -521,7 +509,7 @@ STVector256 STObject::getValueFieldV256(SOE_Field field) const return *cf; } -void STObject::setValueFieldU8(SOE_Field field, unsigned char v) +void STObject::setValueFieldU8(SField::ref field, unsigned char v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -531,7 +519,7 @@ void STObject::setValueFieldU8(SOE_Field field, unsigned char v) cf->setValue(v); } -void STObject::setValueFieldU16(SOE_Field field, uint16 v) +void STObject::setValueFieldU16(SField::ref field, uint16 v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -541,7 +529,7 @@ void STObject::setValueFieldU16(SOE_Field field, uint16 v) cf->setValue(v); } -void STObject::setValueFieldU32(SOE_Field field, uint32 v) +void STObject::setValueFieldU32(SField::ref field, uint32 v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -551,7 +539,7 @@ void STObject::setValueFieldU32(SOE_Field field, uint32 v) cf->setValue(v); } -void STObject::setValueFieldU64(SOE_Field field, uint64 v) +void STObject::setValueFieldU64(SField::ref field, uint64 v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -561,7 +549,7 @@ void STObject::setValueFieldU64(SOE_Field field, uint64 v) cf->setValue(v); } -void STObject::setValueFieldH128(SOE_Field field, const uint128& v) +void STObject::setValueFieldH128(SField::ref field, const uint128& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -571,7 +559,7 @@ void STObject::setValueFieldH128(SOE_Field field, const uint128& v) cf->setValue(v); } -void STObject::setValueFieldH160(SOE_Field field, const uint160& v) +void STObject::setValueFieldH160(SField::ref field, const uint160& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -581,7 +569,7 @@ void STObject::setValueFieldH160(SOE_Field field, const uint160& v) cf->setValue(v); } -void STObject::setValueFieldH256(SOE_Field field, const uint256& v) +void STObject::setValueFieldH256(SField::ref field, const uint256& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -591,7 +579,7 @@ void STObject::setValueFieldH256(SOE_Field field, const uint256& v) cf->setValue(v); } -void STObject::setValueFieldV256(SOE_Field field, const STVector256& v) +void STObject::setValueFieldV256(SField::ref field, const STVector256& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -601,7 +589,7 @@ void STObject::setValueFieldV256(SOE_Field field, const STVector256& v) cf->setValue(v); } -void STObject::setValueFieldAccount(SOE_Field field, const uint160& v) +void STObject::setValueFieldAccount(SField::ref field, const uint160& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -611,7 +599,7 @@ void STObject::setValueFieldAccount(SOE_Field field, const uint160& v) cf->setValueH160(v); } -void STObject::setValueFieldVL(SOE_Field field, const std::vector& v) +void STObject::setValueFieldVL(SField::ref field, const std::vector& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -621,7 +609,7 @@ void STObject::setValueFieldVL(SOE_Field field, const std::vector cf->setValue(v); } -void STObject::setValueFieldAmount(SOE_Field field, const STAmount &v) +void STObject::setValueFieldAmount(SField::ref field, const STAmount &v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -631,7 +619,7 @@ void STObject::setValueFieldAmount(SOE_Field field, const STAmount &v) (*cf) = v; } -void STObject::setValueFieldPathSet(SOE_Field field, const STPathSet &v) +void STObject::setValueFieldPathSet(SField::ref field, const STPathSet &v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -667,6 +655,8 @@ Json::Value STVector256::getJson(int options) const return ret; } +#if 0 + static SOElement testSOElements[2][16] = { // field, name, id, type, flags { @@ -726,4 +716,6 @@ void STObject::unitTest() } +#endif + // vim:ts=4 From 73e4a73f954d9a270db9ab2d870683550bc29407 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 14:07:07 -0700 Subject: [PATCH 331/426] getLedgerID to NetworkOPs. --- src/NetworkOPs.cpp | 5 +++++ src/NetworkOPs.h | 1 + 2 files changed, 6 insertions(+) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 0433892263..38a43580db 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -67,6 +67,11 @@ void NetworkOPs::closeTimeOffset(int offset) Log(lsINFO) << "Close time offset now " << mCloseTimeOffset; } +uint32 NetworkOPs::getLedgerID(const uint256& hash) +{ + return mLedgerMaster->getLedgerByHash(hash)->getLedgerSeq(); +} + uint32 NetworkOPs::getCurrentLedgerID() { return mLedgerMaster->getCurrentLedger()->getLedgerSeq(); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 43b7da9f4e..b62a362bec 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -96,6 +96,7 @@ public: uint32 getValidationTimeNC(); void closeTimeOffset(int); boost::posix_time::ptime getNetworkTimePT(); + uint32 getLedgerID(const uint256& hash); uint32 getCurrentLedgerID(); OperatingMode getOperatingMode() { return mMode; } inline bool available() { From 4cec959e78cf1830eebe547130ef37924a025848 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 14:08:10 -0700 Subject: [PATCH 332/426] WS add command ledger_closed and revise ledger_current. --- src/WSDoor.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index bea4e7ed27..a44ee9098e 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -76,7 +76,9 @@ public: boost::unordered_set parseAccountIds(const Json::Value& jvArray); // Request-Response Commands + void doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRequest); void doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest); + void doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest); // Streaming Commands void doAccountInfoSubscribe(Json::Value& jvResult, const Json::Value& jvRequest); @@ -297,7 +299,9 @@ Json::Value WSConnection::invokeCommand(const Json::Value& jvRequest) doFuncPtr dfpFunc; } commandsA[] = { // Request-Response Commands: - { "ledger_current", &WSConnection::doLedgerCurrent }, + { "ledger_closed", &WSConnection::doLedgerClosed }, + { "ledger_current", &WSConnection::doLedgerCurrent }, + { "ledger_entry", &WSConnection::doLedgerEntry }, // Streaming commands: { "account_info_subscribe", &WSConnection::doAccountInfoSubscribe }, @@ -548,9 +552,55 @@ void WSConnection::doLedgerAccountsUnsubscribe(Json::Value& jvResult, const Json } } +void WSConnection::doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRequest) +{ + uint256 uLedger = theApp->getOPs().getClosedLedger(); + + jvResult["ledger_index"] = theApp->getOPs().getLedgerID(uLedger); + jvResult["ledger"] = uLedger.ToString(); +} + void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest) { - jvResult["ledger"] = theApp->getOPs().getCurrentLedgerID(); + jvResult["ledger_index"] = theApp->getOPs().getCurrentLedgerID(); +} + +void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest) +{ + // Get from request. + uint256 uLedger; + + jvResult["ledger_index"] = theApp->getOPs().getLedgerID(uLedger); + jvResult["ledger"] = uLedger.ToString(); + + if (jvRequest.isMember("index")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("account_root")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("directory")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("generator")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("offer")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("ripple_state")) + { + jvResult["error"] = "notImplemented"; + } + else + { + jvResult["error"] = "unknownOption"; + } } void WSConnection::doTransactionSubcribe(Json::Value& jvResult, const Json::Value& jvRequest) From 8993c8f26838f9773f5d68f9f6ed80870b458fb7 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 14:08:56 -0700 Subject: [PATCH 333/426] UT add testing for ledger_closed and update ledger_current. --- js/remote.js | 10 +++++-- test/standalone-test.js | 66 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 6 deletions(-) diff --git a/js/remote.js b/js/remote.js index d1fa4430cc..c98129d102 100644 --- a/js/remote.js +++ b/js/remote.js @@ -82,7 +82,7 @@ Remote.method('connect_helper', function() { self.done(ws.readyState); }; - // XXX Why doesn't onmessage work? + // Node's ws module doesn't pass arguments to onmessage. ws.on('message', function(json, flags) { var message = JSON.parse(json); // console.log("message: %s", json); @@ -167,12 +167,16 @@ Remote.method('request', function(command, done) { ws.send(JSON.stringify(command)); }); -// Get the current ledger entry (may be live or not). +Remote.method('ledger_closed', function(done) { + this.request({ 'command' : 'ledger_closed' }, done); +}); + +// Get the current proposed ledger entry. May be closed (and revised) at any time (even before returning). +// Only for use by unit tests. Remote.method('ledger_current', function(done) { this.request({ 'command' : 'ledger_current' }, done); }); - // Submit a json transaction. // done(value) // <-> value: { 'status', status, 'result' : result, ... } diff --git a/test/standalone-test.js b/test/standalone-test.js index 2a725dffac..92289ffcfc 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -92,15 +92,75 @@ buster.testCase("Websocket commands", { }); }, - "ledger_current" : + 'ledger_closed' : + function(done) { + alpha.ledger_closed(function (r) { + console.log(r); + + buster.assert(r.ledger === 1); + done(); + }); + }, + + 'ledger_current' : function(done) { alpha.ledger_current(function (r) { console.log(r); - buster.assert(r.ledger === 2); + buster.assert.equals(r.ledger_index, 2); done(); }); - } + }, + + 'ledger_closed' : + function(done) { + alpha.ledger_closed(function (r) { + console.log("result: %s", JSON.stringify(r)); + + buster.assert.equals(r.ledger_index, 1); + done(); + }); + }, }); +buster.testCase("// Work in progress", { + 'setUp' : + function(done) { + server.start("alpha", + function(e) { + buster.refute(e); + + alpha = remote.remoteConfig(config, "alpha"); + + alpha.connect(function(stat) { + buster.assert(1 == stat); // OPEN + + done(); + }, serverDelay); + }); + }, + + 'tearDown' : + function(done) { + alpha.disconnect(function(stat) { + buster.assert(3 == stat); // CLOSED + + server.stop("alpha", function(e) { + buster.refute(e); + + done(); + }); + }); + }, + + 'ledger_closed' : + function(done) { + alpha.ledger_closed(function (r) { + console.log("result: %s", JSON.stringify(r)); + + buster.assert.equals(r.ledger_index, 1); + done(); + }); + }, +}); // vim:ts=4 From c10ff5bac9b67ddf5549fce7e1a31c93b7454877 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 14:22:04 -0700 Subject: [PATCH 334/426] More serialization rework. --- src/Amount.cpp | 18 +++++++++--------- src/FieldNames.cpp | 12 ++++++------ src/FieldNames.h | 4 ++-- src/SerializedTypes.h | 6 +++--- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 7af2d28e71..9b45507502 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -519,7 +519,7 @@ STAmount& STAmount::operator-=(const STAmount& a) STAmount STAmount::operator-(void) const { if (mValue == 0) return *this; - return STAmount(fName, mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative); + return STAmount(getFName(), mCurrency, mIssuer, mValue, mOffset, mIsNative, !mIsNegative); } STAmount& STAmount::operator=(uint64 v) @@ -572,12 +572,12 @@ bool STAmount::operator>=(uint64 v) const STAmount STAmount::operator+(uint64 v) const { - return STAmount(fName, getSNValue() + static_cast(v)); + return STAmount(getFName(), getSNValue() + static_cast(v)); } STAmount STAmount::operator-(uint64 v) const { - return STAmount(fName, getSNValue() - static_cast(v)); + return STAmount(getFName(), getSNValue() - static_cast(v)); } STAmount::operator double() const @@ -595,7 +595,7 @@ STAmount operator+(const STAmount& v1, const STAmount& v2) v1.throwComparable(v2); if (v1.mIsNative) - return STAmount(v1.fName, v1.getSNValue() + v2.getSNValue()); + return STAmount(v1.getFName(), v1.getSNValue() + v2.getSNValue()); int ov1 = v1.mOffset, ov2 = v2.mOffset; @@ -617,9 +617,9 @@ STAmount operator+(const STAmount& v1, const STAmount& v2) int64 fv = vv1 + vv2; if (fv >= 0) - return STAmount(v1.fName, v1.mCurrency, v1.mIssuer, fv, ov1, false); + return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, fv, ov1, false); else - return STAmount(v1.fName, v1.mCurrency, v1.mIssuer, -fv, ov1, true); + return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, -fv, ov1, true); } STAmount operator-(const STAmount& v1, const STAmount& v2) @@ -649,9 +649,9 @@ STAmount operator-(const STAmount& v1, const STAmount& v2) int64 fv = vv1 - vv2; if (fv >= 0) - return STAmount(v1.fName, v1.mCurrency, v1.mIssuer, fv, ov1, false); + return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, fv, ov1, false); else - return STAmount(v1.fName, v1.mCurrency, v1.mIssuer, -fv, ov1, true); + return STAmount(v1.getFName(), v1.mCurrency, v1.mIssuer, -fv, ov1, true); } STAmount STAmount::divide(const STAmount& num, const STAmount& den, const uint160& uCurrencyID, const uint160& uIssuerID) @@ -703,7 +703,7 @@ STAmount STAmount::multiply(const STAmount& v1, const STAmount& v2, const uint16 return STAmount(uCurrencyID, uIssuerID); if (v1.mIsNative && v2.mIsNative) // FIXME: overflow - return STAmount(v1.fName, v1.getSNValue() * v2.getSNValue()); + return STAmount(v1.getFName(), v1.getSNValue() * v2.getSNValue()); uint64 value1 = v1.mValue, value2 = v2.mValue; int offset1 = v1.mOffset, offset2 = v2.mOffset; diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index 483694c2d2..316410ffb6 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -15,7 +15,7 @@ SField sfInvalid(-1), sfGeneric(0); #undef FIELD #undef TYPE -std::map SField::codeToField; +std::map SField::codeToField; boost::mutex SField::mapMutex; SField::ref SField::getField(int code) @@ -28,15 +28,15 @@ SField::ref SField::getField(int code) boost::mutex::scoped_lock sl(mapMutex); - std::map it = codeToField.find(code); + std::map::iterator it = codeToField.find(code); if (it != codeToField.end()) return *(it->second); - switch(type) + switch (type) { // types we are willing to dynamically extend -#define FIELD(name, type, index) case sf##name: -#define TYPE(name, type, index) +#define FIELD(name, type, index) +#define TYPE(name, type, index) case STI_##type: #include "SerializeProto.h" #undef FIELD #undef TYPE @@ -68,7 +68,7 @@ SField::ref SField::getField(int type, int value) return getField(FIELD_CODE(type, value)); } -std::string SField::getName() cosnt +std::string SField::getName() const { if (fieldName != NULL) return fieldName; diff --git a/src/FieldNames.h b/src/FieldNames.h index cd035f1330..cfcb649f06 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -40,8 +40,8 @@ public: typedef SField const * ptr; protected: - static std::map codeToField; - static boost::mutex mapMutex; + static std::map codeToField; + static boost::mutex mapMutex; public: diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 64dae0d73b..5df8b6fada 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -218,11 +218,11 @@ protected: STAmount(bool isNeg, uint64 value) : mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNeg) { ; } - STAmount(SField *name, uint64 value, bool isNegative) + STAmount(SField::ref name, uint64 value, bool isNegative) : SerializedType(fName), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative) { ; } - STAmount(SField *n, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg) - : SerializedType(n), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off), + STAmount(SField::ref name, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg) + : SerializedType(name), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off), mIsNative(isNat), mIsNegative(isNeg) { ; } uint64 toUInt64() const; From f3f116117a13897a1bb93f8d457884c1a8438ee3 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 15:01:21 -0700 Subject: [PATCH 335/426] Make genesis ledger 1. --- src/Ledger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index b419a493fc..e650f9b94f 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -21,7 +21,7 @@ #include "Log.h" -Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(0), +Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(1), mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false), mTransactionMap(new SHAMap()), mAccountStateMap(new SHAMap()) From be54bf070c06d3c4786e6a9464b98734ee9d508d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 15:02:17 -0700 Subject: [PATCH 336/426] Make getLedgerByHash(0) return the current ledger. --- src/LedgerMaster.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h index 37db69c5c2..76e6327381 100644 --- a/src/LedgerMaster.h +++ b/src/LedgerMaster.h @@ -66,10 +66,15 @@ public: Ledger::pointer getLedgerByHash(const uint256& hash) { + if (!hash) + return mCurrentLedger; + if (mCurrentLedger && (mCurrentLedger->getHash() == hash)) return mCurrentLedger; + if (mFinalizedLedger && (mFinalizedLedger->getHash() == hash)) return mFinalizedLedger; + return mLedgerHistory.getLedgerByHash(hash); } From cae6ea1c3356d91191614062340bafb61093b334 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 15:03:19 -0700 Subject: [PATCH 337/426] Remove useless NetworkOPs::getClosedLedger. --- src/NetworkOPs.cpp | 4 ++- src/NetworkOPs.h | 5 --- src/RPCServer.cpp | 82 ++++++++++++++++++---------------------------- 3 files changed, 35 insertions(+), 56 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 38a43580db..9988a03925 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -69,7 +69,9 @@ void NetworkOPs::closeTimeOffset(int offset) uint32 NetworkOPs::getLedgerID(const uint256& hash) { - return mLedgerMaster->getLedgerByHash(hash)->getLedgerSeq(); + Ledger::ref lrLedger = mLedgerMaster->getLedgerByHash(hash); + + return lrLedger ? lrLedger->getLedgerSeq() : 0; } uint32 NetworkOPs::getCurrentLedgerID() diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index b62a362bec..c22c6b63cd 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -107,11 +107,6 @@ public: uint256 getClosedLedger() { return mLedgerMaster->getClosedLedger()->getHash(); } - // FIXME: This function is basically useless since the hash is constantly changing and the ledger - // is ephemeral and mutable. - uint256 getCurrentLedger() - { return mLedgerMaster->getCurrentLedger()->getHash(); } - // // Transaction operations // diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index cd79010c4a..a2d81512ab 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -422,7 +422,6 @@ Json::Value RPCServer::doAccountDomainSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -438,7 +437,7 @@ Json::Value RPCServer::doAccountDomainSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -476,7 +475,6 @@ Json::Value RPCServer::doAccountEmailSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -492,7 +490,7 @@ Json::Value RPCServer::doAccountEmailSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -569,12 +567,11 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) ret["accepted"] = jAccepted; - uint256 uCurrent = mNetOps->getCurrentLedger(); - Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + Json::Value jCurrent = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex); if (jCurrent.empty()) { - AccountState::pointer asCurrent = mNetOps->getAccountState(uCurrent, naAccount); + AccountState::pointer asCurrent = mNetOps->getAccountState(uint256(0), naAccount); if (asCurrent) asCurrent->addJson(jCurrent); @@ -598,7 +595,6 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) Json::Value RPCServer::doAccountMessageSet(const Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); NewcoinAddress naMessagePubKey; if (!naSeed.setSeedGeneric(params[0u].asString())) @@ -619,7 +615,7 @@ Json::Value RPCServer::doAccountMessageSet(const Json::Value& params) { NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); std::vector vucDomain; @@ -659,7 +655,6 @@ Json::Value RPCServer::doAccountPublishSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -675,7 +670,7 @@ Json::Value RPCServer::doAccountPublishSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -717,7 +712,6 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -733,7 +727,7 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -773,7 +767,6 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value ¶ms) Json::Value RPCServer::doAccountWalletSet(const Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -789,7 +782,7 @@ Json::Value RPCServer::doAccountWalletSet(const Json::Value& params) { NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); std::vector vucDomain; @@ -921,8 +914,6 @@ Json::Value RPCServer::doDataStore(const Json::Value& params) // Note: Nicknames are not automatically looked up by commands as they are advisory and can be changed. Json::Value RPCServer::doNicknameInfo(const Json::Value& params) { - uint256 uLedger = mNetOps->getCurrentLedger(); - std::string strNickname = params[0u].asString(); boost::trim(strNickname); @@ -931,7 +922,7 @@ Json::Value RPCServer::doNicknameInfo(const Json::Value& params) return RPCError(rpcNICKNAME_MALFORMED); } - NicknameState::pointer nsSrc = mNetOps->getNicknameState(uLedger, strNickname); + NicknameState::pointer nsSrc = mNetOps->getNicknameState(uint256(0), strNickname); if (!nsSrc) { return RPCError(rpcNICKNAME_MISSING); @@ -951,7 +942,6 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -979,7 +969,7 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) } STAmount saFee; - NicknameState::pointer nsSrc = mNetOps->getNicknameState(uLedger, strNickname); + NicknameState::pointer nsSrc = mNetOps->getNicknameState(uint256(0), strNickname); if (!nsSrc) { @@ -1002,7 +992,7 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, saFee, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1068,7 +1058,7 @@ Json::Value RPCServer::doOfferCreate(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(mNetOps->getCurrentLedger(), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1114,7 +1104,7 @@ Json::Value RPCServer::doOfferCancel(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(mNetOps->getCurrentLedger(), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1154,10 +1144,9 @@ Json::Value RPCServer::doOwnerInfo(const Json::Value& params) ret["accepted"] = jAccepted.empty() ? mNetOps->getOwnerInfo(uAccepted, naAccount) : jAccepted; - uint256 uCurrent = mNetOps->getCurrentLedger(); - Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + Json::Value jCurrent = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex); - ret["current"] = jCurrent.empty() ? mNetOps->getOwnerInfo(uCurrent, naAccount) : jCurrent; + ret["current"] = jCurrent.empty() ? mNetOps->getOwnerInfo(uint256(0), naAccount) : jCurrent; return ret; } @@ -1168,7 +1157,6 @@ Json::Value RPCServer::doPasswordFund(const Json::Value ¶ms) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -1188,7 +1176,7 @@ Json::Value RPCServer::doPasswordFund(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1494,8 +1482,7 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) return RPCError(rpcDST_AMT_MALFORMED); } - uint256 uLedger = mNetOps->getCurrentLedger(); - AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID); + AccountState::pointer asDst = mNetOps->getAccountState(uint256(0), naDstAccountID); STAmount saFee = theConfig.FEE_DEFAULT; NewcoinAddress naVerifyGenerator; @@ -1503,7 +1490,7 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, saFee, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -1556,7 +1543,6 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; STAmount saLimitAmount; - uint256 uLedger = mNetOps->getCurrentLedger(); bool bLimitAmount = true; bool bQualityIn = params.size() >= 6; bool bQualityOut = params.size() >= 7; @@ -1594,7 +1580,7 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1627,7 +1613,6 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) { // uint256 uAccepted = mNetOps->getClosedLedger(); - uint256 uCurrent = mNetOps->getCurrentLedger(); std::string strIdent = params[0u].asString(); bool bIndex; @@ -1637,7 +1622,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) Json::Value ret; - ret = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + ret = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex); if (!ret.empty()) return ret; @@ -1649,7 +1634,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) if (bIndex) ret["index"] = iIndex; - AccountState::pointer as = mNetOps->getAccountState(uCurrent, naAccount); + AccountState::pointer as = mNetOps->getAccountState(uint256(0), naAccount); if (as) { Json::Value jsonLines(Json::arrayValue); @@ -1739,8 +1724,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) } else { - uint256 uLedger = mNetOps->getCurrentLedger(); - AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID); + AccountState::pointer asDst = mNetOps->getAccountState(uint256(0), naDstAccountID); bool bCreate = !asDst; STAmount saFee = bCreate ? theConfig.FEE_ACCOUNT_CREATE : theConfig.FEE_DEFAULT; @@ -1749,7 +1733,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, saFee, asSrc, naVerifyGenerator); // Log(lsINFO) << boost::str(boost::format("doSend: sSrcIssuer=%s sDstIssuer=%s saSrcAmountMax=%s saDstAmount=%s") @@ -2081,7 +2065,6 @@ Json::Value RPCServer::accounts(const uint256& uLedger, const NewcoinAddress& na Json::Value RPCServer::doWalletAccounts(const Json::Value& params) { NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -2091,17 +2074,17 @@ Json::Value RPCServer::doWalletAccounts(const Json::Value& params) // Try the seed as a master seed. NewcoinAddress naMasterGenerator = NewcoinAddress::createGeneratorPublic(naSeed); - Json::Value jsonAccounts = accounts(uLedger, naMasterGenerator); + Json::Value jsonAccounts = accounts(uint256(0), naMasterGenerator); if (jsonAccounts.empty()) { // No account via seed as master, try seed a regular. - Json::Value ret = getMasterGenerator(uLedger, naSeed, naMasterGenerator); + Json::Value ret = getMasterGenerator(uint256(0), naSeed, naMasterGenerator); if (!ret.empty()) return ret; - ret["accounts"] = accounts(uLedger, naMasterGenerator); + ret["accounts"] = accounts(uint256(0), naMasterGenerator); return ret; } @@ -2124,7 +2107,6 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params) NewcoinAddress naSrcAccountID; STAmount saAmount; std::string sDstCurrency; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naRegularSeed.setSeedGeneric(params[0u].asString())) { @@ -2151,7 +2133,7 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naRegularSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naRegularSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_ACCOUNT_CREATE, asSrc, naMasterGenerator); if (!obj.empty()) @@ -2177,7 +2159,7 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params) ++iIndex; naNewAccountPublic.setAccountPublic(naMasterGenerator, iIndex); - asNew = mNetOps->getAccountState(uLedger, naNewAccountPublic); + asNew = mNetOps->getAccountState(uint256(0), naNewAccountPublic); if (!asNew) bAgain = false; } while (bAgain); @@ -2312,7 +2294,6 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -2326,7 +2307,7 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) { return RPCError(rpcDST_ACT_MALFORMED); } - else if (mNetOps->getAccountState(uLedger, naDstAccountID)) + else if (mNetOps->getAccountState(uint256(0), naDstAccountID)) { return RPCError(rpcACT_EXISTS); } @@ -2339,7 +2320,7 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_ACCOUNT_CREATE, asSrc, naMasterGenerator); if (!obj.empty()) @@ -2602,7 +2583,8 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { return RPCError(rpcNO_NETWORK); } - else if ((commandsA[i].iOptions & optCurrent) && mNetOps->getCurrentLedger().isZero()) + // XXX Should verify we have a current ledger. + else if ((commandsA[i].iOptions & optCurrent) && false) { return RPCError(rpcNO_CURRENT); } From 20815377b47b3b140575da3712751d9afad261a7 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 26 Sep 2012 15:07:03 -0700 Subject: [PATCH 338/426] Adjust UTs for genesis 1. --- test/standalone-test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/standalone-test.js b/test/standalone-test.js index 92289ffcfc..ffa593840d 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -107,7 +107,7 @@ buster.testCase("Websocket commands", { alpha.ledger_current(function (r) { console.log(r); - buster.assert.equals(r.ledger_index, 2); + buster.assert.equals(r.ledger_index, 3); done(); }); }, @@ -117,7 +117,7 @@ buster.testCase("Websocket commands", { alpha.ledger_closed(function (r) { console.log("result: %s", JSON.stringify(r)); - buster.assert.equals(r.ledger_index, 1); + buster.assert.equals(r.ledger_index, 2); done(); }); }, @@ -158,7 +158,7 @@ buster.testCase("// Work in progress", { alpha.ledger_closed(function (r) { console.log("result: %s", JSON.stringify(r)); - buster.assert.equals(r.ledger_index, 1); + buster.assert.equals(r.ledger_index, 2); done(); }); }, From 632d506234dcf9b661fa9581d687b8fa81dcff15 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 15:08:43 -0700 Subject: [PATCH 339/426] Make this compile. --- src/Amount.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 9b45507502..793e71c250 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -889,7 +889,7 @@ STAmount STAmount::convertToInternalAmount(uint64 displayAmount, uint64 totalNow STAmount STAmount::deserialize(SerializerIterator& it) { - STAmount *s = construct(it); + STAmount *s = construct(it, sfGeneric); STAmount ret(*s); delete s; From 16cadaf43f0cf47fc6f3e1a31a755fc710387496 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 15:09:00 -0700 Subject: [PATCH 340/426] Special types of high-level objects. --- src/FieldNames.cpp | 3 +++ src/FieldNames.h | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index 316410ffb6..98ba23616e 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -8,6 +8,9 @@ SField sfInvalid(-1), sfGeneric(0); +SField sfLedgerEntry(FIELD_CODE(STI_LEDGERENTRY, 1), STI_LEDGERENTRY, 1, "LedgerEntry"); +SField sfTransaction(FIELD_CODE(STI_TRANSACTION, 1), STI_TRANSACTION, 1, "Transaction"); +SField sfValidation(FIELD_CODE(STI_VALIDATION, 1), STI_VALIDATION, 1, "Validation"); #define FIELD(name, type, index) SField sf##name(FIELD_CODE(STI_##type, index), STI_##type, index, #name); #define TYPE(name, type, index) diff --git a/src/FieldNames.h b/src/FieldNames.h index cfcb649f06..8dbbb0bcd4 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -21,9 +21,9 @@ enum SerializedTypeID #undef FIELD // high level types - STI_TRANSACTION = 100001, - STI_LEDGERENTRY = 100002, - STI_VALIDATION = 100003, + STI_TRANSACTION = 10001, + STI_LEDGERENTRY = 10002, + STI_VALIDATION = 10003, }; enum SOE_Flags @@ -73,7 +73,7 @@ public: static int compare(SField::ref f1, SField::ref f2); }; -extern SField sfInvalid, sfGeneric; +extern SField sfInvalid, sfGeneric, sfLedgerEntry, sfTransaction; #define FIELD(name, type, index) extern SField sf##name; #define TYPE(name, type, index) From d76f61a648081fdd8205f68e069380ddd2cb42da Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 15:09:11 -0700 Subject: [PATCH 341/426] Cleanups. --- src/SerializeProto.h | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/SerializeProto.h b/src/SerializeProto.h index bf60039fb8..7aca88d086 100644 --- a/src/SerializeProto.h +++ b/src/SerializeProto.h @@ -2,11 +2,11 @@ // appropriate #define statements. // types (common) - TYPE("Int32", UINT32, 1) - TYPE("Int64", UINT64, 2) - TYPE("Hash128", HASH128, 3) - TYPE("Hash256", HASH256, 4) - // 5 is reserved + TYPE("Int16", UINT16, 1) + TYPE("Int32", UINT32, 2) + TYPE("Int64", UINT64, 3) + TYPE("Hash128", HASH128, 4) + TYPE("Hash256", HASH256, 5) TYPE("Amount", AMOUNT, 6) TYPE("VariableLength", VL, 7) TYPE("Account", ACCOUNT, 8) @@ -16,16 +16,19 @@ // types (uncommon) TYPE("Int8", UINT8, 16) - TYPE("Int16", UINT16, 17) - TYPE("Hash160", HASH160, 18) - TYPE("PathSet", PATHSET, 19) - TYPE("Vector256", VECTOR256, 20) + TYPE("Hash160", HASH160, 17) + TYPE("PathSet", PATHSET, 18) + TYPE("Vector256", VECTOR256, 19) // 8-bit integers FIELD(CloseResolution, UINT8, 1) + // 16-bit integers + FIELD(LedgerEntryType, UINT16, 1) + FIELD(TransactionType, UINT16, 1) + // 32-bit integers (common) FIELD(ObjectType, UINT32, 1) FIELD(Flags, UINT32, 2) From ad4952b9587d5559892dfffdb9abb054b211991a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 15:09:27 -0700 Subject: [PATCH 342/426] Cleanups. --- src/SerializedObject.cpp | 4 +--- src/SerializedObject.h | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index d7f360b962..ef700db52e 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -169,10 +169,8 @@ bool STObject::isFieldAllowed(SField::ref field) return false; } -bool STObject::set(SOElement::ptrList elem, SerializerIterator& sit, int depth) +bool STObject::set(SerializerIterator& sit, int depth) { // return true = terminated with end-of-object - setType(elem); - mData.empty(); while (!sit.empty()) { diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 58914bfb78..fdc9030e92 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -39,19 +39,19 @@ public: { set(type); } STObject(SOElement::ptrList type, SerializerIterator& sit, SField::ref name) : SerializedType(name) - { set(type, sit); } + { set(sit); setType(type); } virtual ~STObject() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } - void setType(SOElement const * t); + void setType(SOElement::ptrList); bool isValidForType(); bool isFieldAllowed(SField::ref); void set(SOElement::ptrList); - bool set(SOElement::ptrList, SerializerIterator& u, int depth = 0); + bool set(SerializerIterator& u, int depth = 0); virtual SerializedTypeID getSType() const { return STI_OBJECT; } virtual bool isEquivalent(const SerializedType& t) const; From 9c08dc00ae379bf3c0b721a40df0f003ef3f4565 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 15:09:38 -0700 Subject: [PATCH 343/426] Mark a huge number of ugly functions deprecated. You no longer need to use the special 'IField' functions. You can treat a ledger entry like any STObject. --- src/SerializedLedger.h | 88 ++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 47 deletions(-) diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index 813e4dccb9..0b9cb1c17b 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -5,7 +5,7 @@ #include "LedgerFormats.h" #include "NewcoinAddress.h" -class SerializedLedgerEntry : public SerializedType +class SerializedLedgerEntry : public STObject { public: typedef boost::shared_ptr pointer; @@ -14,8 +14,6 @@ public: protected: uint256 mIndex; LedgerEntryType mType; - STUInt16 mVersion; - STObject mObject; const LedgerEntryFormat* mFormat; SerializedLedgerEntry* duplicate() const { return new SerializedLedgerEntry(*this); } @@ -29,40 +27,15 @@ public: std::string getFullText() const; std::string getText() const; Json::Value getJson(int options) const; - void add(Serializer& s) const { mVersion.add(s); mObject.add(s); } virtual bool isEquivalent(const SerializedType& t) const; - bool setFlag(uint32 uSet) { return mObject.setFlag(uSet); } - bool clearFlag(uint32 uClear) { return mObject.clearFlag(uClear); } - uint32 getFlags() const { return mObject.getFlags(); } - - const uint256& getIndex() const { return mIndex; } - void setIndex(const uint256& i) { mIndex = i; } + const uint256& getIndex() const; + void setIndex(const uint256& i); LedgerEntryType getType() const { return mType; } - uint16 getVersion() const { return mVersion.getValue(); } + uint16 getVersion() const { return getValueFieldU16(sfLedgerEntryType); } const LedgerEntryFormat* getFormat() { return mFormat; } - int getIFieldIndex(SField::ref field) const { return mObject.getFieldIndex(field); } - int getIFieldCount() const { return mObject.getCount(); } - const SerializedType& peekIField(SField::ref field) const { return mObject.peekAtField(field); } - SerializedType& getIField(SField::ref field) { return mObject.getField(field); } - SField::ref getIFieldSType(int index) { return mObject.getFieldSType(index); } - - std::string getIFieldString(SField::ref field) const { return mObject.getFieldString(field); } - unsigned char getIFieldU8(SField::ref field) const { return mObject.getValueFieldU8(field); } - uint16 getIFieldU16(SField::ref field) const { return mObject.getValueFieldU16(field); } - uint32 getIFieldU32(SField::ref field) const { return mObject.getValueFieldU32(field); } - uint64 getIFieldU64(SField::ref field) const { return mObject.getValueFieldU64(field); } - uint128 getIFieldH128(SField::ref field) const { return mObject.getValueFieldH128(field); } - uint160 getIFieldH160(SField::ref field) const { return mObject.getValueFieldH160(field); } - uint256 getIFieldH256(SField::ref field) const { return mObject.getValueFieldH256(field); } - std::vector getIFieldVL(SField::ref field) const { return mObject.getValueFieldVL(field); } - std::vector getIFieldTL(SField::ref field) const { return mObject.getValueFieldTL(field); } - NewcoinAddress getIValueFieldAccount(SField::ref field) const { return mObject.getValueFieldAccount(field); } - STAmount getIValueFieldAmount(SField::ref field) const { return mObject.getValueFieldAmount(field); } - STVector256 getIFieldV256(SField::ref field) { return mObject.getValueFieldV256(field); } - bool isThreadedType(); // is this a ledger entry that can be threaded bool isThreaded(); // is this ledger entry actually threaded bool hasOneOwner(); // This node has one other node that owns it (like nickname) @@ -75,28 +48,49 @@ public: bool thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID); std::vector getOwners(); // nodes notified if this node is deleted - void setIFieldU8(SField::ref field, unsigned char v) { return mObject.setValueFieldU8(field, v); } - void setIFieldU16(SField::ref field, uint16 v) { return mObject.setValueFieldU16(field, v); } - void setIFieldU32(SField::ref field, uint32 v) { return mObject.setValueFieldU32(field, v); } - void setIFieldU64(SField::ref field, uint64 v) { return mObject.setValueFieldU64(field, v); } - void setIFieldH128(SField::ref field, const uint128& v) { return mObject.setValueFieldH128(field, v); } - void setIFieldH160(SField::ref field, const uint160& v) { return mObject.setValueFieldH160(field, v); } - void setIFieldH256(SField::ref field, const uint256& v) { return mObject.setValueFieldH256(field, v); } + // CAUTION: All these functions are now obsolete and will be removed after + // the new serialization code is merged. + int getIFieldIndex(SField::ref field) const { return getFieldIndex(field); } + int getIFieldCount() const { return getCount(); } + const SerializedType& peekIField(SField::ref field) const { return peekAtField(field); } + SerializedType& getIField(SField::ref field) { return getField(field); } + SField::ref getIFieldSType(int index) { return getFieldSType(index); } + std::string getIFieldString(SField::ref field) const { return getFieldString(field); } + unsigned char getIFieldU8(SField::ref field) const { return getValueFieldU8(field); } + uint16 getIFieldU16(SField::ref field) const { return getValueFieldU16(field); } + uint32 getIFieldU32(SField::ref field) const { return getValueFieldU32(field); } + uint64 getIFieldU64(SField::ref field) const { return getValueFieldU64(field); } + uint128 getIFieldH128(SField::ref field) const { return getValueFieldH128(field); } + uint160 getIFieldH160(SField::ref field) const { return getValueFieldH160(field); } + uint256 getIFieldH256(SField::ref field) const { return getValueFieldH256(field); } + std::vector getIFieldVL(SField::ref field) const { return getValueFieldVL(field); } + std::vector getIFieldTL(SField::ref field) const { return getValueFieldTL(field); } + NewcoinAddress getIValueFieldAccount(SField::ref field) const { return getValueFieldAccount(field); } + STAmount getIValueFieldAmount(SField::ref field) const { return getValueFieldAmount(field); } + STVector256 getIFieldV256(SField::ref field) { return getValueFieldV256(field); } + void setIFieldU8(SField::ref field, unsigned char v) { return setValueFieldU8(field, v); } + void setIFieldU16(SField::ref field, uint16 v) { return setValueFieldU16(field, v); } + void setIFieldU32(SField::ref field, uint32 v) { return setValueFieldU32(field, v); } + void setIFieldU64(SField::ref field, uint64 v) { return setValueFieldU64(field, v); } + void setIFieldH128(SField::ref field, const uint128& v) { return setValueFieldH128(field, v); } + void setIFieldH160(SField::ref field, const uint160& v) { return setValueFieldH160(field, v); } + void setIFieldH256(SField::ref field, const uint256& v) { return setValueFieldH256(field, v); } void setIFieldVL(SField::ref field, const std::vector& v) - { return mObject.setValueFieldVL(field, v); } + { return setValueFieldVL(field, v); } void setIFieldTL(SField::ref field, const std::vector& v) - { return mObject.setValueFieldTL(field, v); } + { return setValueFieldTL(field, v); } void setIFieldAccount(SField::ref field, const uint160& account) - { return mObject.setValueFieldAccount(field, account); } + { return setValueFieldAccount(field, account); } void setIFieldAccount(SField::ref field, const NewcoinAddress& account) - { return mObject.setValueFieldAccount(field, account); } + { return setValueFieldAccount(field, account); } void setIFieldAmount(SField::ref field, const STAmount& amount) - { return mObject.setValueFieldAmount(field, amount); } - void setIFieldV256(SField::ref field, const STVector256& v) { return mObject.setValueFieldV256(field, v); } + { return setValueFieldAmount(field, amount); } + void setIFieldV256(SField::ref field, const STVector256& v) { return setValueFieldV256(field, v); } + bool getIFieldPresent(SField::ref field) const { return isFieldPresent(field); } + void makeIFieldPresent(SField::ref field) { makeFieldPresent(field); } + void makeIFieldAbsent(SField::ref field) { return makeFieldAbsent(field); } + // CAUTION: All the above functions are obsolete - bool getIFieldPresent(SField::ref field) const { return mObject.isFieldPresent(field); } - void makeIFieldPresent(SField::ref field) { mObject.makeFieldPresent(field); } - void makeIFieldAbsent(SField::ref field) { return mObject.makeFieldAbsent(field); } }; typedef SerializedLedgerEntry SLE; From 3f469c914d42db61dbf89131ad7d72b40dc77c97 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 16:26:39 -0700 Subject: [PATCH 344/426] More serialization work. --- src/FieldNames.h | 2 +- src/SerializeProto.h | 5 ++- src/SerializedLedger.cpp | 70 +++++++++++++++-------------------- src/SerializedLedger.h | 1 - src/SerializedTransaction.cpp | 10 ++--- src/SerializedValidation.cpp | 18 +++++---- 6 files changed, 50 insertions(+), 56 deletions(-) diff --git a/src/FieldNames.h b/src/FieldNames.h index 8dbbb0bcd4..c738e6cefa 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -73,7 +73,7 @@ public: static int compare(SField::ref f1, SField::ref f2); }; -extern SField sfInvalid, sfGeneric, sfLedgerEntry, sfTransaction; +extern SField sfInvalid, sfGeneric, sfLedgerEntry, sfTransaction, sfValidation; #define FIELD(name, type, index) extern SField sf##name; #define TYPE(name, type, index) diff --git a/src/SerializeProto.h b/src/SerializeProto.h index 7aca88d086..eeef22f132 100644 --- a/src/SerializeProto.h +++ b/src/SerializeProto.h @@ -71,8 +71,9 @@ FIELD(TransactionHash, HASH256, 3) FIELD(AccountHash, HASH256, 4) FIELD(LastTxnID, HASH256, 5) - FIELD(WalletLocator, HASH256, 6) - FIELD(PublishHash, HASH256, 7) + FIELD(LedgerIndex, HASH256, 6) + FIELD(WalletLocator, HASH256, 7) + FIELD(PublishHash, HASH256, 8) // 256-bit (uncommon) FIELD(BookDirectory, HASH256, 16) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 0353df8b69..1d26049883 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -6,27 +6,29 @@ #include "Log.h" SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint256& index) - : SerializedType("LedgerEntry"), mIndex(index) + : STObject(sfLedgerEntry), mIndex(index) { - uint16 type = sit.get16(); + set(sit); + uint16 type = getValueFieldU16(sfLedgerEntryType); mFormat = getLgrFormat(static_cast(type)); - if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); + if (mFormat == NULL) + throw std::runtime_error("invalid ledger entry type"); mType = mFormat->t_type; - mVersion.setValue(type); - mObject = STObject(mFormat->elements, sit); + setType(mType); } SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& index) - : SerializedType("LedgerEntry"), mIndex(index) + : STObject(sfLedgerEntry), mIndex(index) { SerializerIterator sit(s); + set(sit); - uint16 type = sit.get16(); + uint16 type = getValueFieldU16(sfLedgerEntryType); mFormat = getLgrFormat(static_cast(type)); - if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); + if (mFormat == NULL) + throw std::runtime_error("invalid ledger entry type"); mType = mFormat->t_type; - mVersion.setValue(type); - mObject.set(mFormat->elements, sit); + setType(mTyhpe); } SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type) : SerializedType("LedgerEntry"), mType(type) @@ -34,7 +36,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type) : SerializedT mFormat = getLgrFormat(type); if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); mVersion.setValue(static_cast(mFormat->t_type)); - mObject.set(mFormat->elements); + set(mFormat->elements); } std::string SerializedLedgerEntry::getFullText() const @@ -44,7 +46,7 @@ std::string SerializedLedgerEntry::getFullText() const ret += "\" = { "; ret += mFormat->t_name; ret += ", "; - ret += mObject.getFullText(); + ret += getFullText(); ret += "}"; return ret; } @@ -53,67 +55,55 @@ std::string SerializedLedgerEntry::getText() const { return str(boost::format("{ %s, %s, %s }") % mIndex.GetHex() - % mVersion.getText() - % mObject.getText()); + % STObject::getText()); } Json::Value SerializedLedgerEntry::getJson(int options) const { - Json::Value ret(mObject.getJson(options)); + Json::Value ret(SerializedObject::getJson(options)); - ret["type"] = mFormat->t_name; ret["index"] = mIndex.GetHex(); - ret["version"] = std::string(1, mVersion); return ret; } -bool SerializedLedgerEntry::isEquivalent(const SerializedType& t) const -{ // locators are not compared - const SerializedLedgerEntry* v = dynamic_cast(&t); - if (!v) return false; - if (mType != v->mType) return false; - if (mObject != v->mObject) return false; - return true; -} - bool SerializedLedgerEntry::isThreadedType() { - return getIFieldIndex(sfLastTxnID) != -1; + return getFieldIndex(sfLastTxnID) != -1; } bool SerializedLedgerEntry::isThreaded() { - return getIFieldPresent(sfLastTxnID); + return isFieldPresent(sfLastTxnID); } uint256 SerializedLedgerEntry::getThreadedTransaction() { - return getIFieldH256(sfLastTxnID); + return getValueFieldH256(sfLastTxnID); } uint32 SerializedLedgerEntry::getThreadedLedger() { - return getIFieldU32(sfLastTxnSeq); + return getValueFieldU32(sfLastTxnSeq); } bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID) { - uint256 oldPrevTxID = getIFieldH256(sfLastTxnID); + uint256 oldPrevTxID = getValueFieldH256(sfLastTxnID); Log(lsTRACE) << "Thread Tx:" << txID << " prev:" << oldPrevTxID; if (oldPrevTxID == txID) return false; prevTxID = oldPrevTxID; - prevLedgerID = getIFieldU32(sfLastTxnSeq); + prevLedgerID = getValueFieldU32(sfLastTxnSeq); assert(prevTxID != txID); - setIFieldH256(sfLastTxnID, txID); - setIFieldU32(sfLastTxnSeq, ledgerSeq); + setFieldH256(sfLastTxnID, txID); + setFieldU32(sfLastTxnSeq, ledgerSeq); return true; } bool SerializedLedgerEntry::hasOneOwner() { - return (mType != ltACCOUNT_ROOT) && (getIFieldIndex(sfAccount) != -1); + return (mType != ltACCOUNT_ROOT) && (getFieldIndex(sfAccount) != -1); } bool SerializedLedgerEntry::hasTwoOwners() @@ -123,17 +113,17 @@ bool SerializedLedgerEntry::hasTwoOwners() NewcoinAddress SerializedLedgerEntry::getOwner() { - return getIValueFieldAccount(sfAccount); + return getValueFieldAccount(sfAccount); } NewcoinAddress SerializedLedgerEntry::getFirstOwner() { - return getIValueFieldAccount(sfLowID); + return getValueFieldAccount(sfLowID); } NewcoinAddress SerializedLedgerEntry::getSecondOwner() { - return getIValueFieldAccount(sfHighID); + return getValueFieldAccount(sfHighID); } std::vector SerializedLedgerEntry::getOwners() @@ -141,9 +131,9 @@ std::vector SerializedLedgerEntry::getOwners() std::vector owners; uint160 account; - for (int i = 0, fields = getIFieldCount(); i < fields; ++i) + for (int i = 0, fields = getCount(); i < fields; ++i) { - switch (getIFieldSType(i)) + switch (getFieldSType(i)) { case sfAccount: case sfLowID: diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index 0b9cb1c17b..7468da4d02 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -27,7 +27,6 @@ public: std::string getFullText() const; std::string getText() const; Json::Value getJson(int options) const; - virtual bool isEquivalent(const SerializedType& t) const; const uint256& getIndex() const; void setIndex(const uint256& i); diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index 0ee218028c..87db2afc0b 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -12,11 +12,11 @@ SerializedTransaction::SerializedTransaction(TransactionType type) : mType(type) mFormat = getTxnFormat(type); if (mFormat == NULL) throw std::runtime_error("invalid transaction type"); - mMiddleTxn.giveObject(new STVariableLength("SigningPubKey")); - mMiddleTxn.giveObject(new STAccount("SourceAccount")); - mMiddleTxn.giveObject(new STUInt32("Sequence")); - mMiddleTxn.giveObject(new STUInt16("Type", static_cast(type))); - mMiddleTxn.giveObject(new STAmount("Fee")); + mMiddleTxn.giveObject(new STVariableLength(sfSigningPubKey)); + mMiddleTxn.giveObject(new STAccount(sfSourceAccount)); + mMiddleTxn.giveObject(new STUInt32(sfSequence)); + mMiddleTxn.giveObject(new STUInt16(sfTransactionType, static_cast(type))); + mMiddleTxn.giveObject(new STAmount(sfFee)); mInnerTxn = STObject(mFormat->elements, "InnerTransaction"); } diff --git a/src/SerializedValidation.cpp b/src/SerializedValidation.cpp index 9ae32c31bb..6eedadb94b 100644 --- a/src/SerializedValidation.cpp +++ b/src/SerializedValidation.cpp @@ -4,24 +4,28 @@ #include "HashPrefixes.h" SOElement SerializedValidation::sValidationFormat[] = { - { sfFlags, "Flags", STI_UINT32, SOE_FLAGS, 0 }, - { sfLedgerHash, "LedgerHash", STI_HASH256, SOE_REQUIRED, 0 }, - { sfSigningTime, "SignTime", STI_UINT32, SOE_REQUIRED, 0 }, - { sfSigningKey, "SigningKey", STI_VL, SOE_REQUIRED, 0 }, - { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 }, + { sfFlags, SOE_REQUIRED }, + { sfLedgerHash, SOE_REQUIRED }, + { sfLedgerSequence, SOE_OPTIONAL }, + { sfCloseTime, SOE_OPTIONAL }, + { sfLoadFee, SOE_OPTIONAL }, + { sfBaseFee, SOE_OPTIONAL }, + { sfSigningTime, SOE_REQUIRED }, + { sfSigningKey, SOE_REQUIRED }, + { sfInvalid, SOE_END } }; const uint32 SerializedValidation::sFullFlag = 0x00010000; SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSignature) - : STObject(sValidationFormat, sit), mSignature(sit, "Signature"), mTrusted(false) + : STObject(sValidationFormat, sit, sfValidation), mSignature(sit, sfSignature), mTrusted(false) { if (checkSignature && !isValid()) throw std::runtime_error("Invalid validation"); } SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint32 signTime, const NewcoinAddress& naSeed, bool isFull) - : STObject(sValidationFormat), mSignature("Signature"), mTrusted(false) + : STObject(sValidationFormat, sfValidation), mSignature(sfSignature), mTrusted(false) { setValueFieldH256(sfLedgerHash, ledgerHash); setValueFieldU32(sfSigningTime, signTime); From c9b8408d0867a7f60edf9cb7c28013aab5af8eaf Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 26 Sep 2012 20:40:23 -0700 Subject: [PATCH 345/426] Cleanups and fixes. --- src/SerializeProto.h | 11 ++++++----- src/SerializedLedger.cpp | 27 ++++++++++----------------- src/SerializedTransaction.cpp | 25 ++++++++++--------------- 3 files changed, 26 insertions(+), 37 deletions(-) diff --git a/src/SerializeProto.h b/src/SerializeProto.h index eeef22f132..225cb85dac 100644 --- a/src/SerializeProto.h +++ b/src/SerializeProto.h @@ -56,11 +56,12 @@ FIELD(OfferSequence, UINT32, 25) // 64-bit integers - FIELD(IndexNext, UINT64, 1) - FIELD(IndexPrevious, UINT64, 2) - FIELD(BookNode, UINT64, 3) - FIELD(OwnerNode, UINT64, 4) - FIELD(BaseFee, UINT64, 5) + FIELD(Fee, UINT64, 1) + FIELD(IndexNext, UINT64, 2) + FIELD(IndexPrevious, UINT64, 3) + FIELD(BookNode, UINT64, 4) + FIELD(OwnerNode, UINT64, 5) + FIELD(BaseFee, UINT64, 6) // 128-bit FIELD(EmailHash, HASH128, 2) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 1d26049883..824f77145b 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -14,7 +14,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); mType = mFormat->t_type; - setType(mType); + setType(mFormat->elements); } SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& index) @@ -28,15 +28,15 @@ SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); mType = mFormat->t_type; - setType(mTyhpe); + setType(mFormat->elements); } -SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type) : SerializedType("LedgerEntry"), mType(type) +SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type) : STObject(sfLedgerEntry), mType(type) { mFormat = getLgrFormat(type); if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); - mVersion.setValue(static_cast(mFormat->t_type)); set(mFormat->elements); + setValueFieldU16(sfLedgerEntryType, static_cast(mFormat->t_type)); } std::string SerializedLedgerEntry::getFullText() const @@ -60,7 +60,7 @@ std::string SerializedLedgerEntry::getText() const Json::Value SerializedLedgerEntry::getJson(int options) const { - Json::Value ret(SerializedObject::getJson(options)); + Json::Value ret(STObject::getJson(options)); ret["index"] = mIndex.GetHex(); @@ -96,8 +96,8 @@ bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint25 prevTxID = oldPrevTxID; prevLedgerID = getValueFieldU32(sfLastTxnSeq); assert(prevTxID != txID); - setFieldH256(sfLastTxnID, txID); - setFieldU32(sfLastTxnSeq, ledgerSeq); + setValueFieldH256(sfLastTxnID, txID); + setValueFieldU32(sfLastTxnSeq, ledgerSeq); return true; } @@ -133,19 +133,12 @@ std::vector SerializedLedgerEntry::getOwners() for (int i = 0, fields = getCount(); i < fields; ++i) { - switch (getFieldSType(i)) + int fc = getFieldSType(i).fieldCode; + if ((fc == sfAccount.fieldCode) || (fc == sfLowID.fieldCode) || (fc == sfHighID.fieldCode)) { - case sfAccount: - case sfLowID: - case sfHighID: - { - const STAccount* entry = dynamic_cast(mObject.peekAtPIndex(i)); + const STAccount* entry = dynamic_cast(peekAtPIndex(i)); if ((entry != NULL) && entry->getValueH160(account)) owners.push_back(Ledger::getAccountRootIndex(account)); - } - - default: - nothing(); } } diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index 87db2afc0b..f77937cce4 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -12,13 +12,13 @@ SerializedTransaction::SerializedTransaction(TransactionType type) : mType(type) mFormat = getTxnFormat(type); if (mFormat == NULL) throw std::runtime_error("invalid transaction type"); - mMiddleTxn.giveObject(new STVariableLength(sfSigningPubKey)); - mMiddleTxn.giveObject(new STAccount(sfSourceAccount)); + mMiddleTxn.giveObject(new STVariableLength(sfSigningKey)); + mMiddleTxn.giveObject(new STAccount(sfAccount)); mMiddleTxn.giveObject(new STUInt32(sfSequence)); mMiddleTxn.giveObject(new STUInt16(sfTransactionType, static_cast(type))); mMiddleTxn.giveObject(new STAmount(sfFee)); - mInnerTxn = STObject(mFormat->elements, "InnerTransaction"); + mInnerTxn = STObject(mFormat->elements, sfInnerTransaction); } SerializedTransaction::SerializedTransaction(SerializerIterator& sit) @@ -53,11 +53,6 @@ SerializedTransaction::SerializedTransaction(SerializerIterator& sit) mInnerTxn = STObject(mFormat->elements, sit, "InnerTransaction"); } -int SerializedTransaction::getLength() const -{ - return mSignature.getLength() + mMiddleTxn.getLength() + mInnerTxn.getLength(); -} - std::string SerializedTransaction::getFullText() const { std::string ret = "\""; @@ -241,7 +236,7 @@ const NewcoinAddress& SerializedTransaction::setSourceAccount(const NewcoinAddre return mSourceAccount; } -uint160 SerializedTransaction::getITFieldAccount(SOE_Field field) const +uint160 SerializedTransaction::getITFieldAccount(SField::ref field) const { uint160 r; const SerializedType* st = mInnerTxn.peekAtPField(field); @@ -253,7 +248,7 @@ uint160 SerializedTransaction::getITFieldAccount(SOE_Field field) const return r; } -int SerializedTransaction::getITFieldIndex(SOE_Field field) const +int SerializedTransaction::getITFieldIndex(SField::ref field) const { return mInnerTxn.getFieldIndex(field); } @@ -263,27 +258,27 @@ int SerializedTransaction::getITFieldCount() const return mInnerTxn.getCount(); } -bool SerializedTransaction::getITFieldPresent(SOE_Field field) const +bool SerializedTransaction::getITFieldPresent(SField::ref field) const { return mInnerTxn.isFieldPresent(field); } -const SerializedType& SerializedTransaction::peekITField(SOE_Field field) const +const SerializedType& SerializedTransaction::peekITField(SField::ref field) const { return mInnerTxn.peekAtField(field); } -SerializedType& SerializedTransaction::getITField(SOE_Field field) +SerializedType& SerializedTransaction::getITField(SField::ref field) { return mInnerTxn.getField(field); } -void SerializedTransaction::makeITFieldPresent(SOE_Field field) +void SerializedTransaction::makeITFieldPresent(SField::ref field) { mInnerTxn.makeFieldPresent(field); } -void SerializedTransaction::makeITFieldAbsent(SOE_Field field) +void SerializedTransaction::makeITFieldAbsent(SField::ref field) { return mInnerTxn.makeFieldAbsent(field); } From b491b9925521d8577ec5b8d5d40baf02a2295a4d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 13:08:59 -0700 Subject: [PATCH 346/426] Rework NetworkOPs to return Ledger:pointer. --- src/NetworkOPs.h | 6 ++++++ src/NewcoinAddress.h | 3 +++ 2 files changed, 9 insertions(+) diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index c22c6b63cd..cc84f9f89a 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -104,9 +104,15 @@ public: return mMode >= omTRACKING; } + Ledger::pointer getCurrentLedger() { return mLedgerMaster->getCurrentLedger(); } + Ledger::pointer getLedgerByHash(const uint256& hash) { return mLedgerMaster->getLedgerByHash(hash); } + Ledger::pointer getLedgerBySeq(const uint32 seq) { return mLedgerMaster->getLedgerBySeq(seq); } + uint256 getClosedLedger() { return mLedgerMaster->getClosedLedger()->getHash(); } + SLE::pointer getSLE(Ledger::pointer lpLedger, const uint256& uHash) { return lpLedger->getSLE(uHash); } + // // Transaction operations // diff --git a/src/NewcoinAddress.h b/src/NewcoinAddress.h index 369b609d04..707a976c52 100644 --- a/src/NewcoinAddress.h +++ b/src/NewcoinAddress.h @@ -73,6 +73,9 @@ public: bool setAccountID(const std::string& strAccountID); void setAccountID(const uint160& hash160In); + static NewcoinAddress createAccountID(const std::string& strAccountID) + { NewcoinAddress na; na.setAccountID(strAccountID); return na; } + static NewcoinAddress createAccountID(const uint160& uiAccountID); static std::string createHumanAccountID(const uint160& uiAccountID) From ff245609ac4ead2b7b329d7306fed9c9551d548c Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 13:09:57 -0700 Subject: [PATCH 347/426] WS: Add support for ledger_entry to return an account_root. --- js/remote.js | 23 ++++++----- src/WSDoor.cpp | 66 ++++++++++++++++++++++++++++--- test/standalone-test.js | 88 +++++++++++++++++++++-------------------- 3 files changed, 119 insertions(+), 58 deletions(-) diff --git a/js/remote.js b/js/remote.js index c98129d102..ffab43eaad 100644 --- a/js/remote.js +++ b/js/remote.js @@ -168,6 +168,8 @@ Remote.method('request', function(command, done) { }); Remote.method('ledger_closed', function(done) { + assert(this.trusted); // If not trusted, need to check proof. + this.request({ 'command' : 'ledger_closed' }, done); }); @@ -177,6 +179,17 @@ Remote.method('ledger_current', function(done) { this.request({ 'command' : 'ledger_current' }, done); }); +// <-> params: +// --> ledger : optional +// --> ledger_index : optional +Remote.method('ledger_entry', function(params, done) { + assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol. + + params.command = 'ledger_entry'; + + this.request(params, done); +}); + // Submit a json transaction. // done(value) // <-> value: { 'status', status, 'result' : result, ... } @@ -186,16 +199,6 @@ Remote.method('submit', function(json, done) { // }); }); -// done(value) -// --> value: { 'status', status, 'result' : result, ... } -// done may be called up to 3 times. -Remote.method('account_root', function(account_id, done) { - this.request({ - 'command' : 'ledger_current', - }, function() { - }); -}); - exports.Remote = Remote; exports.remoteConfig = remoteConfig; diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index a44ee9098e..ae63b02129 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -567,11 +567,46 @@ void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvR void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest) { - // Get from request. - uint256 uLedger; + NetworkOPs& noNetwork = theApp->getOPs(); + uint256 uLedger = jvRequest.isMember("ledger") ? uint256(jvRequest["ledger"].asString()) : 0; + uint32 uLedgerIndex = jvRequest.isMember("ledger_index") && jvRequest["ledger_index"].isNumeric() ? jvRequest["ledger_index"].asUInt() : 0; - jvResult["ledger_index"] = theApp->getOPs().getLedgerID(uLedger); - jvResult["ledger"] = uLedger.ToString(); + Ledger::pointer lpLedger; + + if (!!uLedger) + { + // Ledger directly specified. + lpLedger = noNetwork.getLedgerByHash(uLedger); + + if (!lpLedger) + { + jvResult["error"] = "ledgerNotFound"; + return; + } + + uLedgerIndex = lpLedger->getLedgerSeq(); // Set the current index, override if needed. + } + else if (!!uLedgerIndex) + { + lpLedger = noNetwork.getLedgerBySeq(uLedgerIndex); + + if (!lpLedger) + { + jvResult["error"] = "ledgerNotFound"; // ledger_index from future? + return; + } + } + else + { + // Default to current ledger. + lpLedger = noNetwork.getCurrentLedger(); + uLedgerIndex = lpLedger->getLedgerSeq(); // Set the current index. + } + + if (!!uLedger) + jvResult["ledger"] = uLedger.ToString(); + + jvResult["ledger_index"] = uLedgerIndex; if (jvRequest.isMember("index")) { @@ -579,7 +614,28 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("account_root")) { - jvResult["error"] = "notImplemented"; + NewcoinAddress naAccount = NewcoinAddress::createAccountID(jvRequest["account_root"].asString()); + + if (!naAccount.isValid()) + { + jvResult["error"] = "malformedAddress"; + return; + } + + uint256 accountRootIndex = Ledger::getAccountRootIndex(naAccount.getAccountID()); + + SLE::pointer sleNode = noNetwork.getSLE(lpLedger, accountRootIndex); + + if (!sleNode) + { + // Not found. + // XXX We should also provide proof. + jvResult["error"] = "entryNotFound"; + } + else + { + jvResult["node"] = sleNode->getJson(0); + } } else if (jvRequest.isMember("directory")) { diff --git a/test/standalone-test.js b/test/standalone-test.js index ffa593840d..a3fb947498 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -1,5 +1,3 @@ -// console.log("standalone-test.js>"); - var fs = require("fs"); var buster = require("buster"); @@ -59,9 +57,6 @@ buster.testCase("WebSocket connection", { }, }); -// XXX Figure out a way to stuff this into the test case. -var alpha; - buster.testCase("Websocket commands", { 'setUp' : function(done) { @@ -92,16 +87,6 @@ buster.testCase("Websocket commands", { }); }, - 'ledger_closed' : - function(done) { - alpha.ledger_closed(function (r) { - console.log(r); - - buster.assert(r.ledger === 1); - done(); - }); - }, - 'ledger_current' : function(done) { alpha.ledger_current(function (r) { @@ -112,7 +97,7 @@ buster.testCase("Websocket commands", { }); }, - 'ledger_closed' : + '// ledger_closed' : function(done) { alpha.ledger_closed(function (r) { console.log("result: %s", JSON.stringify(r)); @@ -121,46 +106,63 @@ buster.testCase("Websocket commands", { done(); }); }, -}); -buster.testCase("// Work in progress", { - 'setUp' : + 'account_root success' : function(done) { - server.start("alpha", - function(e) { - buster.refute(e); + alpha.ledger_closed(function (r) { + // console.log("result: %s", JSON.stringify(r)); - alpha = remote.remoteConfig(config, "alpha"); + buster.refute('error' in r); - alpha.connect(function(stat) { - buster.assert(1 == stat); // OPEN + alpha.ledger_entry({ + 'ledger_index' : r.ledger_index, + 'account_root' : 'iHb9CJAWyB4ij91VRWn96DkukG4bwdtyTh' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); + buster.assert('node' in r); done(); - }, serverDelay); - }); - }, - - 'tearDown' : - function(done) { - alpha.disconnect(function(stat) { - buster.assert(3 == stat); // CLOSED - - server.stop("alpha", function(e) { - buster.refute(e); - - done(); - }); + }); }); }, - 'ledger_closed' : + 'account_root malformedAddress' : function(done) { alpha.ledger_closed(function (r) { - console.log("result: %s", JSON.stringify(r)); + // console.log("result: %s", JSON.stringify(r)); - buster.assert.equals(r.ledger_index, 2); - done(); + buster.refute('error' in r); + + alpha.ledger_entry({ + 'ledger_index' : r.ledger_index, + 'account_root' : 'foobar' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); + + buster.assert.equals(r.error, 'malformedAddress'); + done(); + }); + }); + }, + + 'account_root entryNotFound' : + function(done) { + alpha.ledger_closed(function (r) { + // console.log("result: %s", JSON.stringify(r)); + + buster.refute('error' in r); + + alpha.ledger_entry({ + 'ledger_index' : r.ledger_index, + 'account_root' : 'iG1QQv2nh2gi7RCZ1P8YYcBUKCCN633jCn' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); + + buster.assert.equals(r.error, 'entryNotFound'); + done(); + }); }); }, }); + // vim:ts=4 From 22c22bd734e0dd04da84a46a34065c8d8be49779 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 13:36:04 -0700 Subject: [PATCH 348/426] WS: Add support ledger_entry to return a ripple_state. --- src/Amount.cpp | 1 + src/WSDoor.cpp | 58 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index f0692f2af7..637d4ef52d 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -12,6 +12,7 @@ uint64 STAmount::uRateOne = STAmount::getRate(STAmount(1), STAmount(1)); +// --> sCurrency: "", "XNS", or three letter ISO code. bool STAmount::currencyFromString(uint160& uDstCurrency, const std::string& sCurrency) { bool bSuccess = true; diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index ae63b02129..7e6960b831 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -608,33 +608,23 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq jvResult["ledger_index"] = uLedgerIndex; + uint256 uNodeIndex; + if (jvRequest.isMember("index")) { jvResult["error"] = "notImplemented"; } else if (jvRequest.isMember("account_root")) { - NewcoinAddress naAccount = NewcoinAddress::createAccountID(jvRequest["account_root"].asString()); + NewcoinAddress naAccount; - if (!naAccount.isValid()) + if (!naAccount.setAccountID(jvRequest["account_root"].asString())) { jvResult["error"] = "malformedAddress"; - return; - } - - uint256 accountRootIndex = Ledger::getAccountRootIndex(naAccount.getAccountID()); - - SLE::pointer sleNode = noNetwork.getSLE(lpLedger, accountRootIndex); - - if (!sleNode) - { - // Not found. - // XXX We should also provide proof. - jvResult["error"] = "entryNotFound"; } else { - jvResult["node"] = sleNode->getJson(0); + uNodeIndex = Ledger::getAccountRootIndex(naAccount.getAccountID()); } } else if (jvRequest.isMember("directory")) @@ -651,12 +641,48 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("ripple_state")) { - jvResult["error"] = "notImplemented"; + NewcoinAddress naA; + NewcoinAddress naB; + uint160 uCurrency; + + if (!jvRequest.isMember("accounts") + || !jvRequest.isMember("currency") + || !jvRequest["accounts"].isArray() + || 2 != jvRequest["accounts"].size()) { + jvResult["error"] = "malformedRequest"; + } + else if (!naA.setAccountID(jvRequest["accounts"][0u].asString()) + || !naB.setAccountID(jvRequest["accounts"][1u].asString())) { + jvResult["error"] = "malformedAddress"; + } + else if (!STAmount::currencyFromString(uCurrency, jvRequest["currency"].asString())) { + jvResult["error"] = "malformedCurrency"; + } + else + { + uNodeIndex = Ledger::getRippleStateIndex(naA, naB, uCurrency); + } } else { jvResult["error"] = "unknownOption"; } + + if (!!uNodeIndex) + { + SLE::pointer sleNode = noNetwork.getSLE(lpLedger, uNodeIndex); + + if (!sleNode) + { + // Not found. + // XXX We should also provide proof. + jvResult["error"] = "entryNotFound"; + } + else + { + jvResult["node"] = sleNode->getJson(0); + } + } } void WSConnection::doTransactionSubcribe(Json::Value& jvResult, const Json::Value& jvRequest) From 1ffe841be589562d9739de5216fa08dfc13f21dc Mon Sep 17 00:00:00 2001 From: MJK Date: Thu, 27 Sep 2012 13:49:37 -0700 Subject: [PATCH 349/426] add simple log rotating, tentative Ripple pathfinder work --- newcoind.cfg | 2 +- src/Log.cpp | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/Log.h | 7 +++++++ src/RPCServer.cpp | 21 +++++++++++++++++++++ src/RPCServer.h | 2 ++ src/main.cpp | 1 + websocketpp | 2 +- 7 files changed, 79 insertions(+), 2 deletions(-) diff --git a/newcoind.cfg b/newcoind.cfg index ac87d7aa8d..689b276923 100644 --- a/newcoind.cfg +++ b/newcoind.cfg @@ -119,7 +119,7 @@ 1 [debug_logfile] -debug.log +log/debug.log [sntp_servers] time.windows.com diff --git a/src/Log.cpp b/src/Log.cpp index bdd56959b2..948552cbf9 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -10,6 +10,8 @@ boost::recursive_mutex Log::sLock; LogSeverity Log::sMinSeverity = lsINFO; std::ofstream* Log::outStream = NULL; +boost::filesystem::path *Log::pathToLog = NULL; +uint32 Log::logRotateCounter = 0; Log::~Log() { @@ -31,6 +33,48 @@ Log::~Log() (*outStream) << logMsg << std::endl; } + +std::string Log::rotateLog(void) +{ + boost::recursive_mutex::scoped_lock sl(sLock); + boost::filesystem::path abs_path; + std::string abs_path_str; + + uint32 failsafe = 0; + + std::string abs_new_path_str; + do { + std::string s; + std::stringstream out; + + failsafe++; + if (failsafe == std::numeric_limits::max()) { + return "unable to create new log file; too many log files!"; + } + abs_path = boost::filesystem::absolute(""); + abs_path /= *pathToLog; + abs_path_str = abs_path.parent_path().string(); + out << logRotateCounter; + s = out.str(); + + + abs_new_path_str = abs_path_str + "/" + s + + "_" + pathToLog->filename().string(); + + logRotateCounter++; + + } while (boost::filesystem::exists(boost::filesystem::path(abs_new_path_str))); + + outStream->close(); + boost::filesystem::rename(abs_path, boost::filesystem::path(abs_new_path_str)); + + + + setLogFile(*pathToLog); + + return abs_new_path_str; + +} + void Log::setMinSeverity(LogSeverity s) { boost::recursive_mutex::scoped_lock sl(sLock); @@ -52,4 +96,6 @@ void Log::setLogFile(boost::filesystem::path path) outStream = newStream; if (outStream) Log(lsINFO) << "Starting up"; + + pathToLog = new boost::filesystem::path(path); } diff --git a/src/Log.h b/src/Log.h index 7153012226..fd3db13fd3 100644 --- a/src/Log.h +++ b/src/Log.h @@ -9,6 +9,9 @@ // Ensure that we don't get value.h without writer.h #include "../json/json.h" +#include "types.h" +#include + enum LogSeverity { lsTRACE = 0, @@ -33,6 +36,9 @@ protected: mutable std::ostringstream oss; LogSeverity mSeverity; + static boost::filesystem::path *pathToLog; + static uint32 logRotateCounter; + public: Log(LogSeverity s) : mSeverity(s) { ; } @@ -51,6 +57,7 @@ public: static void setMinSeverity(LogSeverity); static void setLogFile(boost::filesystem::path); + static std::string rotateLog(void); }; #endif diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index cd79010c4a..ad845ac8f9 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -14,6 +14,11 @@ #include "Log.h" #include "RippleLines.h" +#include "Pathfinder.h" +#include "Conversion.h" + +extern uint160 humanTo160(const std::string& buf); + #include #include @@ -1795,6 +1800,16 @@ Json::Value RPCServer::doSend(const Json::Value& params) STPathSet spsPaths; + uint160 srcCurrencyID; + bool ret_b; + ret_b = false; + STAmount::currencyFromString(srcCurrencyID, sSrcCurrency); + + Pathfinder pf(naSrcAccountID, naDstAccountID, srcCurrencyID, saDstAmount); + + ret_b = pf.findPaths(5, 1, spsPaths); + // TODO: Nope; the above can't be right + trans = Transaction::sharedPayment( naAccountPublic, naAccountPrivate, naSrcAccountID, @@ -2518,6 +2533,11 @@ Json::Value RPCServer::doLogin(const Json::Value& params) } } +Json::Value RPCServer::doLogRotate(const Json::Value& params) +{ + return Log::rotateLog(); +} + Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params) { Log(lsTRACE) << "RPC:" << command; @@ -2543,6 +2563,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "data_fetch", &RPCServer::doDataFetch, 1, 1, true }, { "data_store", &RPCServer::doDataStore, 2, 2, true }, { "ledger", &RPCServer::doLedger, 0, 2, false, optNetwork }, + { "logrotate", &RPCServer::doLogRotate, 0, 0, true, optCurrent }, { "nickname_info", &RPCServer::doNicknameInfo, 1, 1, false, optCurrent }, { "nickname_set", &RPCServer::doNicknameSet, 2, 3, false, optCurrent }, { "offer_create", &RPCServer::doOfferCreate, 9, 10, false, optCurrent }, diff --git a/src/RPCServer.h b/src/RPCServer.h index 33f9699b03..8d56ed55aa 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -141,6 +141,7 @@ private: Json::Value doDataFetch(const Json::Value& params); Json::Value doDataStore(const Json::Value& params); Json::Value doLedger(const Json::Value& params); + Json::Value doLogRotate(const Json::Value& params); Json::Value doNicknameInfo(const Json::Value& params); Json::Value doNicknameSet(const Json::Value& params); Json::Value doOfferCreate(const Json::Value& params); @@ -184,6 +185,7 @@ private: Json::Value doLogin(const Json::Value& params); + public: static pointer create(boost::asio::io_service& io_service, NetworkOPs* mNetOps) { diff --git a/src/main.cpp b/src/main.cpp index b9154261d1..4a69f9f2da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,6 +51,7 @@ void printHelp(const po::options_description& desc) cout << " data_fetch " << endl; cout << " data_store " << endl; cout << " ledger [|current|lastclosed] [full]" << endl; + cout << " logrotate " << endl; cout << " nickname_info " << endl; cout << " nickname_set [] []" << endl; cout << " offer_create [passive]" << endl; diff --git a/websocketpp b/websocketpp index f78b9df4ad..dd9899c34b 160000 --- a/websocketpp +++ b/websocketpp @@ -1 +1 @@ -Subproject commit f78b9df4adbc354f5fdf8c2c8b9e76549f977cb8 +Subproject commit dd9899c34bb1f86caf486735b136a5460b4760db From a40120b6c9109baf1f96304d4d432b0bbc059df6 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 27 Sep 2012 14:11:10 -0700 Subject: [PATCH 350/426] Cleanups and fixes. --- src/Amount.cpp | 2 +- src/SerializeProto.h | 7 +++---- src/SerializedLedger.h | 4 ++-- src/SerializedObject.cpp | 4 ++-- src/SerializedObject.h | 2 +- src/SerializedTransaction.cpp | 14 +++++++------- src/SerializedTypes.cpp | 4 ++-- src/SerializedTypes.h | 25 +++++++++++++------------ src/SerializedValidation.cpp | 8 ++++---- 9 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 793e71c250..11711917ea 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -274,7 +274,7 @@ void STAmount::canonicalize() assert((mValue != 0) || (mOffset != -100) ); } -void STAmount::add(Serializer& s) const +void STAmount::addData(Serializer& s) const { if (mIsNative) { diff --git a/src/SerializeProto.h b/src/SerializeProto.h index 225cb85dac..2c9115fd85 100644 --- a/src/SerializeProto.h +++ b/src/SerializeProto.h @@ -64,7 +64,7 @@ FIELD(BaseFee, UINT64, 6) // 128-bit - FIELD(EmailHash, HASH128, 2) + FIELD(EmailHash, HASH128, 1) // 256-bit (common) FIELD(LedgerHash, HASH256, 1) @@ -98,7 +98,7 @@ // variable length FIELD(PublicKey, VL, 1) FIELD(MessageKey, VL, 2) - FIELD(SigningKey, VL, 3) + FIELD(SigningPubKey, VL, 3) FIELD(Signature, VL, 4) FIELD(Generator, VL, 5) FIELD(Domain, VL, 6) @@ -125,8 +125,7 @@ // inner object // OBJECT/1 is reserved for end of object - FIELD(MiddleTransaction, OBJECT, 2) - FIELD(InnerTransaction, OBJECT, 3) + FIELD(InnerTransaction, OBJECT, 1) // array of objects // ARRAY/1 is reserved for end of array diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index 7468da4d02..b7f35a34f4 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -28,8 +28,8 @@ public: std::string getText() const; Json::Value getJson(int options) const; - const uint256& getIndex() const; - void setIndex(const uint256& i); + const uint256& getIndex() const { return mIndex; } + void setIndex(const uint256& i) { mIndex = i; } LedgerEntryType getType() const { return mType; } uint16 getVersion() const { return getValueFieldU16(sfLedgerEntryType); } diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index ef700db52e..18f20388b7 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -212,11 +212,11 @@ std::string STObject::getFullText() const void STObject::add(Serializer& s) const { addFieldID(s); - addRaw(s); + addData(s); s.addFieldID(STI_OBJECT, 1); } -void STObject::addRaw(Serializer& s) const +void STObject::addData(Serializer& s) const { // FIXME: need to add in sorted order BOOST_FOREACH(const SerializedType& it, mData) it.add(s); diff --git a/src/SerializedObject.h b/src/SerializedObject.h index fdc9030e92..f037f0446d 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -57,7 +57,7 @@ public: virtual bool isEquivalent(const SerializedType& t) const; void add(Serializer& s) const; // with start/end of object - virtual void addRaw(Serializer& s) const; // just inner elements + virtual void addData(Serializer& s) const; // just inner elements Serializer getSerializer() const { Serializer s; add(s); return s; } std::string getFullText() const; std::string getText() const; diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index f77937cce4..b8a5f96c9a 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -12,7 +12,7 @@ SerializedTransaction::SerializedTransaction(TransactionType type) : mType(type) mFormat = getTxnFormat(type); if (mFormat == NULL) throw std::runtime_error("invalid transaction type"); - mMiddleTxn.giveObject(new STVariableLength(sfSigningKey)); + mMiddleTxn.giveObject(new STVariableLength(sfSigningPubKey)); mMiddleTxn.giveObject(new STAccount(sfAccount)); mMiddleTxn.giveObject(new STUInt32(sfSequence)); mMiddleTxn.giveObject(new STUInt16(sfTransactionType, static_cast(type))); @@ -32,25 +32,25 @@ SerializedTransaction::SerializedTransaction(SerializerIterator& sit) mSignature.setValue(sit.getVL()); - mMiddleTxn.giveObject(new STVariableLength("SigningPubKey", sit.getVL())); + mMiddleTxn.giveObject(new STVariableLength(sfSigningPubKey, sit.getVL())); - STAccount sa("SourceAccount", sit.getVL()); + STAccount sa(sfAccount, sit.getVL()); mSourceAccount = sa.getValueNCA(); mMiddleTxn.giveObject(new STAccount(sa)); - mMiddleTxn.giveObject(new STUInt32("Sequence", sit.get32())); + mMiddleTxn.giveObject(new STUInt32(sfSequence, sit.get32())); mType = static_cast(sit.get16()); - mMiddleTxn.giveObject(new STUInt16("Type", static_cast(mType))); + mMiddleTxn.giveObject(new STUInt16(sfTransactionType, static_cast(mType))); mFormat = getTxnFormat(mType); if (!mFormat) { Log(lsERROR) << "Transaction has invalid type"; throw std::runtime_error("Transaction has invalid type"); } - mMiddleTxn.giveObject(STAmount::deserialize(sit, "Fee")); + mMiddleTxn.giveObject(STAmount::deserialize(sit, sfFee)); - mInnerTxn = STObject(mFormat->elements, sit, "InnerTransaction"); + mInnerTxn = STObject(mFormat->elements, sit, sfInnerTransaction); } std::string SerializedTransaction::getFullText() const diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 6eeb0c9120..4e7ed6ec56 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -202,7 +202,7 @@ STVector256* STVector256::construct(SerializerIterator& u, SField::ref name) return new STVector256(name, value); } -void STVector256::add(Serializer& s) const +void STVector256::addData(Serializer& s) const { s.addVL(mValue.empty() ? NULL : mValue[0].begin(), mValue.size() * (256 / 8)); } @@ -427,7 +427,7 @@ std::string STPathSet::getText() const } #endif -void STPathSet::add(Serializer& s) const +void STPathSet::addData(Serializer& s) const { bool bFirst = true; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 5df8b6fada..e30a2f783c 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -61,7 +61,8 @@ public: virtual Json::Value getJson(int) const { return getText(); } - virtual void add(Serializer& s) const { return; } + virtual void add(Serializer& s) const { addFieldID(s); addData(s); } + virtual void addData(Serializer& s) const { ; } virtual bool isEquivalent(const SerializedType& t) const { assert(getSType() == STI_NOTPRESENT); return t.getSType() == STI_NOTPRESENT; } @@ -97,7 +98,7 @@ public: SerializedTypeID getSType() const { return STI_UINT8; } std::string getText() const; - void add(Serializer& s) const { s.add8(value); } + void addData(Serializer& s) const { s.add8(value); } unsigned char getValue() const { return value; } void setValue(unsigned char v) { value = v; } @@ -123,7 +124,7 @@ public: SerializedTypeID getSType() const { return STI_UINT16; } std::string getText() const; - void add(Serializer& s) const { s.add16(value); } + void addData(Serializer& s) const { s.add16(value); } uint16 getValue() const { return value; } void setValue(uint16 v) { value=v; } @@ -149,7 +150,7 @@ public: SerializedTypeID getSType() const { return STI_UINT32; } std::string getText() const; - void add(Serializer& s) const { s.add32(value); } + void addData(Serializer& s) const { s.add32(value); } uint32 getValue() const { return value; } void setValue(uint32 v) { value=v; } @@ -175,7 +176,7 @@ public: SerializedTypeID getSType() const { return STI_UINT64; } std::string getText() const; - void add(Serializer& s) const { s.add64(value); } + void addData(Serializer& s) const { s.add64(value); } uint64 getValue() const { return value; } void setValue(uint64 v) { value=v; } @@ -267,7 +268,7 @@ public: std::string getText() const; std::string getRaw() const; std::string getFullText() const; - void add(Serializer& s) const; + void addData(Serializer& s) const; int getExponent() const { return mOffset; } uint64 getMantissa() const { return mValue; } @@ -391,7 +392,7 @@ public: SerializedTypeID getSType() const { return STI_HASH128; } virtual std::string getText() const; - void add(Serializer& s) const { s.add128(value); } + void addData(Serializer& s) const { s.add128(value); } const uint128& getValue() const { return value; } void setValue(const uint128& v) { value=v; } @@ -419,7 +420,7 @@ public: SerializedTypeID getSType() const { return STI_HASH160; } virtual std::string getText() const; - void add(Serializer& s) const { s.add160(value); } + void addData(Serializer& s) const { s.add160(value); } const uint160& getValue() const { return value; } void setValue(const uint160& v) { value=v; } @@ -447,7 +448,7 @@ public: SerializedTypeID getSType() const { return STI_HASH256; } std::string getText() const; - void add(Serializer& s) const { s.add256(value); } + void addData(Serializer& s) const { s.add256(value); } const uint256& getValue() const { return value; } void setValue(const uint256& v) { value=v; } @@ -476,7 +477,7 @@ public: virtual SerializedTypeID getSType() const { return STI_VL; } virtual std::string getText() const; - void add(Serializer& s) const { s.addVL(value); } + void addData(Serializer& s) const { s.addVL(value); } const std::vector& peekValue() const { return value; } std::vector& peekValue() { return value; } @@ -641,7 +642,7 @@ public: { return std::auto_ptr(construct(sit, name)); } // std::string getText() const; - void add(Serializer& s) const; + void addData(Serializer& s) const; virtual Json::Value getJson(int) const; SerializedTypeID getSType() const { return STI_PATHSET; } @@ -710,7 +711,7 @@ public: STVector256(const std::vector& vector) : mValue(vector) { ; } SerializedTypeID getSType() const { return STI_VECTOR256; } - void add(Serializer& s) const; + void addData(Serializer& s) const; static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } diff --git a/src/SerializedValidation.cpp b/src/SerializedValidation.cpp index 6eedadb94b..edd4fe721b 100644 --- a/src/SerializedValidation.cpp +++ b/src/SerializedValidation.cpp @@ -11,7 +11,7 @@ SOElement SerializedValidation::sValidationFormat[] = { { sfLoadFee, SOE_OPTIONAL }, { sfBaseFee, SOE_OPTIONAL }, { sfSigningTime, SOE_REQUIRED }, - { sfSigningKey, SOE_REQUIRED }, + { sfSigningPubKey, SOE_REQUIRED }, { sfInvalid, SOE_END } }; @@ -30,7 +30,7 @@ SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint32 sig setValueFieldH256(sfLedgerHash, ledgerHash); setValueFieldU32(sfSigningTime, signTime); if (naSeed.isValid()) - setValueFieldVL(sfSigningKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic()); + setValueFieldVL(sfSigningPubKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic()); if (!isFull) setFlag(sFullFlag); NewcoinAddress::createNodePrivate(naSeed).signNodePrivate(getSigningHash(), mSignature.peekValue()); @@ -73,7 +73,7 @@ bool SerializedValidation::isValid(const uint256& signingHash) const { try { - NewcoinAddress naPublicKey = NewcoinAddress::createNodePublic(getValueFieldVL(sfSigningKey)); + NewcoinAddress naPublicKey = NewcoinAddress::createNodePublic(getValueFieldVL(sfSigningPubKey)); return naPublicKey.isValid() && naPublicKey.verifyNodePublic(signingHash, mSignature.peekValue()); } catch (...) @@ -85,7 +85,7 @@ bool SerializedValidation::isValid(const uint256& signingHash) const NewcoinAddress SerializedValidation::getSignerPublic() const { NewcoinAddress a; - a.setNodePublic(getValueFieldVL(sfSigningKey)); + a.setNodePublic(getValueFieldVL(sfSigningPubKey)); return a; } From 84dd986b6e903bfb51272a2074f7ce9ef125f4f1 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 14:40:56 -0700 Subject: [PATCH 351/426] WS: Add ledger_entry option ledger. --- src/WSDoor.cpp | 20 ++++++++++++++++---- test/standalone-test.js | 20 ++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index 7e6960b831..5eca83fb2d 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -609,10 +609,13 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq jvResult["ledger_index"] = uLedgerIndex; uint256 uNodeIndex; + bool bNodeBinary = false; if (jvRequest.isMember("index")) { - jvResult["error"] = "notImplemented"; + // XXX Needs to provide proof. + uNodeIndex.SetHex(jvRequest["index"].asString()); + bNodeBinary = true; } else if (jvRequest.isMember("account_root")) { @@ -675,12 +678,21 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq if (!sleNode) { // Not found. - // XXX We should also provide proof. - jvResult["error"] = "entryNotFound"; + // XXX Should also provide proof. + jvResult["error"] = "entryNotFound"; + } + else if (bNodeBinary) + { + // XXX Should also provide proof. + Serializer s; + + sleNode->add(s); + + jvResult["node_binary"] = strHex(s.peekData()); } else { - jvResult["node"] = sleNode->getJson(0); + jvResult["node"] = sleNode->getJson(0); } } } diff --git a/test/standalone-test.js b/test/standalone-test.js index a3fb947498..6a18592a42 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -163,6 +163,26 @@ buster.testCase("Websocket commands", { }); }); }, + + 'ledger_entry index' : + function(done) { + alpha.ledger_closed(function (r) { + // console.log("result: %s", JSON.stringify(r)); + + buster.refute('error' in r); + + alpha.ledger_entry({ + 'ledger_index' : r.ledger_index, + 'index' : "2B6AC232AA4C4BE41BF49D2459FA4A0347E1B543A4C92FCEE0821C0201E2E9A8", + } , function (r) { + console.log("node: %s", JSON.stringify(r)); + + buster.assert('node_binary' in r); + done(); + }); + }); + }, + }); // vim:ts=4 From a584a9c2843ed332782135b3723027dda5b9365d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 15:16:38 -0700 Subject: [PATCH 352/426] WS: Add ledger_entry option offer. --- src/WSDoor.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index 5eca83fb2d..8f3a94b100 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -640,7 +640,28 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("offer")) { - jvResult["error"] = "notImplemented"; + NewcoinAddress naAccountID; + + if (!jvRequest.isObject()) + { + uNodeIndex.SetHex(jvRequest["offer"].asString()); + } + else if (!jvRequest["offer"].isMember("account") + || !jvRequest["offer"].isMember("seq") + || !jvRequest["offer"]["seq"].isIntegral()) + { + jvResult["error"] = "malformedRequest"; + } + else if (!naAccountID.setAccountID(jvRequest["offer"]["account"].asString())) + { + jvResult["error"] = "malformedAddress"; + } + else + { + uint32 uSequence = jvRequest["offer"]["seq"].asUInt(); + + uNodeIndex = Ledger::getOfferIndex(naAccountID.getAccountID(), uSequence); + } } else if (jvRequest.isMember("ripple_state")) { From da7155d8ca3f513e9283560b3b23f6aaa933aa16 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 15:42:30 -0700 Subject: [PATCH 353/426] WS: Add ledger_entry option generator. Also have ledger entry return index. --- src/WSDoor.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index 8f3a94b100..e5c68ed82e 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -636,7 +636,29 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("generator")) { - jvResult["error"] = "notImplemented"; + NewcoinAddress naGeneratorID; + + if (!jvRequest.isObject()) + { + uNodeIndex.SetHex(jvRequest["generator"].asString()); + } + else if (!jvRequest["generator"].isMember("regular_seed")) + { + jvResult["error"] = "malformedRequest"; + } + else if (!naGeneratorID.setSeedGeneric(jvRequest["generator"]["regular_seed"].asString())) + { + jvResult["error"] = "malformedAddress"; + } + else + { + NewcoinAddress na0Public; // To find the generator's index. + NewcoinAddress naGenerator = NewcoinAddress::createGeneratorPublic(naGeneratorID); + + na0Public.setAccountPublic(naGenerator, 0); + + uNodeIndex = Ledger::getGeneratorIndex(na0Public.getAccountID()); + } } else if (jvRequest.isMember("offer")) { @@ -710,10 +732,12 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq sleNode->add(s); jvResult["node_binary"] = strHex(s.peekData()); + jvResult["index"] = uNodeIndex.ToString(); } else { jvResult["node"] = sleNode->getJson(0); + jvResult["index"] = uNodeIndex.ToString(); } } } From b6653732b0f84c120a45fff01932d5c4460a6de1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 27 Sep 2012 15:43:29 -0700 Subject: [PATCH 354/426] New serializer work. Rework add/addRaw/addData per discussion with Arthur. New STObject add/deserialize code. STArray add/deserialize code. Allow arrays of normal fields. Other small fixes. --- src/Amount.cpp | 2 +- src/SerializedObject.cpp | 94 +++++++++++++++++++++++++++++++++++++--- src/SerializedObject.h | 61 +++++++++++++------------- src/SerializedTypes.cpp | 4 +- src/SerializedTypes.h | 25 +++++------ src/Serializer.h | 2 +- 6 files changed, 132 insertions(+), 56 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 8bd2d96a02..bfcad54d37 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -275,7 +275,7 @@ void STAmount::canonicalize() assert((mValue != 0) || (mOffset != -100) ); } -void STAmount::addData(Serializer& s) const +void STAmount::add(Serializer& s) const { if (mIsNative) { diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 18f20388b7..25219648d3 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -186,6 +186,14 @@ bool STObject::set(SerializerIterator& sit, int depth) return false; } +std::auto_ptr STObject::deserialize(SerializerIterator& sit, SField::ref name) +{ + STObject *o; + std::auto_ptr object(o = new STObject(name)); + o->set(sit, 1); + return object; +} + std::string STObject::getFullText() const { std::string ret; @@ -211,15 +219,28 @@ std::string STObject::getFullText() const void STObject::add(Serializer& s) const { - addFieldID(s); - addData(s); - s.addFieldID(STI_OBJECT, 1); -} + std::map fields; -void STObject::addData(Serializer& s) const -{ // FIXME: need to add in sorted order BOOST_FOREACH(const SerializedType& it, mData) - it.add(s); + { // pick out the fields and sort them + if (it.getSType() != STI_NOTPRESENT) + fields.insert(std::make_pair(it.getFName().fieldCode, &it)); + } + + + typedef std::pair field_iterator; + BOOST_FOREACH(field_iterator& it, fields) + { // insert them in sorted order + const SerializedType* field = it.second; + + field->addFieldID(s); + field->add(s); + + if (dynamic_cast(field)) + s.addFieldID(STI_OBJECT, 1); + else if (dynamic_cast(field)) + s.addFieldID(STI_ARRAY, 1); + } } std::string STObject::getText() const @@ -653,6 +674,65 @@ Json::Value STVector256::getJson(int options) const return ret; } +std::string STArray::getFullText() const +{ + return "WRITEME"; +} + +std::string STArray::getText() const +{ + return "WRITEME"; +} + +Json::Value STArray::getJson(int) const +{ + return Json::Value("WRITEME"); +} + +void STArray::add(Serializer& s) const +{ + BOOST_FOREACH(const SerializedType& object, value) + { + object.addFieldID(s); + object.add(s); + + if (dynamic_cast(&object)) + s.addFieldID(STI_OBJECT, 1); + else if (dynamic_cast(&object)) + s.addFieldID(STI_ARRAY, 1); + } +} + +bool STArray::isEquivalent(const SerializedType& t) const +{ + const STArray* v = dynamic_cast(&t); + if (!v) + return false; + return value == v->value; +} + +STArray* STArray::construct(SerializerIterator& sit, SField::ref field) +{ + vector value; + + while (!sit.empty()) + { + int type, field; + sit.getFieldID(type, field); + if ((type == STI_ARRAY) && (field == 1)) + break; + + SField::ref fn = SField::getField(type, field); + if (fn.isInvalid()) + throw std::runtime_error("Unknown field"); + + value.push_back(*STObject::makeDeserializedObject(fn.fieldType, fn, sit, 1)); + } + + return new STArray(field, value); +} + + #if 0 static SOElement testSOElements[2][16] = diff --git a/src/SerializedObject.h b/src/SerializedObject.h index f037f0446d..8c696b6b7f 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -28,7 +28,6 @@ protected: std::vector mType; STObject* duplicate() const { return new STObject(*this); } - static STObject* construct(SerializerIterator&, SField::ref); public: STObject() { ; } @@ -43,8 +42,7 @@ public: virtual ~STObject() { ; } - static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) - { return std::auto_ptr(construct(sit, name)); } + static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name); void setType(SOElement::ptrList); bool isValidForType(); @@ -56,8 +54,7 @@ public: virtual SerializedTypeID getSType() const { return STI_OBJECT; } virtual bool isEquivalent(const SerializedType& t) const; - void add(Serializer& s) const; // with start/end of object - virtual void addData(Serializer& s) const; // just inner elements + virtual void add(Serializer& s) const; // just inner elements Serializer getSerializer() const { Serializer s; add(s); return s; } std::string getFullText() const; std::string getText() const; @@ -140,12 +137,12 @@ public: class STArray : public SerializedType { public: - typedef std::vector vector; - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; - typedef std::vector::reverse_iterator reverse_iterator; - typedef std::vector::const_reverse_iterator const_reverse_iterator; - typedef std::vector::size_type size_type; + typedef std::vector vector; + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + typedef std::vector::reverse_iterator reverse_iterator; + typedef std::vector::const_reverse_iterator const_reverse_iterator; + typedef std::vector::size_type size_type; protected: @@ -164,36 +161,36 @@ public: static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } - const vector& getValue() const { return value; } - vector& getValue() { return value; } + const vector& getValue() const { return value; } + vector& getValue() { return value; } // vector-like functions - void push_back(const STObject& object) { value.push_back(object); } - STObject& operator[](int j) { return value[j]; } - const STObject& operator[](int j) const { return value[j]; } - iterator begin() { return value.begin(); } - const_iterator begin() const { return value.begin(); } - iterator end() { return value.end(); } - const_iterator end() const { return value.end(); } - size_type size() const { return value.size(); } - reverse_iterator rbegin() { return value.rbegin(); } - const_reverse_iterator rbegin() const { return value.rbegin(); } - reverse_iterator rend() { return value.rend(); } - const_reverse_iterator rend() const { return value.rend(); } - iterator erase(iterator pos) { return value.erase(pos); } - void pop_back() { value.pop_back(); } - bool empty() const { return value.empty(); } - void clear() { value.clear(); } + void push_back(const SerializedType& object) { value.push_back(object); } + SerializedType& operator[](int j) { return value[j]; } + const SerializedType& operator[](int j) const { return value[j]; } + iterator begin() { return value.begin(); } + const_iterator begin() const { return value.begin(); } + iterator end() { return value.end(); } + const_iterator end() const { return value.end(); } + size_type size() const { return value.size(); } + reverse_iterator rbegin() { return value.rbegin(); } + const_reverse_iterator rbegin() const { return value.rbegin(); } + reverse_iterator rend() { return value.rend(); } + const_reverse_iterator rend() const { return value.rend(); } + iterator erase(iterator pos) { return value.erase(pos); } + void pop_back() { value.pop_back(); } + bool empty() const { return value.empty(); } + void clear() { value.clear(); } virtual std::string getFullText() const; virtual std::string getText() const; virtual Json::Value getJson(int) const; virtual void add(Serializer& s) const; - bool operator==(const STArray &s) { return value == s.value; } - bool operator!=(const STArray &s) { return value != s.value; } + bool operator==(const STArray &s) { return value == s.value; } + bool operator!=(const STArray &s) { return value != s.value; } - virtual SerializedTypeID getSType() const { return STI_ARRAY; } + virtual SerializedTypeID getSType() const { return STI_ARRAY; } virtual bool isEquivalent(const SerializedType& t) const; }; diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 4e7ed6ec56..6eeb0c9120 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -202,7 +202,7 @@ STVector256* STVector256::construct(SerializerIterator& u, SField::ref name) return new STVector256(name, value); } -void STVector256::addData(Serializer& s) const +void STVector256::add(Serializer& s) const { s.addVL(mValue.empty() ? NULL : mValue[0].begin(), mValue.size() * (256 / 8)); } @@ -427,7 +427,7 @@ std::string STPathSet::getText() const } #endif -void STPathSet::addData(Serializer& s) const +void STPathSet::add(Serializer& s) const { bool bFirst = true; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index e30a2f783c..5748f960ec 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -61,8 +61,7 @@ public: virtual Json::Value getJson(int) const { return getText(); } - virtual void add(Serializer& s) const { addFieldID(s); addData(s); } - virtual void addData(Serializer& s) const { ; } + virtual void add(Serializer& s) const { ; } virtual bool isEquivalent(const SerializedType& t) const { assert(getSType() == STI_NOTPRESENT); return t.getSType() == STI_NOTPRESENT; } @@ -98,7 +97,7 @@ public: SerializedTypeID getSType() const { return STI_UINT8; } std::string getText() const; - void addData(Serializer& s) const { s.add8(value); } + void add(Serializer& s) const { s.add8(value); } unsigned char getValue() const { return value; } void setValue(unsigned char v) { value = v; } @@ -124,7 +123,7 @@ public: SerializedTypeID getSType() const { return STI_UINT16; } std::string getText() const; - void addData(Serializer& s) const { s.add16(value); } + void add(Serializer& s) const { s.add16(value); } uint16 getValue() const { return value; } void setValue(uint16 v) { value=v; } @@ -150,7 +149,7 @@ public: SerializedTypeID getSType() const { return STI_UINT32; } std::string getText() const; - void addData(Serializer& s) const { s.add32(value); } + void add(Serializer& s) const { s.add32(value); } uint32 getValue() const { return value; } void setValue(uint32 v) { value=v; } @@ -176,7 +175,7 @@ public: SerializedTypeID getSType() const { return STI_UINT64; } std::string getText() const; - void addData(Serializer& s) const { s.add64(value); } + void add(Serializer& s) const { s.add64(value); } uint64 getValue() const { return value; } void setValue(uint64 v) { value=v; } @@ -268,7 +267,7 @@ public: std::string getText() const; std::string getRaw() const; std::string getFullText() const; - void addData(Serializer& s) const; + void add(Serializer& s) const; int getExponent() const { return mOffset; } uint64 getMantissa() const { return mValue; } @@ -392,7 +391,7 @@ public: SerializedTypeID getSType() const { return STI_HASH128; } virtual std::string getText() const; - void addData(Serializer& s) const { s.add128(value); } + void add(Serializer& s) const { s.add128(value); } const uint128& getValue() const { return value; } void setValue(const uint128& v) { value=v; } @@ -420,7 +419,7 @@ public: SerializedTypeID getSType() const { return STI_HASH160; } virtual std::string getText() const; - void addData(Serializer& s) const { s.add160(value); } + void add(Serializer& s) const { s.add160(value); } const uint160& getValue() const { return value; } void setValue(const uint160& v) { value=v; } @@ -448,7 +447,7 @@ public: SerializedTypeID getSType() const { return STI_HASH256; } std::string getText() const; - void addData(Serializer& s) const { s.add256(value); } + void add(Serializer& s) const { s.add256(value); } const uint256& getValue() const { return value; } void setValue(const uint256& v) { value=v; } @@ -477,7 +476,7 @@ public: virtual SerializedTypeID getSType() const { return STI_VL; } virtual std::string getText() const; - void addData(Serializer& s) const { s.addVL(value); } + void add(Serializer& s) const { s.addVL(value); } const std::vector& peekValue() const { return value; } std::vector& peekValue() { return value; } @@ -642,7 +641,7 @@ public: { return std::auto_ptr(construct(sit, name)); } // std::string getText() const; - void addData(Serializer& s) const; + void add(Serializer& s) const; virtual Json::Value getJson(int) const; SerializedTypeID getSType() const { return STI_PATHSET; } @@ -711,7 +710,7 @@ public: STVector256(const std::vector& vector) : mValue(vector) { ; } SerializedTypeID getSType() const { return STI_VECTOR256; } - void addData(Serializer& s) const; + void add(Serializer& s) const; static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } diff --git a/src/Serializer.h b/src/Serializer.h index ec762e52c7..8666efe4c3 100644 --- a/src/Serializer.h +++ b/src/Serializer.h @@ -70,7 +70,7 @@ public: bool getFieldID(int& type, int& name, int offset) const; int addFieldID(int type, int name); - int addFieldID(SerializedTypeID type, int name); + int addFieldID(SerializedTypeID type, int name) { return addFieldID(static_cast(type), name); } // normal hash functions uint160 getRIPEMD160(int size=-1) const; From bf36fc84bd17e405285fb1da9f914b8550bfcbb7 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 27 Sep 2012 16:06:12 -0700 Subject: [PATCH 355/426] WS: Add ledger entry option directory. --- src/WSDoor.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index e5c68ed82e..1092e8c037 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -632,7 +632,50 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("directory")) { - jvResult["error"] = "notImplemented"; + + if (!jvRequest.isObject()) + { + uNodeIndex.SetHex(jvRequest["directory"].asString()); + } + else if (jvRequest["directory"].isMember("sub_index") + && !jvRequest["directory"]["sub_index"].isIntegral()) + { + jvResult["error"] = "malformedRequest"; + } + else + { + uint64 uSubIndex = jvRequest["directory"].isMember("sub_index") + ? jvRequest["directory"]["sub_index"].asUInt() + : 0; + + if (jvRequest["directory"].isMember("dir_root")) + { + uint256 uDirRoot; + + uDirRoot.SetHex(jvRequest["dir_root"].asString()); + + uNodeIndex = Ledger::getDirNodeIndex(uDirRoot, uSubIndex); + } + else if (jvRequest["directory"].isMember("owner")) + { + NewcoinAddress naOwnerID; + + if (!naOwnerID.setAccountID(jvRequest["directory"]["owner"].asString())) + { + jvResult["error"] = "malformedAddress"; + } + else + { + uint256 uDirRoot = Ledger::getOwnerDirIndex(naOwnerID.getAccountID()); + + uNodeIndex = Ledger::getDirNodeIndex(uDirRoot, uSubIndex); + } + } + else + { + jvResult["error"] = "malformedRequest"; + } + } } else if (jvRequest.isMember("generator")) { From 5b9439689043107110dee6ea4939db16e29e115d Mon Sep 17 00:00:00 2001 From: MJK Date: Thu, 27 Sep 2012 17:01:27 -0700 Subject: [PATCH 356/426] Move around to256 to uint256.h, get rid of Conversion.cpp,h --- src/Conversion.cpp | 50 ----------- src/Conversion.h | 11 --- src/Ledger.cpp | 1 - src/LedgerMaster.cpp | 1 - src/Peer.cpp | 1 - src/RPCServer.cpp | 10 +-- src/UniqueNodeList.cpp | 1 - src/uint256.h | 187 +++++++++++++++++++++-------------------- 8 files changed, 100 insertions(+), 162 deletions(-) delete mode 100644 src/Conversion.cpp delete mode 100644 src/Conversion.h diff --git a/src/Conversion.cpp b/src/Conversion.cpp deleted file mode 100644 index 7f9de9029b..0000000000 --- a/src/Conversion.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "Conversion.h" -#include "base58.h" -using namespace std; - -#if 0 - -uint160 protobufTo160(const std::string& buf) -{ - uint160 ret; - // TODO: - return(ret); -} - -uint256 protobufTo256(const std::string& hash) -{ - uint256 ret; - // TODO: - return(ret); -} - -uint160 humanTo160(const std::string& buf) -{ - vector retVec; - DecodeBase58(buf,retVec); - uint160 ret; - memcpy(ret.begin(), &retVec[0], ret.GetSerializeSize()); - - - return(ret); -} - -bool humanToPK(const std::string& buf,std::vector& retVec) -{ - return(DecodeBase58(buf,retVec)); -} - -bool u160ToHuman(uint160& buf, std::string& retStr) -{ - retStr=EncodeBase58(buf.begin(),buf.end()); - return(true); -} - -#endif - -base_uint256 uint160::to256() const -{ - uint256 m; - memcpy(m.begin(), begin(), size()); - return m; -} diff --git a/src/Conversion.h b/src/Conversion.h deleted file mode 100644 index c2ceb5339a..0000000000 --- a/src/Conversion.h +++ /dev/null @@ -1,11 +0,0 @@ -#include "uint256.h" -#include - -extern uint160 protobufTo160(const std::string& buf); -extern uint256 protobufTo256(const std::string& hash); -extern uint160 humanTo160(const std::string& buf); -extern bool humanToPK(const std::string& buf,std::vector& retVec); - - -extern bool u160ToHuman(uint160& buf, std::string& retStr); - diff --git a/src/Ledger.cpp b/src/Ledger.cpp index e650f9b94f..8d7dec92bf 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -13,7 +13,6 @@ #include "../obj/src/newcoin.pb.h" #include "PackedMessage.h" #include "Config.h" -#include "Conversion.h" #include "BitcoinUtil.h" #include "Wallet.h" #include "LedgerTiming.h" diff --git a/src/LedgerMaster.cpp b/src/LedgerMaster.cpp index abdbf12e99..e0adb16ade 100644 --- a/src/LedgerMaster.cpp +++ b/src/LedgerMaster.cpp @@ -5,7 +5,6 @@ #include "Application.h" #include "NewcoinAddress.h" -#include "Conversion.h" #include "Log.h" uint32 LedgerMaster::getCurrentLedgerIndex() diff --git a/src/Peer.cpp b/src/Peer.cpp index ea27e06c81..641a33571c 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -12,7 +12,6 @@ #include "Peer.h" #include "Config.h" #include "Application.h" -#include "Conversion.h" #include "SerializedTransaction.h" #include "utils.h" #include "Log.h" diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 7f44f1fe58..202f0e5e3d 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -6,7 +6,6 @@ #include "Application.h" #include "RPC.h" #include "Wallet.h" -#include "Conversion.h" #include "NewcoinAddress.h" #include "AccountState.h" #include "NicknameState.h" @@ -15,9 +14,6 @@ #include "RippleLines.h" #include "Pathfinder.h" -#include "Conversion.h" - -extern uint160 humanTo160(const std::string& buf); #include @@ -1783,7 +1779,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) // Destination exists, ordinary send. STPathSet spsPaths; - + /* uint160 srcCurrencyID; bool ret_b; ret_b = false; @@ -1793,7 +1789,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) ret_b = pf.findPaths(5, 1, spsPaths); // TODO: Nope; the above can't be right - + */ trans = Transaction::sharedPayment( naAccountPublic, naAccountPrivate, naSrcAccountID, @@ -2544,7 +2540,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "data_fetch", &RPCServer::doDataFetch, 1, 1, true }, { "data_store", &RPCServer::doDataStore, 2, 2, true }, { "ledger", &RPCServer::doLedger, 0, 2, false, optNetwork }, - { "logrotate", &RPCServer::doLogRotate, 0, 0, true, optCurrent }, + { "logrotate", &RPCServer::doLogRotate, 0, 0, false, optCurrent }, { "nickname_info", &RPCServer::doNicknameInfo, 1, 1, false, optCurrent }, { "nickname_set", &RPCServer::doNicknameSet, 2, 3, false, optCurrent }, { "offer_create", &RPCServer::doOfferCreate, 9, 10, false, optCurrent }, diff --git a/src/UniqueNodeList.cpp b/src/UniqueNodeList.cpp index b5b1d2c804..96ca1b7d7d 100644 --- a/src/UniqueNodeList.cpp +++ b/src/UniqueNodeList.cpp @@ -2,7 +2,6 @@ // XXX Want a limit of 2000 validators. #include "Application.h" -#include "Conversion.h" #include "HttpsClient.h" #include "Log.h" #include "ParseSection.h" diff --git a/src/uint256.h b/src/uint256.h index bb11b101b4..3e2ab10e62 100644 --- a/src/uint256.h +++ b/src/uint256.h @@ -386,96 +386,6 @@ public: }; -////////////////////////////////////////////////////////////////////////////// -// -// uint160 -// - -class uint160 : public base_uint160 -{ -public: - typedef base_uint160 basetype; - - uint160() - { - zero(); - } - - uint160(const basetype& b) - { - *this = b; - } - - uint160& operator=(const basetype& b) - { - for (int i = 0; i < WIDTH; i++) - pn[i] = b.pn[i]; - - return *this; - } - - uint160(uint64 b) - { - *this = b; - } - - uint160& operator=(uint64 uHost) - { - zero(); - - // Put in least significant bits. - ((uint64_t *) end())[-1] = htobe64(uHost); - - return *this; - } - - explicit uint160(const std::string& str) - { - SetHex(str); - } - - explicit uint160(const std::vector& vch) - { - if (vch.size() == sizeof(pn)) - memcpy(pn, &vch[0], sizeof(pn)); - else - zero(); - } - - base_uint256 to256() const; -}; - -inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; } -inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; } - -inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; } -inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; } -inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; } - -inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } - -inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; } -inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } -inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } -inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } -inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } -inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } - -extern std::size_t hash_value(const uint160&); - -inline const std::string strHex(const uint160& ui) -{ - return strHex(ui.begin(), ui.size()); -} - ////////////////////////////////////////////////////////////////////////////// // // uint256 @@ -694,5 +604,102 @@ inline int Testuint256AdHoc(std::vector vArg) return (0); } +////////////////////////////////////////////////////////////////////////////// +// +// uint160 +// + +class uint160 : public base_uint160 +{ +public: + typedef base_uint160 basetype; + + uint160() + { + zero(); + } + + uint160(const basetype& b) + { + *this = b; + } + + uint160& operator=(const basetype& b) + { + for (int i = 0; i < WIDTH; i++) + pn[i] = b.pn[i]; + + return *this; + } + + uint160(uint64 b) + { + *this = b; + } + + uint160& operator=(uint64 uHost) + { + zero(); + + // Put in least significant bits. + ((uint64_t *) end())[-1] = htobe64(uHost); + + return *this; + } + + explicit uint160(const std::string& str) + { + SetHex(str); + } + + explicit uint160(const std::vector& vch) + { + if (vch.size() == sizeof(pn)) + memcpy(pn, &vch[0], sizeof(pn)); + else + zero(); + } + + base_uint256 to256() const + { + uint256 m; + memcpy(m.begin(), begin(), size()); + return m; + } + +}; + +inline bool operator==(const uint160& a, uint64 b) { return (base_uint160)a == b; } +inline bool operator!=(const uint160& a, uint64 b) { return (base_uint160)a != b; } + +inline const uint160 operator^(const base_uint160& a, const base_uint160& b) { return uint160(a) ^= b; } +inline const uint160 operator&(const base_uint160& a, const base_uint160& b) { return uint160(a) &= b; } +inline const uint160 operator|(const base_uint160& a, const base_uint160& b) { return uint160(a) |= b; } + +inline bool operator==(const base_uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const base_uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const base_uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const base_uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const base_uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } + +inline bool operator==(const uint160& a, const base_uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const uint160& a, const base_uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const uint160& a, const base_uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const uint160& a, const base_uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const uint160& a, const base_uint160& b) { return (base_uint160)a | (base_uint160)b; } +inline bool operator==(const uint160& a, const uint160& b) { return (base_uint160)a == (base_uint160)b; } +inline bool operator!=(const uint160& a, const uint160& b) { return (base_uint160)a != (base_uint160)b; } +inline const uint160 operator^(const uint160& a, const uint160& b) { return (base_uint160)a ^ (base_uint160)b; } +inline const uint160 operator&(const uint160& a, const uint160& b) { return (base_uint160)a & (base_uint160)b; } +inline const uint160 operator|(const uint160& a, const uint160& b) { return (base_uint160)a | (base_uint160)b; } + +extern std::size_t hash_value(const uint160&); + +inline const std::string strHex(const uint160& ui) +{ + return strHex(ui.begin(), ui.size()); +} + + #endif // vim:ts=4 From 5ab9871fe6ed3abbc56d6bb78c824daab4849def Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 27 Sep 2012 20:40:15 -0700 Subject: [PATCH 357/426] Bump versions to prevent incomatible server-server connections. --- src/Version.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Version.h b/src/Version.h index d7cd3a02aa..382977f4ab 100644 --- a/src/Version.h +++ b/src/Version.h @@ -5,7 +5,7 @@ // #define SERVER_VERSION_MAJOR 0 -#define SERVER_VERSION_MINOR 5 +#define SERVER_VERSION_MINOR 6 #define SERVER_VERSION_SUB "-a" #define SERVER_NAME "NewCoin" @@ -15,12 +15,12 @@ (SERVER_NAME "-" SV_STRINGIZE(SERVER_VERSION_MAJOR) "." SV_STRINGIZE(SERVER_VERSION_MINOR) SERVER_VERSION_SUB) // Version we prefer to speak: -#define PROTO_VERSION_MAJOR 0 -#define PROTO_VERSION_MINOR 7 +#define PROTO_VERSION_MAJOR 1 +#define PROTO_VERSION_MINOR 0 // Version we will speak to: -#define MIN_PROTO_MAJOR 0 -#define MIN_PROTO_MINOR 7 +#define MIN_PROTO_MAJOR 1 +#define MIN_PROTO_MINOR 0 #define MAKE_VERSION_INT(maj,min) ((maj << 16) | min) #define GET_VERSION_MAJOR(ver) (ver >> 16) From b8a84ec83eae88243e2ad3e34b5450dae73b47ff Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 27 Sep 2012 20:40:34 -0700 Subject: [PATCH 358/426] Bug fixes. --- src/FieldNames.cpp | 6 ++++-- src/LedgerFormats.cpp | 26 ++++++++++++++++++-------- src/TransactionFormats.cpp | 31 ++++++++++++++++++------------- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index 98ba23616e..d631fb7f01 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -7,6 +7,10 @@ #include +// These must stay at the top of this file +std::map SField::codeToField; +boost::mutex SField::mapMutex; + SField sfInvalid(-1), sfGeneric(0); SField sfLedgerEntry(FIELD_CODE(STI_LEDGERENTRY, 1), STI_LEDGERENTRY, 1, "LedgerEntry"); SField sfTransaction(FIELD_CODE(STI_TRANSACTION, 1), STI_TRANSACTION, 1, "Transaction"); @@ -18,8 +22,6 @@ SField sfValidation(FIELD_CODE(STI_VALIDATION, 1), STI_VALIDATION, 1, "Validatio #undef FIELD #undef TYPE -std::map SField::codeToField; -boost::mutex SField::mapMutex; SField::ref SField::getField(int code) { diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 37cc7906e4..59aa5fd668 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -1,10 +1,14 @@ #include "LedgerFormats.h" +#define LEF_BASE \ + { sfLedgerEntryType, SOE_REQUIRED }, \ + { sfFlags, SOE_REQUIRED }, \ + { sfLedgerIndex, SOE_OPTIONAL }, + LedgerEntryFormat LedgerFormats[]= { - { "AccountRoot", ltACCOUNT_ROOT, { - { sfFlags, SOE_REQUIRED }, + { "AccountRoot", ltACCOUNT_ROOT, { LEF_BASE { sfAccount, SOE_REQUIRED }, { sfSequence, SOE_REQUIRED }, { sfBalance, SOE_REQUIRED }, @@ -20,7 +24,8 @@ LedgerEntryFormat LedgerFormats[]= { sfPublishSize, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "Contract", ltCONTRACT, { + { "Contract", ltCONTRACT, { LEF_BASE + { sfLedgerEntryType,SOE_REQUIRED }, { sfFlags, SOE_REQUIRED }, { sfAccount, SOE_REQUIRED }, { sfBalance, SOE_REQUIRED }, @@ -36,25 +41,29 @@ LedgerEntryFormat LedgerFormats[]= { sfExpireCode, SOE_REQUIRED }, { sfInvalid, SOE_END } } }, - { "DirectoryNode", ltDIR_NODE, { + { "DirectoryNode", ltDIR_NODE, { LEF_BASE + { sfLedgerEntryType,SOE_REQUIRED }, { sfFlags, SOE_REQUIRED }, { sfIndexes, SOE_REQUIRED }, { sfIndexNext, SOE_OPTIONAL }, { sfIndexPrevious, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "GeneratorMap", ltGENERATOR_MAP, { + { "GeneratorMap", ltGENERATOR_MAP, { LEF_BASE + { sfLedgerEntryType,SOE_REQUIRED }, { sfFlags, SOE_REQUIRED }, { sfGenerator, SOE_REQUIRED }, { sfInvalid, SOE_END } } }, - { "Nickname", ltNICKNAME, { + { "Nickname", ltNICKNAME, { LEF_BASE + { sfLedgerEntryType,SOE_REQUIRED }, { sfFlags, SOE_REQUIRED }, { sfAccount, SOE_REQUIRED }, { sfMinimumOffer, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "Offer", ltOFFER, { + { "Offer", ltOFFER, { LEF_BASE + { sfLedgerEntryType,SOE_REQUIRED }, { sfFlags, SOE_REQUIRED }, { sfAccount, SOE_REQUIRED }, { sfSequence, SOE_REQUIRED }, @@ -68,7 +77,8 @@ LedgerEntryFormat LedgerFormats[]= { sfExpiration, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "RippleState", ltRIPPLE_STATE, { + { "RippleState", ltRIPPLE_STATE, { LEF_BASE + { sfLedgerEntryType,SOE_REQUIRED }, { sfFlags, SOE_REQUIRED }, { sfBalance, SOE_REQUIRED }, { sfLowID, SOE_REQUIRED }, diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index a23d82320c..2216180dd6 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -1,9 +1,14 @@ #include "TransactionFormats.h" +#define TF_BASE \ + { sfTransactionType, SOE_REQUIRED }, \ + { sfFlags, SOE_REQUIRED }, \ + { sfSignature, SOE_OPTIONAL }, + TransactionFormat InnerTxnFormats[]= { - { "AccountSet", ttACCOUNT_SET, { + { "AccountSet", ttACCOUNT_SET, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfSourceTag, SOE_OPTIONAL }, { sfEmailHash, SOE_OPTIONAL }, @@ -15,7 +20,7 @@ TransactionFormat InnerTxnFormats[]= { sfPublishSize, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "Claim", ttCLAIM, { + { "Claim", ttCLAIM, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfGenerator, SOE_REQUIRED }, { sfPublicKey, SOE_REQUIRED }, @@ -23,7 +28,7 @@ TransactionFormat InnerTxnFormats[]= { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "CreditSet", ttCREDIT_SET, { + { "CreditSet", ttCREDIT_SET, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfDestination, SOE_REQUIRED }, { sfSourceTag, SOE_OPTIONAL }, @@ -33,7 +38,7 @@ TransactionFormat InnerTxnFormats[]= { sfInvalid, SOE_END } } }, /* - { "Invoice", ttINVOICE, { + { "Invoice", ttINVOICE, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfTarget, SOE_REQUIRED }, { sfAmount, SOE_REQUIRED }, @@ -43,7 +48,7 @@ TransactionFormat InnerTxnFormats[]= { sfInvalid, SOE_END } } }, */ - { "NicknameSet", ttNICKNAME_SET, { + { "NicknameSet", ttNICKNAME_SET, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfNickname, SOE_REQUIRED }, { sfMinimumOffer, SOE_OPTIONAL }, @@ -51,7 +56,7 @@ TransactionFormat InnerTxnFormats[]= { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "OfferCreate", ttOFFER_CREATE, { + { "OfferCreate", ttOFFER_CREATE, { TF_BASE { sfFlags, SOE_REQUIRED}, { sfTakerPays, SOE_REQUIRED }, { sfTakerGets, SOE_REQUIRED }, @@ -59,19 +64,19 @@ TransactionFormat InnerTxnFormats[]= { sfExpiration, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "OfferCancel", ttOFFER_CANCEL, { + { "OfferCancel", ttOFFER_CANCEL, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfOfferSequence, SOE_REQUIRED }, { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "PasswordFund", ttPASSWORD_FUND, { + { "PasswordFund", ttPASSWORD_FUND, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfDestination, SOE_REQUIRED }, { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "PasswordSet", ttPASSWORD_SET, { + { "PasswordSet", ttPASSWORD_SET, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfAuthorizedKey, SOE_REQUIRED }, { sfGenerator, SOE_REQUIRED }, @@ -80,7 +85,7 @@ TransactionFormat InnerTxnFormats[]= { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "Payment", ttPAYMENT, { + { "Payment", ttPAYMENT, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfDestination, SOE_REQUIRED }, { sfAmount, SOE_REQUIRED }, @@ -90,7 +95,7 @@ TransactionFormat InnerTxnFormats[]= { sfInvoiceID, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "WalletAdd", ttWALLET_ADD, { + { "WalletAdd", ttWALLET_ADD, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfAmount, SOE_REQUIRED }, { sfAuthorizedKey, SOE_REQUIRED }, @@ -99,7 +104,7 @@ TransactionFormat InnerTxnFormats[]= { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "Contract", ttCONTRACT, { + { "Contract", ttCONTRACT, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfExpiration, SOE_REQUIRED }, { sfBondAmount, SOE_REQUIRED }, @@ -111,7 +116,7 @@ TransactionFormat InnerTxnFormats[]= { sfExpireCode, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, - { "RemoveContract", ttCONTRACT_REMOVE, { + { "RemoveContract", ttCONTRACT_REMOVE, { TF_BASE { sfFlags, SOE_REQUIRED }, { sfTarget, SOE_REQUIRED }, { sfInvalid, SOE_END } } From 2c2bfab52fcca1a8f0bca7613b1e0057af86fd16 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 27 Sep 2012 20:47:11 -0700 Subject: [PATCH 359/426] STArrays should only hold STObject's --- src/SerializedObject.cpp | 14 +++----------- src/SerializedObject.h | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 25219648d3..e2f3cbeab3 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -235,11 +235,7 @@ void STObject::add(Serializer& s) const field->addFieldID(s); field->add(s); - - if (dynamic_cast(field)) - s.addFieldID(STI_OBJECT, 1); - else if (dynamic_cast(field)) - s.addFieldID(STI_ARRAY, 1); + s.addFieldID(STI_OBJECT, 1); } } @@ -691,15 +687,11 @@ Json::Value STArray::getJson(int) const void STArray::add(Serializer& s) const { - BOOST_FOREACH(const SerializedType& object, value) + BOOST_FOREACH(const STObject& object, value) { object.addFieldID(s); object.add(s); - - if (dynamic_cast(&object)) - s.addFieldID(STI_OBJECT, 1); - else if (dynamic_cast(&object)) - s.addFieldID(STI_ARRAY, 1); + s.addFieldID(STI_OBJECT, 1); } } diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 8c696b6b7f..bed99e969b 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -137,12 +137,12 @@ public: class STArray : public SerializedType { public: - typedef std::vector vector; - typedef std::vector::iterator iterator; - typedef std::vector::const_iterator const_iterator; - typedef std::vector::reverse_iterator reverse_iterator; - typedef std::vector::const_reverse_iterator const_reverse_iterator; - typedef std::vector::size_type size_type; + typedef std::vector vector; + typedef std::vector::iterator iterator; + typedef std::vector::const_iterator const_iterator; + typedef std::vector::reverse_iterator reverse_iterator; + typedef std::vector::const_reverse_iterator const_reverse_iterator; + typedef std::vector::size_type size_type; protected: @@ -165,9 +165,9 @@ public: vector& getValue() { return value; } // vector-like functions - void push_back(const SerializedType& object) { value.push_back(object); } - SerializedType& operator[](int j) { return value[j]; } - const SerializedType& operator[](int j) const { return value[j]; } + void push_back(const STObject& object) { value.push_back(object); } + STObject& operator[](int j) { return value[j]; } + const STObject& operator[](int j) const { return value[j]; } iterator begin() { return value.begin(); } const_iterator begin() const { return value.begin(); } iterator end() { return value.end(); } @@ -191,7 +191,7 @@ public: bool operator!=(const STArray &s) { return value != s.value; } virtual SerializedTypeID getSType() const { return STI_ARRAY; } - virtual bool isEquivalent(const SerializedType& t) const; + virtual bool isEquivalent(const STObject& t) const; }; #endif From febe7a1224933073af03e2e09d8f69df791966cc Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 27 Sep 2012 20:47:50 -0700 Subject: [PATCH 360/426] Search/replace went slightly awry. --- src/SerializedObject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializedObject.h b/src/SerializedObject.h index bed99e969b..c74402f15c 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -191,7 +191,7 @@ public: bool operator!=(const STArray &s) { return value != s.value; } virtual SerializedTypeID getSType() const { return STI_ARRAY; } - virtual bool isEquivalent(const STObject& t) const; + virtual bool isEquivalent(const SerializedType& t) const; }; #endif From b88d6486a6bc22605c4b4537997fb6290ea33e08 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 27 Sep 2012 20:55:10 -0700 Subject: [PATCH 361/426] Rather than a polymorphic downcast, just fill in the object in place. --- src/SerializedObject.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index e2f3cbeab3..4834a1f3f5 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -718,7 +718,8 @@ STArray* STArray::construct(SerializerIterator& sit, SField::ref field) if (fn.isInvalid()) throw std::runtime_error("Unknown field"); - value.push_back(*STObject::makeDeserializedObject(fn.fieldType, fn, sit, 1)); + value.push_back(STObject(fn)); + value.rbegin()->set(sit, 1); } return new STArray(field, value); From e2fb75046fee67e741f3b15b9c3b2f81f26324b6 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 28 Sep 2012 12:29:44 -0700 Subject: [PATCH 362/426] RPC: Fix parsing of ripple options limit and average. --- src/RPCServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 202f0e5e3d..4028d8496c 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1451,7 +1451,7 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) bLimit = params.size() != iArg ? params[iArg].asString() == "limit" : false; bAverage = params.size() != iArg ? params[iArg].asString() == "average" : false; - if (!bPartial && !bFull) + if (!bLimit && !bAverage) { return RPCError(rpcINVALID_PARAMS); } From 9f2b38a441ec2d5c94b0cca3593bacfa541cde4d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 28 Sep 2012 12:30:29 -0700 Subject: [PATCH 363/426] TransactionEngine: do not allow bad transfer rate to be set. --- src/TransactionAction.cpp | 10 ++++++++-- src/TransactionErr.cpp | 2 ++ src/TransactionErr.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index 16d2e3f1ed..f37ef5a31c 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -166,18 +166,24 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { uint32 uRate = txn.getITFieldU32(sfTransferRate); - if (!uRate) + if (!uRate || uRate == QUALITY_ONE) { Log(lsINFO) << "doAccountSet: unset transfer rate"; mTxnAccount->makeIFieldAbsent(sfTransferRate); } - else + else if (uRate > QUALITY_ONE) { Log(lsINFO) << "doAccountSet: set transfer rate"; mTxnAccount->setIFieldU32(sfTransferRate, uRate); } + else + { + Log(lsINFO) << "doAccountSet: bad transfer rate"; + + return temBAD_TRANSFER_RATE; + } } // diff --git a/src/TransactionErr.cpp b/src/TransactionErr.cpp index 878d7cd1cd..85ea95594b 100644 --- a/src/TransactionErr.cpp +++ b/src/TransactionErr.cpp @@ -31,6 +31,7 @@ bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman) { temBAD_PATH, "temBAD_PATH", "Malformed." }, { temBAD_PATH_LOOP, "temBAD_PATH_LOOP", "Malformed." }, { temBAD_PUBLISH, "temBAD_PUBLISH", "Malformed: bad publish." }, + { temBAD_TRANSFER_RATE, "temBAD_TRANSFER_RATE", "Malformed: transfer rate must be >= 1.0" }, { temBAD_SET_ID, "temBAD_SET_ID", "Malformed." }, { temCREATEXNS, "temCREATEXNS", "Can not specify non XNS for Create." }, { temDST_IS_SRC, "temDST_IS_SRC", "Destination may not be source." }, @@ -89,3 +90,4 @@ std::string transHuman(TER terCode) return transResultInfo(terCode, strToken, strHuman) ? strHuman : "-"; } +// vim:ts=4 diff --git a/src/TransactionErr.h b/src/TransactionErr.h index 4f0d5a7994..7ce5cd6109 100644 --- a/src/TransactionErr.h +++ b/src/TransactionErr.h @@ -33,6 +33,7 @@ enum TER // aka TransactionEngineResult temBAD_PATH, temBAD_PATH_LOOP, temBAD_PUBLISH, + temBAD_TRANSFER_RATE, temBAD_SET_ID, temCREATEXNS, temDST_IS_SRC, From 3cd90687930e3b387302d7e8591d0fa782af2ba0 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 28 Sep 2012 12:44:39 -0700 Subject: [PATCH 364/426] Clean up js. --- js/ledger.js | 34 ---------------------------------- js/transaction.js | 38 -------------------------------------- test/server.js | 1 - 3 files changed, 73 deletions(-) delete mode 100644 js/ledger.js delete mode 100644 js/transaction.js diff --git a/js/ledger.js b/js/ledger.js deleted file mode 100644 index 42c04fc156..0000000000 --- a/js/ledger.js +++ /dev/null @@ -1,34 +0,0 @@ -// -// Tools for working with ledger entries. -// -// Fundamentally, we work in the more strict case of not trusting the ledger as presented. If we have a server we trust, then the -// burden of verify the ledger entries is left to the server. But, we work in the same fundamental units of information, ledger -// entries, to keep the code orthagonal. -// - -var serializer = require("./serializer"); - -exports.getLedgerEntry = function(key, done) { - var id = (ws.id += 1); - - ws.response[id] = done; - - ws.send({ - 'command': 'getLedgerEntry', - 'id': id, - 'ledger': ledger, - 'account': accountId, - 'proof': false // Eventually, we will want proof if the server is untrusted. - }); -}; - -exports.getAccountRootNode = function(ledger, accountId, done) { - var s = new Serializer(); - - s.addUInt16('a'); - s.addUInt160(accountId); - - getLedgerEntry(s.getSHA512Half(), done); -}; - -// vim:ts=4 diff --git a/js/transaction.js b/js/transaction.js deleted file mode 100644 index 3706a24a1c..0000000000 --- a/js/transaction.js +++ /dev/null @@ -1,38 +0,0 @@ -// Work with transactions. -// -// This works for both trusted and untrusted servers. -// -// For untrusted servers: -// - We never send a secret to an untrusted server. -// - Convert transactions to and from JSON. -// - Sign and verify signatures. -// - Encrypt and decrypt. -// -// For trusted servers: -// - We need a websocket way of working with transactions as JSON. -// - This allows us to not need to port the transaction tools to so many -// languages. -// - -var commands = {}; - -commands.buildSend = function(params) { - var srcAccountID = params.srcAccountID; - var fee = params.fee; - var dstAccountID = params.dstAccountID; - var amount = params.amount; - var sendMax = params.sendMax; - var partial = params.partial; - var limit = params.limit; -}; - - -exports.trustedCreate = function() { - -}; - -exports.untrustedCreate = function() { - -}; - -// vim:ts=4 diff --git a/test/server.js b/test/server.js index 83ed044f39..9e20569a58 100644 --- a/test/server.js +++ b/test/server.js @@ -15,7 +15,6 @@ var fs = require("fs"); var path = require("path"); var util = require("util"); var child = require("child_process"); -var WebSocket = require("ws"); var servers = {}; From 8c2eda1f93536138c881bb0c15e07ea445e9b1d4 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 14:26:19 -0700 Subject: [PATCH 365/426] Fix signature/hash generation. --- src/SerializedObject.cpp | 29 ++++++++++++++++++++++++++--- src/SerializedObject.h | 6 +++++- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 4834a1f3f5..cc6f6f9136 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -217,14 +217,18 @@ std::string STObject::getFullText() const return ret; } -void STObject::add(Serializer& s) const +void STObject::add(Serializer& s, bool withSigningFields) const { std::map fields; BOOST_FOREACH(const SerializedType& it, mData) { // pick out the fields and sort them if (it.getSType() != STI_NOTPRESENT) - fields.insert(std::make_pair(it.getFName().fieldCode, &it)); + { + SField::ref fName = it.getFName(); + if (withSigningFields || (fName == sfSignature) || (fName == sfSignatures)) + fields.insert(std::make_pair(it.getFName().fieldCode, &it)); + } } @@ -235,7 +239,10 @@ void STObject::add(Serializer& s) const field->addFieldID(s); field->add(s); - s.addFieldID(STI_OBJECT, 1); + if (dynamic_cast(field) != NULL) + s.addFieldID(STI_ARRAY, 1); + else if (dynamic_cast(field) != NULL) + s.addFieldID(STI_OBJECT, 1); } } @@ -272,6 +279,22 @@ bool STObject::isEquivalent(const SerializedType& t) const return (it1 == end1) && (it2 == end2); } +uint256 getHash(uint32 prefix) cosnt +{ + Serializer s; + s.add32(prefix); + add(s, true); + return s.getSHA512Half(); +} + +uint256 getSigningHash(uint32 prefix) cosnt +{ + Serializer s; + s.add32(prefix); + add(s, false); + return s.getSHA512Half(); +} + int STObject::getFieldIndex(SField::ref field) const { int i = 0; diff --git a/src/SerializedObject.h b/src/SerializedObject.h index c74402f15c..adb054586b 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -54,7 +54,8 @@ public: virtual SerializedTypeID getSType() const { return STI_OBJECT; } virtual bool isEquivalent(const SerializedType& t) const; - virtual void add(Serializer& s) const; // just inner elements + virtual void add(Serializer& s) const { add(s, true); } // just inner elements + void add(Serializer& s, int withSignature) const; Serializer getSerializer() const { Serializer s; add(s); return s; } std::string getFullText() const; std::string getText() const; @@ -72,6 +73,9 @@ public: bool clearFlag(uint32); uint32 getFlags() const; + uint256 getHash(uint32 prefix) const; + uint256 getSigningHash(uint32 prefix) const; + const SerializedType& peekAtIndex(int offset) const { return mData[offset]; } SerializedType& getIndex(int offset) { return mData[offset]; } const SerializedType* peekAtPIndex(int offset) const { return &(mData[offset]); } From 7bd25b8688598441db41d9265616fb3829bcfb98 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 28 Sep 2012 14:59:34 -0700 Subject: [PATCH 366/426] Remove LowID and HighID from ripple state nodes. --- src/LedgerEntrySet.cpp | 12 +++++++----- src/LedgerFormats.cpp | 2 -- src/RippleState.cpp | 6 +++--- src/SerializedLedger.cpp | 27 ++++++++++++++++++--------- src/TransactionAction.cpp | 22 ++++++++++++++-------- src/Version.h | 4 ++-- 6 files changed, 44 insertions(+), 29 deletions(-) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index dbb364ebca..8588f8f294 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -394,10 +394,9 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) if (origNode->getType() == ltRIPPLE_STATE) { - metaNode.addAccount(TMSLowID, origNode->getIValueFieldAccount(sfLowID)); - metaNode.addAccount(TMSHighID, origNode->getIValueFieldAccount(sfHighID)); + metaNode.addAccount(TMSLowID, NewcoinAddress::createAccountID(origNode->getIValueFieldAmount(sfLowLimit).getIssuer())); + metaNode.addAccount(TMSHighID, NewcoinAddress::createAccountID(origNode->getIValueFieldAmount(sfHighLimit).getIssuer())); } - } if (origNode->getType() == ltOFFER) @@ -1011,6 +1010,7 @@ STAmount LedgerEntrySet::rippleTransferFee(const uint160& uSenderID, const uint1 void LedgerEntrySet::rippleCredit(const uint160& uSenderID, const uint160& uReceiverID, const STAmount& saAmount, bool bCheckIssuer) { uint160 uIssuerID = saAmount.getIssuer(); + uint160 uCurrencyID = saAmount.getCurrency(); assert(!bCheckIssuer || uSenderID == uIssuerID || uReceiverID == uIssuerID); @@ -1024,14 +1024,16 @@ void LedgerEntrySet::rippleCredit(const uint160& uSenderID, const uint160& uRece STAmount saBalance = saAmount; + saBalance.setIssuer(ACCOUNT_ONE); + 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); + sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, STAmount(uCurrencyID, uSenderID)); + sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uReceiverID)); } else { diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 1db310a4c1..fc70296bab 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -73,9 +73,7 @@ LedgerEntryFormat LedgerFormats[]= { "RippleState", ltRIPPLE_STATE, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, { S_FIELD(Balance), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(LowID), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(LowLimit), STI_AMOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(HighID), STI_ACCOUNT, SOE_REQUIRED, 0 }, { S_FIELD(HighLimit), STI_AMOUNT, SOE_REQUIRED, 0 }, { S_FIELD(LastTxnID), STI_HASH256, SOE_REQUIRED, 0 }, { S_FIELD(LastTxnSeq), STI_UINT32, SOE_REQUIRED, 0 }, diff --git a/src/RippleState.cpp b/src/RippleState.cpp index 26a5bb7072..72b9efd10d 100644 --- a/src/RippleState.cpp +++ b/src/RippleState.cpp @@ -7,12 +7,12 @@ RippleState::RippleState(SerializedLedgerEntry::pointer ledgerEntry) : { if (!mLedgerEntry || mLedgerEntry->getType() != ltRIPPLE_STATE) return; - mLowID = mLedgerEntry->getIValueFieldAccount(sfLowID); - mHighID = mLedgerEntry->getIValueFieldAccount(sfHighID); - mLowLimit = mLedgerEntry->getIValueFieldAmount(sfLowLimit); mHighLimit = mLedgerEntry->getIValueFieldAmount(sfHighLimit); + mLowID = NewcoinAddress::createAccountID(mLowLimit.getIssuer()); + mHighID = NewcoinAddress::createAccountID(mHighLimit.getIssuer()); + mLowQualityIn = mLedgerEntry->getIFieldU32(sfLowQualityIn); mLowQualityOut = mLedgerEntry->getIFieldU32(sfLowQualityOut); diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 0353df8b69..08b807890e 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -128,12 +128,12 @@ NewcoinAddress SerializedLedgerEntry::getOwner() NewcoinAddress SerializedLedgerEntry::getFirstOwner() { - return getIValueFieldAccount(sfLowID); + return NewcoinAddress::createAccountID(getIValueFieldAmount(sfLowLimit).getIssuer()); } NewcoinAddress SerializedLedgerEntry::getSecondOwner() { - return getIValueFieldAccount(sfHighID); + return NewcoinAddress::createAccountID(getIValueFieldAmount(sfHighLimit).getIssuer()); } std::vector SerializedLedgerEntry::getOwners() @@ -146,16 +146,25 @@ std::vector SerializedLedgerEntry::getOwners() switch (getIFieldSType(i)) { case sfAccount: - case sfLowID: - case sfHighID: - { - const STAccount* entry = dynamic_cast(mObject.peekAtPIndex(i)); - if ((entry != NULL) && entry->getValueH160(account)) - owners.push_back(Ledger::getAccountRootIndex(account)); - } + { + const STAccount* entry = dynamic_cast(mObject.peekAtPIndex(i)); + if ((entry != NULL) && entry->getValueH160(account)) + owners.push_back(Ledger::getAccountRootIndex(account)); + } + break; + + case sfLowLimit: + case sfHighLimit: + { + const STAmount* entry = dynamic_cast(mObject.peekAtPIndex(i)); + if ((entry != NULL)) + owners.push_back(Ledger::getAccountRootIndex(entry->getIssuer())); + } + break; default: nothing(); + break; } } diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index f37ef5a31c..786ed762f3 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -246,13 +246,13 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) if (!uDstAccountID) { - Log(lsINFO) << "doCreditSet: Invalid transaction: Destination account not specifed."; + Log(lsINFO) << "doCreditSet: Malformed transaction: Destination account not specifed."; return temDST_NEEDED; } else if (mTxnAccountID == uDstAccountID) { - Log(lsINFO) << "doCreditSet: Invalid transaction: Can not extend credit to self."; + Log(lsINFO) << "doCreditSet: Malformed transaction: Can not extend credit to self."; return temDST_IS_SRC; } @@ -275,6 +275,13 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) const uint160 uCurrencyID = saLimitAmount.getCurrency(); bool bDelIndex = false; + if (bLimitAmount && saLimitAmount.getIssuer() != mTxnAccountID) + { + Log(lsINFO) << "doCreditSet: Malformed transaction: issuer must be signer"; + + return temBAD_ISSUER; + } + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); if (sleRippleState) { @@ -283,8 +290,8 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) if (!saLimitAmount) { // Zeroing line. - uint160 uLowID = sleRippleState->getIValueFieldAccount(sfLowID).getAccountID(); - uint160 uHighID = sleRippleState->getIValueFieldAccount(sfHighID).getAccountID(); + uint160 uLowID = sleRippleState->getIValueFieldAmount(sfLowLimit).getIssuer(); + uint160 uHighID = sleRippleState->getIValueFieldAmount(sfHighLimit).getIssuer(); bool bLow = uLowID == uSrcAccountID; bool bHigh = uLowID == uDstAccountID; bool bBalanceZero = !sleRippleState->getIValueFieldAmount(sfBalance); @@ -306,7 +313,7 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) if (!bDelIndex) { if (bLimitAmount) - sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit , saLimitAmount); + sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit, saLimitAmount); if (!bQualityIn) { @@ -355,9 +362,8 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency. sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAmount); - sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, ACCOUNT_ONE)); - sleRippleState->setIFieldAccount(bFlipped ? sfHighID : sfLowID, mTxnAccountID); - sleRippleState->setIFieldAccount(bFlipped ? sfLowID : sfHighID, uDstAccountID); + sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uDstAccountID)); + if (uQualityIn) sleRippleState->setIFieldU32(bFlipped ? sfHighQualityIn : sfLowQualityIn, uQualityIn); if (uQualityOut) diff --git a/src/Version.h b/src/Version.h index d7cd3a02aa..f35da8166c 100644 --- a/src/Version.h +++ b/src/Version.h @@ -16,11 +16,11 @@ // Version we prefer to speak: #define PROTO_VERSION_MAJOR 0 -#define PROTO_VERSION_MINOR 7 +#define PROTO_VERSION_MINOR 8 // Version we will speak to: #define MIN_PROTO_MAJOR 0 -#define MIN_PROTO_MINOR 7 +#define MIN_PROTO_MINOR 8 #define MAKE_VERSION_INT(maj,min) ((maj << 16) | min) #define GET_VERSION_MAJOR(ver) (ver >> 16) From c74cb38e0915b8b26ce0319af60e342d87381a7e Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 28 Sep 2012 17:46:32 -0700 Subject: [PATCH 367/426] Do not do SNTP in standalone mode. --- src/Application.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Application.cpp b/src/Application.cpp index 00aea956aa..2011ca8e78 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -73,7 +73,8 @@ void Application::run() boost::thread auxThread(boost::bind(&boost::asio::io_service::run, &mAuxService)); auxThread.detach(); - mSNTPClient.init(theConfig.SNTP_SERVERS); + if (!theConfig.RUN_STANDALONE) + mSNTPClient.init(theConfig.SNTP_SERVERS); // // Construct databases. From 40b51892093394abaff50f26f1c5f5c49c3c49a5 Mon Sep 17 00:00:00 2001 From: MJK Date: Fri, 28 Sep 2012 18:34:42 -0700 Subject: [PATCH 368/426] Changes to logrotate per arthur's comment --- src/RPCServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 4028d8496c..91bb578b4b 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -2540,7 +2540,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "data_fetch", &RPCServer::doDataFetch, 1, 1, true }, { "data_store", &RPCServer::doDataStore, 2, 2, true }, { "ledger", &RPCServer::doLedger, 0, 2, false, optNetwork }, - { "logrotate", &RPCServer::doLogRotate, 0, 0, false, optCurrent }, + { "logrotate", &RPCServer::doLogRotate, 0, 0, true, 0 }, { "nickname_info", &RPCServer::doNicknameInfo, 1, 1, false, optCurrent }, { "nickname_set", &RPCServer::doNicknameSet, 2, 3, false, optCurrent }, { "offer_create", &RPCServer::doOfferCreate, 9, 10, false, optCurrent }, From 64231daadbff7002adc4f4b104636510c0164e6d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 19:11:24 -0700 Subject: [PATCH 369/426] Protocol updates. --- src/SerializeProto.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/SerializeProto.h b/src/SerializeProto.h index 2c9115fd85..fe8778c04a 100644 --- a/src/SerializeProto.h +++ b/src/SerializeProto.h @@ -56,12 +56,11 @@ FIELD(OfferSequence, UINT32, 25) // 64-bit integers - FIELD(Fee, UINT64, 1) - FIELD(IndexNext, UINT64, 2) - FIELD(IndexPrevious, UINT64, 3) - FIELD(BookNode, UINT64, 4) - FIELD(OwnerNode, UINT64, 5) - FIELD(BaseFee, UINT64, 6) + FIELD(IndexNext, UINT64, 1) + FIELD(IndexPrevious, UINT64, 2) + FIELD(BookNode, UINT64, 3) + FIELD(OwnerNode, UINT64, 4) + FIELD(BaseFee, UINT64, 5) // 128-bit FIELD(EmailHash, HASH128, 1) @@ -89,6 +88,7 @@ FIELD(TakerGets, AMOUNT, 5) FIELD(LowLimit, AMOUNT, 6) FIELD(HighLimit, AMOUNT, 7) + FIELD(Fee, AMOUNT, 8) FIELD(SendMax, AMOUNT, 9) // current amount (uncommon) @@ -125,8 +125,8 @@ // inner object // OBJECT/1 is reserved for end of object - FIELD(InnerTransaction, OBJECT, 1) // array of objects // ARRAY/1 is reserved for end of array FIELD(SigningAccounts, ARRAY, 2) + FIELD(Signatures, ARRAY, 3) From 3f0c87588eef3c767a3ef2c66742a7cd09a35af1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 19:12:07 -0700 Subject: [PATCH 370/426] Small changes to support new transaction serialization code. --- src/Transaction.cpp | 9 ++------- src/TransactionEngine.cpp | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 526f433bf1..863e8e834c 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -18,7 +18,7 @@ Transaction::Transaction(const SerializedTransaction::pointer& sit, bool bValida { try { - mFromPubKey.setAccountPublic(mTransaction->peekSigningPubKey()); + mFromPubKey.setAccountPublic(mTransaction->getSigningPubKey()); mTransactionID = mTransaction->getTransactionID(); mAccountFrom = mTransaction->getSourceAccount(); } @@ -92,12 +92,7 @@ bool Transaction::sign(const NewcoinAddress& naAccountPrivate) Log(lsWARNING) << "No private key for signing"; bResult = false; } - else if (!getSTransaction()->sign(naAccountPrivate)) - { - Log(lsWARNING) << "Failed to make signature"; - assert(false); - bResult = false; - } + getSTransaction()->sign(naAccountPrivate); if (bResult) { diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 3dc45c7c15..55f252dda6 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -105,7 +105,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa NewcoinAddress naSigningPubKey; if (tesSUCCESS == terResult) - naSigningPubKey = NewcoinAddress::createAccountPublic(txn.peekSigningPubKey()); + naSigningPubKey = NewcoinAddress::createAccountPublic(txn.setSigningPubKey()); // Consistency: really signed. if ((tesSUCCESS == terResult) && !isSetBit(params, tapNO_CHECK_SIGN) && !txn.checkSign(naSigningPubKey)) From dc2e47b67c175687401fa0e7242ed80199888b74 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 19:12:38 -0700 Subject: [PATCH 371/426] Hash functions. --- src/SerializedObject.cpp | 10 +++++----- src/SerializedObject.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index cc6f6f9136..20f0835e24 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -131,7 +131,7 @@ void STObject::set(SOElement::ptr elem) void STObject::setType(SOElement::ptrList t) { - mData.empty(); + mType.empty(); while (t->flags != SOE_END) mType.push_back(t++); } @@ -239,9 +239,9 @@ void STObject::add(Serializer& s, bool withSigningFields) const field->addFieldID(s); field->add(s); - if (dynamic_cast(field) != NULL) + if (dynamic_cast(field) != NULL) s.addFieldID(STI_ARRAY, 1); - else if (dynamic_cast(field) != NULL) + else if (dynamic_cast(field) != NULL) s.addFieldID(STI_OBJECT, 1); } } @@ -279,7 +279,7 @@ bool STObject::isEquivalent(const SerializedType& t) const return (it1 == end1) && (it2 == end2); } -uint256 getHash(uint32 prefix) cosnt +uint256 STObject::getHash(uint32 prefix) const { Serializer s; s.add32(prefix); @@ -287,7 +287,7 @@ uint256 getHash(uint32 prefix) cosnt return s.getSHA512Half(); } -uint256 getSigningHash(uint32 prefix) cosnt +uint256 STObject::getSigningHash(uint32 prefix) const { Serializer s; s.add32(prefix); diff --git a/src/SerializedObject.h b/src/SerializedObject.h index adb054586b..c69f18d3a9 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -55,7 +55,7 @@ public: virtual bool isEquivalent(const SerializedType& t) const; virtual void add(Serializer& s) const { add(s, true); } // just inner elements - void add(Serializer& s, int withSignature) const; + void add(Serializer& s, bool withSignature) const; Serializer getSerializer() const { Serializer s; add(s); return s; } std::string getFullText() const; std::string getText() const; From 01c164c6fbdb796ff241c8fcdd19305006756b5b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 19:12:56 -0700 Subject: [PATCH 372/426] Rewrite a lot of the SerializedTransaction code. Mostly just removing obsolete code. --- src/SerializedTransaction.cpp | 241 +++++++--------------------------- src/SerializedTransaction.h | 105 +++++++-------- src/TransactionFormats.h | 6 - 3 files changed, 91 insertions(+), 261 deletions(-) diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index b8a5f96c9a..5d1bdc6fe2 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -7,21 +7,16 @@ #include "Log.h" #include "HashPrefixes.h" -SerializedTransaction::SerializedTransaction(TransactionType type) : mType(type) +SerializedTransaction::SerializedTransaction(TransactionType type) : STObject(sfTransaction), mType(type) { mFormat = getTxnFormat(type); - if (mFormat == NULL) throw std::runtime_error("invalid transaction type"); - - mMiddleTxn.giveObject(new STVariableLength(sfSigningPubKey)); - mMiddleTxn.giveObject(new STAccount(sfAccount)); - mMiddleTxn.giveObject(new STUInt32(sfSequence)); - mMiddleTxn.giveObject(new STUInt16(sfTransactionType, static_cast(type))); - mMiddleTxn.giveObject(new STAmount(sfFee)); - - mInnerTxn = STObject(mFormat->elements, sfInnerTransaction); + if (mFormat == NULL) + throw std::runtime_error("invalid transaction type"); + set(mFormat->elements); + setValueFieldU16(sfTransactionType, mFormat->t_type); } -SerializedTransaction::SerializedTransaction(SerializerIterator& sit) +SerializedTransaction::SerializedTransaction(SerializerIterator& sit) : STObject(sfTransaction) { int length = sit.getBytesLeft(); if ((length < TransactionMinLen) || (length > TransactionMaxLen)) @@ -30,27 +25,18 @@ SerializedTransaction::SerializedTransaction(SerializerIterator& sit) throw std::runtime_error("Transaction length invalid"); } - mSignature.setValue(sit.getVL()); + set(sit); + mType = static_cast(getValueFieldU16(sfTransactionType)); - mMiddleTxn.giveObject(new STVariableLength(sfSigningPubKey, sit.getVL())); - - STAccount sa(sfAccount, sit.getVL()); - mSourceAccount = sa.getValueNCA(); - mMiddleTxn.giveObject(new STAccount(sa)); - - mMiddleTxn.giveObject(new STUInt32(sfSequence, sit.get32())); - - mType = static_cast(sit.get16()); - mMiddleTxn.giveObject(new STUInt16(sfTransactionType, static_cast(mType))); mFormat = getTxnFormat(mType); if (!mFormat) + throw std::runtime_error("invalid transction type"); + setType(mFormat->elements); + if (!isValidForType()) { - Log(lsERROR) << "Transaction has invalid type"; - throw std::runtime_error("Transaction has invalid type"); + Log(lsDEBUG) << "Transaction not valid for type " << getJson(0); + throw std::runtime_error("transaction not valid"); } - mMiddleTxn.giveObject(STAmount::deserialize(sit, sfFee)); - - mInnerTxn = STObject(mFormat->elements, sit, sfInnerTransaction); } std::string SerializedTransaction::getFullText() const @@ -58,29 +44,21 @@ std::string SerializedTransaction::getFullText() const std::string ret = "\""; ret += getTransactionID().GetHex(); ret += "\" = {"; - ret += mSignature.getFullText(); - ret += mMiddleTxn.getFullText(); - ret += mInnerTxn.getFullText(); + ret += STObject::getFullText(); ret += "}"; return ret; } std::string SerializedTransaction::getText() const { - std::string ret = "{"; - ret += mSignature.getText(); - ret += mMiddleTxn.getText(); - ret += mInnerTxn.getText(); - ret += "}"; - return ret; + return STObject::getText(); } std::vector SerializedTransaction::getAffectedAccounts() const { std::vector accounts; - accounts.push_back(mSourceAccount); - BOOST_FOREACH(const SerializedType& it, mInnerTxn.peekData()) + BOOST_FOREACH(const SerializedType& it, peekData()) { const STAccount* sa = dynamic_cast(&it); if (sa != NULL) @@ -103,197 +81,70 @@ std::vector SerializedTransaction::getAffectedAccounts() const return accounts; } -void SerializedTransaction::add(Serializer& s) const -{ - mSignature.add(s); - mMiddleTxn.add(s); - mInnerTxn.add(s); -} - -bool SerializedTransaction::isEquivalent(const SerializedType& t) const -{ // Signatures are not compared - const SerializedTransaction* v = dynamic_cast(&t); - if (!v) return false; - if (mType != v->mType) return false; - if (mMiddleTxn != v->mMiddleTxn) return false; - if (mInnerTxn != v->mInnerTxn) return false; - return true; -} - uint256 SerializedTransaction::getSigningHash() const { - Serializer s; - s.add32(sHP_TransactionSign); - mMiddleTxn.add(s); - mInnerTxn.add(s); - return s.getSHA512Half(); + return STObject::getSigningHash(sHP_TransactionSign); } uint256 SerializedTransaction::getTransactionID() const { // perhaps we should cache this - Serializer s; - s.add32(sHP_TransactionID); - mSignature.add(s); - mMiddleTxn.add(s); - mInnerTxn.add(s); - return s.getSHA512Half(); + return getHash(sHP_TransactionID); } std::vector SerializedTransaction::getSignature() const { - return mSignature.getValue(); + try + { + return getValueFieldVL(sfSignature); + } + catch (...) + { + return std::vector(); + } } -const std::vector& SerializedTransaction::peekSignature() const +void SerializedTransaction::sign(const NewcoinAddress& naAccountPrivate) { - return mSignature.peekValue(); -} - -bool SerializedTransaction::sign(const NewcoinAddress& naAccountPrivate) -{ - return naAccountPrivate.accountPrivateSign(getSigningHash(), mSignature.peekValue()); + std::vector signature; + naAccountPrivate.accountPrivateSign(getSigningHash(), signature); + setValueFieldVL(sfSignature, signature); } bool SerializedTransaction::checkSign(const NewcoinAddress& naAccountPublic) const { - return naAccountPublic.accountPublicVerify(getSigningHash(), mSignature.getValue()); + try + { + return naAccountPublic.accountPublicVerify(getSigningHash(), getValueFieldVL(sfSignature)); + } + catch (...) + { + return false; + } } -void SerializedTransaction::setSignature(const std::vector& sig) +void SerializedTransaction::setSigningPubKey(const NewcoinAddress& naSignPubKey) { - mSignature.setValue(sig); + setValueFieldVL(sfSigningPubKey, naSignPubKey.getAccountPublic()); } -STAmount SerializedTransaction::getTransactionFee() const +void SerializedTransaction::setSourceAccount(const NewcoinAddress& naSource) { - const STAmount* v = dynamic_cast(mMiddleTxn.peekAtPIndex(TransactionIFee)); - if (!v) throw std::runtime_error("corrupt transaction"); - return *v; -} - -void SerializedTransaction::setTransactionFee(const STAmount& fee) -{ - STAmount* v = dynamic_cast(mMiddleTxn.getPIndex(TransactionIFee)); - if (!v) throw std::runtime_error("corrupt transaction"); - v->setValue(fee); -} - -uint32 SerializedTransaction::getSequence() const -{ - const STUInt32* v = dynamic_cast(mMiddleTxn.peekAtPIndex(TransactionISequence)); - if (!v) throw std::runtime_error("corrupt transaction"); - return v->getValue(); -} - -void SerializedTransaction::setSequence(uint32 seq) -{ - STUInt32* v = dynamic_cast(mMiddleTxn.getPIndex(TransactionISequence)); - if (!v) throw std::runtime_error("corrupt transaction"); - v->setValue(seq); -} - -std::vector SerializedTransaction::getSigningPubKey() const -{ - const STVariableLength* v = - dynamic_cast(mMiddleTxn.peekAtPIndex(TransactionISigningPubKey)); - if (!v) throw std::runtime_error("corrupt transaction"); - return v->getValue(); -} - -const std::vector& SerializedTransaction::peekSigningPubKey() const -{ - const STVariableLength* v= - dynamic_cast(mMiddleTxn.peekAtPIndex(TransactionISigningPubKey)); - if (!v) throw std::runtime_error("corrupt transaction"); - return v->peekValue(); -} - -std::vector& SerializedTransaction::peekSigningPubKey() -{ - STVariableLength* v = dynamic_cast(mMiddleTxn.getPIndex(TransactionISigningPubKey)); - if (!v) throw std::runtime_error("corrupt transaction"); - return v->peekValue(); -} - -const NewcoinAddress& SerializedTransaction::setSigningPubKey(const NewcoinAddress& naSignPubKey) -{ - mSignPubKey = naSignPubKey; - - STVariableLength* v = dynamic_cast(mMiddleTxn.getPIndex(TransactionISigningPubKey)); - if (!v) throw std::runtime_error("corrupt transaction"); - v->setValue(mSignPubKey.getAccountPublic()); - - return mSignPubKey; -} - -const NewcoinAddress& SerializedTransaction::setSourceAccount(const NewcoinAddress& naSource) -{ - mSourceAccount = naSource; - - STAccount* v = dynamic_cast(mMiddleTxn.getPIndex(TransactionISourceID)); - if (!v) throw std::runtime_error("corrupt transaction"); - v->setValueNCA(mSourceAccount); - return mSourceAccount; + setValueFieldAccount(sfAccount, naSource); } uint160 SerializedTransaction::getITFieldAccount(SField::ref field) const { uint160 r; - const SerializedType* st = mInnerTxn.peekAtPField(field); - if (!st) return r; - - const STAccount* ac = dynamic_cast(st); - if (!ac) return r; - ac->getValueH160(r); + const STAccount* ac = dynamic_cast(peekAtPField(field)); + if (ac) + ac->getValueH160(r); return r; } -int SerializedTransaction::getITFieldIndex(SField::ref field) const -{ - return mInnerTxn.getFieldIndex(field); -} - -int SerializedTransaction::getITFieldCount() const -{ - return mInnerTxn.getCount(); -} - -bool SerializedTransaction::getITFieldPresent(SField::ref field) const -{ - return mInnerTxn.isFieldPresent(field); -} - -const SerializedType& SerializedTransaction::peekITField(SField::ref field) const -{ - return mInnerTxn.peekAtField(field); -} - -SerializedType& SerializedTransaction::getITField(SField::ref field) -{ - return mInnerTxn.getField(field); -} - -void SerializedTransaction::makeITFieldPresent(SField::ref field) -{ - mInnerTxn.makeFieldPresent(field); -} - -void SerializedTransaction::makeITFieldAbsent(SField::ref field) -{ - return mInnerTxn.makeFieldAbsent(field); -} - Json::Value SerializedTransaction::getJson(int options) const { - Json::Value ret = Json::objectValue; + Json::Value ret = STObject::getJson(0); ret["id"] = getTransactionID().GetHex(); - ret["signature"] = mSignature.getText(); - - Json::Value middle = mMiddleTxn.getJson(options); - middle["type"] = mFormat->t_name; - ret["middle"] = middle; - - ret["inner"] = mInnerTxn.getJson(options); return ret; } diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index ce997b5b8c..953cf20947 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -17,17 +17,13 @@ #define TXN_SQL_INCLUDED 'I' #define TXN_SQL_UNKNOWN 'U' -class SerializedTransaction : public SerializedType +class SerializedTransaction : public STObject { public: typedef boost::shared_ptr pointer; protected: - NewcoinAddress mSignPubKey; - NewcoinAddress mSourceAccount; TransactionType mType; - STVariableLength mSignature; - STObject mMiddleTxn, mInnerTxn; const TransactionFormat* mFormat; SerializedTransaction* duplicate() const { return new SerializedTransaction(*this); } @@ -40,80 +36,69 @@ public: SerializedTypeID getSType() const { return STI_TRANSACTION; } std::string getFullText() const; std::string getText() const; - void add(Serializer& s) const; - virtual bool isEquivalent(const SerializedType& t) const; // outer transaction functions / signature functions std::vector getSignature() const; - const std::vector& peekSignature() const; - void setSignature(const std::vector& s); + void setSignature(const std::vector& s) { setValueFieldVL(sfSignature, s); } uint256 getSigningHash() const; - TransactionType getTxnType() const { return mType; } - STAmount getTransactionFee() const; - void setTransactionFee(const STAmount& fee); + TransactionType getTxnType() const { return mType; } + STAmount getTransactionFee() const { return getValueFieldAmount(sfFee); } + void setTransactionFee(const STAmount& fee) { setValueFieldAmount(sfFee, fee); } - const NewcoinAddress& getSourceAccount() const { return mSourceAccount; } + NewcoinAddress getSourceAccount() const { return getValueFieldAccount(sfAccount); } std::vector getSigningPubKey() const; - const std::vector& peekSigningPubKey() const; - std::vector& peekSigningPubKey(); - const NewcoinAddress& setSigningPubKey(const NewcoinAddress& naSignPubKey); - const NewcoinAddress& setSourceAccount(const NewcoinAddress& naSource); + void setSigningPubKey(const NewcoinAddress& naSignPubKey); + void setSourceAccount(const NewcoinAddress& naSource); std::string getTransactionType() const { return mFormat->t_name; } - // inner transaction functions - uint32 getFlags() const { return mInnerTxn.getFlags(); } - void setFlag(uint32 v) { mInnerTxn.setFlag(v); } - void clearFlag(uint32 v) { mInnerTxn.clearFlag(v); } + uint32 getSequence() const { return getValueFieldU32(sfSequence); } + void setSequence(uint32 seq) { return setValueFieldU32(sfSequence, seq); } - uint32 getSequence() const; - void setSequence(uint32); + // inner transaction field functions (OBSOLETE - use STObject functions) + int getITFieldIndex(SField::ref field) const { return getFieldIndex(field); } + const SerializedType& peekITField(SField::ref field) const { return peekAtField(field); } + SerializedType& getITField(SField::ref field) { return getField(field); } - // inner transaction field functions - int getITFieldIndex(SField::ref field) const; - int getITFieldCount() const; - const SerializedType& peekITField(SField::ref field) const; - SerializedType& getITField(SField::ref field); - - // inner transaction field value functions - std::string getITFieldString(SField::ref field) const { return mInnerTxn.getFieldString(field); } - unsigned char getITFieldU8(SField::ref field) const { return mInnerTxn.getValueFieldU8(field); } - uint16 getITFieldU16(SField::ref field) const { return mInnerTxn.getValueFieldU16(field); } - uint32 getITFieldU32(SField::ref field) const { return mInnerTxn.getValueFieldU32(field); } - uint64 getITFieldU64(SField::ref field) const { return mInnerTxn.getValueFieldU64(field); } - uint128 getITFieldH128(SField::ref field) const { return mInnerTxn.getValueFieldH128(field); } - uint160 getITFieldH160(SField::ref field) const { return mInnerTxn.getValueFieldH160(field); } + // inner transaction field value functions (OBSOLETE - use STObject functions) + std::string getITFieldString(SField::ref field) const { return getFieldString(field); } + unsigned char getITFieldU8(SField::ref field) const { return getValueFieldU8(field); } + uint16 getITFieldU16(SField::ref field) const { return getValueFieldU16(field); } + uint32 getITFieldU32(SField::ref field) const { return getValueFieldU32(field); } + uint64 getITFieldU64(SField::ref field) const { return getValueFieldU64(field); } + uint128 getITFieldH128(SField::ref field) const { return getValueFieldH128(field); } + uint160 getITFieldH160(SField::ref field) const { return getValueFieldH160(field); } uint160 getITFieldAccount(SField::ref field) const; - uint256 getITFieldH256(SField::ref field) const { return mInnerTxn.getValueFieldH256(field); } - std::vector getITFieldVL(SField::ref field) const { return mInnerTxn.getValueFieldVL(field); } - std::vector getITFieldTL(SField::ref field) const { return mInnerTxn.getValueFieldTL(field); } - STAmount getITFieldAmount(SField::ref field) const { return mInnerTxn.getValueFieldAmount(field); } - STPathSet getITFieldPathSet(SField::ref field) const { return mInnerTxn.getValueFieldPathSet(field); } + uint256 getITFieldH256(SField::ref field) const { return getValueFieldH256(field); } + std::vector getITFieldVL(SField::ref field) const { return getValueFieldVL(field); } + std::vector getITFieldTL(SField::ref field) const { return getValueFieldTL(field); } + STAmount getITFieldAmount(SField::ref field) const { return getValueFieldAmount(field); } + STPathSet getITFieldPathSet(SField::ref field) const { return getValueFieldPathSet(field); } - void setITFieldU8(SField::ref field, unsigned char v) { return mInnerTxn.setValueFieldU8(field, v); } - void setITFieldU16(SField::ref field, uint16 v) { return mInnerTxn.setValueFieldU16(field, v); } - void setITFieldU32(SField::ref field, uint32 v) { return mInnerTxn.setValueFieldU32(field, v); } - void setITFieldU64(SField::ref field, uint32 v) { return mInnerTxn.setValueFieldU64(field, v); } - void setITFieldH128(SField::ref field, const uint128& v) { return mInnerTxn.setValueFieldH128(field, v); } - void setITFieldH160(SField::ref field, const uint160& v) { return mInnerTxn.setValueFieldH160(field, v); } - void setITFieldH256(SField::ref field, const uint256& v) { return mInnerTxn.setValueFieldH256(field, v); } + void setITFieldU8(SField::ref field, unsigned char v) { return setValueFieldU8(field, v); } + void setITFieldU16(SField::ref field, uint16 v) { return setValueFieldU16(field, v); } + void setITFieldU32(SField::ref field, uint32 v) { return setValueFieldU32(field, v); } + void setITFieldU64(SField::ref field, uint32 v) { return setValueFieldU64(field, v); } + void setITFieldH128(SField::ref field, const uint128& v) { return setValueFieldH128(field, v); } + void setITFieldH160(SField::ref field, const uint160& v) { return setValueFieldH160(field, v); } + void setITFieldH256(SField::ref field, const uint256& v) { return setValueFieldH256(field, v); } void setITFieldVL(SField::ref field, const std::vector& v) - { return mInnerTxn.setValueFieldVL(field, v); } + { return setValueFieldVL(field, v); } void setITFieldTL(SField::ref field, const std::vector& v) - { return mInnerTxn.setValueFieldTL(field, v); } + { return setValueFieldTL(field, v); } void setITFieldAccount(SField::ref field, const uint160& v) - { return mInnerTxn.setValueFieldAccount(field, v); } + { return setValueFieldAccount(field, v); } void setITFieldAccount(SField::ref field, const NewcoinAddress& v) - { return mInnerTxn.setValueFieldAccount(field, v); } + { return setValueFieldAccount(field, v); } void setITFieldAmount(SField::ref field, const STAmount& v) - { return mInnerTxn.setValueFieldAmount(field, v); } + { return setValueFieldAmount(field, v); } void setITFieldPathSet(SField::ref field, const STPathSet& v) - { return mInnerTxn.setValueFieldPathSet(field, v); } + { return setValueFieldPathSet(field, v); } - // optional field functions - bool getITFieldPresent(SField::ref field) const; - void makeITFieldPresent(SField::ref field); - void makeITFieldAbsent(SField::ref field); + // optional field functions (OBSOLETE - use STObject functions) + bool getITFieldPresent(SField::ref field) const { return isFieldPresent(field); } + void makeITFieldPresent(SField::ref field) { makeFieldPresent(field); } + void makeITFieldAbsent(SField::ref field) { makeFieldAbsent(field); } std::vector getAffectedAccounts() const; @@ -121,7 +106,7 @@ public: virtual Json::Value getJson(int options) const; - bool sign(const NewcoinAddress& naAccountPrivate); + void sign(const NewcoinAddress& naAccountPrivate); bool checkSign(const NewcoinAddress& naAccountPublic) const; // SQL Functions diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index 0efaf03397..edbccf3a69 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -28,12 +28,6 @@ struct TransactionFormat SOElement elements[24]; }; -const int TransactionISigningPubKey = 0; -const int TransactionISourceID = 1; -const int TransactionISequence = 2; -const int TransactionIType = 3; -const int TransactionIFee = 4; - const int TransactionMinLen = 32; const int TransactionMaxLen = 1048576; From 2b0c95a83811661ce6b8742986b4c748863b8c78 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 19:13:34 -0700 Subject: [PATCH 373/426] Typo. --- src/TransactionEngine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 55f252dda6..8847ca87e1 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -105,7 +105,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa NewcoinAddress naSigningPubKey; if (tesSUCCESS == terResult) - naSigningPubKey = NewcoinAddress::createAccountPublic(txn.setSigningPubKey()); + naSigningPubKey = NewcoinAddress::createAccountPublic(txn.getSigningPubKey()); // Consistency: really signed. if ((tesSUCCESS == terResult) && !isSetBit(params, tapNO_CHECK_SIGN) && !txn.checkSign(naSigningPubKey)) From ebf3aeee64e23ce61c7e16563b4c25a401266504 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 19:14:21 -0700 Subject: [PATCH 374/426] Remove infinite loop. --- src/SerializedLedger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 824f77145b..db21fe47dd 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -46,7 +46,7 @@ std::string SerializedLedgerEntry::getFullText() const ret += "\" = { "; ret += mFormat->t_name; ret += ", "; - ret += getFullText(); + ret += STObject::getFullText(); ret += "}"; return ret; } From 16ea43d60cd6323d4ce93de7f76b3a910593095b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 19:26:36 -0700 Subject: [PATCH 375/426] Fixups. --- src/SerializedLedger.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 38781b503b..b2cd4f95ce 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -133,14 +133,14 @@ std::vector SerializedLedgerEntry::getOwners() for (int i = 0, fields = getCount(); i < fields; ++i) { - int fc = getFieldSType(i).fieldCode; - if ((fc == sfAccount.fieldCode) || (fc == sfOwner.fieldCode)) + SField::ref fc = getFieldSType(i); + if ((fc == sfAccount) || (fc == sfOwner)) { const STAccount* entry = dynamic_cast(peekAtPIndex(i)); if ((entry != NULL) && entry->getValueH160(account)) owners.push_back(Ledger::getAccountRootIndex(account)); } - if ((fc == sfLowLimit.fieldCode) || (fs == sfHighLimit.fieldCode)) + if ((fc == sfLowLimit) || (fc == sfHighLimit)) { const STAmount* entry = dynamic_cast(peekAtPIndex(i)); if ((entry != NULL)) @@ -148,6 +148,7 @@ std::vector SerializedLedgerEntry::getOwners() uint160 issuer = entry->getIssuer(); if (issuer.isNonZero()) owners.push_back(Ledger::getAccountRootIndex(issuer)); + } } } From 431ba3033520bf9405c65df1dd15ba76d0aebc67 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 19:34:21 -0700 Subject: [PATCH 376/426] Missing function. --- src/SerializedTransaction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index 953cf20947..8153a76487 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -47,7 +47,7 @@ public: void setTransactionFee(const STAmount& fee) { setValueFieldAmount(sfFee, fee); } NewcoinAddress getSourceAccount() const { return getValueFieldAccount(sfAccount); } - std::vector getSigningPubKey() const; + std::vector getSigningPubKey() const { return getValueFieldVL(sfSigningPubKey); } void setSigningPubKey(const NewcoinAddress& naSignPubKey); void setSourceAccount(const NewcoinAddress& naSource); std::string getTransactionType() const { return mFormat->t_name; } From cc8d470e2134817f3dacb88a26e84977bdd07919 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 22:39:43 -0700 Subject: [PATCH 377/426] Bugfix., --- src/SerializedTypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 5748f960ec..9852735e35 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -219,7 +219,7 @@ protected: STAmount(bool isNeg, uint64 value) : mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNeg) { ; } STAmount(SField::ref name, uint64 value, bool isNegative) - : SerializedType(fName), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative) + : SerializedType(name), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative) { ; } STAmount(SField::ref name, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg) : SerializedType(name), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off), From 079d376390070dafc4b78f166d2b0da1f30bec10 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 22:40:00 -0700 Subject: [PATCH 378/426] Bugfix. --- src/SerializeProto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializeProto.h b/src/SerializeProto.h index fe8778c04a..2b1050bb41 100644 --- a/src/SerializeProto.h +++ b/src/SerializeProto.h @@ -27,7 +27,7 @@ // 16-bit integers FIELD(LedgerEntryType, UINT16, 1) - FIELD(TransactionType, UINT16, 1) + FIELD(TransactionType, UINT16, 2) // 32-bit integers (common) FIELD(ObjectType, UINT32, 1) From 609edfddbd672504e9d949c5e149bc51503d7b77 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 22:40:14 -0700 Subject: [PATCH 379/426] Cleanups. --- src/Amount.cpp | 23 +++++++---------------- src/SerializedObject.cpp | 3 ++- 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index bfcad54d37..c398e49f3f 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -325,7 +325,8 @@ void STAmount::setValue(const STAmount &a) uint64 STAmount::toUInt64() const { // makes them sort easily - if (mValue == 0) return 0x4000000000000000ull; + if (mValue == 0) + return 0x4000000000000000ull; if (mIsNegative) return mValue | (static_cast(mOffset + 97) << (64 - 10)); return mValue | (static_cast(mOffset + 256 + 97) << (64 - 10)); @@ -351,8 +352,6 @@ STAmount* STAmount::construct(SerializerIterator& sit, SField::ref name) int offset = static_cast(value >> (64 - 10)); // 10 bits for the offset, sign and "not native" flag value &= ~(1023ull << (64-10)); - STAmount* sapResult; - if (value) { bool isNegative = (offset & 256) == 0; @@ -360,17 +359,12 @@ STAmount* STAmount::construct(SerializerIterator& sit, SField::ref name) if ((value < cMinValue) || (value > cMaxValue) || (offset < cMinOffset) || (offset > cMaxOffset)) throw std::runtime_error("invalid currency value"); - sapResult = new STAmount(name, uCurrencyID, uIssuerID, value, offset, isNegative); - } - else - { - if (offset != 512) - throw std::runtime_error("invalid currency value"); - - sapResult = new STAmount(name, uCurrencyID, uIssuerID); + return new STAmount(name, uCurrencyID, uIssuerID, value, offset, isNegative); } - return sapResult; + if (offset != 512) + throw std::runtime_error("invalid currency value"); + return new STAmount(name, uCurrencyID, uIssuerID); } int64 STAmount::getSNValue() const @@ -890,11 +884,8 @@ STAmount STAmount::convertToInternalAmount(uint64 displayAmount, uint64 totalNow STAmount STAmount::deserialize(SerializerIterator& it) { - STAmount *s = construct(it, sfGeneric); + auto_ptr s = construct(it, sfGeneric); STAmount ret(*s); - - delete s; - return ret; } diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 20f0835e24..8d5fc3ec18 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -677,7 +677,8 @@ Json::Value STObject::getJson(int options) const { if (it.getName() == NULL) ret[boost::lexical_cast(index)] = it.getJson(options); - else ret[it.getName()] = it.getJson(options); + else + ret[it.getName()] = it.getJson(options); } } return ret; From b6c73c87d41e97ffd8f9daa3652394d7cd30adb7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 23:35:40 -0700 Subject: [PATCH 380/426] auto_ptr semantics are a bit odd --- src/Amount.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index c398e49f3f..28f3516cf3 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -884,7 +884,7 @@ STAmount STAmount::convertToInternalAmount(uint64 displayAmount, uint64 totalNow STAmount STAmount::deserialize(SerializerIterator& it) { - auto_ptr s = construct(it, sfGeneric); + std::auto_ptr s(dynamic_cast(construct(it, sfGeneric))); STAmount ret(*s); return ret; } From aa8401066efb53d3184d579c1c98c96322a7f758 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 28 Sep 2012 23:48:19 -0700 Subject: [PATCH 381/426] Bugfixes. --- src/SerializedObject.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 8d5fc3ec18..e77c756e1a 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -298,8 +298,12 @@ uint256 STObject::getSigningHash(uint32 prefix) const int STObject::getFieldIndex(SField::ref field) const { int i = 0; - for (std::vector::const_iterator it = mType.begin(), end = mType.end(); it != end; ++it, ++i) - if ((*it)->e_field == field) return i; + BOOST_FOREACH(const SerializedType& elem, mData) + { + if (elem.getFName() == field) + return i; + ++i; + } return -1; } @@ -321,7 +325,7 @@ SerializedType& STObject::getField(SField::ref field) SField::ref STObject::getFieldSType(int index) const { - return mType[index]->e_field; + return mData[index].getFName(); } const SerializedType* STObject::peekAtPField(SField::ref field) const @@ -383,7 +387,7 @@ SerializedType* STObject::makeFieldPresent(SField::ref field) SerializedType* f = getPIndex(index); if (f->getSType() != STI_NOTPRESENT) return f; - mData.replace(index, makeDefaultObject(mType[index]->e_field)); + mData.replace(index, makeDefaultObject(f->getFName())); return getPIndex(index); } @@ -392,13 +396,12 @@ void STObject::makeFieldAbsent(SField::ref field) int index = getFieldIndex(field); if (index == -1) throw std::runtime_error("Field not found"); - if (mType[index]->flags != SOE_OPTIONAL) - throw std::runtime_error("field is not optional"); - if (peekAtIndex(index).getSType() == STI_NOTPRESENT) + const SerializedType& f = peekAtIndex(index); + if (f.getSType() == STI_NOTPRESENT) return; - mData.replace(index, makeDefaultObject(mType[index]->e_field)); + mData.replace(index, makeDefaultObject(f.getFName())); } std::string STObject::getFieldString(SField::ref field) const From 29a5b60154188c5abfc2218230f3ce0e18cab6c7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 29 Sep 2012 00:05:54 -0700 Subject: [PATCH 382/426] Fix txn signature breakage. --- src/SerializedObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index e77c756e1a..4178ef0087 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -226,7 +226,7 @@ void STObject::add(Serializer& s, bool withSigningFields) const if (it.getSType() != STI_NOTPRESENT) { SField::ref fName = it.getFName(); - if (withSigningFields || (fName == sfSignature) || (fName == sfSignatures)) + if (withSigningFields || ((fName != sfSignature) && (fName != sfSignatures))) fields.insert(std::make_pair(it.getFName().fieldCode, &it)); } } From 135b4054e0b34f0c072d51130985bd9ae51511bf Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 29 Sep 2012 00:06:08 -0700 Subject: [PATCH 383/426] Cleanup, remove dead code. --- src/NetworkOPs.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 9988a03925..7985e2dbe6 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -83,17 +83,18 @@ uint32 NetworkOPs::getCurrentLedgerID() Transaction::pointer NetworkOPs::submitTransaction(const Transaction::pointer& tpTrans) { Serializer s; - tpTrans->getSTransaction()->add(s); - std::vector vucTransaction = s.getData(); - - SerializerIterator sit(s); - Transaction::pointer tpTransNew = Transaction::sharedTransaction(s.getData(), true); - assert(tpTransNew); - assert(tpTransNew->getSTransaction()->isEquivalent(*tpTrans->getSTransaction())); + + if(!tpTransNew->getSTransaction()->isEquivalent(*tpTrans->getSTransaction())) + { + Log(lsFATAL) << "Transaction reconstruction failure"; + Log(lsFATAL) << tpTransNew->getSTransaction()->getJson(0); + Log(lsFATAL) << tpTrans->getSTransaction()->getJson(0); + assert(false); + } (void) NetworkOPs::processTransaction(tpTransNew); From 4800899c478bbc5aee2b4e4fd3baab7277f224eb Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 29 Sep 2012 00:06:17 -0700 Subject: [PATCH 384/426] Cleanup. bugfixes. --- src/TransactionFormats.cpp | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 2216180dd6..3665af7d59 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -4,13 +4,16 @@ #define TF_BASE \ { sfTransactionType, SOE_REQUIRED }, \ { sfFlags, SOE_REQUIRED }, \ + { sfSourceTag, SOE_OPTIONAL }, \ + { sfAccount, SOE_REQUIRED }, \ + { sfSequence, SOE_REQUIRED }, \ + { sfFee, SOE_REQUIRED }, \ + { sfSigningPubKey, SOE_REQUIRED }, \ { sfSignature, SOE_OPTIONAL }, TransactionFormat InnerTxnFormats[]= { { "AccountSet", ttACCOUNT_SET, { TF_BASE - { sfFlags, SOE_REQUIRED }, - { sfSourceTag, SOE_OPTIONAL }, { sfEmailHash, SOE_OPTIONAL }, { sfWalletLocator, SOE_OPTIONAL }, { sfMessageKey, SOE_OPTIONAL }, @@ -21,17 +24,12 @@ TransactionFormat InnerTxnFormats[]= { sfInvalid, SOE_END } } }, { "Claim", ttCLAIM, { TF_BASE - { sfFlags, SOE_REQUIRED }, { sfGenerator, SOE_REQUIRED }, { sfPublicKey, SOE_REQUIRED }, - { sfSignature, SOE_REQUIRED }, - { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, { "CreditSet", ttCREDIT_SET, { TF_BASE - { sfFlags, SOE_REQUIRED }, { sfDestination, SOE_REQUIRED }, - { sfSourceTag, SOE_OPTIONAL }, { sfLimitAmount, SOE_OPTIONAL }, { sfQualityIn, SOE_OPTIONAL }, { sfQualityOut, SOE_OPTIONAL }, @@ -39,73 +37,53 @@ TransactionFormat InnerTxnFormats[]= }, /* { "Invoice", ttINVOICE, { TF_BASE - { sfFlags, SOE_REQUIRED }, { sfTarget, SOE_REQUIRED }, { sfAmount, SOE_REQUIRED }, - { sfSourceTag, SOE_OPTIONAL }, { sfDestination, SOE_OPTIONAL }, { sfIdentifier, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, */ { "NicknameSet", ttNICKNAME_SET, { TF_BASE - { sfFlags, SOE_REQUIRED }, { sfNickname, SOE_REQUIRED }, { sfMinimumOffer, SOE_OPTIONAL }, - { sfSignature, SOE_OPTIONAL }, - { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, { "OfferCreate", ttOFFER_CREATE, { TF_BASE - { sfFlags, SOE_REQUIRED}, { sfTakerPays, SOE_REQUIRED }, { sfTakerGets, SOE_REQUIRED }, - { sfSourceTag, SOE_OPTIONAL }, { sfExpiration, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, { "OfferCancel", ttOFFER_CANCEL, { TF_BASE - { sfFlags, SOE_REQUIRED }, { sfOfferSequence, SOE_REQUIRED }, - { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, { "PasswordFund", ttPASSWORD_FUND, { TF_BASE - { sfFlags, SOE_REQUIRED }, { sfDestination, SOE_REQUIRED }, - { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, { "PasswordSet", ttPASSWORD_SET, { TF_BASE - { sfFlags, SOE_REQUIRED }, { sfAuthorizedKey, SOE_REQUIRED }, { sfGenerator, SOE_REQUIRED }, { sfPublicKey, SOE_REQUIRED }, - { sfSignature, SOE_REQUIRED }, - { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, { "Payment", ttPAYMENT, { TF_BASE - { sfFlags, SOE_REQUIRED }, { sfDestination, SOE_REQUIRED }, { sfAmount, SOE_REQUIRED }, { sfSendMax, SOE_OPTIONAL }, { sfPaths, SOE_OPTIONAL }, - { sfSourceTag, SOE_OPTIONAL }, { sfInvoiceID, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, { "WalletAdd", ttWALLET_ADD, { TF_BASE - { sfFlags, SOE_REQUIRED }, { sfAmount, SOE_REQUIRED }, { sfAuthorizedKey, SOE_REQUIRED }, { sfPublicKey, SOE_REQUIRED }, - { sfSignature, SOE_REQUIRED }, - { sfSourceTag, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, { "Contract", ttCONTRACT, { TF_BASE - { sfFlags, SOE_REQUIRED }, { sfExpiration, SOE_REQUIRED }, { sfBondAmount, SOE_REQUIRED }, { sfStampEscrow, SOE_REQUIRED }, @@ -117,7 +95,6 @@ TransactionFormat InnerTxnFormats[]= { sfInvalid, SOE_END } } }, { "RemoveContract", ttCONTRACT_REMOVE, { TF_BASE - { sfFlags, SOE_REQUIRED }, { sfTarget, SOE_REQUIRED }, { sfInvalid, SOE_END } } }, From 3e305871c376ebb2c8391adb535664414c689dd8 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 29 Sep 2012 00:30:21 -0700 Subject: [PATCH 385/426] Missing sort. --- src/SerializedObject.cpp | 16 ++++++++++++++++ src/SerializedObject.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 4178ef0087..9cd320e06f 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -3,6 +3,7 @@ #include #include +#include #include "../json/writer.h" @@ -129,11 +130,26 @@ void STObject::set(SOElement::ptr elem) } } +bool STObject::compare(const SerializedType& f1, const SerializedType& f2) +{ + BOOST_FOREACH(SOElement::ptr elem, mType) + { + if (elem->e_field == f1.getFName()) // element one comes first + return true; + if (elem->e_field == f2.getFName()) // element two comes first + return false; + } + assert(false); + return false; +} + void STObject::setType(SOElement::ptrList t) { mType.empty(); while (t->flags != SOE_END) mType.push_back(t++); + + std::sort(mData.begin(), mData.end(), boost::bind(&STObject::compare, this, _1, _2)); } bool STObject::isValidForType() diff --git a/src/SerializedObject.h b/src/SerializedObject.h index c69f18d3a9..ee66681ee4 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -28,6 +28,7 @@ protected: std::vector mType; STObject* duplicate() const { return new STObject(*this); } + bool compare(const SerializedType& f1, const SerializedType& f2); public: STObject() { ; } From 98655aed4dd822f58024644a3d96582b7e8f3131 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 29 Sep 2012 01:30:17 -0700 Subject: [PATCH 386/426] Correctly check validity for type during setType. --- src/SerializedLedger.cpp | 6 ++-- src/SerializedObject.cpp | 67 ++++++++++++++++++++--------------- src/SerializedObject.h | 3 +- src/SerializedTransaction.cpp | 7 ++-- 4 files changed, 46 insertions(+), 37 deletions(-) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index b2cd4f95ce..f96e96e2f9 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -14,7 +14,8 @@ SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); mType = mFormat->t_type; - setType(mFormat->elements); + if (!setType(mFormat->elements)) + throw std::runtime_error("ledger entry not valid for type"); } SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& index) @@ -28,7 +29,8 @@ SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); mType = mFormat->t_type; - setType(mFormat->elements); + if (!setType(mFormat->elements)) + throw std::runtime_error("ledger entry not valid for type"); } SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type) : STObject(sfLedgerEntry), mType(type) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 9cd320e06f..c810c0de4d 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -130,46 +130,54 @@ void STObject::set(SOElement::ptr elem) } } -bool STObject::compare(const SerializedType& f1, const SerializedType& f2) +bool STObject::setType(SOElement::ptrList t) { - BOOST_FOREACH(SOElement::ptr elem, mType) - { - if (elem->e_field == f1.getFName()) // element one comes first - return true; - if (elem->e_field == f2.getFName()) // element two comes first - return false; - } - assert(false); - return false; -} + boost::ptr_vector newData; + bool valid = true; -void STObject::setType(SOElement::ptrList t) -{ mType.empty(); while (t->flags != SOE_END) - mType.push_back(t++); + { + bool match = false; + for (boost::ptr_vector::iterator it = mData.begin(); it != mData.end(); ++it) + if (it->getFName() == t->e_field) + { + match = true; + newData.push_back(mData.release(it).release()); + break; + } - std::sort(mData.begin(), mData.end(), boost::bind(&STObject::compare, this, _1, _2)); + if (!match) + { + if (t->flags != SOE_OPTIONAL) + { + Log(lsTRACE) << "setType !valid missing"; + valid = false; + } + newData.push_back(makeNonPresentObject(t->e_field)); + } + + mType.push_back(t++); + } + if (mData.size() != 0) + { + Log(lsTRACE) << "setType !valid leftover"; + valid = false; + } + mData.swap(newData); + return valid; } bool STObject::isValidForType() { + boost::ptr_vector::iterator it = mData.begin(); BOOST_FOREACH(SOElement::ptr elem, mType) - { // are any required elemnents missing - if ((elem->flags == SOE_REQUIRED) && (getPField(elem->e_field) == NULL)) - { - Log(lsWARNING) << getName() << " missing required element " << elem->e_field.fieldName; + { + if (it == mData.end()) return false; - } - } - - BOOST_FOREACH(const SerializedType& elem, mData) - { // are any non-permitted elements present - if (!isFieldAllowed(elem.getFName())) - { - Log(lsWARNING) << getName() << " has non-permitted element " << elem.getName(); + if (elem->e_field != it->getFName()) return false; - } + ++it; } return true; @@ -282,7 +290,8 @@ std::string STObject::getText() const bool STObject::isEquivalent(const SerializedType& t) const { const STObject* v = dynamic_cast(&t); - if (!v) return false; + if (!v) + return false; boost::ptr_vector::const_iterator it1 = mData.begin(), end1 = mData.end(); boost::ptr_vector::const_iterator it2 = v->mData.begin(), end2 = v->mData.end(); while ((it1 != end1) && (it2 != end2)) diff --git a/src/SerializedObject.h b/src/SerializedObject.h index ee66681ee4..98ffc8407e 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -28,7 +28,6 @@ protected: std::vector mType; STObject* duplicate() const { return new STObject(*this); } - bool compare(const SerializedType& f1, const SerializedType& f2); public: STObject() { ; } @@ -45,7 +44,7 @@ public: static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name); - void setType(SOElement::ptrList); + bool setType(SOElement::ptrList); bool isValidForType(); bool isFieldAllowed(SField::ref); diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index 5d1bdc6fe2..1fe5109ce6 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -30,11 +30,10 @@ SerializedTransaction::SerializedTransaction(SerializerIterator& sit) : STObject mFormat = getTxnFormat(mType); if (!mFormat) - throw std::runtime_error("invalid transction type"); - setType(mFormat->elements); - if (!isValidForType()) + throw std::runtime_error("invalid transaction type"); + if (!setType(mFormat->elements)) { - Log(lsDEBUG) << "Transaction not valid for type " << getJson(0); + assert(false); throw std::runtime_error("transaction not valid"); } } From dd44fd7908f3b2eddd02dea81a9c737f6aacaabe Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 29 Sep 2012 14:40:35 -0700 Subject: [PATCH 387/426] Cosmetic --- src/WSDoor.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index 1092e8c037..208c5c71c3 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -22,6 +22,9 @@ // This is a light weight, untrusted interface for web clients. // For now we don't provide proof. Later we will. // +// Might need to support this header for browsers: Access-Control-Allow-Origin: * +// - https://developer.mozilla.org/en-US/docs/HTTP_access_control +// // // Strategy: From 68ee1a4fa71636090d5956c5a387ceef0cfc7580 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 29 Sep 2012 17:49:57 -0700 Subject: [PATCH 388/426] Fix RPC ripple_line_set & TA credit_set to correctly handle issuer. --- src/RPCServer.cpp | 2 +- src/TransactionAction.cpp | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 91bb578b4b..5e2f78454b 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1562,7 +1562,7 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) { return RPCError(rpcDST_ACT_MALFORMED); } - else if (!saLimitAmount.setFullValue(params[3u].asString(), params.size() >= 5 ? params[4u].asString() : "")) + else if (!saLimitAmount.setFullValue(params[3u].asString(), params.size() >= 5 ? params[4u].asString() : "", params[1u].asString())) { return RPCError(rpcSRC_AMT_MALFORMED); } diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index 786ed762f3..6a28a89ebc 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -275,13 +275,16 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) const uint160 uCurrencyID = saLimitAmount.getCurrency(); bool bDelIndex = false; - if (bLimitAmount && saLimitAmount.getIssuer() != mTxnAccountID) + if (bLimitAmount && saLimitAmount.getIssuer() != uDstAccountID) { - Log(lsINFO) << "doCreditSet: Malformed transaction: issuer must be signer"; + Log(lsINFO) << "doCreditSet: Malformed transaction: issuer must be destination account."; return temBAD_ISSUER; } + STAmount saLimitAllow = saLimitAmount; + saLimitAllow.setIssuer(mTxnAccountID); + SLE::pointer sleRippleState = entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(mTxnAccountID, uDstAccountID, uCurrencyID)); if (sleRippleState) { @@ -313,7 +316,7 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) if (!bDelIndex) { if (bLimitAmount) - sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit, saLimitAmount); + sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit, saLimitAllow); if (!bQualityIn) { @@ -361,7 +364,7 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString(); sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency. - sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAmount); + sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAllow); sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uDstAccountID)); if (uQualityIn) From ed94c2f4a8f47607ab84ddefde2d2a98e648ac26 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 29 Sep 2012 17:58:07 -0700 Subject: [PATCH 389/426] Really fix RPC ripple_line_set. --- src/RPCServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 5e2f78454b..ba6415daf3 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1562,7 +1562,7 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) { return RPCError(rpcDST_ACT_MALFORMED); } - else if (!saLimitAmount.setFullValue(params[3u].asString(), params.size() >= 5 ? params[4u].asString() : "", params[1u].asString())) + else if (!saLimitAmount.setFullValue(params[3u].asString(), params.size() >= 5 ? params[4u].asString() : "", params[2u].asString())) { return RPCError(rpcSRC_AMT_MALFORMED); } From 22873ff73de6d81a7e1118c7df4a94fc1e12fb22 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 29 Sep 2012 18:28:05 -0700 Subject: [PATCH 390/426] Remove destination field from credit_set transaction. --- src/RPCServer.cpp | 4 +--- src/RippleCalc.cpp | 2 +- src/Transaction.cpp | 13 +++---------- src/Transaction.h | 4 ---- src/TransactionAction.cpp | 31 +++++++++++-------------------- src/TransactionFormats.cpp | 9 ++++----- 6 files changed, 20 insertions(+), 43 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index ba6415daf3..ffa8d0d439 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1544,7 +1544,6 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; STAmount saLimitAmount; - bool bLimitAmount = true; bool bQualityIn = params.size() >= 6; bool bQualityOut = params.size() >= 7; uint32 uQualityIn = 0; @@ -1593,8 +1592,7 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) asSrc->getSeq(), theConfig.FEE_DEFAULT, 0, // YYY No source tag - naDstAccountID, - bLimitAmount, saLimitAmount, + saLimitAmount, bQualityIn, uQualityIn, bQualityOut, uQualityOut); diff --git a/src/RippleCalc.cpp b/src/RippleCalc.cpp index 7b88303bc9..3a1b1cc2f2 100644 --- a/src/RippleCalc.cpp +++ b/src/RippleCalc.cpp @@ -744,7 +744,7 @@ void RippleCalc::calcNodeRipple( { const uint160 uCurrencyID = saCur.getCurrency(); const uint160 uCurIssuerID = saCur.getIssuer(); - const uint160 uPrvIssuerID = saPrv.getIssuer(); + // const uint160 uPrvIssuerID = saPrv.getIssuer(); STAmount saCurIn = STAmount::divide(STAmount::multiply(saCur, uQualityOut, uCurrencyID, uCurIssuerID), uQualityIn, uCurrencyID, uCurIssuerID); diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 526f433bf1..c6488cb8a0 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -256,18 +256,13 @@ Transaction::pointer Transaction::sharedCreate( Transaction::pointer Transaction::setCreditSet( const NewcoinAddress& naPrivateKey, - const NewcoinAddress& naDstAccountID, - bool bLimitAmount, const STAmount& saLimitAmount, bool bQualityIn, uint32 uQualityIn, bool bQualityOut, uint32 uQualityOut) { - mTransaction->setITFieldAccount(sfDestination, naDstAccountID); - - if (bLimitAmount) - mTransaction->setITFieldAmount(sfLimitAmount, saLimitAmount); + mTransaction->setITFieldAmount(sfLimitAmount, saLimitAmount); if (bQualityIn) mTransaction->setITFieldU32(sfQualityIn, uQualityIn); @@ -286,8 +281,6 @@ Transaction::pointer Transaction::sharedCreditSet( uint32 uSeq, const STAmount& saFee, uint32 uSourceTag, - const NewcoinAddress& naDstAccountID, - bool bLimitAmount, const STAmount& saLimitAmount, bool bQualityIn, uint32 uQualityIn, @@ -296,8 +289,8 @@ Transaction::pointer Transaction::sharedCreditSet( { pointer tResult = boost::make_shared(ttCREDIT_SET, naPublicKey, naSourceAccount, uSeq, saFee, uSourceTag); - return tResult->setCreditSet(naPrivateKey, naDstAccountID, - bLimitAmount, saLimitAmount, + return tResult->setCreditSet(naPrivateKey, + saLimitAmount, bQualityIn, uQualityIn, bQualityOut, uQualityOut); } diff --git a/src/Transaction.h b/src/Transaction.h index abe612853f..d8dc7fa7cc 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -74,8 +74,6 @@ private: Transaction::pointer setCreditSet( const NewcoinAddress& naPrivateKey, - const NewcoinAddress& naDstAccountID, - bool bLimitAmount, const STAmount& saLimitAmount, bool bQualityIn, uint32 uQualityIn, @@ -185,8 +183,6 @@ public: uint32 uSeq, const STAmount& saFee, uint32 uSourceTag, - const NewcoinAddress& naDstAccountID, - bool bLimitAmount, const STAmount& saLimitAmount, bool bQualityIn, uint32 uQualityIn, diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index 6a28a89ebc..9c4cf6a1d2 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -241,8 +241,17 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) TER terResult = tesSUCCESS; Log(lsINFO) << "doCreditSet>"; + const STAmount saLimitAmount = txn.getITFieldAmount(sfLimitAmount); + const bool bQualityIn = txn.getITFieldPresent(sfQualityIn); + const uint32 uQualityIn = bQualityIn ? txn.getITFieldU32(sfQualityIn) : 0; + const bool bQualityOut = txn.getITFieldPresent(sfQualityOut); + const uint32 uQualityOut = bQualityIn ? txn.getITFieldU32(sfQualityOut) : 0; + const uint160 uCurrencyID = saLimitAmount.getCurrency(); + uint160 uDstAccountID = saLimitAmount.getIssuer(); + const bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest. + bool bDelIndex = false; + // Check if destination makes sense. - uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); if (!uDstAccountID) { @@ -265,23 +274,6 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) return terNO_DST; } - const bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest. - const bool bLimitAmount = txn.getITFieldPresent(sfLimitAmount); - const STAmount saLimitAmount = bLimitAmount ? txn.getITFieldAmount(sfLimitAmount) : STAmount(); - const bool bQualityIn = txn.getITFieldPresent(sfQualityIn); - const uint32 uQualityIn = bQualityIn ? txn.getITFieldU32(sfQualityIn) : 0; - const bool bQualityOut = txn.getITFieldPresent(sfQualityOut); - const uint32 uQualityOut = bQualityIn ? txn.getITFieldU32(sfQualityOut) : 0; - const uint160 uCurrencyID = saLimitAmount.getCurrency(); - bool bDelIndex = false; - - if (bLimitAmount && saLimitAmount.getIssuer() != uDstAccountID) - { - Log(lsINFO) << "doCreditSet: Malformed transaction: issuer must be destination account."; - - return temBAD_ISSUER; - } - STAmount saLimitAllow = saLimitAmount; saLimitAllow.setIssuer(mTxnAccountID); @@ -315,8 +307,7 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) if (!bDelIndex) { - if (bLimitAmount) - sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit, saLimitAllow); + sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit, saLimitAllow); if (!bQualityIn) { diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 3ab00f7dea..a66f36d41b 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -27,11 +27,10 @@ TransactionFormat InnerTxnFormats[]= }, { "CreditSet", ttCREDIT_SET, { { S_FIELD(Flags), STI_UINT32, SOE_FLAGS, 0 }, - { S_FIELD(Destination), STI_ACCOUNT, SOE_REQUIRED, 0 }, - { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 1 }, - { S_FIELD(LimitAmount), STI_AMOUNT, SOE_IFFLAG, 2 }, - { S_FIELD(QualityIn), STI_UINT32, SOE_IFFLAG, 4 }, - { S_FIELD(QualityOut), STI_UINT32, SOE_IFFLAG, 8 }, + { S_FIELD(LimitAmount), STI_AMOUNT, SOE_REQUIRED, 0 }, + { S_FIELD(QualityIn), STI_UINT32, SOE_IFFLAG, 1 }, + { S_FIELD(QualityOut), STI_UINT32, SOE_IFFLAG, 2 }, + { S_FIELD(SourceTag), STI_UINT32, SOE_IFFLAG, 4 }, { sfInvalid, NULL, STI_DONE, SOE_NEVER, -1 } } }, /* From 9496050bdf55d69369d3c8238f14e0a370f61ce5 Mon Sep 17 00:00:00 2001 From: MJK Date: Sat, 29 Sep 2012 18:29:02 -0700 Subject: [PATCH 391/426] Towards pathfinder() changes --- src/RPCServer.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index ba6415daf3..17c2b4b6b1 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1779,17 +1779,17 @@ Json::Value RPCServer::doSend(const Json::Value& params) // Destination exists, ordinary send. STPathSet spsPaths; - /* uint160 srcCurrencyID; - bool ret_b; - ret_b = false; - STAmount::currencyFromString(srcCurrencyID, sSrcCurrency); + bool ret_b; + ret_b = false; - Pathfinder pf(naSrcAccountID, naDstAccountID, srcCurrencyID, saDstAmount); - - ret_b = pf.findPaths(5, 1, spsPaths); - // TODO: Nope; the above can't be right - */ + if (!saSrcAmountMax.isNative() || !saDstAmount.isNative()) + { + STAmount::currencyFromString(srcCurrencyID, sSrcCurrency); + Pathfinder pf(naSrcAccountID, naDstAccountID, srcCurrencyID, saDstAmount); + ret_b = pf.findPaths(5, 1, spsPaths); + } + trans = Transaction::sharedPayment( naAccountPublic, naAccountPrivate, naSrcAccountID, From 11d092b98e11c4e197191c6338b0176fab5c9f25 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 30 Sep 2012 22:41:08 -0700 Subject: [PATCH 392/426] Oops, accidental reversion .# ntest --- src/LedgerFormats.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index c3c9bc9bc9..f8fc80d4d2 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -50,21 +50,15 @@ LedgerEntryFormat LedgerFormats[]= { sfInvalid, SOE_END } } }, { "GeneratorMap", ltGENERATOR_MAP, { LEF_BASE - { sfLedgerEntryType,SOE_REQUIRED }, - { sfFlags, SOE_REQUIRED }, { sfGenerator, SOE_REQUIRED }, { sfInvalid, SOE_END } } }, { "Nickname", ltNICKNAME, { LEF_BASE - { sfLedgerEntryType,SOE_REQUIRED }, - { sfFlags, SOE_REQUIRED }, { sfAccount, SOE_REQUIRED }, { sfMinimumOffer, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, { "Offer", ltOFFER, { LEF_BASE - { sfLedgerEntryType,SOE_REQUIRED }, - { sfFlags, SOE_REQUIRED }, { sfAccount, SOE_REQUIRED }, { sfSequence, SOE_REQUIRED }, { sfTakerPays, SOE_REQUIRED }, @@ -78,8 +72,6 @@ LedgerEntryFormat LedgerFormats[]= { sfInvalid, SOE_END } } }, { "RippleState", ltRIPPLE_STATE, { LEF_BASE - { sfLedgerEntryType,SOE_REQUIRED }, - { sfFlags, SOE_REQUIRED }, { sfBalance, SOE_REQUIRED }, { sfLowLimit, SOE_REQUIRED }, { sfHighLimit, SOE_REQUIRED }, From 5cc421bc767f5d3b086e866e1cca896be7d5c16e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 30 Sep 2012 22:42:06 -0700 Subject: [PATCH 393/426] Temporary fix to some issues caused by transaction flattening. Will work out details with Arthur. --- src/SerializeProto.h | 16 +++++++++------- src/SerializedLedger.cpp | 4 ++++ src/SerializedObject.cpp | 2 +- src/SerializedTransaction.cpp | 6 +++--- src/SerializedTransaction.h | 2 +- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/SerializeProto.h b/src/SerializeProto.h index 2b1050bb41..23a2260bb7 100644 --- a/src/SerializeProto.h +++ b/src/SerializeProto.h @@ -99,13 +99,14 @@ FIELD(PublicKey, VL, 1) FIELD(MessageKey, VL, 2) FIELD(SigningPubKey, VL, 3) - FIELD(Signature, VL, 4) + FIELD(TxnSignature, VL, 4) FIELD(Generator, VL, 5) - FIELD(Domain, VL, 6) - FIELD(FundCode, VL, 7) - FIELD(RemoveCode, VL, 8) - FIELD(ExpireCode, VL, 9) - FIELD(CreateCode, VL, 10) + FIELD(Signature, VL, 6) + FIELD(Domain, VL, 7) + FIELD(FundCode, VL, 8) + FIELD(RemoveCode, VL, 9) + FIELD(ExpireCode, VL, 10) + FIELD(CreateCode, VL, 11) // account FIELD(Account, ACCOUNT, 1) @@ -129,4 +130,5 @@ // array of objects // ARRAY/1 is reserved for end of array FIELD(SigningAccounts, ARRAY, 2) - FIELD(Signatures, ARRAY, 3) + FIELD(TxnSignatures, ARRAY, 3) + FIELD(Signatures, ARRAY, 4) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 5b153d11f3..4ba43bd1e3 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -30,7 +30,11 @@ SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& throw std::runtime_error("invalid ledger entry type"); mType = mFormat->t_type; if (!setType(mFormat->elements)) + { + Log(lsWARNING) << "Ledger entry not valid for type " << mFormat->t_name; + Log(lsWARNING) << getJson(0); throw std::runtime_error("ledger entry not valid for type"); + } } SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type) : STObject(sfLedgerEntry), mType(type) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index c810c0de4d..a2980efa21 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -250,7 +250,7 @@ void STObject::add(Serializer& s, bool withSigningFields) const if (it.getSType() != STI_NOTPRESENT) { SField::ref fName = it.getFName(); - if (withSigningFields || ((fName != sfSignature) && (fName != sfSignatures))) + if (withSigningFields || ((fName != sfTxnSignature) && (fName != sfTxnSignatures))) fields.insert(std::make_pair(it.getFName().fieldCode, &it)); } } diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index 1fe5109ce6..aca26946ca 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -94,7 +94,7 @@ std::vector SerializedTransaction::getSignature() const { try { - return getValueFieldVL(sfSignature); + return getValueFieldVL(sfTxnSignature); } catch (...) { @@ -106,14 +106,14 @@ void SerializedTransaction::sign(const NewcoinAddress& naAccountPrivate) { std::vector signature; naAccountPrivate.accountPrivateSign(getSigningHash(), signature); - setValueFieldVL(sfSignature, signature); + setValueFieldVL(sfTxnSignature, signature); } bool SerializedTransaction::checkSign(const NewcoinAddress& naAccountPublic) const { try { - return naAccountPublic.accountPublicVerify(getSigningHash(), getValueFieldVL(sfSignature)); + return naAccountPublic.accountPublicVerify(getSigningHash(), getValueFieldVL(sfTxnSignature)); } catch (...) { diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index 8153a76487..295d0eb3cb 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -39,7 +39,7 @@ public: // outer transaction functions / signature functions std::vector getSignature() const; - void setSignature(const std::vector& s) { setValueFieldVL(sfSignature, s); } + void setSignature(const std::vector& s) { setValueFieldVL(sfTxnSignature, s); } uint256 getSigningHash() const; TransactionType getTxnType() const { return mType; } From de3b89d5c167a9563e63e6a5d9db7589697933f7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 30 Sep 2012 23:38:29 -0700 Subject: [PATCH 394/426] Fix the bug Jed reported. Need isTeRetry. --- src/LedgerConsensus.cpp | 8 +++++--- src/TransactionErr.h | 2 ++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 2b2af08a78..f42acb9f0a 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -977,21 +977,23 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, const Serializ { #endif TER result = engine.applyTransaction(*txn, parms); - if (result > 0) + if (isTerRetry(result { Log(lsINFO) << " retry"; assert(!ledger->hasTransaction(txn->getTransactionID())); failedTransactions.push_back(txn); } - else if (result == 0) + else if (isTepSuccess(result)) // FIXME: Need to do partial success { Log(lsTRACE) << " success"; assert(ledger->hasTransaction(txn->getTransactionID())); } - else + else if (isTemMalformed(result) || isTefFailure(result)) { Log(lsINFO) << " hard fail"; } + else + assert(false); #ifndef TRUST_NETWORK } catch (...) diff --git a/src/TransactionErr.h b/src/TransactionErr.h index 7ce5cd6109..59f42b46be 100644 --- a/src/TransactionErr.h +++ b/src/TransactionErr.h @@ -111,6 +111,8 @@ enum TER // aka TransactionEngineResult #define isTemMalformed(x) ((x) >= temMALFORMED && (x) < tefFAILURE) #define isTefFailure(x) ((x) >= tefFAILURE && (x) < terRETRY) #define isTepPartial(x) ((x) >= tepPATH_PARTIAL) +#define isTepSucess(x) ((x) >= tesSUCCESS) +#define isTerRetry(x) ((x) >= terRETRY && (x) < tesSUCCESS) bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman); std::string transToken(TER terCode); From b973f3509c03bc7332695e2a404f929beccb4a97 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 30 Sep 2012 23:40:21 -0700 Subject: [PATCH 395/426] Typo fixes. --- src/LedgerConsensus.cpp | 2 +- src/TransactionErr.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index f42acb9f0a..2dc6672f6f 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -977,7 +977,7 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, const Serializ { #endif TER result = engine.applyTransaction(*txn, parms); - if (isTerRetry(result + if (isTerRetry(result)) { Log(lsINFO) << " retry"; assert(!ledger->hasTransaction(txn->getTransactionID())); diff --git a/src/TransactionErr.h b/src/TransactionErr.h index 59f42b46be..576f3dbf80 100644 --- a/src/TransactionErr.h +++ b/src/TransactionErr.h @@ -111,7 +111,7 @@ enum TER // aka TransactionEngineResult #define isTemMalformed(x) ((x) >= temMALFORMED && (x) < tefFAILURE) #define isTefFailure(x) ((x) >= tefFAILURE && (x) < terRETRY) #define isTepPartial(x) ((x) >= tepPATH_PARTIAL) -#define isTepSucess(x) ((x) >= tesSUCCESS) +#define isTepSuccess(x) ((x) >= tesSUCCESS) #define isTerRetry(x) ((x) >= terRETRY && (x) < tesSUCCESS) bool transResultInfo(TER terCode, std::string& strToken, std::string& strHuman); From c6aa3b26788c3b13a138204fd87534d1cb68f56e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 1 Oct 2012 00:55:16 -0700 Subject: [PATCH 396/426] Type json improvements --- src/LedgerFormats.cpp | 9 +++++++-- src/LedgerFormats.h | 1 + src/SerializedTypes.cpp | 14 ++++++++++++++ src/TransactionFormats.cpp | 16 +++++++++++----- src/TransactionFormats.h | 1 + 5 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index f8fc80d4d2..89cc24d078 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -86,13 +86,18 @@ LedgerEntryFormat LedgerFormats[]= { NULL, ltINVALID } }; - LedgerEntryFormat* getLgrFormat(LedgerEntryType t) +{ + return getLgrFormat(t); +} + +LedgerEntryFormat* getLgrFormat(int t) { LedgerEntryFormat* f = LedgerFormats; while (f->t_name != NULL) { - if (f->t_type == t) return f; + if (f->t_type == t) + return f; ++f; } return NULL; diff --git a/src/LedgerFormats.h b/src/LedgerFormats.h index 82221ca31d..7b4a95683e 100644 --- a/src/LedgerFormats.h +++ b/src/LedgerFormats.h @@ -48,5 +48,6 @@ struct LedgerEntryFormat extern LedgerEntryFormat LedgerFormats[]; extern LedgerEntryFormat* getLgrFormat(LedgerEntryType t); +extern LedgerEntryFormat* getLgrFormat(int t); #endif // vim:ts=4 diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 6eeb0c9120..570a2e80ce 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -5,6 +5,8 @@ #include "SerializedTypes.h" #include "SerializedObject.h" #include "TransactionFormats.h" +#include "LedgerFormats.h" +#include "FieldNames.h" #include "Log.h" #include "NewcoinAddress.h" #include "utils.h" @@ -50,6 +52,18 @@ STUInt16* STUInt16::construct(SerializerIterator& u, SField::ref name) std::string STUInt16::getText() const { + if (getFName() == sfLedgerEntryType) + { + LedgerEntryFormat *f = getLgrFormat(value); + if (f != NULL) + return f->t_name; + } + if (getFName() == sfTransactionType) + { + TransactionFormat *f = getTxnFormat(value); + if (f != NULL) + return f->t_name; + } return boost::lexical_cast(value); } diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index eec5b363de..9e84d32004 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -100,14 +100,20 @@ TransactionFormat InnerTxnFormats[]= { NULL, ttINVALID } }; -TransactionFormat* getTxnFormat(TransactionType t) +TransactionFormat* getTxnFormat(TransactionType t) { - TransactionFormat* f = InnerTxnFormats; - while (f->t_name != NULL) + return getTxnFormat(t); +} + +TransactionFormat* getTxnFormat(int t) +{ + TransactionFormat* f = InnerTxnFormats; + while (f->t_name != NULL) { - if (f->t_type == t) return f; + if (f->t_type == t) + return f; ++f; } - return NULL; + return NULL; } // vim:ts=4 diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index edbccf3a69..57b155285f 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -46,5 +46,6 @@ const uint32 tfNoRippleDirect = 0x00080000; extern TransactionFormat InnerTxnFormats[]; extern TransactionFormat* getTxnFormat(TransactionType t); +extern TransactionFormat* getTxnFormat(int t); #endif // vim:ts=4 From d37db0219d82d62f897dfb628b53d61fdffd0dc7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 1 Oct 2012 00:57:01 -0700 Subject: [PATCH 397/426] Fix endless recursion. --- src/LedgerFormats.cpp | 2 +- src/TransactionFormats.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 89cc24d078..84aaf73d14 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -88,7 +88,7 @@ LedgerEntryFormat LedgerFormats[]= LedgerEntryFormat* getLgrFormat(LedgerEntryType t) { - return getLgrFormat(t); + return getLgrFormat(static_cast(t)); } LedgerEntryFormat* getLgrFormat(int t) diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 9e84d32004..cebc37a49c 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -102,7 +102,7 @@ TransactionFormat InnerTxnFormats[]= TransactionFormat* getTxnFormat(TransactionType t) { - return getTxnFormat(t); + return getTxnFormat(static_cast(t)); } TransactionFormat* getTxnFormat(int t) From 98d8823be0ab59a68659b4ffcb294b262608480f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 1 Oct 2012 02:19:17 -0700 Subject: [PATCH 398/426] Get ready for Json decode. --- src/FieldNames.cpp | 2 +- src/FieldNames.h | 6 +++--- src/SerializedObject.cpp | 15 ++++++++++++++- src/SerializedObject.h | 2 ++ src/SerializedTypes.cpp | 2 +- src/SerializedTypes.h | 2 +- 6 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index d631fb7f01..e6af94ad26 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -75,7 +75,7 @@ SField::ref SField::getField(int type, int value) std::string SField::getName() const { - if (fieldName != NULL) + if (!fieldName.empty()) return fieldName; if (fieldValue == 0) return ""; diff --git a/src/FieldNames.h b/src/FieldNames.h index c738e6cefa..4d966c547c 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -48,20 +48,20 @@ public: const int fieldCode; // (type<<16)|index const SerializedTypeID fieldType; // STI_* const int fieldValue; // Code number for protocol - const char* fieldName; + std::string fieldName; SField(int fc, SerializedTypeID tid, int fv, const char* fn) : fieldCode(fc), fieldType(tid), fieldValue(fv), fieldName(fn) { codeToField[fc] = this; } - SField(int fc) : fieldCode(fc), fieldType(STI_UNKNOWN), fieldValue(0), fieldName(NULL) { ; } + SField(int fc) : fieldCode(fc), fieldType(STI_UNKNOWN), fieldValue(0) { ; } static SField::ref getField(int fieldCode); static SField::ref getField(int fieldType, int fieldValue); static SField::ref getField(SerializedTypeID type, int value) { return getField(FIELD_CODE(type, value)); } std::string getName() const; - bool hasName() const { return (fieldName != NULL) || (fieldValue != 0); } + bool hasName() const { return !fieldName.empty(); } bool isGeneric() const { return fieldCode == 0; } bool isInvalid() const { return fieldCode == -1; } diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index a2980efa21..af7ac0c47b 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -703,7 +703,7 @@ Json::Value STObject::getJson(int options) const { if (it.getSType() != STI_NOTPRESENT) { - if (it.getName() == NULL) + if (!it.getFName().hasName()) ret[boost::lexical_cast(index)] = it.getJson(options); else ret[it.getName()] = it.getJson(options); @@ -777,6 +777,19 @@ STArray* STArray::construct(SerializerIterator& sit, SField::ref field) return new STArray(field, value); } +STObject::STObject(const Json::Value& object, SField::ref name) : SerializedType(name) +{ + if (!object.isObject()) + throw std::runtime_error("Value is not an object"); + + Json::Value::Members members(object.getMemberNames()); + for (Json::Value::Members::iterator it = members.begin(), end = members.end(); it != end; ++it) + { + const std::string& name = *it; + const Json::Value& value = object[name]; + // WRITEME + } +} #if 0 diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 98ffc8407e..bfcc7c090c 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -40,6 +40,8 @@ public: STObject(SOElement::ptrList type, SerializerIterator& sit, SField::ref name) : SerializedType(name) { set(sit); setType(type); } + STObject(const Json::Value& value, SField::ref name); + virtual ~STObject() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name); diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 570a2e80ce..4cee5f5c9b 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -19,7 +19,7 @@ std::string SerializedType::getFullText() const std::string ret; if (getSType() != STI_NOTPRESENT) { - if(fName != NULL) + if(fName->hasName()) { ret = fName->fieldName; ret += " = "; diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 9852735e35..33706ae456 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -50,7 +50,7 @@ public: void setFName(SField::ref n) { fName = &n; assert(fName); } SField::ref getFName() const { return *fName; } - const char *getName() const { return fName->fieldName; } + std::string getName() const { return fName->fieldName; } virtual SerializedTypeID getSType() const { return STI_NOTPRESENT; } std::auto_ptr clone() const { return std::auto_ptr(duplicate()); } From c4275c6d806e4e3e5148c247e3ffe4215908e8ff Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 1 Oct 2012 08:32:23 -0700 Subject: [PATCH 399/426] More work on the JSON conversion code. --- src/FieldNames.cpp | 13 ++++ src/FieldNames.h | 1 + src/LedgerFormats.cpp | 4 +- src/SerializedObject.cpp | 126 ++++++++++++++++++++++++++++++++++++++- src/SerializedObject.h | 5 +- src/SerializedTypes.h | 28 ++++----- 6 files changed, 157 insertions(+), 20 deletions(-) diff --git a/src/FieldNames.cpp b/src/FieldNames.cpp index e6af94ad26..612d250c97 100644 --- a/src/FieldNames.cpp +++ b/src/FieldNames.cpp @@ -5,6 +5,7 @@ #include #include +#include // These must stay at the top of this file @@ -82,3 +83,15 @@ std::string SField::getName() const return boost::lexical_cast(static_cast(fieldType)) + "/" + boost::lexical_cast(fieldValue); } + +SField::ref SField::getField(const std::string& fieldName) +{ // OPTIMIZEME me with a map. CHECKME this is case sensitive + boost::mutex::scoped_lock sl(mapMutex); + typedef std::pair int_sfref_pair; + BOOST_FOREACH(const int_sfref_pair& fieldPair, codeToField) + { + if (fieldPair.second->fieldName == fieldName) + return *(fieldPair.second); + } + return sfInvalid; +} diff --git a/src/FieldNames.h b/src/FieldNames.h index 4d966c547c..ed51006499 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -58,6 +58,7 @@ public: static SField::ref getField(int fieldCode); static SField::ref getField(int fieldType, int fieldValue); + static SField::ref getField(const std::string& fieldName); static SField::ref getField(SerializedTypeID type, int value) { return getField(FIELD_CODE(type, value)); } std::string getName() const; diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 84aaf73d14..bc4ab86ed1 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -2,9 +2,9 @@ #include "LedgerFormats.h" #define LEF_BASE \ + { sfLedgerIndex, SOE_OPTIONAL }, \ { sfLedgerEntryType, SOE_REQUIRED }, \ - { sfFlags, SOE_REQUIRED }, \ - { sfLedgerIndex, SOE_OPTIONAL }, + { sfFlags, SOE_REQUIRED }, LedgerEntryFormat LedgerFormats[]= { diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index af7ac0c47b..0bfab6c928 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -429,6 +429,20 @@ void STObject::makeFieldAbsent(SField::ref field) mData.replace(index, makeDefaultObject(f.getFName())); } +bool STObject::delField(SField::ref field) +{ + int index = getFieldIndex(field); + if (index == -1) + return false; + delField(index); + return true; +} + +void STObject::delField(int index) +{ + mData.erase(mData.begin() + index); +} + std::string STObject::getFieldString(SField::ref field) const { const SerializedType* rf = peekAtPField(field); @@ -777,18 +791,126 @@ STArray* STArray::construct(SerializerIterator& sit, SField::ref field) return new STArray(field, value); } -STObject::STObject(const Json::Value& object, SField::ref name) : SerializedType(name) +std::auto_ptr STObject::parseJson(const Json::Value& object, SField::ref name, int depth) { if (!object.isObject()) throw std::runtime_error("Value is not an object"); + boost::ptr_vector data; Json::Value::Members members(object.getMemberNames()); for (Json::Value::Members::iterator it = members.begin(), end = members.end(); it != end; ++it) { const std::string& name = *it; const Json::Value& value = object[name]; - // WRITEME + + SField::ref field = SField::getField(name); + if (field == sfInvalid) + throw std::runtime_error("Unknown field: " + name); + + switch (field.fieldType) + { + case STI_UINT8: + if (value.isString()) + data.push_back(new STUInt8(field, boost::lexical_cast(value.asString()))); + else if (value.isInt()) + data.push_back(new STUInt8(field, boost::lexical_cast(value.asInt()))); + else if (value.isUInt()) + data.push_back(new STUInt8(field, boost::lexical_cast(value.asUInt()))); + else + throw std::runtime_error("Incorrect type"); + break; + + case STI_UINT16: + if (value.isString()) + { + std::string strValue = value.asString(); + if (!strValue.empty() && (strValue[0]<'0' || strValue[0]>'9')) + { + if (field == sfTransactionType) + { + // WRITEME + } + else if (field == sfLedgerEntryType) + { + // WRITEME + } + else + throw std::runtime_error("Invalid field data"); + } + data.push_back(new STUInt16(field, boost::lexical_cast(strValue))); + } + else if (value.isInt()) + data.push_back(new STUInt16(field, boost::lexical_cast(value.asInt()))); + else if (value.isUInt()) + data.push_back(new STUInt16(field, boost::lexical_cast(value.asUInt()))); + else + throw std::runtime_error("Incorrect type"); + break; + + case STI_UINT32: + if (value.isString()) + data.push_back(new STUInt32(field, boost::lexical_cast(value.asString()))); + else if (value.isInt()) + data.push_back(new STUInt32(field, boost::lexical_cast(value.asInt()))); + else if (value.isUInt()) + data.push_back(new STUInt32(field, boost::lexical_cast(value.asUInt()))); + else + throw std::runtime_error("Incorrect type"); + break; + + case STI_UINT64: + if (value.isString()) + data.push_back(new STUInt64(field, boost::lexical_cast(value.asString()))); + else if (value.isInt()) + data.push_back(new STUInt64(field, boost::lexical_cast(value.asInt()))); + else if (value.isUInt()) + data.push_back(new STUInt64(field, boost::lexical_cast(value.asUInt()))); + else + throw std::runtime_error("Incorrect type"); + break; + + + case STI_HASH128: + // WRITEME + + case STI_HASH160: + // WRITEME + + case STI_HASH256: + // WRITEME + + case STI_VL: + // WRITEME + + case STI_AMOUNT: + // WRITEME + + case STI_VECTOR256: + // WRITEME + + case STI_PATHSET: + // WRITEME + + case STI_OBJECT: + case STI_ACCOUNT: + case STI_TRANSACTION: + case STI_LEDGERENTRY: + case STI_VALIDATION: + if (!value.isObject()) + throw std::runtime_error("Inner value is not an object"); + if (depth > 64) + throw std::runtime_error("Json nest depth exceeded"); + data.push_back(parseJson(value, field, depth + 1)); + break; + + case STI_ARRAY: + // WRITEME + + default: + throw std::runtime_error("Invalid field type"); + } } + return std::auto_ptr(new STObject(name, data)); } #if 0 diff --git a/src/SerializedObject.h b/src/SerializedObject.h index bfcc7c090c..58a926d983 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -28,6 +28,7 @@ protected: std::vector mType; STObject* duplicate() const { return new STObject(*this); } + STObject(SField::ref name, boost::ptr_vector& data) : SerializedType(name) { mData.swap(data); } public: STObject() { ; } @@ -40,7 +41,7 @@ public: STObject(SOElement::ptrList type, SerializerIterator& sit, SField::ref name) : SerializedType(name) { set(sit); setType(type); } - STObject(const Json::Value& value, SField::ref name); + static std::auto_ptr parseJson(const Json::Value& value, SField::ref name, int depth = 0); virtual ~STObject() { ; } @@ -127,6 +128,8 @@ public: bool isFieldPresent(SField::ref field) const; SerializedType* makeFieldPresent(SField::ref field); void makeFieldAbsent(SField::ref field); + bool delField(SField::ref field); + void delField(int index); static std::auto_ptr makeDefaultObject(SerializedTypeID id, SField::ref name); static std::auto_ptr makeDeserializedObject(SerializedTypeID id, SField::ref name, diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 33706ae456..de1fb75eb6 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -91,7 +91,7 @@ protected: public: STUInt8(unsigned char v = 0) : value(v) { ; } - STUInt8(SField::ref n, unsigned char v=0) : SerializedType(n), value(v) { ; } + STUInt8(SField::ref n, unsigned char v = 0) : SerializedType(n), value(v) { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } @@ -116,8 +116,8 @@ protected: public: - STUInt16(uint16 v=0) : value(v) { ; } - STUInt16(SField::ref n, uint16 v=0) : SerializedType(n), value(v) { ; } + STUInt16(uint16 v = 0) : value(v) { ; } + STUInt16(SField::ref n, uint16 v = 0) : SerializedType(n), value(v) { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } @@ -143,7 +143,7 @@ protected: public: STUInt32(uint32 v = 0) : value(v) { ; } - STUInt32(SField::ref n, uint32 v=0) : SerializedType(n), value(v) { ; } + STUInt32(SField::ref n, uint32 v = 0) : SerializedType(n), value(v) { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } @@ -168,8 +168,8 @@ protected: public: - STUInt64(uint64 v=0) : value(v) { ; } - STUInt64(SField::ref n, uint64 v=0) : SerializedType(n), value(v) { ; } + STUInt64(uint64 v = 0) : value(v) { ; } + STUInt64(SField::ref n, uint64 v = 0) : SerializedType(n), value(v) { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } @@ -225,6 +225,8 @@ protected: : SerializedType(name), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off), mIsNative(isNat), mIsNegative(isNeg) { ; } + STAmount(SField::ref name, const Json::Value& value); + uint64 toUInt64() const; static uint64 muldiv(uint64, uint64, uint64); @@ -232,13 +234,13 @@ public: static uint64 uRateOne; STAmount(uint64 v = 0, bool isNeg = false) : mValue(v), mOffset(0), mIsNative(true), mIsNegative(isNeg) - { if (v==0) mIsNegative = false; } + { if (v == 0) mIsNegative = false; } STAmount(SField::ref n, uint64 v = 0) : SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false) { ; } - STAmount(const uint160& uCurrencyID, const uint160& uIssuerID, uint64 uV=0, int iOff=0, bool bNegative=false) + STAmount(const uint160& uCurrencyID, const uint160& uIssuerID, uint64 uV = 0, int iOff = 0, bool bNegative = false) : mCurrency(uCurrencyID), mIssuer(uIssuerID), mValue(uV), mOffset(iOff), mIsNegative(bNegative) { canonicalize(); } @@ -254,14 +256,10 @@ public: { return std::auto_ptr(construct(sit, name)); } static STAmount saFromRate(uint64 uRate = 0) - { - return STAmount(CURRENCY_ONE, ACCOUNT_ONE, uRate, -9, false); - } + { return STAmount(CURRENCY_ONE, ACCOUNT_ONE, uRate, -9, false); } - static STAmount saFromSigned(const uint160& uCurrencyID, const uint160& uIssuerID, int64 iV=0, int iOff=0) - { - return STAmount(uCurrencyID, uIssuerID, iV < 0 ? -iV : iV, iOff, iV < 0); - } + static STAmount saFromSigned(const uint160& uCurrencyID, const uint160& uIssuerID, int64 iV = 0, int iOff = 0) + { return STAmount(uCurrencyID, uIssuerID, iV < 0 ? -iV : iV, iOff, iV < 0); } SerializedTypeID getSType() const { return STI_AMOUNT; } std::string getText() const; From cba4b820912769f4ce5df1e73abebb1b620dcd94 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 1 Oct 2012 12:16:59 -0700 Subject: [PATCH 400/426] Don't allow offer amounts to be negative. --- src/TransactionAction.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index 9c4cf6a1d2..190a66bb3f 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -758,7 +758,7 @@ TER TransactionEngine::takeOffers( else { // Have an offer directory to consider. - Log(lsINFO) << "takeOffers: considering dir : " << sleOfferDir->getJson(0); + Log(lsINFO) << "takeOffers: considering dir: " << sleOfferDir->getJson(0); SLE::pointer sleBookNode; unsigned int uBookEntry; @@ -965,7 +965,7 @@ Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGe terResult = temBAD_OFFER; } - else if (!saTakerPays || !saTakerGets) + else if (!saTakerPays.isPositive() || !saTakerGets.isPositive()) { Log(lsWARNING) << "doOfferCreate: Malformed offer: bad amount"; From eb2244de7644d5297b8e51fd09eb544370094362 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 1 Oct 2012 13:22:21 -0700 Subject: [PATCH 401/426] Get rid of compiler warning. --- src/RPCServer.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index ee3fb06204..8936231c2c 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -355,7 +355,9 @@ Json::Value RPCServer::authorize(const uint256& uLedger, } else { + Log(lsINFO) << "authorize: before: fee=" << saFee.getFullText() << " balance=" << saSrcBalance.getFullText(); saSrcBalance -= saFee; + Log(lsINFO) << "authorize: after: fee=" << saFee.getFullText() << " balance=" << saSrcBalance.getFullText(); } Json::Value obj; @@ -1778,14 +1780,15 @@ Json::Value RPCServer::doSend(const Json::Value& params) STPathSet spsPaths; uint160 srcCurrencyID; - bool ret_b; - ret_b = false; +// bool ret_b; +// ret_b = false; if (!saSrcAmountMax.isNative() || !saDstAmount.isNative()) { STAmount::currencyFromString(srcCurrencyID, sSrcCurrency); Pathfinder pf(naSrcAccountID, naDstAccountID, srcCurrencyID, saDstAmount); - ret_b = pf.findPaths(5, 1, spsPaths); +// ret_b = pf.findPaths(5, 1, spsPaths); + pf.findPaths(5, 1, spsPaths); } trans = Transaction::sharedPayment( From 61e939285e3f811acfd11642557765c730fe24c0 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 1 Oct 2012 13:22:36 -0700 Subject: [PATCH 402/426] Fix operator-() for XNS. --- src/Amount.cpp | 17 +++++------------ src/SerializedTypes.h | 11 +++-------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 28f3516cf3..0e7f63988e 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -299,18 +299,11 @@ void STAmount::add(Serializer& s) const } } -STAmount::STAmount(SField::ref name, int64 value) : SerializedType(name), mOffset(0), mIsNative(true) +STAmount STAmount::createFromInt64(SField::ref name, int64 value) { - if (value >= 0) - { - mIsNegative = false; - mValue = static_cast(value); - } - else - { - mIsNegative = true; - mValue = static_cast(-value); - } + return value >= 0 + ? STAmount(name, static_cast(value), false) + : STAmount(name, static_cast(-value), true); } void STAmount::setValue(const STAmount &a) @@ -623,7 +616,7 @@ STAmount operator-(const STAmount& v1, const STAmount& v2) v1.throwComparable(v2); if (v2.mIsNative) - return STAmount(v1.fName, v1.getSNValue() - v2.getSNValue()); + return STAmount::createFromInt64(v1.getFName(), v1.getSNValue() - v2.getSNValue()); int ov1 = v1.mOffset, ov2 = v2.mOffset; int64 vv1 = static_cast(v1.mValue), vv2 = static_cast(v2.mValue); diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index de1fb75eb6..246e4cde1f 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -216,11 +216,6 @@ protected: static const uint64 cNotNative = 0x8000000000000000ull; static const uint64 cPosNative = 0x4000000000000000ull; - STAmount(bool isNeg, uint64 value) : mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNeg) { ; } - - STAmount(SField::ref name, uint64 value, bool isNegative) - : SerializedType(name), mValue(value), mOffset(0), mIsNative(true), mIsNegative(isNegative) - { ; } STAmount(SField::ref name, const uint160& cur, const uint160& iss, uint64 val, int off, bool isNat, bool isNeg) : SerializedType(name), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off), mIsNative(isNat), mIsNegative(isNeg) { ; } @@ -236,8 +231,8 @@ public: STAmount(uint64 v = 0, bool isNeg = false) : mValue(v), mOffset(0), mIsNative(true), mIsNegative(isNeg) { if (v == 0) mIsNegative = false; } - STAmount(SField::ref n, uint64 v = 0) - : SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(false) + STAmount(SField::ref n, uint64 v = 0, bool isNeg = false) + : SerializedType(n), mValue(v), mOffset(0), mIsNative(true), mIsNegative(isNeg) { ; } STAmount(const uint160& uCurrencyID, const uint160& uIssuerID, uint64 uV = 0, int iOff = 0, bool bNegative = false) @@ -250,7 +245,7 @@ public: SerializedType(n), mCurrency(currency), mIssuer(issuer), mValue(v), mOffset(off), mIsNegative(isNeg) { canonicalize(); } - STAmount(SField::ref n, int64 v); + static STAmount createFromInt64(SField::ref n, int64 v); static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) { return std::auto_ptr(construct(sit, name)); } From 841a40411483769f481f62a427b0604149808ff0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 1 Oct 2012 14:33:13 -0700 Subject: [PATCH 403/426] Fix duplicate fields. --- src/LedgerFormats.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index bc4ab86ed1..9f0ed403ac 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -25,8 +25,6 @@ LedgerEntryFormat LedgerFormats[]= { sfInvalid, SOE_END } } }, { "Contract", ltCONTRACT, { LEF_BASE - { sfLedgerEntryType,SOE_REQUIRED }, - { sfFlags, SOE_REQUIRED }, { sfAccount, SOE_REQUIRED }, { sfBalance, SOE_REQUIRED }, { sfLastTxnID, SOE_REQUIRED }, @@ -42,8 +40,6 @@ LedgerEntryFormat LedgerFormats[]= { sfInvalid, SOE_END } } }, { "DirectoryNode", ltDIR_NODE, { LEF_BASE - { sfLedgerEntryType,SOE_REQUIRED }, - { sfFlags, SOE_REQUIRED }, { sfIndexes, SOE_REQUIRED }, { sfIndexNext, SOE_OPTIONAL }, { sfIndexPrevious, SOE_OPTIONAL }, From 0b49c0dee97a91e0fffd52404382a371d215a1b5 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 1 Oct 2012 15:05:53 -0700 Subject: [PATCH 404/426] Get rid of unneeded signature parameter for NicknameSet. --- src/Amount.cpp | 3 +++ src/RPCServer.cpp | 8 +++----- src/Transaction.cpp | 11 +++-------- src/Transaction.h | 6 ++---- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 0e7f63988e..fbe6e0a5ac 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -616,7 +616,10 @@ STAmount operator-(const STAmount& v1, const STAmount& v2) v1.throwComparable(v2); if (v2.mIsNative) + { + // XXX This could be better, check for overflow and that maximum range is covered. return STAmount::createFromInt64(v1.getFName(), v1.getSNValue() - v2.getSNValue()); + } int ov1 = v1.mOffset, ov2 = v2.mOffset; int64 vv1 = static_cast(v1.mValue), vv2 = static_cast(v2.mValue); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 8936231c2c..516345a65f 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -960,7 +960,6 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) std::string strOfferCurrency; std::string strNickname = params[2u].asString(); boost::trim(strNickname); - std::vector vucSignature; if (strNickname.empty()) { @@ -1012,8 +1011,7 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) 0, // YYY No source tag Ledger::getNicknameHash(strNickname), bSetOffer, - saMinimumOffer, - vucSignature); + saMinimumOffer); trans = mNetOps->submitTransaction(trans); @@ -1783,14 +1781,14 @@ Json::Value RPCServer::doSend(const Json::Value& params) // bool ret_b; // ret_b = false; - if (!saSrcAmountMax.isNative() || !saDstAmount.isNative()) + if (!saSrcAmountMax.isNative() || !saDstAmount.isNative()) { STAmount::currencyFromString(srcCurrencyID, sSrcCurrency); Pathfinder pf(naSrcAccountID, naDstAccountID, srcCurrencyID, saDstAmount); // ret_b = pf.findPaths(5, 1, spsPaths); pf.findPaths(5, 1, spsPaths); } - + trans = Transaction::sharedPayment( naAccountPublic, naAccountPrivate, naSrcAccountID, diff --git a/src/Transaction.cpp b/src/Transaction.cpp index ec209bdf16..d7a410ad8c 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -298,8 +298,7 @@ Transaction::pointer Transaction::setNicknameSet( const NewcoinAddress& naPrivateKey, const uint256& uNickname, bool bSetOffer, - const STAmount& saMinimumOffer, - const std::vector& vucSignature) + const STAmount& saMinimumOffer) { mTransaction->setITFieldH256(sfNickname, uNickname); @@ -307,9 +306,6 @@ Transaction::pointer Transaction::setNicknameSet( if (bSetOffer) mTransaction->setITFieldAmount(sfMinimumOffer, saMinimumOffer); - if (!vucSignature.empty()) - mTransaction->setITFieldVL(sfSignature, vucSignature); - sign(naPrivateKey); return shared_from_this(); @@ -325,12 +321,11 @@ Transaction::pointer Transaction::sharedNicknameSet( uint32 uSourceTag, const uint256& uNickname, bool bSetOffer, - const STAmount& saMinimumOffer, - const std::vector& vucSignature) + const STAmount& saMinimumOffer) { pointer tResult = boost::make_shared(ttNICKNAME_SET, naPublicKey, naSourceAccount, uSeq, saFee, uSourceTag); - return tResult->setNicknameSet(naPrivateKey, uNickname, bSetOffer, saMinimumOffer, vucSignature); + return tResult->setNicknameSet(naPrivateKey, uNickname, bSetOffer, saMinimumOffer); } // diff --git a/src/Transaction.h b/src/Transaction.h index d8dc7fa7cc..c5e17a29c7 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -84,8 +84,7 @@ private: const NewcoinAddress& naPrivateKey, const uint256& uNickname, bool bSetOffer, - const STAmount& saMinimumOffer, - const std::vector& vucSignature); + const STAmount& saMinimumOffer); Transaction::pointer setOfferCreate( const NewcoinAddress& naPrivateKey, @@ -198,8 +197,7 @@ public: uint32 uSourceTag, const uint256& uNickname, bool bSetOffer, - const STAmount& saMinimumOffer, - const std::vector& vucSignature); + const STAmount& saMinimumOffer); // Pre-fund password change. static Transaction::pointer sharedPasswordFund( From 79c35f2689b18bfdc405489af97c00dfa0e40ae2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 1 Oct 2012 15:21:22 -0700 Subject: [PATCH 405/426] Remove all IField/ITField functions. They are now obsolete. Use the correponding STObject functions. --- src/AccountState.cpp | 6 +- src/AccountState.h | 8 +- src/Ledger.cpp | 4 +- src/LedgerEntrySet.cpp | 108 ++++++++--------- src/NetworkOPs.cpp | 14 +-- src/NicknameState.cpp | 8 +- src/OrderBook.cpp | 4 +- src/RPCServer.cpp | 4 +- src/RippleCalc.cpp | 28 ++--- src/RippleLines.cpp | 4 +- src/RippleState.cpp | 14 +-- src/SerializedLedger.cpp | 4 +- src/SerializedLedger.h | 44 ------- src/SerializedObject.cpp | 22 ++++ src/SerializedObject.h | 1 + src/SerializedTransaction.cpp | 9 -- src/SerializedTransaction.h | 45 ------- src/Transaction.cpp | 78 ++++++------ src/Transaction.h | 18 +-- src/TransactionAction.cpp | 216 +++++++++++++++++----------------- src/TransactionEngine.cpp | 14 +-- 21 files changed, 289 insertions(+), 364 deletions(-) diff --git a/src/AccountState.cpp b/src/AccountState.cpp index 85ad825fed..42acd03d42 100644 --- a/src/AccountState.cpp +++ b/src/AccountState.cpp @@ -17,7 +17,7 @@ AccountState::AccountState(const NewcoinAddress& naAccountID) : mAccountID(naAcc mLedgerEntry = boost::make_shared(ltACCOUNT_ROOT); mLedgerEntry->setIndex(Ledger::getAccountRootIndex(naAccountID)); - mLedgerEntry->setIFieldAccount(sfAccount, naAccountID.getAccountID()); + mLedgerEntry->setValueFieldAccount(sfAccount, naAccountID.getAccountID()); mValid = true; } @@ -48,8 +48,8 @@ void AccountState::addJson(Json::Value& val) if (mValid) { - if (mLedgerEntry->getIFieldPresent(sfEmailHash)) - val["UrlGravatar"] = createGravatarUrl(mLedgerEntry->getIFieldH128(sfEmailHash)); + if (mLedgerEntry->isFieldPresent(sfEmailHash)) + val["UrlGravatar"] = createGravatarUrl(mLedgerEntry->getValueFieldH128(sfEmailHash)); } else { diff --git a/src/AccountState.h b/src/AccountState.h index 5559990a72..b0d68205bb 100644 --- a/src/AccountState.h +++ b/src/AccountState.h @@ -33,16 +33,16 @@ public: bool bHaveAuthorizedKey() { - return mLedgerEntry->getIFieldPresent(sfAuthorizedKey); + return mLedgerEntry->isFieldPresent(sfAuthorizedKey); } NewcoinAddress getAuthorizedKey() { - return mLedgerEntry->getIValueFieldAccount(sfAuthorizedKey); + return mLedgerEntry->getValueFieldAccount(sfAuthorizedKey); } - STAmount getBalance() const { return mLedgerEntry->getIValueFieldAmount(sfBalance); } - uint32 getSeq() const { return mLedgerEntry->getIFieldU32(sfSequence); } + STAmount getBalance() const { return mLedgerEntry->getValueFieldAmount(sfBalance); } + uint32 getSeq() const { return mLedgerEntry->getValueFieldU32(sfSequence); } SerializedLedgerEntry::pointer getSLE() { return mLedgerEntry; } const SerializedLedgerEntry& peekSLE() const { return *mLedgerEntry; } diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 8d7dec92bf..f9c4bf343f 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -27,8 +27,8 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(s { // special case: put coins in root account AccountState::pointer startAccount = boost::make_shared(masterID); - startAccount->peekSLE().setIFieldAmount(sfBalance, startAmount); - startAccount->peekSLE().setIFieldU32(sfSequence, 1); + startAccount->peekSLE().setValueFieldAmount(sfBalance, startAmount); + startAccount->peekSLE().setValueFieldU32(sfSequence, 1); writeBack(lepCREATE, startAccount->getSLE()); #if 0 std::cerr << "Root account:"; diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index c64b90d972..5147ed6286 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -383,28 +383,28 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) assert(origNode); threadOwners(origNode, mLedger, newMod); - if (origNode->getIFieldPresent(sfAmount)) + if (origNode->isFieldPresent(sfAmount)) { // node has an amount, covers ripple state nodes - STAmount amount = origNode->getIValueFieldAmount(sfAmount); + STAmount amount = origNode->getValueFieldAmount(sfAmount); if (amount.isNonZero()) metaNode.addAmount(TMSPrevBalance, amount); - amount = curNode->getIValueFieldAmount(sfAmount); + amount = curNode->getValueFieldAmount(sfAmount); if (amount.isNonZero()) metaNode.addAmount(TMSFinalBalance, amount); if (origNode->getType() == ltRIPPLE_STATE) { - metaNode.addAccount(TMSLowID, NewcoinAddress::createAccountID(origNode->getIValueFieldAmount(sfLowLimit).getIssuer())); - metaNode.addAccount(TMSHighID, NewcoinAddress::createAccountID(origNode->getIValueFieldAmount(sfHighLimit).getIssuer())); + metaNode.addAccount(TMSLowID, NewcoinAddress::createAccountID(origNode->getValueFieldAmount(sfLowLimit).getIssuer())); + metaNode.addAccount(TMSHighID, NewcoinAddress::createAccountID(origNode->getValueFieldAmount(sfHighLimit).getIssuer())); } } if (origNode->getType() == ltOFFER) { // check for non-zero balances - STAmount amount = origNode->getIValueFieldAmount(sfTakerPays); + STAmount amount = origNode->getValueFieldAmount(sfTakerPays); if (amount.isNonZero()) metaNode.addAmount(TMSFinalTakerPays, amount); - amount = origNode->getIValueFieldAmount(sfTakerGets); + amount = origNode->getValueFieldAmount(sfTakerGets); if (amount.isNonZero()) metaNode.addAmount(TMSFinalTakerGets, amount); } @@ -429,20 +429,20 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) if (nType == TMNModifiedNode) { assert(origNode); - if (origNode->getIFieldPresent(sfAmount)) + if (origNode->isFieldPresent(sfAmount)) { // node has an amount, covers account root nodes and ripple nodes - STAmount amount = origNode->getIValueFieldAmount(sfAmount); - if (amount != curNode->getIValueFieldAmount(sfAmount)) + STAmount amount = origNode->getValueFieldAmount(sfAmount); + if (amount != curNode->getValueFieldAmount(sfAmount)) metaNode.addAmount(TMSPrevBalance, amount); } if (origNode->getType() == ltOFFER) { - STAmount amount = origNode->getIValueFieldAmount(sfTakerPays); - if (amount != curNode->getIValueFieldAmount(sfTakerPays)) + STAmount amount = origNode->getValueFieldAmount(sfTakerPays); + if (amount != curNode->getValueFieldAmount(sfTakerPays)) metaNode.addAmount(TMSPrevTakerPays, amount); - amount = origNode->getIValueFieldAmount(sfTakerGets); - if (amount != curNode->getIValueFieldAmount(sfTakerGets)) + amount = origNode->getValueFieldAmount(sfTakerGets); + if (amount != curNode->getValueFieldAmount(sfTakerGets)) metaNode.addAmount(TMSPrevTakerGets, amount); } @@ -485,7 +485,7 @@ TER LedgerEntrySet::dirAdd( } else { - uNodeDir = sleRoot->getIFieldU64(sfIndexPrevious); // Get index to last directory node. + uNodeDir = sleRoot->getValueFieldU64(sfIndexPrevious); // Get index to last directory node. if (uNodeDir) { @@ -500,7 +500,7 @@ TER LedgerEntrySet::dirAdd( sleNode = sleRoot; } - svIndexes = sleNode->getIFieldV256(sfIndexes); + svIndexes = sleNode->getValueFieldV256(sfIndexes); if (DIR_NODE_MAX != svIndexes.peekValue().size()) { @@ -519,7 +519,7 @@ TER LedgerEntrySet::dirAdd( { // Previous node is root node. - sleRoot->setIFieldU64(sfIndexNext, uNodeDir); + sleRoot->setValueFieldU64(sfIndexNext, uNodeDir); } else { @@ -527,14 +527,14 @@ TER LedgerEntrySet::dirAdd( SLE::pointer slePrevious = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeDir-1)); - slePrevious->setIFieldU64(sfIndexNext, uNodeDir); + slePrevious->setValueFieldU64(sfIndexNext, uNodeDir); entryModify(slePrevious); - sleNode->setIFieldU64(sfIndexPrevious, uNodeDir-1); + sleNode->setValueFieldU64(sfIndexPrevious, uNodeDir-1); } // Have root point to new node. - sleRoot->setIFieldU64(sfIndexPrevious, uNodeDir); + sleRoot->setValueFieldU64(sfIndexPrevious, uNodeDir); entryModify(sleRoot); // Create the new node. @@ -544,7 +544,7 @@ TER LedgerEntrySet::dirAdd( } svIndexes.peekValue().push_back(uLedgerIndex); // Append entry. - sleNode->setIFieldV256(sfIndexes, svIndexes); // Save entry. + sleNode->setValueFieldV256(sfIndexes, svIndexes); // Save entry. Log(lsINFO) << "dirAdd: creating: root: " << uRootIndex.ToString(); Log(lsINFO) << "dirAdd: appending: Entry: " << uLedgerIndex.ToString(); @@ -574,7 +574,7 @@ TER LedgerEntrySet::dirDelete( return tefBAD_LEDGER; } - STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes); + STVector256 svIndexes = sleNode->getValueFieldV256(sfIndexes); std::vector& vuiIndexes = svIndexes.peekValue(); std::vector::iterator it; @@ -608,14 +608,14 @@ TER LedgerEntrySet::dirDelete( vuiIndexes.clear(); } - sleNode->setIFieldV256(sfIndexes, svIndexes); + sleNode->setValueFieldV256(sfIndexes, svIndexes); entryModify(sleNode); if (vuiIndexes.empty()) { // May be able to delete nodes. - uint64 uNodePrevious = sleNode->getIFieldU64(sfIndexPrevious); - uint64 uNodeNext = sleNode->getIFieldU64(sfIndexNext); + uint64 uNodePrevious = sleNode->getValueFieldU64(sfIndexPrevious); + uint64 uNodeNext = sleNode->getValueFieldU64(sfIndexNext); if (!uNodeCur) { @@ -646,7 +646,7 @@ TER LedgerEntrySet::dirDelete( assert(sleLast); - if (sleLast->getIFieldV256(sfIndexes).peekValue().empty()) + if (sleLast->getValueFieldV256(sfIndexes).peekValue().empty()) { // Both nodes are empty. @@ -690,11 +690,11 @@ TER LedgerEntrySet::dirDelete( } // Fix previous to point to its new next. - slePrevious->setIFieldU64(sfIndexNext, uNodeNext); + slePrevious->setValueFieldU64(sfIndexNext, uNodeNext); entryModify(slePrevious); // Fix next to point to its new previous. - sleNext->setIFieldU64(sfIndexPrevious, uNodePrevious); + sleNext->setValueFieldU64(sfIndexPrevious, uNodePrevious); entryModify(sleNext); } // Last node. @@ -712,7 +712,7 @@ TER LedgerEntrySet::dirDelete( assert(sleRoot); - if (sleRoot->getIFieldV256(sfIndexes).peekValue().empty()) + if (sleRoot->getValueFieldV256(sfIndexes).peekValue().empty()) { // Both nodes are empty. @@ -755,12 +755,12 @@ bool LedgerEntrySet::dirNext( unsigned int& uDirEntry, // <-> next entry uint256& uEntryIndex) // <-- The entry, if available. Otherwise, zero. { - STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes); + STVector256 svIndexes = sleNode->getValueFieldV256(sfIndexes); std::vector& vuiIndexes = svIndexes.peekValue(); if (uDirEntry == vuiIndexes.size()) { - uint64 uNodeNext = sleNode->getIFieldU64(sfIndexNext); + uint64 uNodeNext = sleNode->getValueFieldU64(sfIndexNext); if (!uNodeNext) { @@ -785,13 +785,13 @@ Log(lsINFO) << boost::str(boost::format("dirNext: uDirEntry=%d uEntryIndex=%s") TER LedgerEntrySet::offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID) { - uint64 uOwnerNode = sleOffer->getIFieldU64(sfOwnerNode); + uint64 uOwnerNode = sleOffer->getValueFieldU64(sfOwnerNode); TER terResult = dirDelete(false, uOwnerNode, Ledger::getOwnerDirIndex(uOwnerID), uOfferIndex, false); if (tesSUCCESS == terResult) { - uint256 uDirectory = sleOffer->getIFieldH256(sfBookDirectory); - uint64 uBookNode = sleOffer->getIFieldU64(sfBookNode); + uint256 uDirectory = sleOffer->getValueFieldH256(sfBookDirectory); + uint64 uBookNode = sleOffer->getValueFieldU64(sfBookNode); terResult = dirDelete(false, uBookNode, uDirectory, uOfferIndex, true); } @@ -804,7 +804,7 @@ TER LedgerEntrySet::offerDelete(const SLE::pointer& sleOffer, const uint256& uOf TER LedgerEntrySet::offerDelete(const uint256& uOfferIndex) { SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - const uint160 uOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + const uint160 uOwnerID = sleOffer->getValueFieldAccount(sfAccount).getAccountID(); return offerDelete(sleOffer, uOfferIndex, uOwnerID); } @@ -818,7 +818,7 @@ STAmount LedgerEntrySet::rippleOwed(const uint160& uToAccountID, const uint160& if (sleRippleState) { - saBalance = sleRippleState->getIValueFieldAmount(sfBalance); + saBalance = sleRippleState->getValueFieldAmount(sfBalance); if (uToAccountID < uFromAccountID) saBalance.negate(); saBalance.setIssuer(uToAccountID); @@ -849,7 +849,7 @@ STAmount LedgerEntrySet::rippleLimit(const uint160& uToAccountID, const uint160& assert(sleRippleState); if (sleRippleState) { - saLimit = sleRippleState->getIValueFieldAmount(uToAccountID < uFromAccountID ? sfLowLimit : sfHighLimit); + saLimit = sleRippleState->getValueFieldAmount(uToAccountID < uFromAccountID ? sfLowLimit : sfHighLimit); saLimit.setIssuer(uToAccountID); } @@ -861,8 +861,8 @@ uint32 LedgerEntrySet::rippleTransferRate(const uint160& uIssuerID) { SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uIssuerID)); - uint32 uQuality = sleAccount && sleAccount->getIFieldPresent(sfTransferRate) - ? sleAccount->getIFieldU32(sfTransferRate) + uint32 uQuality = sleAccount && sleAccount->isFieldPresent(sfTransferRate) + ? sleAccount->getValueFieldU32(sfTransferRate) : QUALITY_ONE; Log(lsINFO) << boost::str(boost::format("rippleTransferRate: uIssuerID=%s account_exists=%d transfer_rate=%f") @@ -893,8 +893,8 @@ uint32 LedgerEntrySet::rippleQualityIn(const uint160& uToAccountID, const uint16 { SField::ref sfField = uToAccountID < uFromAccountID ? sfLow: sfHigh; - uQuality = sleRippleState->getIFieldPresent(sfField) - ? sleRippleState->getIFieldU32(sfField) + uQuality = sleRippleState->isFieldPresent(sfField) + ? sleRippleState->getValueFieldU32(sfField) : QUALITY_ONE; if (!uQuality) @@ -924,7 +924,7 @@ STAmount LedgerEntrySet::rippleHolds(const uint160& uAccountID, const uint160& u if (sleRippleState) { - saBalance = sleRippleState->getIValueFieldAmount(sfBalance); + saBalance = sleRippleState->getValueFieldAmount(sfBalance); if (uAccountID > uIssuerID) saBalance.negate(); // Put balance in uAccountID terms. @@ -942,7 +942,7 @@ STAmount LedgerEntrySet::accountHolds(const uint160& uAccountID, const uint160& { SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uAccountID)); - saAmount = sleAccount->getIValueFieldAmount(sfBalance); + saAmount = sleAccount->getValueFieldAmount(sfBalance); } else { @@ -1031,13 +1031,13 @@ void LedgerEntrySet::rippleCredit(const uint160& uSenderID, const uint160& uRece if (!bFlipped) saBalance.negate(); - sleRippleState->setIFieldAmount(sfBalance, saBalance); - sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, STAmount(uCurrencyID, uSenderID)); - sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uReceiverID)); + sleRippleState->setValueFieldAmount(sfBalance, saBalance); + sleRippleState->setValueFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, STAmount(uCurrencyID, uSenderID)); + sleRippleState->setValueFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uReceiverID)); } else { - STAmount saBalance = sleRippleState->getIValueFieldAmount(sfBalance); + STAmount saBalance = sleRippleState->getValueFieldAmount(sfBalance); if (!bFlipped) saBalance.negate(); // Put balance in low terms. @@ -1047,7 +1047,7 @@ void LedgerEntrySet::rippleCredit(const uint160& uSenderID, const uint160& uRece if (!bFlipped) saBalance.negate(); - sleRippleState->setIFieldAmount(sfBalance, saBalance); + sleRippleState->setValueFieldAmount(sfBalance, saBalance); entryModify(sleRippleState); } @@ -1106,28 +1106,28 @@ void LedgerEntrySet::accountSend(const uint160& uSenderID, const uint160& uRecei Log(lsINFO) << boost::str(boost::format("accountSend> %s (%s) -> %s (%s) : %s") % NewcoinAddress::createHumanAccountID(uSenderID) - % (sleSender ? (sleSender->getIValueFieldAmount(sfBalance)).getFullText() : "-") + % (sleSender ? (sleSender->getValueFieldAmount(sfBalance)).getFullText() : "-") % NewcoinAddress::createHumanAccountID(uReceiverID) - % (sleReceiver ? (sleReceiver->getIValueFieldAmount(sfBalance)).getFullText() : "-") + % (sleReceiver ? (sleReceiver->getValueFieldAmount(sfBalance)).getFullText() : "-") % saAmount.getFullText()); if (sleSender) { - sleSender->setIFieldAmount(sfBalance, sleSender->getIValueFieldAmount(sfBalance) - saAmount); + sleSender->setValueFieldAmount(sfBalance, sleSender->getValueFieldAmount(sfBalance) - saAmount); entryModify(sleSender); } if (sleReceiver) { - sleReceiver->setIFieldAmount(sfBalance, sleReceiver->getIValueFieldAmount(sfBalance) + saAmount); + sleReceiver->setValueFieldAmount(sfBalance, sleReceiver->getValueFieldAmount(sfBalance) + saAmount); entryModify(sleReceiver); } Log(lsINFO) << boost::str(boost::format("accountSend< %s (%s) -> %s (%s) : %s") % NewcoinAddress::createHumanAccountID(uSenderID) - % (sleSender ? (sleSender->getIValueFieldAmount(sfBalance)).getFullText() : "-") + % (sleSender ? (sleSender->getValueFieldAmount(sfBalance)).getFullText() : "-") % NewcoinAddress::createHumanAccountID(uReceiverID) - % (sleReceiver ? (sleReceiver->getIValueFieldAmount(sfBalance)).getFullText() : "-") + % (sleReceiver ? (sleReceiver->getValueFieldAmount(sfBalance)).getFullText() : "-") % saAmount.getFullText()); } else diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 7985e2dbe6..c645fd1fbb 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -245,12 +245,12 @@ STVector256 NetworkOPs::getDirNodeInfo( { Log(lsDEBUG) << "getDirNodeInfo: node index: " << uNodeIndex.ToString(); - Log(lsTRACE) << "getDirNodeInfo: first: " << strHex(sleNode->getIFieldU64(sfIndexPrevious)); - Log(lsTRACE) << "getDirNodeInfo: last: " << strHex(sleNode->getIFieldU64(sfIndexNext)); + Log(lsTRACE) << "getDirNodeInfo: first: " << strHex(sleNode->getValueFieldU64(sfIndexPrevious)); + Log(lsTRACE) << "getDirNodeInfo: last: " << strHex(sleNode->getValueFieldU64(sfIndexNext)); - uNodePrevious = sleNode->getIFieldU64(sfIndexPrevious); - uNodeNext = sleNode->getIFieldU64(sfIndexNext); - svIndexes = sleNode->getIFieldV256(sfIndexes); + uNodePrevious = sleNode->getValueFieldU64(sfIndexPrevious); + uNodeNext = sleNode->getValueFieldU64(sfIndexNext); + svIndexes = sleNode->getValueFieldV256(sfIndexes); Log(lsTRACE) << "getDirNodeInfo: first: " << strHex(uNodePrevious); Log(lsTRACE) << "getDirNodeInfo: last: " << strHex(uNodeNext); @@ -299,7 +299,7 @@ Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddr do { - STVector256 svIndexes = sleNode->getIFieldV256(sfIndexes); + STVector256 svIndexes = sleNode->getValueFieldV256(sfIndexes); const std::vector& vuiIndexes = svIndexes.peekValue(); BOOST_FOREACH(const uint256& uDirEntry, vuiIndexes) @@ -332,7 +332,7 @@ Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddr } } - uNodeDir = sleNode->getIFieldU64(sfIndexNext); + uNodeDir = sleNode->getValueFieldU64(sfIndexNext); if (uNodeDir) { lspNode = lepNONE; diff --git a/src/NicknameState.cpp b/src/NicknameState.cpp index 9b2cb3e857..e1dcb39aa8 100644 --- a/src/NicknameState.cpp +++ b/src/NicknameState.cpp @@ -8,19 +8,19 @@ NicknameState::NicknameState(SerializedLedgerEntry::pointer ledgerEntry) : bool NicknameState::haveMinimumOffer() const { - return mLedgerEntry->getIFieldPresent(sfMinimumOffer); + return mLedgerEntry->isFieldPresent(sfMinimumOffer); } STAmount NicknameState::getMinimumOffer() const { - return mLedgerEntry->getIFieldPresent(sfMinimumOffer) - ? mLedgerEntry->getIValueFieldAmount(sfMinimumOffer) + return mLedgerEntry->isFieldPresent(sfMinimumOffer) + ? mLedgerEntry->getValueFieldAmount(sfMinimumOffer) : STAmount(); } NewcoinAddress NicknameState::getAccountID() const { - return mLedgerEntry->getIValueFieldAccount(sfAccount); + return mLedgerEntry->getValueFieldAccount(sfAccount); } void NicknameState::addJson(Json::Value& val) diff --git a/src/OrderBook.cpp b/src/OrderBook.cpp index d349609107..9c032b9670 100644 --- a/src/OrderBook.cpp +++ b/src/OrderBook.cpp @@ -10,8 +10,8 @@ OrderBook::pointer OrderBook::newOrderBook(SerializedLedgerEntry::pointer ledger OrderBook::OrderBook(SerializedLedgerEntry::pointer ledgerEntry) { - const STAmount saTakerGets = ledgerEntry->getIValueFieldAmount(sfTakerGets); - const STAmount saTakerPays = ledgerEntry->getIValueFieldAmount(sfTakerPays); + const STAmount saTakerGets = ledgerEntry->getValueFieldAmount(sfTakerGets); + const STAmount saTakerPays = ledgerEntry->getValueFieldAmount(sfTakerPays); mCurrencyIn = saTakerGets.getCurrency(); mCurrencyOut = saTakerPays.getCurrency(); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 8936231c2c..cc9d1aa568 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -252,7 +252,7 @@ Json::Value RPCServer::getMasterGenerator(const uint256& uLedger, const NewcoinA return RPCError(rpcNO_ACCOUNT); } - std::vector vucCipher = sleGen->getIFieldVL(sfGenerator); + std::vector vucCipher = sleGen->getValueFieldVL(sfGenerator); std::vector vucMasterGenerator = na0Private.accountPrivateDecrypt(na0Public, vucCipher); if (vucMasterGenerator.empty()) { @@ -402,7 +402,7 @@ Json::Value RPCServer::accountFromString(const uint256& uLedger, NewcoinAddress& else { // Found master public key. - std::vector vucCipher = sleGen->getIFieldVL(sfGenerator); + std::vector vucCipher = sleGen->getValueFieldVL(sfGenerator); std::vector vucMasterGenerator = naRegular0Private.accountPrivateDecrypt(naRegular0Public, vucCipher); if (vucMasterGenerator.empty()) { diff --git a/src/RippleCalc.cpp b/src/RippleCalc.cpp index 3a1b1cc2f2..1292964cb4 100644 --- a/src/RippleCalc.cpp +++ b/src/RippleCalc.cpp @@ -116,8 +116,8 @@ TER RippleCalc::calcNodeAdvance( { if (bFundsDirty) { - saTakerPays = sleOffer->getIValueFieldAmount(sfTakerPays); - saTakerGets = sleOffer->getIValueFieldAmount(sfTakerGets); + saTakerPays = sleOffer->getValueFieldAmount(sfTakerPays); + saTakerGets = sleOffer->getValueFieldAmount(sfTakerGets); saOfferFunds = lesActive.accountFunds(uOfrOwnerID, saTakerGets); // Funds left. bFundsDirty = false; @@ -153,13 +153,13 @@ TER RippleCalc::calcNodeAdvance( { // Got a new offer. sleOffer = lesActive.entryCache(ltOFFER, uOfferIndex); - uOfrOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); + uOfrOwnerID = sleOffer->getValueFieldAccount(sfAccount).getAccountID(); const aciSource asLine = boost::make_tuple(uOfrOwnerID, uCurCurrencyID, uCurIssuerID); Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: uOfrOwnerID=%s") % NewcoinAddress::createHumanAccountID(uOfrOwnerID)); - if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= lesActive.getLedger()->getParentCloseTimeNC()) + if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getValueFieldU32(sfExpiration) <= lesActive.getLedger()->getParentCloseTimeNC()) { // Offer is expired. Log(lsINFO) << "calcNodeAdvance: expired offer"; @@ -207,8 +207,8 @@ TER RippleCalc::calcNodeAdvance( continue; } - saTakerPays = sleOffer->getIValueFieldAmount(sfTakerPays); - saTakerGets = sleOffer->getIValueFieldAmount(sfTakerGets); + saTakerPays = sleOffer->getValueFieldAmount(sfTakerPays); + saTakerGets = sleOffer->getValueFieldAmount(sfTakerGets); saOfferFunds = lesActive.accountFunds(uOfrOwnerID, saTakerGets); // Funds left. @@ -430,8 +430,8 @@ TER RippleCalc::calcNodeDeliverRev( lesActive.accountSend(uOfrOwnerID, uCurIssuerID, saOutPass); // Adjust offer - sleOffer->setIFieldAmount(sfTakerGets, saTakerGets - saOutPass); - sleOffer->setIFieldAmount(sfTakerPays, saTakerPays - saInPassAct); + sleOffer->setValueFieldAmount(sfTakerGets, saTakerGets - saOutPass); + sleOffer->setValueFieldAmount(sfTakerPays, saTakerPays - saInPassAct); lesActive.entryModify(sleOffer); @@ -580,8 +580,8 @@ TER RippleCalc::calcNodeDeliverFwd( lesActive.accountSend(uInAccountID, uOfrOwnerID, saInPassAct); // Adjust offer - sleOffer->setIFieldAmount(sfTakerGets, saTakerGets - saOutPassAct); - sleOffer->setIFieldAmount(sfTakerPays, saTakerPays - saInPassAct); + sleOffer->setValueFieldAmount(sfTakerGets, saTakerGets - saOutPassAct); + sleOffer->setValueFieldAmount(sfTakerPays, saTakerPays - saInPassAct); lesActive.entryModify(sleOffer); @@ -2092,11 +2092,11 @@ void TransactionEngine::calcOfferBridgeNext( SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - uint160 uOfferOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); - STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); - STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); + uint160 uOfferOwnerID = sleOffer->getValueFieldAccount(sfAccount).getAccountID(); + STAmount saOfferPays = sleOffer->getValueFieldAmount(sfTakerGets); + STAmount saOfferGets = sleOffer->getValueFieldAmount(sfTakerPays); - if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getValueFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) { // Offer is expired. Log(lsINFO) << "calcOfferFirst: encountered expired offer"; diff --git a/src/RippleLines.cpp b/src/RippleLines.cpp index 391d38c02d..e66168f58e 100644 --- a/src/RippleLines.cpp +++ b/src/RippleLines.cpp @@ -25,7 +25,7 @@ void RippleLines::fillLines(const uint160& accountID, Ledger::pointer ledger) SLE::pointer rippleDir=ledger->getDirNode(lspNode, currentIndex); if (!rippleDir) return; - STVector256 svOwnerNodes = rippleDir->getIFieldV256(sfIndexes); + STVector256 svOwnerNodes = rippleDir->getValueFieldV256(sfIndexes); BOOST_FOREACH(uint256& uNode, svOwnerNodes.peekValue()) { SLE::pointer sleCur = ledger->getSLE(uNode); @@ -45,7 +45,7 @@ void RippleLines::fillLines(const uint160& accountID, Ledger::pointer ledger) } } - uint64 uNodeNext = rippleDir->getIFieldU64(sfIndexNext); + uint64 uNodeNext = rippleDir->getValueFieldU64(sfIndexNext); if (!uNodeNext) return; currentIndex = Ledger::getDirNodeIndex(rootIndex, uNodeNext); diff --git a/src/RippleState.cpp b/src/RippleState.cpp index 72b9efd10d..911a7380ee 100644 --- a/src/RippleState.cpp +++ b/src/RippleState.cpp @@ -7,19 +7,19 @@ RippleState::RippleState(SerializedLedgerEntry::pointer ledgerEntry) : { if (!mLedgerEntry || mLedgerEntry->getType() != ltRIPPLE_STATE) return; - mLowLimit = mLedgerEntry->getIValueFieldAmount(sfLowLimit); - mHighLimit = mLedgerEntry->getIValueFieldAmount(sfHighLimit); + mLowLimit = mLedgerEntry->getValueFieldAmount(sfLowLimit); + mHighLimit = mLedgerEntry->getValueFieldAmount(sfHighLimit); mLowID = NewcoinAddress::createAccountID(mLowLimit.getIssuer()); mHighID = NewcoinAddress::createAccountID(mHighLimit.getIssuer()); - mLowQualityIn = mLedgerEntry->getIFieldU32(sfLowQualityIn); - mLowQualityOut = mLedgerEntry->getIFieldU32(sfLowQualityOut); + mLowQualityIn = mLedgerEntry->getValueFieldU32(sfLowQualityIn); + mLowQualityOut = mLedgerEntry->getValueFieldU32(sfLowQualityOut); - mHighQualityIn = mLedgerEntry->getIFieldU32(sfHighQualityIn); - mHighQualityOut = mLedgerEntry->getIFieldU32(sfHighQualityOut); + mHighQualityIn = mLedgerEntry->getValueFieldU32(sfHighQualityIn); + mHighQualityOut = mLedgerEntry->getValueFieldU32(sfHighQualityOut); - mBalance = mLedgerEntry->getIValueFieldAmount(sfBalance); + mBalance = mLedgerEntry->getValueFieldAmount(sfBalance); mValid = true; } diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 4ba43bd1e3..4b854d2384 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -124,12 +124,12 @@ NewcoinAddress SerializedLedgerEntry::getOwner() NewcoinAddress SerializedLedgerEntry::getFirstOwner() { - return NewcoinAddress::createAccountID(getIValueFieldAmount(sfLowLimit).getIssuer()); + return NewcoinAddress::createAccountID(getValueFieldAmount(sfLowLimit).getIssuer()); } NewcoinAddress SerializedLedgerEntry::getSecondOwner() { - return NewcoinAddress::createAccountID(getIValueFieldAmount(sfHighLimit).getIssuer()); + return NewcoinAddress::createAccountID(getValueFieldAmount(sfHighLimit).getIssuer()); } std::vector SerializedLedgerEntry::getOwners() diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index b7f35a34f4..455830661e 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -46,50 +46,6 @@ public: uint32 getThreadedLedger(); bool thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID); std::vector getOwners(); // nodes notified if this node is deleted - - // CAUTION: All these functions are now obsolete and will be removed after - // the new serialization code is merged. - int getIFieldIndex(SField::ref field) const { return getFieldIndex(field); } - int getIFieldCount() const { return getCount(); } - const SerializedType& peekIField(SField::ref field) const { return peekAtField(field); } - SerializedType& getIField(SField::ref field) { return getField(field); } - SField::ref getIFieldSType(int index) { return getFieldSType(index); } - std::string getIFieldString(SField::ref field) const { return getFieldString(field); } - unsigned char getIFieldU8(SField::ref field) const { return getValueFieldU8(field); } - uint16 getIFieldU16(SField::ref field) const { return getValueFieldU16(field); } - uint32 getIFieldU32(SField::ref field) const { return getValueFieldU32(field); } - uint64 getIFieldU64(SField::ref field) const { return getValueFieldU64(field); } - uint128 getIFieldH128(SField::ref field) const { return getValueFieldH128(field); } - uint160 getIFieldH160(SField::ref field) const { return getValueFieldH160(field); } - uint256 getIFieldH256(SField::ref field) const { return getValueFieldH256(field); } - std::vector getIFieldVL(SField::ref field) const { return getValueFieldVL(field); } - std::vector getIFieldTL(SField::ref field) const { return getValueFieldTL(field); } - NewcoinAddress getIValueFieldAccount(SField::ref field) const { return getValueFieldAccount(field); } - STAmount getIValueFieldAmount(SField::ref field) const { return getValueFieldAmount(field); } - STVector256 getIFieldV256(SField::ref field) { return getValueFieldV256(field); } - void setIFieldU8(SField::ref field, unsigned char v) { return setValueFieldU8(field, v); } - void setIFieldU16(SField::ref field, uint16 v) { return setValueFieldU16(field, v); } - void setIFieldU32(SField::ref field, uint32 v) { return setValueFieldU32(field, v); } - void setIFieldU64(SField::ref field, uint64 v) { return setValueFieldU64(field, v); } - void setIFieldH128(SField::ref field, const uint128& v) { return setValueFieldH128(field, v); } - void setIFieldH160(SField::ref field, const uint160& v) { return setValueFieldH160(field, v); } - void setIFieldH256(SField::ref field, const uint256& v) { return setValueFieldH256(field, v); } - void setIFieldVL(SField::ref field, const std::vector& v) - { return setValueFieldVL(field, v); } - void setIFieldTL(SField::ref field, const std::vector& v) - { return setValueFieldTL(field, v); } - void setIFieldAccount(SField::ref field, const uint160& account) - { return setValueFieldAccount(field, account); } - void setIFieldAccount(SField::ref field, const NewcoinAddress& account) - { return setValueFieldAccount(field, account); } - void setIFieldAmount(SField::ref field, const STAmount& amount) - { return setValueFieldAmount(field, amount); } - void setIFieldV256(SField::ref field, const STVector256& v) { return setValueFieldV256(field, v); } - bool getIFieldPresent(SField::ref field) const { return isFieldPresent(field); } - void makeIFieldPresent(SField::ref field) { makeFieldPresent(field); } - void makeIFieldAbsent(SField::ref field) { return makeFieldAbsent(field); } - // CAUTION: All the above functions are obsolete - }; typedef SerializedLedgerEntry SLE; diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 0bfab6c928..5cf6a4e7dc 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -545,6 +545,28 @@ NewcoinAddress STObject::getValueFieldAccount(SField::ref field) const return cf->getValueNCA(); } +uint160 STObject::getValueFieldAccount160(SField::ref field) const +{ + uint160 a; + const SerializedType* rf = peekAtPField(field); + if (!rf) + { +#ifdef DEBUG + std::cerr << "Account field not found" << std::endl; + std::cerr << getFullText() << std::endl; +#endif + throw std::runtime_error("Field not found"); + } + SerializedTypeID id = rf->getSType(); + if (id != STI_NOTPRESENT) + { + const STAccount* cf = dynamic_cast(rf); + if (!cf) throw std::runtime_error("Wrong field type"); + cf->getValueH160(a); + } + return a; +} + std::vector STObject::getValueFieldVL(SField::ref field) const { const SerializedType* rf = peekAtPField(field); diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 58a926d983..321e8c1c78 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -103,6 +103,7 @@ public: uint160 getValueFieldH160(SField::ref field) const; uint256 getValueFieldH256(SField::ref field) const; NewcoinAddress getValueFieldAccount(SField::ref field) const; + uint160 getValueFieldAccount160(SField::ref field) const; std::vector getValueFieldVL(SField::ref field) const; std::vector getValueFieldTL(SField::ref field) const; STAmount getValueFieldAmount(SField::ref field) const; diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index aca26946ca..5059848b46 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -131,15 +131,6 @@ void SerializedTransaction::setSourceAccount(const NewcoinAddress& naSource) setValueFieldAccount(sfAccount, naSource); } -uint160 SerializedTransaction::getITFieldAccount(SField::ref field) const -{ - uint160 r; - const STAccount* ac = dynamic_cast(peekAtPField(field)); - if (ac) - ac->getValueH160(r); - return r; -} - Json::Value SerializedTransaction::getJson(int options) const { Json::Value ret = STObject::getJson(0); diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index 295d0eb3cb..f38f9c73fd 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -55,51 +55,6 @@ public: uint32 getSequence() const { return getValueFieldU32(sfSequence); } void setSequence(uint32 seq) { return setValueFieldU32(sfSequence, seq); } - // inner transaction field functions (OBSOLETE - use STObject functions) - int getITFieldIndex(SField::ref field) const { return getFieldIndex(field); } - const SerializedType& peekITField(SField::ref field) const { return peekAtField(field); } - SerializedType& getITField(SField::ref field) { return getField(field); } - - // inner transaction field value functions (OBSOLETE - use STObject functions) - std::string getITFieldString(SField::ref field) const { return getFieldString(field); } - unsigned char getITFieldU8(SField::ref field) const { return getValueFieldU8(field); } - uint16 getITFieldU16(SField::ref field) const { return getValueFieldU16(field); } - uint32 getITFieldU32(SField::ref field) const { return getValueFieldU32(field); } - uint64 getITFieldU64(SField::ref field) const { return getValueFieldU64(field); } - uint128 getITFieldH128(SField::ref field) const { return getValueFieldH128(field); } - uint160 getITFieldH160(SField::ref field) const { return getValueFieldH160(field); } - uint160 getITFieldAccount(SField::ref field) const; - uint256 getITFieldH256(SField::ref field) const { return getValueFieldH256(field); } - std::vector getITFieldVL(SField::ref field) const { return getValueFieldVL(field); } - std::vector getITFieldTL(SField::ref field) const { return getValueFieldTL(field); } - STAmount getITFieldAmount(SField::ref field) const { return getValueFieldAmount(field); } - STPathSet getITFieldPathSet(SField::ref field) const { return getValueFieldPathSet(field); } - - void setITFieldU8(SField::ref field, unsigned char v) { return setValueFieldU8(field, v); } - void setITFieldU16(SField::ref field, uint16 v) { return setValueFieldU16(field, v); } - void setITFieldU32(SField::ref field, uint32 v) { return setValueFieldU32(field, v); } - void setITFieldU64(SField::ref field, uint32 v) { return setValueFieldU64(field, v); } - void setITFieldH128(SField::ref field, const uint128& v) { return setValueFieldH128(field, v); } - void setITFieldH160(SField::ref field, const uint160& v) { return setValueFieldH160(field, v); } - void setITFieldH256(SField::ref field, const uint256& v) { return setValueFieldH256(field, v); } - void setITFieldVL(SField::ref field, const std::vector& v) - { return setValueFieldVL(field, v); } - void setITFieldTL(SField::ref field, const std::vector& v) - { return setValueFieldTL(field, v); } - void setITFieldAccount(SField::ref field, const uint160& v) - { return setValueFieldAccount(field, v); } - void setITFieldAccount(SField::ref field, const NewcoinAddress& v) - { return setValueFieldAccount(field, v); } - void setITFieldAmount(SField::ref field, const STAmount& v) - { return setValueFieldAmount(field, v); } - void setITFieldPathSet(SField::ref field, const STPathSet& v) - { return setValueFieldPathSet(field, v); } - - // optional field functions (OBSOLETE - use STObject functions) - bool getITFieldPresent(SField::ref field) const { return isFieldPresent(field); } - void makeITFieldPresent(SField::ref field) { makeFieldPresent(field); } - void makeITFieldAbsent(SField::ref field) { makeFieldAbsent(field); } - std::vector getAffectedAccounts() const; uint256 getTransactionID() const; diff --git a/src/Transaction.cpp b/src/Transaction.cpp index ec209bdf16..81586f7280 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -78,8 +78,8 @@ Transaction::Transaction( if (uSourceTag) { - mTransaction->makeITFieldPresent(sfSourceTag); - mTransaction->setITFieldU32(sfSourceTag, uSourceTag); + mTransaction->makeFieldPresent(sfSourceTag); + mTransaction->setValueFieldU32(sfSourceTag, uSourceTag); } } @@ -127,24 +127,24 @@ Transaction::pointer Transaction::setAccountSet( ) { if (!bEmailHash) - mTransaction->setITFieldH128(sfEmailHash, uEmailHash); + mTransaction->setValueFieldH128(sfEmailHash, uEmailHash); if (!bWalletLocator) - mTransaction->setITFieldH256(sfWalletLocator, uWalletLocator); + mTransaction->setValueFieldH256(sfWalletLocator, uWalletLocator); if (naMessagePublic.isValid()) - mTransaction->setITFieldVL(sfMessageKey, naMessagePublic.getAccountPublic()); + mTransaction->setValueFieldVL(sfMessageKey, naMessagePublic.getAccountPublic()); if (bDomain) - mTransaction->setITFieldVL(sfDomain, vucDomain); + mTransaction->setValueFieldVL(sfDomain, vucDomain); if (bTransferRate) - mTransaction->setITFieldU32(sfTransferRate, uTransferRate); + mTransaction->setValueFieldU32(sfTransferRate, uTransferRate); if (bPublish) { - mTransaction->setITFieldH256(sfPublishHash, uPublishHash); - mTransaction->setITFieldU32(sfPublishSize, uPublishSize); + mTransaction->setValueFieldH256(sfPublishHash, uPublishHash); + mTransaction->setValueFieldU32(sfPublishSize, uPublishSize); } sign(naPrivateKey); @@ -188,9 +188,9 @@ Transaction::pointer Transaction::setClaim( const std::vector& vucPubKey, const std::vector& vucSignature) { - mTransaction->setITFieldVL(sfGenerator, vucGenerator); - mTransaction->setITFieldVL(sfPublicKey, vucPubKey); - mTransaction->setITFieldVL(sfSignature, vucSignature); + mTransaction->setValueFieldVL(sfGenerator, vucGenerator); + mTransaction->setValueFieldVL(sfPublicKey, vucPubKey); + mTransaction->setValueFieldVL(sfSignature, vucSignature); sign(naPrivateKey); @@ -222,9 +222,9 @@ Transaction::pointer Transaction::setCreate( const NewcoinAddress& naCreateAccountID, const STAmount& saFund) { - mTransaction->setITFieldU32(sfFlags, tfCreateAccount); - mTransaction->setITFieldAccount(sfDestination, naCreateAccountID); - mTransaction->setITFieldAmount(sfAmount, saFund); + mTransaction->setValueFieldU32(sfFlags, tfCreateAccount); + mTransaction->setValueFieldAccount(sfDestination, naCreateAccountID); + mTransaction->setValueFieldAmount(sfAmount, saFund); sign(naPrivateKey); @@ -257,13 +257,13 @@ Transaction::pointer Transaction::setCreditSet( bool bQualityOut, uint32 uQualityOut) { - mTransaction->setITFieldAmount(sfLimitAmount, saLimitAmount); + mTransaction->setValueFieldAmount(sfLimitAmount, saLimitAmount); if (bQualityIn) - mTransaction->setITFieldU32(sfQualityIn, uQualityIn); + mTransaction->setValueFieldU32(sfQualityIn, uQualityIn); if (bQualityOut) - mTransaction->setITFieldU32(sfQualityOut, uQualityOut); + mTransaction->setValueFieldU32(sfQualityOut, uQualityOut); sign(naPrivateKey); @@ -301,14 +301,14 @@ Transaction::pointer Transaction::setNicknameSet( const STAmount& saMinimumOffer, const std::vector& vucSignature) { - mTransaction->setITFieldH256(sfNickname, uNickname); + mTransaction->setValueFieldH256(sfNickname, uNickname); // XXX Make sure field is present even for 0! if (bSetOffer) - mTransaction->setITFieldAmount(sfMinimumOffer, saMinimumOffer); + mTransaction->setValueFieldAmount(sfMinimumOffer, saMinimumOffer); if (!vucSignature.empty()) - mTransaction->setITFieldVL(sfSignature, vucSignature); + mTransaction->setValueFieldVL(sfSignature, vucSignature); sign(naPrivateKey); @@ -345,13 +345,13 @@ Transaction::pointer Transaction::setOfferCreate( uint32 uExpiration) { if (bPassive) - mTransaction->setITFieldU32(sfFlags, tfPassive); + mTransaction->setValueFieldU32(sfFlags, tfPassive); - mTransaction->setITFieldAmount(sfTakerPays, saTakerPays); - mTransaction->setITFieldAmount(sfTakerGets, saTakerGets); + mTransaction->setValueFieldAmount(sfTakerPays, saTakerPays); + mTransaction->setValueFieldAmount(sfTakerGets, saTakerGets); if (uExpiration) - mTransaction->setITFieldU32(sfExpiration, uExpiration); + mTransaction->setValueFieldU32(sfExpiration, uExpiration); sign(naPrivateKey); @@ -382,7 +382,7 @@ Transaction::pointer Transaction::setOfferCancel( const NewcoinAddress& naPrivateKey, uint32 uSequence) { - mTransaction->setITFieldU32(sfOfferSequence, uSequence); + mTransaction->setValueFieldU32(sfOfferSequence, uSequence); sign(naPrivateKey); @@ -410,7 +410,7 @@ Transaction::pointer Transaction::setPasswordFund( const NewcoinAddress& naPrivateKey, const NewcoinAddress& naDstAccountID) { - mTransaction->setITFieldAccount(sfDestination, naDstAccountID); + mTransaction->setValueFieldAccount(sfDestination, naDstAccountID); sign(naPrivateKey); @@ -441,10 +441,10 @@ Transaction::pointer Transaction::setPasswordSet( const std::vector& vucPubKey, const std::vector& vucSignature) { - mTransaction->setITFieldAccount(sfAuthorizedKey, naAuthKeyID); - mTransaction->setITFieldVL(sfGenerator, vucGenerator); - mTransaction->setITFieldVL(sfPublicKey, vucPubKey); - mTransaction->setITFieldVL(sfSignature, vucSignature); + mTransaction->setValueFieldAccount(sfAuthorizedKey, naAuthKeyID); + mTransaction->setValueFieldVL(sfGenerator, vucGenerator); + mTransaction->setValueFieldVL(sfPublicKey, vucPubKey); + mTransaction->setValueFieldVL(sfSignature, vucSignature); sign(naPrivateKey); @@ -481,17 +481,17 @@ Transaction::pointer Transaction::setPayment( const bool bPartial, const bool bLimit) { - mTransaction->setITFieldAccount(sfDestination, naDstAccountID); - mTransaction->setITFieldAmount(sfAmount, saAmount); + mTransaction->setValueFieldAccount(sfDestination, naDstAccountID); + mTransaction->setValueFieldAmount(sfAmount, saAmount); if (saAmount != saSendMax || saAmount.getCurrency() != saSendMax.getCurrency()) { - mTransaction->setITFieldAmount(sfSendMax, saSendMax); + mTransaction->setValueFieldAmount(sfSendMax, saSendMax); } if (spsPaths.getPathCount()) { - mTransaction->setITFieldPathSet(sfPaths, spsPaths); + mTransaction->setValueFieldPathSet(sfPaths, spsPaths); } sign(naPrivateKey); @@ -528,10 +528,10 @@ Transaction::pointer Transaction::setWalletAdd( const NewcoinAddress& naNewPubKey, const std::vector& vucSignature) { - mTransaction->setITFieldAmount(sfAmount, saAmount); - mTransaction->setITFieldAccount(sfAuthorizedKey, naAuthKeyID); - mTransaction->setITFieldVL(sfPublicKey, naNewPubKey.getAccountPublic()); - mTransaction->setITFieldVL(sfSignature, vucSignature); + mTransaction->setValueFieldAmount(sfAmount, saAmount); + mTransaction->setValueFieldAccount(sfAuthorizedKey, naAuthKeyID); + mTransaction->setValueFieldVL(sfPublicKey, naNewPubKey.getAccountPublic()); + mTransaction->setValueFieldVL(sfSignature, vucSignature); sign(naPrivateKey); diff --git a/src/Transaction.h b/src/Transaction.h index d8dc7fa7cc..2e97d20940 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -272,15 +272,15 @@ public: SerializedTransaction::pointer getSTransaction() { return mTransaction; } - const uint256& getID() const { return mTransactionID; } - const NewcoinAddress& getFromAccount() const { return mAccountFrom; } - STAmount getAmount() const { return mTransaction->getITFieldU64(sfAmount); } - STAmount getFee() const { return mTransaction->getTransactionFee(); } - uint32 getFromAccountSeq() const { return mTransaction->getSequence(); } - uint32 getIdent() const { return mTransaction->getITFieldU32(sfSourceTag); } - std::vector getSignature() const { return mTransaction->getSignature(); } - uint32 getLedger() const { return mInLedger; } - TransStatus getStatus() const { return mStatus; } + const uint256& getID() const { return mTransactionID; } + const NewcoinAddress& getFromAccount() const { return mAccountFrom; } + STAmount getAmount() const { return mTransaction->getValueFieldU64(sfAmount); } + STAmount getFee() const { return mTransaction->getTransactionFee(); } + uint32 getFromAccountSeq() const { return mTransaction->getSequence(); } + uint32 getIdent() const { return mTransaction->getValueFieldU32(sfSourceTag); } + std::vector getSignature() const { return mTransaction->getSignature(); } + uint32 getLedger() const { return mInLedger; } + TransStatus getStatus() const { return mStatus; } void setStatus(TransStatus status, uint32 ledgerSeq); void setStatus(TransStatus status) { mStatus=status; } diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index 190a66bb3f..64dd343863 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -29,9 +29,9 @@ TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMus // Otherwise, people could deny access to generators. // - std::vector vucCipher = txn.getITFieldVL(sfGenerator); - std::vector vucPubKey = txn.getITFieldVL(sfPublicKey); - std::vector vucSignature = txn.getITFieldVL(sfSignature); + std::vector vucCipher = txn.getValueFieldVL(sfGenerator); + std::vector vucPubKey = txn.getValueFieldVL(sfPublicKey); + std::vector vucSignature = txn.getValueFieldVL(sfSignature); NewcoinAddress naAccountPublic = NewcoinAddress::createAccountPublic(vucPubKey); if (!naAccountPublic.accountPublicVerify(Serializer::getSHA512Half(vucCipher), vucSignature)) @@ -52,7 +52,7 @@ TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMus sleGen = entryCreate(ltGENERATOR_MAP, Ledger::getGeneratorIndex(hGeneratorID)); - sleGen->setIFieldVL(sfGenerator, vucCipher); + sleGen->setValueFieldVL(sfGenerator, vucCipher); } else if (bMustSetGenerator) { @@ -66,9 +66,9 @@ TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMus // Set the public key needed to use the account. uint160 uAuthKeyID = bMustSetGenerator ? hGeneratorID // Claim - : txn.getITFieldAccount(sfAuthorizedKey); // PasswordSet + : txn.getValueFieldAccount160(sfAuthorizedKey); // PasswordSet - mTxnAccount->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); + mTxnAccount->setValueFieldAccount(sfAuthorizedKey, uAuthKeyID); return tesSUCCESS; } @@ -81,21 +81,21 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) // EmailHash // - if (txn.getITFieldPresent(sfEmailHash)) + if (txn.isFieldPresent(sfEmailHash)) { - uint128 uHash = txn.getITFieldH128(sfEmailHash); + uint128 uHash = txn.getValueFieldH128(sfEmailHash); if (!uHash) { Log(lsINFO) << "doAccountSet: unset email hash"; - mTxnAccount->makeIFieldAbsent(sfEmailHash); + mTxnAccount->makeFieldAbsent(sfEmailHash); } else { Log(lsINFO) << "doAccountSet: set email hash"; - mTxnAccount->setIFieldH128(sfEmailHash, uHash); + mTxnAccount->setValueFieldH128(sfEmailHash, uHash); } } @@ -103,21 +103,21 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) // WalletLocator // - if (txn.getITFieldPresent(sfWalletLocator)) + if (txn.isFieldPresent(sfWalletLocator)) { - uint256 uHash = txn.getITFieldH256(sfWalletLocator); + uint256 uHash = txn.getValueFieldH256(sfWalletLocator); if (!uHash) { Log(lsINFO) << "doAccountSet: unset wallet locator"; - mTxnAccount->makeIFieldAbsent(sfEmailHash); + mTxnAccount->makeFieldAbsent(sfEmailHash); } else { Log(lsINFO) << "doAccountSet: set wallet locator"; - mTxnAccount->setIFieldH256(sfWalletLocator, uHash); + mTxnAccount->setValueFieldH256(sfWalletLocator, uHash); } } @@ -125,7 +125,7 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) // MessageKey // - if (!txn.getITFieldPresent(sfMessageKey)) + if (!txn.isFieldPresent(sfMessageKey)) { nothing(); } @@ -133,28 +133,28 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { Log(lsINFO) << "doAccountSet: set message key"; - mTxnAccount->setIFieldVL(sfMessageKey, txn.getITFieldVL(sfMessageKey)); + mTxnAccount->setValueFieldVL(sfMessageKey, txn.getValueFieldVL(sfMessageKey)); } // // Domain // - if (txn.getITFieldPresent(sfDomain)) + if (txn.isFieldPresent(sfDomain)) { - std::vector vucDomain = txn.getITFieldVL(sfDomain); + std::vector vucDomain = txn.getValueFieldVL(sfDomain); if (vucDomain.empty()) { Log(lsINFO) << "doAccountSet: unset domain"; - mTxnAccount->makeIFieldAbsent(sfDomain); + mTxnAccount->makeFieldAbsent(sfDomain); } else { Log(lsINFO) << "doAccountSet: set domain"; - mTxnAccount->setIFieldVL(sfDomain, vucDomain); + mTxnAccount->setValueFieldVL(sfDomain, vucDomain); } } @@ -162,21 +162,21 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) // TransferRate // - if (txn.getITFieldPresent(sfTransferRate)) + if (txn.isFieldPresent(sfTransferRate)) { - uint32 uRate = txn.getITFieldU32(sfTransferRate); + uint32 uRate = txn.getValueFieldU32(sfTransferRate); if (!uRate || uRate == QUALITY_ONE) { Log(lsINFO) << "doAccountSet: unset transfer rate"; - mTxnAccount->makeIFieldAbsent(sfTransferRate); + mTxnAccount->makeFieldAbsent(sfTransferRate); } else if (uRate > QUALITY_ONE) { Log(lsINFO) << "doAccountSet: set transfer rate"; - mTxnAccount->setIFieldU32(sfTransferRate, uRate); + mTxnAccount->setValueFieldU32(sfTransferRate, uRate); } else { @@ -190,8 +190,8 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) // PublishHash && PublishSize // - bool bPublishHash = txn.getITFieldPresent(sfPublishHash); - bool bPublishSize = txn.getITFieldPresent(sfPublishSize); + bool bPublishHash = txn.isFieldPresent(sfPublishHash); + bool bPublishSize = txn.isFieldPresent(sfPublishSize); if (bPublishHash ^ bPublishSize) { @@ -201,22 +201,22 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) } else if (bPublishHash && bPublishSize) { - uint256 uHash = txn.getITFieldH256(sfPublishHash); - uint32 uSize = txn.getITFieldU32(sfPublishSize); + uint256 uHash = txn.getValueFieldH256(sfPublishHash); + uint32 uSize = txn.getValueFieldU32(sfPublishSize); if (!uHash) { Log(lsINFO) << "doAccountSet: unset publish"; - mTxnAccount->makeIFieldAbsent(sfPublishHash); - mTxnAccount->makeIFieldAbsent(sfPublishSize); + mTxnAccount->makeFieldAbsent(sfPublishHash); + mTxnAccount->makeFieldAbsent(sfPublishSize); } else { Log(lsINFO) << "doAccountSet: set publish"; - mTxnAccount->setIFieldH256(sfPublishHash, uHash); - mTxnAccount->setIFieldU32(sfPublishSize, uSize); + mTxnAccount->setValueFieldH256(sfPublishHash, uHash); + mTxnAccount->setValueFieldU32(sfPublishSize, uSize); } } @@ -241,11 +241,11 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) TER terResult = tesSUCCESS; Log(lsINFO) << "doCreditSet>"; - const STAmount saLimitAmount = txn.getITFieldAmount(sfLimitAmount); - const bool bQualityIn = txn.getITFieldPresent(sfQualityIn); - const uint32 uQualityIn = bQualityIn ? txn.getITFieldU32(sfQualityIn) : 0; - const bool bQualityOut = txn.getITFieldPresent(sfQualityOut); - const uint32 uQualityOut = bQualityIn ? txn.getITFieldU32(sfQualityOut) : 0; + const STAmount saLimitAmount = txn.getValueFieldAmount(sfLimitAmount); + const bool bQualityIn = txn.isFieldPresent(sfQualityIn); + const uint32 uQualityIn = bQualityIn ? txn.getValueFieldU32(sfQualityIn) : 0; + const bool bQualityOut = txn.isFieldPresent(sfQualityOut); + const uint32 uQualityOut = bQualityIn ? txn.getValueFieldU32(sfQualityOut) : 0; const uint160 uCurrencyID = saLimitAmount.getCurrency(); uint160 uDstAccountID = saLimitAmount.getIssuer(); const bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest. @@ -285,12 +285,12 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) if (!saLimitAmount) { // Zeroing line. - uint160 uLowID = sleRippleState->getIValueFieldAmount(sfLowLimit).getIssuer(); - uint160 uHighID = sleRippleState->getIValueFieldAmount(sfHighLimit).getIssuer(); + uint160 uLowID = sleRippleState->getValueFieldAmount(sfLowLimit).getIssuer(); + uint160 uHighID = sleRippleState->getValueFieldAmount(sfHighLimit).getIssuer(); bool bLow = uLowID == uSrcAccountID; bool bHigh = uLowID == uDstAccountID; - bool bBalanceZero = !sleRippleState->getIValueFieldAmount(sfBalance); - STAmount saDstLimit = sleRippleState->getIValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit); + bool bBalanceZero = !sleRippleState->getValueFieldAmount(sfBalance); + STAmount saDstLimit = sleRippleState->getValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit); bool bDstLimitZero = !saDstLimit; assert(bLow || bHigh); @@ -307,7 +307,7 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) if (!bDelIndex) { - sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit: sfLowLimit, saLimitAllow); + sleRippleState->setValueFieldAmount(bFlipped ? sfHighLimit: sfLowLimit, saLimitAllow); if (!bQualityIn) { @@ -315,11 +315,11 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) } else if (uQualityIn) { - sleRippleState->setIFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn); + sleRippleState->setValueFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn); } else { - sleRippleState->makeIFieldAbsent(bFlipped ? sfLowQualityIn : sfHighQualityIn); + sleRippleState->makeFieldAbsent(bFlipped ? sfLowQualityIn : sfHighQualityIn); } if (!bQualityOut) @@ -328,11 +328,11 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) } else if (uQualityOut) { - sleRippleState->setIFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut); + sleRippleState->setValueFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut); } else { - sleRippleState->makeIFieldAbsent(bFlipped ? sfLowQualityOut : sfHighQualityOut); + sleRippleState->makeFieldAbsent(bFlipped ? sfLowQualityOut : sfHighQualityOut); } entryModify(sleRippleState); @@ -354,14 +354,14 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString(); - sleRippleState->setIFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency. - sleRippleState->setIFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAllow); - sleRippleState->setIFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uDstAccountID)); + sleRippleState->setValueFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency. + sleRippleState->setValueFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAllow); + sleRippleState->setValueFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uDstAccountID)); if (uQualityIn) - sleRippleState->setIFieldU32(bFlipped ? sfHighQualityIn : sfLowQualityIn, uQualityIn); + sleRippleState->setValueFieldU32(bFlipped ? sfHighQualityIn : sfLowQualityIn, uQualityIn); if (uQualityOut) - sleRippleState->setIFieldU32(bFlipped ? sfHighQualityOut : sfLowQualityOut, uQualityOut); + sleRippleState->setValueFieldU32(bFlipped ? sfHighQualityOut : sfLowQualityOut, uQualityOut); uint64 uSrcRef; // Ignored, dirs never delete. @@ -380,24 +380,24 @@ TER TransactionEngine::doNicknameSet(const SerializedTransaction& txn) { std::cerr << "doNicknameSet>" << std::endl; - const uint256 uNickname = txn.getITFieldH256(sfNickname); - const bool bMinOffer = txn.getITFieldPresent(sfMinimumOffer); - const STAmount saMinOffer = bMinOffer ? txn.getITFieldAmount(sfAmount) : STAmount(); + const uint256 uNickname = txn.getValueFieldH256(sfNickname); + const bool bMinOffer = txn.isFieldPresent(sfMinimumOffer); + const STAmount saMinOffer = bMinOffer ? txn.getValueFieldAmount(sfAmount) : STAmount(); SLE::pointer sleNickname = entryCache(ltNICKNAME, uNickname); if (sleNickname) { // Edit old entry. - sleNickname->setIFieldAccount(sfAccount, mTxnAccountID); + sleNickname->setValueFieldAccount(sfAccount, mTxnAccountID); if (bMinOffer && saMinOffer) { - sleNickname->setIFieldAmount(sfMinimumOffer, saMinOffer); + sleNickname->setValueFieldAmount(sfMinimumOffer, saMinOffer); } else { - sleNickname->makeIFieldAbsent(sfMinimumOffer); + sleNickname->makeFieldAbsent(sfMinimumOffer); } entryModify(sleNickname); @@ -411,10 +411,10 @@ TER TransactionEngine::doNicknameSet(const SerializedTransaction& txn) std::cerr << "doNicknameSet: Creating nickname node: " << sleNickname->getIndex().ToString() << std::endl; - sleNickname->setIFieldAccount(sfAccount, mTxnAccountID); + sleNickname->setValueFieldAccount(sfAccount, mTxnAccountID); if (bMinOffer && saMinOffer) - sleNickname->setIFieldAmount(sfMinimumOffer, saMinOffer); + sleNickname->setValueFieldAmount(sfMinimumOffer, saMinOffer); } std::cerr << "doNicknameSet<" << std::endl; @@ -426,7 +426,7 @@ TER TransactionEngine::doPasswordFund(const SerializedTransaction& txn) { std::cerr << "doPasswordFund>" << std::endl; - const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); + const uint160 uDstAccountID = txn.getValueFieldAccount160(sfDestination); SLE::pointer sleDst = mTxnAccountID == uDstAccountID ? mTxnAccount : entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); @@ -486,11 +486,11 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac const bool bPartialPayment = isSetBit(uTxFlags, tfPartialPayment); const bool bLimitQuality = isSetBit(uTxFlags, tfLimitQuality); const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect); - const bool bPaths = txn.getITFieldPresent(sfPaths); - const bool bMax = txn.getITFieldPresent(sfSendMax); - const uint160 uDstAccountID = txn.getITFieldAccount(sfDestination); - const STAmount saDstAmount = txn.getITFieldAmount(sfAmount); - const STAmount saMaxAmount = bMax ? txn.getITFieldAmount(sfSendMax) : saDstAmount; + const bool bPaths = txn.isFieldPresent(sfPaths); + const bool bMax = txn.isFieldPresent(sfSendMax); + const uint160 uDstAccountID = txn.getValueFieldAccount160(sfDestination); + const STAmount saDstAmount = txn.getValueFieldAmount(sfAmount); + const STAmount saMaxAmount = bMax ? txn.getValueFieldAmount(sfSendMax) : saDstAmount; const uint160 uSrcCurrency = saMaxAmount.getCurrency(); const uint160 uDstCurrency = saDstAmount.getCurrency(); @@ -550,8 +550,8 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac // Create the account. sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - sleDst->setIFieldAccount(sfAccount, uDstAccountID); - sleDst->setIFieldU32(sfSequence, 1); + sleDst->setValueFieldAccount(sfAccount, uDstAccountID); + sleDst->setValueFieldU32(sfSequence, 1); } else { @@ -566,7 +566,7 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac { // Ripple payment - STPathSet spsPaths = txn.getITFieldPathSet(sfPaths); + STPathSet spsPaths = txn.getValueFieldPathSet(sfPaths); STAmount saMaxAmountAct; STAmount saDstAmountAct; @@ -589,7 +589,7 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac { // Direct XNS payment. - STAmount saSrcXNSBalance = mTxnAccount->getIValueFieldAmount(sfBalance); + STAmount saSrcXNSBalance = mTxnAccount->getValueFieldAmount(sfBalance); if (saSrcXNSBalance < saDstAmount) { @@ -600,8 +600,8 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac } else { - mTxnAccount->setIFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); - sleDst->setIFieldAmount(sfBalance, sleDst->getIValueFieldAmount(sfBalance) + saDstAmount); + mTxnAccount->setValueFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); + sleDst->setValueFieldAmount(sfBalance, sleDst->getValueFieldAmount(sfBalance) + saDstAmount); terResult = tesSUCCESS; } @@ -626,9 +626,9 @@ TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn) { std::cerr << "WalletAdd>" << std::endl; - const std::vector vucPubKey = txn.getITFieldVL(sfPublicKey); - const std::vector vucSignature = txn.getITFieldVL(sfSignature); - const uint160 uAuthKeyID = txn.getITFieldAccount(sfAuthorizedKey); + const std::vector vucPubKey = txn.getValueFieldVL(sfPublicKey); + const std::vector vucSignature = txn.getValueFieldVL(sfSignature); + const uint160 uAuthKeyID = txn.getValueFieldAccount160(sfAuthorizedKey); const NewcoinAddress naMasterPubKey = NewcoinAddress::createAccountPublic(vucPubKey); const uint160 uDstAccountID = naMasterPubKey.getAccountID(); @@ -648,8 +648,8 @@ TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn) return tefCREATED; } - STAmount saAmount = txn.getITFieldAmount(sfAmount); - STAmount saSrcBalance = mTxnAccount->getIValueFieldAmount(sfBalance); + STAmount saAmount = txn.getValueFieldAmount(sfAmount); + STAmount saSrcBalance = mTxnAccount->getValueFieldAmount(sfBalance); if (saSrcBalance < saAmount) { @@ -663,15 +663,15 @@ TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn) } // Deduct initial balance from source account. - mTxnAccount->setIFieldAmount(sfBalance, saSrcBalance-saAmount); + mTxnAccount->setValueFieldAmount(sfBalance, saSrcBalance-saAmount); // Create the account. sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - sleDst->setIFieldAccount(sfAccount, uDstAccountID); - sleDst->setIFieldU32(sfSequence, 1); - sleDst->setIFieldAmount(sfBalance, saAmount); - sleDst->setIFieldAccount(sfAuthorizedKey, uAuthKeyID); + sleDst->setValueFieldAccount(sfAccount, uDstAccountID); + sleDst->setValueFieldU32(sfSequence, 1); + sleDst->setValueFieldAmount(sfBalance, saAmount); + sleDst->setValueFieldAccount(sfAuthorizedKey, uAuthKeyID); std::cerr << "WalletAdd<" << std::endl; @@ -770,11 +770,11 @@ TER TransactionEngine::takeOffers( Log(lsINFO) << "takeOffers: considering offer : " << sleOffer->getJson(0); - const uint160 uOfferOwnerID = sleOffer->getIValueFieldAccount(sfAccount).getAccountID(); - STAmount saOfferPays = sleOffer->getIValueFieldAmount(sfTakerGets); - STAmount saOfferGets = sleOffer->getIValueFieldAmount(sfTakerPays); + const uint160 uOfferOwnerID = sleOffer->getValueFieldAccount(sfAccount).getAccountID(); + STAmount saOfferPays = sleOffer->getValueFieldAmount(sfTakerGets); + STAmount saOfferGets = sleOffer->getValueFieldAmount(sfTakerPays); - if (sleOffer->getIFieldPresent(sfExpiration) && sleOffer->getIFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getValueFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) { // Offer is expired. Expired offers are considered unfunded. Delete it. Log(lsINFO) << "takeOffers: encountered expired offer"; @@ -849,10 +849,10 @@ TER TransactionEngine::takeOffers( // Adjust offer // Offer owner will pay less. Subtract what taker just got. - sleOffer->setIFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot); + sleOffer->setValueFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot); // Offer owner will get less. Subtract what owner just paid. - sleOffer->setIFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid); + sleOffer->setValueFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid); entryModify(sleOffer); @@ -919,8 +919,8 @@ TER TransactionEngine::doOfferCreate(const SerializedTransaction& txn) Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); const uint32 txFlags = txn.getFlags(); const bool bPassive = isSetBit(txFlags, tfPassive); - STAmount saTakerPays = txn.getITFieldAmount(sfTakerPays); - STAmount saTakerGets = txn.getITFieldAmount(sfTakerGets); + STAmount saTakerPays = txn.getValueFieldAmount(sfTakerPays); + STAmount saTakerGets = txn.getValueFieldAmount(sfTakerGets); Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGets=%s") % saTakerPays.getFullText() @@ -928,8 +928,8 @@ Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGe const uint160 uPaysIssuerID = saTakerPays.getIssuer(); const uint160 uGetsIssuerID = saTakerGets.getIssuer(); - const uint32 uExpiration = txn.getITFieldU32(sfExpiration); - const bool bHaveExpiration = txn.getITFieldPresent(sfExpiration); + const uint32 uExpiration = txn.getValueFieldU32(sfExpiration); + const bool bHaveExpiration = txn.isFieldPresent(sfExpiration); const uint32 uSequence = txn.getSequence(); const uint256 uLedgerIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); @@ -1090,16 +1090,16 @@ Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGe Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency(); Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency(); - sleOffer->setIFieldAccount(sfAccount, mTxnAccountID); - sleOffer->setIFieldU32(sfSequence, uSequence); - sleOffer->setIFieldH256(sfBookDirectory, uDirectory); - sleOffer->setIFieldAmount(sfTakerPays, saTakerPays); - sleOffer->setIFieldAmount(sfTakerGets, saTakerGets); - sleOffer->setIFieldU64(sfOwnerNode, uOwnerNode); - sleOffer->setIFieldU64(sfBookNode, uBookNode); + sleOffer->setValueFieldAccount(sfAccount, mTxnAccountID); + sleOffer->setValueFieldU32(sfSequence, uSequence); + sleOffer->setValueFieldH256(sfBookDirectory, uDirectory); + sleOffer->setValueFieldAmount(sfTakerPays, saTakerPays); + sleOffer->setValueFieldAmount(sfTakerGets, saTakerGets); + sleOffer->setValueFieldU64(sfOwnerNode, uOwnerNode); + sleOffer->setValueFieldU64(sfBookNode, uBookNode); if (uExpiration) - sleOffer->setIFieldU32(sfExpiration, uExpiration); + sleOffer->setValueFieldU32(sfExpiration, uExpiration); if (bPassive) sleOffer->setFlag(lsfPassive); @@ -1114,7 +1114,7 @@ Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGe TER TransactionEngine::doOfferCancel(const SerializedTransaction& txn) { TER terResult; - const uint32 uSequence = txn.getITFieldU32(sfOfferSequence); + const uint32 uSequence = txn.getValueFieldU32(sfOfferSequence); const uint256 uOfferIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); @@ -1141,14 +1141,14 @@ TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) { Log(lsWARNING) << "doContractAdd> " << txn.getJson(0); - const uint32 expiration = txn.getITFieldU32(sfExpiration); -// const uint32 bondAmount = txn.getITFieldU32(sfBondAmount); -// const uint32 stampEscrow = txn.getITFieldU32(sfStampEscrow); - STAmount rippleEscrow = txn.getITFieldAmount(sfRippleEscrow); - std::vector createCode = txn.getITFieldVL(sfCreateCode); - std::vector fundCode = txn.getITFieldVL(sfFundCode); - std::vector removeCode = txn.getITFieldVL(sfRemoveCode); - std::vector expireCode = txn.getITFieldVL(sfExpireCode); + const uint32 expiration = txn.getValueFieldU32(sfExpiration); +// const uint32 bondAmount = txn.getValueFieldU32(sfBondAmount); +// const uint32 stampEscrow = txn.getValueFieldU32(sfStampEscrow); + STAmount rippleEscrow = txn.getValueFieldAmount(sfRippleEscrow); + std::vector createCode = txn.getValueFieldVL(sfCreateCode); + std::vector fundCode = txn.getValueFieldVL(sfFundCode); + std::vector removeCode = txn.getValueFieldVL(sfRemoveCode); + std::vector expireCode = txn.getValueFieldVL(sfExpireCode); // make sure // expiration hasn't passed diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 8847ca87e1..6452ca0775 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -136,7 +136,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa case ttNICKNAME_SET: { - SLE::pointer sleNickname = entryCache(ltNICKNAME, txn.getITFieldH256(sfNickname)); + SLE::pointer sleNickname = entryCache(ltNICKNAME, txn.getValueFieldH256(sfNickname)); if (!sleNickname) saCost = theConfig.FEE_NICKNAME_CREATE; @@ -222,8 +222,8 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa } else { - saSrcBalance = mTxnAccount->getIValueFieldAmount(sfBalance); - bHaveAuthKey = mTxnAccount->getIFieldPresent(sfAuthorizedKey); + saSrcBalance = mTxnAccount->getValueFieldAmount(sfBalance); + bHaveAuthKey = mTxnAccount->isFieldPresent(sfAuthorizedKey); } // Check if account claimed. @@ -279,7 +279,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa default: // Verify the transaction's signing public key is the key authorized for signing. - if (bHaveAuthKey && naSigningPubKey.getAccountID() == mTxnAccount->getIValueFieldAccount(sfAuthorizedKey).getAccountID()) + if (bHaveAuthKey && naSigningPubKey.getAccountID() == mTxnAccount->getValueFieldAccount(sfAuthorizedKey).getAccountID()) { // Authorized to continue. nothing(); @@ -322,7 +322,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa } else { - mTxnAccount->setIFieldAmount(sfBalance, saSrcBalance - saPaid); + mTxnAccount->setValueFieldAmount(sfBalance, saSrcBalance - saPaid); } // Validate sequence @@ -332,7 +332,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa } else if (saCost) { - uint32 a_seq = mTxnAccount->getIFieldU32(sfSequence); + uint32 a_seq = mTxnAccount->getValueFieldU32(sfSequence); Log(lsTRACE) << "Aseq=" << a_seq << ", Tseq=" << t_seq; @@ -359,7 +359,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa } else { - mTxnAccount->setIFieldU32(sfSequence, t_seq + 1); + mTxnAccount->setValueFieldU32(sfSequence, t_seq + 1); } } else From e04b69543409bc19a579c96be235ca1e83ac1cbd Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 1 Oct 2012 15:35:30 -0700 Subject: [PATCH 406/426] Burninate "Value" in "*ValueField*" functions. It was just pointless extra typing. What else would you set/get in a field, by name, other than its value? --- src/AccountState.cpp | 4 +- src/AccountState.h | 6 +- src/Ledger.cpp | 4 +- src/LedgerEntrySet.cpp | 100 ++++++++++---------- src/NetworkOPs.cpp | 14 +-- src/NicknameState.cpp | 4 +- src/OrderBook.cpp | 4 +- src/RPCServer.cpp | 4 +- src/RippleCalc.cpp | 28 +++--- src/RippleLines.cpp | 4 +- src/RippleState.cpp | 14 +-- src/SerializedLedger.cpp | 24 ++--- src/SerializedLedger.h | 2 +- src/SerializedObject.cpp | 60 ++++++------ src/SerializedObject.h | 58 ++++++------ src/SerializedTransaction.cpp | 14 +-- src/SerializedTransaction.h | 14 +-- src/SerializedValidation.cpp | 16 ++-- src/Transaction.cpp | 74 +++++++-------- src/Transaction.h | 4 +- src/TransactionAction.cpp | 172 +++++++++++++++++----------------- src/TransactionEngine.cpp | 12 +-- 22 files changed, 318 insertions(+), 318 deletions(-) diff --git a/src/AccountState.cpp b/src/AccountState.cpp index 42acd03d42..9aee8f8694 100644 --- a/src/AccountState.cpp +++ b/src/AccountState.cpp @@ -17,7 +17,7 @@ AccountState::AccountState(const NewcoinAddress& naAccountID) : mAccountID(naAcc mLedgerEntry = boost::make_shared(ltACCOUNT_ROOT); mLedgerEntry->setIndex(Ledger::getAccountRootIndex(naAccountID)); - mLedgerEntry->setValueFieldAccount(sfAccount, naAccountID.getAccountID()); + mLedgerEntry->setFieldAccount(sfAccount, naAccountID.getAccountID()); mValid = true; } @@ -49,7 +49,7 @@ void AccountState::addJson(Json::Value& val) if (mValid) { if (mLedgerEntry->isFieldPresent(sfEmailHash)) - val["UrlGravatar"] = createGravatarUrl(mLedgerEntry->getValueFieldH128(sfEmailHash)); + val["UrlGravatar"] = createGravatarUrl(mLedgerEntry->getFieldH128(sfEmailHash)); } else { diff --git a/src/AccountState.h b/src/AccountState.h index b0d68205bb..728d5ae96a 100644 --- a/src/AccountState.h +++ b/src/AccountState.h @@ -38,11 +38,11 @@ public: NewcoinAddress getAuthorizedKey() { - return mLedgerEntry->getValueFieldAccount(sfAuthorizedKey); + return mLedgerEntry->getFieldAccount(sfAuthorizedKey); } - STAmount getBalance() const { return mLedgerEntry->getValueFieldAmount(sfBalance); } - uint32 getSeq() const { return mLedgerEntry->getValueFieldU32(sfSequence); } + STAmount getBalance() const { return mLedgerEntry->getFieldAmount(sfBalance); } + uint32 getSeq() const { return mLedgerEntry->getFieldU32(sfSequence); } SerializedLedgerEntry::pointer getSLE() { return mLedgerEntry; } const SerializedLedgerEntry& peekSLE() const { return *mLedgerEntry; } diff --git a/src/Ledger.cpp b/src/Ledger.cpp index f9c4bf343f..2f3c8cfdf1 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -27,8 +27,8 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(s { // special case: put coins in root account AccountState::pointer startAccount = boost::make_shared(masterID); - startAccount->peekSLE().setValueFieldAmount(sfBalance, startAmount); - startAccount->peekSLE().setValueFieldU32(sfSequence, 1); + startAccount->peekSLE().setFieldAmount(sfBalance, startAmount); + startAccount->peekSLE().setFieldU32(sfSequence, 1); writeBack(lepCREATE, startAccount->getSLE()); #if 0 std::cerr << "Root account:"; diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 5147ed6286..22f0798422 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -385,26 +385,26 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) if (origNode->isFieldPresent(sfAmount)) { // node has an amount, covers ripple state nodes - STAmount amount = origNode->getValueFieldAmount(sfAmount); + STAmount amount = origNode->getFieldAmount(sfAmount); if (amount.isNonZero()) metaNode.addAmount(TMSPrevBalance, amount); - amount = curNode->getValueFieldAmount(sfAmount); + amount = curNode->getFieldAmount(sfAmount); if (amount.isNonZero()) metaNode.addAmount(TMSFinalBalance, amount); if (origNode->getType() == ltRIPPLE_STATE) { - metaNode.addAccount(TMSLowID, NewcoinAddress::createAccountID(origNode->getValueFieldAmount(sfLowLimit).getIssuer())); - metaNode.addAccount(TMSHighID, NewcoinAddress::createAccountID(origNode->getValueFieldAmount(sfHighLimit).getIssuer())); + metaNode.addAccount(TMSLowID, NewcoinAddress::createAccountID(origNode->getFieldAmount(sfLowLimit).getIssuer())); + metaNode.addAccount(TMSHighID, NewcoinAddress::createAccountID(origNode->getFieldAmount(sfHighLimit).getIssuer())); } } if (origNode->getType() == ltOFFER) { // check for non-zero balances - STAmount amount = origNode->getValueFieldAmount(sfTakerPays); + STAmount amount = origNode->getFieldAmount(sfTakerPays); if (amount.isNonZero()) metaNode.addAmount(TMSFinalTakerPays, amount); - amount = origNode->getValueFieldAmount(sfTakerGets); + amount = origNode->getFieldAmount(sfTakerGets); if (amount.isNonZero()) metaNode.addAmount(TMSFinalTakerGets, amount); } @@ -431,18 +431,18 @@ void LedgerEntrySet::calcRawMeta(Serializer& s) assert(origNode); if (origNode->isFieldPresent(sfAmount)) { // node has an amount, covers account root nodes and ripple nodes - STAmount amount = origNode->getValueFieldAmount(sfAmount); - if (amount != curNode->getValueFieldAmount(sfAmount)) + STAmount amount = origNode->getFieldAmount(sfAmount); + if (amount != curNode->getFieldAmount(sfAmount)) metaNode.addAmount(TMSPrevBalance, amount); } if (origNode->getType() == ltOFFER) { - STAmount amount = origNode->getValueFieldAmount(sfTakerPays); - if (amount != curNode->getValueFieldAmount(sfTakerPays)) + STAmount amount = origNode->getFieldAmount(sfTakerPays); + if (amount != curNode->getFieldAmount(sfTakerPays)) metaNode.addAmount(TMSPrevTakerPays, amount); - amount = origNode->getValueFieldAmount(sfTakerGets); - if (amount != curNode->getValueFieldAmount(sfTakerGets)) + amount = origNode->getFieldAmount(sfTakerGets); + if (amount != curNode->getFieldAmount(sfTakerGets)) metaNode.addAmount(TMSPrevTakerGets, amount); } @@ -485,7 +485,7 @@ TER LedgerEntrySet::dirAdd( } else { - uNodeDir = sleRoot->getValueFieldU64(sfIndexPrevious); // Get index to last directory node. + uNodeDir = sleRoot->getFieldU64(sfIndexPrevious); // Get index to last directory node. if (uNodeDir) { @@ -500,7 +500,7 @@ TER LedgerEntrySet::dirAdd( sleNode = sleRoot; } - svIndexes = sleNode->getValueFieldV256(sfIndexes); + svIndexes = sleNode->getFieldV256(sfIndexes); if (DIR_NODE_MAX != svIndexes.peekValue().size()) { @@ -519,7 +519,7 @@ TER LedgerEntrySet::dirAdd( { // Previous node is root node. - sleRoot->setValueFieldU64(sfIndexNext, uNodeDir); + sleRoot->setFieldU64(sfIndexNext, uNodeDir); } else { @@ -527,14 +527,14 @@ TER LedgerEntrySet::dirAdd( SLE::pointer slePrevious = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeDir-1)); - slePrevious->setValueFieldU64(sfIndexNext, uNodeDir); + slePrevious->setFieldU64(sfIndexNext, uNodeDir); entryModify(slePrevious); - sleNode->setValueFieldU64(sfIndexPrevious, uNodeDir-1); + sleNode->setFieldU64(sfIndexPrevious, uNodeDir-1); } // Have root point to new node. - sleRoot->setValueFieldU64(sfIndexPrevious, uNodeDir); + sleRoot->setFieldU64(sfIndexPrevious, uNodeDir); entryModify(sleRoot); // Create the new node. @@ -544,7 +544,7 @@ TER LedgerEntrySet::dirAdd( } svIndexes.peekValue().push_back(uLedgerIndex); // Append entry. - sleNode->setValueFieldV256(sfIndexes, svIndexes); // Save entry. + sleNode->setFieldV256(sfIndexes, svIndexes); // Save entry. Log(lsINFO) << "dirAdd: creating: root: " << uRootIndex.ToString(); Log(lsINFO) << "dirAdd: appending: Entry: " << uLedgerIndex.ToString(); @@ -574,7 +574,7 @@ TER LedgerEntrySet::dirDelete( return tefBAD_LEDGER; } - STVector256 svIndexes = sleNode->getValueFieldV256(sfIndexes); + STVector256 svIndexes = sleNode->getFieldV256(sfIndexes); std::vector& vuiIndexes = svIndexes.peekValue(); std::vector::iterator it; @@ -608,14 +608,14 @@ TER LedgerEntrySet::dirDelete( vuiIndexes.clear(); } - sleNode->setValueFieldV256(sfIndexes, svIndexes); + sleNode->setFieldV256(sfIndexes, svIndexes); entryModify(sleNode); if (vuiIndexes.empty()) { // May be able to delete nodes. - uint64 uNodePrevious = sleNode->getValueFieldU64(sfIndexPrevious); - uint64 uNodeNext = sleNode->getValueFieldU64(sfIndexNext); + uint64 uNodePrevious = sleNode->getFieldU64(sfIndexPrevious); + uint64 uNodeNext = sleNode->getFieldU64(sfIndexNext); if (!uNodeCur) { @@ -646,7 +646,7 @@ TER LedgerEntrySet::dirDelete( assert(sleLast); - if (sleLast->getValueFieldV256(sfIndexes).peekValue().empty()) + if (sleLast->getFieldV256(sfIndexes).peekValue().empty()) { // Both nodes are empty. @@ -690,11 +690,11 @@ TER LedgerEntrySet::dirDelete( } // Fix previous to point to its new next. - slePrevious->setValueFieldU64(sfIndexNext, uNodeNext); + slePrevious->setFieldU64(sfIndexNext, uNodeNext); entryModify(slePrevious); // Fix next to point to its new previous. - sleNext->setValueFieldU64(sfIndexPrevious, uNodePrevious); + sleNext->setFieldU64(sfIndexPrevious, uNodePrevious); entryModify(sleNext); } // Last node. @@ -712,7 +712,7 @@ TER LedgerEntrySet::dirDelete( assert(sleRoot); - if (sleRoot->getValueFieldV256(sfIndexes).peekValue().empty()) + if (sleRoot->getFieldV256(sfIndexes).peekValue().empty()) { // Both nodes are empty. @@ -755,12 +755,12 @@ bool LedgerEntrySet::dirNext( unsigned int& uDirEntry, // <-> next entry uint256& uEntryIndex) // <-- The entry, if available. Otherwise, zero. { - STVector256 svIndexes = sleNode->getValueFieldV256(sfIndexes); + STVector256 svIndexes = sleNode->getFieldV256(sfIndexes); std::vector& vuiIndexes = svIndexes.peekValue(); if (uDirEntry == vuiIndexes.size()) { - uint64 uNodeNext = sleNode->getValueFieldU64(sfIndexNext); + uint64 uNodeNext = sleNode->getFieldU64(sfIndexNext); if (!uNodeNext) { @@ -785,13 +785,13 @@ Log(lsINFO) << boost::str(boost::format("dirNext: uDirEntry=%d uEntryIndex=%s") TER LedgerEntrySet::offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID) { - uint64 uOwnerNode = sleOffer->getValueFieldU64(sfOwnerNode); + uint64 uOwnerNode = sleOffer->getFieldU64(sfOwnerNode); TER terResult = dirDelete(false, uOwnerNode, Ledger::getOwnerDirIndex(uOwnerID), uOfferIndex, false); if (tesSUCCESS == terResult) { - uint256 uDirectory = sleOffer->getValueFieldH256(sfBookDirectory); - uint64 uBookNode = sleOffer->getValueFieldU64(sfBookNode); + uint256 uDirectory = sleOffer->getFieldH256(sfBookDirectory); + uint64 uBookNode = sleOffer->getFieldU64(sfBookNode); terResult = dirDelete(false, uBookNode, uDirectory, uOfferIndex, true); } @@ -804,7 +804,7 @@ TER LedgerEntrySet::offerDelete(const SLE::pointer& sleOffer, const uint256& uOf TER LedgerEntrySet::offerDelete(const uint256& uOfferIndex) { SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - const uint160 uOwnerID = sleOffer->getValueFieldAccount(sfAccount).getAccountID(); + const uint160 uOwnerID = sleOffer->getFieldAccount(sfAccount).getAccountID(); return offerDelete(sleOffer, uOfferIndex, uOwnerID); } @@ -818,7 +818,7 @@ STAmount LedgerEntrySet::rippleOwed(const uint160& uToAccountID, const uint160& if (sleRippleState) { - saBalance = sleRippleState->getValueFieldAmount(sfBalance); + saBalance = sleRippleState->getFieldAmount(sfBalance); if (uToAccountID < uFromAccountID) saBalance.negate(); saBalance.setIssuer(uToAccountID); @@ -849,7 +849,7 @@ STAmount LedgerEntrySet::rippleLimit(const uint160& uToAccountID, const uint160& assert(sleRippleState); if (sleRippleState) { - saLimit = sleRippleState->getValueFieldAmount(uToAccountID < uFromAccountID ? sfLowLimit : sfHighLimit); + saLimit = sleRippleState->getFieldAmount(uToAccountID < uFromAccountID ? sfLowLimit : sfHighLimit); saLimit.setIssuer(uToAccountID); } @@ -862,7 +862,7 @@ uint32 LedgerEntrySet::rippleTransferRate(const uint160& uIssuerID) SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uIssuerID)); uint32 uQuality = sleAccount && sleAccount->isFieldPresent(sfTransferRate) - ? sleAccount->getValueFieldU32(sfTransferRate) + ? sleAccount->getFieldU32(sfTransferRate) : QUALITY_ONE; Log(lsINFO) << boost::str(boost::format("rippleTransferRate: uIssuerID=%s account_exists=%d transfer_rate=%f") @@ -894,7 +894,7 @@ uint32 LedgerEntrySet::rippleQualityIn(const uint160& uToAccountID, const uint16 SField::ref sfField = uToAccountID < uFromAccountID ? sfLow: sfHigh; uQuality = sleRippleState->isFieldPresent(sfField) - ? sleRippleState->getValueFieldU32(sfField) + ? sleRippleState->getFieldU32(sfField) : QUALITY_ONE; if (!uQuality) @@ -924,7 +924,7 @@ STAmount LedgerEntrySet::rippleHolds(const uint160& uAccountID, const uint160& u if (sleRippleState) { - saBalance = sleRippleState->getValueFieldAmount(sfBalance); + saBalance = sleRippleState->getFieldAmount(sfBalance); if (uAccountID > uIssuerID) saBalance.negate(); // Put balance in uAccountID terms. @@ -942,7 +942,7 @@ STAmount LedgerEntrySet::accountHolds(const uint160& uAccountID, const uint160& { SLE::pointer sleAccount = entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uAccountID)); - saAmount = sleAccount->getValueFieldAmount(sfBalance); + saAmount = sleAccount->getFieldAmount(sfBalance); } else { @@ -1031,13 +1031,13 @@ void LedgerEntrySet::rippleCredit(const uint160& uSenderID, const uint160& uRece if (!bFlipped) saBalance.negate(); - sleRippleState->setValueFieldAmount(sfBalance, saBalance); - sleRippleState->setValueFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, STAmount(uCurrencyID, uSenderID)); - sleRippleState->setValueFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uReceiverID)); + sleRippleState->setFieldAmount(sfBalance, saBalance); + sleRippleState->setFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, STAmount(uCurrencyID, uSenderID)); + sleRippleState->setFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uReceiverID)); } else { - STAmount saBalance = sleRippleState->getValueFieldAmount(sfBalance); + STAmount saBalance = sleRippleState->getFieldAmount(sfBalance); if (!bFlipped) saBalance.negate(); // Put balance in low terms. @@ -1047,7 +1047,7 @@ void LedgerEntrySet::rippleCredit(const uint160& uSenderID, const uint160& uRece if (!bFlipped) saBalance.negate(); - sleRippleState->setValueFieldAmount(sfBalance, saBalance); + sleRippleState->setFieldAmount(sfBalance, saBalance); entryModify(sleRippleState); } @@ -1106,28 +1106,28 @@ void LedgerEntrySet::accountSend(const uint160& uSenderID, const uint160& uRecei Log(lsINFO) << boost::str(boost::format("accountSend> %s (%s) -> %s (%s) : %s") % NewcoinAddress::createHumanAccountID(uSenderID) - % (sleSender ? (sleSender->getValueFieldAmount(sfBalance)).getFullText() : "-") + % (sleSender ? (sleSender->getFieldAmount(sfBalance)).getFullText() : "-") % NewcoinAddress::createHumanAccountID(uReceiverID) - % (sleReceiver ? (sleReceiver->getValueFieldAmount(sfBalance)).getFullText() : "-") + % (sleReceiver ? (sleReceiver->getFieldAmount(sfBalance)).getFullText() : "-") % saAmount.getFullText()); if (sleSender) { - sleSender->setValueFieldAmount(sfBalance, sleSender->getValueFieldAmount(sfBalance) - saAmount); + sleSender->setFieldAmount(sfBalance, sleSender->getFieldAmount(sfBalance) - saAmount); entryModify(sleSender); } if (sleReceiver) { - sleReceiver->setValueFieldAmount(sfBalance, sleReceiver->getValueFieldAmount(sfBalance) + saAmount); + sleReceiver->setFieldAmount(sfBalance, sleReceiver->getFieldAmount(sfBalance) + saAmount); entryModify(sleReceiver); } Log(lsINFO) << boost::str(boost::format("accountSend< %s (%s) -> %s (%s) : %s") % NewcoinAddress::createHumanAccountID(uSenderID) - % (sleSender ? (sleSender->getValueFieldAmount(sfBalance)).getFullText() : "-") + % (sleSender ? (sleSender->getFieldAmount(sfBalance)).getFullText() : "-") % NewcoinAddress::createHumanAccountID(uReceiverID) - % (sleReceiver ? (sleReceiver->getValueFieldAmount(sfBalance)).getFullText() : "-") + % (sleReceiver ? (sleReceiver->getFieldAmount(sfBalance)).getFullText() : "-") % saAmount.getFullText()); } else diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index c645fd1fbb..ce77bf69d7 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -245,12 +245,12 @@ STVector256 NetworkOPs::getDirNodeInfo( { Log(lsDEBUG) << "getDirNodeInfo: node index: " << uNodeIndex.ToString(); - Log(lsTRACE) << "getDirNodeInfo: first: " << strHex(sleNode->getValueFieldU64(sfIndexPrevious)); - Log(lsTRACE) << "getDirNodeInfo: last: " << strHex(sleNode->getValueFieldU64(sfIndexNext)); + Log(lsTRACE) << "getDirNodeInfo: first: " << strHex(sleNode->getFieldU64(sfIndexPrevious)); + Log(lsTRACE) << "getDirNodeInfo: last: " << strHex(sleNode->getFieldU64(sfIndexNext)); - uNodePrevious = sleNode->getValueFieldU64(sfIndexPrevious); - uNodeNext = sleNode->getValueFieldU64(sfIndexNext); - svIndexes = sleNode->getValueFieldV256(sfIndexes); + uNodePrevious = sleNode->getFieldU64(sfIndexPrevious); + uNodeNext = sleNode->getFieldU64(sfIndexNext); + svIndexes = sleNode->getFieldV256(sfIndexes); Log(lsTRACE) << "getDirNodeInfo: first: " << strHex(uNodePrevious); Log(lsTRACE) << "getDirNodeInfo: last: " << strHex(uNodeNext); @@ -299,7 +299,7 @@ Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddr do { - STVector256 svIndexes = sleNode->getValueFieldV256(sfIndexes); + STVector256 svIndexes = sleNode->getFieldV256(sfIndexes); const std::vector& vuiIndexes = svIndexes.peekValue(); BOOST_FOREACH(const uint256& uDirEntry, vuiIndexes) @@ -332,7 +332,7 @@ Json::Value NetworkOPs::getOwnerInfo(Ledger::pointer lpLedger, const NewcoinAddr } } - uNodeDir = sleNode->getValueFieldU64(sfIndexNext); + uNodeDir = sleNode->getFieldU64(sfIndexNext); if (uNodeDir) { lspNode = lepNONE; diff --git a/src/NicknameState.cpp b/src/NicknameState.cpp index e1dcb39aa8..72fbaa662f 100644 --- a/src/NicknameState.cpp +++ b/src/NicknameState.cpp @@ -14,13 +14,13 @@ bool NicknameState::haveMinimumOffer() const STAmount NicknameState::getMinimumOffer() const { return mLedgerEntry->isFieldPresent(sfMinimumOffer) - ? mLedgerEntry->getValueFieldAmount(sfMinimumOffer) + ? mLedgerEntry->getFieldAmount(sfMinimumOffer) : STAmount(); } NewcoinAddress NicknameState::getAccountID() const { - return mLedgerEntry->getValueFieldAccount(sfAccount); + return mLedgerEntry->getFieldAccount(sfAccount); } void NicknameState::addJson(Json::Value& val) diff --git a/src/OrderBook.cpp b/src/OrderBook.cpp index 9c032b9670..2cf716257e 100644 --- a/src/OrderBook.cpp +++ b/src/OrderBook.cpp @@ -10,8 +10,8 @@ OrderBook::pointer OrderBook::newOrderBook(SerializedLedgerEntry::pointer ledger OrderBook::OrderBook(SerializedLedgerEntry::pointer ledgerEntry) { - const STAmount saTakerGets = ledgerEntry->getValueFieldAmount(sfTakerGets); - const STAmount saTakerPays = ledgerEntry->getValueFieldAmount(sfTakerPays); + const STAmount saTakerGets = ledgerEntry->getFieldAmount(sfTakerGets); + const STAmount saTakerPays = ledgerEntry->getFieldAmount(sfTakerPays); mCurrencyIn = saTakerGets.getCurrency(); mCurrencyOut = saTakerPays.getCurrency(); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index f1247f23c5..ef0feb4933 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -252,7 +252,7 @@ Json::Value RPCServer::getMasterGenerator(const uint256& uLedger, const NewcoinA return RPCError(rpcNO_ACCOUNT); } - std::vector vucCipher = sleGen->getValueFieldVL(sfGenerator); + std::vector vucCipher = sleGen->getFieldVL(sfGenerator); std::vector vucMasterGenerator = na0Private.accountPrivateDecrypt(na0Public, vucCipher); if (vucMasterGenerator.empty()) { @@ -402,7 +402,7 @@ Json::Value RPCServer::accountFromString(const uint256& uLedger, NewcoinAddress& else { // Found master public key. - std::vector vucCipher = sleGen->getValueFieldVL(sfGenerator); + std::vector vucCipher = sleGen->getFieldVL(sfGenerator); std::vector vucMasterGenerator = naRegular0Private.accountPrivateDecrypt(naRegular0Public, vucCipher); if (vucMasterGenerator.empty()) { diff --git a/src/RippleCalc.cpp b/src/RippleCalc.cpp index 1292964cb4..e768d8180a 100644 --- a/src/RippleCalc.cpp +++ b/src/RippleCalc.cpp @@ -116,8 +116,8 @@ TER RippleCalc::calcNodeAdvance( { if (bFundsDirty) { - saTakerPays = sleOffer->getValueFieldAmount(sfTakerPays); - saTakerGets = sleOffer->getValueFieldAmount(sfTakerGets); + saTakerPays = sleOffer->getFieldAmount(sfTakerPays); + saTakerGets = sleOffer->getFieldAmount(sfTakerGets); saOfferFunds = lesActive.accountFunds(uOfrOwnerID, saTakerGets); // Funds left. bFundsDirty = false; @@ -153,13 +153,13 @@ TER RippleCalc::calcNodeAdvance( { // Got a new offer. sleOffer = lesActive.entryCache(ltOFFER, uOfferIndex); - uOfrOwnerID = sleOffer->getValueFieldAccount(sfAccount).getAccountID(); + uOfrOwnerID = sleOffer->getFieldAccount(sfAccount).getAccountID(); const aciSource asLine = boost::make_tuple(uOfrOwnerID, uCurCurrencyID, uCurIssuerID); Log(lsINFO) << boost::str(boost::format("calcNodeAdvance: uOfrOwnerID=%s") % NewcoinAddress::createHumanAccountID(uOfrOwnerID)); - if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getValueFieldU32(sfExpiration) <= lesActive.getLedger()->getParentCloseTimeNC()) + if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getFieldU32(sfExpiration) <= lesActive.getLedger()->getParentCloseTimeNC()) { // Offer is expired. Log(lsINFO) << "calcNodeAdvance: expired offer"; @@ -207,8 +207,8 @@ TER RippleCalc::calcNodeAdvance( continue; } - saTakerPays = sleOffer->getValueFieldAmount(sfTakerPays); - saTakerGets = sleOffer->getValueFieldAmount(sfTakerGets); + saTakerPays = sleOffer->getFieldAmount(sfTakerPays); + saTakerGets = sleOffer->getFieldAmount(sfTakerGets); saOfferFunds = lesActive.accountFunds(uOfrOwnerID, saTakerGets); // Funds left. @@ -430,8 +430,8 @@ TER RippleCalc::calcNodeDeliverRev( lesActive.accountSend(uOfrOwnerID, uCurIssuerID, saOutPass); // Adjust offer - sleOffer->setValueFieldAmount(sfTakerGets, saTakerGets - saOutPass); - sleOffer->setValueFieldAmount(sfTakerPays, saTakerPays - saInPassAct); + sleOffer->setFieldAmount(sfTakerGets, saTakerGets - saOutPass); + sleOffer->setFieldAmount(sfTakerPays, saTakerPays - saInPassAct); lesActive.entryModify(sleOffer); @@ -580,8 +580,8 @@ TER RippleCalc::calcNodeDeliverFwd( lesActive.accountSend(uInAccountID, uOfrOwnerID, saInPassAct); // Adjust offer - sleOffer->setValueFieldAmount(sfTakerGets, saTakerGets - saOutPassAct); - sleOffer->setValueFieldAmount(sfTakerPays, saTakerPays - saInPassAct); + sleOffer->setFieldAmount(sfTakerGets, saTakerGets - saOutPassAct); + sleOffer->setFieldAmount(sfTakerPays, saTakerPays - saInPassAct); lesActive.entryModify(sleOffer); @@ -2092,11 +2092,11 @@ void TransactionEngine::calcOfferBridgeNext( SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); - uint160 uOfferOwnerID = sleOffer->getValueFieldAccount(sfAccount).getAccountID(); - STAmount saOfferPays = sleOffer->getValueFieldAmount(sfTakerGets); - STAmount saOfferGets = sleOffer->getValueFieldAmount(sfTakerPays); + uint160 uOfferOwnerID = sleOffer->getFieldAccount(sfAccount).getAccountID(); + STAmount saOfferPays = sleOffer->getFieldAmount(sfTakerGets); + STAmount saOfferGets = sleOffer->getFieldAmount(sfTakerPays); - if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getValueFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) { // Offer is expired. Log(lsINFO) << "calcOfferFirst: encountered expired offer"; diff --git a/src/RippleLines.cpp b/src/RippleLines.cpp index e66168f58e..bae60414b1 100644 --- a/src/RippleLines.cpp +++ b/src/RippleLines.cpp @@ -25,7 +25,7 @@ void RippleLines::fillLines(const uint160& accountID, Ledger::pointer ledger) SLE::pointer rippleDir=ledger->getDirNode(lspNode, currentIndex); if (!rippleDir) return; - STVector256 svOwnerNodes = rippleDir->getValueFieldV256(sfIndexes); + STVector256 svOwnerNodes = rippleDir->getFieldV256(sfIndexes); BOOST_FOREACH(uint256& uNode, svOwnerNodes.peekValue()) { SLE::pointer sleCur = ledger->getSLE(uNode); @@ -45,7 +45,7 @@ void RippleLines::fillLines(const uint160& accountID, Ledger::pointer ledger) } } - uint64 uNodeNext = rippleDir->getValueFieldU64(sfIndexNext); + uint64 uNodeNext = rippleDir->getFieldU64(sfIndexNext); if (!uNodeNext) return; currentIndex = Ledger::getDirNodeIndex(rootIndex, uNodeNext); diff --git a/src/RippleState.cpp b/src/RippleState.cpp index 911a7380ee..673d563b3d 100644 --- a/src/RippleState.cpp +++ b/src/RippleState.cpp @@ -7,19 +7,19 @@ RippleState::RippleState(SerializedLedgerEntry::pointer ledgerEntry) : { if (!mLedgerEntry || mLedgerEntry->getType() != ltRIPPLE_STATE) return; - mLowLimit = mLedgerEntry->getValueFieldAmount(sfLowLimit); - mHighLimit = mLedgerEntry->getValueFieldAmount(sfHighLimit); + mLowLimit = mLedgerEntry->getFieldAmount(sfLowLimit); + mHighLimit = mLedgerEntry->getFieldAmount(sfHighLimit); mLowID = NewcoinAddress::createAccountID(mLowLimit.getIssuer()); mHighID = NewcoinAddress::createAccountID(mHighLimit.getIssuer()); - mLowQualityIn = mLedgerEntry->getValueFieldU32(sfLowQualityIn); - mLowQualityOut = mLedgerEntry->getValueFieldU32(sfLowQualityOut); + mLowQualityIn = mLedgerEntry->getFieldU32(sfLowQualityIn); + mLowQualityOut = mLedgerEntry->getFieldU32(sfLowQualityOut); - mHighQualityIn = mLedgerEntry->getValueFieldU32(sfHighQualityIn); - mHighQualityOut = mLedgerEntry->getValueFieldU32(sfHighQualityOut); + mHighQualityIn = mLedgerEntry->getFieldU32(sfHighQualityIn); + mHighQualityOut = mLedgerEntry->getFieldU32(sfHighQualityOut); - mBalance = mLedgerEntry->getValueFieldAmount(sfBalance); + mBalance = mLedgerEntry->getFieldAmount(sfBalance); mValid = true; } diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 4b854d2384..9a57267eb3 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -9,7 +9,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint : STObject(sfLedgerEntry), mIndex(index) { set(sit); - uint16 type = getValueFieldU16(sfLedgerEntryType); + uint16 type = getFieldU16(sfLedgerEntryType); mFormat = getLgrFormat(static_cast(type)); if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); @@ -24,7 +24,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& SerializerIterator sit(s); set(sit); - uint16 type = getValueFieldU16(sfLedgerEntryType); + uint16 type = getFieldU16(sfLedgerEntryType); mFormat = getLgrFormat(static_cast(type)); if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); @@ -42,7 +42,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type) : STObject(sf mFormat = getLgrFormat(type); if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); set(mFormat->elements); - setValueFieldU16(sfLedgerEntryType, static_cast(mFormat->t_type)); + setFieldU16(sfLedgerEntryType, static_cast(mFormat->t_type)); } std::string SerializedLedgerEntry::getFullText() const @@ -85,25 +85,25 @@ bool SerializedLedgerEntry::isThreaded() uint256 SerializedLedgerEntry::getThreadedTransaction() { - return getValueFieldH256(sfLastTxnID); + return getFieldH256(sfLastTxnID); } uint32 SerializedLedgerEntry::getThreadedLedger() { - return getValueFieldU32(sfLastTxnSeq); + return getFieldU32(sfLastTxnSeq); } bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint256& prevTxID, uint32& prevLedgerID) { - uint256 oldPrevTxID = getValueFieldH256(sfLastTxnID); + uint256 oldPrevTxID = getFieldH256(sfLastTxnID); Log(lsTRACE) << "Thread Tx:" << txID << " prev:" << oldPrevTxID; if (oldPrevTxID == txID) return false; prevTxID = oldPrevTxID; - prevLedgerID = getValueFieldU32(sfLastTxnSeq); + prevLedgerID = getFieldU32(sfLastTxnSeq); assert(prevTxID != txID); - setValueFieldH256(sfLastTxnID, txID); - setValueFieldU32(sfLastTxnSeq, ledgerSeq); + setFieldH256(sfLastTxnID, txID); + setFieldU32(sfLastTxnSeq, ledgerSeq); return true; } @@ -119,17 +119,17 @@ bool SerializedLedgerEntry::hasTwoOwners() NewcoinAddress SerializedLedgerEntry::getOwner() { - return getValueFieldAccount(sfAccount); + return getFieldAccount(sfAccount); } NewcoinAddress SerializedLedgerEntry::getFirstOwner() { - return NewcoinAddress::createAccountID(getValueFieldAmount(sfLowLimit).getIssuer()); + return NewcoinAddress::createAccountID(getFieldAmount(sfLowLimit).getIssuer()); } NewcoinAddress SerializedLedgerEntry::getSecondOwner() { - return NewcoinAddress::createAccountID(getValueFieldAmount(sfHighLimit).getIssuer()); + return NewcoinAddress::createAccountID(getFieldAmount(sfHighLimit).getIssuer()); } std::vector SerializedLedgerEntry::getOwners() diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index 455830661e..fb5bad0dc6 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -32,7 +32,7 @@ public: void setIndex(const uint256& i) { mIndex = i; } LedgerEntryType getType() const { return mType; } - uint16 getVersion() const { return getValueFieldU16(sfLedgerEntryType); } + uint16 getVersion() const { return getFieldU16(sfLedgerEntryType); } const LedgerEntryFormat* getFormat() { return mFormat; } bool isThreadedType(); // is this a ledger entry that can be threaded diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 5cf6a4e7dc..a217c02681 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -450,7 +450,7 @@ std::string STObject::getFieldString(SField::ref field) const return rf->getText(); } -unsigned char STObject::getValueFieldU8(SField::ref field) const +unsigned char STObject::getFieldU8(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -461,7 +461,7 @@ unsigned char STObject::getValueFieldU8(SField::ref field) const return cf->getValue(); } -uint16 STObject::getValueFieldU16(SField::ref field) const +uint16 STObject::getFieldU16(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -472,7 +472,7 @@ uint16 STObject::getValueFieldU16(SField::ref field) const return cf->getValue(); } -uint32 STObject::getValueFieldU32(SField::ref field) const +uint32 STObject::getFieldU32(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -483,7 +483,7 @@ uint32 STObject::getValueFieldU32(SField::ref field) const return cf->getValue(); } -uint64 STObject::getValueFieldU64(SField::ref field) const +uint64 STObject::getFieldU64(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -494,7 +494,7 @@ uint64 STObject::getValueFieldU64(SField::ref field) const return cf->getValue(); } -uint128 STObject::getValueFieldH128(SField::ref field) const +uint128 STObject::getFieldH128(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -505,7 +505,7 @@ uint128 STObject::getValueFieldH128(SField::ref field) const return cf->getValue(); } -uint160 STObject::getValueFieldH160(SField::ref field) const +uint160 STObject::getFieldH160(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -516,7 +516,7 @@ uint160 STObject::getValueFieldH160(SField::ref field) const return cf->getValue(); } -uint256 STObject::getValueFieldH256(SField::ref field) const +uint256 STObject::getFieldH256(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -527,7 +527,7 @@ uint256 STObject::getValueFieldH256(SField::ref field) const return cf->getValue(); } -NewcoinAddress STObject::getValueFieldAccount(SField::ref field) const +NewcoinAddress STObject::getFieldAccount(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) @@ -545,7 +545,7 @@ NewcoinAddress STObject::getValueFieldAccount(SField::ref field) const return cf->getValueNCA(); } -uint160 STObject::getValueFieldAccount160(SField::ref field) const +uint160 STObject::getFieldAccount160(SField::ref field) const { uint160 a; const SerializedType* rf = peekAtPField(field); @@ -567,7 +567,7 @@ uint160 STObject::getValueFieldAccount160(SField::ref field) const return a; } -std::vector STObject::getValueFieldVL(SField::ref field) const +std::vector STObject::getFieldVL(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -578,7 +578,7 @@ std::vector STObject::getValueFieldVL(SField::ref field) const return cf->getValue(); } -STAmount STObject::getValueFieldAmount(SField::ref field) const +STAmount STObject::getFieldAmount(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -589,7 +589,7 @@ STAmount STObject::getValueFieldAmount(SField::ref field) const return *cf; } -STPathSet STObject::getValueFieldPathSet(SField::ref field) const +STPathSet STObject::getFieldPathSet(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -600,7 +600,7 @@ STPathSet STObject::getValueFieldPathSet(SField::ref field) const return *cf; } -STVector256 STObject::getValueFieldV256(SField::ref field) const +STVector256 STObject::getFieldV256(SField::ref field) const { const SerializedType* rf = peekAtPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -611,7 +611,7 @@ STVector256 STObject::getValueFieldV256(SField::ref field) const return *cf; } -void STObject::setValueFieldU8(SField::ref field, unsigned char v) +void STObject::setFieldU8(SField::ref field, unsigned char v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -621,7 +621,7 @@ void STObject::setValueFieldU8(SField::ref field, unsigned char v) cf->setValue(v); } -void STObject::setValueFieldU16(SField::ref field, uint16 v) +void STObject::setFieldU16(SField::ref field, uint16 v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -631,7 +631,7 @@ void STObject::setValueFieldU16(SField::ref field, uint16 v) cf->setValue(v); } -void STObject::setValueFieldU32(SField::ref field, uint32 v) +void STObject::setFieldU32(SField::ref field, uint32 v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -641,7 +641,7 @@ void STObject::setValueFieldU32(SField::ref field, uint32 v) cf->setValue(v); } -void STObject::setValueFieldU64(SField::ref field, uint64 v) +void STObject::setFieldU64(SField::ref field, uint64 v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -651,7 +651,7 @@ void STObject::setValueFieldU64(SField::ref field, uint64 v) cf->setValue(v); } -void STObject::setValueFieldH128(SField::ref field, const uint128& v) +void STObject::setFieldH128(SField::ref field, const uint128& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -661,7 +661,7 @@ void STObject::setValueFieldH128(SField::ref field, const uint128& v) cf->setValue(v); } -void STObject::setValueFieldH160(SField::ref field, const uint160& v) +void STObject::setFieldH160(SField::ref field, const uint160& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -671,7 +671,7 @@ void STObject::setValueFieldH160(SField::ref field, const uint160& v) cf->setValue(v); } -void STObject::setValueFieldH256(SField::ref field, const uint256& v) +void STObject::setFieldH256(SField::ref field, const uint256& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -681,7 +681,7 @@ void STObject::setValueFieldH256(SField::ref field, const uint256& v) cf->setValue(v); } -void STObject::setValueFieldV256(SField::ref field, const STVector256& v) +void STObject::setFieldV256(SField::ref field, const STVector256& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -691,7 +691,7 @@ void STObject::setValueFieldV256(SField::ref field, const STVector256& v) cf->setValue(v); } -void STObject::setValueFieldAccount(SField::ref field, const uint160& v) +void STObject::setFieldAccount(SField::ref field, const uint160& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -701,7 +701,7 @@ void STObject::setValueFieldAccount(SField::ref field, const uint160& v) cf->setValueH160(v); } -void STObject::setValueFieldVL(SField::ref field, const std::vector& v) +void STObject::setFieldVL(SField::ref field, const std::vector& v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -711,7 +711,7 @@ void STObject::setValueFieldVL(SField::ref field, const std::vectorsetValue(v); } -void STObject::setValueFieldAmount(SField::ref field, const STAmount &v) +void STObject::setFieldAmount(SField::ref field, const STAmount &v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -721,7 +721,7 @@ void STObject::setValueFieldAmount(SField::ref field, const STAmount &v) (*cf) = v; } -void STObject::setValueFieldPathSet(SField::ref field, const STPathSet &v) +void STObject::setFieldPathSet(SField::ref field, const STPathSet &v) { SerializedType* rf = getPField(field); if (!rf) throw std::runtime_error("Field not found"); @@ -961,7 +961,7 @@ void STObject::unitTest() if (!object1.isFieldPresent(sfTest2)) throw std::runtime_error("STObject Error"); if ((object1.getFlags() != 1) || (object2.getFlags() != 0)) throw std::runtime_error("STObject error"); - if (object1.getValueFieldH256(sfTest2) != uint256()) throw std::runtime_error("STObject error"); + if (object1.getFieldH256(sfTest2) != uint256()) throw std::runtime_error("STObject error"); if (object1.getSerializer() == object2.getSerializer()) throw std::runtime_error("STObject error"); object1.makeFieldAbsent(sfTest2); @@ -973,7 +973,7 @@ void STObject::unitTest() if (object1.isFieldPresent(sfTest2)) throw std::runtime_error("STObject error"); if (copy.isFieldPresent(sfTest2)) throw std::runtime_error("STObject error"); if (object1.getSerializer() != copy.getSerializer()) throw std::runtime_error("STObject error"); - copy.setValueFieldU32(sfTest3, 1); + copy.setFieldU32(sfTest3, 1); if (object1.getSerializer() == copy.getSerializer()) throw std::runtime_error("STObject error"); #ifdef DEBUG Log(lsDEBUG) << copy.getJson(0); @@ -983,15 +983,15 @@ void STObject::unitTest() { std::cerr << "tol: i=" << i << std::endl; std::vector j(i, 2); - object1.setValueFieldVL(sfTest1, j); + object1.setFieldVL(sfTest1, j); Serializer s; object1.add(s); SerializerIterator it(s); STObject object3(testSOElements[0], it, "TestElement3"); - if (object1.getValueFieldVL(sfTest1) != j) throw std::runtime_error("STObject error"); - if (object3.getValueFieldVL(sfTest1) != j) throw std::runtime_error("STObject error"); + if (object1.getFieldVL(sfTest1) != j) throw std::runtime_error("STObject error"); + if (object3.getFieldVL(sfTest1) != j) throw std::runtime_error("STObject error"); } } diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 321e8c1c78..a60a3efba2 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -95,36 +95,36 @@ public: // these throw if the field type doesn't match, or return default values if the // field is optional but not present std::string getFieldString(SField::ref field) const; - unsigned char getValueFieldU8(SField::ref field) const; - uint16 getValueFieldU16(SField::ref field) const; - uint32 getValueFieldU32(SField::ref field) const; - uint64 getValueFieldU64(SField::ref field) const; - uint128 getValueFieldH128(SField::ref field) const; - uint160 getValueFieldH160(SField::ref field) const; - uint256 getValueFieldH256(SField::ref field) const; - NewcoinAddress getValueFieldAccount(SField::ref field) const; - uint160 getValueFieldAccount160(SField::ref field) const; - std::vector getValueFieldVL(SField::ref field) const; - std::vector getValueFieldTL(SField::ref field) const; - STAmount getValueFieldAmount(SField::ref field) const; - STPathSet getValueFieldPathSet(SField::ref field) const; - STVector256 getValueFieldV256(SField::ref field) const; + unsigned char getFieldU8(SField::ref field) const; + uint16 getFieldU16(SField::ref field) const; + uint32 getFieldU32(SField::ref field) const; + uint64 getFieldU64(SField::ref field) const; + uint128 getFieldH128(SField::ref field) const; + uint160 getFieldH160(SField::ref field) const; + uint256 getFieldH256(SField::ref field) const; + NewcoinAddress getFieldAccount(SField::ref field) const; + uint160 getFieldAccount160(SField::ref field) const; + std::vector getFieldVL(SField::ref field) const; + std::vector getFieldTL(SField::ref field) const; + STAmount getFieldAmount(SField::ref field) const; + STPathSet getFieldPathSet(SField::ref field) const; + STVector256 getFieldV256(SField::ref field) const; - void setValueFieldU8(SField::ref field, unsigned char); - void setValueFieldU16(SField::ref field, uint16); - void setValueFieldU32(SField::ref field, uint32); - void setValueFieldU64(SField::ref field, uint64); - void setValueFieldH128(SField::ref field, const uint128&); - void setValueFieldH160(SField::ref field, const uint160&); - void setValueFieldH256(SField::ref field, const uint256&); - void setValueFieldVL(SField::ref field, const std::vector&); - void setValueFieldTL(SField::ref field, const std::vector&); - void setValueFieldAccount(SField::ref field, const uint160&); - void setValueFieldAccount(SField::ref field, const NewcoinAddress& addr) - { setValueFieldAccount(field, addr.getAccountID()); } - void setValueFieldAmount(SField::ref field, const STAmount&); - void setValueFieldPathSet(SField::ref field, const STPathSet&); - void setValueFieldV256(SField::ref field, const STVector256& v); + void setFieldU8(SField::ref field, unsigned char); + void setFieldU16(SField::ref field, uint16); + void setFieldU32(SField::ref field, uint32); + void setFieldU64(SField::ref field, uint64); + void setFieldH128(SField::ref field, const uint128&); + void setFieldH160(SField::ref field, const uint160&); + void setFieldH256(SField::ref field, const uint256&); + void setFieldVL(SField::ref field, const std::vector&); + void setFieldTL(SField::ref field, const std::vector&); + void setFieldAccount(SField::ref field, const uint160&); + void setFieldAccount(SField::ref field, const NewcoinAddress& addr) + { setFieldAccount(field, addr.getAccountID()); } + void setFieldAmount(SField::ref field, const STAmount&); + void setFieldPathSet(SField::ref field, const STPathSet&); + void setFieldV256(SField::ref field, const STVector256& v); bool isFieldPresent(SField::ref field) const; SerializedType* makeFieldPresent(SField::ref field); diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index 5059848b46..3c3643ea3e 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -13,7 +13,7 @@ SerializedTransaction::SerializedTransaction(TransactionType type) : STObject(sf if (mFormat == NULL) throw std::runtime_error("invalid transaction type"); set(mFormat->elements); - setValueFieldU16(sfTransactionType, mFormat->t_type); + setFieldU16(sfTransactionType, mFormat->t_type); } SerializedTransaction::SerializedTransaction(SerializerIterator& sit) : STObject(sfTransaction) @@ -26,7 +26,7 @@ SerializedTransaction::SerializedTransaction(SerializerIterator& sit) : STObject } set(sit); - mType = static_cast(getValueFieldU16(sfTransactionType)); + mType = static_cast(getFieldU16(sfTransactionType)); mFormat = getTxnFormat(mType); if (!mFormat) @@ -94,7 +94,7 @@ std::vector SerializedTransaction::getSignature() const { try { - return getValueFieldVL(sfTxnSignature); + return getFieldVL(sfTxnSignature); } catch (...) { @@ -106,14 +106,14 @@ void SerializedTransaction::sign(const NewcoinAddress& naAccountPrivate) { std::vector signature; naAccountPrivate.accountPrivateSign(getSigningHash(), signature); - setValueFieldVL(sfTxnSignature, signature); + setFieldVL(sfTxnSignature, signature); } bool SerializedTransaction::checkSign(const NewcoinAddress& naAccountPublic) const { try { - return naAccountPublic.accountPublicVerify(getSigningHash(), getValueFieldVL(sfTxnSignature)); + return naAccountPublic.accountPublicVerify(getSigningHash(), getFieldVL(sfTxnSignature)); } catch (...) { @@ -123,12 +123,12 @@ bool SerializedTransaction::checkSign(const NewcoinAddress& naAccountPublic) con void SerializedTransaction::setSigningPubKey(const NewcoinAddress& naSignPubKey) { - setValueFieldVL(sfSigningPubKey, naSignPubKey.getAccountPublic()); + setFieldVL(sfSigningPubKey, naSignPubKey.getAccountPublic()); } void SerializedTransaction::setSourceAccount(const NewcoinAddress& naSource) { - setValueFieldAccount(sfAccount, naSource); + setFieldAccount(sfAccount, naSource); } Json::Value SerializedTransaction::getJson(int options) const diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index f38f9c73fd..0d9f59e529 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -39,21 +39,21 @@ public: // outer transaction functions / signature functions std::vector getSignature() const; - void setSignature(const std::vector& s) { setValueFieldVL(sfTxnSignature, s); } + void setSignature(const std::vector& s) { setFieldVL(sfTxnSignature, s); } uint256 getSigningHash() const; TransactionType getTxnType() const { return mType; } - STAmount getTransactionFee() const { return getValueFieldAmount(sfFee); } - void setTransactionFee(const STAmount& fee) { setValueFieldAmount(sfFee, fee); } + STAmount getTransactionFee() const { return getFieldAmount(sfFee); } + void setTransactionFee(const STAmount& fee) { setFieldAmount(sfFee, fee); } - NewcoinAddress getSourceAccount() const { return getValueFieldAccount(sfAccount); } - std::vector getSigningPubKey() const { return getValueFieldVL(sfSigningPubKey); } + NewcoinAddress getSourceAccount() const { return getFieldAccount(sfAccount); } + std::vector getSigningPubKey() const { return getFieldVL(sfSigningPubKey); } void setSigningPubKey(const NewcoinAddress& naSignPubKey); void setSourceAccount(const NewcoinAddress& naSource); std::string getTransactionType() const { return mFormat->t_name; } - uint32 getSequence() const { return getValueFieldU32(sfSequence); } - void setSequence(uint32 seq) { return setValueFieldU32(sfSequence, seq); } + uint32 getSequence() const { return getFieldU32(sfSequence); } + void setSequence(uint32 seq) { return setFieldU32(sfSequence, seq); } std::vector getAffectedAccounts() const; diff --git a/src/SerializedValidation.cpp b/src/SerializedValidation.cpp index edd4fe721b..0a937c8d18 100644 --- a/src/SerializedValidation.cpp +++ b/src/SerializedValidation.cpp @@ -27,10 +27,10 @@ SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint32 sig const NewcoinAddress& naSeed, bool isFull) : STObject(sValidationFormat, sfValidation), mSignature(sfSignature), mTrusted(false) { - setValueFieldH256(sfLedgerHash, ledgerHash); - setValueFieldU32(sfSigningTime, signTime); + setFieldH256(sfLedgerHash, ledgerHash); + setFieldU32(sfSigningTime, signTime); if (naSeed.isValid()) - setValueFieldVL(sfSigningPubKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic()); + setFieldVL(sfSigningPubKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic()); if (!isFull) setFlag(sFullFlag); NewcoinAddress::createNodePrivate(naSeed).signNodePrivate(getSigningHash(), mSignature.peekValue()); @@ -51,17 +51,17 @@ uint256 SerializedValidation::getSigningHash() const uint256 SerializedValidation::getLedgerHash() const { - return getValueFieldH256(sfLedgerHash); + return getFieldH256(sfLedgerHash); } uint32 SerializedValidation::getSignTime() const { - return getValueFieldU32(sfSigningTime); + return getFieldU32(sfSigningTime); } uint32 SerializedValidation::getFlags() const { - return getValueFieldU32(sfFlags); + return getFieldU32(sfFlags); } bool SerializedValidation::isValid() const @@ -73,7 +73,7 @@ bool SerializedValidation::isValid(const uint256& signingHash) const { try { - NewcoinAddress naPublicKey = NewcoinAddress::createNodePublic(getValueFieldVL(sfSigningPubKey)); + NewcoinAddress naPublicKey = NewcoinAddress::createNodePublic(getFieldVL(sfSigningPubKey)); return naPublicKey.isValid() && naPublicKey.verifyNodePublic(signingHash, mSignature.peekValue()); } catch (...) @@ -85,7 +85,7 @@ bool SerializedValidation::isValid(const uint256& signingHash) const NewcoinAddress SerializedValidation::getSignerPublic() const { NewcoinAddress a; - a.setNodePublic(getValueFieldVL(sfSigningPubKey)); + a.setNodePublic(getFieldVL(sfSigningPubKey)); return a; } diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 40c20d9130..76bd2a9408 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -79,7 +79,7 @@ Transaction::Transaction( if (uSourceTag) { mTransaction->makeFieldPresent(sfSourceTag); - mTransaction->setValueFieldU32(sfSourceTag, uSourceTag); + mTransaction->setFieldU32(sfSourceTag, uSourceTag); } } @@ -127,24 +127,24 @@ Transaction::pointer Transaction::setAccountSet( ) { if (!bEmailHash) - mTransaction->setValueFieldH128(sfEmailHash, uEmailHash); + mTransaction->setFieldH128(sfEmailHash, uEmailHash); if (!bWalletLocator) - mTransaction->setValueFieldH256(sfWalletLocator, uWalletLocator); + mTransaction->setFieldH256(sfWalletLocator, uWalletLocator); if (naMessagePublic.isValid()) - mTransaction->setValueFieldVL(sfMessageKey, naMessagePublic.getAccountPublic()); + mTransaction->setFieldVL(sfMessageKey, naMessagePublic.getAccountPublic()); if (bDomain) - mTransaction->setValueFieldVL(sfDomain, vucDomain); + mTransaction->setFieldVL(sfDomain, vucDomain); if (bTransferRate) - mTransaction->setValueFieldU32(sfTransferRate, uTransferRate); + mTransaction->setFieldU32(sfTransferRate, uTransferRate); if (bPublish) { - mTransaction->setValueFieldH256(sfPublishHash, uPublishHash); - mTransaction->setValueFieldU32(sfPublishSize, uPublishSize); + mTransaction->setFieldH256(sfPublishHash, uPublishHash); + mTransaction->setFieldU32(sfPublishSize, uPublishSize); } sign(naPrivateKey); @@ -188,9 +188,9 @@ Transaction::pointer Transaction::setClaim( const std::vector& vucPubKey, const std::vector& vucSignature) { - mTransaction->setValueFieldVL(sfGenerator, vucGenerator); - mTransaction->setValueFieldVL(sfPublicKey, vucPubKey); - mTransaction->setValueFieldVL(sfSignature, vucSignature); + mTransaction->setFieldVL(sfGenerator, vucGenerator); + mTransaction->setFieldVL(sfPublicKey, vucPubKey); + mTransaction->setFieldVL(sfSignature, vucSignature); sign(naPrivateKey); @@ -222,9 +222,9 @@ Transaction::pointer Transaction::setCreate( const NewcoinAddress& naCreateAccountID, const STAmount& saFund) { - mTransaction->setValueFieldU32(sfFlags, tfCreateAccount); - mTransaction->setValueFieldAccount(sfDestination, naCreateAccountID); - mTransaction->setValueFieldAmount(sfAmount, saFund); + mTransaction->setFieldU32(sfFlags, tfCreateAccount); + mTransaction->setFieldAccount(sfDestination, naCreateAccountID); + mTransaction->setFieldAmount(sfAmount, saFund); sign(naPrivateKey); @@ -257,13 +257,13 @@ Transaction::pointer Transaction::setCreditSet( bool bQualityOut, uint32 uQualityOut) { - mTransaction->setValueFieldAmount(sfLimitAmount, saLimitAmount); + mTransaction->setFieldAmount(sfLimitAmount, saLimitAmount); if (bQualityIn) - mTransaction->setValueFieldU32(sfQualityIn, uQualityIn); + mTransaction->setFieldU32(sfQualityIn, uQualityIn); if (bQualityOut) - mTransaction->setValueFieldU32(sfQualityOut, uQualityOut); + mTransaction->setFieldU32(sfQualityOut, uQualityOut); sign(naPrivateKey); @@ -300,11 +300,11 @@ Transaction::pointer Transaction::setNicknameSet( bool bSetOffer, const STAmount& saMinimumOffer) { - mTransaction->setValueFieldH256(sfNickname, uNickname); + mTransaction->setFieldH256(sfNickname, uNickname); // XXX Make sure field is present even for 0! if (bSetOffer) - mTransaction->setValueFieldAmount(sfMinimumOffer, saMinimumOffer); + mTransaction->setFieldAmount(sfMinimumOffer, saMinimumOffer); sign(naPrivateKey); @@ -340,13 +340,13 @@ Transaction::pointer Transaction::setOfferCreate( uint32 uExpiration) { if (bPassive) - mTransaction->setValueFieldU32(sfFlags, tfPassive); + mTransaction->setFieldU32(sfFlags, tfPassive); - mTransaction->setValueFieldAmount(sfTakerPays, saTakerPays); - mTransaction->setValueFieldAmount(sfTakerGets, saTakerGets); + mTransaction->setFieldAmount(sfTakerPays, saTakerPays); + mTransaction->setFieldAmount(sfTakerGets, saTakerGets); if (uExpiration) - mTransaction->setValueFieldU32(sfExpiration, uExpiration); + mTransaction->setFieldU32(sfExpiration, uExpiration); sign(naPrivateKey); @@ -377,7 +377,7 @@ Transaction::pointer Transaction::setOfferCancel( const NewcoinAddress& naPrivateKey, uint32 uSequence) { - mTransaction->setValueFieldU32(sfOfferSequence, uSequence); + mTransaction->setFieldU32(sfOfferSequence, uSequence); sign(naPrivateKey); @@ -405,7 +405,7 @@ Transaction::pointer Transaction::setPasswordFund( const NewcoinAddress& naPrivateKey, const NewcoinAddress& naDstAccountID) { - mTransaction->setValueFieldAccount(sfDestination, naDstAccountID); + mTransaction->setFieldAccount(sfDestination, naDstAccountID); sign(naPrivateKey); @@ -436,10 +436,10 @@ Transaction::pointer Transaction::setPasswordSet( const std::vector& vucPubKey, const std::vector& vucSignature) { - mTransaction->setValueFieldAccount(sfAuthorizedKey, naAuthKeyID); - mTransaction->setValueFieldVL(sfGenerator, vucGenerator); - mTransaction->setValueFieldVL(sfPublicKey, vucPubKey); - mTransaction->setValueFieldVL(sfSignature, vucSignature); + mTransaction->setFieldAccount(sfAuthorizedKey, naAuthKeyID); + mTransaction->setFieldVL(sfGenerator, vucGenerator); + mTransaction->setFieldVL(sfPublicKey, vucPubKey); + mTransaction->setFieldVL(sfSignature, vucSignature); sign(naPrivateKey); @@ -476,17 +476,17 @@ Transaction::pointer Transaction::setPayment( const bool bPartial, const bool bLimit) { - mTransaction->setValueFieldAccount(sfDestination, naDstAccountID); - mTransaction->setValueFieldAmount(sfAmount, saAmount); + mTransaction->setFieldAccount(sfDestination, naDstAccountID); + mTransaction->setFieldAmount(sfAmount, saAmount); if (saAmount != saSendMax || saAmount.getCurrency() != saSendMax.getCurrency()) { - mTransaction->setValueFieldAmount(sfSendMax, saSendMax); + mTransaction->setFieldAmount(sfSendMax, saSendMax); } if (spsPaths.getPathCount()) { - mTransaction->setValueFieldPathSet(sfPaths, spsPaths); + mTransaction->setFieldPathSet(sfPaths, spsPaths); } sign(naPrivateKey); @@ -523,10 +523,10 @@ Transaction::pointer Transaction::setWalletAdd( const NewcoinAddress& naNewPubKey, const std::vector& vucSignature) { - mTransaction->setValueFieldAmount(sfAmount, saAmount); - mTransaction->setValueFieldAccount(sfAuthorizedKey, naAuthKeyID); - mTransaction->setValueFieldVL(sfPublicKey, naNewPubKey.getAccountPublic()); - mTransaction->setValueFieldVL(sfSignature, vucSignature); + mTransaction->setFieldAmount(sfAmount, saAmount); + mTransaction->setFieldAccount(sfAuthorizedKey, naAuthKeyID); + mTransaction->setFieldVL(sfPublicKey, naNewPubKey.getAccountPublic()); + mTransaction->setFieldVL(sfSignature, vucSignature); sign(naPrivateKey); diff --git a/src/Transaction.h b/src/Transaction.h index ae064f2df2..9ae05685d6 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -272,10 +272,10 @@ public: const uint256& getID() const { return mTransactionID; } const NewcoinAddress& getFromAccount() const { return mAccountFrom; } - STAmount getAmount() const { return mTransaction->getValueFieldU64(sfAmount); } + STAmount getAmount() const { return mTransaction->getFieldU64(sfAmount); } STAmount getFee() const { return mTransaction->getTransactionFee(); } uint32 getFromAccountSeq() const { return mTransaction->getSequence(); } - uint32 getIdent() const { return mTransaction->getValueFieldU32(sfSourceTag); } + uint32 getIdent() const { return mTransaction->getFieldU32(sfSourceTag); } std::vector getSignature() const { return mTransaction->getSignature(); } uint32 getLedger() const { return mInLedger; } TransStatus getStatus() const { return mStatus; } diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index 64dd343863..acdeacadb9 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -29,9 +29,9 @@ TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMus // Otherwise, people could deny access to generators. // - std::vector vucCipher = txn.getValueFieldVL(sfGenerator); - std::vector vucPubKey = txn.getValueFieldVL(sfPublicKey); - std::vector vucSignature = txn.getValueFieldVL(sfSignature); + std::vector vucCipher = txn.getFieldVL(sfGenerator); + std::vector vucPubKey = txn.getFieldVL(sfPublicKey); + std::vector vucSignature = txn.getFieldVL(sfSignature); NewcoinAddress naAccountPublic = NewcoinAddress::createAccountPublic(vucPubKey); if (!naAccountPublic.accountPublicVerify(Serializer::getSHA512Half(vucCipher), vucSignature)) @@ -52,7 +52,7 @@ TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMus sleGen = entryCreate(ltGENERATOR_MAP, Ledger::getGeneratorIndex(hGeneratorID)); - sleGen->setValueFieldVL(sfGenerator, vucCipher); + sleGen->setFieldVL(sfGenerator, vucCipher); } else if (bMustSetGenerator) { @@ -66,9 +66,9 @@ TER TransactionEngine::setAuthorized(const SerializedTransaction& txn, bool bMus // Set the public key needed to use the account. uint160 uAuthKeyID = bMustSetGenerator ? hGeneratorID // Claim - : txn.getValueFieldAccount160(sfAuthorizedKey); // PasswordSet + : txn.getFieldAccount160(sfAuthorizedKey); // PasswordSet - mTxnAccount->setValueFieldAccount(sfAuthorizedKey, uAuthKeyID); + mTxnAccount->setFieldAccount(sfAuthorizedKey, uAuthKeyID); return tesSUCCESS; } @@ -83,7 +83,7 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) if (txn.isFieldPresent(sfEmailHash)) { - uint128 uHash = txn.getValueFieldH128(sfEmailHash); + uint128 uHash = txn.getFieldH128(sfEmailHash); if (!uHash) { @@ -95,7 +95,7 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { Log(lsINFO) << "doAccountSet: set email hash"; - mTxnAccount->setValueFieldH128(sfEmailHash, uHash); + mTxnAccount->setFieldH128(sfEmailHash, uHash); } } @@ -105,7 +105,7 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) if (txn.isFieldPresent(sfWalletLocator)) { - uint256 uHash = txn.getValueFieldH256(sfWalletLocator); + uint256 uHash = txn.getFieldH256(sfWalletLocator); if (!uHash) { @@ -117,7 +117,7 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { Log(lsINFO) << "doAccountSet: set wallet locator"; - mTxnAccount->setValueFieldH256(sfWalletLocator, uHash); + mTxnAccount->setFieldH256(sfWalletLocator, uHash); } } @@ -133,7 +133,7 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { Log(lsINFO) << "doAccountSet: set message key"; - mTxnAccount->setValueFieldVL(sfMessageKey, txn.getValueFieldVL(sfMessageKey)); + mTxnAccount->setFieldVL(sfMessageKey, txn.getFieldVL(sfMessageKey)); } // @@ -142,7 +142,7 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) if (txn.isFieldPresent(sfDomain)) { - std::vector vucDomain = txn.getValueFieldVL(sfDomain); + std::vector vucDomain = txn.getFieldVL(sfDomain); if (vucDomain.empty()) { @@ -154,7 +154,7 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { Log(lsINFO) << "doAccountSet: set domain"; - mTxnAccount->setValueFieldVL(sfDomain, vucDomain); + mTxnAccount->setFieldVL(sfDomain, vucDomain); } } @@ -164,7 +164,7 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) if (txn.isFieldPresent(sfTransferRate)) { - uint32 uRate = txn.getValueFieldU32(sfTransferRate); + uint32 uRate = txn.getFieldU32(sfTransferRate); if (!uRate || uRate == QUALITY_ONE) { @@ -176,7 +176,7 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { Log(lsINFO) << "doAccountSet: set transfer rate"; - mTxnAccount->setValueFieldU32(sfTransferRate, uRate); + mTxnAccount->setFieldU32(sfTransferRate, uRate); } else { @@ -201,8 +201,8 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) } else if (bPublishHash && bPublishSize) { - uint256 uHash = txn.getValueFieldH256(sfPublishHash); - uint32 uSize = txn.getValueFieldU32(sfPublishSize); + uint256 uHash = txn.getFieldH256(sfPublishHash); + uint32 uSize = txn.getFieldU32(sfPublishSize); if (!uHash) { @@ -215,8 +215,8 @@ TER TransactionEngine::doAccountSet(const SerializedTransaction& txn) { Log(lsINFO) << "doAccountSet: set publish"; - mTxnAccount->setValueFieldH256(sfPublishHash, uHash); - mTxnAccount->setValueFieldU32(sfPublishSize, uSize); + mTxnAccount->setFieldH256(sfPublishHash, uHash); + mTxnAccount->setFieldU32(sfPublishSize, uSize); } } @@ -241,11 +241,11 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) TER terResult = tesSUCCESS; Log(lsINFO) << "doCreditSet>"; - const STAmount saLimitAmount = txn.getValueFieldAmount(sfLimitAmount); + const STAmount saLimitAmount = txn.getFieldAmount(sfLimitAmount); const bool bQualityIn = txn.isFieldPresent(sfQualityIn); - const uint32 uQualityIn = bQualityIn ? txn.getValueFieldU32(sfQualityIn) : 0; + const uint32 uQualityIn = bQualityIn ? txn.getFieldU32(sfQualityIn) : 0; const bool bQualityOut = txn.isFieldPresent(sfQualityOut); - const uint32 uQualityOut = bQualityIn ? txn.getValueFieldU32(sfQualityOut) : 0; + const uint32 uQualityOut = bQualityIn ? txn.getFieldU32(sfQualityOut) : 0; const uint160 uCurrencyID = saLimitAmount.getCurrency(); uint160 uDstAccountID = saLimitAmount.getIssuer(); const bool bFlipped = mTxnAccountID > uDstAccountID; // true, iff current is not lowest. @@ -285,12 +285,12 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) if (!saLimitAmount) { // Zeroing line. - uint160 uLowID = sleRippleState->getValueFieldAmount(sfLowLimit).getIssuer(); - uint160 uHighID = sleRippleState->getValueFieldAmount(sfHighLimit).getIssuer(); + uint160 uLowID = sleRippleState->getFieldAmount(sfLowLimit).getIssuer(); + uint160 uHighID = sleRippleState->getFieldAmount(sfHighLimit).getIssuer(); bool bLow = uLowID == uSrcAccountID; bool bHigh = uLowID == uDstAccountID; - bool bBalanceZero = !sleRippleState->getValueFieldAmount(sfBalance); - STAmount saDstLimit = sleRippleState->getValueFieldAmount(bSendLow ? sfLowLimit : sfHighLimit); + bool bBalanceZero = !sleRippleState->getFieldAmount(sfBalance); + STAmount saDstLimit = sleRippleState->getFieldAmount(bSendLow ? sfLowLimit : sfHighLimit); bool bDstLimitZero = !saDstLimit; assert(bLow || bHigh); @@ -307,7 +307,7 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) if (!bDelIndex) { - sleRippleState->setValueFieldAmount(bFlipped ? sfHighLimit: sfLowLimit, saLimitAllow); + sleRippleState->setFieldAmount(bFlipped ? sfHighLimit: sfLowLimit, saLimitAllow); if (!bQualityIn) { @@ -315,7 +315,7 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) } else if (uQualityIn) { - sleRippleState->setValueFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn); + sleRippleState->setFieldU32(bFlipped ? sfLowQualityIn : sfHighQualityIn, uQualityIn); } else { @@ -328,7 +328,7 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) } else if (uQualityOut) { - sleRippleState->setValueFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut); + sleRippleState->setFieldU32(bFlipped ? sfLowQualityOut : sfHighQualityOut, uQualityOut); } else { @@ -354,14 +354,14 @@ TER TransactionEngine::doCreditSet(const SerializedTransaction& txn) Log(lsINFO) << "doCreditSet: Creating ripple line: " << sleRippleState->getIndex().ToString(); - sleRippleState->setValueFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency. - sleRippleState->setValueFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAllow); - sleRippleState->setValueFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uDstAccountID)); + sleRippleState->setFieldAmount(sfBalance, STAmount(uCurrencyID, ACCOUNT_ONE)); // Zero balance in currency. + sleRippleState->setFieldAmount(bFlipped ? sfHighLimit : sfLowLimit, saLimitAllow); + sleRippleState->setFieldAmount(bFlipped ? sfLowLimit : sfHighLimit, STAmount(uCurrencyID, uDstAccountID)); if (uQualityIn) - sleRippleState->setValueFieldU32(bFlipped ? sfHighQualityIn : sfLowQualityIn, uQualityIn); + sleRippleState->setFieldU32(bFlipped ? sfHighQualityIn : sfLowQualityIn, uQualityIn); if (uQualityOut) - sleRippleState->setValueFieldU32(bFlipped ? sfHighQualityOut : sfLowQualityOut, uQualityOut); + sleRippleState->setFieldU32(bFlipped ? sfHighQualityOut : sfLowQualityOut, uQualityOut); uint64 uSrcRef; // Ignored, dirs never delete. @@ -380,20 +380,20 @@ TER TransactionEngine::doNicknameSet(const SerializedTransaction& txn) { std::cerr << "doNicknameSet>" << std::endl; - const uint256 uNickname = txn.getValueFieldH256(sfNickname); + const uint256 uNickname = txn.getFieldH256(sfNickname); const bool bMinOffer = txn.isFieldPresent(sfMinimumOffer); - const STAmount saMinOffer = bMinOffer ? txn.getValueFieldAmount(sfAmount) : STAmount(); + const STAmount saMinOffer = bMinOffer ? txn.getFieldAmount(sfAmount) : STAmount(); SLE::pointer sleNickname = entryCache(ltNICKNAME, uNickname); if (sleNickname) { // Edit old entry. - sleNickname->setValueFieldAccount(sfAccount, mTxnAccountID); + sleNickname->setFieldAccount(sfAccount, mTxnAccountID); if (bMinOffer && saMinOffer) { - sleNickname->setValueFieldAmount(sfMinimumOffer, saMinOffer); + sleNickname->setFieldAmount(sfMinimumOffer, saMinOffer); } else { @@ -411,10 +411,10 @@ TER TransactionEngine::doNicknameSet(const SerializedTransaction& txn) std::cerr << "doNicknameSet: Creating nickname node: " << sleNickname->getIndex().ToString() << std::endl; - sleNickname->setValueFieldAccount(sfAccount, mTxnAccountID); + sleNickname->setFieldAccount(sfAccount, mTxnAccountID); if (bMinOffer && saMinOffer) - sleNickname->setValueFieldAmount(sfMinimumOffer, saMinOffer); + sleNickname->setFieldAmount(sfMinimumOffer, saMinOffer); } std::cerr << "doNicknameSet<" << std::endl; @@ -426,7 +426,7 @@ TER TransactionEngine::doPasswordFund(const SerializedTransaction& txn) { std::cerr << "doPasswordFund>" << std::endl; - const uint160 uDstAccountID = txn.getValueFieldAccount160(sfDestination); + const uint160 uDstAccountID = txn.getFieldAccount160(sfDestination); SLE::pointer sleDst = mTxnAccountID == uDstAccountID ? mTxnAccount : entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); @@ -488,9 +488,9 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac const bool bNoRippleDirect = isSetBit(uTxFlags, tfNoRippleDirect); const bool bPaths = txn.isFieldPresent(sfPaths); const bool bMax = txn.isFieldPresent(sfSendMax); - const uint160 uDstAccountID = txn.getValueFieldAccount160(sfDestination); - const STAmount saDstAmount = txn.getValueFieldAmount(sfAmount); - const STAmount saMaxAmount = bMax ? txn.getValueFieldAmount(sfSendMax) : saDstAmount; + const uint160 uDstAccountID = txn.getFieldAccount160(sfDestination); + const STAmount saDstAmount = txn.getFieldAmount(sfAmount); + const STAmount saMaxAmount = bMax ? txn.getFieldAmount(sfSendMax) : saDstAmount; const uint160 uSrcCurrency = saMaxAmount.getCurrency(); const uint160 uDstCurrency = saDstAmount.getCurrency(); @@ -550,8 +550,8 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac // Create the account. sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - sleDst->setValueFieldAccount(sfAccount, uDstAccountID); - sleDst->setValueFieldU32(sfSequence, 1); + sleDst->setFieldAccount(sfAccount, uDstAccountID); + sleDst->setFieldU32(sfSequence, 1); } else { @@ -566,7 +566,7 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac { // Ripple payment - STPathSet spsPaths = txn.getValueFieldPathSet(sfPaths); + STPathSet spsPaths = txn.getFieldPathSet(sfPaths); STAmount saMaxAmountAct; STAmount saDstAmountAct; @@ -589,7 +589,7 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac { // Direct XNS payment. - STAmount saSrcXNSBalance = mTxnAccount->getValueFieldAmount(sfBalance); + STAmount saSrcXNSBalance = mTxnAccount->getFieldAmount(sfBalance); if (saSrcXNSBalance < saDstAmount) { @@ -600,8 +600,8 @@ TER TransactionEngine::doPayment(const SerializedTransaction& txn, const Transac } else { - mTxnAccount->setValueFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); - sleDst->setValueFieldAmount(sfBalance, sleDst->getValueFieldAmount(sfBalance) + saDstAmount); + mTxnAccount->setFieldAmount(sfBalance, saSrcXNSBalance - saDstAmount); + sleDst->setFieldAmount(sfBalance, sleDst->getFieldAmount(sfBalance) + saDstAmount); terResult = tesSUCCESS; } @@ -626,9 +626,9 @@ TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn) { std::cerr << "WalletAdd>" << std::endl; - const std::vector vucPubKey = txn.getValueFieldVL(sfPublicKey); - const std::vector vucSignature = txn.getValueFieldVL(sfSignature); - const uint160 uAuthKeyID = txn.getValueFieldAccount160(sfAuthorizedKey); + const std::vector vucPubKey = txn.getFieldVL(sfPublicKey); + const std::vector vucSignature = txn.getFieldVL(sfSignature); + const uint160 uAuthKeyID = txn.getFieldAccount160(sfAuthorizedKey); const NewcoinAddress naMasterPubKey = NewcoinAddress::createAccountPublic(vucPubKey); const uint160 uDstAccountID = naMasterPubKey.getAccountID(); @@ -648,8 +648,8 @@ TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn) return tefCREATED; } - STAmount saAmount = txn.getValueFieldAmount(sfAmount); - STAmount saSrcBalance = mTxnAccount->getValueFieldAmount(sfBalance); + STAmount saAmount = txn.getFieldAmount(sfAmount); + STAmount saSrcBalance = mTxnAccount->getFieldAmount(sfBalance); if (saSrcBalance < saAmount) { @@ -663,15 +663,15 @@ TER TransactionEngine::doWalletAdd(const SerializedTransaction& txn) } // Deduct initial balance from source account. - mTxnAccount->setValueFieldAmount(sfBalance, saSrcBalance-saAmount); + mTxnAccount->setFieldAmount(sfBalance, saSrcBalance-saAmount); // Create the account. sleDst = entryCreate(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uDstAccountID)); - sleDst->setValueFieldAccount(sfAccount, uDstAccountID); - sleDst->setValueFieldU32(sfSequence, 1); - sleDst->setValueFieldAmount(sfBalance, saAmount); - sleDst->setValueFieldAccount(sfAuthorizedKey, uAuthKeyID); + sleDst->setFieldAccount(sfAccount, uDstAccountID); + sleDst->setFieldU32(sfSequence, 1); + sleDst->setFieldAmount(sfBalance, saAmount); + sleDst->setFieldAccount(sfAuthorizedKey, uAuthKeyID); std::cerr << "WalletAdd<" << std::endl; @@ -770,11 +770,11 @@ TER TransactionEngine::takeOffers( Log(lsINFO) << "takeOffers: considering offer : " << sleOffer->getJson(0); - const uint160 uOfferOwnerID = sleOffer->getValueFieldAccount(sfAccount).getAccountID(); - STAmount saOfferPays = sleOffer->getValueFieldAmount(sfTakerGets); - STAmount saOfferGets = sleOffer->getValueFieldAmount(sfTakerPays); + const uint160 uOfferOwnerID = sleOffer->getFieldAccount(sfAccount).getAccountID(); + STAmount saOfferPays = sleOffer->getFieldAmount(sfTakerGets); + STAmount saOfferGets = sleOffer->getFieldAmount(sfTakerPays); - if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getValueFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) + if (sleOffer->isFieldPresent(sfExpiration) && sleOffer->getFieldU32(sfExpiration) <= mLedger->getParentCloseTimeNC()) { // Offer is expired. Expired offers are considered unfunded. Delete it. Log(lsINFO) << "takeOffers: encountered expired offer"; @@ -849,10 +849,10 @@ TER TransactionEngine::takeOffers( // Adjust offer // Offer owner will pay less. Subtract what taker just got. - sleOffer->setValueFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot); + sleOffer->setFieldAmount(sfTakerGets, saOfferPays -= saSubTakerGot); // Offer owner will get less. Subtract what owner just paid. - sleOffer->setValueFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid); + sleOffer->setFieldAmount(sfTakerPays, saOfferGets -= saSubTakerPaid); entryModify(sleOffer); @@ -919,8 +919,8 @@ TER TransactionEngine::doOfferCreate(const SerializedTransaction& txn) Log(lsWARNING) << "doOfferCreate> " << txn.getJson(0); const uint32 txFlags = txn.getFlags(); const bool bPassive = isSetBit(txFlags, tfPassive); - STAmount saTakerPays = txn.getValueFieldAmount(sfTakerPays); - STAmount saTakerGets = txn.getValueFieldAmount(sfTakerGets); + STAmount saTakerPays = txn.getFieldAmount(sfTakerPays); + STAmount saTakerGets = txn.getFieldAmount(sfTakerGets); Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGets=%s") % saTakerPays.getFullText() @@ -928,7 +928,7 @@ Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGe const uint160 uPaysIssuerID = saTakerPays.getIssuer(); const uint160 uGetsIssuerID = saTakerGets.getIssuer(); - const uint32 uExpiration = txn.getValueFieldU32(sfExpiration); + const uint32 uExpiration = txn.getFieldU32(sfExpiration); const bool bHaveExpiration = txn.isFieldPresent(sfExpiration); const uint32 uSequence = txn.getSequence(); @@ -1090,16 +1090,16 @@ Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGe Log(lsWARNING) << "doOfferCreate: uPaysCurrency=" << saTakerPays.getHumanCurrency(); Log(lsWARNING) << "doOfferCreate: uGetsCurrency=" << saTakerGets.getHumanCurrency(); - sleOffer->setValueFieldAccount(sfAccount, mTxnAccountID); - sleOffer->setValueFieldU32(sfSequence, uSequence); - sleOffer->setValueFieldH256(sfBookDirectory, uDirectory); - sleOffer->setValueFieldAmount(sfTakerPays, saTakerPays); - sleOffer->setValueFieldAmount(sfTakerGets, saTakerGets); - sleOffer->setValueFieldU64(sfOwnerNode, uOwnerNode); - sleOffer->setValueFieldU64(sfBookNode, uBookNode); + sleOffer->setFieldAccount(sfAccount, mTxnAccountID); + sleOffer->setFieldU32(sfSequence, uSequence); + sleOffer->setFieldH256(sfBookDirectory, uDirectory); + sleOffer->setFieldAmount(sfTakerPays, saTakerPays); + sleOffer->setFieldAmount(sfTakerGets, saTakerGets); + sleOffer->setFieldU64(sfOwnerNode, uOwnerNode); + sleOffer->setFieldU64(sfBookNode, uBookNode); if (uExpiration) - sleOffer->setValueFieldU32(sfExpiration, uExpiration); + sleOffer->setFieldU32(sfExpiration, uExpiration); if (bPassive) sleOffer->setFlag(lsfPassive); @@ -1114,7 +1114,7 @@ Log(lsINFO) << boost::str(boost::format("doOfferCreate: saTakerPays=%s saTakerGe TER TransactionEngine::doOfferCancel(const SerializedTransaction& txn) { TER terResult; - const uint32 uSequence = txn.getValueFieldU32(sfOfferSequence); + const uint32 uSequence = txn.getFieldU32(sfOfferSequence); const uint256 uOfferIndex = Ledger::getOfferIndex(mTxnAccountID, uSequence); SLE::pointer sleOffer = entryCache(ltOFFER, uOfferIndex); @@ -1141,14 +1141,14 @@ TER TransactionEngine::doContractAdd(const SerializedTransaction& txn) { Log(lsWARNING) << "doContractAdd> " << txn.getJson(0); - const uint32 expiration = txn.getValueFieldU32(sfExpiration); -// const uint32 bondAmount = txn.getValueFieldU32(sfBondAmount); -// const uint32 stampEscrow = txn.getValueFieldU32(sfStampEscrow); - STAmount rippleEscrow = txn.getValueFieldAmount(sfRippleEscrow); - std::vector createCode = txn.getValueFieldVL(sfCreateCode); - std::vector fundCode = txn.getValueFieldVL(sfFundCode); - std::vector removeCode = txn.getValueFieldVL(sfRemoveCode); - std::vector expireCode = txn.getValueFieldVL(sfExpireCode); + const uint32 expiration = txn.getFieldU32(sfExpiration); +// const uint32 bondAmount = txn.getFieldU32(sfBondAmount); +// const uint32 stampEscrow = txn.getFieldU32(sfStampEscrow); + STAmount rippleEscrow = txn.getFieldAmount(sfRippleEscrow); + std::vector createCode = txn.getFieldVL(sfCreateCode); + std::vector fundCode = txn.getFieldVL(sfFundCode); + std::vector removeCode = txn.getFieldVL(sfRemoveCode); + std::vector expireCode = txn.getFieldVL(sfExpireCode); // make sure // expiration hasn't passed diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index 6452ca0775..a89562dd01 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -136,7 +136,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa case ttNICKNAME_SET: { - SLE::pointer sleNickname = entryCache(ltNICKNAME, txn.getValueFieldH256(sfNickname)); + SLE::pointer sleNickname = entryCache(ltNICKNAME, txn.getFieldH256(sfNickname)); if (!sleNickname) saCost = theConfig.FEE_NICKNAME_CREATE; @@ -222,7 +222,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa } else { - saSrcBalance = mTxnAccount->getValueFieldAmount(sfBalance); + saSrcBalance = mTxnAccount->getFieldAmount(sfBalance); bHaveAuthKey = mTxnAccount->isFieldPresent(sfAuthorizedKey); } @@ -279,7 +279,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa default: // Verify the transaction's signing public key is the key authorized for signing. - if (bHaveAuthKey && naSigningPubKey.getAccountID() == mTxnAccount->getValueFieldAccount(sfAuthorizedKey).getAccountID()) + if (bHaveAuthKey && naSigningPubKey.getAccountID() == mTxnAccount->getFieldAccount(sfAuthorizedKey).getAccountID()) { // Authorized to continue. nothing(); @@ -322,7 +322,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa } else { - mTxnAccount->setValueFieldAmount(sfBalance, saSrcBalance - saPaid); + mTxnAccount->setFieldAmount(sfBalance, saSrcBalance - saPaid); } // Validate sequence @@ -332,7 +332,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa } else if (saCost) { - uint32 a_seq = mTxnAccount->getValueFieldU32(sfSequence); + uint32 a_seq = mTxnAccount->getFieldU32(sfSequence); Log(lsTRACE) << "Aseq=" << a_seq << ", Tseq=" << t_seq; @@ -359,7 +359,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa } else { - mTxnAccount->setValueFieldU32(sfSequence, t_seq + 1); + mTxnAccount->setFieldU32(sfSequence, t_seq + 1); } } else From e7c9ee09f66b07c47b830eb3df8afbbcd74ce89c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 1 Oct 2012 16:53:54 -0700 Subject: [PATCH 407/426] New JSON functionality. --- src/LedgerFormats.cpp | 15 +++++++---- src/LedgerFormats.h | 1 + src/SerializedObject.cpp | 53 ++++++++++++++++++++++++++++---------- src/SerializedObject.h | 2 +- src/SerializedTypes.h | 6 +++++ src/TransactionFormats.cpp | 21 +++++++++------ src/TransactionFormats.h | 3 ++- 7 files changed, 73 insertions(+), 28 deletions(-) diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 9f0ed403ac..56c8a39a21 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -89,13 +89,18 @@ LedgerEntryFormat* getLgrFormat(LedgerEntryType t) LedgerEntryFormat* getLgrFormat(int t) { - LedgerEntryFormat* f = LedgerFormats; - while (f->t_name != NULL) - { + for (LedgerEntryFormat* f = LedgerFormats; f->t_name != NULL; ++f) if (f->t_type == t) return f; - ++f; - } return NULL; } + +LedgerEntryFormat* getLgrFormat(const std::string& t) +{ + for (LedgerEntryFormat* f = LedgerFormats; f->t_name != NULL; ++f) + if (t == f->t_name) + return f; + return NULL; +} + // vim:ts=4 diff --git a/src/LedgerFormats.h b/src/LedgerFormats.h index 7b4a95683e..348116880d 100644 --- a/src/LedgerFormats.h +++ b/src/LedgerFormats.h @@ -48,6 +48,7 @@ struct LedgerEntryFormat extern LedgerEntryFormat LedgerFormats[]; extern LedgerEntryFormat* getLgrFormat(LedgerEntryType t); +extern LedgerEntryFormat* getLgrFormat(const std::string& t); extern LedgerEntryFormat* getLgrFormat(int t); #endif // vim:ts=4 diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index a217c02681..7584d53dc5 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -8,6 +8,8 @@ #include "../json/writer.h" #include "Log.h" +#include "LedgerFormats.h" +#include "TransactionFormats.h" std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, SField::ref name) { @@ -813,21 +815,23 @@ STArray* STArray::construct(SerializerIterator& sit, SField::ref field) return new STArray(field, value); } -std::auto_ptr STObject::parseJson(const Json::Value& object, SField::ref name, int depth) +std::auto_ptr STObject::parseJson(const Json::Value& object, SField::ref inName, int depth) { if (!object.isObject()) throw std::runtime_error("Value is not an object"); + SField::ptr name = &inName; + boost::ptr_vector data; Json::Value::Members members(object.getMemberNames()); for (Json::Value::Members::iterator it = members.begin(), end = members.end(); it != end; ++it) { - const std::string& name = *it; - const Json::Value& value = object[name]; + const std::string& fieldName = *it; + const Json::Value& value = object[fieldName]; - SField::ref field = SField::getField(name); + SField::ref field = SField::getField(fieldName); if (field == sfInvalid) - throw std::runtime_error("Unknown field: " + name); + throw std::runtime_error("Unknown field: " + fieldName); switch (field.fieldType) { @@ -846,20 +850,31 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r if (value.isString()) { std::string strValue = value.asString(); - if (!strValue.empty() && (strValue[0]<'0' || strValue[0]>'9')) + if (!strValue.empty() && ((strValue[0] < '0') || (strValue[0] > '9'))) { if (field == sfTransactionType) { - // WRITEME + TransactionFormat* f = getTxnFormat(strValue); + if (!f) + throw std::runtime_error("Unknown transaction type"); + data.push_back(new STUInt16(field, static_cast(f->t_type))); + if (*name == sfGeneric) + name = &sfTransaction; } else if (field == sfLedgerEntryType) { - // WRITEME + LedgerEntryFormat* f = getLgrFormat(strValue); + if (!f) + throw std::runtime_error("Unknown ledger entry type"); + data.push_back(new STUInt16(field, static_cast(f->t_type))); + if (*name == sfGeneric) + name = &sfLedgerEntry; } else throw std::runtime_error("Invalid field data"); } - data.push_back(new STUInt16(field, boost::lexical_cast(strValue))); + else + data.push_back(new STUInt16(field, boost::lexical_cast(strValue))); } else if (value.isInt()) data.push_back(new STUInt16(field, boost::lexical_cast(value.asInt()))); @@ -893,13 +908,25 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r case STI_HASH128: - // WRITEME + if (value.isString()) + data.push_back(new STHash128(field, value.asString())); + else + throw std::runtime_error("Incorrect type"); + break; case STI_HASH160: - // WRITEME + if (value.isString()) + data.push_back(new STHash160(field, value.asString())); + else + throw std::runtime_error("Incorrect type"); + break; case STI_HASH256: - // WRITEME + if (value.isString()) + data.push_back(new STHash256(field, value.asString())); + else + throw std::runtime_error("Incorrect type"); + break; case STI_VL: // WRITEME @@ -932,7 +959,7 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r throw std::runtime_error("Invalid field type"); } } - return std::auto_ptr(new STObject(name, data)); + return std::auto_ptr(new STObject(*name, data)); } #if 0 diff --git a/src/SerializedObject.h b/src/SerializedObject.h index a60a3efba2..5255c463ef 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -41,7 +41,7 @@ public: STObject(SOElement::ptrList type, SerializerIterator& sit, SField::ref name) : SerializedType(name) { set(sit); setType(type); } - static std::auto_ptr parseJson(const Json::Value& value, SField::ref name, int depth = 0); + static std::auto_ptr parseJson(const Json::Value& value, SField::ref name = sfGeneric, int depth = 0); virtual ~STObject() { ; } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 246e4cde1f..046c39e52b 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -377,6 +377,8 @@ public: STHash128(const uint128& v) : value(v) { ; } STHash128(SField::ref n, const uint128& v) : SerializedType(n), value(v) { ; } + STHash128(SField::ref n, const char *v) : SerializedType(n) { value.SetHex(v); } + STHash128(SField::ref n, const std::string &v) : SerializedType(n) { value.SetHex(v); } STHash128(SField::ref n) : SerializedType(n) { ; } STHash128() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) @@ -405,6 +407,8 @@ public: STHash160(const uint160& v) : value(v) { ; } STHash160(SField::ref n, const uint160& v) : SerializedType(n), value(v) { ; } + STHash160(SField::ref n, const char *v) : SerializedType(n) { value.SetHex(v); } + STHash160(SField::ref n, const std::string &v) : SerializedType(n) { value.SetHex(v); } STHash160(SField::ref n) : SerializedType(n) { ; } STHash160() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) @@ -433,6 +437,8 @@ public: STHash256(const uint256& v) : value(v) { ; } STHash256(SField::ref n, const uint256& v) : SerializedType(n), value(v) { ; } + STHash256(SField::ref n, const char *v) : SerializedType(n) { value.SetHex(v); } + STHash256(SField::ref n, const std::string &v) : SerializedType(n) { value.SetHex(v); } STHash256(SField::ref n) : SerializedType(n) { ; } STHash256() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index cebc37a49c..12d614de2d 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -10,7 +10,7 @@ { sfSigningPubKey, SOE_REQUIRED }, \ { sfTxnSignature, SOE_OPTIONAL }, -TransactionFormat InnerTxnFormats[]= +TransactionFormat TxnFormats[]= { { "AccountSet", ttACCOUNT_SET, { TF_BASE { sfEmailHash, SOE_OPTIONAL }, @@ -30,7 +30,7 @@ TransactionFormat InnerTxnFormats[]= }, { "CreditSet", ttCREDIT_SET, { TF_BASE { sfLimitAmount, SOE_OPTIONAL }, - { sfQualityIn, SOE_OPTIONAL }, + { sfQualityIn, SOE_OPTIONAL }, { sfQualityOut, SOE_OPTIONAL }, { sfInvalid, SOE_END } } }, @@ -107,13 +107,18 @@ TransactionFormat* getTxnFormat(TransactionType t) TransactionFormat* getTxnFormat(int t) { - TransactionFormat* f = InnerTxnFormats; - while (f->t_name != NULL) - { - if (f->t_type == t) + for (TransactionFormat* f = TxnFormats; f->t_name != NULL; ++f) + if (t == f->t_type) return f; - ++f; - } return NULL; } + +TransactionFormat* getTxnFormat(const std::string& format) +{ + for (TransactionFormat* f = TxnFormats; f->t_name != NULL; ++f) + if (format == f->t_name) + return f; + return NULL; +} + // vim:ts=4 diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index 57b155285f..dd385bad59 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -44,8 +44,9 @@ const uint32 tfPartialPayment = 0x00020000; const uint32 tfLimitQuality = 0x00040000; const uint32 tfNoRippleDirect = 0x00080000; -extern TransactionFormat InnerTxnFormats[]; +extern TransactionFormat TxnFormats[]; extern TransactionFormat* getTxnFormat(TransactionType t); +extern TransactionFormat* getTxnFormat(const std::string& t); extern TransactionFormat* getTxnFormat(int t); #endif // vim:ts=4 From e2c257f50bfeb34fbd741eff93efdcb4de48b434 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 1 Oct 2012 20:09:24 -0700 Subject: [PATCH 408/426] Fix a bug Jed reported. More JSON work. Redo format layouts. --- src/FieldNames.h | 2 +- src/LedgerFormats.cpp | 194 ++++++++++++++-------------- src/LedgerFormats.h | 31 +++-- src/SerializedLedger.cpp | 6 +- src/SerializedObject.cpp | 60 +++++---- src/SerializedObject.h | 11 +- src/SerializedTransaction.cpp | 4 +- src/SerializedTypes.cpp | 4 +- src/SerializedValidation.cpp | 25 ++-- src/SerializedValidation.h | 1 - src/TransactionFormats.cpp | 230 ++++++++++++++++++---------------- src/TransactionFormats.h | 31 +++-- 12 files changed, 335 insertions(+), 264 deletions(-) diff --git a/src/FieldNames.h b/src/FieldNames.h index ed51006499..784900c148 100644 --- a/src/FieldNames.h +++ b/src/FieldNames.h @@ -28,7 +28,7 @@ enum SerializedTypeID enum SOE_Flags { - SOE_END = -1, // marks end of object + SOE_INVALID = -1, SOE_REQUIRED = 0, // required SOE_OPTIONAL = 1, // optional }; diff --git a/src/LedgerFormats.cpp b/src/LedgerFormats.cpp index 56c8a39a21..c696d72ed2 100644 --- a/src/LedgerFormats.cpp +++ b/src/LedgerFormats.cpp @@ -1,106 +1,118 @@ #include "LedgerFormats.h" -#define LEF_BASE \ - { sfLedgerIndex, SOE_OPTIONAL }, \ - { sfLedgerEntryType, SOE_REQUIRED }, \ - { sfFlags, SOE_REQUIRED }, +std::map LedgerEntryFormat::byType; +std::map LedgerEntryFormat::byName; -LedgerEntryFormat LedgerFormats[]= -{ - { "AccountRoot", ltACCOUNT_ROOT, { LEF_BASE - { sfAccount, SOE_REQUIRED }, - { sfSequence, SOE_REQUIRED }, - { sfBalance, SOE_REQUIRED }, - { sfLastTxnID, SOE_REQUIRED }, - { sfLastTxnSeq, SOE_REQUIRED }, - { sfAuthorizedKey, SOE_OPTIONAL }, - { sfEmailHash, SOE_OPTIONAL }, - { sfWalletLocator, SOE_OPTIONAL }, - { sfMessageKey, SOE_OPTIONAL }, - { sfTransferRate, SOE_OPTIONAL }, - { sfDomain, SOE_OPTIONAL }, - { sfPublishHash, SOE_OPTIONAL }, - { sfPublishSize, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "Contract", ltCONTRACT, { LEF_BASE - { sfAccount, SOE_REQUIRED }, - { sfBalance, SOE_REQUIRED }, - { sfLastTxnID, SOE_REQUIRED }, - { sfLastTxnSeq, SOE_REQUIRED }, - { sfIssuer, SOE_REQUIRED }, - { sfOwner, SOE_REQUIRED }, - { sfExpiration, SOE_REQUIRED }, - { sfBondAmount, SOE_REQUIRED }, - { sfCreateCode, SOE_REQUIRED }, - { sfFundCode, SOE_REQUIRED }, - { sfRemoveCode, SOE_REQUIRED }, - { sfExpireCode, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "DirectoryNode", ltDIR_NODE, { LEF_BASE - { sfIndexes, SOE_REQUIRED }, - { sfIndexNext, SOE_OPTIONAL }, - { sfIndexPrevious, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "GeneratorMap", ltGENERATOR_MAP, { LEF_BASE - { sfGenerator, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "Nickname", ltNICKNAME, { LEF_BASE - { sfAccount, SOE_REQUIRED }, - { sfMinimumOffer, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "Offer", ltOFFER, { LEF_BASE - { sfAccount, SOE_REQUIRED }, - { sfSequence, SOE_REQUIRED }, - { sfTakerPays, SOE_REQUIRED }, - { sfTakerGets, SOE_REQUIRED }, - { sfBookDirectory, SOE_REQUIRED }, - { sfBookNode, SOE_REQUIRED }, - { sfOwnerNode, SOE_REQUIRED }, - { sfLastTxnID, SOE_REQUIRED }, - { sfLastTxnSeq, SOE_REQUIRED }, - { sfExpiration, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "RippleState", ltRIPPLE_STATE, { LEF_BASE - { sfBalance, SOE_REQUIRED }, - { sfLowLimit, SOE_REQUIRED }, - { sfHighLimit, SOE_REQUIRED }, - { sfLastTxnID, SOE_REQUIRED }, - { sfLastTxnSeq, SOE_REQUIRED }, - { sfLowQualityIn, SOE_OPTIONAL }, - { sfLowQualityOut, SOE_OPTIONAL }, - { sfHighQualityIn, SOE_OPTIONAL }, - { sfHighQualityOut, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { NULL, ltINVALID } -}; +#define LEF_BASE \ + << SOElement(sfLedgerIndex, SOE_OPTIONAL) \ + << SOElement(sfLedgerEntryType, SOE_REQUIRED) \ + << SOElement(sfFlags, SOE_REQUIRED) -LedgerEntryFormat* getLgrFormat(LedgerEntryType t) +#define DECLARE_LEF(name, type) lef = new LedgerEntryFormat(#name, type); (*lef) LEF_BASE + +static bool LEFInit() { - return getLgrFormat(static_cast(t)); + LedgerEntryFormat* lef; + + DECLARE_LEF(AccountRoot, ltACCOUNT_ROOT) + << SOElement(sfAccount, SOE_REQUIRED) + << SOElement(sfSequence, SOE_REQUIRED) + << SOElement(sfBalance, SOE_REQUIRED) + << SOElement(sfLastTxnID, SOE_REQUIRED) + << SOElement(sfLastTxnSeq, SOE_REQUIRED) + << SOElement(sfAuthorizedKey, SOE_OPTIONAL) + << SOElement(sfEmailHash, SOE_OPTIONAL) + << SOElement(sfWalletLocator, SOE_OPTIONAL) + << SOElement(sfMessageKey, SOE_OPTIONAL) + << SOElement(sfTransferRate, SOE_OPTIONAL) + << SOElement(sfDomain, SOE_OPTIONAL) + << SOElement(sfPublishHash, SOE_OPTIONAL) + << SOElement(sfPublishSize, SOE_OPTIONAL) + ; + + DECLARE_LEF(Contract, ltCONTRACT) + << SOElement(sfAccount, SOE_REQUIRED) + << SOElement(sfBalance, SOE_REQUIRED) + << SOElement(sfLastTxnID, SOE_REQUIRED) + << SOElement(sfLastTxnSeq, SOE_REQUIRED) + << SOElement(sfIssuer, SOE_REQUIRED) + << SOElement(sfOwner, SOE_REQUIRED) + << SOElement(sfExpiration, SOE_REQUIRED) + << SOElement(sfBondAmount, SOE_REQUIRED) + << SOElement(sfCreateCode, SOE_REQUIRED) + << SOElement(sfFundCode, SOE_REQUIRED) + << SOElement(sfRemoveCode, SOE_REQUIRED) + << SOElement(sfExpireCode, SOE_REQUIRED) + ; + + DECLARE_LEF(DirectoryNode, ltDIR_NODE) + << SOElement(sfIndexes, SOE_REQUIRED) + << SOElement(sfIndexNext, SOE_OPTIONAL) + << SOElement(sfIndexPrevious, SOE_OPTIONAL) + ; + + DECLARE_LEF(GeneratorMap, ltGENERATOR_MAP) + << SOElement(sfGenerator, SOE_REQUIRED) + ; + + DECLARE_LEF(Nickname, ltNICKNAME) + << SOElement(sfAccount, SOE_REQUIRED) + << SOElement(sfMinimumOffer, SOE_OPTIONAL) + ; + + DECLARE_LEF(Offer, ltOFFER) + << SOElement(sfAccount, SOE_REQUIRED) + << SOElement(sfSequence, SOE_REQUIRED) + << SOElement(sfTakerPays, SOE_REQUIRED) + << SOElement(sfTakerGets, SOE_REQUIRED) + << SOElement(sfBookDirectory, SOE_REQUIRED) + << SOElement(sfBookNode, SOE_REQUIRED) + << SOElement(sfOwnerNode, SOE_REQUIRED) + << SOElement(sfLastTxnID, SOE_REQUIRED) + << SOElement(sfLastTxnSeq, SOE_REQUIRED) + << SOElement(sfExpiration, SOE_OPTIONAL) + ; + + DECLARE_LEF(RippleState, ltRIPPLE_STATE) + << SOElement(sfBalance, SOE_REQUIRED) + << SOElement(sfLowLimit, SOE_REQUIRED) + << SOElement(sfHighLimit, SOE_REQUIRED) + << SOElement(sfLastTxnID, SOE_REQUIRED) + << SOElement(sfLastTxnSeq, SOE_REQUIRED) + << SOElement(sfLowQualityIn, SOE_OPTIONAL) + << SOElement(sfLowQualityOut, SOE_OPTIONAL) + << SOElement(sfHighQualityIn, SOE_OPTIONAL) + << SOElement(sfHighQualityOut, SOE_OPTIONAL) + ; + + return true; } -LedgerEntryFormat* getLgrFormat(int t) +bool LEFInitComplete = LEFInit(); + +LedgerEntryFormat* LedgerEntryFormat::getLgrFormat(LedgerEntryType t) { - for (LedgerEntryFormat* f = LedgerFormats; f->t_name != NULL; ++f) - if (f->t_type == t) - return f; - return NULL; + std::map::iterator it = byType.find(static_cast(t)); + if (it == byType.end()) + return NULL; + return it->second; } -LedgerEntryFormat* getLgrFormat(const std::string& t) +LedgerEntryFormat* LedgerEntryFormat::getLgrFormat(int t) { - for (LedgerEntryFormat* f = LedgerFormats; f->t_name != NULL; ++f) - if (t == f->t_name) - return f; - return NULL; + std::map::iterator it = byType.find((t)); + if (it == byType.end()) + return NULL; + return it->second; +} + +LedgerEntryFormat* LedgerEntryFormat::getLgrFormat(const std::string& t) +{ + std::map::iterator it = byName.find((t)); + if (it == byName.end()) + return NULL; + return it->second; } // vim:ts=4 diff --git a/src/LedgerFormats.h b/src/LedgerFormats.h index 348116880d..947cb65be5 100644 --- a/src/LedgerFormats.h +++ b/src/LedgerFormats.h @@ -39,16 +39,31 @@ enum LedgerSpecificFlags lsfPassive = 0x00010000, }; -struct LedgerEntryFormat +class LedgerEntryFormat { - const char * t_name; - LedgerEntryType t_type; - SOElement elements[24]; +public: + std::string t_name; + LedgerEntryType t_type; + std::vector elements; + + static std::map byType; + static std::map byName; + + LedgerEntryFormat(const char *name, LedgerEntryType type) : t_name(name), t_type(type) + { + byName[name] = this; + byType[type] = this; + } + LedgerEntryFormat& operator<<(const SOElement& el) + { + elements.push_back(new SOElement(el)); + return *this; + } + + static LedgerEntryFormat* getLgrFormat(LedgerEntryType t); + static LedgerEntryFormat* getLgrFormat(const std::string& t); + static LedgerEntryFormat* getLgrFormat(int t); }; -extern LedgerEntryFormat LedgerFormats[]; -extern LedgerEntryFormat* getLgrFormat(LedgerEntryType t); -extern LedgerEntryFormat* getLgrFormat(const std::string& t); -extern LedgerEntryFormat* getLgrFormat(int t); #endif // vim:ts=4 diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 9a57267eb3..acc58da3c1 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -10,7 +10,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint { set(sit); uint16 type = getFieldU16(sfLedgerEntryType); - mFormat = getLgrFormat(static_cast(type)); + mFormat = LedgerEntryFormat::getLgrFormat(static_cast(type)); if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); mType = mFormat->t_type; @@ -25,7 +25,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& set(sit); uint16 type = getFieldU16(sfLedgerEntryType); - mFormat = getLgrFormat(static_cast(type)); + mFormat = LedgerEntryFormat::getLgrFormat(static_cast(type)); if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); mType = mFormat->t_type; @@ -39,7 +39,7 @@ SerializedLedgerEntry::SerializedLedgerEntry(const Serializer& s, const uint256& SerializedLedgerEntry::SerializedLedgerEntry(LedgerEntryType type) : STObject(sfLedgerEntry), mType(type) { - mFormat = getLgrFormat(type); + mFormat = LedgerEntryFormat::getLgrFormat(type); if (mFormat == NULL) throw std::runtime_error("invalid ledger entry type"); set(mFormat->elements); setFieldU16(sfLedgerEntryType, static_cast(mFormat->t_type)); diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 7584d53dc5..2b9ee828e6 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -116,33 +116,32 @@ std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID } } -void STObject::set(SOElement::ptr elem) +void STObject::set(const std::vector& type) { mData.empty(); mType.empty(); - while (elem->flags != SOE_END) + BOOST_FOREACH(const SOElement::ptr& elem, type) { mType.push_back(elem); if (elem->flags == SOE_OPTIONAL) giveObject(makeNonPresentObject(elem->e_field)); else giveObject(makeDefaultObject(elem->e_field)); - ++elem; } } -bool STObject::setType(SOElement::ptrList t) +bool STObject::setType(const std::vector &type) { boost::ptr_vector newData; bool valid = true; mType.empty(); - while (t->flags != SOE_END) + BOOST_FOREACH(const SOElement::ptr& elem, type) { bool match = false; for (boost::ptr_vector::iterator it = mData.begin(); it != mData.end(); ++it) - if (it->getFName() == t->e_field) + if (it->getFName() == elem->e_field) { match = true; newData.push_back(mData.release(it).release()); @@ -151,15 +150,15 @@ bool STObject::setType(SOElement::ptrList t) if (!match) { - if (t->flags != SOE_OPTIONAL) + if (elem->flags != SOE_OPTIONAL) { Log(lsTRACE) << "setType !valid missing"; valid = false; } - newData.push_back(makeNonPresentObject(t->e_field)); + newData.push_back(makeNonPresentObject(elem->e_field)); } - mType.push_back(t++); + mType.push_back(elem); } if (mData.size() != 0) { @@ -742,7 +741,7 @@ Json::Value STObject::getJson(int options) const if (it.getSType() != STI_NOTPRESENT) { if (!it.getFName().hasName()) - ret[boost::lexical_cast(index)] = it.getJson(options); + ret[lexical_cast_i(index)] = it.getJson(options); else ret[it.getName()] = it.getJson(options); } @@ -837,11 +836,19 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r { case STI_UINT8: if (value.isString()) - data.push_back(new STUInt8(field, boost::lexical_cast(value.asString()))); - else if (value.isInt()) - data.push_back(new STUInt8(field, boost::lexical_cast(value.asInt()))); + data.push_back(new STUInt8(field, lexical_cast_s(value.asString()))); + else if (value.isInt()) + { + if (value.asInt() < 0 || value.asInt() > 255) + throw std::runtime_error("value out of rand"); + data.push_back(new STUInt8(field, static_cast(value.asInt()))); + } else if (value.isUInt()) - data.push_back(new STUInt8(field, boost::lexical_cast(value.asUInt()))); + { + if (value.asUInt() > 255) + throw std::runtime_error("value out of rand"); + data.push_back(new STUInt8(field, static_cast(value.asUInt()))); + } else throw std::runtime_error("Incorrect type"); break; @@ -854,7 +861,7 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r { if (field == sfTransactionType) { - TransactionFormat* f = getTxnFormat(strValue); + TransactionFormat* f = TransactionFormat::getTxnFormat(strValue); if (!f) throw std::runtime_error("Unknown transaction type"); data.push_back(new STUInt16(field, static_cast(f->t_type))); @@ -863,7 +870,7 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r } else if (field == sfLedgerEntryType) { - LedgerEntryFormat* f = getLgrFormat(strValue); + LedgerEntryFormat* f = LedgerEntryFormat::getLgrFormat(strValue); if (!f) throw std::runtime_error("Unknown ledger entry type"); data.push_back(new STUInt16(field, static_cast(f->t_type))); @@ -874,34 +881,34 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r throw std::runtime_error("Invalid field data"); } else - data.push_back(new STUInt16(field, boost::lexical_cast(strValue))); + data.push_back(new STUInt16(field, lexical_cast_s(strValue))); } else if (value.isInt()) - data.push_back(new STUInt16(field, boost::lexical_cast(value.asInt()))); + data.push_back(new STUInt16(field, static_cast(value.asInt()))); else if (value.isUInt()) - data.push_back(new STUInt16(field, boost::lexical_cast(value.asUInt()))); + data.push_back(new STUInt16(field, static_cast(value.asUInt()))); else throw std::runtime_error("Incorrect type"); break; case STI_UINT32: if (value.isString()) - data.push_back(new STUInt32(field, boost::lexical_cast(value.asString()))); + data.push_back(new STUInt32(field, lexical_cast_s(value.asString()))); else if (value.isInt()) - data.push_back(new STUInt32(field, boost::lexical_cast(value.asInt()))); + data.push_back(new STUInt32(field, static_cast(value.asInt()))); else if (value.isUInt()) - data.push_back(new STUInt32(field, boost::lexical_cast(value.asUInt()))); + data.push_back(new STUInt32(field, static_cast(value.asUInt()))); else throw std::runtime_error("Incorrect type"); break; case STI_UINT64: if (value.isString()) - data.push_back(new STUInt64(field, boost::lexical_cast(value.asString()))); + data.push_back(new STUInt64(field, lexical_cast_s(value.asString()))); else if (value.isInt()) - data.push_back(new STUInt64(field, boost::lexical_cast(value.asInt()))); + data.push_back(new STUInt64(field, static_cast(value.asInt()))); else if (value.isUInt()) - data.push_back(new STUInt64(field, boost::lexical_cast(value.asUInt()))); + data.push_back(new STUInt64(field, static_cast(value.asUInt()))); else throw std::runtime_error("Incorrect type"); break; @@ -929,7 +936,10 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r break; case STI_VL: + { // WRITEME + } + break; case STI_AMOUNT: // WRITEME diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 5255c463ef..6de71dcbf5 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -15,10 +15,11 @@ class SOElement { // An element in the description of a serialized object public: typedef SOElement const * ptr; // used to point to one element - typedef SOElement const * ptrList; // used to point to a terminated list of elements SField::ref e_field; const SOE_Flags flags; + + SOElement(SField::ref fi, SOE_Flags fl) : e_field(fi), flags(fl) { ; } }; class STObject : public SerializedType @@ -35,10 +36,10 @@ public: STObject(SField::ref name) : SerializedType(name) { ; } - STObject(SOElement::ptrList type, SField::ref name) : SerializedType(name) + STObject(const std::vector& type, SField::ref name) : SerializedType(name) { set(type); } - STObject(SOElement::ptrList type, SerializerIterator& sit, SField::ref name) : SerializedType(name) + STObject(const std::vector& type, SerializerIterator& sit, SField::ref name) : SerializedType(name) { set(sit); setType(type); } static std::auto_ptr parseJson(const Json::Value& value, SField::ref name = sfGeneric, int depth = 0); @@ -47,11 +48,11 @@ public: static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name); - bool setType(SOElement::ptrList); + bool setType(const std::vector& type); bool isValidForType(); bool isFieldAllowed(SField::ref); - void set(SOElement::ptrList); + void set(const std::vector&); bool set(SerializerIterator& u, int depth = 0); virtual SerializedTypeID getSType() const { return STI_OBJECT; } diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index 3c3643ea3e..617125c02e 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -9,7 +9,7 @@ SerializedTransaction::SerializedTransaction(TransactionType type) : STObject(sfTransaction), mType(type) { - mFormat = getTxnFormat(type); + mFormat = TransactionFormat::getTxnFormat(type); if (mFormat == NULL) throw std::runtime_error("invalid transaction type"); set(mFormat->elements); @@ -28,7 +28,7 @@ SerializedTransaction::SerializedTransaction(SerializerIterator& sit) : STObject set(sit); mType = static_cast(getFieldU16(sfTransactionType)); - mFormat = getTxnFormat(mType); + mFormat = TransactionFormat::getTxnFormat(mType); if (!mFormat) throw std::runtime_error("invalid transaction type"); if (!setType(mFormat->elements)) diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 4cee5f5c9b..f4853a82e8 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -54,13 +54,13 @@ std::string STUInt16::getText() const { if (getFName() == sfLedgerEntryType) { - LedgerEntryFormat *f = getLgrFormat(value); + LedgerEntryFormat *f = LedgerEntryFormat::getLgrFormat(value); if (f != NULL) return f->t_name; } if (getFName() == sfTransactionType) { - TransactionFormat *f = getTxnFormat(value); + TransactionFormat *f = TransactionFormat::getTxnFormat(value); if (f != NULL) return f->t_name; } diff --git a/src/SerializedValidation.cpp b/src/SerializedValidation.cpp index 0a937c8d18..84b40eb8ac 100644 --- a/src/SerializedValidation.cpp +++ b/src/SerializedValidation.cpp @@ -3,18 +3,23 @@ #include "HashPrefixes.h" -SOElement SerializedValidation::sValidationFormat[] = { - { sfFlags, SOE_REQUIRED }, - { sfLedgerHash, SOE_REQUIRED }, - { sfLedgerSequence, SOE_OPTIONAL }, - { sfCloseTime, SOE_OPTIONAL }, - { sfLoadFee, SOE_OPTIONAL }, - { sfBaseFee, SOE_OPTIONAL }, - { sfSigningTime, SOE_REQUIRED }, - { sfSigningPubKey, SOE_REQUIRED }, - { sfInvalid, SOE_END } +std::vector sValidationFormat; + +static bool SVFInit() +{ + sValidationFormat.push_back(new SOElement(sfFlags, SOE_REQUIRED)); + sValidationFormat.push_back(new SOElement(sfLedgerHash, SOE_REQUIRED)); + sValidationFormat.push_back(new SOElement(sfLedgerSequence, SOE_OPTIONAL)); + sValidationFormat.push_back(new SOElement(sfCloseTime, SOE_OPTIONAL)); + sValidationFormat.push_back(new SOElement(sfLoadFee, SOE_OPTIONAL)); + sValidationFormat.push_back(new SOElement(sfBaseFee, SOE_OPTIONAL)); + sValidationFormat.push_back(new SOElement(sfSigningTime, SOE_REQUIRED)); + sValidationFormat.push_back(new SOElement(sfSigningPubKey, SOE_REQUIRED)); + return true; }; +bool SVFinitComplete = SVFInit(); + const uint32 SerializedValidation::sFullFlag = 0x00010000; SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSignature) diff --git a/src/SerializedValidation.h b/src/SerializedValidation.h index 299c35a0ed..c76b233c54 100644 --- a/src/SerializedValidation.h +++ b/src/SerializedValidation.h @@ -17,7 +17,6 @@ public: typedef boost::shared_ptr pointer; typedef const boost::shared_ptr& ref; - static SOElement sValidationFormat[16]; static const uint32 sFullFlag; // These throw if the object is not valid diff --git a/src/TransactionFormats.cpp b/src/TransactionFormats.cpp index 12d614de2d..32c7caa714 100644 --- a/src/TransactionFormats.cpp +++ b/src/TransactionFormats.cpp @@ -1,124 +1,138 @@ #include "TransactionFormats.h" -#define TF_BASE \ - { sfTransactionType, SOE_REQUIRED }, \ - { sfFlags, SOE_REQUIRED }, \ - { sfSourceTag, SOE_OPTIONAL }, \ - { sfAccount, SOE_REQUIRED }, \ - { sfSequence, SOE_REQUIRED }, \ - { sfFee, SOE_REQUIRED }, \ - { sfSigningPubKey, SOE_REQUIRED }, \ - { sfTxnSignature, SOE_OPTIONAL }, +std::map TransactionFormat::byType; +std::map TransactionFormat::byName; -TransactionFormat TxnFormats[]= +#define TF_BASE \ + << SOElement(sfTransactionType, SOE_REQUIRED) \ + << SOElement(sfFlags, SOE_REQUIRED) \ + << SOElement(sfSourceTag, SOE_OPTIONAL) \ + << SOElement(sfAccount, SOE_REQUIRED) \ + << SOElement(sfSequence, SOE_REQUIRED) \ + << SOElement(sfFee, SOE_REQUIRED) \ + << SOElement(sfSigningPubKey, SOE_REQUIRED) \ + << SOElement(sfTxnSignature, SOE_OPTIONAL) + +#define DECLARE_TF(name, type) tf = new TransactionFormat(#name, type); (*tf) TF_BASE + +static bool TFInit() { - { "AccountSet", ttACCOUNT_SET, { TF_BASE - { sfEmailHash, SOE_OPTIONAL }, - { sfWalletLocator, SOE_OPTIONAL }, - { sfMessageKey, SOE_OPTIONAL }, - { sfDomain, SOE_OPTIONAL }, - { sfTransferRate, SOE_OPTIONAL }, - { sfPublishHash, SOE_OPTIONAL }, - { sfPublishSize, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "Claim", ttCLAIM, { TF_BASE - { sfGenerator, SOE_REQUIRED }, - { sfPublicKey, SOE_REQUIRED }, - { sfSignature, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "CreditSet", ttCREDIT_SET, { TF_BASE - { sfLimitAmount, SOE_OPTIONAL }, - { sfQualityIn, SOE_OPTIONAL }, - { sfQualityOut, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, + TransactionFormat* tf; + + DECLARE_TF(AccountSet, ttACCOUNT_SET) + << SOElement(sfEmailHash, SOE_OPTIONAL) + << SOElement(sfWalletLocator, SOE_OPTIONAL) + << SOElement(sfMessageKey, SOE_OPTIONAL) + << SOElement(sfDomain, SOE_OPTIONAL) + << SOElement(sfTransferRate, SOE_OPTIONAL) + << SOElement(sfPublishHash, SOE_OPTIONAL) + << SOElement(sfPublishSize, SOE_OPTIONAL) + ; + + DECLARE_TF(Claim, ttCLAIM) + << SOElement(sfGenerator, SOE_REQUIRED) + << SOElement(sfPublicKey, SOE_REQUIRED) + << SOElement(sfSignature, SOE_REQUIRED) + ; + + DECLARE_TF(CreditSet, ttCREDIT_SET) + << SOElement(sfLimitAmount, SOE_OPTIONAL) + << SOElement(sfQualityIn, SOE_OPTIONAL) + << SOElement(sfQualityOut, SOE_OPTIONAL) + ; + + /* - { "Invoice", ttINVOICE, { TF_BASE - { sfTarget, SOE_REQUIRED }, - { sfAmount, SOE_REQUIRED }, - { sfDestination, SOE_OPTIONAL }, - { sfIdentifier, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, + DECLARE_TF(Invoice, ttINVOICE) + << SOElement(sfTarget, SOE_REQUIRED) + << SOElement(sfAmount, SOE_REQUIRED) + << SOElement(sfDestination, SOE_OPTIONAL) + << SOElement(sfIdentifier, SOE_OPTIONAL) + ; + ) */ - { "NicknameSet", ttNICKNAME_SET, { TF_BASE - { sfNickname, SOE_REQUIRED }, - { sfMinimumOffer, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "OfferCreate", ttOFFER_CREATE, { TF_BASE - { sfTakerPays, SOE_REQUIRED }, - { sfTakerGets, SOE_REQUIRED }, - { sfExpiration, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "OfferCancel", ttOFFER_CANCEL, { TF_BASE - { sfOfferSequence, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "PasswordFund", ttPASSWORD_FUND, { TF_BASE - { sfDestination, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "PasswordSet", ttPASSWORD_SET, { TF_BASE - { sfAuthorizedKey, SOE_REQUIRED }, - { sfGenerator, SOE_REQUIRED }, - { sfPublicKey, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "Payment", ttPAYMENT, { TF_BASE - { sfDestination, SOE_REQUIRED }, - { sfAmount, SOE_REQUIRED }, - { sfSendMax, SOE_OPTIONAL }, - { sfPaths, SOE_OPTIONAL }, - { sfInvoiceID, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "WalletAdd", ttWALLET_ADD, { TF_BASE - { sfAmount, SOE_REQUIRED }, - { sfAuthorizedKey, SOE_REQUIRED }, - { sfPublicKey, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { "Contract", ttCONTRACT, { TF_BASE - { sfExpiration, SOE_REQUIRED }, - { sfBondAmount, SOE_REQUIRED }, - { sfStampEscrow, SOE_REQUIRED }, - { sfRippleEscrow, SOE_REQUIRED }, - { sfCreateCode, SOE_OPTIONAL }, - { sfFundCode, SOE_OPTIONAL }, - { sfRemoveCode, SOE_OPTIONAL }, - { sfExpireCode, SOE_OPTIONAL }, - { sfInvalid, SOE_END } } - }, - { "RemoveContract", ttCONTRACT_REMOVE, { TF_BASE - { sfTarget, SOE_REQUIRED }, - { sfInvalid, SOE_END } } - }, - { NULL, ttINVALID } -}; -TransactionFormat* getTxnFormat(TransactionType t) -{ - return getTxnFormat(static_cast(t)); + DECLARE_TF(NicknameSet, ttNICKNAME_SET) + << SOElement(sfNickname, SOE_REQUIRED) + << SOElement(sfMinimumOffer, SOE_OPTIONAL) + ; + + DECLARE_TF(OfferCreate, ttOFFER_CREATE) + << SOElement(sfTakerPays, SOE_REQUIRED) + << SOElement(sfTakerGets, SOE_REQUIRED) + << SOElement(sfExpiration, SOE_OPTIONAL) + ; + + DECLARE_TF(OfferCancel, ttOFFER_CANCEL) + << SOElement(sfOfferSequence, SOE_REQUIRED) + ; + + DECLARE_TF(PasswordFund, ttPASSWORD_FUND) + << SOElement(sfDestination, SOE_REQUIRED) + ; + + DECLARE_TF(PasswordSet, ttPASSWORD_SET) + << SOElement(sfAuthorizedKey, SOE_REQUIRED) + << SOElement(sfGenerator, SOE_REQUIRED) + << SOElement(sfPublicKey, SOE_REQUIRED) + ; + + DECLARE_TF(Payment, ttPAYMENT) + << SOElement(sfDestination, SOE_REQUIRED) + << SOElement(sfAmount, SOE_REQUIRED) + << SOElement(sfSendMax, SOE_OPTIONAL) + << SOElement(sfPaths, SOE_OPTIONAL) + << SOElement(sfInvoiceID, SOE_OPTIONAL) + ; + + DECLARE_TF(WalletAdd, ttWALLET_ADD) + << SOElement(sfAmount, SOE_REQUIRED) + << SOElement(sfAuthorizedKey, SOE_REQUIRED) + << SOElement(sfPublicKey, SOE_REQUIRED) + ; + + DECLARE_TF(Contract, ttCONTRACT) + << SOElement(sfExpiration, SOE_REQUIRED) + << SOElement(sfBondAmount, SOE_REQUIRED) + << SOElement(sfStampEscrow, SOE_REQUIRED) + << SOElement(sfRippleEscrow, SOE_REQUIRED) + << SOElement(sfCreateCode, SOE_OPTIONAL) + << SOElement(sfFundCode, SOE_OPTIONAL) + << SOElement(sfRemoveCode, SOE_OPTIONAL) + << SOElement(sfExpireCode, SOE_OPTIONAL) + ; + + DECLARE_TF(RemoveContract, ttCONTRACT_REMOVE) + << SOElement(sfTarget, SOE_REQUIRED) + ; + + return true; } -TransactionFormat* getTxnFormat(int t) +bool TFInitComplete = TFInit(); + +TransactionFormat* TransactionFormat::getTxnFormat(TransactionType t) { - for (TransactionFormat* f = TxnFormats; f->t_name != NULL; ++f) - if (t == f->t_type) - return f; - return NULL; + std::map::iterator it = byType.find(static_cast(t)); + if (it == byType.end()) + return NULL; + return it->second; } -TransactionFormat* getTxnFormat(const std::string& format) +TransactionFormat* TransactionFormat::getTxnFormat(int t) { - for (TransactionFormat* f = TxnFormats; f->t_name != NULL; ++f) - if (format == f->t_name) - return f; - return NULL; + std::map::iterator it = byType.find((t)); + if (it == byType.end()) + return NULL; + return it->second; +} + +TransactionFormat* TransactionFormat::getTxnFormat(const std::string& t) +{ + std::map::iterator it = byName.find((t)); + if (it == byName.end()) + return NULL; + return it->second; } // vim:ts=4 diff --git a/src/TransactionFormats.h b/src/TransactionFormats.h index dd385bad59..857a43189c 100644 --- a/src/TransactionFormats.h +++ b/src/TransactionFormats.h @@ -21,11 +21,30 @@ enum TransactionType ttCREDIT_SET = 20, }; -struct TransactionFormat +class TransactionFormat { - const char * t_name; - TransactionType t_type; - SOElement elements[24]; +public: + std::string t_name; + TransactionType t_type; + std::vector elements; + + static std::map byType; + static std::map byName; + + TransactionFormat(const char *name, TransactionType type) : t_name(name), t_type(type) + { + byName[name] = this; + byType[type] = this; + } + TransactionFormat& operator<<(const SOElement& el) + { + elements.push_back(new SOElement(el)); + return *this; + } + + static TransactionFormat* getTxnFormat(TransactionType t); + static TransactionFormat* getTxnFormat(const std::string& t); + static TransactionFormat* getTxnFormat(int t); }; const int TransactionMinLen = 32; @@ -44,9 +63,5 @@ const uint32 tfPartialPayment = 0x00020000; const uint32 tfLimitQuality = 0x00040000; const uint32 tfNoRippleDirect = 0x00080000; -extern TransactionFormat TxnFormats[]; -extern TransactionFormat* getTxnFormat(TransactionType t); -extern TransactionFormat* getTxnFormat(const std::string& t); -extern TransactionFormat* getTxnFormat(int t); #endif // vim:ts=4 From ef28ebe7a5d9f29034034c7339e7c173c99a9344 Mon Sep 17 00:00:00 2001 From: MJK Date: Mon, 1 Oct 2012 21:35:45 -0700 Subject: [PATCH 409/426] fix for mis-parsed send_max param in doSend() --- src/RPCServer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index ef0feb4933..514407dc4d 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1695,11 +1695,11 @@ Json::Value RPCServer::doSend(const Json::Value& params) if (params.size() >= 6) sDstIssuer = params[5u].asString(); - if (params.size() >= 7) - sSrcCurrency = params[6u].asString(); - if (params.size() >= 8) - sSrcIssuer = params[7u].asString(); + sSrcCurrency = params[7u].asString(); + + if (params.size() >= 9) + sSrcIssuer = params[8u].asString(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -1717,7 +1717,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) { return RPCError(rpcDST_AMT_MALFORMED); } - else if (params.size() >= 7 && !saSrcAmountMax.setFullValue(params[5u].asString(), sSrcCurrency, sSrcIssuer)) + else if (params.size() >= 7 && !saSrcAmountMax.setFullValue(params[6u].asString(), sSrcCurrency, sSrcIssuer)) { return RPCError(rpcSRC_AMT_MALFORMED); } From 2b18d9dce8d5ed0c408bb84097d2fd3ce017bd67 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 2 Oct 2012 00:31:00 -0700 Subject: [PATCH 410/426] Some range check helper functions and lexical_cast_ functions that throw. --- src/utils.h | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/utils.h b/src/utils.h index 91c5ff9b36..eab185b34a 100644 --- a/src/utils.h +++ b/src/utils.h @@ -171,7 +171,7 @@ template T lexical_cast_s(const std::string& string) } } -template std::string lexical_cast_i(T t) +template std::string lexical_cast_i(const T& t) { // lexicaly cast the selected type to a string. Does not throw try { @@ -183,6 +183,44 @@ template std::string lexical_cast_i(T t) } } +template T lexical_cast_st(const std::string& string) +{ // lexically cast a string to the selected type. Does throw + return boost::lexical_cast(string); +} + +template std::string lexical_cast_it(const T& t) +{ // lexicaly cast the selected type to a string. Does not throw + return boost::lexical_cast(t); +} + +template T range_check(const T& value, const T& minimum, const T& maximum) +{ + if ((value < minimum) || (value > maximum)) + throw std::runtime_error("Value out of range"); + return value; +} + +template T range_check_min(const T& value, const T& minimum) +{ + if (value < minimum) + throw std::runtime_error("Value out of range"); + return value; +} + +template T range_check_max(const T& value, const T& maximum) +{ + if (value > maximum) + throw std::runtime_error("Value out of range"); + return value; +} + +template T range_check_cast(const U& value, const T& minimum, const T& maximum) +{ + if ((value < minimum) || (value > maximum)) + throw std::runtime_error("Value out of range"); + return static_cast(value); +} + #endif // vim:ts=4 From 670adae3536d7d3747c658b97f16930db89064fc Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 2 Oct 2012 00:31:18 -0700 Subject: [PATCH 411/426] Cleanup. --- src/Amount.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index fbe6e0a5ac..d4898101d0 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -387,14 +387,14 @@ std::string STAmount::getRaw() const if (mValue == 0) return "0"; if (mIsNative) { - if (mIsNegative) return std::string("-") + boost::lexical_cast(mValue); - else return boost::lexical_cast(mValue); + if (mIsNegative) return std::string("-") + lexical_cast_i(mValue); + else return lexical_cast_i(mValue); } if (mIsNegative) return mCurrency.GetHex() + ": -" + - boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset); + lexical_cast_i(mValue) + "e" + lexical_cast_i(mOffset); else return mCurrency.GetHex() + ": " + - boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset); + lexical_cast_i(mValue) + "e" + lexical_cast_i(mOffset); } std::string STAmount::getText() const @@ -403,20 +403,20 @@ std::string STAmount::getText() const if (mIsNative) { if (mIsNegative) - return std::string("-") + boost::lexical_cast(mValue); - else return boost::lexical_cast(mValue); + return std::string("-") + lexical_cast_i(mValue); + else return lexical_cast_i(mValue); } if ((mOffset < -25) || (mOffset > -5)) { if (mIsNegative) - return std::string("-") + boost::lexical_cast(mValue) + - "e" + boost::lexical_cast(mOffset); + return std::string("-") + lexical_cast_i(mValue) + + "e" + lexical_cast_i(mOffset); else - return boost::lexical_cast(mValue) + "e" + boost::lexical_cast(mOffset); + return lexical_cast_i(mValue) + "e" + lexical_cast_i(mOffset); } std::string val = "000000000000000000000000000"; - val += boost::lexical_cast(mValue); + val += lexical_cast_i(mValue); val += "00000000000000000000000"; std::string pre = val.substr(0, mOffset + 43); From 3bed31ae4ad08e8a17508b5310cc6a2a49a720b0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 2 Oct 2012 00:31:30 -0700 Subject: [PATCH 412/426] Detect more error conditions. --- src/SerializedObject.cpp | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 2b9ee828e6..7ff7482648 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -836,18 +836,18 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r { case STI_UINT8: if (value.isString()) - data.push_back(new STUInt8(field, lexical_cast_s(value.asString()))); + data.push_back(new STUInt8(field, lexical_cast_st(value.asString()))); else if (value.isInt()) { if (value.asInt() < 0 || value.asInt() > 255) throw std::runtime_error("value out of rand"); - data.push_back(new STUInt8(field, static_cast(value.asInt()))); + data.push_back(new STUInt8(field, range_check_cast(value.asInt(), 0, 255))); } else if (value.isUInt()) { if (value.asUInt() > 255) throw std::runtime_error("value out of rand"); - data.push_back(new STUInt8(field, static_cast(value.asUInt()))); + data.push_back(new STUInt8(field, range_check_cast(value.asUInt(), 0, 255))); } else throw std::runtime_error("Incorrect type"); @@ -881,32 +881,33 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r throw std::runtime_error("Invalid field data"); } else - data.push_back(new STUInt16(field, lexical_cast_s(strValue))); + data.push_back(new STUInt16(field, lexical_cast_st(strValue))); } else if (value.isInt()) - data.push_back(new STUInt16(field, static_cast(value.asInt()))); + data.push_back(new STUInt16(field, range_check_cast(value.asInt(), 0, 65535))); else if (value.isUInt()) - data.push_back(new STUInt16(field, static_cast(value.asUInt()))); + data.push_back(new STUInt16(field, range_check_cast(value.asUInt(), 0, 65535))); else throw std::runtime_error("Incorrect type"); break; case STI_UINT32: if (value.isString()) - data.push_back(new STUInt32(field, lexical_cast_s(value.asString()))); + data.push_back(new STUInt32(field, lexical_cast_st(value.asString()))); else if (value.isInt()) - data.push_back(new STUInt32(field, static_cast(value.asInt()))); + data.push_back(new STUInt32(field, range_check_cast(value.asInt(), 0, 4294967295))); else if (value.isUInt()) - data.push_back(new STUInt32(field, static_cast(value.asUInt()))); + data.push_back(new STUInt32(field, static_cast(value.asUInt(), 0, 4294967295))); else throw std::runtime_error("Incorrect type"); break; case STI_UINT64: if (value.isString()) - data.push_back(new STUInt64(field, lexical_cast_s(value.asString()))); + data.push_back(new STUInt64(field, lexical_cast_st(value.asString()))); else if (value.isInt()) - data.push_back(new STUInt64(field, static_cast(value.asInt()))); + data.push_back(new STUInt64(field, + range_check_cast(value.asInt(), 0, 18446744073709551615ull))); else if (value.isUInt()) data.push_back(new STUInt64(field, static_cast(value.asUInt()))); else @@ -936,9 +937,9 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r break; case STI_VL: - { - // WRITEME - } + if (!value.isString()) + throw std::runtime_error("Incorrect type"); + data.push_back(new STVariableLength(field, strUnHex(value.asString()))); break; case STI_AMOUNT: @@ -950,8 +951,10 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r case STI_PATHSET: // WRITEME - case STI_OBJECT: case STI_ACCOUNT: + // WRITEME + + case STI_OBJECT: case STI_TRANSACTION: case STI_LEDGERENTRY: case STI_VALIDATION: From d9b0d39cf6ef84cedf1dd87df83d933efe64bd71 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 2 Oct 2012 01:01:27 -0700 Subject: [PATCH 413/426] JSON->Account --- src/SerializedObject.cpp | 26 ++++++++++++++++++++++---- src/SerializedTypes.cpp | 7 ++++++- src/SerializedTypes.h | 1 + 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 7ff7482648..5dc6b29b6c 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -897,7 +897,7 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r else if (value.isInt()) data.push_back(new STUInt32(field, range_check_cast(value.asInt(), 0, 4294967295))); else if (value.isUInt()) - data.push_back(new STUInt32(field, static_cast(value.asUInt(), 0, 4294967295))); + data.push_back(new STUInt32(field, static_cast(value.asUInt()))); else throw std::runtime_error("Incorrect type"); break; @@ -940,7 +940,7 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r if (!value.isString()) throw std::runtime_error("Incorrect type"); data.push_back(new STVariableLength(field, strUnHex(value.asString()))); - break; + break; case STI_AMOUNT: // WRITEME @@ -950,9 +950,27 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r case STI_PATHSET: // WRITEME - + break; case STI_ACCOUNT: - // WRITEME + { + if (!value.isString()) + throw std::runtime_error("Incorrect type"); + std::string strValue = value.asString(); + if (value.size() == 40) // 160-bit hex account value + { + uint160 v; + v.SetHex(strValue); + data.push_back(new STAccount(field, v)); + } + else + { // newcoin addres + NewcoinAddress a; + if (!a.setAccountPublic(strValue)) + throw std::runtime_error("Account invalid"); + data.push_back(new STAccount(field, a.getAccountID())); + } + } + break; case STI_OBJECT: case STI_TRANSACTION: diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index f4853a82e8..097395b5ca 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -231,9 +231,14 @@ bool STVector256::isEquivalent(const SerializedType& t) const // STAccount // +STAccount::STAccount(SField::ref n, const uint160& v) : STVariableLength(n) +{ + peekValue().insert(peekValue().end(), v.begin(), v.end()); +} + bool STAccount::isValueH160() const { - return peekValue().size() == (160/8); + return peekValue().size() == (160 / 8); } void STAccount::setValueH160(const uint160& v) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 046c39e52b..785e62515d 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -496,6 +496,7 @@ public: STAccount(const std::vector& v) : STVariableLength(v) { ; } STAccount(SField::ref n, const std::vector& v) : STVariableLength(n, v) { ; } + STAccount(SField::ref n, const uint160& v); STAccount(SField::ref n) : STVariableLength(n) { ; } STAccount() { ; } static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) From 17a99e686b07f5bd25fd6f74624cd4ba74108bd3 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 2 Oct 2012 03:49:46 -0700 Subject: [PATCH 414/426] More STAmount JSON work. --- src/Amount.cpp | 73 ++++++++++++++++++++++++++++++++++++++++ src/SerializedObject.cpp | 5 +-- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index d4898101d0..9ceaa11975 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include "Config.h" @@ -54,6 +56,77 @@ std::string STAmount::getHumanCurrency() const return createHumanCurrency(mCurrency); } +STAmount::STAmount(SField::ref n, const Json::Value& v) + : SerializedType(n), mValue(0), mOffset(0), mIsNative(false), mIsNegative(false) +{ + Json::Value value, currency, issuer; + + if (v.isArray()) + { + value = v["value"]; + currency = v["currency"]; + issuer = v["issuer"]; + } + else if (v.isString()) + { + std::string val = v.asString(); + std::vector elements; + boost::split(elements, val, boost::is_any_of("\t\n\r ,/")); + + if ((elements.size() < 0) || (elements.size() > 3)) + throw std::runtime_error("invalid amount string"); + + value = elements[0]; + if (elements.size() > 0) + currency = elements[1]; + if (elements.size() > 1) + issuer = elements[2]; + } + else + value = v; + + if (value.isInt()) + { + if (value.asInt() >= 0) + mValue = value.asInt(); + else + { + mValue = -value.asInt(); + mIsNegative = true; + } + } + else if (value.isUInt()) + mValue = v.asUInt(); + else if (value.isDouble()) + { + // WRITEME + } + else if (value.isString()) + { // FIXME: If it has a '.' we have to process it specially! + int64 val = lexical_cast_st(value.asString()); + if (val >= 0) + mValue = val; + else + { + mValue = -val; + mIsNegative = true; + } + } + else + throw std::runtime_error("invalid amount type"); + + if (!currency.isString() || currency.asString().empty() || (currency.asString() == SYSTEM_CURRENCY_CODE)) + { + mIsNative = true; + return; + } + + // parse currency and issuer + // WRITEME + + canonicalize(); +} + std::string STAmount::createHumanCurrency(const uint160& uCurrency) { std::string sCurrency; diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 5dc6b29b6c..74137bcc37 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -938,12 +938,12 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r case STI_VL: if (!value.isString()) - throw std::runtime_error("Incorrect type"); data.push_back(new STVariableLength(field, strUnHex(value.asString()))); break; case STI_AMOUNT: - // WRITEME + data.push_back(new STAmount(field, value)); + break; case STI_VECTOR256: // WRITEME @@ -951,6 +951,7 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r case STI_PATHSET: // WRITEME break; + case STI_ACCOUNT: { if (!value.isString()) From ddab25ab44eb6784eca0a6e41ca2c489655c7521 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 2 Oct 2012 04:28:01 -0700 Subject: [PATCH 415/426] Break out the portion that sets the value from the STAmount code. Fix its mishandling of negative amounts. Support array types in STAmount JSON input. --- src/Amount.cpp | 193 ++++++++++++++++++++++++------------------ src/SerializedTypes.h | 5 +- 2 files changed, 114 insertions(+), 84 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 9ceaa11975..ef8f417c7a 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -57,16 +57,22 @@ std::string STAmount::getHumanCurrency() const } STAmount::STAmount(SField::ref n, const Json::Value& v) - : SerializedType(n), mValue(0), mOffset(0), mIsNative(false), mIsNegative(false) + : SerializedType(n), mValue(0), mOffset(0), mIsNegative(false) { Json::Value value, currency, issuer; - if (v.isArray()) + if (v.isObject()) { value = v["value"]; currency = v["currency"]; issuer = v["issuer"]; } + else if (v.isArray()) + { + value = v.get(Json::UInt(0), 0); + currency = v.get(Json::UInt(1), Json::nullValue); + issuer = v.get(Json::UInt(2), Json::nullValue); + } else if (v.isString()) { std::string val = v.asString(); @@ -85,6 +91,8 @@ STAmount::STAmount(SField::ref n, const Json::Value& v) else value = v; + mIsNative = !currency.isString() || currency.asString().empty() || (currency.asString() == SYSTEM_CURRENCY_CODE); + if (value.isInt()) { if (value.asInt() >= 0) @@ -97,29 +105,27 @@ STAmount::STAmount(SField::ref n, const Json::Value& v) } else if (value.isUInt()) mValue = v.asUInt(); - else if (value.isDouble()) - { - // WRITEME - } else if (value.isString()) { // FIXME: If it has a '.' we have to process it specially! - int64 val = lexical_cast_st(value.asString()); - if (val >= 0) - mValue = val; - else + if (mIsNative) { - mValue = -val; - mIsNegative = true; + int64 val = lexical_cast_st(value.asString()); + if (val >= 0) + mValue = val; + else + { + mValue = -val; + mIsNegative = true; + } } + else + setValue(value.asString()); } else throw std::runtime_error("invalid amount type"); - if (!currency.isString() || currency.asString().empty() || (currency.asString() == SYSTEM_CURRENCY_CODE)) - { - mIsNative = true; + if (mIsNative) return; - } // parse currency and issuer // WRITEME @@ -173,6 +179,94 @@ std::string STAmount::createHumanCurrency(const uint160& uCurrency) return sCurrency; } +bool STAmount::setValue(const std::string& sAmount) +{ // Note: mIsNative must be set already! + uint64 uValue; + int iOffset; + size_t uDecimal = sAmount.find_first_of(mIsNative ? "^" : "."); + bool bInteger = uDecimal == std::string::npos; + + mIsNegative = false; + if (bInteger) + { + try + { + int64 a = sAmount.empty() ? 0 : lexical_cast_st(sAmount); + if (a >= 0) + uValue = static_cast(a); + else + { + uValue = static_cast(-a); + mIsNegative = true; + } + + } + catch (...) + { + Log(lsINFO) << "Bad integer amount: " << sAmount; + + return false; + } + iOffset = 0; + } + else + { + // Example size decimal size-decimal offset + // ^1 2 0 2 -1 + // 123^ 4 3 1 0 + // 1^23 4 1 3 -2 + iOffset = -int(sAmount.size() - uDecimal - 1); + + + // Issolate integer and fraction. + uint64 uInteger; + int64 iInteger = uDecimal ? lexical_cast_st(sAmount.substr(0, uDecimal)) : 0; + if (iInteger >= 0) + uInteger = static_cast(iInteger); + else + { + uInteger = static_cast(-iInteger); + mIsNegative = true; + } + + + uint64 uFraction = iOffset ? lexical_cast_st(sAmount.substr(uDecimal+1)) : 0; + + // Scale the integer portion to the same offset as the fraction. + uValue = uInteger; + for (int i = -iOffset; i--;) + uValue *= 10; + + // Add in the fraction. + uValue += uFraction; + } + + if (mIsNative) + { + if (bInteger) + iOffset = -SYSTEM_CURRENCY_PRECISION; + + while (iOffset > -SYSTEM_CURRENCY_PRECISION) { + uValue *= 10; + --iOffset; + } + + while (iOffset < -SYSTEM_CURRENCY_PRECISION) { + uValue /= 10; + ++iOffset; + } + + mValue = uValue; + } + else + { + mValue = uValue; + mOffset = iOffset; + canonicalize(); + } + return true; +} + // Not meant to be the ultimate parser. For use by RPC which is supposed to be sane and trusted. // Native has special handling: // - Integer values are in base units. @@ -216,72 +310,7 @@ bool STAmount::setFullValue(const std::string& sAmount, const std::string& sCurr return false; } - uint64 uValue; - int iOffset; - size_t uDecimal = sAmount.find_first_of(mIsNative ? "^" : "."); - bool bInteger = uDecimal == std::string::npos; - - if (bInteger) - { - try - { - uValue = sAmount.empty() ? 0 : boost::lexical_cast(sAmount); - } - catch (...) - { - Log(lsINFO) << "Bad integer amount: " << sAmount; - - return false; - } - iOffset = 0; - } - else - { - // Example size decimal size-decimal offset - // ^1 2 0 2 -1 - // 123^ 4 3 1 0 - // 1^23 4 1 3 -2 - iOffset = -int(sAmount.size()-uDecimal-1); - - - // Issolate integer and fraction. - uint64 uInteger = uDecimal ? boost::lexical_cast(sAmount.substr(0, uDecimal)) : 0; - uint64 uFraction = iOffset ? boost::lexical_cast(sAmount.substr(uDecimal+1)) : 0; - - // Scale the integer portion to the same offset as the fraction. - uValue = uInteger; - for (int i=-iOffset; i--;) - uValue *= 10; - - // Add in the fraction. - uValue += uFraction; - } - - if (mIsNative) - { - if (bInteger) - iOffset = -SYSTEM_CURRENCY_PRECISION; - - while (iOffset > -SYSTEM_CURRENCY_PRECISION) { - uValue *= 10; - --iOffset; - } - - while (iOffset < -SYSTEM_CURRENCY_PRECISION) { - uValue /= 10; - ++iOffset; - } - - mValue = uValue; - } - else - { - mValue = uValue; - mOffset = iOffset; - canonicalize(); - } - - return true; + return setValue(sAmount); } // amount = value * [10 ^ offset] diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 785e62515d..7bafa039d5 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -220,8 +220,6 @@ protected: : SerializedType(name), mCurrency(cur), mIssuer(iss), mValue(val), mOffset(off), mIsNative(isNat), mIsNegative(isNeg) { ; } - STAmount(SField::ref name, const Json::Value& value); - uint64 toUInt64() const; static uint64 muldiv(uint64, uint64, uint64); @@ -245,6 +243,8 @@ public: SerializedType(n), mCurrency(currency), mIssuer(issuer), mValue(v), mOffset(off), mIsNegative(isNeg) { canonicalize(); } + STAmount(SField::ref, const Json::Value&); + static STAmount createFromInt64(SField::ref n, int64 v); static std::auto_ptr deserialize(SerializerIterator& sit, SField::ref name) @@ -288,6 +288,7 @@ public: void setIssuer(const uint160& uIssuer) { mIssuer = uIssuer; } const uint160& getCurrency() const { return mCurrency; } + bool setValue(const std::string& sAmount); bool setFullValue(const std::string& sAmount, const std::string& sCurrency = "", const std::string& sIssuer = ""); void setValue(const STAmount &); From 5ff5e7669d17df9f0cc6ef4e2d1097d351ad33ed Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 2 Oct 2012 16:22:03 -0700 Subject: [PATCH 416/426] RPC: add profile command. --- src/RPCServer.cpp | 132 ++++++++++++++++++++++++++++++++++++-- src/RPCServer.h | 1 + src/Transaction.cpp | 4 +- src/TransactionAction.cpp | 14 +++- 4 files changed, 141 insertions(+), 10 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index ef0feb4933..587e70cc0e 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -318,7 +319,7 @@ Json::Value RPCServer::authorize(const uint256& uLedger, { naMasterAccountPublic.setAccountPublic(naMasterGenerator, iIndex); - Log(lsINFO) << "authorize: " << iIndex << " : " << naMasterAccountPublic.humanAccountID() << " : " << naSrcAccountID.humanAccountID(); + Log(lsDEBUG) << "authorize: " << iIndex << " : " << naMasterAccountPublic.humanAccountID() << " : " << naSrcAccountID.humanAccountID(); bFound = naSrcAccountID.getAccountID() == naMasterAccountPublic.getAccountID(); if (!bFound) @@ -355,13 +356,10 @@ Json::Value RPCServer::authorize(const uint256& uLedger, } else { - Log(lsINFO) << "authorize: before: fee=" << saFee.getFullText() << " balance=" << saSrcBalance.getFullText(); saSrcBalance -= saFee; - Log(lsINFO) << "authorize: after: fee=" << saFee.getFullText() << " balance=" << saSrcBalance.getFullText(); } - Json::Value obj; - return obj; + return Json::Value(); } // --> strIdent: public key, account ID, or regular seed. @@ -1304,6 +1302,122 @@ Json::Value RPCServer::doPeers(const Json::Value& params) return obj; } +// profile offers [submit] +// profile 0:offers 1:pass_a 2:account_a 3:currency_offer_a 4:pass_b 5:account_b 6:currency_offer_b 7: 8:[submit] +// issuer is the offering account +// the amount of each offer will be 1. +// --> count: defaults to 100 +// --> submit: 'submit|true|false': defaults to false +// Prior to running allow each to have a credit line of what they will be getting from the other account. +Json::Value RPCServer::doProfile(const Json::Value ¶ms) +{ + int iArgs = params.size(); + NewcoinAddress naSeedA; + NewcoinAddress naAccountA; + uint160 uCurrencyOfferA; + NewcoinAddress naSeedB; + NewcoinAddress naAccountB; + uint160 uCurrencyOfferB; + uint32 iCount = 100; + bool bSubmit = false; + + if (iArgs < 7 || "offers" != params[0u].asString()) + { + return RPCError(rpcINVALID_PARAMS); + } + + if (!naSeedA.setSeedGeneric(params[1u].asString())) // + return RPCError(rpcINVALID_PARAMS); + + naAccountA.setAccountID(params[2u].asString()); // + + if (!STAmount::currencyFromString(uCurrencyOfferA, params[3u].asString())) // + return RPCError(rpcINVALID_PARAMS); + + if (!naSeedB.setSeedGeneric(params[4u].asString())) // + return RPCError(rpcINVALID_PARAMS); + + naAccountB.setAccountID(params[5u].asString()); // + if (!STAmount::currencyFromString(uCurrencyOfferB, params[6u].asString())) // + return RPCError(rpcINVALID_PARAMS); + + if (iArgs >= 8) + iCount = lexical_cast_s(params[7u].asString()); + + if (iArgs >= 9 && "false" != params[8u].asString()) + bSubmit = true; + + boost::posix_time::ptime ptStart(boost::posix_time::microsec_clock::local_time()); + + for (int i = iCount; i-- >= 0;) { + NewcoinAddress naMasterGeneratorA; + NewcoinAddress naAccountPublicA; + NewcoinAddress naAccountPrivateA; + AccountState::pointer asSrcA; + STAmount saSrcBalanceA; + Json::Value jvObjA = authorize(uint256(0), naSeedA, naAccountA, naAccountPublicA, naAccountPrivateA, + saSrcBalanceA, theConfig.FEE_DEFAULT, asSrcA, naMasterGeneratorA); + + if (!jvObjA.empty()) + return jvObjA; + + Transaction::pointer tpOfferA = Transaction::sharedOfferCreate( + naAccountPublicA, naAccountPrivateA, + naAccountA, // naSourceAccount, + asSrcA->getSeq(), // uSeq + theConfig.FEE_DEFAULT, + 0, // uSourceTag, + false, // bPassive + STAmount(uCurrencyOfferA, naAccountA.getAccountID(), 1), // saTakerPays + STAmount(uCurrencyOfferB, naAccountB.getAccountID(), 1), // saTakerGets + 0); // uExpiration + + if (bSubmit) + tpOfferA = mNetOps->submitTransaction(tpOfferA); + + NewcoinAddress naMasterGeneratorB; + NewcoinAddress naAccountPublicB; + NewcoinAddress naAccountPrivateB; + AccountState::pointer asSrcB; + STAmount saSrcBalanceB; + Json::Value jvObjB = authorize(uint256(0), naSeedB, naAccountB, naAccountPublicB, naAccountPrivateB, + saSrcBalanceB, theConfig.FEE_DEFAULT, asSrcB, naMasterGeneratorB); + + if (!jvObjB.empty()) + return jvObjB; + + Transaction::pointer tpOfferB = Transaction::sharedOfferCreate( + naAccountPublicB, naAccountPrivateB, + naAccountB, // naSourceAccount, + asSrcB->getSeq(), // uSeq + theConfig.FEE_DEFAULT, + 0, // uSourceTag, + false, // bPassive + STAmount(uCurrencyOfferB, naAccountB.getAccountID(), 1), // saTakerPays + STAmount(uCurrencyOfferA, naAccountA.getAccountID(), 1), // saTakerGets + 0); // uExpiration + + if (bSubmit) + tpOfferB = mNetOps->submitTransaction(tpOfferB); + } + + boost::posix_time::ptime ptEnd(boost::posix_time::microsec_clock::local_time()); + boost::posix_time::time_duration tdInterval = ptEnd-ptStart; + long lMilliseconds = tdInterval.total_milliseconds(); + float fRate = lMilliseconds ? iCount/(lMilliseconds/1000000.0) : 0.0; + + Json::Value obj(Json::objectValue); + + obj["count"] = iCount; + obj["sumbit"] = bSubmit; + obj["start"] = boost::posix_time::to_simple_string(ptStart); + obj["end"] = boost::posix_time::to_simple_string(ptEnd); + obj["interval"] = boost::posix_time::to_simple_string(tdInterval); + obj["rate_per_second"] = fRate; + + return obj; +} + // ripple // [] // + @@ -1701,6 +1815,9 @@ Json::Value RPCServer::doSend(const Json::Value& params) if (params.size() >= 8) sSrcIssuer = params[7u].asString(); + if (params.size() >= 9) + sSrcIssuer = params[8u].asString(); + if (!naSeed.setSeedGeneric(params[0u].asString())) { return RPCError(rpcBAD_SEED); @@ -1717,7 +1834,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) { return RPCError(rpcDST_AMT_MALFORMED); } - else if (params.size() >= 7 && !saSrcAmountMax.setFullValue(params[5u].asString(), sSrcCurrency, sSrcIssuer)) + else if (params.size() >= 7 && !saSrcAmountMax.setFullValue(params[6u].asString(), sSrcCurrency, sSrcIssuer)) { return RPCError(rpcSRC_AMT_MALFORMED); } @@ -2539,7 +2656,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "data_fetch", &RPCServer::doDataFetch, 1, 1, true }, { "data_store", &RPCServer::doDataStore, 2, 2, true }, { "ledger", &RPCServer::doLedger, 0, 2, false, optNetwork }, - { "logrotate", &RPCServer::doLogRotate, 0, 0, true, 0 }, + { "logrotate", &RPCServer::doLogRotate, 0, 0, true }, { "nickname_info", &RPCServer::doNicknameInfo, 1, 1, false, optCurrent }, { "nickname_set", &RPCServer::doNicknameSet, 2, 3, false, optCurrent }, { "offer_create", &RPCServer::doOfferCreate, 9, 10, false, optCurrent }, @@ -2548,6 +2665,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "password_fund", &RPCServer::doPasswordFund, 2, 3, false, optCurrent }, { "password_set", &RPCServer::doPasswordSet, 2, 3, false, optNetwork }, { "peers", &RPCServer::doPeers, 0, 0, true }, + { "profile", &RPCServer::doProfile, 1, 9, false, optCurrent }, { "ripple", &RPCServer::doRipple, 9, -1, false, optCurrent|optClosed }, { "ripple_lines_get", &RPCServer::doRippleLinesGet, 1, 2, false, optCurrent }, { "ripple_line_set", &RPCServer::doRippleLineSet, 4, 7, false, optCurrent }, diff --git a/src/RPCServer.h b/src/RPCServer.h index 8d56ed55aa..d203cbc3ca 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -149,6 +149,7 @@ private: Json::Value doOwnerInfo(const Json::Value& params); Json::Value doPasswordFund(const Json::Value& params); Json::Value doPasswordSet(const Json::Value& params); + Json::Value doProfile(const Json::Value& params); Json::Value doPeers(const Json::Value& params); Json::Value doRipple(const Json::Value ¶ms); Json::Value doRippleLinesGet(const Json::Value ¶ms); diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 76bd2a9408..e56e12f0f0 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -68,8 +68,8 @@ Transaction::Transaction( mTransaction = boost::make_shared(ttKind); - Log(lsINFO) << str(boost::format("Transaction: account: %s") % naSourceAccount.humanAccountID()); - Log(lsINFO) << str(boost::format("Transaction: mAccountFrom: %s") % mAccountFrom.humanAccountID()); + // Log(lsINFO) << str(boost::format("Transaction: account: %s") % naSourceAccount.humanAccountID()); + // Log(lsINFO) << str(boost::format("Transaction: mAccountFrom: %s") % mAccountFrom.humanAccountID()); mTransaction->setSigningPubKey(mFromPubKey); mTransaction->setSourceAccount(mAccountFrom); diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index acdeacadb9..bf96f344f8 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -727,7 +727,7 @@ TER TransactionEngine::takeOffers( // Figure out next offer to take, if needed. if (saTakerGets != saTakerGot && saTakerPays != saTakerPaid) { - // Taker has needs. + // Taker, still, needs to get and pay. sleOfferDir = entryCache(ltDIR_NODE, mLedger->getNextLedgerIndex(uTipIndex, uBookEnd)); if (sleOfferDir) @@ -832,7 +832,19 @@ TER TransactionEngine::takeOffers( Log(lsINFO) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText(); Log(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText(); Log(lsINFO) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText(); +#if 0 + STAmount saTakerPaysRate = + uTakerPaysAccountID == uTakerAccountID // Taker is issuing, no fee. + || uTakerPaysAccountID == uOfferAccountID // Taker is redeeming, no fee. + ? 0.0 + : getRate(uTakerPaysAccountID); + STAmount saOfferPaysRate = + uTakerGetsAccountID == uTakerGetsAccountID // Offerer is redeeming, no fee. + || uTakerGetsAccountID == uOfferAccountID // Offerer is issuing, no fee. + ? 0.0 + : getRate(uTakerGetsAccountID); +#endif bool bOfferDelete = STAmount::applyOffer( saOfferFunds, saPay, // Driver XXX need to account for fees. From ae3198bb9c44983e1bb00f6624e012f6aa107057 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 2 Oct 2012 16:28:05 -0700 Subject: [PATCH 417/426] Fix typo. --- src/RPCServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index ad09a292dd..7f0b41ddd2 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1409,7 +1409,7 @@ Json::Value RPCServer::doProfile(const Json::Value ¶ms) Json::Value obj(Json::objectValue); obj["count"] = iCount; - obj["sumbit"] = bSubmit; + obj["submit"] = bSubmit; obj["start"] = boost::posix_time::to_simple_string(ptStart); obj["end"] = boost::posix_time::to_simple_string(ptEnd); obj["interval"] = boost::posix_time::to_simple_string(tdInterval); From facca3ef17ba5e3cb957d5f6702a035de4e0b709 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 2 Oct 2012 16:37:31 -0700 Subject: [PATCH 418/426] RPC fix rate_per_second for profile. --- src/RPCServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 7f0b41ddd2..9e4c7a546c 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1403,8 +1403,8 @@ Json::Value RPCServer::doProfile(const Json::Value ¶ms) boost::posix_time::ptime ptEnd(boost::posix_time::microsec_clock::local_time()); boost::posix_time::time_duration tdInterval = ptEnd-ptStart; - long lMilliseconds = tdInterval.total_milliseconds(); - float fRate = lMilliseconds ? iCount/(lMilliseconds/1000000.0) : 0.0; + long lMicroseconds = tdInterval.total_microseconds(); + float fRate = lMicroseconds ? iCount/(lMicroseconds/1000000.0) : 0.0; Json::Value obj(Json::objectValue); From fa712549ea6172ea97bf8028b88206a67e2900bf Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 2 Oct 2012 16:56:44 -0700 Subject: [PATCH 419/426] RPC profile: Fix transactions reported. --- src/RPCServer.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 9e4c7a546c..fb560045e0 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1306,7 +1306,7 @@ Json::Value RPCServer::doPeers(const Json::Value& params) // profile 0:offers 1:pass_a 2:account_a 3:currency_offer_a 4:pass_b 5:account_b 6:currency_offer_b 7: 8:[submit] // issuer is the offering account // the amount of each offer will be 1. -// --> count: defaults to 100 +// --> count: defaults to 100, does 2 offers per iteration. // --> submit: 'submit|true|false': defaults to false // Prior to running allow each to have a credit line of what they will be getting from the other account. Json::Value RPCServer::doProfile(const Json::Value ¶ms) @@ -1404,11 +1404,12 @@ Json::Value RPCServer::doProfile(const Json::Value ¶ms) boost::posix_time::ptime ptEnd(boost::posix_time::microsec_clock::local_time()); boost::posix_time::time_duration tdInterval = ptEnd-ptStart; long lMicroseconds = tdInterval.total_microseconds(); - float fRate = lMicroseconds ? iCount/(lMicroseconds/1000000.0) : 0.0; + int iTransactions = iCount*2; + float fRate = lMicroseconds ? iTransactions/(lMicroseconds/1000000.0) : 0.0; Json::Value obj(Json::objectValue); - obj["count"] = iCount; + obj["transactions"] = iTransactions; obj["submit"] = bSubmit; obj["start"] = boost::posix_time::to_simple_string(ptStart); obj["end"] = boost::posix_time::to_simple_string(ptEnd); From d7d5a0d2b16b2487b7d7e75078af0ef7c81d8f57 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 2 Oct 2012 20:15:51 -0700 Subject: [PATCH 420/426] Finish STAmount JSON parser. --- src/Amount.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index ef8f417c7a..b4f6b0ba48 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -106,7 +106,7 @@ STAmount::STAmount(SField::ref n, const Json::Value& v) else if (value.isUInt()) mValue = v.asUInt(); else if (value.isString()) - { // FIXME: If it has a '.' we have to process it specially! + { if (mIsNative) { int64 val = lexical_cast_st(value.asString()); @@ -127,8 +127,23 @@ STAmount::STAmount(SField::ref n, const Json::Value& v) if (mIsNative) return; - // parse currency and issuer - // WRITEME + if (!currencyFromString(mCurrency, currency.asString())) + throw std::runtime_error("invalid currency"); + + if (!issuer.isString()) + throw std::runtime_error("invalid issuer"); + + if (issuer.size() == (160/4)) + mIssuer.SetHex(issuer.asString()); + else + { + NewcoinAddress is; + if(!is.setAccountID(issuer.asString())) + throw std::runtime_error("invalid issuer"); + mIssuer = is.getAccountID(); + } + if (mIssuer.isZero()) + throw std::runtime_error("invalid issuer"); canonicalize(); } From f0320f0b7f6a5dd6a73c6b6feb08f71ddd96de4f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 3 Oct 2012 13:53:06 -0700 Subject: [PATCH 421/426] More JSON work. --- src/Pathfinder.cpp | 2 +- src/SerializedObject.cpp | 81 ++++++++++++++++++++++++++++++++++++++-- src/SerializedObject.h | 16 ++++++-- src/SerializedTypes.cpp | 4 +- src/SerializedTypes.h | 18 ++++----- 5 files changed, 102 insertions(+), 19 deletions(-) diff --git a/src/Pathfinder.cpp b/src/Pathfinder.cpp index a83771a57f..4f0276a451 100644 --- a/src/Pathfinder.cpp +++ b/src/Pathfinder.cpp @@ -154,7 +154,7 @@ void Pathfinder::addOptions(PathOption::pointer tail) { // we have a ripple line from the tail to somewhere else PathOption::pointer pathOption(new PathOption(tail)); - STPathElement ele(line->getAccountIDPeer().getAccountID(), uint160(),uint160()); + STPathElement ele(line->getAccountIDPeer().getAccountID(), uint160(), uint160()); pathOption->mPath.addElement(ele); diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 74137bcc37..3f2fcdaa8f 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -946,10 +946,77 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r break; case STI_VECTOR256: - // WRITEME + if (!value.isArray()) + throw std::runtime_error("Incorrect type"); + { + data.push_back(new STVector256(field)); + STVector256* tail = dynamic_cast(&data.back()); + assert(tail); + for (Json::UInt i = 0; !object.isValidIndex(i); ++i) + { + uint256 s; + s.SetHex(object[i].asString()); + tail->addValue(s); + } + } + break; case STI_PATHSET: - // WRITEME + if (!value.isArray()) + throw std::runtime_error("Path set must be array"); + { + data.push_back(new STPathSet(field)); + STPathSet* tail = dynamic_cast(&data.back()); + assert(tail); + for (Json::UInt i = 0; !object.isValidIndex(i); ++i) + { + STPath p; + if (!object[i].isArray()) + throw std::runtime_error("Path must be array"); + for (Json::UInt j = 0; !object[i].isValidIndex(j); ++j) + { // each element in this path has some combination of account, currency, or issuer + + Json::Value pathEl = object[i][j]; + if (!pathEl.isObject()) + throw std::runtime_error("Path elements must be objects"); + const Json::Value& account = pathEl["account"]; + const Json::Value& currency = pathEl["currency"]; + const Json::Value& issuer = pathEl["issuer"]; + + uint160 uAccount, uCurrency, uIssuer; + bool hasCurrency; + if (!account.isNull()) + { // human account id + if (!account.isString()) + throw std::runtime_error("path element accounts must be strings"); + std::string strValue = account.asString(); + if (value.size() == 40) // 160-bit hex account value + uAccount.SetHex(strvalue); + { + NewcoinAddress a; + if (!a.setAccountPublic(strValue)) + throw std::runtime_error("Account in path element invalid"); + uAccount = a.getAccountID(); + } + } + if (!currency.isNull()) + { // human currency + if (!currency.isString()) + throw std::runtime_error("path element currencies must be strings"); + hasCurrency = true; + // WRITEME + } + if (!issuer.isNull()) + { // human account id + if (!issuer.isString()) + throw std::runtime_error("path element issuers must be strings"); + // WRITEME + } + p.addElement(STPathElement(uAccount, uCurrency, uIssuer, hasCurrency)); + } + tail->addPath(p); + } + } break; case STI_ACCOUNT: @@ -985,7 +1052,15 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r break; case STI_ARRAY: - // WRITEME + if (!value.isArray()) + throw std::runtime_error("Inner value is not an array"); + { + data.push_back(new STArray(field)); + STArray* tail = dynamic_cast(&data.back()); + assert(tail); + for (Json::UInt i = 0; !object.isValidIndex(i); ++i) + tail->push_back(*STObject::parseJson(object[i], sfGeneric, depth + 1)); + } default: throw std::runtime_error("Invalid field type"); diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 6de71dcbf5..ed8d06560e 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -65,11 +65,15 @@ public: std::string getText() const; virtual Json::Value getJson(int options) const; - int addObject(const SerializedType& t) { mData.push_back(t.clone()); return mData.size() - 1; } - int giveObject(std::auto_ptr t) { mData.push_back(t); return mData.size() - 1; } - int giveObject(SerializedType* t) { mData.push_back(t); return mData.size() - 1; } + int addObject(const SerializedType& t) { mData.push_back(t.clone()); return mData.size() - 1; } + int giveObject(std::auto_ptr t) { mData.push_back(t); return mData.size() - 1; } + int giveObject(SerializedType* t) { mData.push_back(t); return mData.size() - 1; } const boost::ptr_vector& peekData() const { return mData; } - boost::ptr_vector& peekData() { return mData; } + boost::ptr_vector& peekData() { return mData; } + SerializedType& front() { return mData.front(); } + const SerializedType& front() const { return mData.front(); } + SerializedType& back() { return mData.back(); } + const SerializedType& back() const { return mData.back(); } int getCount() const { return mData.size(); } @@ -189,6 +193,10 @@ public: reverse_iterator rend() { return value.rend(); } const_reverse_iterator rend() const { return value.rend(); } iterator erase(iterator pos) { return value.erase(pos); } + STObject& front() { return value.front(); } + const STObject& front() const { return value.front(); } + STObject& back() { return value.back(); } + const STObject& back() const { return value.back(); } void pop_back() { value.pop_back(); } bool empty() const { return value.empty(); } void clear() { value.clear(); } diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 097395b5ca..92316d8b96 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -365,8 +365,8 @@ Json::Value STPath::getJson(int) const Json::Value elem(Json::objectValue); int iType = it.getNodeType(); - elem["type"] = it.getNodeType(); - elem["type_hex"] = strHex(it.getNodeType()); + elem["type"] = iType; + elem["type_hex"] = strHex(iType); if (iType & STPathElement::typeAccount) elem["account"] = NewcoinAddress::createHumanAccountID(it.getAccountID()); diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 7bafa039d5..41230fb273 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -537,12 +537,13 @@ protected: uint160 mIssuerID; public: - STPathElement(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID) - : mAccountID(uAccountID), mCurrencyID(uCurrencyID), mIssuerID(uIssuerID) + STPathElement(const uint160& uAccountID, const uint160& uCurrencyID, const uint160& uIssuerID, + bool forceCurrency = false) + : mAccountID(uAccountID), mCurrencyID(uCurrencyID), mIssuerID(uIssuerID) { mType = (uAccountID.isZero() ? 0 : STPathElement::typeAccount) - | (uCurrencyID.isZero() ? 0 : STPathElement::typeCurrency) + | ((uCurrencyID.isZero() && !forceCurrency) ? 0 : STPathElement::typeCurrency) | (uIssuerID.isZero() ? 0 : STPathElement::typeIssuer); } @@ -720,12 +721,11 @@ public: std::vector& peekValue() { return mValue; } virtual bool isEquivalent(const SerializedType& t) const; - std::vector getValue() const { return mValue; } - - bool isEmpty() const { return mValue.empty(); } - - void setValue(const STVector256& v) { mValue = v.mValue; } - void setValue(const std::vector& v) { mValue = v; } + std::vector getValue() const { return mValue; } + bool isEmpty() const { return mValue.empty(); } + void setValue(const STVector256& v) { mValue = v.mValue; } + void setValue(const std::vector& v) { mValue = v; } + void addValue(const uint256& v) { mValue.push_back(v); } Json::Value getJson(int) const; }; From 5b1ac0b1e5e43e91fb8263738414b7aad0c898ed Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 3 Oct 2012 14:44:59 -0700 Subject: [PATCH 422/426] Add transfer support to offer taking. --- src/Amount.cpp | 74 ++++++++++++++++++++++++++++++--------- src/LedgerEntrySet.cpp | 9 +++++ src/LedgerEntrySet.h | 1 + src/SerializedTypes.h | 4 ++- src/TransactionAction.cpp | 28 +++++++-------- 5 files changed, 83 insertions(+), 33 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index ef8f417c7a..b78dbd491e 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -883,40 +883,56 @@ STAmount STAmount::setRate(uint64 rate) } // Taker gets all taker can pay for with saTakerFunds, limited by saOfferPays and saOfferFunds. -// --> saOfferFunds: Limit for saOfferPays -// --> saTakerFunds: Limit for saOfferGets : How much taker really wants. : Driver -// --> saOfferPays: Request : this should be reduced as the offer is fullfilled. -// --> saOfferGets: Request : this should be reduced as the offer is fullfilled. -// --> saTakerPays: Total : Used to know the approximate ratio of the exchange. -// --> saTakerGets: Total : Used to know the approximate ratio of the exchange. -// <-- saTakerPaid: Actual -// <-- saTakerGot: Actual -// <-- bRemove: remove offer it is either fullfilled or unfunded +// --> uTakerPaysRate: >= QUALITY_ONE +// --> uOfferPaysRate: >= QUALITY_ONE +// --> saOfferFunds: Limit for saOfferPays +// --> saTakerFunds: Limit for saOfferGets : How much taker really wants. : Driver +// --> saOfferPays: Request : this should be reduced as the offer is fullfilled. +// --> saOfferGets: Request : this should be reduced as the offer is fullfilled. +// --> saTakerPays: Total : Used to know the approximate ratio of the exchange. +// --> saTakerGets: Total : Used to know the approximate ratio of the exchange. +// <-- saTakerPaid: Actual +// <-- saTakerGot: Actual +// <-- saTakerIssuerFee: Actual +// <-- saOfferIssuerFee: Actual +// <-- bRemove: remove offer it is either fullfilled or unfunded bool STAmount::applyOffer( + const uint32 uTakerPaysRate, const uint32 uOfferPaysRate, const STAmount& saOfferFunds, const STAmount& saTakerFunds, const STAmount& saOfferPays, const STAmount& saOfferGets, const STAmount& saTakerPays, const STAmount& saTakerGets, - STAmount& saTakerPaid, STAmount& saTakerGot) + STAmount& saTakerPaid, STAmount& saTakerGot, + STAmount& saTakerIssuerFee, STAmount& saOfferIssuerFee) { saOfferGets.throwComparable(saTakerPays); assert(!saOfferFunds.isZero() && !saTakerFunds.isZero()); // Must have funds. assert(!saOfferGets.isZero() && !saOfferPays.isZero()); // Must not be a null offer. + // Amount offer can pay out, limited by funds and fees. + STAmount saOfferFundsAvailable = QUALITY_ONE == uOfferPaysRate + ? saOfferFunds + : STAmount::divide(saOfferFunds, STAmount(CURRENCY_ONE, uOfferPaysRate, -9)); + // Amount offer can pay out, limited by offer and funds. - STAmount saOfferPaysAvailable = saOfferFunds < saOfferPays ? saOfferFunds : saOfferPays; + STAmount saOfferPaysAvailable = std::min(saOfferFundsAvailable, saOfferPays); // Amount offer can get in proportion, limited by offer funds. STAmount saOfferGetsAvailable = - saOfferFunds == saOfferPays + saOfferFundsAvailable == saOfferPays ? saOfferGets // Offer was fully funded, avoid shenanigans. : divide(multiply(saTakerPays, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saTakerGets, saOfferGets.getCurrency(), saOfferGets.getIssuer()); - if (saOfferGets == saOfferGetsAvailable && saTakerFunds >= saOfferGets) + // Amount taker can spend, limited by funds and fees. + STAmount saTakerFundsAvailable = QUALITY_ONE == uTakerPaysRate + ? saTakerFunds + : STAmount::divide(saTakerFunds, STAmount(CURRENCY_ONE, uTakerPaysRate, -9)); + + if (saOfferGets == saOfferGetsAvailable && saTakerFundsAvailable >= saOfferGets) { // Taker gets all of offer available. - saTakerPaid = saOfferGets; // Taker paid what offer could get. - saTakerGot = saOfferPays; // Taker got what offer could pay. + saTakerPaid = saOfferGets; // Taker paid what offer could get. + saTakerGot = saOfferPays; // Taker got what offer could pay. Log(lsINFO) << "applyOffer: took all outright"; } @@ -934,8 +950,32 @@ bool STAmount::applyOffer( saTakerPaid = saTakerFunds; // Taker paid all he had. saTakerGot = divide(multiply(saTakerFunds, saOfferPaysAvailable, CURRENCY_ONE, ACCOUNT_ONE), saOfferGetsAvailable, saOfferPays.getCurrency(), saOfferPays.getIssuer()); - Log(lsINFO) << "applyOffer: saTakerGot=" << saTakerGot; - Log(lsINFO) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable; + Log(lsINFO) << "applyOffer: saTakerGot=" << saTakerGot.getFullText(); + Log(lsINFO) << "applyOffer: saOfferPaysAvailable=" << saOfferPaysAvailable.getFullText(); + } + + if (uTakerPaysRate == QUALITY_ONE) + { + saTakerIssuerFee = STAmount(saTakerPaid.getCurrency(), saTakerPaid.getIssuer()); + } + else + { + // Compute fees in a rounding safe way. + STAmount saTotal = STAmount::multiply(saTakerPaid, STAmount(CURRENCY_ONE, uTakerPaysRate, -9)); + + saTakerIssuerFee = (saTotal > saTakerFunds) ? saTakerFunds-saTakerPaid : saTotal - saTakerPaid; + } + + if (uOfferPaysRate == QUALITY_ONE) + { + saOfferIssuerFee = STAmount(saTakerGot.getCurrency(), saTakerGot.getIssuer()); + } + else + { + // Compute fees in a rounding safe way. + STAmount saTotal = STAmount::multiply(saTakerPaid, STAmount(CURRENCY_ONE, uTakerPaysRate, -9)); + + saOfferIssuerFee = (saTotal > saOfferFunds) ? saOfferFunds-saTakerGot : saTotal - saTakerGot; } return saTakerGot >= saOfferPays; diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 22f0798422..478290bb33 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -875,6 +875,15 @@ uint32 LedgerEntrySet::rippleTransferRate(const uint160& uIssuerID) return uQuality; } +uint32 LedgerEntrySet::rippleTransferRate(const uint160& uSenderID, const uint160& uReceiverID, const uint160& uIssuerID) +{ + uint32 uQuality; + + return uSenderID == uIssuerID || uReceiverID == uIssuerID + ? QUALITY_ONE + : rippleTransferRate(uIssuerID); +} + // XXX Might not need this, might store in nodes on calc reverse. uint32 LedgerEntrySet::rippleQualityIn(const uint160& uToAccountID, const uint160& uFromAccountID, const uint160& uCurrencyID, SField::ref sfLow, SField::ref sfHigh) { diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index 8a7c926c4e..be44b0e973 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -102,6 +102,7 @@ public: // Balance functions. uint32 rippleTransferRate(const uint160& uIssuerID); + uint32 rippleTransferRate(const uint160& uSenderID, const uint160& uReceiverID, 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, diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 7bafa039d5..a91e2fe97c 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -343,10 +343,12 @@ public: // Someone is offering X for Y, I try to pay Z, how much do I get? // And what's left of the offer? And how much do I actually pay? static bool applyOffer( + const uint32 uTakerPaysRate, const uint32 uOfferPaysRate, const STAmount& saOfferFunds, const STAmount& saTakerFunds, const STAmount& saOfferPays, const STAmount& saOfferGets, const STAmount& saTakerPays, const STAmount& saTakerGets, - STAmount& saTakerPaid, STAmount& saTakerGot); + STAmount& saTakerPaid, STAmount& saTakerGot, + STAmount& saTakerIssuerFee, STAmount& saOfferIssuerFee); // Someone is offering X for Y, I need Z, how much do I pay static STAmount getPay(const STAmount& offerOut, const STAmount& offerIn, const STAmount& needed); diff --git a/src/TransactionAction.cpp b/src/TransactionAction.cpp index bf96f344f8..35ed8397dc 100644 --- a/src/TransactionAction.cpp +++ b/src/TransactionAction.cpp @@ -822,6 +822,8 @@ TER TransactionEngine::takeOffers( saPay = saTakerFunds; STAmount saSubTakerPaid; STAmount saSubTakerGot; + STAmount saTakerIssuerFee; + STAmount saOfferIssuerFee; Log(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText(); Log(lsINFO) << "takeOffers: applyOffer: saTakerPaid: " << saTakerPaid.getFullText(); @@ -832,20 +834,10 @@ TER TransactionEngine::takeOffers( Log(lsINFO) << "takeOffers: applyOffer: saOfferGets: " << saOfferGets.getFullText(); Log(lsINFO) << "takeOffers: applyOffer: saTakerPays: " << saTakerPays.getFullText(); Log(lsINFO) << "takeOffers: applyOffer: saTakerGets: " << saTakerGets.getFullText(); -#if 0 - STAmount saTakerPaysRate = - uTakerPaysAccountID == uTakerAccountID // Taker is issuing, no fee. - || uTakerPaysAccountID == uOfferAccountID // Taker is redeeming, no fee. - ? 0.0 - : getRate(uTakerPaysAccountID); - STAmount saOfferPaysRate = - uTakerGetsAccountID == uTakerGetsAccountID // Offerer is redeeming, no fee. - || uTakerGetsAccountID == uOfferAccountID // Offerer is issuing, no fee. - ? 0.0 - : getRate(uTakerGetsAccountID); -#endif bool bOfferDelete = STAmount::applyOffer( + mNodes.rippleTransferRate(uTakerAccountID, uOfferOwnerID, uTakerPaysAccountID), + mNodes.rippleTransferRate(uOfferOwnerID, uTakerAccountID, uTakerGetsAccountID), saOfferFunds, saPay, // Driver XXX need to account for fees. saOfferPays, @@ -853,7 +845,9 @@ TER TransactionEngine::takeOffers( saTakerPays, saTakerGets, saSubTakerPaid, - saSubTakerGot); + saSubTakerGot, + saTakerIssuerFee, + saOfferIssuerFee); Log(lsINFO) << "takeOffers: applyOffer: saSubTakerPaid: " << saSubTakerPaid.getFullText(); Log(lsINFO) << "takeOffers: applyOffer: saSubTakerGot: " << saSubTakerGot.getFullText(); @@ -884,16 +878,20 @@ TER TransactionEngine::takeOffers( } // Offer owner pays taker. - saSubTakerGot.setIssuer(uTakerGetsAccountID); // XXX Move this earlier? + // saSubTakerGot.setIssuer(uTakerGetsAccountID); // XXX Move this earlier? + assert(!!saSubTakerGot.getIssuer()); mNodes.accountSend(uOfferOwnerID, uTakerAccountID, saSubTakerGot); + mNodes.accountSend(uOfferOwnerID, uTakerGetsAccountID, saOfferIssuerFee); saTakerGot += saSubTakerGot; // Taker pays offer owner. - saSubTakerPaid.setIssuer(uTakerPaysAccountID); + // saSubTakerPaid.setIssuer(uTakerPaysAccountID); + assert(!!saSubTakerPaid.getIssuer()); mNodes.accountSend(uTakerAccountID, uOfferOwnerID, saSubTakerPaid); + mNodes.accountSend(uTakerAccountID, uTakerPaysAccountID, saTakerIssuerFee); saTakerPaid += saSubTakerPaid; } From fca0f6fffc7093dfad366a8679a988dfce62e831 Mon Sep 17 00:00:00 2001 From: MJK Date: Wed, 3 Oct 2012 15:14:08 -0700 Subject: [PATCH 423/426] fix typo in strValue's name --- src/SerializedObject.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 3f2fcdaa8f..baf9ba1cbc 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -991,7 +991,7 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r throw std::runtime_error("path element accounts must be strings"); std::string strValue = account.asString(); if (value.size() == 40) // 160-bit hex account value - uAccount.SetHex(strvalue); + uAccount.SetHex(strValue); { NewcoinAddress a; if (!a.setAccountPublic(strValue)) From 437ab7b6ae1e6562d48de2b8cb3ca26fd05aa365 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 3 Oct 2012 20:29:44 -0700 Subject: [PATCH 424/426] Put RPC commands in a try catch. --- src/RPCServer.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index fb560045e0..3790691058 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -2729,7 +2729,13 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params } else { - return (this->*(commandsA[i].dfpFunc))(params); + try { + return (this->*(commandsA[i].dfpFunc))(params); + } + catch (...) + { + return RPCError(rpcINTERNAL); + } } } From 39cb1899d0f252bc20b8417ea29d96b56be8268d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 3 Oct 2012 22:23:32 -0700 Subject: [PATCH 425/426] A few small bugfixes and some exra logging to track down a sync bug that Jed reported. --- src/ConnectionPool.cpp | 8 ++++- src/ConnectionPool.h | 2 +- src/LedgerAcquire.cpp | 3 +- src/LedgerConsensus.cpp | 4 +++ src/NetworkOPs.cpp | 65 +++++++++++++++++++++++++++------------ src/NetworkOPs.h | 1 + src/Peer.cpp | 3 +- src/TransactionEngine.cpp | 4 --- 8 files changed, 62 insertions(+), 28 deletions(-) diff --git a/src/ConnectionPool.cpp b/src/ConnectionPool.cpp index ed196af6c6..6285d45551 100644 --- a/src/ConnectionPool.cpp +++ b/src/ConnectionPool.cpp @@ -227,8 +227,9 @@ void ConnectionPool::policyHandler(const boost::system::error_code& ecResult) // YYY: Should probably do this in the background. // YYY: Might end up sending to disconnected peer? -void ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg) +int ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg) { + int sentTo = 0; boost::mutex::scoped_lock sl(mPeerLock); BOOST_FOREACH(naPeer pair, mConnectedMap) @@ -237,8 +238,13 @@ void ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& if (!peer) std::cerr << "CP::RM null peer in list" << std::endl; else if ((!fromPeer || !(peer.get() == fromPeer)) && peer->isConnected()) + { + ++sentTo; peer->sendPacket(msg); + } } + + return sentTo; } // Schedule a connection via scanning. diff --git a/src/ConnectionPool.h b/src/ConnectionPool.h index bb13d06436..4db0239853 100644 --- a/src/ConnectionPool.h +++ b/src/ConnectionPool.h @@ -58,7 +58,7 @@ public: void start(); // Send message to network. - void relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg); + int relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg); // Manual connection request. // Queue for immediate scanning. diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index bbfd67063b..76a43e7276 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -267,7 +267,8 @@ void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL, Peer::ref peer) void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL) { boost::recursive_mutex::scoped_lock sl(mLock); - if (mPeers.empty()) return; + if (mPeers.empty()) + return; PackedMessage::pointer packet = boost::make_shared(tmGL, newcoin::mtGET_LEDGER); diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 2dc6672f6f..65730e8177 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -50,9 +50,13 @@ boost::weak_ptr TransactionAcquire::pmDowncast() void TransactionAcquire::trigger(Peer::ref peer, bool timer) { if (mComplete || mFailed) + { + Log(lsINFO) << "complete or failed"; return; + } if (!mHaveRoot) { + Log(lsINFO) << "have no root"; newcoin::TMGetLedger tmGL; tmGL.set_ledgerhash(mHash.begin(), mHash.size()); tmGL.set_itype(newcoin::liTS_CANDIDATE); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index ce77bf69d7..4f24651c92 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -25,7 +25,7 @@ NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) : mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster), mCloseTimeOffset(0), - mLastCloseProposers(0), mLastCloseConvergeTime(LEDGER_IDLE_INTERVAL), mLastValidationTime(0) + mLastCloseProposers(0), mLastCloseConvergeTime(1000 * LEDGER_IDLE_INTERVAL), mLastValidationTime(0) { } @@ -114,7 +114,18 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, } TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tapOPEN_LEDGER); - if (r == tefFAILURE) throw Fault(IO_ERROR); + +#ifdef DEBUG + if (r != tesSUCCESS) + { + std::string token, human; + if (transResultInfo(r, token, human)) + Log(lsINFO) << "TransactionResult: " << token << ": " << human; + } +#endif + + if (r == tefFAILURE) + throw Fault(IO_ERROR); if (r == terPRE_SEQ) { // transaction should be held @@ -150,7 +161,8 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, tx.set_receivetimestamp(getNetworkTimeNC()); PackedMessage::pointer packet = boost::make_shared(tx, newcoin::mtTRANSACTION); - theApp->getConnectionPool().relayMessage(source, packet); + int sentTo = theApp->getConnectionPool().relayMessage(source, packet); + Log(lsINFO) << "Transaction relayed to " << sentTo << " node(s)"; return trans; } @@ -629,6 +641,24 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo return mConsensus->startup(); } +bool NetworkOPs::haveConsensusObject() +{ + if (mConsensus) + return true; + if (mMode != omFULL) + return false; + + uint256 networkClosed; + std::vector peerList = theApp->getConnectionPool().getPeerVector(); + bool ledgerChange = checkLastClosedLedger(peerList, networkClosed); + if (!ledgerChange) + { + Log(lsWARNING) << "Beginning consensus due to peer action"; + beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger()); + } + return mConsensus; +} + // <-- bool: true to relay bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger, uint32 closeTime, const std::string& pubKey, const std::string& signature, const NewcoinAddress& nodePublic) @@ -651,18 +681,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, cons NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey)); - if ((!mConsensus) && (mMode == omFULL)) - { - uint256 networkClosed; - std::vector peerList = theApp->getConnectionPool().getPeerVector(); - bool ledgerChange = checkLastClosedLedger(peerList, networkClosed); - if (!ledgerChange) - { - Log(lsWARNING) << "Beginning consensus due to proposal from peer"; - beginConsensus(networkClosed, theApp->getMasterLedger().getCurrentLedger()); - } - } - if (!mConsensus) + if (!haveConsensusObject()) { Log(lsINFO) << "Received proposal outside consensus window"; return mMode != omFULL; @@ -704,7 +723,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, cons SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash) { - if (!mConsensus) + if (!haveConsensusObject()) return SHAMap::pointer(); return mConsensus->getTransactionTree(hash, false); } @@ -712,21 +731,24 @@ SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash) bool NetworkOPs::gotTXData(const boost::shared_ptr& peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { - if (!mConsensus) + if (!haveConsensusObject()) return false; return mConsensus->peerGaveNodes(peer, hash, nodeIDs, nodeData); } bool NetworkOPs::hasTXSet(const boost::shared_ptr& peer, const uint256& set, newcoin::TxSetStatus status) { - if (!mConsensus) + if (!haveConsensusObject()) + { + Log(lsINFO) << "Peer has TX set, not during consensus"; return false; + } return mConsensus->peerHasSet(peer, set, status); } void NetworkOPs::mapComplete(const uint256& hash, SHAMap::ref map) { - if (mConsensus) + if (!haveConsensusObject()) mConsensus->mapComplete(hash, map, true); } @@ -832,6 +854,11 @@ Json::Value NetworkOPs::getServerInfo() if (!theConfig.VALIDATION_SEED.isValid()) info["serverState"] = "none"; else info["validationPKey"] = NewcoinAddress::createNodePublic(theConfig.VALIDATION_SEED).humanNodePublic(); + Json::Value lastClose = Json::objectValue; + lastClose["proposers"] = theApp->getOPs().getPreviousProposers(); + lastClose["convergeTime"] = theApp->getOPs().getPreviousConvergeTime(); + info["lastClose"] = lastClose; + if (mConsensus) info["consensus"] = mConsensus->getJson(); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index cc84f9f89a..4c64374f17 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -84,6 +84,7 @@ protected: Json::Value transJson(const SerializedTransaction& stTxn, TER terResult, const std::string& strStatus, int iSeq, const std::string& strType); void pubTransactionAll(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState); void pubTransactionAccounts(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, const char* pState); + bool haveConsensusObject(); Json::Value pubBootstrapAccountInfo(Ledger::ref lpAccepted, const NewcoinAddress& naAccountID); diff --git a/src/Peer.cpp b/src/Peer.cpp index 641a33571c..db4ca281b4 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -937,7 +937,6 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) if (packet.itype() == newcoin::liTS_CANDIDATE) { // Request is for a transaction candidate set Log(lsINFO) << "Received request for TX candidate set data " << getIP(); - Ledger::pointer ledger; if ((!packet.has_ledgerhash() || packet.ledgerhash().size() != 32)) { punishPeer(PP_INVALID_REQUEST); @@ -948,7 +947,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) map = theApp->getOPs().getTXMap(txHash); if (!map) { - Log(lsERROR) << "We do not hav the map our peer wants"; + Log(lsERROR) << "We do not have the map our peer wants"; punishPeer(PP_INVALID_REQUEST); return; } diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp index a89562dd01..2994034c89 100644 --- a/src/TransactionEngine.cpp +++ b/src/TransactionEngine.cpp @@ -345,11 +345,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa terResult = terPRE_SEQ; } else if (mLedger->hasTransaction(txID)) - { - Log(lsWARNING) << "applyTransaction: duplicate sequence number"; - terResult = tefALREADY; - } else { Log(lsWARNING) << "applyTransaction: past sequence number"; From 414a44b6b5c3fdc65f0d8e41574811cda0749af1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 4 Oct 2012 02:19:47 -0700 Subject: [PATCH 426/426] Prevent a race condition that can cause us to miss an "I have a transaction set" message if it arrives as we're in the process of generating a new last-closed ledger. --- src/LedgerConsensus.cpp | 8 ++++++++ src/Peer.cpp | 27 ++++++++++++++++++++++++--- src/Peer.h | 3 +++ 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 65730e8177..b96589212a 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -790,6 +790,14 @@ void LedgerConsensus::startAcquiring(const TransactionAcquire::pointer& acquire) } } } + + std::vector peerList = theApp->getConnectionPool().getPeerVector(); + BOOST_FOREACH(Peer::ref peer, peerList) + { + if (peer->hasTxSet(acquire->getHash()) + acquire->peerHash(peer); + } + acquire->resetTimer(); } diff --git a/src/Peer.cpp b/src/Peer.cpp index db4ca281b4..2397071ae1 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -744,8 +744,11 @@ void Peer::recvHaveTxSet(newcoin::TMHaveTransactionSet& packet) punishPeer(PP_INVALID_REQUEST); return; } - memcpy(hashes.begin(), packet.hash().data(), 32); - if (!theApp->getOPs().hasTXSet(shared_from_this(), hashes, packet.status())) + uint256 hash; + memcpy(hash.begin(), packet.hash().data(), 32); + if (packet.status() == newcoin::tsHAVE) + addTxSet(hash); + if (!theApp->getOPs().hasTXSet(shared_from_this(), hash, packet.status())) punishPeer(PP_UNWANTED_DATA); } @@ -1142,11 +1145,29 @@ void Peer::addLedger(const uint256& hash) BOOST_FOREACH(const uint256& ledger, mRecentLedgers) if (ledger == hash) return; - if (mRecentLedgers.size() == 16) + if (mRecentLedgers.size() == 128) mRecentLedgers.pop_front(); mRecentLedgers.push_back(hash); } +bool Peer::hasTxSet(const uint256& hash) const +{ + BOOST_FOREACH(const uint256& set, mRecentTxSets) + if (set == hash) + return true; + return false; +} + +void Peer::addTxSet(const uint256& hash) +{ + BOOST_FOREACH(const uint256& set, mRecentTxSets) + if (set == hash) + return; + if (mRecentTxSets.size() == 128) + mRecentTxSets.pop_front(); + mRecentTxSets.push_back(hash); +} + // Get session information we can sign to prevent man in the middle attack. // (both sides get the same information, neither side controls it) void Peer::getSessionCookie(std::string& strDst) diff --git a/src/Peer.h b/src/Peer.h index ae4abf7307..0b28a1dc9b 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -46,6 +46,7 @@ private: uint256 mClosedLedgerHash, mPreviousLedgerHash; std::list mRecentLedgers; + std::list mRecentTxSets; boost::asio::ssl::stream mSocketSsl; @@ -118,6 +119,7 @@ protected: void getSessionCookie(std::string& strDst); void addLedger(const uint256& ledger); + void addTxSet(const uint256& TxSet); public: @@ -157,6 +159,7 @@ public: uint256 getClosedLedgerHash() const { return mClosedLedgerHash; } bool hasLedger(const uint256& hash) const; + bool hasTxSet(const uint256& hash) const; NewcoinAddress getNodePublic() const { return mNodePublic; } void cycleStatus() { mPreviousLedgerHash = mClosedLedgerHash; mClosedLedgerHash.zero(); } };