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
This commit is contained in:
JoelKatz
2012-10-05 03:46:24 -07:00
parent e17720717a
commit 0630a4b7f4
6 changed files with 72 additions and 42 deletions

View File

@@ -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<uint256, int> vals =
theApp->getValidations().getCurrentValidations(favoredLedger);
boost::unordered_map<uint256, currentValidationCount> vals =
theApp->getValidations().getCurrentValidations(favoredLedger);
typedef std::pair<const uint256, int> u256_int_pair;
BOOST_FOREACH(u256_int_pair& it, vals)
if (it.second > netLgrCount)
typedef std::pair<const uint256, currentValidationCount> 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)

View File

@@ -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<Peer::pointer>& peerLis
boost::unordered_map<uint256, ValidationCount> ledgers;
{
boost::unordered_map<uint256, int> current = theApp->getValidations().getCurrentValidations(closedLedger);
typedef std::pair<const uint256, int> u256_int_pair;
BOOST_FOREACH(u256_int_pair& it, current)
ledgers[it.first].trustedValidations += it.second;
boost::unordered_map<uint256, currentValidationCount> current =
theApp->getValidations().getCurrentValidations(closedLedger);
typedef std::pair<const uint256, currentValidationCount> 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<Peer::pointer>& 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<Peer::pointer>& 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<Peer::pointer>& 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<Peer::pointer>& 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;
}

View File

@@ -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);

View File

@@ -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; }

View File

@@ -150,35 +150,37 @@ int ValidationCollection::getLoadRatio(bool overLoaded)
return (goodNodes * 100) / (goodNodes + badNodes);
}
boost::unordered_map<uint256, int> ValidationCollection::getCurrentValidations(uint256 currentLedger)
boost::unordered_map<uint256, currentValidationCount>
ValidationCollection::getCurrentValidations(uint256 currentLedger)
{
uint32 cutoff = theApp->getOPs().getNetworkTimeNC() - LEDGER_VAL_INTERVAL;
bool valCurrentLedger = currentLedger.isNonZero();
boost::unordered_map<uint256, int> ret;
boost::unordered_map<uint256, currentValidationCount> ret;
boost::mutex::scoped_lock sl(mValidationLock);
boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin();
while (it != mCurrentValidations.end())
{
boost::mutex::scoped_lock sl(mValidationLock);
boost::unordered_map<uint160, SerializedValidation::pointer>::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;
}
}

View File

@@ -12,6 +12,8 @@
typedef boost::unordered_map<uint160, SerializedValidation::pointer> ValidationSet;
typedef std::pair<int, uint160> 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<uint256, int> getCurrentValidations(uint256 currentLedger = uint256());
boost::unordered_map<uint256, currentValidationCount> getCurrentValidations(uint256 currentLedger);
void flush();
};