diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index ebe2b08794..8ecccdcd87 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -321,12 +321,19 @@ void LedgerConsensus::handleLCL(const uint256& lclHash) BOOST_FOREACH(Peer::ref peer, peerList) mAcquiringLedger->peerHas(peer); } + if (mHaveCorrectLCL && mProposing) + { + Log(lsINFO) << "Bowing out of consensus"; + mOurPosition->bowOut(); + propose(); + } mHaveCorrectLCL = false; mProposing = false; mValidating = false; mCloseTimes.clear(); mPeerPositions.clear(); mDisputes.clear(); + mDeadNodes.clear(); return; } @@ -491,7 +498,7 @@ void LedgerConsensus::statePreClose() } else { - sinceClose = theApp->getOPs().getLastCloseTime(); + sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - theApp->getOPs().getLastCloseTime()); idleInterval = LEDGER_IDLE_INTERVAL; } @@ -517,7 +524,7 @@ void LedgerConsensus::stateEstablish() if (haveConsensus()) Log(lsINFO) << "We have TX consensus but not CT consensus"; } - if (haveConsensus()) + else if (haveConsensus()) { Log(lsINFO) << "Converge cutoff (" << mPeerPositions.size() << " participants)"; mState = lcsFINISHED; @@ -638,7 +645,7 @@ void LedgerConsensus::updateOurPositions() for (std::map::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it) { - Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << " out of " << thresh; + Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << ", " << thresh << " required"; if (it->second > thresh) { Log(lsINFO) << "Close time consensus reached: " << it->first; @@ -794,11 +801,18 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) { - LedgerProposal::pointer& currentPosition = mPeerPositions[newPosition->getPeerID()]; + uint160 peerID = newPosition->getPeerID(); + if (mDeadNodes.find(peerID) != mDeadNodes.end()) + { + Log(lsINFO) << "Position from dead node"; + return false; + } + + LedgerProposal::pointer& currentPosition = mPeerPositions[peerID]; if (currentPosition) { - assert(newPosition->getPeerID() == currentPosition->getPeerID()); + assert(peerID == currentPosition->getPeerID()); if (newPosition->getProposeSeq() <= currentPosition->getProposeSeq()) return false; } @@ -808,14 +822,24 @@ bool LedgerConsensus::peerPosition(const LedgerProposal::pointer& newPosition) Log(lsTRACE) << "Peer reports close time as " << newPosition->getCloseTime(); ++mCloseTimes[newPosition->getCloseTime()]; } + else if (newPosition->getProposeSeq() == LedgerProposal::seqLeave) + { + BOOST_FOREACH(u256_lct_pair& it, mDisputes) + it.second->unVote(peerID); + mPeerPositions.erase(peerID); + mDeadNodes.insert(peerID); + return true; + } + Log(lsINFO) << "Processing peer proposal " << newPosition->getProposeSeq() << "/" << newPosition->getCurrentHash(); currentPosition = newPosition; + SHAMap::pointer set = getTransactionTree(newPosition->getCurrentHash(), true); if (set) { BOOST_FOREACH(u256_lct_pair& it, mDisputes) - it.second->setVote(newPosition->getPeerID(), set->hasItem(it.first)); + it.second->setVote(peerID, set->hasItem(it.first)); } else Log(lsTRACE) << "Don't have that tx set"; diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 4e1db172dd..17aa02691d 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -115,6 +115,9 @@ protected: // deferred proposals (node ID -> proposals from that peer) boost::unordered_map< uint160, std::list > mDeferredProposals; + // nodes that have bowed out of this consensus process + boost::unordered_set mDeadNodes; + // final accept logic static void Saccept(boost::shared_ptr This, SHAMap::pointer txSet); void accept(const SHAMap::pointer& txSet); diff --git a/src/LedgerProposal.cpp b/src/LedgerProposal.cpp index d96b397434..5840c10372 100644 --- a/src/LedgerProposal.cpp +++ b/src/LedgerProposal.cpp @@ -62,6 +62,13 @@ void LedgerProposal::changePosition(const uint256& newPosition, uint32 closeTime ++mProposeSeq; } +void LedgerProposal::bowOut() +{ + mCurrentHash = uint256(); + mTime = boost::posix_time::second_clock::universal_time(); + mProposeSeq = seqLeave; +} + std::vector LedgerProposal::sign(void) { std::vector ret; @@ -78,9 +85,14 @@ Json::Value LedgerProposal::getJson() const { Json::Value ret = Json::objectValue; ret["previous_ledger"] = mPreviousLedger.GetHex(); - ret["transaction_hash"] = mCurrentHash.GetHex(); + + if (mProposeSeq != seqLeave) + { + ret["transaction_hash"] = mCurrentHash.GetHex(); + ret["propose_seq"] = mProposeSeq; + } + ret["close_time"] = mCloseTime; - ret["propose_seq"] = mProposeSeq; if (mPublicKey.isValid()) ret["peer_id"] = mPublicKey.humanNodePublic(); diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index 74d0f7c071..adaa557719 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -26,6 +26,7 @@ protected: boost::posix_time::ptime mTime; public: + static const uint32 seqLeave = 0xffffffff; // leaving the consensus process typedef boost::shared_ptr pointer; @@ -63,6 +64,7 @@ public: bool isStale(boost::posix_time::ptime cutoff) { return mTime <= cutoff; } void changePosition(const uint256& newPosition, uint32 newCloseTime); + void bowOut(); Json::Value getJson() const; }; diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index b19ee994bd..9ce760fc4d 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -27,7 +27,7 @@ bool ContinuousLedgerTiming::shouldClose( boost::str(boost::format("CLC::shouldClose range Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") % (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentMSeconds % previousMSeconds); - return true;; + return true; } if (!anyTransactions)