From 0630a4b7f417f0b3362ed06954930fdc9af77e83 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 5 Oct 2012 03:46:24 -0700 Subject: [PATCH] We have to track the high node ID of trusted validators as a tie-breaker. 1) Change return from getCurrentValidations 2) Log tiebreaker logic to aid debugging 3) Change checkLastClosedLedger to use the new tie-breaker logic 4) Log when we refuse to switch to our own previous ledger 5) Track node ID in the serialized validation object 6) Simplify getCurrentValidations ledger suppression logic --- src/LedgerConsensus.cpp | 16 ++++++------ src/NetworkOPs.cpp | 35 +++++++++++++++++++------- src/SerializedValidation.cpp | 9 ++++++- src/SerializedValidation.h | 2 ++ src/ValidationCollection.cpp | 48 +++++++++++++++++++----------------- src/ValidationCollection.h | 4 ++- 6 files changed, 72 insertions(+), 42 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index fc18926b48..f5ed0dde0b 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -259,15 +259,15 @@ void LedgerConsensus::checkLCL() int netLgrCount = 0; uint256 favoredLedger = (mState == lcsPRE_CLOSE) ? uint256() : mPrevLedgerHash; // Don't get stuck one ledger behind - boost::unordered_map vals = - theApp->getValidations().getCurrentValidations(favoredLedger); + boost::unordered_map vals = + theApp->getValidations().getCurrentValidations(favoredLedger); - typedef std::pair u256_int_pair; - BOOST_FOREACH(u256_int_pair& it, vals) - if (it.second > netLgrCount) + typedef std::pair u256_cvc_pair; + BOOST_FOREACH(u256_cvc_pair& it, vals) + if (it.second.first > netLgrCount) { netLgr = it.first; - netLgrCount = it.second; + netLgrCount = it.second.first; } if (netLgr != mPrevLedgerHash) @@ -287,8 +287,8 @@ void LedgerConsensus::checkLCL() Log(lsWARNING) << mPrevLedgerHash << " to " << netLgr; #ifdef DEBUG - BOOST_FOREACH(u256_int_pair& it, vals) - Log(lsDEBUG) << "V: " << it.first << ", " << it.second; + BOOST_FOREACH(u256_cvc_pair& it, vals) + Log(lsDEBUG) << "V: " << it.first << ", " << it.second.first; #endif if (mHaveCorrectLCL) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 4f24651c92..27e28d413c 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -372,7 +372,7 @@ class ValidationCount { public: int trustedValidations, nodesUsing; - NewcoinAddress highNode; + uint160 highNodeUsing, highValidation; ValidationCount() : trustedValidations(0), nodesUsing(0) { ; } bool operator>(const ValidationCount& v) @@ -383,8 +383,9 @@ public: { if (nodesUsing > v.nodesUsing) return true; if (nodesUsing < v.nodesUsing) return false; + return highNodeUsing > v.highNodeUsing; } - return highNode > v.highNode; + return highValidation > v.highValidation; } }; @@ -474,10 +475,16 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis boost::unordered_map ledgers; { - boost::unordered_map current = theApp->getValidations().getCurrentValidations(closedLedger); - typedef std::pair u256_int_pair; - BOOST_FOREACH(u256_int_pair& it, current) - ledgers[it.first].trustedValidations += it.second; + boost::unordered_map current = + theApp->getValidations().getCurrentValidations(closedLedger); + typedef std::pair u256_cvc_pair; + BOOST_FOREACH(u256_cvc_pair& it, current) + { + ValidationCount& vc = ledgers[it.first]; + vc.trustedValidations += it.second.first; + if (it.second.second > vc.highValidation) + vc.highValidation = it.second.second; + } } ValidationCount& ourVC = ledgers[closedLedger]; @@ -485,7 +492,9 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis if ((theConfig.LEDGER_CREATOR) && (mMode >= omTRACKING)) { ++ourVC.nodesUsing; - ourVC.highNode = theApp->getWallet().getNodePublic(); + uint160 ourAddress = theApp->getWallet().getNodePublic().getNodeID(); + if (ourAddress > ourVC.highNodeUsing) + ourVC.highNodeUsing = ourAddress; } BOOST_FOREACH(Peer::ref it, peerList) @@ -500,8 +509,8 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis 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().getNodeID() > vc.highNodeUsing)) + vc.highNodeUsing = it->getNodePublic().getNodeID(); ++vc.nodesUsing; } } @@ -516,6 +525,13 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis { Log(lsTRACE) << "L: " << it->first << " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; + + // Temporary logging to make sure tiebreaking isn't broken + if (it->second.trustedValidations > 0) + Log(lsTRACE) << " TieBreakTV: " << it->second.highValidation; + else if (it->second.nodesUsing > 0) + Log(lsTRACE) << " TieBreakNU: " << it->second.highNodeUsing; + if (it->second > bestVC) { bestVC = it->second; @@ -526,6 +542,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis if (switchLedgers && (closedLedger == prevClosedLedger)) { // don't switch to our own previous ledger + Log(lsINFO) << "We won't switch to our own previous ledger"; networkClosed = ourClosed->getHash(); switchLedgers = false; } diff --git a/src/SerializedValidation.cpp b/src/SerializedValidation.cpp index 646fc3d9ff..f95866a514 100644 --- a/src/SerializedValidation.cpp +++ b/src/SerializedValidation.cpp @@ -27,6 +27,8 @@ const uint32 SerializedValidation::sFullFlag = 0x1; SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSignature) : STObject(sValidationFormat, sit, sfValidation), mTrusted(false) { + mNodeID = NewcoinAddress::createNodePublic(getFieldVL(sfSigningPubKey)).getNodeID(); + assert(mNodeID.isNonZero()); if (checkSignature && !isValid()) { Log(lsTRACE) << "Invalid validation " << getJson(0); @@ -41,7 +43,12 @@ SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint32 sig setFieldH256(sfLedgerHash, ledgerHash); setFieldU32(sfSigningTime, signTime); if (naSeed.isValid()) - setFieldVL(sfSigningPubKey, NewcoinAddress::createNodePublic(naSeed).getNodePublic()); + { + NewcoinAddress np = NewcoinAddress::createNodePublic(naSeed); + setFieldVL(sfSigningPubKey, np.getNodePublic()); + mNodeID = np.getNodeID(); + assert(mNodeID.isNonZero()); + } if (!isFull) setFlag(sFullFlag); diff --git a/src/SerializedValidation.h b/src/SerializedValidation.h index 1aab631041..9ce8fb6a28 100644 --- a/src/SerializedValidation.h +++ b/src/SerializedValidation.h @@ -8,6 +8,7 @@ class SerializedValidation : public STObject { protected: uint256 mPreviousHash; + uint160 mNodeID; bool mTrusted; void setNode(); @@ -26,6 +27,7 @@ public: uint32 getSignTime() const; uint32 getFlags() const; NewcoinAddress getSignerPublic() const; + uint160 getNodeID() const { return mNodeID; } bool isValid() const; bool isFull() const; bool isTrusted() const { return mTrusted; } diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index e4d1117549..0e356c7151 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -150,35 +150,37 @@ int ValidationCollection::getLoadRatio(bool overLoaded) return (goodNodes * 100) / (goodNodes + badNodes); } -boost::unordered_map ValidationCollection::getCurrentValidations(uint256 currentLedger) +boost::unordered_map +ValidationCollection::getCurrentValidations(uint256 currentLedger) { uint32 cutoff = theApp->getOPs().getNetworkTimeNC() - LEDGER_VAL_INTERVAL; bool valCurrentLedger = currentLedger.isNonZero(); - boost::unordered_map ret; + boost::unordered_map ret; + boost::mutex::scoped_lock sl(mValidationLock); + boost::unordered_map::iterator it = mCurrentValidations.begin(); + while (it != mCurrentValidations.end()) { - boost::mutex::scoped_lock sl(mValidationLock); - boost::unordered_map::iterator it = mCurrentValidations.begin(); - while (it != mCurrentValidations.end()) - { - if (!it->second) // contains no record - it = mCurrentValidations.erase(it); - else if (it->second->getSignTime() < cutoff) - { // contains a stale record - mStaleValidations.push_back(it->second); - it->second = SerializedValidation::pointer(); - condWrite(); - it = mCurrentValidations.erase(it); - } - else - { // contains a live record - if (valCurrentLedger && it->second->isPreviousHash(currentLedger)) - ++ret[currentLedger]; // count for the favored ledger - else - ++ret[it->second->getLedgerHash()]; - ++it; - } + if (!it->second) // contains no record + it = mCurrentValidations.erase(it); + else if (it->second->getSignTime() < cutoff) + { // contains a stale record + mStaleValidations.push_back(it->second); + it->second = SerializedValidation::pointer(); + condWrite(); + it = mCurrentValidations.erase(it); + } + else + { // contains a live record + bool countPreferred = valCurrentLedger && it->second->isPreviousHash(currentLedger); + currentValidationCount& p = countPreferred ? ret[currentLedger] : ret[it->second->getLedgerHash()]; + + ++(p.first); // count for the favored ledger + uint160 ni = it->second->getNodeID(); + if (ni > p.second) + p.second = ni; + ++it; } } diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index 95cd4592e0..c4653a86a4 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -12,6 +12,8 @@ typedef boost::unordered_map ValidationSet; +typedef std::pair currentValidationCount; // nodes validating and highest node ID validating + class ValidationCollection { protected: @@ -38,7 +40,7 @@ public: int getNodesAfter(const uint256& ledger); int getLoadRatio(bool overLoaded); - boost::unordered_map getCurrentValidations(uint256 currentLedger = uint256()); + boost::unordered_map getCurrentValidations(uint256 currentLedger); void flush(); };