diff --git a/src/cpp/ripple/LedgerEntrySet.cpp b/src/cpp/ripple/LedgerEntrySet.cpp index 5edd8944b5..23ee1bc7f7 100644 --- a/src/cpp/ripple/LedgerEntrySet.cpp +++ b/src/cpp/ripple/LedgerEntrySet.cpp @@ -486,6 +486,35 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, TER result, uint32 index) cLog(lsTRACE) << "Metadata:" << mSet.getJson(0); } +TER LedgerEntrySet::dirCount(const uint256& uRootIndex, uint32& uCount) +{ + uint64 uNodeDir = 0; + + uCount = 0; + + do + { + SLE::pointer sleNode = entryCache(ltDIR_NODE, Ledger::getDirNodeIndex(uRootIndex, uNodeDir)); + + if (sleNode) + { + uCount += sleNode->getFieldV256(sfIndexes).peekValue().size(); + + uNodeDir = sleNode->getFieldU64(sfIndexNext); // Get next node. + } + else if (uNodeDir) + { + cLog(lsWARNING) << "dirCount: no such node"; + + assert(false); + + return tefBAD_LEDGER; + } + } while (uNodeDir); + + return tesSUCCESS; +} + // <-- 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. @@ -814,11 +843,53 @@ bool LedgerEntrySet::dirNext( return true; } +// If there is a count, adjust the owner count by iAmount. Otherwise, compute the owner count and store it. +TER LedgerEntrySet::ownerCountAdjust(const uint160& uOwnerID, int iAmount, SLE::ref sleAccountRoot) +{ + SLE::pointer sleHold = sleAccountRoot + ? SLE::pointer() + : entryCache(ltACCOUNT_ROOT, Ledger::getAccountRootIndex(uOwnerID)); + + SLE::ref sleRoot = sleAccountRoot + ? sleAccountRoot + : sleHold; + + const bool bHaveOwnerCount = sleRoot->isFieldPresent(sfOwnerCount); + TER terResult; + + if (bHaveOwnerCount) + { + const uint32 uOwnerCount = sleRoot->getFieldU32(sfOwnerCount); + + sleRoot->setFieldU32(sfOwnerCount, uOwnerCount+iAmount); + + terResult = tesSUCCESS; + } + else + { + uint32 uActualCount; + + terResult = dirCount(Ledger::getOwnerDirIndex(uOwnerID), uActualCount); + + if (tesSUCCESS == terResult) + { + sleRoot->setFieldU32(sfOwnerCount, uActualCount); + } + } + + return terResult; +} + TER LedgerEntrySet::offerDelete(const SLE::pointer& sleOffer, const uint256& uOfferIndex, const uint160& uOwnerID) { uint64 uOwnerNode = sleOffer->getFieldU64(sfOwnerNode); TER terResult = dirDelete(false, uOwnerNode, Ledger::getOwnerDirIndex(uOwnerID), uOfferIndex, false); + if (tesSUCCESS == terResult) + { + terResult = ownerCountAdjust(uOwnerID, -1); + } + if (tesSUCCESS == terResult) { uint256 uDirectory = sleOffer->getFieldH256(sfBookDirectory); diff --git a/src/cpp/ripple/LedgerEntrySet.h b/src/cpp/ripple/LedgerEntrySet.h index ea91ff9fbb..6015f94896 100644 --- a/src/cpp/ripple/LedgerEntrySet.h +++ b/src/cpp/ripple/LedgerEntrySet.h @@ -99,8 +99,11 @@ public: 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); + 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 dirCount(const uint256& uDirIndex, uint32& uCount); + + TER ownerCountAdjust(const uint160& uOwnerID, int iAmount, SLE::ref sleAccountRoot=SLE::pointer()); // Offer functions. TER offerDelete(const uint256& uOfferIndex); diff --git a/src/cpp/ripple/OfferCancelTransactor.cpp b/src/cpp/ripple/OfferCancelTransactor.cpp index 2110c037e9..0eaff9daa8 100644 --- a/src/cpp/ripple/OfferCancelTransactor.cpp +++ b/src/cpp/ripple/OfferCancelTransactor.cpp @@ -38,4 +38,6 @@ TER OfferCancelTransactor::doApply() } return terResult; -} \ No newline at end of file +} + +// vim:ts=4 diff --git a/src/cpp/ripple/OfferCreateTransactor.cpp b/src/cpp/ripple/OfferCreateTransactor.cpp index 9e1bb20fe5..55a3d4a8b0 100644 --- a/src/cpp/ripple/OfferCreateTransactor.cpp +++ b/src/cpp/ripple/OfferCreateTransactor.cpp @@ -399,6 +399,12 @@ TER OfferCreateTransactor::doApply() boost::bind(&Ledger::qualityDirDescriber, _1, saTakerPays.getCurrency(), uPaysIssuerID, saTakerGets.getCurrency(), uGetsIssuerID, uRate)); + // Update owner count. + if (tesSUCCESS == terResult) + { + terResult = mEngine->getNodes().ownerCountAdjust(mTxnAccountID, 1, mTxnAccount); + } + if (tesSUCCESS == terResult) { uint256 uBookBase = Ledger::getBookBase(uPaysCurrency, uPaysIssuerID, uGetsCurrency, uGetsIssuerID); diff --git a/src/cpp/ripple/Transactor.h b/src/cpp/ripple/Transactor.h index 88a1a6764b..1c456637df 100644 --- a/src/cpp/ripple/Transactor.h +++ b/src/cpp/ripple/Transactor.h @@ -9,25 +9,25 @@ class Transactor { protected: - const SerializedTransaction& mTxn; - TransactionEngine* mEngine; - TransactionEngineParams mParams; + const SerializedTransaction& mTxn; + TransactionEngine* mEngine; + TransactionEngineParams mParams; - uint160 mTxnAccountID; - STAmount mFeeDue; - STAmount mSourceBalance; - SLE::pointer mTxnAccount; - bool mHasAuthKey; - RippleAddress mSigningPubKey; - + uint160 mTxnAccountID; + STAmount mFeeDue; + STAmount mSourceBalance; + SLE::pointer mTxnAccount; + bool mHasAuthKey; + RippleAddress mSigningPubKey; TER preCheck(); TER checkSeq(); TER payFee(); + virtual void calculateFee(); virtual TER checkSig(); virtual TER doApply()=0; - + Transactor(const SerializedTransaction& txn, TransactionEngineParams params, TransactionEngine* engine); public: @@ -38,4 +38,6 @@ public: TER apply(); }; -#endif \ No newline at end of file +#endif + +// vim:ts=4 diff --git a/src/cpp/ripple/TrustSetTransactor.cpp b/src/cpp/ripple/TrustSetTransactor.cpp index 3403c40389..54e1efc124 100644 --- a/src/cpp/ripple/TrustSetTransactor.cpp +++ b/src/cpp/ripple/TrustSetTransactor.cpp @@ -53,7 +53,12 @@ TER TrustSetTransactor::doApply() if (sleRippleState) { // A line exists in one or more directions. + #if 0 + // We might delete a ripple state node if everything is set to defaults. + // However, this is problematic as it may make predicting reserve amounts harder for users. + // The code here is incomplete. + if (!saLimitAmount) { // Zeroing line. @@ -135,7 +140,7 @@ TER TrustSetTransactor::doApply() if (uQualityOut) sleRippleState->setFieldU32(bFlipped ? sfHighQualityOut : sfLowQualityOut, uQualityOut); - uint64 uSrcRef; // Ignored, dirs never delete. + uint64 uSrcRef; // <-- Ignored, dirs never delete. terResult = mEngine->getNodes().dirAdd( uSrcRef, @@ -143,12 +148,18 @@ TER TrustSetTransactor::doApply() sleRippleState->getIndex(), boost::bind(&Ledger::ownerDirDescriber, _1, mTxnAccountID)); + if (tesSUCCESS == terResult) + terResult = mEngine->getNodes().ownerCountAdjust(mTxnAccountID, 1, mTxnAccount); + if (tesSUCCESS == terResult) terResult = mEngine->getNodes().dirAdd( uSrcRef, Ledger::getOwnerDirIndex(uDstAccountID), sleRippleState->getIndex(), boost::bind(&Ledger::ownerDirDescriber, _1, uDstAccountID)); + + if (tesSUCCESS == terResult) + terResult = mEngine->getNodes().ownerCountAdjust(uDstAccountID, 1, sleDst); } Log(lsINFO) << "doTrustSet<";