From d25fc9c5938d8403be5fdb6ccbb5cff0b9c394ec Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 1 Aug 2012 14:36:39 -0700 Subject: [PATCH 01/61] Fix endless recursion. --- src/TransactionMeta.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index 576503418..bec1c4c5d 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -36,11 +36,11 @@ public: bool operator>(const TransactionMetaNodeEntry&) const; bool operator>=(const TransactionMetaNodeEntry&) const; - std::auto_ptr clone() const - { return std::auto_ptr(clone()); } + virtual std::auto_ptr clone() const + { return std::auto_ptr(duplicate()); } protected: - virtual TransactionMetaNodeEntry* clone(void) = 0; + virtual TransactionMetaNodeEntry* duplicate(void) const = 0; }; class TMNEBalance : public TransactionMetaNodeEntry @@ -73,7 +73,7 @@ public: virtual Json::Value getJson(int) const; virtual int compare(const TransactionMetaNodeEntry&) const; - virtual TransactionMetaNodeEntry* clone(void) { return new TMNEBalance(*this); } + virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEBalance(*this); } }; class TMNEUnfunded : public TransactionMetaNodeEntry @@ -88,7 +88,7 @@ public: virtual void addRaw(Serializer&) const; virtual Json::Value getJson(int) const; virtual int compare(const TransactionMetaNodeEntry&) const; - virtual TransactionMetaNodeEntry* clone(void) { return new TMNEUnfunded(*this); } + virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEUnfunded(*this); } }; inline TransactionMetaNodeEntry* new_clone(const TransactionMetaNodeEntry& s) { return s.clone().release(); } From ee3562a9a92683578342f3282235628c0464ec09 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 1 Aug 2012 14:38:29 -0700 Subject: [PATCH 02/61] Cleanup resynch logic. --- src/LedgerConsensus.cpp | 3 +-- src/NetworkOPs.cpp | 4 +++- src/NetworkOPs.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index c4eeab81d..699e1bd6c 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -888,11 +888,10 @@ void LedgerConsensus::accept(SHAMap::pointer set) ssw.write(Log(lsTRACE).ref(), p); } #endif - // FIXME: If necessary, change state to TRACKING/FULL } void LedgerConsensus::endConsensus() { - theApp->getOPs().endConsensus(); + theApp->getOPs().endConsensus(mHaveCorrectLCL); } // vim:ts=4 diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index a802b8b08..d1b216ebb 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -643,7 +643,7 @@ void NetworkOPs::mapComplete(const uint256& hash, SHAMap::pointer map) mConsensus->mapComplete(hash, map, true); } -void NetworkOPs::endConsensus() +void NetworkOPs::endConsensus(bool correctLCL) { uint256 deadLedger = theApp->getMasterLedger().getClosedLedger()->getParentHash(); Log(lsTRACE) << "Ledger " << deadLedger.GetHex() << " is now dead"; @@ -655,6 +655,8 @@ void NetworkOPs::endConsensus() (*it)->cycleStatus(); } mConsensus = boost::shared_ptr(); + if (correctLCL && (mMode == omCONNECTED)) + setMode(omTRACKING); } void NetworkOPs::setMode(OperatingMode om) diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 36c194145..2afa07ecf 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -184,7 +184,7 @@ public: void switchLastClosedLedger(Ledger::pointer newLedger); // Used for the "jump" case bool checkLastClosedLedger(const std::vector&, uint256& networkClosed); int beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger); - void endConsensus(); + void endConsensus(bool correctLCL); void setStateTimer(); void newLCL(int proposers, int convergeTime, const uint256& ledgerHash); int getPreviousProposers() { return mLastCloseProposers; } From 8772f7ca90aa87032f1e8c37ab22e7580cfaba2f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 1 Aug 2012 14:39:00 -0700 Subject: [PATCH 03/61] Bump versions to 4 just in case it's a version mismatch. --- src/Version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Version.h b/src/Version.h index 8fd1805a6..51603753c 100644 --- a/src/Version.h +++ b/src/Version.h @@ -5,7 +5,7 @@ // #define SERVER_VERSION_MAJOR 0 -#define SERVER_VERSION_MINOR 3 +#define SERVER_VERSION_MINOR 4 #define SERVER_VERSION_SUB "-a" #define SERVER_NAME "NewCoin" @@ -16,11 +16,11 @@ // Version we prefer to speak: #define PROTO_VERSION_MAJOR 0 -#define PROTO_VERSION_MINOR 3 +#define PROTO_VERSION_MINOR 4 // Version we wil speak to: #define MIN_PROTO_MAJOR 0 -#define MIN_PROTO_MINOR 3 +#define MIN_PROTO_MINOR 4 #define MAKE_VERSION_INT(maj,min) ((maj << 16) | min) #define GET_VERSION_MAJOR(ver) (ver >> 16) From 68677270bf238337dd822322c878020c8d066b1f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 1 Aug 2012 14:43:19 -0700 Subject: [PATCH 04/61] Revert inadvertant commit. --- src/SerializedTypes.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 7b8d10beb..9a1c34b3f 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -83,7 +83,7 @@ public: virtual void add(Serializer& s) const { return; } virtual bool isEquivalent(const SerializedType& t) const - { std::cerr << getSType() << std::endl; assert(getSType() == STI_NOTPRESENT); return t.getSType() == STI_NOTPRESENT; } + { assert(getSType() == STI_NOTPRESENT); return t.getSType() == STI_NOTPRESENT; } bool operator==(const SerializedType& t) const { return (getSType() == t.getSType()) && isEquivalent(t); } From a902134133d00757e4a9803cf7f3052b4b17ea19 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 1 Aug 2012 15:00:39 -0700 Subject: [PATCH 05/61] Don't be blind to validations during the idle time. --- src/LedgerConsensus.cpp | 33 +++++++++++++++++++++++++++++++++ src/LedgerConsensus.h | 1 + src/NetworkOPs.cpp | 2 -- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 699e1bd6c..a99a54a0b 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -226,6 +226,38 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer pre } } +void LedgerConsensus::checkLCL() +{ + uint256 netLgr; + int netLgrCount = 0; + { + boost::unordered_map vals = theApp->getValidations().getCurrentValidations(); + for (boost::unordered_map::iterator it = vals.begin(), end = vals.end(); it != end; ++it) + if (it->second > netLgrCount) + { + netLgr = it->first; + netLgrCount = it->second; + } + } + if ((netLgrCount > 0) && (netLgr != mPrevLedgerHash)) + { // LCL change + Log(lsWARNING) << "View of consensus changed during consensus"; + mPrevLedgerHash = netLgr; + mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash); + std::vector peerList = theApp->getConnectionPool().getPeerVector(); + bool found = false; + for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) + if ((*it)->hasLedger(mPrevLedgerHash)) + { + found = true; + mAcquiringLedger->peerHas(*it); + } + if (!found) + for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) + mAcquiringLedger->peerHas(*it); + } +} + void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) { SHAMap::pointer initialSet = initialLedger.peekTransactionMap()->snapShot(false); @@ -418,6 +450,7 @@ void LedgerConsensus::timerEntry() { if (!mHaveCorrectLCL) { + checkLCL(); Log(lsINFO) << "Checking for consensus ledger " << mPrevLedgerHash.GetHex(); Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(mPrevLedgerHash); if (consensus) diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 215175d8e..6f167e72d 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -149,6 +149,7 @@ public: SHAMap::pointer getTransactionTree(const uint256& hash, bool doAcquire); TransactionAcquire::pointer getAcquiring(const uint256& hash); void mapComplete(const uint256& hash, SHAMap::pointer map, bool acquired); + void checkLCL(); void timerEntry(); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index d1b216ebb..b4f15780d 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -655,8 +655,6 @@ void NetworkOPs::endConsensus(bool correctLCL) (*it)->cycleStatus(); } mConsensus = boost::shared_ptr(); - if (correctLCL && (mMode == omCONNECTED)) - setMode(omTRACKING); } void NetworkOPs::setMode(OperatingMode om) From 63576f0709f4801897c54aa16fa7dcf560e08b39 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 2 Aug 2012 11:33:58 -0700 Subject: [PATCH 06/61] Fix the crash bug Jed reported. --- src/LedgerConsensus.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index a99a54a0b..71a808369 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -533,7 +533,10 @@ void LedgerConsensus::updateOurPositions() } } if (closeTime != (mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution))) + { + ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); changes = true; + } if (changes) { From befd7aa108b5cdf63857959e93d6c86c989406fa Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 2 Aug 2012 11:34:11 -0700 Subject: [PATCH 07/61] Fix an infinite timeout scenario with ledger acquisition. --- src/LedgerAcquire.cpp | 10 ++++++++++ src/LedgerAcquire.h | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 088c8c663..090ee616a 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -95,6 +95,16 @@ LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE #endif } +void LedgerAcquire::onTimer() +{ + if (getTimeouts() > 6) + { + setFailed(); + done(); + } + else trigger(Peer::pointer()); +} + boost::weak_ptr LedgerAcquire::pmDowncast() { return boost::shared_polymorphic_downcast(shared_from_this()); diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index 62540172b..5409d63c1 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -70,7 +70,7 @@ protected: std::vector< boost::function > mOnComplete; void done(); - void onTimer() { trigger(Peer::pointer()); } + void onTimer(); void newPeer(Peer::pointer peer) { trigger(peer); } From 67ee822948e6734b2bb5e69b357c6c1cafb09a66 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 2 Aug 2012 11:36:48 -0700 Subject: [PATCH 08/61] Fix the other half of the acquire timeout bug. --- src/LedgerAcquire.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 090ee616a..1f88aecff 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -123,7 +123,8 @@ void LedgerAcquire::done() mOnComplete.empty(); mLock.unlock(); - theApp->getMasterLedger().storeLedger(mLedger); + if (mLedger) + theApp->getMasterLedger().storeLedger(mLedger); for (int i = 0; i < triggers.size(); ++i) triggers[i](shared_from_this()); From e373a58f5c82a35f88799405cd043dff1018f20f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 2 Aug 2012 11:50:59 -0700 Subject: [PATCH 09/61] Avoid duplicate completion of acquired ledgers. --- src/LedgerAcquire.cpp | 5 ++++- src/LedgerAcquire.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 1f88aecff..d04a952ef 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -88,7 +88,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), mAborted(false) + mHaveBase(false), mHaveState(false), mHaveTransactions(false), mAborted(false), mSignaled(false) { #ifdef LA_DEBUG Log(lsTRACE) << "Acquiring ledger " << mHash.GetHex(); @@ -112,6 +112,9 @@ boost::weak_ptr LedgerAcquire::pmDowncast() void LedgerAcquire::done() { + if (mSignaled) + return; + mSignaled = true; #ifdef LA_DEBUG Log(lsTRACE) << "Done acquiring ledger " << mHash.GetHex(); #endif diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index 5409d63c1..fbcac6c7e 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -65,7 +65,7 @@ public: protected: Ledger::pointer mLedger; - bool mHaveBase, mHaveState, mHaveTransactions, mAborted; + bool mHaveBase, mHaveState, mHaveTransactions, mAborted, mSignaled; std::vector< boost::function > mOnComplete; From 0f44af556e99c1e4abb2f7bb4ce297e65cc16fc1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 2 Aug 2012 11:51:24 -0700 Subject: [PATCH 10/61] Better reporting of ledger jumps. --- src/LedgerConsensus.cpp | 5 ++++- src/NetworkOPs.cpp | 6 +++--- src/NetworkOPs.h | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 71a808369..2e57baea9 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -207,6 +207,7 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer pre if (!mHaveCorrectLCL) { + Log(lsINFO) << "Entering consensus process without correct LCL"; mHaveCorrectLCL = mProposing = mValidating = false; mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(prevLCLHash); std::vector peerList = theApp->getConnectionPool().getPeerVector(); @@ -216,11 +217,13 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer pre } else if (mValSeed.isValid()) { + Log(lsINFO) << "Entering consensus process, validating"; mHaveCorrectLCL = mValidating = true; mProposing = theApp->getOPs().getOperatingMode() == NetworkOPs::omFULL; } else { + Log(lsINFO) << "Entering consensus process, proposing"; mHaveCorrectLCL = true; mProposing = mValidating = false; } @@ -457,7 +460,7 @@ void LedgerConsensus::timerEntry() { Log(lsINFO) << "We have acquired the consensus ledger"; if (theApp->getMasterLedger().getClosedLedger()->getHash() != mPrevLedgerHash) - theApp->getOPs().switchLastClosedLedger(consensus); + theApp->getOPs().switchLastClosedLedger(consensus, true); mPreviousLedger = consensus; mHaveCorrectLCL = true; } diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index b4f15780d..612646214 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -518,15 +518,15 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis // FIXME: If this rewinds the ledger sequence, or has the same sequence, we should update the status on // any stored transactions in the invalidated ledgers. - switchLastClosedLedger(consensus); + switchLastClosedLedger(consensus, false); return true; } -void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger) +void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger, bool duringConsensus) { // set the newledger as our last closed ledger -- this is abnormal code - Log(lsERROR) << "ABNORMAL Switching last closed ledger to " << newLedger->getHash().GetHex(); + Log(lsERROR) << "JUMP last closed ledger to " << newLedger->getHash().GetHex(); newLedger->setClosed(); Ledger::pointer openLedger = boost::make_shared(false, boost::ref(*newLedger)); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 2afa07ecf..6ecd43a87 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -181,7 +181,7 @@ public: // network state machine void checkState(const boost::system::error_code& result); - void switchLastClosedLedger(Ledger::pointer newLedger); // Used for the "jump" case + void switchLastClosedLedger(Ledger::pointer newLedger, bool duringConsensus); // Used for the "jump" case bool checkLastClosedLedger(const std::vector&, uint256& networkClosed); int beginConsensus(const uint256& networkClosed, Ledger::pointer closingLedger); void endConsensus(bool correctLCL); From a089dd5460db00fe239db7f2a2dc8d7758dd6db9 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 02:57:14 -0700 Subject: [PATCH 11/61] Fix a bug in how we count validations. --- src/ValidationCollection.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index fcbe669b9..bd1f9a673 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -7,8 +7,9 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) { + NewcoinAddress signer = val->getSignerPublic(); bool isCurrent = false; - if (theApp->getUNL().nodeInUNL(val->getSignerPublic())) + if (theApp->getUNL().nodeInUNL(signer)) { val->setTrusted(); uint32 now = theApp->getOPs().getNetworkTimeNC(); @@ -20,7 +21,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) } uint256 hash = val->getLedgerHash(); - uint160 node = val->getSignerPublic().getNodeID(); + uint160 node = signer.getNodeID(); { boost::mutex::scoped_lock sl(mValidationLock); @@ -39,7 +40,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) } } - Log(lsINFO) << "Val for " << hash.GetHex() << " from " << val->getSignerPublic().humanNodePublic() + Log(lsINFO) << "Val for " << hash.GetHex() << " from " << signer.humanNodePublic() << " added " << (val->isTrusted() ? "trusted" : "UNtrusted"); return isCurrent; } @@ -50,7 +51,8 @@ ValidationSet ValidationCollection::getValidations(const uint256& ledger) { boost::mutex::scoped_lock sl(mValidationLock); boost::unordered_map::iterator it = mValidations.find(ledger); - if (it != mValidations.end()) ret = it->second; + if (it != mValidations.end()) + ret = it->second; } return ret; } @@ -70,7 +72,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren { uint32 closeTime = vit->second->getCloseTime(); if ((now < closeTime) || (now > (closeTime + 2 * LEDGER_MAX_INTERVAL))) - trusted = false; + isTrusted = false; } if (isTrusted) ++trusted; From c5f76561379561f20d0af35186af19c238b7fa59 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 02:57:36 -0700 Subject: [PATCH 12/61] Better logging of ledger jumps. --- src/NetworkOPs.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 612646214..514bdceba 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -526,7 +526,10 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis void NetworkOPs::switchLastClosedLedger(Ledger::pointer newLedger, bool duringConsensus) { // set the newledger as our last closed ledger -- this is abnormal code - Log(lsERROR) << "JUMP last closed ledger to " << newLedger->getHash().GetHex(); + if (duringConsensus) + Log(lsERROR) << "JUMPdc last closed ledger to " << newLedger->getHash().GetHex(); + else + Log(lsERROR) << "JUMP last closed ledger to " << newLedger->getHash().GetHex(); newLedger->setClosed(); Ledger::pointer openLedger = boost::make_shared(false, boost::ref(*newLedger)); From a202eb50d713b4cd1589b297b57753cdb69b2cf8 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 02:57:55 -0700 Subject: [PATCH 13/61] Cleanups. --- src/TransactionMeta.cpp | 14 ++++++++++++-- src/TransactionMeta.h | 13 +++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index d1f4840e7..4ad06c650 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -152,6 +152,17 @@ TransactionMetaNodeEntry* TransactionMetaNode::findEntry(int nodeType) return NULL; } +TMNEBalance* TransactionMetaNode::findBalance() +{ + for (boost::ptr_vector::iterator it = mEntries.begin(), end = mEntries.end(); + it != end; ++it) + if (it->getType() == TransactionMetaNodeEntry::TMNChangedBalance) + return dynamic_cast(&*it); + TMNEBalance* node = new TMNEBalance(); + mEntries.push_back(node); + return node; +} + void TransactionMetaNode::addNode(TransactionMetaNodeEntry* node) { mEntries.push_back(node); @@ -261,7 +272,7 @@ void TransactionMetaSet::threadNode(const uint256& node, const uint256& prevTx, modifyNode(node).thread(prevTx, prevLgr); } -bool TransactionMetaSet::deleteUnfunded(const uint256& nodeID, +void TransactionMetaSet::deleteUnfunded(const uint256& nodeID, const STAmount& firstBalance, const STAmount &secondBalance) { TransactionMetaNode& node = modifyNode(nodeID); @@ -270,5 +281,4 @@ bool TransactionMetaSet::deleteUnfunded(const uint256& nodeID, entry->setBalances(firstBalance, secondBalance); else node.addNode(new TMNEUnfunded(firstBalance, secondBalance)); - return true; } diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h index bec1c4c5d..d863ccb70 100644 --- a/src/TransactionMeta.h +++ b/src/TransactionMeta.h @@ -114,6 +114,7 @@ public: const boost::ptr_vector& peekEntries() const { return mEntries; } TransactionMetaNodeEntry* findEntry(int nodeType); + TMNEBalance* findBalance(); void addNode(TransactionMetaNodeEntry*); bool operator<(const TransactionMetaNode& n) const { return mNode < n.mNode; } @@ -126,6 +127,11 @@ public: TransactionMetaNode(const uint256&node, SerializerIterator&); void addRaw(Serializer&); Json::Value getJson(int) const; + + void threadNode(const uint256& previousTransaction, uint32 previousLedger); + void deleteUnfunded(const STAmount& firstBalance, const STAmount& secondBalance); + void adjustBalance(unsigned flags, const STAmount &amount, bool signedBy); + void adjustBalances(unsigned flags, const STAmount &firstAmt, const STAmount &secondAmt); }; @@ -148,16 +154,11 @@ public: void swap(TransactionMetaSet&); bool isNodeAffected(const uint256&) const; + TransactionMetaNode& getAffectedNode(const uint256&); const TransactionMetaNode& peekAffectedNode(const uint256&) const; Json::Value getJson(int) const; void addRaw(Serializer&); - - void threadNode(const uint256& node, const uint256& previousTransaction, uint32 previousLedger); - bool signedBy(const uint256& node, const STAmount& fee); - bool deleteUnfunded(const uint256& node, const STAmount& firstBalance, const STAmount& secondBalance); - bool adjustBalance(const uint256& node, unsigned flags, const STAmount &amount); - bool adjustBalances(const uint256& node, unsigned flags, const STAmount &firstAmt, const STAmount &secondAmt); }; #endif From 7b44fffb278385f2d4566c3c18a6acd2ae71e6b1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 03:22:00 -0700 Subject: [PATCH 14/61] Make this compile. --- src/TransactionMeta.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index 4ad06c650..0476b9420 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -267,6 +267,7 @@ TransactionMetaNode& TransactionMetaSet::modifyNode(const uint256& node) return mNodes.insert(std::make_pair(node, TransactionMetaNode(node))).first->second; } +#if 0 void TransactionMetaSet::threadNode(const uint256& node, const uint256& prevTx, uint32 prevLgr) { modifyNode(node).thread(prevTx, prevLgr); @@ -282,3 +283,4 @@ void TransactionMetaSet::deleteUnfunded(const uint256& nodeID, else node.addNode(new TMNEUnfunded(firstBalance, secondBalance)); } +#endif \ No newline at end of file From 9eaf052ee8fd2e73b40a2d29046f93c0050d7485 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 03:22:32 -0700 Subject: [PATCH 15/61] Make this compile temporarily. --- src/LedgerEntrySet.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index 0c87f7849..fb4903ff4 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -169,9 +169,11 @@ void LedgerEntrySet::entryDelete(SLE::pointer& sle, bool unfunded) if (unfunded) { assert(sle->getType() == ltOFFER); // only offers can be unfunded +#if 0 mSet.deleteUnfunded(sle->getIndex(), sle->getIValueFieldAmount(sfTakerPays), sle->getIValueFieldAmount(sfTakerGets)); +#endif } break; From debcea79f0b82efb735024ca6267bc4813b0adaf Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 03:46:31 -0700 Subject: [PATCH 16/61] Don't switch to our own previous ledger. --- src/NetworkOPs.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 514bdceba..8d0ffd9ce 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -415,6 +415,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis Ledger::pointer ourClosed = mLedgerMaster->getClosedLedger(); uint256 closedLedger = ourClosed->getHash(); + uint256 prevClosedLedger = ourClosed->getParentHash(); ValidationCount& ourVC = ledgers[closedLedger]; if ((theConfig.LEDGER_CREATOR) && (mMode >= omTRACKING)) @@ -459,7 +460,14 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis switchLedgers = true; } } - networkClosed = closedLedger; + + if (switchLedger && (closedLedger == prevClosedLedger)) + { // don't switch to our own previous ledger + NetworkClosed = ourClosed->getHash(); + switchLedgers = false; + } + else + networkClosed = closedLedger; if (!switchLedgers) { From d251a67d17ee2dfd39ed31fbe021e0e5c841c8e7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 03:47:27 -0700 Subject: [PATCH 17/61] Fix typos. --- src/NetworkOPs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 8d0ffd9ce..a5ef2b5c6 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -461,9 +461,9 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis } } - if (switchLedger && (closedLedger == prevClosedLedger)) + if (switchLedgers && (closedLedger == prevClosedLedger)) { // don't switch to our own previous ledger - NetworkClosed = ourClosed->getHash(); + networkClosed = ourClosed->getHash(); switchLedgers = false; } else From 6815c7ef981cf07af38e868e486fff872813eb16 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 04:06:53 -0700 Subject: [PATCH 18/61] Cleanups. --- src/LedgerAcquire.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index d04a952ef..846fc8c9f 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -485,7 +485,6 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi ledger->trigger(peer); return true; } - Log(lsDEBUG) << "liBASE includes ASbase"; if (!ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata()))) { Log(lsWARNING) << "Included ASbase invalid"; @@ -495,7 +494,6 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi ledger->trigger(peer); return true; } - Log(lsDEBUG) << "liBASE includes TXbase"; if (!ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata()))) Log(lsWARNING) << "Invcluded TXbase invalid"; ledger->trigger(peer); From 5778cb118306b0970d2ddf84c60de9be7e018a43 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 04:07:01 -0700 Subject: [PATCH 19/61] Keep one validation back to avoid a split case when some nodes have sent new validations and some haven't --- src/ValidationCollection.cpp | 54 ++++++++++++++++++++++++++---------- src/ValidationCollection.h | 10 ++++++- 2 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index bd1f9a673..acfe29142 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -19,6 +19,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) else Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose; } + else Log(lsINFO) << "Node " << signer.humanNodePublic() << " not in UNL"; uint256 hash = val->getLedgerHash(); uint160 node = signer.getNodeID(); @@ -29,13 +30,22 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) return false; if (isCurrent) { - boost::unordered_map::iterator it = mCurrentValidations.find(node); - if ((it == mCurrentValidations.end()) || (val->getCloseTime() >= it->second->getCloseTime())) + boost::unordered_map::iterator it = mCurrentValidations.find(node); + if ((it == mCurrentValidations.end()) || (!it->second.newest) || + (val->getCloseTime() > it->second.newest->getCloseTime())) { if (it != mCurrentValidations.end()) - mStaleValidations.push_back(it->second); - mCurrentValidations[node] = val; - condWrite(); + { + if (it->second.oldest) + { + mStaleValidations.push_back(it->second.oldest); + condWrite(); + } + it->second.oldest = it->second.newest; + it->second.newest = val; + } + else + mCurrentValidations.insert(std::make_pair(node, ValidationPair(val))); } } } @@ -102,10 +112,10 @@ int ValidationCollection::getCurrentValidationCount(uint32 afterTime) { int count = 0; boost::mutex::scoped_lock sl(mValidationLock); - for (boost::unordered_map::iterator it = mCurrentValidations.begin(), + for (boost::unordered_map::iterator it = mCurrentValidations.begin(), end = mCurrentValidations.end(); it != end; ++it) { - if (it->second->isTrusted() && (it->second->getCloseTime() > afterTime)) + if (it->second.newest->isTrusted() && (it->second.newest->getCloseTime() > afterTime)) ++count; } return count; @@ -118,19 +128,32 @@ boost::unordered_map ValidationCollection::getCurrentValidations() { boost::mutex::scoped_lock sl(mValidationLock); - boost::unordered_map::iterator it = mCurrentValidations.begin(); + boost::unordered_map::iterator it = mCurrentValidations.begin(); bool anyNew = false; while (it != mCurrentValidations.end()) { - if (now > (it->second->getCloseTime() + LEDGER_MAX_INTERVAL)) + ValidationPair& pair = it->second; + + if (pair.oldest && (now > (pair.oldest->getCloseTime() + LEDGER_MAX_INTERVAL))) { - mStaleValidations.push_back(it->second); - it = mCurrentValidations.erase(it); + mStaleValidations.push_back(pair.oldest); + pair.oldest = SerializedValidation::pointer(); anyNew = true; } + if (pair.newest && (now > (pair.newest->getCloseTime() + LEDGER_MAX_INTERVAL))) + { + mStaleValidations.push_back(pair.newest); + pair.newest = SerializedValidation::pointer(); + anyNew = true; + } + if (!pair.newest && !pair.oldest) + it = mCurrentValidations.erase(it); else { - ++ret[it->second->getLedgerHash()]; + if (pair.newest) + ++ret[pair.newest->getLedgerHash()]; + if (pair.oldest) + ++ret[pair.oldest->getLedgerHash()]; ++it; } } @@ -144,11 +167,14 @@ boost::unordered_map ValidationCollection::getCurrentValidations() void ValidationCollection::flush() { boost::mutex::scoped_lock sl(mValidationLock); - boost::unordered_map::iterator it = mCurrentValidations.begin(); + boost::unordered_map::iterator it = mCurrentValidations.begin(); bool anyNew = false; while (it != mCurrentValidations.end()) { - mStaleValidations.push_back(it->second); + if (it->second.oldest) + mStaleValidations.push_back(it->second.oldest); + if (it->second.newest) + mStaleValidations.push_back(it->second.newest); ++it; anyNew = true; } diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index 2b2760ff3..4120a9e24 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -12,13 +12,21 @@ typedef boost::unordered_map ValidationSet; +class ValidationPair +{ +public: + SerializedValidation::pointer oldest, newest; + + ValidationPair(SerializedValidation::pointer v) : newest(v) { ; } +}; + class ValidationCollection { protected: boost::mutex mValidationLock; boost::unordered_map mValidations; - boost::unordered_map mCurrentValidations; + boost::unordered_map mCurrentValidations; std::vector mStaleValidations; bool mWriting; From 1892e7e00ac9d8aaeb17f226581582c986ac6bba Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 04:11:52 -0700 Subject: [PATCH 20/61] Some extra debug. --- src/ValidationCollection.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index acfe29142..c8ba94856 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -150,10 +150,18 @@ boost::unordered_map ValidationCollection::getCurrentValidations() it = mCurrentValidations.erase(it); else { - if (pair.newest) - ++ret[pair.newest->getLedgerHash()]; if (pair.oldest) + { + Log(lsTRACE) << "OLD " << pair.oldest->getLedgerHash().GetHex() << " " << + boost::lexical_cast(pair.oldest->getCloseTime()); ++ret[pair.oldest->getLedgerHash()]; + } + if (pair.newest) + { + Log(lsTRACE) << "NEW " << pair.newest->getLedgerHash().GetHex() << " " << + boost::lexical_cast(pair.newest->getCloseTime()); + ++ret[pair.newest->getLedgerHash()]; + } ++it; } } From 0f4800f6bb3a0f296449c75ead2edb349006f4c4 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 04:39:52 -0700 Subject: [PATCH 21/61] Support for a local time to network time offset --- src/NetworkOPs.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 6ecd43a87..67ada0363 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -46,6 +46,10 @@ public: }; protected: + typedef boost::unordered_map > subInfoMapType; + typedef boost::unordered_map >::value_type subInfoMapValue; + typedef boost::unordered_map >::iterator subInfoMapIterator; + OperatingMode mMode; boost::posix_time::ptime mConnectTime; boost::asio::deadline_timer mNetTimer; @@ -54,16 +58,12 @@ protected: LedgerMaster* mLedgerMaster; LedgerAcquire::pointer mAcquiringLedger; - void setMode(OperatingMode); - - typedef boost::unordered_map > subInfoMapType; - typedef boost::unordered_map >::value_type subInfoMapValue; - typedef boost::unordered_map >::iterator subInfoMapIterator; + int mTimeOffset; // last ledger close - int mLastCloseProposers, mLastCloseConvergeTime; - uint256 mLastCloseHash; - uint32 mLastCloseNetTime; + int mLastCloseProposers, mLastCloseConvergeTime; + uint256 mLastCloseHash; + uint32 mLastCloseNetTime; // XXX Split into more locks. boost::interprocess::interprocess_upgradable_mutex mMonitorLock; @@ -75,6 +75,8 @@ protected: boost::unordered_set mSubTransaction; // all transactions // subInfoMapType mSubTransactionAccounts; + void setMode(OperatingMode); + Json::Value transJson(const SerializedTransaction& stTxn, TransactionEngineResult terResult, const std::string& strStatus, int iSeq, const std::string& strType); void pubTransactionAll(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState); void pubTransactionAccounts(const Ledger::pointer& lpCurrent, const SerializedTransaction& stTxn, TransactionEngineResult terResult, const char* pState); From 97c1dc73f670322de9aae97f43a8f2ecf9bfa69c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 04:40:10 -0700 Subject: [PATCH 22/61] Use the offset. --- src/NetworkOPs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index a5ef2b5c6..3ba931e9c 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -24,14 +24,14 @@ // there's a functional network. NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) : - mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster), + mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster), mTimeOffset(0), mLastCloseProposers(0), mLastCloseConvergeTime(LEDGER_IDLE_INTERVAL) { } boost::posix_time::ptime NetworkOPs::getNetworkTimePT() { - return boost::posix_time::second_clock::universal_time(); + return boost::posix_time::second_clock::universal_time() + boost::posix_time::seconds(mTimeOffset); } uint32 NetworkOPs::getNetworkTimeNC() From d98a931b8e5ee19f3b9ffbbb13faf2c084313aec Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 04:40:16 -0700 Subject: [PATCH 23/61] Compute our clock offset. (We don't actually set it yet though.) --- src/LedgerConsensus.cpp | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 2e57baea9..f3243a76b 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -917,6 +917,23 @@ void LedgerConsensus::accept(SHAMap::pointer set) mState = lcsACCEPTED; sl.unlock(); + { + Log(lsINFO) << "We closed at " << boost::lexical_cast(mCloseTime); + uint64 closeTotal = mCloseTime; + int closeCount = 1; + for(std::map::iterator it = mCloseTimes.begin(), end = mCloseTimes.end(); it != end; ++it) + { + Log(lsINFO) << boost::lexical_cast(it->second) << " time votes for " + << boost::lexical_cast(it->first); + closeCount += it->second; + closeTotal += static_cast(it->first) * static_cast(it->second); + } + closeTotal += (closeCount / 2); + closeTotal /= closeCount; + int offset = static_cast(closeTotal) - static_cast(mCloseTime); + Log(lsINFO) << "Our clock offset is estimated at " << offset; + } + #ifdef DEBUG Json::StyledStreamWriter ssw; if (1) From 127391b34527d1d9a9cf430071f371604863f4cf Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 06:51:32 -0700 Subject: [PATCH 24/61] Remove assert. --- src/LedgerConsensus.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index f3243a76b..e4b2fe428 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -872,7 +872,6 @@ void LedgerConsensus::accept(SHAMap::pointer set) statusChange(newcoin::neACCEPTED_LEDGER, *newLCL); if (mValidating) { - assert (theApp->getOPs().getNetworkTimeNC() > newLCL->getCloseTimeNC()); SerializedValidation::pointer v = boost::make_shared (newLCLHash, newLCL->getCloseTimeNC(), mValSeed, mProposing); v->setTrusted(); From 78f415f386b2ff43669e81b983ed8a779125dde3 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 3 Aug 2012 07:02:18 -0700 Subject: [PATCH 25/61] Allow a 20 second clock offset. --- src/Peer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index 22994c3cf..ccc1b1122 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -571,8 +571,8 @@ void Peer::recvHello(newcoin::TMHello& packet) // Cancel verification timeout. (void) mVerifyTimer.cancel(); - uint32 minTime = theApp->getOPs().getNetworkTimeNC() - 4; - uint32 maxTime = minTime + 8; + uint32 minTime = theApp->getOPs().getNetworkTimeNC() - 20; + uint32 maxTime = minTime + 20; if (packet.has_nettime() && ((packet.nettime() < minTime) || (packet.nettime() > maxTime))) { From ee01b558741c2227e996c31f2d24669992b845c1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 4 Aug 2012 21:33:05 -0700 Subject: [PATCH 26/61] An SNTP client implementation. About 95% complete right now. --- newcoind.cfg | 8 ++ src/Application.cpp | 5 +- src/Application.h | 2 + src/Config.cpp | 7 ++ src/Config.h | 1 + src/SNTPClient.cpp | 180 ++++++++++++++++++++++++++++++++++++++++++++ src/SNTPClient.h | 58 ++++++++++++++ 7 files changed, 260 insertions(+), 1 deletion(-) create mode 100644 src/SNTPClient.cpp create mode 100644 src/SNTPClient.h diff --git a/newcoind.cfg b/newcoind.cfg index 01b72581e..179a14802 100644 --- a/newcoind.cfg +++ b/newcoind.cfg @@ -85,6 +85,9 @@ # 192.168.0.1 3939 # 2001:0db8:0100:f101:0210:a4ff:fee3:9566 # +# [sntp_servers] +# IP address or domain of servers to use for time synchronization. +# # [peer_ip]: # IP address or domain to bind to allow external connections from peers. # Defaults to not allow external connections from peers. @@ -140,6 +143,11 @@ [debug_logfile] debug.log +[sntp_servers] +time.windows.com +us.pool.ntp.org +time.apple.com + [validation_seed] shh1D4oj5czH3PUEjYES8c7Bay3tE diff --git a/src/Application.cpp b/src/Application.cpp index dd4fd40a2..0ceef99b7 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -38,7 +38,8 @@ DatabaseCon::~DatabaseCon() Application::Application() : mUNL(mIOService), mNetOps(mIOService, &mMasterLedger), mTempNodeCache(16384, 90), mHashedObjectStore(16384, 300), - mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), + mSNTPClient(mIOService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), + mHashNodeDB(NULL), mNetNodeDB(NULL), mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL) { RAND_bytes(mNonce256.begin(), mNonce256.size()); @@ -68,6 +69,8 @@ void Application::run() if (!theConfig.DEBUG_LOGFILE.empty()) Log::setLogFile(theConfig.DEBUG_LOGFILE); + mSNTPClient.init(theConfig.SNTP_SERVERS); + // // Construct databases. // diff --git a/src/Application.h b/src/Application.h index 14281abbf..3ba29dee2 100644 --- a/src/Application.h +++ b/src/Application.h @@ -16,6 +16,7 @@ #include "TaggedCache.h" #include "ValidationCollection.h" #include "Suppression.h" +#include "SNTPClient.h" #include "../database/database.h" @@ -50,6 +51,7 @@ class Application ValidationCollection mValidations; SuppressionTable mSuppressions; HashedObjectStore mHashedObjectStore; + SNTPClient mSNTPClient; DatabaseCon *mRpcDB, *mTxnDB, *mLedgerDB, *mWalletDB, *mHashNodeDB, *mNetNodeDB; diff --git a/src/Config.cpp b/src/Config.cpp index e8e81747d..cf9c135bf 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -23,6 +23,7 @@ #define SECTION_RPC_ALLOW_REMOTE "rpc_allow_remote" #define SECTION_RPC_IP "rpc_ip" #define SECTION_RPC_PORT "rpc_port" +#define SECTION_SNTP "sntp_servers" #define SECTION_UNL_DEFAULT "unl_default" #define SECTION_VALIDATION_QUORUM "validation_quorum" #define SECTION_VALIDATION_SEED "validation_seed" @@ -193,6 +194,12 @@ void Config::load() // sectionEntriesPrint(&IPS, SECTION_IPS); } + smtTmp = sectionEntries(secConfig, SECTION_SNTP); + if (smtTmp) + { + SNTP_SERVERS = *smtTmp; + } + (void) sectionSingleB(secConfig, SECTION_VALIDATORS_SITE, VALIDATORS_SITE); (void) sectionSingleB(secConfig, SECTION_PEER_IP, PEER_IP); diff --git a/src/Config.h b/src/Config.h index 85de649e2..585980b92 100644 --- a/src/Config.h +++ b/src/Config.h @@ -54,6 +54,7 @@ public: std::string VALIDATORS_SITE; // Where to find validators.txt on the Internet. std::vector VALIDATORS; // Validators from newcoind.cfg. std::vector IPS; // Peer IPs from newcoind.cfg. + std::vector SNTP_SERVERS; // SNTP servers from newcoind.cfg. // Network parameters int NETWORK_START_TIME; // The Unix time we start ledger 0. diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp new file mode 100644 index 000000000..75226b075 --- /dev/null +++ b/src/SNTPClient.cpp @@ -0,0 +1,180 @@ +#include "SNTPClient.h" + +#include +#include + +#include "utils.h" +#include "Log.h" + +static uint8_t SNTPQueryData[48] = { + 0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +}; + +SNTPClient::SNTPClient(boost::asio::io_service& service) : + mIOService(service), mSocket(service), mTimer(service), mResolver(service), + mOffset(0), mLastOffsetUpdate((time_t) -1), mReceiveBuffer(256) +{ + mSocket.open(boost::asio::ip::udp::v4()); + mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint, + boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); + + mTimer.expires_from_now(boost::posix_time::seconds(1)); + mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error)); +} + +void SNTPClient::resolveComplete(const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator it) +{ + if (!error) + { + boost::asio::ip::udp::resolver::iterator sel = it; + int i = 1; + while (++it != boost::asio::ip::udp::resolver::iterator()) + if ((rand() % ++i) == 0) + sel = it; + if (sel != boost::asio::ip::udp::resolver::iterator()) + { + boost::mutex::scoped_lock sl(mLock); + SNTPQuery& query = mQueries[*sel]; + time_t now = time(NULL); + if ((query.mLocalTimeSent == now) || ((query.mLocalTimeSent + 1) == now)) + { + Log(lsINFO) << "SNTP: Redundant query suppressed"; + return; + } + query.mReceivedReply = false; + query.mLocalTimeSent = now; + mSocket.async_send_to(boost::asio::buffer(SNTPQueryData, 256), *sel, + boost::bind(&SNTPClient::sendComplete, this, + boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + } +} + +void SNTPClient::receivePacket(const boost::system::error_code& error, std::size_t bytes_xferd) +{ + if (!error) + { + boost::mutex::scoped_lock sl(mLock); + Log(lsINFO) << "SNTP: Packet from " << mReceiveEndpoint; + std::map::iterator query = mQueries.find(mReceiveEndpoint); + if (query == mQueries.end()) + Log(lsINFO) << "SNTP: Reply found without matching query"; + else if (query->second.mReceivedReply) + Log(lsINFO) << "SNTP: Duplicate response to query"; + else + { + query->second.mReceivedReply = true; + if (time(NULL) > (query->second.mLocalTimeSent + 1)) + Log(lsINFO) << "SNTP: Late response"; + else + if (bytes_xferd < 48) + Log(lsINFO) << "SNTP: Short reply (" << bytes_xferd << ") " << mReceiveBuffer.size(); + else + processReply(); + } + } + + mSocket.async_receive_from(boost::asio::buffer(mReceiveBuffer, 256), mReceiveEndpoint, + boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); +} + +void SNTPClient::sendComplete(const boost::system::error_code& error, std::size_t) +{ + if (error) + Log(lsINFO) << "SNTP: Send error"; +} + +void SNTPClient::processReply() +{ + assert(mReceiveBuffer.size() >= 48); + uint32 *recvBuffer = reinterpret_cast(&mReceiveBuffer.front()); + + unsigned info = ntohl(recvBuffer[0]); + int64_t timev = ntohl(recvBuffer[8]); + unsigned stratum = (info >> 16) & 0xff; + + if ((info >> 30) == 3) + { + Log(lsINFO) << "SNTP: Alarm condition"; + return; + } + if ((stratum == 0) || (stratum > 14)) + { + Log(lsINFO) << "SNTP: Unreasonable stratum"; + return; + } + + timev -= time(NULL); + timev -= 0x83AA7E80ULL; + Log(lsINFO) << "SNTP: Offset is " << timev; + + // WRITEME +} + +void SNTPClient::timerEntry(const boost::system::error_code& error) +{ + if (!error) + { + doQuery(); + mTimer.expires_from_now(boost::posix_time::seconds(10)); + mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error)); + } +} + +void SNTPClient::addServer(const std::string& server) +{ + boost::mutex::scoped_lock sl(mLock); + mServers.push_back(std::make_pair(server, (time_t) -1)); +} + +void SNTPClient::init(const std::vector& servers) +{ + std::vector::const_iterator it = servers.begin(); + if (it == servers.end()) + { + Log(lsINFO) << "SNTP: no server specified"; + return; + } + do + addServer(*it++); + while (it != servers.end()); + queryAll(); +} + +void SNTPClient::queryAll() +{ + while(doQuery()) + nothing(); +} + +bool SNTPClient::doQuery() +{ + boost::mutex::scoped_lock sl(mLock); + std::vector< std::pair >::iterator best = mServers.end(); + for (std::vector< std::pair >::iterator it = mServers.begin(), end = best; + it != end; ++it) + if ((best == end) || (it->second == (time_t) -1) || (it->second < best->second)) + best = it; + if (best == mServers.end()) + { + Log(lsINFO) << "SNTP: No server to query"; + return false; + } + time_t now = time(NULL); + if ((best->second == now) || (best->second == (now - 1))) + { + Log(lsINFO) << "SNTP: All servers recently queried"; + return false; + } + best->second = now; + + boost::asio::ip::udp::resolver::query query(boost::asio::ip::udp::v4(), best->first, "ntp"); + mResolver.async_resolve(query, + boost::bind(&SNTPClient::resolveComplete, this, + boost::asio::placeholders::error, boost::asio::placeholders::iterator)); + Log(lsINFO) << "SNTP: Resolve pending for " << best->first; + return true; +} diff --git a/src/SNTPClient.h b/src/SNTPClient.h new file mode 100644 index 000000000..8e6489a0a --- /dev/null +++ b/src/SNTPClient.h @@ -0,0 +1,58 @@ +#ifndef __SNTPCLIENT__ +#define __SNTPCLIENT__ + +#include +#include +#include + +#include +#include + +class SNTPQuery +{ +public: + bool mReceivedReply; + time_t mLocalTimeSent; + + SNTPQuery(time_t j = (time_t) -1) : mReceivedReply(false), mLocalTimeSent(j) { ; } +}; + +class SNTPClient +{ +public: + typedef boost::shared_ptr pointer; + +protected: + std::map mQueries; + boost::mutex mLock; + + boost::asio::io_service& mIOService; + boost::asio::ip::udp::socket mSocket; + boost::asio::deadline_timer mTimer; + boost::asio::ip::udp::resolver mResolver; + + std::vector< std::pair > mServers; + int mOffset; + time_t mLastOffsetUpdate; + + std::vector mReceiveBuffer; + boost::asio::ip::udp::endpoint mReceiveEndpoint; + + void receivePacket(const boost::system::error_code& error, std::size_t bytes); + void resolveComplete(const boost::system::error_code& error, boost::asio::ip::udp::resolver::iterator iterator); + void sentPacket(boost::shared_ptr, const boost::system::error_code&, std::size_t); + void timerEntry(const boost::system::error_code&); + void sendComplete(const boost::system::error_code& error, std::size_t bytesTransferred); + void processReply(); + +public: + SNTPClient(boost::asio::io_service& service); + void init(const std::vector& servers); + void addServer(const std::string& mServer); + + void queryAll(); + bool doQuery(); + bool getOffset(int& offset); +}; + +#endif From 6bd7738303f7f05243759646c40a6e62ad873ea1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 5 Aug 2012 00:19:41 -0700 Subject: [PATCH 27/61] Make time errors a thing of the past. --- src/Application.cpp | 4 ++-- src/Application.h | 1 + src/NetworkOPs.cpp | 7 ++++++- src/Peer.cpp | 15 +++++++++++---- src/SNTPClient.cpp | 35 +++++++++++++++++++++++++---------- 5 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 0ceef99b7..89fe9d2dd 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -69,8 +69,6 @@ void Application::run() if (!theConfig.DEBUG_LOGFILE.empty()) Log::setLogFile(theConfig.DEBUG_LOGFILE); - mSNTPClient.init(theConfig.SNTP_SERVERS); - // // Construct databases. // @@ -149,6 +147,8 @@ void Application::run() mNetOps.setLastCloseNetTime(secondLedger->getCloseTimeNC()); } + mSNTPClient.init(theConfig.SNTP_SERVERS); + mNetOps.setStateTimer(); mIOService.run(); // This blocks diff --git a/src/Application.h b/src/Application.h index 3ba29dee2..9efbc89fc 100644 --- a/src/Application.h +++ b/src/Application.h @@ -88,6 +88,7 @@ public: bool isNew(const uint256& s) { return mSuppressions.addSuppression(s); } bool isNew(const uint160& s) { return mSuppressions.addSuppression(s); } bool running() { return mTxnDB != NULL; } + bool getSystemTimeOffset(int& offset) { return mSNTPClient.getOffset(offset); } DatabaseCon* getRpcDB() { return mRpcDB; } DatabaseCon* getTxnDB() { return mTxnDB; } diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 3ba931e9c..4d243e654 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -31,7 +31,12 @@ NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedge boost::posix_time::ptime NetworkOPs::getNetworkTimePT() { - return boost::posix_time::second_clock::universal_time() + boost::posix_time::seconds(mTimeOffset); + int offset; + if (theApp->getSystemTimeOffset(offset)) + offset += mTimeOffset; + else + offset = mTimeOffset; + return boost::posix_time::second_clock::universal_time() + boost::posix_time::seconds(offset); } uint32 NetworkOPs::getNetworkTimeNC() diff --git a/src/Peer.cpp b/src/Peer.cpp index ccc1b1122..3a8e385f3 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -571,15 +571,22 @@ void Peer::recvHello(newcoin::TMHello& packet) // Cancel verification timeout. (void) mVerifyTimer.cancel(); - uint32 minTime = theApp->getOPs().getNetworkTimeNC() - 20; - uint32 maxTime = minTime + 20; + uint32 ourTime = theApp->getOPs().getNetworkTimeNC(); + uint32 minTime = ourTime - 10; + uint32 maxTime = ourTime + 10; + + if (packet.has_nettime()) + { + int64 to = ourTime; + to -= packet.nettime(); + Log(lsTRACE) << "Connect: time error " << to; + } if (packet.has_nettime() && ((packet.nettime() < minTime) || (packet.nettime() > maxTime))) { Log(lsINFO) << "Recv(Hello): Disconnect: Clock is far off"; } - - if (packet.protoversionmin() < MAKE_VERSION_INT(MIN_PROTO_MAJOR, MIN_PROTO_MINOR)) + else if (packet.protoversionmin() < MAKE_VERSION_INT(MIN_PROTO_MAJOR, MIN_PROTO_MINOR)) { Log(lsINFO) << "Recv(Hello): Server requires protocol version " << GET_VERSION_MAJOR(packet.protoversion()) << "." << GET_VERSION_MINOR(packet.protoversion()) diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index 75226b075..7f652fa40 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -40,7 +40,7 @@ void SNTPClient::resolveComplete(const boost::system::error_code& error, boost:: time_t now = time(NULL); if ((query.mLocalTimeSent == now) || ((query.mLocalTimeSent + 1) == now)) { - Log(lsINFO) << "SNTP: Redundant query suppressed"; + Log(lsTRACE) << "SNTP: Redundant query suppressed"; return; } query.mReceivedReply = false; @@ -57,20 +57,20 @@ void SNTPClient::receivePacket(const boost::system::error_code& error, std::size if (!error) { boost::mutex::scoped_lock sl(mLock); - Log(lsINFO) << "SNTP: Packet from " << mReceiveEndpoint; + Log(lsTRACE) << "SNTP: Packet from " << mReceiveEndpoint; std::map::iterator query = mQueries.find(mReceiveEndpoint); if (query == mQueries.end()) - Log(lsINFO) << "SNTP: Reply found without matching query"; + Log(lsDEBUG) << "SNTP: Reply found without matching query"; else if (query->second.mReceivedReply) - Log(lsINFO) << "SNTP: Duplicate response to query"; + Log(lsDEBUG) << "SNTP: Duplicate response to query"; else { query->second.mReceivedReply = true; if (time(NULL) > (query->second.mLocalTimeSent + 1)) - Log(lsINFO) << "SNTP: Late response"; + Log(lsWARNING) << "SNTP: Late response"; else if (bytes_xferd < 48) - Log(lsINFO) << "SNTP: Short reply (" << bytes_xferd << ") " << mReceiveBuffer.size(); + Log(lsWARNING) << "SNTP: Short reply (" << bytes_xferd << ") " << mReceiveBuffer.size(); else processReply(); } @@ -84,7 +84,7 @@ void SNTPClient::receivePacket(const boost::system::error_code& error, std::size void SNTPClient::sendComplete(const boost::system::error_code& error, std::size_t) { if (error) - Log(lsINFO) << "SNTP: Send error"; + Log(lsWARNING) << "SNTP: Send error"; } void SNTPClient::processReply() @@ -107,11 +107,17 @@ void SNTPClient::processReply() return; } - timev -= time(NULL); + time_t now = time(NULL); + timev -= now; timev -= 0x83AA7E80ULL; - Log(lsINFO) << "SNTP: Offset is " << timev; + Log(lsTRACE) << "SNTP: Offset is " << timev; - // WRITEME + if ((mLastOffsetUpdate == (time_t) -1) || (mLastOffsetUpdate < (now - 180))) + mOffset = timev; + else + mOffset = ((mOffset * 7) + timev) / 8; + mLastOffsetUpdate = now; + Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << timev; } void SNTPClient::timerEntry(const boost::system::error_code& error) @@ -150,6 +156,15 @@ void SNTPClient::queryAll() nothing(); } +bool SNTPClient::getOffset(int& offset) +{ + boost::mutex::scoped_lock sl(mLock); + if ((mLastOffsetUpdate == (time_t) -1) || ((mLastOffsetUpdate + 90) < time(NULL))) + return false; + offset = mOffset; + return true; +} + bool SNTPClient::doQuery() { boost::mutex::scoped_lock sl(mLock); From 3e3d367c98854bd8ce6397a2163d664bf8fa7b38 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 5 Aug 2012 00:39:06 -0700 Subject: [PATCH 28/61] Finalizations, cleanup, and security improvements. --- src/SNTPClient.cpp | 42 ++++++++++++++++++++++++++++++++---------- src/SNTPClient.h | 1 + 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index 7f652fa40..e86edca76 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -11,6 +11,24 @@ static uint8_t SNTPQueryData[48] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +// NTP timestamp constant +#define NTP_UNIX_OFFSET 0x83AA7E80 + +// SNTP packet offsets +#define NTP_OFF_INFO 0 +#define NTP_OFF_ROOTDELAY 1 +#define NTP_OFF_ROOTDISP 2 +#define NTP_OFF_REFERENCEID 3 +#define NTP_OFF_REFTS_INT 4 +#define NTP_OFF_REFTS_FRAC 5 +#define NTP_OFF_ORGTS_INT 6 +#define NTP_OFF_ORGTS_FRAC 7 +#define NTP_OFF_RECVTS_INT 8 +#define NTP_OFF_RECVTS_FRAC 9 +#define NTP_OFF_XMITTS_INT 10 +#define NTP_OFF_XMITTS_FRAC 11 + + SNTPClient::SNTPClient(boost::asio::io_service& service) : mIOService(service), mSocket(service), mTimer(service), mResolver(service), mOffset(0), mLastOffsetUpdate((time_t) -1), mReceiveBuffer(256) @@ -45,7 +63,10 @@ void SNTPClient::resolveComplete(const boost::system::error_code& error, boost:: } query.mReceivedReply = false; query.mLocalTimeSent = now; - mSocket.async_send_to(boost::asio::buffer(SNTPQueryData, 256), *sel, + query.mQueryMagic = rand(); + reinterpret_cast(SNTPQueryData)[NTP_OFF_XMITTS_INT] = time(NULL) + NTP_UNIX_OFFSET; + reinterpret_cast(SNTPQueryData)[NTP_OFF_XMITTS_FRAC] = query.mQueryMagic; + mSocket.async_send_to(boost::asio::buffer(SNTPQueryData, 48), *sel, boost::bind(&SNTPClient::sendComplete, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); } @@ -68,11 +89,12 @@ void SNTPClient::receivePacket(const boost::system::error_code& error, std::size query->second.mReceivedReply = true; if (time(NULL) > (query->second.mLocalTimeSent + 1)) Log(lsWARNING) << "SNTP: Late response"; + else if (bytes_xferd < 48) + Log(lsWARNING) << "SNTP: Short reply (" << bytes_xferd << ") " << mReceiveBuffer.size(); + else if (reinterpret_cast(&mReceiveBuffer[0])[NTP_OFF_ORGTS_FRAC] != query->second.mQueryMagic) + Log(lsWARNING) << "SNTP: Reply had wrong magic number"; else - if (bytes_xferd < 48) - Log(lsWARNING) << "SNTP: Short reply (" << bytes_xferd << ") " << mReceiveBuffer.size(); - else - processReply(); + processReply(); } } @@ -92,8 +114,8 @@ void SNTPClient::processReply() assert(mReceiveBuffer.size() >= 48); uint32 *recvBuffer = reinterpret_cast(&mReceiveBuffer.front()); - unsigned info = ntohl(recvBuffer[0]); - int64_t timev = ntohl(recvBuffer[8]); + unsigned info = ntohl(recvBuffer[NTP_OFF_INFO]); + int64_t timev = ntohl(recvBuffer[NTP_OFF_RECVTS_INT]); unsigned stratum = (info >> 16) & 0xff; if ((info >> 30) == 3) @@ -109,7 +131,7 @@ void SNTPClient::processReply() time_t now = time(NULL); timev -= now; - timev -= 0x83AA7E80ULL; + timev -= NTP_UNIX_OFFSET; Log(lsTRACE) << "SNTP: Offset is " << timev; if ((mLastOffsetUpdate == (time_t) -1) || (mLastOffsetUpdate < (now - 180))) @@ -181,7 +203,7 @@ bool SNTPClient::doQuery() time_t now = time(NULL); if ((best->second == now) || (best->second == (now - 1))) { - Log(lsINFO) << "SNTP: All servers recently queried"; + Log(lsTRACE) << "SNTP: All servers recently queried"; return false; } best->second = now; @@ -190,6 +212,6 @@ bool SNTPClient::doQuery() mResolver.async_resolve(query, boost::bind(&SNTPClient::resolveComplete, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); - Log(lsINFO) << "SNTP: Resolve pending for " << best->first; + Log(lsTRACE) << "SNTP: Resolve pending for " << best->first; return true; } diff --git a/src/SNTPClient.h b/src/SNTPClient.h index 8e6489a0a..f8b00c071 100644 --- a/src/SNTPClient.h +++ b/src/SNTPClient.h @@ -13,6 +13,7 @@ class SNTPQuery public: bool mReceivedReply; time_t mLocalTimeSent; + int mQueryMagic; SNTPQuery(time_t j = (time_t) -1) : mReceivedReply(false), mLocalTimeSent(j) { ; } }; From ed8635c98dc9d44e28dc8e82dccddaa55076b639 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 5 Aug 2012 00:54:28 -0700 Subject: [PATCH 29/61] Use the OpenSSL RNG for randomness that needs to be secure. --- src/SNTPClient.cpp | 10 ++++++---- src/SNTPClient.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index e86edca76..84460101f 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "utils.h" #include "Log.h" @@ -63,9 +65,9 @@ void SNTPClient::resolveComplete(const boost::system::error_code& error, boost:: } query.mReceivedReply = false; query.mLocalTimeSent = now; - query.mQueryMagic = rand(); + RAND_bytes(reinterpret_cast(&query.mQueryNonce), sizeof(query.mQueryNonce)); reinterpret_cast(SNTPQueryData)[NTP_OFF_XMITTS_INT] = time(NULL) + NTP_UNIX_OFFSET; - reinterpret_cast(SNTPQueryData)[NTP_OFF_XMITTS_FRAC] = query.mQueryMagic; + reinterpret_cast(SNTPQueryData)[NTP_OFF_XMITTS_FRAC] = query.mQueryNonce; mSocket.async_send_to(boost::asio::buffer(SNTPQueryData, 48), *sel, boost::bind(&SNTPClient::sendComplete, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); @@ -91,8 +93,8 @@ void SNTPClient::receivePacket(const boost::system::error_code& error, std::size Log(lsWARNING) << "SNTP: Late response"; else if (bytes_xferd < 48) Log(lsWARNING) << "SNTP: Short reply (" << bytes_xferd << ") " << mReceiveBuffer.size(); - else if (reinterpret_cast(&mReceiveBuffer[0])[NTP_OFF_ORGTS_FRAC] != query->second.mQueryMagic) - Log(lsWARNING) << "SNTP: Reply had wrong magic number"; + else if (reinterpret_cast(&mReceiveBuffer[0])[NTP_OFF_ORGTS_FRAC] != query->second.mQueryNonce) + Log(lsWARNING) << "SNTP: Reply had wrong nonce"; else processReply(); } diff --git a/src/SNTPClient.h b/src/SNTPClient.h index f8b00c071..06f54ad0c 100644 --- a/src/SNTPClient.h +++ b/src/SNTPClient.h @@ -13,7 +13,7 @@ class SNTPQuery public: bool mReceivedReply; time_t mLocalTimeSent; - int mQueryMagic; + int mQueryNonce; SNTPQuery(time_t j = (time_t) -1) : mReceivedReply(false), mLocalTimeSent(j) { ; } }; From ad0650b7fa650ef2eeb37857176d773e95c36890 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 5 Aug 2012 03:47:15 -0700 Subject: [PATCH 30/61] Suppress small offsets. They are likely just due to rounding. --- src/SNTPClient.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index 84460101f..5dfe2af07 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -134,14 +134,16 @@ void SNTPClient::processReply() time_t now = time(NULL); timev -= now; timev -= NTP_UNIX_OFFSET; - Log(lsTRACE) << "SNTP: Offset is " << timev; + + if ((timev == -1) || (timev == 1)) // small corrections likely do more harm than good + timev = 0; if ((mLastOffsetUpdate == (time_t) -1) || (mLastOffsetUpdate < (now - 180))) mOffset = timev; else mOffset = ((mOffset * 7) + timev) / 8; mLastOffsetUpdate = now; - Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << timev; + Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset; } void SNTPClient::timerEntry(const boost::system::error_code& error) From 65cbd319c17d8f0e331efb18aab664212c7e6583 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 5 Aug 2012 03:56:17 -0700 Subject: [PATCH 31/61] Cleanups. --- newcoind.cfg | 6 ++++-- src/Peer.cpp | 4 +++- src/SNTPClient.cpp | 9 +++++++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/newcoind.cfg b/newcoind.cfg index 179a14802..774a32129 100644 --- a/newcoind.cfg +++ b/newcoind.cfg @@ -86,7 +86,8 @@ # 2001:0db8:0100:f101:0210:a4ff:fee3:9566 # # [sntp_servers] -# IP address or domain of servers to use for time synchronization. +# IP address or domain of servers to use for time synchronization. +# The default time servers are suitable for servers located in the United States # # [peer_ip]: # IP address or domain to bind to allow external connections from peers. @@ -145,8 +146,9 @@ debug.log [sntp_servers] time.windows.com -us.pool.ntp.org time.apple.com +time.nist.gov +pool.ntp.org [validation_seed] shh1D4oj5czH3PUEjYES8c7Bay3tE diff --git a/src/Peer.cpp b/src/Peer.cpp index 3a8e385f3..7c822dd22 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -575,12 +575,14 @@ void Peer::recvHello(newcoin::TMHello& packet) uint32 minTime = ourTime - 10; uint32 maxTime = ourTime + 10; +#ifdef DEBUG if (packet.has_nettime()) { int64 to = ourTime; to -= packet.nettime(); - Log(lsTRACE) << "Connect: time error " << to; + Log(lsDEBUG) << "Connect: time offset " << to; } +#endif if (packet.has_nettime() && ((packet.nettime() < minTime) || (packet.nettime() > maxTime))) { diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index 5dfe2af07..01931549c 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -13,6 +13,9 @@ static uint8_t SNTPQueryData[48] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +// NTP query frequency - 5 minutes +#define NTP_QUERY_FREQUENCY (5 * 60) + // NTP timestamp constant #define NTP_UNIX_OFFSET 0x83AA7E80 @@ -40,7 +43,7 @@ SNTPClient::SNTPClient(boost::asio::io_service& service) : boost::bind(&SNTPClient::receivePacket, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); - mTimer.expires_from_now(boost::posix_time::seconds(1)); + mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY)); mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error)); } @@ -138,11 +141,13 @@ void SNTPClient::processReply() if ((timev == -1) || (timev == 1)) // small corrections likely do more harm than good timev = 0; + // FIXME: We really should use the median of all recent valid offsets if ((mLastOffsetUpdate == (time_t) -1) || (mLastOffsetUpdate < (now - 180))) mOffset = timev; else mOffset = ((mOffset * 7) + timev) / 8; mLastOffsetUpdate = now; + Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset; } @@ -151,7 +156,7 @@ void SNTPClient::timerEntry(const boost::system::error_code& error) if (!error) { doQuery(); - mTimer.expires_from_now(boost::posix_time::seconds(10)); + mTimer.expires_from_now(boost::posix_time::seconds(NTP_QUERY_FREQUENCY)); mTimer.async_wait(boost::bind(&SNTPClient::timerEntry, this, boost::asio::placeholders::error)); } } From 05e193f370ea6ec51fcdef5b8fe688d0f05886cd Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 5 Aug 2012 20:07:08 -0700 Subject: [PATCH 32/61] Use a median filter to protect against bad timeservers. --- src/SNTPClient.cpp | 29 +++++++++++++++++++++-------- src/SNTPClient.h | 3 +++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index 01931549c..d84cfa3c5 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -16,6 +16,9 @@ static uint8_t SNTPQueryData[48] = { // NTP query frequency - 5 minutes #define NTP_QUERY_FREQUENCY (5 * 60) +// NTP sample window (should be odd) +#define NTP_SAMPLE_WINDOW 9 + // NTP timestamp constant #define NTP_UNIX_OFFSET 0x83AA7E80 @@ -138,16 +141,26 @@ void SNTPClient::processReply() timev -= now; timev -= NTP_UNIX_OFFSET; - if ((timev == -1) || (timev == 1)) // small corrections likely do more harm than good - timev = 0; - - // FIXME: We really should use the median of all recent valid offsets - if ((mLastOffsetUpdate == (time_t) -1) || (mLastOffsetUpdate < (now - 180))) - mOffset = timev; - else - mOffset = ((mOffset * 7) + timev) / 8; + // add offset to list, replacing oldest one if appropriate + mOffsetList.push_back(timev); + if (mOffsetList.size() >= NTP_SAMPLE_WINDOW) + mOffsetList.pop_front(); mLastOffsetUpdate = now; + // select median time + std::list offsetList = mOffsetList; + offsetList.sort(); + int j = offsetList.size(); + std::list::iterator it = offsetList.begin(); + for (int i = 0; i < (j / 2); ++i) + ++it; + mOffset = *it; + if ((j % 2) == 0) + mOffset = (mOffset + (*--it)) / 2; + + if ((mOffset == -1) || (mOffset == 1)) // small corrections likely do more harm than good + mOffset = 0; + Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset; } diff --git a/src/SNTPClient.h b/src/SNTPClient.h index 06f54ad0c..ea7b0e7c8 100644 --- a/src/SNTPClient.h +++ b/src/SNTPClient.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -33,8 +34,10 @@ protected: boost::asio::ip::udp::resolver mResolver; std::vector< std::pair > mServers; + int mOffset; time_t mLastOffsetUpdate; + std::list mOffsetList; std::vector mReceiveBuffer; boost::asio::ip::udp::endpoint mReceiveEndpoint; From b14b2f5daba4dae54a060037185ab17183e21f88 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 02:12:27 -0700 Subject: [PATCH 33/61] Separate close times and network times. --- src/Ledger.cpp | 2 +- src/LedgerConsensus.cpp | 6 +++--- src/LedgerTiming.h | 2 +- src/NetworkOPs.cpp | 14 ++++++++------ src/NetworkOPs.h | 3 ++- src/ValidationCollection.cpp | 6 +++--- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index aa279f8a4..e94c6dc5b 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -71,7 +71,7 @@ Ledger::Ledger(bool dummy, Ledger& prevLedger) : prevLedger.getCloseAgree(), mLedgerSeq); if (prevLedger.mCloseTime == 0) { - mCloseTime = theApp->getOPs().getNetworkTimeNC(); + mCloseTime = theApp->getOPs().getCloseTimeNC(); mCloseTime -= (mCloseTime % mCloseResolution); } else diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index e4b2fe428..deeb5a7a6 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -404,7 +404,7 @@ void LedgerConsensus::statePreClose() int proposersClosed = mPeerPositions.size(); // This ledger is open. This computes how long since the last ledger closed - int sinceClose = 1000 * (theApp->getOPs().getNetworkTimeNC() - theApp->getOPs().getLastCloseNetTime()); + int sinceClose = 1000 * (theApp->getOPs().getCloseTimeNC() - theApp->getOPs().getLastCloseNetTime()); if (sinceClose >= ContinuousLedgerTiming::shouldClose(anyTransactions, mPreviousProposers, proposersClosed, mPreviousMSeconds, sinceClose)) @@ -412,7 +412,7 @@ void LedgerConsensus::statePreClose() Log(lsINFO) << "CLC: closing ledger"; mState = lcsESTABLISH; mConsensusStartTime = boost::posix_time::second_clock::universal_time(); - mCloseTime = theApp->getOPs().getNetworkTimeNC(); + mCloseTime = theApp->getOPs().getCloseTimeNC(); theApp->getOPs().setLastCloseNetTime(mCloseTime); statusChange(newcoin::neCLOSING_LEDGER, *mPreviousLedger); takeInitialPosition(*theApp->getMasterLedger().closeLedger()); @@ -930,7 +930,7 @@ void LedgerConsensus::accept(SHAMap::pointer set) closeTotal += (closeCount / 2); closeTotal /= closeCount; int offset = static_cast(closeTotal) - static_cast(mCloseTime); - Log(lsINFO) << "Our clock offset is estimated at " << offset; + Log(lsINFO) << "Our close offset is estimated at " << offset << " (" << closeCount << ")"; } #ifdef DEBUG diff --git a/src/LedgerTiming.h b/src/LedgerTiming.h index add26558f..41e85762a 100644 --- a/src/LedgerTiming.h +++ b/src/LedgerTiming.h @@ -5,7 +5,7 @@ # define LEDGER_IDLE_INTERVAL 15 // The number of seconds a validation remains current -# define LEDGER_MAX_INTERVAL 60 +# define LEDGER_MAX_INTERVAL (LEDGER_IDLE_INTERVAL * 4) // The number of milliseconds we wait minimum to ensure participation # define LEDGER_MIN_CONSENSUS 2000 diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 4d243e654..22eae18a1 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -24,18 +24,15 @@ // there's a functional network. NetworkOPs::NetworkOPs(boost::asio::io_service& io_service, LedgerMaster* pLedgerMaster) : - mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster), mTimeOffset(0), + mMode(omDISCONNECTED),mNetTimer(io_service), mLedgerMaster(pLedgerMaster), mCloseTimeOffset(0), mLastCloseProposers(0), mLastCloseConvergeTime(LEDGER_IDLE_INTERVAL) { } boost::posix_time::ptime NetworkOPs::getNetworkTimePT() { - int offset; - if (theApp->getSystemTimeOffset(offset)) - offset += mTimeOffset; - else - offset = mTimeOffset; + int offset = 0; + theApp->getSystemTimeOffset(offset); return boost::posix_time::second_clock::universal_time() + boost::posix_time::seconds(offset); } @@ -44,6 +41,11 @@ uint32 NetworkOPs::getNetworkTimeNC() return iToSeconds(getNetworkTimePT()); } +uint32 NetworkOPs::getCloseTimeNC() +{ + return iToSeconds(getNetworkTimePT() + boost::posix_time::seconds(mCloseTimeOffset)); +} + uint32 NetworkOPs::getCurrentLedgerID() { return mLedgerMaster->getCurrentLedger()->getLedgerSeq(); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 67ada0363..8e8e45c24 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -58,7 +58,7 @@ protected: LedgerMaster* mLedgerMaster; LedgerAcquire::pointer mAcquiringLedger; - int mTimeOffset; + int mCloseTimeOffset; // last ledger close int mLastCloseProposers, mLastCloseConvergeTime; @@ -88,6 +88,7 @@ public: // network information uint32 getNetworkTimeNC(); + uint32 getCloseTimeNC(); boost::posix_time::ptime getNetworkTimePT(); uint32 getCurrentLedgerID(); OperatingMode getOperatingMode() { return mMode; } diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index c8ba94856..98c70258b 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -12,7 +12,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) if (theApp->getUNL().nodeInUNL(signer)) { val->setTrusted(); - uint32 now = theApp->getOPs().getNetworkTimeNC(); + uint32 now = theApp->getOPs().getCloseTimeNC(); uint32 valClose = val->getCloseTime(); if ((now > valClose) && (now < (valClose + LEDGER_MAX_INTERVAL))) isCurrent = true; @@ -72,7 +72,7 @@ void ValidationCollection::getValidationCount(const uint256& ledger, bool curren trusted = untrusted = 0; boost::mutex::scoped_lock sl(mValidationLock); boost::unordered_map::iterator it = mValidations.find(ledger); - uint32 now = theApp->getOPs().getNetworkTimeNC(); + uint32 now = theApp->getOPs().getCloseTimeNC(); if (it != mValidations.end()) { for (ValidationSet::iterator vit = it->second.begin(), end = it->second.end(); vit != end; ++vit) @@ -123,7 +123,7 @@ int ValidationCollection::getCurrentValidationCount(uint32 afterTime) boost::unordered_map ValidationCollection::getCurrentValidations() { - uint32 now = theApp->getOPs().getNetworkTimeNC(); + uint32 now = theApp->getOPs().getCloseTimeNC(); boost::unordered_map ret; { From 39b28e1f50704aa223c96bf1e016dc2970261603 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 02:21:17 -0700 Subject: [PATCH 34/61] Don't switch to a dead ledger. Without this, we can even get out of sync with ourselves! --- src/NetworkOPs.cpp | 20 ++++++++++++++++---- src/ValidationCollection.cpp | 7 +++++++ src/ValidationCollection.h | 14 +++++++++++--- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 22eae18a1..81f5b0da8 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -455,16 +455,27 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis // 3) Is there a network ledger we'd like to switch to? If so, do we have it? bool switchLedgers = false; - for(boost::unordered_map::iterator it = ledgers.begin(), end = ledgers.end(); + std::list deadLedgers = theApp->getValidations().getDeadLedgers(); + for (boost::unordered_map::iterator it = ledgers.begin(), end = ledgers.end(); it != end; ++it) { Log(lsTRACE) << "L: " << it->first.GetHex() << " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; if (it->second > bestVC) { - bestVC = it->second; - closedLedger = it->first; - switchLedgers = true; + bool dead = false; + for (std::list::iterator dit = deadLedgers.begin(), end = deadLedgers.end(); dit != end; ++it) + if (*dit == it->first) + { + dead = true; + break; + } + if (!dead) + { + bestVC = it->second; + closedLedger = it->first; + switchLedgers = true; + } } } @@ -665,6 +676,7 @@ void NetworkOPs::endConsensus(bool correctLCL) { uint256 deadLedger = theApp->getMasterLedger().getClosedLedger()->getParentHash(); Log(lsTRACE) << "Ledger " << deadLedger.GetHex() << " is now dead"; + theApp->getValidations().addDeadLedger(deadLedger); std::vector peerList = theApp->getConnectionPool().getPeerVector(); for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) if (*it && ((*it)->getClosedLedgerHash() == deadLedger)) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 98c70258b..cd3f981f2 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -172,6 +172,13 @@ boost::unordered_map ValidationCollection::getCurrentValidations() return ret; } +void ValidationCollection::addDeadLedger(const uint256& ledger) +{ + mDeadLedgers.push_back(ledger); + if (mDeadLedgers.size() >= 128) + mDeadLedgers.pop_front(); +} + void ValidationCollection::flush() { boost::mutex::scoped_lock sl(mValidationLock); diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index 4120a9e24..5f58956bc 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -25,9 +25,11 @@ class ValidationCollection protected: boost::mutex mValidationLock; - boost::unordered_map mValidations; - boost::unordered_map mCurrentValidations; - std::vector mStaleValidations; + boost::unordered_map mValidations; + boost::unordered_map mCurrentValidations; + std::vector mStaleValidations; + std::list mDeadLedgers; + bool mWriting; void doWrite(); @@ -39,9 +41,15 @@ public: bool addValidation(SerializedValidation::pointer); ValidationSet getValidations(const uint256& ledger); void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted); + int getTrustedValidationCount(const uint256& ledger); int getCurrentValidationCount(uint32 afterTime); + boost::unordered_map getCurrentValidations(); + + void addDeadLedger(const uint256&); + std::list getDeadLedgers() { return mDeadLedgers; } + void flush(); }; From 71b5b19198142b9ecce2b8c1699100dc06c97a1e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 02:25:59 -0700 Subject: [PATCH 35/61] Bugfix. --- src/NetworkOPs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 81f5b0da8..647e195fa 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -464,7 +464,7 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis if (it->second > bestVC) { bool dead = false; - for (std::list::iterator dit = deadLedgers.begin(), end = deadLedgers.end(); dit != end; ++it) + for (std::list::iterator dit = deadLedgers.begin(), end = deadLedgers.end(); dit != end; ++dit) if (*dit == it->first) { dead = true; From 3e2ecc88cc7a75c08ed5ba0a94cb414907381a86 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 02:32:53 -0700 Subject: [PATCH 36/61] Check that we don't already have a dead ledger. --- src/ValidationCollection.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index cd3f981f2..21888dffa 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -174,6 +174,9 @@ boost::unordered_map ValidationCollection::getCurrentValidations() void ValidationCollection::addDeadLedger(const uint256& ledger) { + for (std::list::iterator it = mDeadLedgers.begin(), end = mDeadLedgers.end(); it != end; ++it) + if (*it == ledger) + return; mDeadLedgers.push_back(ledger); if (mDeadLedgers.size() >= 128) mDeadLedgers.pop_front(); From 3ae8ec616827c5f014fca2a4763e37a38bb3331f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 03:05:17 -0700 Subject: [PATCH 37/61] Remove some old debug. --- src/LedgerAcquire.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 846fc8c9f..16cc1abe4 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -10,7 +10,7 @@ #include "SHAMapSync.h" #include "HashPrefixes.h" -#define LA_DEBUG +// #define LA_DEBUG #define LEDGER_ACQUIRE_TIMEOUT 2 #define TRUST_NETWORK @@ -142,7 +142,7 @@ void LedgerAcquire::addOnComplete(boost::function void LedgerAcquire::trigger(Peer::pointer peer) { - if (mAborted) + if (mAborted || mComplete || mFailed) return; #ifdef LA_DEBUG if(peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex() << " from " << peer->getIP(); @@ -150,8 +150,6 @@ void LedgerAcquire::trigger(Peer::pointer peer) Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed; Log(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState; #endif - if (mComplete || mFailed) - return; if (!mHaveBase) { #ifdef LA_DEBUG From 6553b21318587e78d5796cf75f189c52c15b0c93 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 03:05:35 -0700 Subject: [PATCH 38/61] Fix some dead ledger logic. --- src/ValidationCollection.cpp | 14 +++++++++++--- src/ValidationCollection.h | 1 + 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index 21888dffa..466b3d7f2 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -14,7 +14,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) val->setTrusted(); uint32 now = theApp->getOPs().getCloseTimeNC(); uint32 valClose = val->getCloseTime(); - if ((now > valClose) && (now < (valClose + LEDGER_MAX_INTERVAL))) + if ((now > (valClose - 4)) && (now < (valClose + LEDGER_MAX_INTERVAL))) isCurrent = true; else Log(lsWARNING) << "Received stale validation now=" << now << ", close=" << valClose; @@ -172,11 +172,19 @@ boost::unordered_map ValidationCollection::getCurrentValidations() return ret; } -void ValidationCollection::addDeadLedger(const uint256& ledger) +bool ValidationCollection::isDeadLedger(const uint256& ledger) { for (std::list::iterator it = mDeadLedgers.begin(), end = mDeadLedgers.end(); it != end; ++it) if (*it == ledger) - return; + return true; + return false; +} + +void ValidationCollection::addDeadLedger(const uint256& ledger) +{ + if (isDeadLedger(ledger)) + return; + mDeadLedgers.push_back(ledger); if (mDeadLedgers.size() >= 128) mDeadLedgers.pop_front(); diff --git a/src/ValidationCollection.h b/src/ValidationCollection.h index 5f58956bc..2198a967f 100644 --- a/src/ValidationCollection.h +++ b/src/ValidationCollection.h @@ -48,6 +48,7 @@ public: boost::unordered_map getCurrentValidations(); void addDeadLedger(const uint256&); + bool isDeadLedger(const uint256&); std::list getDeadLedgers() { return mDeadLedgers; } void flush(); From 573ef488f280c3585d3950fab3e4748251bc510e Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 03:05:44 -0700 Subject: [PATCH 39/61] Fix dead ledger logic. Improve some logging. Fix how we handle close time consensus based on whether we're validating. --- src/LedgerConsensus.cpp | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index deeb5a7a6..bc53a12f2 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -207,7 +207,8 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer pre if (!mHaveCorrectLCL) { - Log(lsINFO) << "Entering consensus process without correct LCL"; + Log(lsINFO) << "Entering consensus with: " << previousLedger->getHash().GetHex(); + Log(lsINFO) << "Correct LCL is: " << prevLCLHash.GetHex(); mHaveCorrectLCL = mProposing = mValidating = false; mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(prevLCLHash); std::vector peerList = theApp->getConnectionPool().getPeerVector(); @@ -231,20 +232,20 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer pre void LedgerConsensus::checkLCL() { - uint256 netLgr; + uint256 netLgr = mPrevLedgerHash; int netLgrCount = 0; { boost::unordered_map vals = theApp->getValidations().getCurrentValidations(); for (boost::unordered_map::iterator it = vals.begin(), end = vals.end(); it != end; ++it) - if (it->second > netLgrCount) + if ((it->second > netLgrCount) && !theApp->getValidations().isDeadLedger(it->first)) { netLgr = it->first; netLgrCount = it->second; } } - if ((netLgrCount > 0) && (netLgr != mPrevLedgerHash)) + if (netLgr != mPrevLedgerHash) { // LCL change - Log(lsWARNING) << "View of consensus changed during consensus"; + Log(lsWARNING) << "View of consensus changed during consensus (" << netLgrCount << ")"; mPrevLedgerHash = netLgr; mAcquiringLedger = theApp->getMasterLedgerAcquire().findCreate(mPrevLedgerHash); std::vector peerList = theApp->getConnectionPool().getPeerVector(); @@ -473,9 +474,9 @@ void LedgerConsensus::timerEntry() switch (mState) { - case lcsPRE_CLOSE: statePreClose(); if (mState != lcsESTABLISH) return; - case lcsESTABLISH: stateEstablish(); if (mState != lcsFINISHED) return; - case lcsFINISHED: stateFinished(); if (mState != lcsACCEPTED) return; + case lcsPRE_CLOSE: statePreClose(); if (mState != lcsESTABLISH) return; fallthru(); + case lcsESTABLISH: stateEstablish(); if (mState != lcsFINISHED) return; fallthru(); + case lcsFINISHED: stateFinished(); if (mState != lcsACCEPTED) return; fallthru(); case lcsACCEPTED: stateAccepted(); return; } assert(false); @@ -515,8 +516,6 @@ void LedgerConsensus::updateOurPositions() for (boost::unordered_map::iterator it = mPeerPositions.begin(), end = mPeerPositions.end(); it != end; ++it) ++closeTimes[it->second->getCloseTime() - (it->second->getCloseTime() % mCloseResolution)]; - ++closeTimes[mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)]; - int neededWeight; if (mClosePercent < AV_MID_CONSENSUS_TIME) @@ -525,10 +524,18 @@ void LedgerConsensus::updateOurPositions() neededWeight = AV_MID_CONSENSUS_PCT; else neededWeight = AV_LATE_CONSENSUS_PCT; - int thresh = mPeerPositions.size() * neededWeight / 100; + int thresh = mPeerPositions.size(); + if (mProposing) + { + ++closeTimes[mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)]; + ++thresh; + } + thresh = thresh * neededWeight / 100; + uint32 closeTime = 0; for (std::map::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it) { + Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << " out of " << thresh; if (it->second > thresh) { mHaveCloseTimeConsensus = true; @@ -882,7 +889,6 @@ void LedgerConsensus::accept(SHAMap::pointer set) theApp->getConnectionPool().relayMessage(NULL, boost::make_shared(val, newcoin::mtVALIDATION)); Log(lsINFO) << "Validation sent " << newLCLHash.GetHex(); } - else Log(lsWARNING) << "Not validating"; Ledger::pointer newOL = boost::make_shared(true, boost::ref(*newLCL)); ScopedLock sl = theApp->getMasterLedger().getLock(); From e4919220588bb58239095ba8503c12d64281f6e2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 03:06:16 -0700 Subject: [PATCH 40/61] Simplify. --- src/NetworkOPs.cpp | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 647e195fa..c6be046c4 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -455,27 +455,16 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis // 3) Is there a network ledger we'd like to switch to? If so, do we have it? bool switchLedgers = false; - std::list deadLedgers = theApp->getValidations().getDeadLedgers(); for (boost::unordered_map::iterator it = ledgers.begin(), end = ledgers.end(); it != end; ++it) { Log(lsTRACE) << "L: " << it->first.GetHex() << " t=" << it->second.trustedValidations << ", n=" << it->second.nodesUsing; - if (it->second > bestVC) + if ((it->second > bestVC) && !theApp->getValidations().isDeadLedger(it->first)) { - bool dead = false; - for (std::list::iterator dit = deadLedgers.begin(), end = deadLedgers.end(); dit != end; ++dit) - if (*dit == it->first) - { - dead = true; - break; - } - if (!dead) - { - bestVC = it->second; - closedLedger = it->first; - switchLedgers = true; - } + bestVC = it->second; + closedLedger = it->first; + switchLedgers = true; } } From 85c029367398ddfd7d29bf6ea7482190a306e4c0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 03:39:45 -0700 Subject: [PATCH 41/61] Report peer close times. --- src/LedgerConsensus.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index bc53a12f2..8a9bf8263 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -698,6 +698,7 @@ bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition) } else if (newPosition->getProposeSeq() == 0) { // new initial close time estimate + Log(lsTRACE) << "Peer reports close time as " << newPosition->getCloseTime(); ++mCloseTimes[newPosition->getCloseTime()]; } Log(lsINFO) << "Processing peer proposal " << newPosition->getProposeSeq() << "/" From efa3653b800ecfd931bd34ab343bf6867bec005d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 03:40:52 -0700 Subject: [PATCH 42/61] Bugfix for moving from connected to tracking state. Skeleting for getting Json info from consensus engine. --- src/LedgerConsensus.cpp | 8 ++++++++ src/LedgerConsensus.h | 3 +++ src/NetworkOPs.cpp | 9 +++------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 8a9bf8263..93229b5e4 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -956,4 +956,12 @@ void LedgerConsensus::endConsensus() { theApp->getOPs().endConsensus(mHaveCorrectLCL); } + +Json::Value LedgerConsensus::getJson() +{ + Json::Value ret(Json::objectValue); + + return ret; +} + // vim:ts=4 diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 6f167e72d..205a75cd1 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -8,6 +8,8 @@ #include #include +#include "../json/value.h" + #include "key.h" #include "Transaction.h" #include "LedgerAcquire.h" @@ -142,6 +144,7 @@ public: LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer previousLedger, uint32 closeTime); int startup(); + Json::Value getJson(); Ledger::pointer peekPreviousLedger() { return mPreviousLedger; } uint256 getLCL() { return mPrevLedgerHash; } diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index c6be046c4..875834a1e 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -604,12 +604,6 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, uint if (!theApp->isNew(s.getSHA512Half())) return false; - if ((mMode != omFULL) && (mMode != omTRACKING)) - { - Log(lsINFO) << "Received proposal when not full/tracking: " << mMode; - return true; - } - if (!mConsensus) { // FIXME: CLC Log(lsWARNING) << "Received proposal when full but not during consensus window"; @@ -754,6 +748,9 @@ Json::Value NetworkOPs::getServerInfo() if (!theConfig.VALIDATION_SEED.isValid()) info["serverState"] = "none"; else info["validationPKey"] = NewcoinAddress::createNodePublic(theConfig.VALIDATION_SEED).humanNodePublic(); + if (mConsensus) + info["consensus"] = mConsensus->getJson(); + return info; } From 7a5db15041dc909b173b59906e407ccf9a64f10c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 03:51:44 -0700 Subject: [PATCH 43/61] Add more consensus information to the "server_info" RPC call. --- src/LedgerConsensus.cpp | 19 +++++++++++++++++++ src/LedgerProposal.h | 3 +++ 2 files changed, 22 insertions(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 93229b5e4..e07bd8a81 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -960,6 +960,25 @@ void LedgerConsensus::endConsensus() Json::Value LedgerConsensus::getJson() { Json::Value ret(Json::objectValue); + ret["proposing"] = mProposing ? "yes" : "no"; + ret["validating"] = mValidating ? "yes" : "no"; + ret["synched"] = mHaveCorrectLCL ? "yes" : "no"; + ret["proposers"] = static_cast(mPeerPositions.size()); + + switch (mState) + { + case lcsPRE_CLOSE: ret["state"] = "open"; break; + case lcsESTABLISH: ret["state"] = "consensus"; break; + case lcsFINISHED: ret["state"] = "finished"; break; + case lcsACCEPTED: ret["state"] = "accepted"; break; + } + + int v = mDisputes.size(); + if (v != 0) + ret["disputes"] = v; + + if (mOurPosition) + ret["our_position"] = mOurPosition->getJson(); return ret; } diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index 1490e9d5e..790b61fb4 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -5,6 +5,8 @@ #include +#include "../json/value.h" + #include "NewcoinAddress.h" #include "Serializer.h" @@ -48,6 +50,7 @@ public: std::vector sign(); void changePosition(const uint256& newPosition, uint32 newCloseTime); + Json::Value getJson() const; }; #endif From 241393410adaf02c3b4d5bb45795bd33f89e7f1f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 03:57:01 -0700 Subject: [PATCH 44/61] More json information about consensus process. Fix a bug where swithing ledgers during the consensus window caused us to use the wrong close resolution. --- src/LedgerConsensus.cpp | 15 +++++++++++++-- src/LedgerProposal.cpp | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index e07bd8a81..72cb43ebc 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -201,7 +201,7 @@ LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::pointer pre assert(mPreviousMSeconds); mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution( - previousLedger->getCloseResolution(), previousLedger->getCloseAgree(), previousLedger->getLedgerSeq() + 1); + mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(), previousLedger->getLedgerSeq() + 1); mHaveCorrectLCL = previousLedger->getHash() == prevLCLHash; @@ -464,6 +464,9 @@ void LedgerConsensus::timerEntry() theApp->getOPs().switchLastClosedLedger(consensus, true); mPreviousLedger = consensus; mHaveCorrectLCL = true; + mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution( + mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(), + mPreviousLedger->getLedgerSeq() + 1); } else Log(lsINFO) << "We still don't have it"; } @@ -962,9 +965,17 @@ Json::Value LedgerConsensus::getJson() Json::Value ret(Json::objectValue); ret["proposing"] = mProposing ? "yes" : "no"; ret["validating"] = mValidating ? "yes" : "no"; - ret["synched"] = mHaveCorrectLCL ? "yes" : "no"; ret["proposers"] = static_cast(mPeerPositions.size()); + if (mHaveCorrectLCL) + { + ret["synched"] = "yes"; + ret["ledger_seq"] = mPreviousLedger->getLedgerSeq() + 1; + ret["close_granularity"] = mCloseResolution; + } + else + ret["synched"] = "no"; + switch (mState) { case lcsPRE_CLOSE: ret["state"] = "open"; break; diff --git a/src/LedgerProposal.cpp b/src/LedgerProposal.cpp index 55c7f0afc..70d9458f6 100644 --- a/src/LedgerProposal.cpp +++ b/src/LedgerProposal.cpp @@ -72,4 +72,18 @@ std::vector LedgerProposal::sign(void) return ret; } +Json::Value LedgerProposal::getJson() const +{ + Json::Value ret = Json::objectValue; + ret["previous_ledger"] = mPreviousLedger.GetHex(); + ret["transaction_hash"] = mCurrentHash.GetHex(); + ret["close_time"] = mCloseTime; + ret["propose_seq"] = mProposeSeq; + + if (mPublicKey.isValid()) + ret["peer_id"] = mPublicKey.humanNodePublic(); + + return ret; +} + // vim:ts=4 From 7186d45f4534d3c9f2af567e76d390e32a9733cd Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 04:22:35 -0700 Subject: [PATCH 45/61] Some extra debug to try to find the close time consensus buglet. --- src/LedgerConsensus.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 72cb43ebc..b1513a418 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -541,10 +541,12 @@ void LedgerConsensus::updateOurPositions() Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << " out of " << thresh; if (it->second > thresh) { + Log(lsINFO) << "Close time consensus reached: " << closeTime; mHaveCloseTimeConsensus = true; closeTime = it->first; } } + if (closeTime != (mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution))) { ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true); @@ -558,6 +560,7 @@ void LedgerConsensus::updateOurPositions() if (mProposing) propose(addedTx, removedTx); mapComplete(newHash, ourPosition, false); Log(lsINFO) << "We change our position to " << newHash.GetHex(); + Log(lsINFO) << " Close time " << closeTime; } } From 5c01dc73383a18e1d48c12cef5993f545e3b5e79 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 6 Aug 2012 04:28:20 -0700 Subject: [PATCH 46/61] We can lose time consensus. --- src/LedgerConsensus.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index b1513a418..3b0d9b41e 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -536,6 +536,7 @@ void LedgerConsensus::updateOurPositions() thresh = thresh * neededWeight / 100; uint32 closeTime = 0; + mHaveCloseTimeConsensus = false; for (std::map::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it) { Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << " out of " << thresh; From f80b884e8131c51f42324a78d6147fab79b411d5 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 7 Aug 2012 01:30:39 -0700 Subject: [PATCH 47/61] Fix a consensus close time bug. --- src/LedgerConsensus.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 3b0d9b41e..6902ab659 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -872,13 +872,15 @@ void LedgerConsensus::accept(SHAMap::pointer set) applyTransactions(set, newLCL, newLCL, failedTransactions, true); newLCL->setClosed(); - uint32 closeTime = mOurPosition->getCloseTime(); + uint32 closeTime = mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() & mCloseResolution); bool closeTimeCorrect = true; if (closeTime == 0) - { // we didn't agree + { // we agreed to disagree closeTimeCorrect = false; closeTime = mPreviousLedger->getCloseTimeNC() + 1; + Log(lsINFO) << "Consensus close time (good) " << closeTime; } + else Log(lsINFO) << "Consensus close time (bad) " << closeTime; newLCL->setAccepted(closeTime, mCloseResolution, closeTimeCorrect); newLCL->updateHash(); From 03e8104f6249dc8a50dd46af3df55ec66cb9e1d7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 7 Aug 2012 01:39:34 -0700 Subject: [PATCH 48/61] Small close time consensus fix. --- src/LedgerConsensus.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 6902ab659..0d53af7b8 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -527,7 +527,15 @@ void LedgerConsensus::updateOurPositions() neededWeight = AV_MID_CONSENSUS_PCT; else neededWeight = AV_LATE_CONSENSUS_PCT; + uint32 closeTime = 0; + mHaveCloseTimeConsensus = false; + int thresh = mPeerPositions.size(); + if (thresh == 0) + { // no other times + mHaveCloseTimeConsensus = true; + closeTime = mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution); + } if (mProposing) { ++closeTimes[mOurPosition->getCloseTime() - (mOurPosition->getCloseTime() % mCloseResolution)]; @@ -535,8 +543,6 @@ void LedgerConsensus::updateOurPositions() } thresh = thresh * neededWeight / 100; - uint32 closeTime = 0; - mHaveCloseTimeConsensus = false; for (std::map::iterator it = closeTimes.begin(), end = closeTimes.end(); it != end; ++it) { Log(lsINFO) << "CCTime: " << it->first << " has " << it->second << " out of " << thresh; From 86b9597ddd61404f475f954036dd9f78f7bc16d2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 7 Aug 2012 03:32:58 -0700 Subject: [PATCH 49/61] Reduce log chattiness. Acquire transaction and state trees in parallel. --- src/HashedObject.cpp | 1 - src/LedgerAcquire.cpp | 60 ++++++++++++++--------------------------- src/LedgerConsensus.cpp | 15 +++++------ src/SNTPClient.cpp | 24 +++++++++++------ 4 files changed, 43 insertions(+), 57 deletions(-) diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp index 8c9ef0ac7..9dc7e6e92 100644 --- a/src/HashedObject.cpp +++ b/src/HashedObject.cpp @@ -37,7 +37,6 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index, t.detach(); } } - Log(lsTRACE) << "HOS: " << hash.GetHex() << " store: deferred"; return true; } diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 16cc1abe4..bc065606e 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -147,27 +147,22 @@ void LedgerAcquire::trigger(Peer::pointer peer) #ifdef LA_DEBUG if(peer) Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex() << " from " << peer->getIP(); else Log(lsTRACE) << "Trigger acquiring ledger " << mHash.GetHex(); - Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed; - Log(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState; + if (mComplete || mFailed) + Log(lsTRACE) << "complete=" << mComplete << " failed=" << mFailed; + else + Log(lsTRACE) << "base=" << mHaveBase << " tx=" << mHaveTransactions << " as=" << mHaveState; #endif if (!mHaveBase) { -#ifdef LA_DEBUG - Log(lsTRACE) << "need base"; -#endif newcoin::TMGetLedger tmGL; tmGL.set_ledgerhash(mHash.begin(), mHash.size()); tmGL.set_itype(newcoin::liBASE); *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); - if (peer) - { - sendRequest(tmGL, peer); - return; - } - else sendRequest(tmGL); + sendRequest(tmGL, peer); + return; // Cannot go on without base } - if (mHaveBase && !mHaveTransactions) + if (!mHaveTransactions) { #ifdef LA_DEBUG Log(lsTRACE) << "need tx"; @@ -180,12 +175,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) tmGL.set_ledgerseq(mLedger->getLedgerSeq()); tmGL.set_itype(newcoin::liTX_NODE); *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); - if (peer) - { - sendRequest(tmGL, peer); - return; - } - sendRequest(tmGL); + sendRequest(tmGL, peer); } else { @@ -199,7 +189,8 @@ void LedgerAcquire::trigger(Peer::pointer peer) else { mHaveTransactions = true; - if (mHaveState) mComplete = true; + if (mHaveState) + mComplete = true; } } else @@ -210,17 +201,12 @@ void LedgerAcquire::trigger(Peer::pointer peer) tmGL.set_itype(newcoin::liTX_NODE); for (std::vector::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it) *(tmGL.add_nodeids()) = it->getRawString(); - if (peer) - { - sendRequest(tmGL, peer); - return; - } - sendRequest(tmGL); + sendRequest(tmGL, peer); } } } - if (mHaveBase && !mHaveState) + if (!mHaveState) { #ifdef LA_DEBUG Log(lsTRACE) << "need as"; @@ -233,12 +219,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) tmGL.set_ledgerseq(mLedger->getLedgerSeq()); tmGL.set_itype(newcoin::liAS_NODE); *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); - if (peer) - { - sendRequest(tmGL, peer); - return; - } - sendRequest(tmGL); + sendRequest(tmGL, peer); } else { @@ -252,7 +233,8 @@ void LedgerAcquire::trigger(Peer::pointer peer) else { mHaveState = true; - if (mHaveTransactions) mComplete = true; + if (mHaveTransactions) + mComplete = true; } } else @@ -263,12 +245,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) tmGL.set_itype(newcoin::liAS_NODE); for (std::vector::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it) *(tmGL.add_nodeids()) = it->getRawString(); - if (peer) - { - sendRequest(tmGL, peer); - return; - } - sendRequest(tmGL); + sendRequest(tmGL, peer); } } } @@ -281,7 +258,10 @@ void LedgerAcquire::trigger(Peer::pointer peer) void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL, Peer::pointer peer) { - peer->sendPacket(boost::make_shared(tmGL, newcoin::mtGET_LEDGER)); + if (!peer) + sendRequest(tmGL); + else + peer->sendPacket(boost::make_shared(tmGL, newcoin::mtGET_LEDGER)); } void PeerSet::sendRequest(const newcoin::TMGetLedger& tmGL) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 0d53af7b8..440be88ee 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -427,9 +427,10 @@ void LedgerConsensus::stateEstablish() updateOurPositions(); if (!mHaveCloseTimeConsensus) { - Log(lsINFO) << "No close time consensus"; + if (haveConsensus()) + Log(lsINFO) << "We have TX consensus but not CT consensus"; } - else if (haveConsensus()) + if (haveConsensus()) { Log(lsINFO) << "Converge cutoff"; mState = lcsFINISHED; @@ -455,11 +456,10 @@ void LedgerConsensus::timerEntry() if (!mHaveCorrectLCL) { checkLCL(); - Log(lsINFO) << "Checking for consensus ledger " << mPrevLedgerHash.GetHex(); Ledger::pointer consensus = theApp->getMasterLedger().getLedgerByHash(mPrevLedgerHash); if (consensus) { - Log(lsINFO) << "We have acquired the consensus ledger"; + Log(lsINFO) << "Acquired the consensus ledger " << mPrevLedgerHash.GetHex(); if (theApp->getMasterLedger().getClosedLedger()->getHash() != mPrevLedgerHash) theApp->getOPs().switchLastClosedLedger(consensus, true); mPreviousLedger = consensus; @@ -468,7 +468,8 @@ void LedgerConsensus::timerEntry() mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(), mPreviousLedger->getLedgerSeq() + 1); } - else Log(lsINFO) << "We still don't have it"; + else + Log(lsINFO) << "Need consensus ledger " << mPrevLedgerHash.GetHex(); } mCurrentMSeconds = (mCloseTime == 0) ? 0 : @@ -487,7 +488,6 @@ void LedgerConsensus::timerEntry() void LedgerConsensus::updateOurPositions() { - Log(lsINFO) << "Updating our positions"; bool changes = false; SHAMap::pointer ourPosition; std::vector addedTx, removedTx; @@ -566,8 +566,7 @@ void LedgerConsensus::updateOurPositions() mOurPosition->changePosition(newHash, closeTime); if (mProposing) propose(addedTx, removedTx); mapComplete(newHash, ourPosition, false); - Log(lsINFO) << "We change our position to " << newHash.GetHex(); - Log(lsINFO) << " Close time " << closeTime; + Log(lsINFO) << "Position change: CTime " << closeTime << ", tx " << newHash.GetHex(); } } diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index d84cfa3c5..ffd2eecbe 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -8,6 +8,8 @@ #include "utils.h" #include "Log.h" +// #define SNTP_DEBUG + static uint8_t SNTPQueryData[48] = { 0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 @@ -86,21 +88,24 @@ void SNTPClient::receivePacket(const boost::system::error_code& error, std::size if (!error) { boost::mutex::scoped_lock sl(mLock); +#ifdef SNTP_DEBUG Log(lsTRACE) << "SNTP: Packet from " << mReceiveEndpoint; +#endif std::map::iterator query = mQueries.find(mReceiveEndpoint); if (query == mQueries.end()) - Log(lsDEBUG) << "SNTP: Reply found without matching query"; + Log(lsDEBUG) << "SNTP: Reply from " << mReceiveEndpoint << " found without matching query"; else if (query->second.mReceivedReply) - Log(lsDEBUG) << "SNTP: Duplicate response to query"; + Log(lsDEBUG) << "SNTP: Duplicate response from " << mReceiveEndpoint; else { query->second.mReceivedReply = true; if (time(NULL) > (query->second.mLocalTimeSent + 1)) - Log(lsWARNING) << "SNTP: Late response"; + Log(lsWARNING) << "SNTP: Late response from " << mReceiveEndpoint; else if (bytes_xferd < 48) - Log(lsWARNING) << "SNTP: Short reply (" << bytes_xferd << ") " << mReceiveBuffer.size(); + Log(lsWARNING) << "SNTP: Short reply from " << mReceiveEndpoint + << " (" << bytes_xferd << ") " << mReceiveBuffer.size(); else if (reinterpret_cast(&mReceiveBuffer[0])[NTP_OFF_ORGTS_FRAC] != query->second.mQueryNonce) - Log(lsWARNING) << "SNTP: Reply had wrong nonce"; + Log(lsWARNING) << "SNTP: Reply from " << mReceiveEndpoint << "had wrong nonce"; else processReply(); } @@ -128,12 +133,12 @@ void SNTPClient::processReply() if ((info >> 30) == 3) { - Log(lsINFO) << "SNTP: Alarm condition"; + Log(lsINFO) << "SNTP: Alarm condition " << mReceiveEndpoint; return; } if ((stratum == 0) || (stratum > 14)) { - Log(lsINFO) << "SNTP: Unreasonable stratum"; + Log(lsINFO) << "SNTP: Unreasonable stratum (" << stratum << ") from " << mReceiveEndpoint; return; } @@ -161,7 +166,8 @@ void SNTPClient::processReply() if ((mOffset == -1) || (mOffset == 1)) // small corrections likely do more harm than good mOffset = 0; - Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset; + if (timev || mOffset) + Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset; } void SNTPClient::timerEntry(const boost::system::error_code& error) @@ -234,6 +240,8 @@ bool SNTPClient::doQuery() mResolver.async_resolve(query, boost::bind(&SNTPClient::resolveComplete, this, boost::asio::placeholders::error, boost::asio::placeholders::iterator)); +#ifdef SNTP_DEBUG Log(lsTRACE) << "SNTP: Resolve pending for " << best->first; +#endif return true; } From b4e63c30254769b4da03480a4e27acced7ab5fd1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 7 Aug 2012 04:11:20 -0700 Subject: [PATCH 50/61] Fix a few cases where we reset the acquire timer when we should not. --- src/LedgerAcquire.cpp | 19 +++++++++---------- src/LedgerAcquire.h | 4 ++-- src/LedgerConsensus.cpp | 6 +++--- src/LedgerConsensus.h | 6 +++--- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index bc065606e..95c4d287e 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -102,7 +102,7 @@ void LedgerAcquire::onTimer() setFailed(); done(); } - else trigger(Peer::pointer()); + else trigger(Peer::pointer(), true); } boost::weak_ptr LedgerAcquire::pmDowncast() @@ -140,7 +140,7 @@ void LedgerAcquire::addOnComplete(boost::function mLock.unlock(); } -void LedgerAcquire::trigger(Peer::pointer peer) +void LedgerAcquire::trigger(Peer::pointer peer, bool timer) { if (mAborted || mComplete || mFailed) return; @@ -159,10 +159,9 @@ void LedgerAcquire::trigger(Peer::pointer peer) tmGL.set_itype(newcoin::liBASE); *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); sendRequest(tmGL, peer); - return; // Cannot go on without base } - if (!mHaveTransactions) + if (mHaveBase && !mHaveTransactions) { #ifdef LA_DEBUG Log(lsTRACE) << "need tx"; @@ -206,7 +205,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) } } - if (!mHaveState) + if (mHaveBase && !mHaveState) { #ifdef LA_DEBUG Log(lsTRACE) << "need as"; @@ -252,7 +251,7 @@ void LedgerAcquire::trigger(Peer::pointer peer) if (mComplete || mFailed) done(); - else + else if (timer) resetTimer(); } @@ -460,7 +459,7 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi return false; if (packet.nodes_size() == 1) { - ledger->trigger(peer); + ledger->trigger(peer, false); return true; } if (!ledger->takeAsRootNode(strCopy(packet.nodes(1).nodedata()))) @@ -469,12 +468,12 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi } if (packet.nodes().size() == 2) { - ledger->trigger(peer); + ledger->trigger(peer, false); return true; } if (!ledger->takeTxRootNode(strCopy(packet.nodes(2).nodedata()))) Log(lsWARNING) << "Invcluded TXbase invalid"; - ledger->trigger(peer); + ledger->trigger(peer, false); return true; } @@ -498,7 +497,7 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi else ret = ledger->takeAsNode(nodeIDs, nodeData); if (ret) - ledger->trigger(peer); + ledger->trigger(peer, false); return ret; } diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index fbcac6c7e..1497ca41a 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -72,7 +72,7 @@ protected: void done(); void onTimer(); - void newPeer(Peer::pointer peer) { trigger(peer); } + void newPeer(Peer::pointer peer) { trigger(peer, false); } boost::weak_ptr pmDowncast(); @@ -92,7 +92,7 @@ public: bool takeTxRootNode(const std::vector& data); bool takeAsNode(const std::list& IDs, const std::list >& data); bool takeAsRootNode(const std::vector& data); - void trigger(Peer::pointer); + void trigger(Peer::pointer, bool timer); }; class LedgerAcquireMaster diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 440be88ee..2549ecfb8 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -36,7 +36,7 @@ boost::weak_ptr TransactionAcquire::pmDowncast() return boost::shared_polymorphic_downcast(shared_from_this()); } -void TransactionAcquire::trigger(Peer::pointer peer) +void TransactionAcquire::trigger(Peer::pointer peer, bool timer) { if (mComplete || mFailed) return; @@ -76,7 +76,7 @@ void TransactionAcquire::trigger(Peer::pointer peer) } if (mComplete || mFailed) done(); - else + else if (timer) resetTimer(); } @@ -110,7 +110,7 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, ++nodeIDit; ++nodeDatait; } - trigger(peer); + trigger(peer, false); progress(); return true; } diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index 205a75cd1..7e104a43b 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -27,11 +27,11 @@ protected: SHAMap::pointer mMap; bool mHaveRoot; - void onTimer() { trigger(Peer::pointer()); } - void newPeer(Peer::pointer peer) { trigger(peer); } + void onTimer() { trigger(Peer::pointer(), true); } + void newPeer(Peer::pointer peer) { trigger(peer, false); } void done(); - void trigger(Peer::pointer); + void trigger(Peer::pointer, bool timer); boost::weak_ptr pmDowncast(); public: From 8e89335e2bd5d001127905fde87051347057c373 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 7 Aug 2012 19:52:09 -0700 Subject: [PATCH 51/61] Cleanups to the sha map node format code. --- src/LedgerAcquire.cpp | 14 ++++++++------ src/LedgerConsensus.cpp | 2 +- src/Peer.cpp | 8 ++++---- src/SHAMap.cpp | 4 ++-- src/SHAMap.h | 19 +++++++++++-------- src/SHAMapNodes.cpp | 20 ++++++++++---------- src/SHAMapSync.cpp | 20 ++++++++++---------- 7 files changed, 46 insertions(+), 41 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 95c4d287e..525096872 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -311,8 +311,10 @@ bool LedgerAcquire::takeBase(const std::string& data) theApp->getHashedObjectStore().store(LEDGER, mLedger->getLedgerSeq(), s.peekData(), mHash); progress(); - if (!mLedger->getTransHash()) mHaveTransactions = true; - if (!mLedger->getAccountHash()) mHaveState = true; + if (!mLedger->getTransHash()) + mHaveTransactions = true; + if (!mLedger->getAccountHash()) + mHaveState = true; mLedger->setAcquiring(); return true; } @@ -328,7 +330,7 @@ bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, { if (nodeIDit->isRoot()) { - if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, STN_ARF_WIRE)) + if (!mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), *nodeDatait, snfWIRE)) return false; } else if (!mLedger->peekTransactionMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter)) @@ -363,7 +365,7 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, { if (nodeIDit->isRoot()) { - if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), *nodeDatait, STN_ARF_WIRE)) + if (!mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), *nodeDatait, snfWIRE)) return false; } else if (!mLedger->peekAccountStateMap()->addKnownNode(*nodeIDit, *nodeDatait, &tFilter)) @@ -387,13 +389,13 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, bool LedgerAcquire::takeAsRootNode(const std::vector& data) { if (!mHaveBase) return false; - return mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, STN_ARF_WIRE); + return mLedger->peekAccountStateMap()->addRootNode(mLedger->getAccountHash(), data, snfWIRE); } bool LedgerAcquire::takeTxRootNode(const std::vector& data) { if (!mHaveBase) return false; - return mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, STN_ARF_WIRE); + return mLedger->peekTransactionMap()->addRootNode(mLedger->getTransHash(), data, snfWIRE); } LedgerAcquire::pointer LedgerAcquireMaster::findCreate(const uint256& hash) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 2549ecfb8..7a194d8d7 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -101,7 +101,7 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, Log(lsWARNING) << "Got root TXS node, already have it"; return false; } - if (!mMap->addRootNode(getHash(), *nodeDatait, STN_ARF_WIRE)) + if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE)) return false; else mHaveRoot = true; } diff --git a/src/Peer.cpp b/src/Peer.cpp index 7c822dd22..991d18456 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -1007,13 +1007,13 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) reply.add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength()); if (packet.nodeids().size() != 0) - { + { // new-style root request Log(lsINFO) << "Ledger root w/map roots request"; SHAMap::pointer map = ledger->peekAccountStateMap(); if (map) - { + { // return account state root node if possible Serializer rootNode(768); - if (map->getRootNode(rootNode, STN_ARF_WIRE)) + if (map->getRootNode(rootNode, snfWIRE)) { reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength()); if (ledger->getTransHash().isNonZero()) @@ -1022,7 +1022,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) if (map) { rootNode.resize(0); - if (map->getRootNode(rootNode, STN_ARF_WIRE)) + if (map->getRootNode(rootNode, snfWIRE)) reply.add_nodes()->set_nodedata(rootNode.getDataPtr(), rootNode.getLength()); } } diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 738d1858e..1221ed336 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -641,7 +641,7 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui try { - SHAMapTreeNode::pointer ret = boost::make_shared(id, obj->getData(), mSeq, STN_ARF_PREFIXED); + SHAMapTreeNode::pointer ret = boost::make_shared(id, obj->getData(), mSeq, snfPREFIX); #ifdef DEBUG assert((ret->getNodeHash() == hash) && (id == *ret)); #endif @@ -672,7 +672,7 @@ int SHAMap::flushDirty(int maxNodes, HashedObjectType t, uint32 seq) while (it != dirtyNodes.end()) { s.erase(); - it->second->addRaw(s, STN_ARF_PREFIXED); + it->second->addRaw(s, snfPREFIX); theApp->getHashedObjectStore().store(t, seq, s.peekData(), s.getSHA512Half()); if (flushed++ >= maxNodes) return flushed; diff --git a/src/SHAMap.h b/src/SHAMap.h index 0130a624d..4bfd7999d 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -122,6 +122,12 @@ public: virtual void dump(); }; +enum SHANodeFormat +{ + snfPREFIX = 1, // Form that hashes to its official hash + snfWIRE = 2, // Compressed form used on the wire +}; + class SHAMapTreeNode : public SHAMapNode { friend class SHAMap; @@ -156,12 +162,9 @@ public: SHAMapTreeNode(const SHAMapTreeNode& node, uint32 seq); // copy node from older tree SHAMapTreeNode(const SHAMapNode& nodeID, SHAMapItem::pointer item, TNType type, uint32 seq); -#define STN_ARF_PREFIXED 1 -#define STN_ARF_WIRE 2 - // raw node functions - SHAMapTreeNode(const SHAMapNode& id, const std::vector& contents, uint32 seq, int format); - void addRaw(Serializer &, int format); + SHAMapTreeNode(const SHAMapNode& id, const std::vector& data, uint32 seq, SHANodeFormat format); + void addRaw(Serializer &, SHANodeFormat format); virtual bool isPopulated() const { return true; } @@ -325,9 +328,9 @@ public: SHAMapSyncFilter* filter); bool getNodeFat(const SHAMapNode& node, std::vector& nodeIDs, std::list >& rawNode, bool fatLeaves); - bool getRootNode(Serializer& s, int format); - bool addRootNode(const uint256& hash, const std::vector& rootNode, int format); - bool addRootNode(const std::vector& rootNode, int format); + bool getRootNode(Serializer& s, SHANodeFormat format); + bool addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format); + bool addRootNode(const std::vector& rootNode, SHANodeFormat format); bool addKnownNode(const SHAMapNode& nodeID, const std::vector& rawNode, SHAMapSyncFilter* filter); diff --git a/src/SHAMapNodes.cpp b/src/SHAMapNodes.cpp index 95fdcb1f9..da4ef4ebf 100644 --- a/src/SHAMapNodes.cpp +++ b/src/SHAMapNodes.cpp @@ -189,10 +189,10 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& node, SHAMapItem::pointer item, updateHash(); } -SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector& rawNode, uint32 seq, int format) - : SHAMapNode(id), mSeq(seq), mType(tnERROR), mFullBelow(false) +SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector& rawNode, uint32 seq, + SHANodeFormat format) : SHAMapNode(id), mSeq(seq), mType(tnERROR), mFullBelow(false) { - if (format == STN_ARF_WIRE) + if (format == snfWIRE) { Serializer s(rawNode); int type = s.removeLastByte(); @@ -256,7 +256,7 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vectoraddRaw(s); @@ -400,7 +400,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format) } else if (mType == tnTRANSACTION_NM) { - if (format == STN_ARF_PREFIXED) + if (format == snfPREFIX) { s.add32(sHP_TransactionID); mItem->addRaw(s); @@ -413,7 +413,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, int format) } else if (mType == tnTRANSACTION_MD) { - if (format == STN_ARF_PREFIXED) + if (format == snfPREFIX) { s.add32(sHP_TransactionNode); mItem->addRaw(s); diff --git a/src/SHAMapSync.cpp b/src/SHAMapSync.cpp index ab230c79f..25c2d019a 100644 --- a/src/SHAMapSync.cpp +++ b/src/SHAMapSync.cpp @@ -58,7 +58,7 @@ void SHAMap::getMissingNodes(std::vector& nodeIDs, std::vector nodeData; if (filter->haveNode(childID, childHash, nodeData)) { - d = boost::make_shared(childID, nodeData, mSeq, STN_ARF_PREFIXED); + d = boost::make_shared(childID, nodeData, mSeq, snfPREFIX); if (childHash != d->getNodeHash()) { Log(lsERROR) << "Wrong hash from cached object"; @@ -99,7 +99,7 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector& nodeI nodeIDs.push_back(*node); Serializer s; - node->addRaw(s, STN_ARF_WIRE); + node->addRaw(s, snfWIRE); rawNodes.push_back(s.peekData()); if (node->isRoot() || node->isLeaf()) // don't get a fat root, can't get a fat leaf @@ -114,7 +114,7 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector& nodeI { nodeIDs.push_back(*nextNode); Serializer s; - nextNode->addRaw(s, STN_ARF_WIRE); + nextNode->addRaw(s, snfWIRE); rawNodes.push_back(s.peekData()); } } @@ -122,14 +122,14 @@ bool SHAMap::getNodeFat(const SHAMapNode& wanted, std::vector& nodeI return true; } -bool SHAMap::getRootNode(Serializer& s, int format) +bool SHAMap::getRootNode(Serializer& s, SHANodeFormat format) { boost::recursive_mutex::scoped_lock sl(mLock); root->addRaw(s, format); return true; } -bool SHAMap::addRootNode(const std::vector& rootNode, int format) +bool SHAMap::addRootNode(const std::vector& rootNode, SHANodeFormat format) { boost::recursive_mutex::scoped_lock sl(mLock); @@ -160,7 +160,7 @@ bool SHAMap::addRootNode(const std::vector& rootNode, int format) return true; } -bool SHAMap::addRootNode(const uint256& hash, const std::vector& rootNode, int format) +bool SHAMap::addRootNode(const uint256& hash, const std::vector& rootNode, SHANodeFormat format) { boost::recursive_mutex::scoped_lock sl(mLock); @@ -236,14 +236,14 @@ bool SHAMap::addKnownNode(const SHAMapNode& node, const std::vectorgetChildHash(branch); if (!hash) return false; - SHAMapTreeNode::pointer newNode = boost::make_shared(node, rawNode, mSeq, STN_ARF_WIRE); + SHAMapTreeNode::pointer newNode = boost::make_shared(node, rawNode, mSeq, snfWIRE); if (hash != newNode->getNodeHash()) // these aren't the droids we're looking for return false; if (filter) { Serializer s; - newNode->addRaw(s, STN_ARF_PREFIXED); + newNode->addRaw(s, snfPREFIX); filter->gotNode(node, hash, s.peekData(), newNode->isLeaf()); } @@ -399,7 +399,7 @@ std::list > SHAMap::getTrustedPath(const uint256& ind Serializer s; while (!stack.empty()) { - stack.top()->addRaw(s, STN_ARF_WIRE); + stack.top()->addRaw(s, snfWIRE); path.push_back(s.getData()); s.erase(); stack.pop(); @@ -454,7 +454,7 @@ BOOST_AUTO_TEST_CASE( SHAMapSync_test ) Log(lsFATAL) << "Didn't get root node " << gotNodes.size(); BOOST_FAIL("NodeSize"); } - if (!destination.addRootNode(*gotNodes.begin(), STN_ARF_WIRE)) + if (!destination.addRootNode(*gotNodes.begin(), snfWIRE)) { Log(lsFATAL) << "AddRootNode fails"; BOOST_FAIL("AddRootNode"); From 9fc4f469b817063f7d61e432c2d1ea6ae05f4628 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 8 Aug 2012 01:35:34 -0700 Subject: [PATCH 52/61] Add STAmount::isNonZero --- src/SerializedTypes.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 9a1c34b3f..cb719d2c1 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -290,6 +290,7 @@ public: bool isNative() const { return mIsNative; } bool isZero() const { return mValue == 0; } + bool isNonZero() const { return mValue != 0; } bool isNegative() const { return mIsNegative && !isZero(); } bool isPositive() const { return !mIsNegative && !isZero(); } bool isGEZero() const { return !mIsNegative; } From 3a4762c60985da6f5492ce562a811da0991c041c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 8 Aug 2012 01:35:44 -0700 Subject: [PATCH 53/61] Don't try to calculate close time offsets if a ledger closed due to being idle. --- src/LedgerConsensus.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 7a194d8d7..1a9eda60d 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -937,7 +937,8 @@ void LedgerConsensus::accept(SHAMap::pointer set) mState = lcsACCEPTED; sl.unlock(); - { + if (mValidating && mOurPosition->getCurrentHash().isNonZero()) + { // see how close our close time is to other node's close time reports Log(lsINFO) << "We closed at " << boost::lexical_cast(mCloseTime); uint64 closeTotal = mCloseTime; int closeCount = 1; From 7fd327ee38ea197c74b3506c759b0c51ead44172 Mon Sep 17 00:00:00 2001 From: jed Date: Wed, 8 Aug 2012 10:22:54 -0700 Subject: [PATCH 54/61] compile on windows --- newcoin.vcxproj | 5 +---- newcoin.vcxproj.filters | 7 +++---- src/LedgerAcquire.cpp | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/newcoin.vcxproj b/newcoin.vcxproj index c053c90f5..d6c37b34c 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -146,6 +146,7 @@ + @@ -248,17 +249,13 @@ Designer - - - Document ..\protoc-2.4.1-win32\protoc -I=..\newcoin\src --cpp_out=..\newcoin\obj\src ..\newcoin\src\newcoin.proto obj\src\newcoin.pb.h - diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index b8c3acee1..2116e8937 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -273,6 +273,9 @@ Source Files + + Source Files + @@ -506,16 +509,12 @@ - html - - - diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 525096872..2407616bd 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -129,7 +129,7 @@ void LedgerAcquire::done() if (mLedger) theApp->getMasterLedger().storeLedger(mLedger); - for (int i = 0; i < triggers.size(); ++i) + for (unsigned int i = 0; i < triggers.size(); ++i) triggers[i](shared_from_this()); } From 9991c9532feb772b32224c246b87727f27cb6588 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 8 Aug 2012 13:56:31 -0700 Subject: [PATCH 55/61] Not sure why I put this in, but it's wrong. --- src/LedgerTiming.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index e3ea06164..c28fc80e0 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -101,7 +101,6 @@ bool ContinuousLedgerTiming::haveConsensus( int ContinuousLedgerTiming::getNextLedgerTimeResolution(int previousResolution, bool previousAgree, int ledgerSeq) { assert(ledgerSeq); - assert(previousAgree); // TEMPORARY if ((!previousAgree) && ((ledgerSeq % LEDGER_RES_DECREASE) == 0)) { // reduce resolution int i = 1; From be17a3866ff8abfa070cbed1fd755c75a8edaa33 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 8 Aug 2012 14:22:03 -0700 Subject: [PATCH 56/61] Fix the race condition bug Jed reported. A time jump on startup could cause an apparently overly-long (or even negative) ledger interval. The fix is to start up time synch earlier and to tolerate slight negative ledger intervals. --- src/Application.cpp | 10 ++++++++-- src/Application.h | 2 +- src/LedgerTiming.cpp | 10 ++-------- src/SNTPClient.cpp | 2 ++ 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 89fe9d2dd..daac98dd5 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -38,7 +38,7 @@ DatabaseCon::~DatabaseCon() Application::Application() : mUNL(mIOService), mNetOps(mIOService, &mMasterLedger), mTempNodeCache(16384, 90), mHashedObjectStore(16384, 300), - mSNTPClient(mIOService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), + mSNTPClient(mAuxService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL) { @@ -51,6 +51,7 @@ extern int RpcDBCount, TxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount void Application::stop() { + mAuxService.stop(); mIOService.stop(); mHashedObjectStore.bulkWrite(); mValidations.flush(); @@ -69,6 +70,11 @@ void Application::run() if (!theConfig.DEBUG_LOGFILE.empty()) Log::setLogFile(theConfig.DEBUG_LOGFILE); + mSNTPClient.init(theConfig.SNTP_SERVERS); + + boost::thread auxThread(boost::bind(&boost::asio::io_service::run, &mAuxService)); + auxThread.detach(); + // // Construct databases. // @@ -91,6 +97,7 @@ void Application::run() // getUNL().nodeBootstrap(); + // // Allow peer connections. // @@ -147,7 +154,6 @@ void Application::run() mNetOps.setLastCloseNetTime(secondLedger->getCloseTimeNC()); } - mSNTPClient.init(theConfig.SNTP_SERVERS); mNetOps.setStateTimer(); diff --git a/src/Application.h b/src/Application.h index 9efbc89fc..79ffb8cf3 100644 --- a/src/Application.h +++ b/src/Application.h @@ -39,7 +39,7 @@ public: class Application { - boost::asio::io_service mIOService; + boost::asio::io_service mIOService, mAuxService; Wallet mWallet; UniqueNodeList mUNL; diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index c28fc80e0..0585abd47 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -19,8 +19,8 @@ int ContinuousLedgerTiming::shouldClose( int previousMSeconds, // seconds the previous ledger took to reach consensus int currentMSeconds) // seconds since the previous ledger closed { - assert((previousMSeconds > 0) && (previousMSeconds < 600000)); - assert((currentMSeconds >= 0) && (currentMSeconds < 600000)); + assert((previousMSeconds > -1000) && (previousMSeconds < 600000)); + assert((currentMSeconds >= -1000) && (currentMSeconds < 600000)); #if 0 Log(lsTRACE) << boost::str(boost::format("CLC::shouldClose Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") % @@ -44,12 +44,6 @@ int ContinuousLedgerTiming::shouldClose( return LEDGER_IDLE_INTERVAL * 1000; // normal idle } - if (previousMSeconds == (1000 * LEDGER_IDLE_INTERVAL)) // coming out of idle, close now - { - Log(lsTRACE) << "leaving idle, close now"; - return currentMSeconds; - } - Log(lsTRACE) << "close now"; return currentMSeconds; // this ledger should close now } diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index ffd2eecbe..728e6f412 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -166,7 +166,9 @@ void SNTPClient::processReply() if ((mOffset == -1) || (mOffset == 1)) // small corrections likely do more harm than good mOffset = 0; +#ifndef SNTP_DEBUG if (timev || mOffset) +#endif Log(lsTRACE) << "SNTP: Offset is " << timev << ", new system offset is " << mOffset; } From 4e99d8d7bdb7c2acf5be7d4b0ce012df27a50dc4 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 8 Aug 2012 23:08:24 -0700 Subject: [PATCH 57/61] Cleanups. --- src/SNTPClient.cpp | 16 ++++++++-------- src/SNTPClient.h | 4 ---- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index 728e6f412..e5cafd46e 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -10,14 +10,15 @@ // #define SNTP_DEBUG -static uint8_t SNTPQueryData[48] = { - 0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -}; +static uint8_t SNTPQueryData[48] = +{ 0x1B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; // NTP query frequency - 5 minutes #define NTP_QUERY_FREQUENCY (5 * 60) +// NTP minimum interval to query same servers - 3 minutes +#define NTP_MIN_QUERY (3 * 60) + // NTP sample window (should be odd) #define NTP_SAMPLE_WINDOW 9 @@ -39,8 +40,7 @@ static uint8_t SNTPQueryData[48] = { #define NTP_OFF_XMITTS_FRAC 11 -SNTPClient::SNTPClient(boost::asio::io_service& service) : - mIOService(service), mSocket(service), mTimer(service), mResolver(service), +SNTPClient::SNTPClient(boost::asio::io_service& service) : mSocket(service), mTimer(service), mResolver(service), mOffset(0), mLastOffsetUpdate((time_t) -1), mReceiveBuffer(256) { mSocket.open(boost::asio::ip::udp::v4()); @@ -67,7 +67,7 @@ void SNTPClient::resolveComplete(const boost::system::error_code& error, boost:: SNTPQuery& query = mQueries[*sel]; time_t now = time(NULL); if ((query.mLocalTimeSent == now) || ((query.mLocalTimeSent + 1) == now)) - { + { // This can happen if the same IP address is reached through multiple names Log(lsTRACE) << "SNTP: Redundant query suppressed"; return; } @@ -231,7 +231,7 @@ bool SNTPClient::doQuery() return false; } time_t now = time(NULL); - if ((best->second == now) || (best->second == (now - 1))) + if ((best->second != (time_t) -1) && ((best->second + NTP_MIN_QUERY) >= now)) { Log(lsTRACE) << "SNTP: All servers recently queried"; return false; diff --git a/src/SNTPClient.h b/src/SNTPClient.h index ea7b0e7c8..51adf3ceb 100644 --- a/src/SNTPClient.h +++ b/src/SNTPClient.h @@ -21,14 +21,10 @@ public: class SNTPClient { -public: - typedef boost::shared_ptr pointer; - protected: std::map mQueries; boost::mutex mLock; - boost::asio::io_service& mIOService; boost::asio::ip::udp::socket mSocket; boost::asio::deadline_timer mTimer; boost::asio::ip::udp::resolver mResolver; From 1aa15c62e10951e15c3ff9bdb5911a5874eed5be Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 9 Aug 2012 16:03:00 -0700 Subject: [PATCH 58/61] Implement STAmount::getRate. --- src/Amount.cpp | 32 +++++++++++++++++++++++--------- src/SerializedTypes.h | 1 + 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 7d95eeffc..4ada7054c 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -446,7 +446,7 @@ bool STAmount::operator==(const STAmount& a) const bool STAmount::operator!=(const STAmount& a) const { - return (mOffset != a.mOffset) || (mValue != a.mValue) || (mIsNegative!= a.mIsNegative) || !isComparable(a); + return (mOffset != a.mOffset) || (mValue != a.mValue) || (mIsNegative != a.mIsNegative) || !isComparable(a); } bool STAmount::operator<(const STAmount& a) const @@ -762,6 +762,14 @@ uint64 STAmount::getRate(const STAmount& offerOut, const STAmount& offerIn) return (ret << (64 - 8)) | r.getMantissa(); } +STAmount STAmount::setRate(uint64 rate, const uint160& currencyOut) +{ + uint64 mantissa = rate & ~(255ull << (64 - 8)); + int exponent = static_cast(rate >> (64 - 8)) - 100; + + return STAmount(currencyOut, mantissa, exponent); +} + // Taker gets all taker can pay for with saTakerFunds, limited by saOfferPays and saOfferFunds. // --> saOfferFunds: Limit for saOfferPays // --> saTakerFunds: Limit for saOfferGets : How much taker really wants. : Driver @@ -1105,6 +1113,12 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test ) if (STAmount::divide(STAmount(currency, 60) , STAmount(currency, 3), uint160()).getText() != "20") BOOST_FAIL("STAmount divide fail"); + STAmount a1(currency, 60), a2 (currency, 10, -1); + if(STAmount::divide(a2, a1, currency) != STAmount::setRate(STAmount::getRate(a1, a2), currency)) + BOOST_FAIL("STAmount setRate(getRate) fail"); + if(STAmount::divide(a1, a2, currency) != STAmount::setRate(STAmount::getRate(a2, a1), currency)) + BOOST_FAIL("STAmount setRate(getRate) fail"); + BOOST_TEST_MESSAGE("Amount CC Complete"); } @@ -1115,21 +1129,21 @@ BOOST_AUTO_TEST_CASE( CurrencyMulDivTests ) uint160 c(1); if (STAmount::getRate(STAmount(1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(c, 1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(c, 10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(c, 1), STAmount(10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(c, 10), STAmount(1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(1), STAmount(c, 10)) != (((100ul-14)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); if (STAmount::getRate(STAmount(10), STAmount(c, 1)) != (((100ul-16)<<(64-8))|1000000000000000ul)) - BOOST_FAIL("STAmount getrate fail"); + BOOST_FAIL("STAmount getRate fail"); } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index cb719d2c1..0db565839 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -343,6 +343,7 @@ public: // Someone is offering X for Y, what is the rate? static uint64 getRate(const STAmount& offerOut, const STAmount& offerIn); + static STAmount setRate(uint64 rate, const uint160& currencyOut); // Someone is offering X for Y, I try to pay Z, how much do I get? // And what's left of the offer? And how much do I actually pay? From d477172f65514a21f8e896e095657b718d6ea0b2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 9 Aug 2012 19:20:53 -0700 Subject: [PATCH 59/61] Cleanups and whitespace fixes. --- src/Amount.cpp | 4 +-- src/LedgerConsensus.cpp | 17 +++++------ src/PubKeyCache.cpp | 1 - src/SHAMap.cpp | 66 ++++++++++++++++++++++------------------- src/SHAMapNodes.cpp | 36 +++++++++++----------- src/SNTPClient.cpp | 2 +- src/SerializedTypes.h | 2 +- src/TransactionMeta.cpp | 2 +- 8 files changed, 66 insertions(+), 64 deletions(-) diff --git a/src/Amount.cpp b/src/Amount.cpp index 4ada7054c..1e2db3124 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -1114,9 +1114,9 @@ BOOST_AUTO_TEST_CASE( CustomCurrency_test ) BOOST_FAIL("STAmount divide fail"); STAmount a1(currency, 60), a2 (currency, 10, -1); - if(STAmount::divide(a2, a1, currency) != STAmount::setRate(STAmount::getRate(a1, a2), currency)) + if (STAmount::divide(a2, a1, currency) != STAmount::setRate(STAmount::getRate(a1, a2), currency)) BOOST_FAIL("STAmount setRate(getRate) fail"); - if(STAmount::divide(a1, a2, currency) != STAmount::setRate(STAmount::getRate(a2, a1), currency)) + if (STAmount::divide(a1, a2, currency) != STAmount::setRate(STAmount::getRate(a2, a1), currency)) BOOST_FAIL("STAmount setRate(getRate) fail"); BOOST_TEST_MESSAGE("Amount CC Complete"); diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 1a9eda60d..b9bd54345 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -146,7 +146,7 @@ void LCTransaction::setVote(const uint160& peer, bool votesYes) ++mYays; res.first->second = true; } - else if(!votesYes && res.first->second) + else if (!votesYes && res.first->second) { // changes vote to no Log(lsTRACE) << "Peer " << peer.GetHex() << " now votes NO on " << mTransactionID.GetHex(); ++mNays; @@ -270,7 +270,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger) // if any peers have taken a contrary position, process disputes boost::unordered_set found; - for(boost::unordered_map::iterator it = mPeerPositions.begin(), + for (boost::unordered_map::iterator it = mPeerPositions.begin(), end = mPeerPositions.end(); it != end; ++it) { uint256 set = it->second->getCurrentHash(); @@ -296,14 +296,14 @@ void LedgerConsensus::createDisputes(SHAMap::pointer m1, SHAMap::pointer m2) { SHAMap::SHAMapDiff differences; m1->compare(m2, differences, 16384); - for(SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos) + for (SHAMap::SHAMapDiff::iterator pos = differences.begin(), end = differences.end(); pos != end; ++pos) { // create disputed transactions (from the ledger that has them) if (pos->second.first) { assert(!pos->second.second); addDisputedTransaction(pos->first, pos->second.first->peekData()); } - else if(pos->second.second) + else if (pos->second.second) { assert(!pos->second.first); addDisputedTransaction(pos->first, pos->second.second->peekData()); @@ -371,7 +371,7 @@ void LedgerConsensus::adjustCount(SHAMap::pointer map, const std::vectorhasItem(it->second->getTransactionID()); - for(std::vector::const_iterator pit = peers.begin(), pend = peers.end(); pit != pend; ++pit) + for (std::vector::const_iterator pit = peers.begin(), pend = peers.end(); pit != pend; ++pit) it->second->setVote(*pit, setHas); } } @@ -492,7 +492,7 @@ void LedgerConsensus::updateOurPositions() SHAMap::pointer ourPosition; std::vector addedTx, removedTx; - for(boost::unordered_map::iterator it = mDisputes.begin(), + for (boost::unordered_map::iterator it = mDisputes.begin(), end = mDisputes.end(); it != end; ++it) { if (it->second->updatePosition(mClosePercent, mProposing)) @@ -942,7 +942,7 @@ void LedgerConsensus::accept(SHAMap::pointer set) Log(lsINFO) << "We closed at " << boost::lexical_cast(mCloseTime); uint64 closeTotal = mCloseTime; int closeCount = 1; - for(std::map::iterator it = mCloseTimes.begin(), end = mCloseTimes.end(); it != end; ++it) + for (std::map::iterator it = mCloseTimes.begin(), end = mCloseTimes.end(); it != end; ++it) { Log(lsINFO) << boost::lexical_cast(it->second) << " time votes for " << boost::lexical_cast(it->first); @@ -956,9 +956,8 @@ void LedgerConsensus::accept(SHAMap::pointer set) } #ifdef DEBUG - Json::StyledStreamWriter ssw; - if (1) { + Json::StyledStreamWriter ssw; Log(lsTRACE) << "newLCL"; Json::Value p; newLCL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE); diff --git a/src/PubKeyCache.cpp b/src/PubKeyCache.cpp index 011996954..f6a4096d3 100644 --- a/src/PubKeyCache.cpp +++ b/src/PubKeyCache.cpp @@ -6,7 +6,6 @@ CKey::pointer PubKeyCache::locate(const NewcoinAddress& id) { - if(1) { // is it in cache boost::mutex::scoped_lock sl(mLock); std::map::iterator it(mCache.find(id)); diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 1221ed336..b360908f2 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -262,7 +262,7 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node) break; } if (!foundNode) return SHAMapItem::pointer(); - } while (1); + } while (true); } SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node) @@ -284,7 +284,7 @@ SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node) break; } if (!foundNode) return SHAMapItem::pointer(); - } while (1); + } while (true); } SHAMapItem::pointer SHAMap::onlyBelow(SHAMapTreeNode* node) @@ -359,22 +359,23 @@ SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id) boost::recursive_mutex::scoped_lock sl(mLock); std::stack stack = getStack(id, true, false); - while(!stack.empty()) + while (!stack.empty()) { SHAMapTreeNode::pointer node = stack.top(); stack.pop(); - if(node->isLeaf()) + if (node->isLeaf()) { - if(node->peekItem()->getTag()>id) + if (node->peekItem()->getTag() > id) return node->peekItem(); } - else for(int i = node->selectBranch(id) + 1; i < 16; ++i) - if(!node->isEmptyBranch(i)) + else for (int i = node->selectBranch(id) + 1; i < 16; ++i) + if (!node->isEmptyBranch(i)) { node = getNode(node->getChildNodeID(i), node->getChildHash(i), false); SHAMapItem::pointer item = firstBelow(node.get()); - if (!item) throw std::runtime_error("missing node"); + if (!item) + throw std::runtime_error("missing node"); return item; } } @@ -392,17 +393,18 @@ SHAMapItem::pointer SHAMap::peekPrevItem(const uint256& id) SHAMapTreeNode::pointer node = stack.top(); stack.pop(); - if(node->isLeaf()) + if (node->isLeaf()) { - if(node->peekItem()->getTag()peekItem()->getTag() < id) return node->peekItem(); } - else for(int i = node->selectBranch(id) - 1; i >= 0; --i) - if(!node->isEmptyBranch(i)) + else for (int i = node->selectBranch(id) - 1; i >= 0; --i) + if (!node->isEmptyBranch(i)) { node = getNode(node->getChildNodeID(i), node->getChildHash(i), false); SHAMapItem::pointer item = firstBelow(node.get()); - if (!item) throw std::runtime_error("missing node"); + if (!item) + throw std::runtime_error("missing node"); return item; } } @@ -414,7 +416,8 @@ SHAMapItem::pointer SHAMap::peekItem(const uint256& id) { boost::recursive_mutex::scoped_lock sl(mLock); SHAMapTreeNode* leaf = walkToPointer(id); - if (!leaf) return SHAMapItem::pointer(); + if (!leaf) + return SHAMapItem::pointer(); return leaf->peekItem(); } @@ -432,7 +435,7 @@ bool SHAMap::delItem(const uint256& id) assert(mState != Immutable); std::stack stack = getStack(id, true, false); - if(stack.empty()) + if (stack.empty()) throw std::runtime_error("missing node"); SHAMapTreeNode::pointer leaf=stack.top(); @@ -442,7 +445,7 @@ bool SHAMap::delItem(const uint256& id) SHAMapTreeNode::TNType type=leaf->getType(); returnNode(leaf, true); - if(mTNByID.erase(*leaf)==0) + if (mTNByID.erase(*leaf) == 0) assert(false); uint256 prevHash; @@ -460,8 +463,8 @@ bool SHAMap::delItem(const uint256& id) } if (!node->isRoot()) { // we may have made this a node with 1 or 0 children - int bc=node->getBranchCount(); - if(bc==0) + int bc = node->getBranchCount(); + if (bc == 0) { #ifdef DEBUG std::cerr << "delItem makes empty node" << std::endl; @@ -470,10 +473,10 @@ bool SHAMap::delItem(const uint256& id) if (!mTNByID.erase(*node)) assert(false); } - else if(bc==1) + else if (bc == 1) { // pull up on the thread SHAMapItem::pointer item = onlyBelow(node.get()); - if(item) + if (item) { eraseChildren(node); #ifdef ST_DEBUG @@ -521,7 +524,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM uint256 prevHash; returnNode(node, true); - if(node->isInner()) + if (node->isInner()) { // easy case, we end on an inner node #ifdef ST_DEBUG std::cerr << "aGI inner " << node->getString() << std::endl; @@ -530,7 +533,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM assert(node->isEmptyBranch(branch)); SHAMapTreeNode::pointer newNode = boost::make_shared(node->getChildNodeID(branch), item, type, mSeq); - if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) + if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) { std::cerr << "Node: " << node->getString() << std::endl; std::cerr << "NewNode: " << newNode->getString() << std::endl; @@ -562,7 +565,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM SHAMapTreeNode::pointer newNode = boost::make_shared(mSeq, node->getChildNodeID(b1)); newNode->makeInner(); - if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) + if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) assert(false); stack.push(node); node = newNode; @@ -579,7 +582,7 @@ bool SHAMap::addGiveItem(SHAMapItem::pointer item, bool isTransaction, bool hasM newNode = boost::make_shared(node->getChildNodeID(b2), otherItem, type, mSeq); assert(newNode->isValid() && newNode->isLeaf()); - if(!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) + if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second) assert(false); node->setChildHash(b2, newNode->getNodeHash()); } @@ -635,7 +638,7 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui throw SHAMapMissingNode(id, hash); HashedObject::pointer obj(theApp->getHashedObjectStore().retrieve(hash)); - if(!obj) + if (!obj) throw SHAMapMissingNode(id, hash); assert(Serializer::getSHA512Half(obj->getData()) == hash); @@ -665,7 +668,7 @@ int SHAMap::flushDirty(int maxNodes, HashedObjectType t, uint32 seq) int flushed = 0; Serializer s; - if(mDirtyNodes) + if (mDirtyNodes) { boost::unordered_map& dirtyNodes = *mDirtyNodes; boost::unordered_map::iterator it = dirtyNodes.begin(); @@ -714,10 +717,10 @@ void SHAMap::dump(bool hash) #if 0 std::cerr << "SHAMap::dump" << std::endl; SHAMapItem::pointer i=peekFirstItem(); - while(i) + while (i) { std::cerr << "Item: id=" << i->getTag().GetHex() << std::endl; - i=peekNextItem(i->getTag()); + i = peekNextItem(i->getTag()); } std::cerr << "SHAMap::dump done" << std::endl; #endif @@ -728,7 +731,8 @@ void SHAMap::dump(bool hash) it != mTNByID.end(); ++it) { std::cerr << it->second->getString() << std::endl; - if(hash) std::cerr << " " << it->second->getNodeHash().GetHex() << std::endl; + if (hash) + std::cerr << " " << it->second->getNodeHash().GetHex() << std::endl; } } @@ -756,8 +760,8 @@ BOOST_AUTO_TEST_CASE( SHAMap_test ) SHAMap sMap; SHAMapItem i1(h1, IntToVUC(1)), i2(h2, IntToVUC(2)), i3(h3, IntToVUC(3)), i4(h4, IntToVUC(4)), i5(h5, IntToVUC(5)); - if(!sMap.addItem(i2, true, false)) BOOST_FAIL("no add"); - if(!sMap.addItem(i1, true, false)) BOOST_FAIL("no add"); + if (!sMap.addItem(i2, true, false)) BOOST_FAIL("no add"); + if (!sMap.addItem(i1, true, false)) BOOST_FAIL("no add"); SHAMapItem::pointer i; diff --git a/src/SHAMapNodes.cpp b/src/SHAMapNodes.cpp index da4ef4ebf..689745995 100644 --- a/src/SHAMapNodes.cpp +++ b/src/SHAMapNodes.cpp @@ -27,50 +27,50 @@ uint256 SHAMapNode::smMasks[65]; bool SHAMapNode::operator<(const SHAMapNode &s) const { - if(s.mDepthmDepth) return false; - return mNodeID mDepth) return false; + return mNodeID < s.mNodeID; } bool SHAMapNode::operator>(const SHAMapNode &s) const { - if(s.mDepthmDepth) return true; - return mNodeID>s.mNodeID; + if (s.mDepth < mDepth) return false; + if (s.mDepth > mDepth) return true; + return mNodeID > s.mNodeID; } bool SHAMapNode::operator<=(const SHAMapNode &s) const { - if(s.mDepthmDepth) return false; - return mNodeID<=s.mNodeID; + if (s.mDepth < mDepth) return true; + if (s.mDepth > mDepth) return false; + return mNodeID <= s.mNodeID; } bool SHAMapNode::operator>=(const SHAMapNode &s) const { - if(s.mDepthmDepth) return true; - return mNodeID>=s.mNodeID; + if (s.mDepth < mDepth) return false; + if (s.mDepth > mDepth) return true; + return mNodeID >= s.mNodeID; } bool SHAMapNode::operator==(const SHAMapNode &s) const { - return (s.mDepth==mDepth) && (s.mNodeID==mNodeID); + return (s.mDepth == mDepth) && (s.mNodeID == mNodeID); } bool SHAMapNode::operator!=(const SHAMapNode &s) const { - return (s.mDepth!=mDepth) || (s.mNodeID!=mNodeID); + return (s.mDepth != mDepth) || (s.mNodeID != mNodeID); } bool SHAMapNode::operator==(const uint256 &s) const { - return s==mNodeID; + return s == mNodeID; } bool SHAMapNode::operator!=(const uint256 &s) const { - return s!=mNodeID; + return s != mNodeID; } static bool j = SHAMapNode::ClassInit(); @@ -78,7 +78,7 @@ static bool j = SHAMapNode::ClassInit(); bool SHAMapNode::ClassInit() { // set up the depth masks uint256 selector; - for(int i = 0; i < 64; i += 2) + for (int i = 0; i < 64; i += 2) { smMasks[i] = selector; *(selector.begin() + (i / 2)) = 0xF0; @@ -476,7 +476,7 @@ std::string SHAMapTreeNode::getString() const ret += ")"; if (isInner()) { - for(int i = 0; i < 16; ++i) + for (int i = 0; i < 16; ++i) if (!isEmptyBranch(i)) { ret += "\nb"; diff --git a/src/SNTPClient.cpp b/src/SNTPClient.cpp index e5cafd46e..444b7b6c7 100644 --- a/src/SNTPClient.cpp +++ b/src/SNTPClient.cpp @@ -204,7 +204,7 @@ void SNTPClient::init(const std::vector& servers) void SNTPClient::queryAll() { - while(doQuery()) + while (doQuery()) nothing(); } diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 0db565839..6372ec66c 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -655,7 +655,7 @@ public: int getLength() const; SerializedTypeID getSType() const { return STI_TL; } std::string getText() const; - void add(Serializer& s) const { if(s.addTaggedList(value)<0) throw(0); } + void add(Serializer& s) const { if (s.addTaggedList(value) < 0) throw(0); } const std::vector& peekValue() const { return value; } std::vector& peekValue() { return value; } diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp index 0476b9420..0ab28f391 100644 --- a/src/TransactionMeta.cpp +++ b/src/TransactionMeta.cpp @@ -205,7 +205,7 @@ TransactionMetaSet::TransactionMetaSet(uint32 ledger, const std::vector Date: Thu, 9 Aug 2012 19:21:08 -0700 Subject: [PATCH 60/61] More LedgerEntrySet code. Retrieve as Json. Finalize before serializing. --- src/LedgerEntrySet.cpp | 60 ++++++++++++++++++++++++++++++++++++++++++ src/LedgerEntrySet.h | 3 +++ 2 files changed, 63 insertions(+) diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp index fb4903ff4..cf2e0234b 100644 --- a/src/LedgerEntrySet.cpp +++ b/src/LedgerEntrySet.cpp @@ -189,4 +189,64 @@ void LedgerEntrySet::entryDelete(SLE::pointer& sle, bool unfunded) } } +Json::Value LedgerEntrySet::getJson(int) const +{ + Json::Value ret(Json::objectValue); + + Json::Value nodes(Json::arrayValue); + for (boost::unordered_map::const_iterator it = mEntries.begin(), + end = mEntries.end(); it != end; ++it) + { + Json::Value entry(Json::objectValue); + entry["node"] = it->first.GetHex(); + switch (it->second.mEntry->getType()) + { + case ltINVALID: entry["type"] = "invalid"; break; + case ltACCOUNT_ROOT: entry["type"] = "acccount_root"; break; + case ltDIR_NODE: entry["type"] = "dir_node"; break; + case ltGENERATOR_MAP: entry["type"] = "generator_map"; break; + case ltRIPPLE_STATE: entry["type"] = "ripple_state"; break; + case ltNICKNAME: entry["type"] = "nickname"; break; + case ltOFFER: entry["type"] = "offer"; break; + default: assert(false); + } + switch (it->second.mAction) + { + case taaCACHED: entry["action"] = "cache"; break; + case taaMODIFY: entry["action"] = "modify"; break; + case taaDELETE: entry["action"] = "delete"; break; + case taaCREATE: entry["action"] = "create"; break; + default: assert(false); + } + nodes.append(entry); + } + ret["nodes" ] = nodes; + + return ret; +} + +void LedgerEntrySet::addRawMeta(Serializer& s) +{ + for (boost::unordered_map::const_iterator it = mEntries.begin(), + end = mEntries.end(); it != end; ++it) + { + switch (it->second.mAction) + { + case taaMODIFY: + // WRITEME + break; + case taaDELETE: + // WRITEME + break; + case taaCREATE: + // WRITEME + break; + default: + // ignore these + break; + } + } + mSet.addRaw(s); +} + // vim:ts=4 diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h index e600060f3..11843f060 100644 --- a/src/LedgerEntrySet.h +++ b/src/LedgerEntrySet.h @@ -58,6 +58,9 @@ public: void entryDelete(SLE::pointer&, bool unfunded); void entryModify(SLE::pointer&); // This entry will be modified + Json::Value getJson(int) const; + void addRawMeta(Serializer&); + // iterator functions bool isEmpty() const { return mEntries.empty(); } boost::unordered_map::const_iterator begin() const { return mEntries.begin(); } From 5b431ea4f629a702a0bb145f023c043357fc24b5 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 10 Aug 2012 10:51:35 -0700 Subject: [PATCH 61/61] Fix the bug Jed reported where our second closed ledger has a close time in the past which crashes the CLC timing code. --- src/Ledger.cpp | 2 +- src/LedgerTiming.cpp | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index e94c6dc5b..131e7d3b9 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -71,7 +71,7 @@ Ledger::Ledger(bool dummy, Ledger& prevLedger) : prevLedger.getCloseAgree(), mLedgerSeq); if (prevLedger.mCloseTime == 0) { - mCloseTime = theApp->getOPs().getCloseTimeNC(); + mCloseTime = theApp->getOPs().getCloseTimeNC() - mCloseResolution; mCloseTime -= (mCloseTime % mCloseResolution); } else diff --git a/src/LedgerTiming.cpp b/src/LedgerTiming.cpp index 0585abd47..ecff1f441 100644 --- a/src/LedgerTiming.cpp +++ b/src/LedgerTiming.cpp @@ -19,13 +19,15 @@ int ContinuousLedgerTiming::shouldClose( int previousMSeconds, // seconds the previous ledger took to reach consensus int currentMSeconds) // seconds since the previous ledger closed { - assert((previousMSeconds > -1000) && (previousMSeconds < 600000)); - assert((currentMSeconds >= -1000) && (currentMSeconds < 600000)); - -#if 0 - Log(lsTRACE) << boost::str(boost::format("CLC::shouldClose Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") % - (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed % currentMSeconds % previousMSeconds); -#endif + if ((previousMSeconds < -1000) || (previousMSeconds > 600000) || + (currentMSeconds < -1000) || (currentMSeconds > 600000)) + { + Log(lsFATAL) << + boost::str(boost::format("CLC::shouldClose range error Trans=%s, Prop: %d/%d, Secs: %d (last:%d)") + % (anyTransactions ? "yes" : "no") % previousProposers % proposersClosed + % currentMSeconds % previousMSeconds); + return currentMSeconds; + } if (!anyTransactions) { // no transactions so far this interval