diff --git a/src/cpp/ripple/LedgerAcquire.cpp b/src/cpp/ripple/LedgerAcquire.cpp index 0d979f61d..c3387cf5f 100644 --- a/src/cpp/ripple/LedgerAcquire.cpp +++ b/src/cpp/ripple/LedgerAcquire.cpp @@ -396,7 +396,7 @@ bool LedgerAcquire::takeBase(const std::string& data) } bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, - const std::list< std::vector >& data) + const std::list< std::vector >& data, SMAddNode& san) { if (!mHaveBase) return false; std::list::const_iterator nodeIDit = nodeIDs.begin(); @@ -406,11 +406,15 @@ bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, { if (nodeIDit->isRoot()) { - if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, snfWIRE, &tFilter)) + if (!san.combine(mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, + snfWIRE, &tFilter))) + return false; + } + else + { + if (!san.combine(mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter))) return false; } - else if (!mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter)) - return false; ++nodeIDit; ++nodeDatait; } @@ -428,7 +432,7 @@ bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, } bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, - const std::list< std::vector >& data) + const std::list< std::vector >& data, SMAddNode& san) { cLog(lsTRACE) << "got ASdata (" << nodeIDs.size() <<") acquiring ledger " << mHash; tLog(nodeIDs.size() == 1, lsTRACE) << "got AS node: " << nodeIDs.front(); @@ -446,14 +450,14 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, { if (nodeIDit->isRoot()) { - if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), - *nodeDatait, snfWIRE, &tFilter)) + if (!san.combine(mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), + *nodeDatait, snfWIRE, &tFilter))) { cLog(lsWARNING) << "Bad ledger base"; return false; } } - else if (!mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter)) + else if (!san.combine(mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter))) { cLog(lsWARNING) << "Unable to add AS node"; return false; @@ -474,24 +478,22 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, return true; } -bool LedgerAcquire::takeAsRootNode(const std::vector& data) +bool LedgerAcquire::takeAsRootNode(const std::vector& data, SMAddNode& san) { if (!mHaveBase) return false; AccountStateSF tFilter(mLedger->getHash(), mLedger->getLedgerSeq()); - if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, snfWIRE, &tFilter)) - return false; - return true; + return san.combine( + mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, snfWIRE, &tFilter)); } -bool LedgerAcquire::takeTxRootNode(const std::vector& data) +bool LedgerAcquire::takeTxRootNode(const std::vector& data, SMAddNode& san) { if (!mHaveBase) return false; TransactionStateSF tFilter(mLedger->getHash(), mLedger->getLedgerSeq()); - if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, snfWIRE, &tFilter)) - return false; - return true; + return san.combine( + mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, snfWIRE, &tFilter)); } LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash) @@ -532,13 +534,13 @@ void LedgerAcquireMaster::dropLedger(const uint256& hash) mLedgers.erase(hash); } -bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref peer) +SMAddNode LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref peer) { uint256 hash; if (packet.ledgerhash().size() != 32) { std::cerr << "Acquire error" << std::endl; - return false; + return SMAddNode::invalid(); } memcpy(hash.begin(), packet.ledgerhash().data(), 32); cLog(lsTRACE) << "Got data (" << packet.nodes().size() << ") for acquiring ledger: " << hash; @@ -547,7 +549,7 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref if (!ledger) { cLog(lsINFO) << "Got data for ledger we're not acquiring"; - return false; + return SMAddNode(); } if (packet.type() == ripple::liBASE) @@ -555,23 +557,24 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref if (packet.nodes_size() < 1) { cLog(lsWARNING) << "Got empty base data"; - return false; + return SMAddNode::invalid(); } if (!ledger->takeBase(packet.nodes(0).nodedata())) { cLog(lsWARNING) << "Got invalid base data"; - return false; + return SMAddNode::invalid(); } - if ((packet.nodes().size() > 1) && !ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata()))) + SMAddNode san = SMAddNode::useful(); + if ((packet.nodes().size() > 1) && !ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata()), san)) { cLog(lsWARNING) << "Included ASbase invalid"; } - if ((packet.nodes().size() > 2) && !ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata()))) + if ((packet.nodes().size() > 2) && !ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata()), san)) { cLog(lsWARNING) << "Included TXbase invalid"; } ledger->trigger(peer, false); - return true; + return san; } if ((packet.type() == ripple::liTX_NODE) || (packet.type() == ripple::liAS_NODE)) @@ -581,8 +584,8 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref if (packet.nodes().size() <= 0) { - cLog(lsINFO) << "Got request for no nodes"; - return false; + cLog(lsINFO) << "Got response with no nodes"; + return SMAddNode::invalid(); } for (int i = 0; i < packet.nodes().size(); ++i) { @@ -590,24 +593,24 @@ bool LedgerAcquireMaster::gotLedgerData(ripple::TMLedgerData& packet, Peer::ref if (!node.has_nodeid() || !node.has_nodedata()) { cLog(lsWARNING) << "Got bad node"; - return false; + return SMAddNode::invalid(); } nodeIDs.push_back(SHAMapNode(node.nodeid().data(), node.nodeid().size())); nodeData.push_back(std::vector(node.nodedata().begin(), node.nodedata().end())); } - bool ret; + SMAddNode ret; if (packet.type() == ripple::liTX_NODE) - ret = ledger->takeTxNode(nodeIDs, nodeData); + ledger->takeTxNode(nodeIDs, nodeData, ret); else - ret = ledger->takeAsNode(nodeIDs, nodeData); - if (ret) + ledger->takeAsNode(nodeIDs, nodeData, ret); + if (!ret.isInvalid()) ledger->trigger(peer, false); return ret; } cLog(lsWARNING) << "Not sure what ledger data we got"; - return false; + return SMAddNode::invalid(); } // vim:ts=4 diff --git a/src/cpp/ripple/LedgerAcquire.h b/src/cpp/ripple/LedgerAcquire.h index eab3e47d8..2f9778c56 100644 --- a/src/cpp/ripple/LedgerAcquire.h +++ b/src/cpp/ripple/LedgerAcquire.h @@ -97,10 +97,12 @@ public: void addOnComplete(boost::function); bool takeBase(const std::string& data); - bool takeTxNode(const std::list& IDs, const std::list >& data); - bool takeTxRootNode(const std::vector& data); - bool takeAsNode(const std::list& IDs, const std::list >& data); - bool takeAsRootNode(const std::vector& data); + bool takeTxNode(const std::list& IDs, const std::list >& data, + SMAddNode&); + bool takeTxRootNode(const std::vector& data, SMAddNode&); + bool takeAsNode(const std::list& IDs, const std::list >& data, + SMAddNode&); + bool takeAsRootNode(const std::vector& data, SMAddNode&); void trigger(Peer::ref, bool timer); bool tryLocal(); void addPeers(); @@ -119,7 +121,7 @@ public: LedgerAcquire::pointer find(const uint256& hash); bool hasLedger(const uint256& ledgerHash); void dropLedger(const uint256& ledgerHash); - bool gotLedgerData(ripple::TMLedgerData& packet, Peer::ref); + SMAddNode gotLedgerData(ripple::TMLedgerData& packet, Peer::ref); }; #endif diff --git a/src/cpp/ripple/LedgerConsensus.cpp b/src/cpp/ripple/LedgerConsensus.cpp index 7cc01870d..27ac245ae 100644 --- a/src/cpp/ripple/LedgerConsensus.cpp +++ b/src/cpp/ripple/LedgerConsensus.cpp @@ -126,21 +126,23 @@ void TransactionAcquire::trigger(Peer::ref peer, bool timer) resetTimer(); } -bool TransactionAcquire::takeNodes(const std::list& nodeIDs, +SMAddNode TransactionAcquire::takeNodes(const std::list& nodeIDs, const std::list< std::vector >& data, Peer::ref peer) { if (mComplete) { cLog(lsTRACE) << "TX set complete"; - return true; + return SMAddNode(); } if (mFailed) { cLog(lsTRACE) << "TX set failed"; - return false; + return SMAddNode(); } try { + if (nodeIDs.empty()) + return SMAddNode::invalid(); std::list::const_iterator nodeIDit = nodeIDs.begin(); std::list< std::vector >::const_iterator nodeDatait = data.begin(); ConsensusTransSetSF sf; @@ -151,12 +153,12 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, if (mHaveRoot) { cLog(lsWARNING) << "Got root TXS node, already have it"; - return false; + return SMAddNode(); } if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE, NULL)) { cLog(lsWARNING) << "TX acquire got bad root node"; - return false; + return SMAddNode::invalid(); } else mHaveRoot = true; @@ -164,19 +166,19 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait, &sf)) { cLog(lsWARNING) << "TX acquire got bad non-root node"; - return false; + return SMAddNode::invalid(); } ++nodeIDit; ++nodeDatait; } trigger(peer, false); progress(); - return true; + return SMAddNode::useful(); } catch (...) { cLog(lsERROR) << "Peer sends us junky transaction node data"; - return false; + return SMAddNode::invalid(); } } @@ -996,14 +998,14 @@ bool LedgerConsensus::peerHasSet(Peer::ref peer, const uint256& hashSet, ripple: return true; } -bool LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash, +SMAddNode LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { boost::unordered_map::iterator acq = mAcquiring.find(setHash); if (acq == mAcquiring.end()) { cLog(lsINFO) << "Got TX data for set not acquiring: " << setHash; - return false; + return SMAddNode(); } TransactionAcquire::pointer set = acq->second; // We must keep the set around during the function return set->takeNodes(nodeIDs, nodeData, peer); diff --git a/src/cpp/ripple/LedgerConsensus.h b/src/cpp/ripple/LedgerConsensus.h index 1db706996..accbb4df4 100644 --- a/src/cpp/ripple/LedgerConsensus.h +++ b/src/cpp/ripple/LedgerConsensus.h @@ -45,7 +45,8 @@ public: SHAMap::pointer getMap() { return mMap; } - bool takeNodes(const std::list& IDs, const std::list< std::vector >& data, Peer::ref); + SMAddNode takeNodes(const std::list& IDs, + const std::list< std::vector >& data, Peer::ref); }; class LCTransaction @@ -184,7 +185,7 @@ public: bool peerHasSet(Peer::ref peer, const uint256& set, ripple::TxSetStatus status); - bool peerGaveNodes(Peer::ref peer, const uint256& setHash, + SMAddNode peerGaveNodes(Peer::ref peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); bool isOurPubKey(const RippleAddress &k) { return k == mValPublic; } diff --git a/src/cpp/ripple/NetworkOPs.cpp b/src/cpp/ripple/NetworkOPs.cpp index ed4847f9b..21933a88b 100644 --- a/src/cpp/ripple/NetworkOPs.cpp +++ b/src/cpp/ripple/NetworkOPs.cpp @@ -813,13 +813,13 @@ SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash) return mConsensus->getTransactionTree(hash, false); } -bool NetworkOPs::gotTXData(const boost::shared_ptr& peer, const uint256& hash, +SMAddNode NetworkOPs::gotTXData(const boost::shared_ptr& peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData) { if (!haveConsensusObject()) { cLog(lsWARNING) << "Got TX data with no consensus object"; - return false; + return SMAddNode(); } return mConsensus->peerGaveNodes(peer, hash, nodeIDs, nodeData); } diff --git a/src/cpp/ripple/NetworkOPs.h b/src/cpp/ripple/NetworkOPs.h index 778846a22..4826979e1 100644 --- a/src/cpp/ripple/NetworkOPs.h +++ b/src/cpp/ripple/NetworkOPs.h @@ -199,7 +199,7 @@ public: // ledger proposal/close functions void processTrustedProposal(LedgerProposal::pointer proposal, boost::shared_ptr set, RippleAddress nodePublic, uint256 checkLedger, bool sigGood); - bool gotTXData(const boost::shared_ptr& peer, const uint256& hash, + SMAddNode gotTXData(const boost::shared_ptr& peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); bool recvValidation(const SerializedValidation::pointer& val); SHAMap::pointer getTXMap(const uint256& hash); diff --git a/src/cpp/ripple/Peer.cpp b/src/cpp/ripple/Peer.cpp index c42108e2e..fcca1754d 100644 --- a/src/cpp/ripple/Peer.cpp +++ b/src/cpp/ripple/Peer.cpp @@ -1432,12 +1432,14 @@ void Peer::recvLedger(ripple::TMLedgerData& packet) nodeIDs.push_back(SHAMapNode(node.nodeid().data(), node.nodeid().size())); nodeData.push_back(std::vector(node.nodedata().begin(), node.nodedata().end())); } - if (!theApp->getOPs().gotTXData(shared_from_this(), hash, nodeIDs, nodeData)) + SMAddNode san = theApp->getOPs().gotTXData(shared_from_this(), hash, nodeIDs, nodeData); + if (san.isInvalid()) punishPeer(PP_UNWANTED_DATA); return; } - if (!theApp->getMasterLedgerAcquire().gotLedgerData(packet, shared_from_this())) + SMAddNode san = theApp->getMasterLedgerAcquire().gotLedgerData(packet, shared_from_this()); + if (san.isInvalid()) punishPeer(PP_UNWANTED_DATA); } diff --git a/src/cpp/ripple/Peer.h b/src/cpp/ripple/Peer.h index f3c29c0f2..c05aac0d2 100644 --- a/src/cpp/ripple/Peer.h +++ b/src/cpp/ripple/Peer.h @@ -22,6 +22,12 @@ enum PeerPunish PP_BAD_SIGNATURE = 4, // Object had bad signature }; +enum PeerReward +{ + PR_NEEDED_DATA = 1, + PR_NEW_TRANSACTION = 2, +}; + typedef std::pair ipPort; DEFINE_INSTANCE(Peer); diff --git a/src/cpp/ripple/ProofOfWork.cpp b/src/cpp/ripple/ProofOfWork.cpp index c550a9749..1e4ab5d9b 100644 --- a/src/cpp/ripple/ProofOfWork.cpp +++ b/src/cpp/ripple/ProofOfWork.cpp @@ -213,12 +213,28 @@ void ProofOfWorkGenerator::sweep() void ProofOfWorkGenerator::loadHigh() { - // WRITEME + time_t now = time(NULL); + + boost::mutex::scoped_lock sl(mLock); + if (mLastDifficultyChange == now) + return; + if (mPowEntry == 30) + return; + ++mPowEntry; + mLastDifficultyChange = now; } void ProofOfWorkGenerator::loadLow() { - // WRITEME + time_t now = time(NULL); + + boost::mutex::scoped_lock sl(mLock); + if (mLastDifficultyChange == now) + return; + if (mPowEntry == 0) + return; + --mPowEntry; + mLastDifficultyChange = now; } struct PowEntry diff --git a/src/cpp/ripple/SHAMap.h b/src/cpp/ripple/SHAMap.h index 7adc92bc2..c4d830262 100644 --- a/src/cpp/ripple/SHAMap.h +++ b/src/cpp/ripple/SHAMap.h @@ -281,6 +281,44 @@ public: extern std::ostream& operator<<(std::ostream&, const SHAMapMissingNode&); +class SMAddNode +{ // results of adding nodes +protected: + bool mInvalid, mUseful; + + SMAddNode(bool i, bool u) : mInvalid(i), mUseful(u) { ; } + +public: + SMAddNode() : mInvalid(false), mUseful(false) { ; } + + void setInvalid() { mInvalid = true; } + void setUseful() { mUseful = true; } + void reset() { mInvalid = false; mUseful = false; } + + bool isInvalid() const { return mInvalid; } + bool isUseful() const { return mUseful; } + + bool combine(const SMAddNode& n) + { + if (n.mInvalid) + { + mInvalid = true; + return false; + } + if (n.mUseful) + mUseful = true; + return true; + } + + operator bool() const { return !mInvalid; } + + static SMAddNode okay() { return SMAddNode(false, false); } + static SMAddNode useful() { return SMAddNode(false, true); } + static SMAddNode invalid() { return SMAddNode(true, false); } +}; + +extern bool SMANCombine(SMAddNode& existing, const SMAddNode& additional); + class SHAMap : public IS_INSTANCE(SHAMap) { public: @@ -374,11 +412,11 @@ public: bool getNodeFat(const SHAMapNode& node, std::vector& nodeIDs, std::list >& rawNode, bool fatRoot, bool fatLeaves); bool getRootNode(Serializer& s, SHANodeFormat format); - bool addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format, + SMAddNode addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format, SHAMapSyncFilter* filter); - bool addRootNode(const std::vector& rootNode, SHANodeFormat format, + SMAddNode addRootNode(const std::vector& rootNode, SHANodeFormat format, SHAMapSyncFilter* filter); - bool addKnownNode(const SHAMapNode& nodeID, const std::vector& rawNode, + SMAddNode addKnownNode(const SHAMapNode& nodeID, const std::vector& rawNode, SHAMapSyncFilter* filter); // status functions diff --git a/src/cpp/ripple/SHAMapSync.cpp b/src/cpp/ripple/SHAMapSync.cpp index 5c419f106..7abcf9fd8 100644 --- a/src/cpp/ripple/SHAMapSync.cpp +++ b/src/cpp/ripple/SHAMapSync.cpp @@ -135,7 +135,8 @@ bool SHAMap::getRootNode(Serializer& s, SHANodeFormat format) return true; } -bool SHAMap::addRootNode(const std::vector& rootNode, SHANodeFormat format, SHAMapSyncFilter* filter) +SMAddNode SHAMap::addRootNode(const std::vector& rootNode, SHANodeFormat format, + SHAMapSyncFilter* filter) { boost::recursive_mutex::scoped_lock sl(mLock); @@ -143,12 +144,12 @@ bool SHAMap::addRootNode(const std::vector& rootNode, SHANodeForm if (root->getNodeHash().isNonZero()) { cLog(lsTRACE) << "got root node, already have one"; - return true; + return SMAddNode::okay(); } SHAMapTreeNode::pointer node = boost::make_shared(SHAMapNode(), rootNode, 0, format); if (!node) - return false; + return SMAddNode::invalid(); #ifdef DEBUG node->dump(); @@ -170,10 +171,10 @@ bool SHAMap::addRootNode(const std::vector& rootNode, SHANodeForm filter->gotNode(*root, root->getNodeHash(), s.peekData(), root->getType()); } - return true; + return SMAddNode::useful(); } -bool SHAMap::addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format, +SMAddNode SHAMap::addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format, SHAMapSyncFilter* filter) { boost::recursive_mutex::scoped_lock sl(mLock); @@ -183,14 +184,12 @@ bool SHAMap::addRootNode(const uint256& hash, const std::vector& { cLog(lsTRACE) << "got root node, already have one"; assert(root->getNodeHash() == hash); - return true; + return SMAddNode::okay(); } SHAMapTreeNode::pointer node = boost::make_shared(SHAMapNode(), rootNode, 0, format); - if (!node) - return false; - if (node->getNodeHash() != hash) - return false; + if (!node || node->getNodeHash() != hash) + return SMAddNode::invalid(); returnNode(root, true); root = node; @@ -207,42 +206,42 @@ bool SHAMap::addRootNode(const uint256& hash, const std::vector& filter->gotNode(*root, root->getNodeHash(), s.peekData(), root->getType()); } - return true; + return SMAddNode::useful(); } -bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector& rawNode, +SMAddNode SHAMap::addKnownNode(const SHAMapNode& node, const std::vector& rawNode, SHAMapSyncFilter* filter) { // return value: true=okay, false=error assert(!node.isRoot()); if (!isSynching()) { cLog(lsINFO) << "AddKnownNode while not synching"; - return true; + return SMAddNode::okay(); } boost::recursive_mutex::scoped_lock sl(mLock); if (checkCacheNode(node)) - return true; + return SMAddNode::okay(); std::stack stack = getStack(node.getNodeID(), true, true); if (stack.empty()) { cLog(lsWARNING) << "AddKnownNode with empty stack"; - return false; + return SMAddNode::invalid(); } SHAMapTreeNode::pointer iNode = stack.top(); if (!iNode) { // we should always have a root assert(false); - return true; + return SMAddNode::invalid(); } if (iNode->isLeaf() || (iNode->getDepth() >= node.getDepth())) { cLog(lsTRACE) << "got inner node, already had it (late)"; - return true; + return SMAddNode::okay(); } if (iNode->getDepth() != (node.getDepth() - 1)) @@ -250,25 +249,25 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vector(node, rawNode, mSeq, snfWIRE); if (hash != newNode->getNodeHash()) // these aren't the droids we're looking for - return false; + return SMAddNode::invalid(); if (filter) { @@ -279,7 +278,7 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vectorisLeaf()) - return true; // only a leaf can fill a branch + return SMAddNode::useful(); // only a leaf can fill a branch // did this new leaf cause its parents to fill up do @@ -294,11 +293,11 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vectorgetChildNodeID(i), iNode->getChildHash(i), false); if (nextNode->isInner() && !nextNode->isFullBelow()) - return true; + return SMAddNode::useful(); } catch (SHAMapMissingNode&) { - return true; + return SMAddNode::useful(); } } iNode->setFullBelow(); @@ -306,7 +305,7 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vectorisFullBelow()) clearSynching(); - return true; + return SMAddNode::useful(); } bool SHAMap::deepCompare(SHAMap& other) @@ -486,6 +485,8 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) cLog(lsFATAL) << "Didn't get root node " << gotNodes.size(); BOOST_FAIL("NodeSize"); } + + SMAddNode node(); if (!destination.addRootNode(*gotNodes.begin(), snfWIRE, NULL)) { cLog(lsFATAL) << "AddRootNode fails";