From bcd08c368c19ace041ff8b6324a1a50038b0961e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 28 Aug 2012 04:05:19 -0700 Subject: [PATCH 1/2] 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 7bf224200b2b8e6665ea0e27bd967cf19ac00a2b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 28 Aug 2012 15:31:41 -0700 Subject: [PATCH 2/2] 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);