diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 34bd631e29..1a71d79bc1 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -67,7 +67,7 @@ void PeerSet::TimerEntry(boost::weak_ptr wptr, const boost::system::err } LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE_TIMEOUT), - mHaveBase(false), mHaveState(false), mHaveTransactions(false) + mFilter(&theApp->getNodeCache()), mHaveBase(false), mHaveState(false), mHaveTransactions(false) { #ifdef DEBUG std::cerr << "Acquiring ledger " << mHash.GetHex() << std::endl; @@ -152,7 +152,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) { std::vector nodeIDs; std::vector nodeHashes; - mLedger->peekTransactionMap()->getMissingNodes(nodeIDs, nodeHashes, 128); + mLedger->peekTransactionMap()->getMissingNodes(nodeIDs, nodeHashes, 128, &mFilter); if (nodeIDs.empty()) { if (!mLedger->peekTransactionMap()->isValid()) mFailed = true; @@ -204,7 +204,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) { std::vector nodeIDs; std::vector nodeHashes; - mLedger->peekAccountStateMap()->getMissingNodes(nodeIDs, nodeHashes, 128); + mLedger->peekAccountStateMap()->getMissingNodes(nodeIDs, nodeHashes, 128, &mFilter); if (nodeIDs.empty()) { if (!mLedger->peekAccountStateMap()->isValid()) mFailed = true; @@ -303,7 +303,7 @@ bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait)) return false; } - else if (!mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait)) + else if (!mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait, &mFilter)) return false; ++nodeIDit; ++nodeDatait; @@ -333,7 +333,7 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), *nodeDatait)) return false; } - else if (!mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait)) + else if (!mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait, &mFilter)) return false; ++nodeIDit; ++nodeDatait; diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index 7e92d024f2..bffe386998 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -13,6 +13,7 @@ #include "Ledger.h" #include "Peer.h" +#include "TaggedCache.h" #include "../obj/src/newcoin.pb.h" class PeerSet @@ -53,6 +54,30 @@ private: static void TimerEntry(boost::weak_ptr, const boost::system::error_code& result); }; +typedef TaggedCache< uint256, std::vector > NodeCache; +typedef std::vector VUC; + +class THSyncFilter : public SHAMapSyncFilter +{ +protected: + NodeCache* mCache; + +public: + THSyncFilter(NodeCache* cache) : mCache(cache) { ; } + virtual void gotNode(const uint256& nodeHash, const std::vector& nodeData, bool) + { + boost::shared_ptr ptr = boost::make_shared(nodeData); + mCache->canonicalize(nodeHash, ptr); + } + virtual bool haveNode(const uint256& nodeHash, std::vector& nodeData) + { + boost::shared_ptr entry = mCache->fetch(nodeHash); + if (!entry) return false; + nodeData = *entry; + return true; + } +}; + class LedgerAcquire : public PeerSet, public boost::enable_shared_from_this { // A ledger we are trying to acquire public: @@ -60,6 +85,7 @@ public: protected: Ledger::pointer mLedger; + THSyncFilter mFilter; bool mHaveBase, mHaveState, mHaveTransactions; std::vector< boost::function > mOnComplete; @@ -106,4 +132,5 @@ public: }; #endif + // vim:ts=4 diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index e2c95fbe84..d1bae73334 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -11,7 +11,8 @@ #define TRUST_NETWORK -TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, 1), mHaveRoot(false) +TransactionAcquire::TransactionAcquire(const uint256& hash) + : PeerSet(hash, 1), mFilter(&theApp->getNodeCache()), mHaveRoot(false) { mMap = boost::make_shared(); mMap->setSynching(); @@ -48,7 +49,7 @@ void TransactionAcquire::trigger(Peer::pointer peer) Log(lsTRACE) << "Have root"; std::vector nodeIDs; std::vector nodeHashes; - mMap->getMissingNodes(nodeIDs, nodeHashes, 256); + mMap->getMissingNodes(nodeIDs, nodeHashes, 256, &mFilter); if (nodeIDs.empty()) { if (mMap->isValid()) @@ -100,7 +101,7 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, return false; else mHaveRoot = true; } - else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait)) + else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait, &mFilter)) return false; ++nodeIDit; ++nodeDatait; diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 9541f926c3..3a6aeaecde 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -21,6 +21,7 @@ public: protected: SHAMap::pointer mMap; + THSyncFilter mFilter; // FIXME: Should use transaction master too bool mHaveRoot; void onTimer() { trigger(Peer::pointer()); } diff --git a/src/SHAMap.h b/src/SHAMap.h index 329ce65f6e..175958ab49 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -219,6 +219,17 @@ enum SHAMapState Invalid = 4, // Map is known not to be valid (usually synching a corrupt ledger) }; +class SHAMapSyncFilter +{ +public: + SHAMapSyncFilter() { ; } + virtual ~SHAMapSyncFilter() { ; } + virtual void gotNode(const uint256& nodeHash, const std::vector& nodeData, bool isLeaf) + { ; } + virtual bool haveNode(const uint256&nodeHash, std::vector& nodeData) + { return false; } +}; + class SHAMap { public: @@ -293,12 +304,14 @@ public: SHAMapItem::pointer peekPrevItem(const uint256&); // comparison/sync functions - void getMissingNodes(std::vector& nodeIDs, std::vector& hashes, int max); + void getMissingNodes(std::vector& nodeIDs, std::vector& hashes, int max, + SHAMapSyncFilter* filter); bool getNodeFat(const SHAMapNode& node, std::vector& nodeIDs, std::list >& rawNode, bool fatLeaves); bool addRootNode(const uint256& hash, const std::vector& rootNode); bool addRootNode(const std::vector& rootNode); - bool addKnownNode(const SHAMapNode& nodeID, const std::vector& rawNode); + bool addKnownNode(const SHAMapNode& nodeID, const std::vector& rawNode, + SHAMapSyncFilter* filter); // status functions void setImmutable(void) { assert(mState != Invalid); mState = Immutable; } diff --git a/src/SHAMapSync.cpp b/src/SHAMapSync.cpp index aca6891d54..54c7a0d20d 100644 --- a/src/SHAMapSync.cpp +++ b/src/SHAMapSync.cpp @@ -11,7 +11,8 @@ #include "Log.h" -void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vector& hashes, int max) +void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vector& hashes, int max, + SHAMapSyncFilter* filter) { boost::recursive_mutex::scoped_lock sl(mLock); @@ -44,6 +45,24 @@ void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vectorisEmptyBranch(branch)) { SHAMapTreeNode::pointer d = getNode(node->getChildNodeID(branch), node->getChildHash(branch), false); + if ((!d) && (filter != NULL)) + { + std::vector nodeData; + if (filter->haveNode(node->getChildHash(branch), nodeData)) + { + d = boost::make_shared(node->getChildNodeID(branch), nodeData, mSeq); + if (node->getChildHash(branch) != d->getNodeHash()) + { + Log(lsERROR) << "Wrong hash from cached object"; + d = SHAMapTreeNode::pointer(); + } + else + { + Log(lsTRACE) << "Got sync node from cache"; + mTNByID[*d] = d; + } + } + } if (!d) { nodeIDs.push_back(node->getChildNodeID(branch)); @@ -153,7 +172,8 @@ bool SHAMap::addRootNode(const uint256& hash, const std::vector& return true; } -bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector& rawNode) +bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector& rawNode, + SHAMapSyncFilter* filter) { // return value: true=okay, false=error assert(!node.isRoot()); if (!isSynching()) return false; @@ -199,6 +219,8 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vectorgetNodeHash()) // these aren't the droids we're looking for return false; + if (filter) filter->gotNode(hash, rawNode, newNode->isLeaf()); + mTNByID[*newNode] = newNode; if (!newNode->isLeaf()) return true; // only a leaf can fill a branch @@ -416,7 +438,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) hashes.clear(); // get the list of nodes we know we need - destination.getMissingNodes(nodeIDs, hashes, 2048); + destination.getMissingNodes(nodeIDs, hashes, 2048, NULL); if(nodeIDs.empty()) break; Log(lsINFO) << nodeIDs.size() << " needed nodes"; @@ -446,7 +468,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) #ifdef SMS_DEBUG bytes += rawNodeIterator->size(); #endif - if (!destination.addKnownNode(*nodeIDIterator, *rawNodeIterator)) + if (!destination.addKnownNode(*nodeIDIterator, *rawNodeIterator, NULL)) { Log(lsTRACE) << "AddKnownNode fails"; BOOST_FAIL("AddKnownNode");