From e02e785a723a7910a346c64af5bc1b069a1f3d59 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 27 Aug 2012 12:22:03 -0700 Subject: [PATCH 1/7] 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 2/7] 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 3/7] 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 4/7] 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 5/7] 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 192c64461dfe86c5b7ec62def347fd9018ba0c53 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 28 Aug 2012 15:35:47 -0700 Subject: [PATCH 6/7] 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 7/7] 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;"); }