diff --git a/src/Amount.cpp b/src/Amount.cpp index 3e30ed9916..a3831035f9 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -527,14 +527,14 @@ STAmount::operator double() const } STAmount operator+(const STAmount& v1, const STAmount& v2) -{ // We can check for precision loss here (value%10)!=0 -// FIXME +{ + if (v1.isZero()) return v2; + if (v2.isZero()) return v1; + v1.throwComparable(v2); if (v1.mIsNative) return STAmount(v1.name, v1.getSNValue() + v2.getSNValue()); - if (v1.isZero()) return v2; - if (v2.isZero()) return v1; int ov1 = v1.mOffset, ov2 = v2.mOffset; int64 vv1 = static_cast(v1.mValue), vv2 = static_cast(v2.mValue); @@ -562,14 +562,12 @@ STAmount operator+(const STAmount& v1, const STAmount& v2) STAmount operator-(const STAmount& v1, const STAmount& v2) { + if (v2.isZero()) return v1; + v1.throwComparable(v2); if (v2.mIsNative) return STAmount(v1.name, v1.getSNValue() - v2.getSNValue()); - if (v2.isZero()) return v1; - if (v1.isZero() || (v2.mOffset > v1.mOffset) ) - throw std::runtime_error("value underflow"); - int ov1 = v1.mOffset, ov2 = v2.mOffset; int64 vv1 = static_cast(v1.mValue), vv2 = static_cast(v2.mValue); if (v1.mIsNegative) vv1 = -vv1; diff --git a/src/Application.cpp b/src/Application.cpp index ebca2d4524..f85992d93b 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -37,7 +37,7 @@ DatabaseCon::~DatabaseCon() Application::Application() : mUNL(mIOService), - mNetOps(mIOService, &mMasterLedger), mNodeCache(16384, 600), + mNetOps(mIOService, &mMasterLedger), mNodeCache(16384, 600), mHashedObjectStore(16384, 300), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL) { diff --git a/src/Application.h b/src/Application.h index 629976dadb..b63ff58d41 100644 --- a/src/Application.h +++ b/src/Application.h @@ -49,6 +49,7 @@ class Application NodeCache mNodeCache; ValidationCollection mValidations; SuppressionTable mSuppressions; + HashedObjectStore mHashedObjectStore; DatabaseCon *mTxnDB, *mLedgerDB, *mWalletDB, *mHashNodeDB, *mNetNodeDB; @@ -80,9 +81,10 @@ public: LedgerAcquireMaster& getMasterLedgerAcquire() { return mMasterLedgerAcquire; } TransactionMaster& getMasterTransaction() { return mMasterTransaction; } NodeCache& getNodeCache() { return mNodeCache; } + HashedObjectStore& getHashedObjectStore() { return mHashedObjectStore; } ValidationCollection& getValidations() { return mValidations; } - bool suppress(const uint256& s) { return mSuppressions.addSuppression(s); } - bool suppress(const uint160& s) { return mSuppressions.addSuppression(s); } + bool isNew(const uint256& s) { return mSuppressions.addSuppression(s); } + bool isNew(const uint160& s) { return mSuppressions.addSuppression(s); } DatabaseCon* getTxnDB() { return mTxnDB; } DatabaseCon* getLedgerDB() { return mLedgerDB; } diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp index faaf870ae8..63ff9f633f 100644 --- a/src/HashedObject.cpp +++ b/src/HashedObject.cpp @@ -7,7 +7,6 @@ #include "Application.h" #include "Log.h" - bool HashedObject::checkHash() const { uint256 hash = Serializer::getSHA512Half(mData); @@ -27,18 +26,19 @@ void HashedObject::setHash() mHash = Serializer::getSHA512Half(mData); } -// FIXME: Stores should be added to a queue that's services by an auxilliary thread or from an +// FIXME: Stores should be added to a queue that's serviced by an auxilliary thread or from an // auxilliary thread pool. These should be tied into a cache, since you need one to handle // an immedate read back (before the write completes) -bool HashedObject::store(HashedObjectType type, uint32 index, const std::vector& data, - const uint256& hash) +bool HashedObjectStore::store(HashedObjectType type, uint32 index, + const std::vector& data, const uint256& hash) { if (!theApp->getHashNodeDB()) return true; -#ifdef DEBUG - Serializer s(data); - assert(hash == s.getSHA512Half()); -#endif + HashedObject::pointer object = boost::make_shared(type, index, data); + object->setHash(); + if (object->getHash() != hash) + throw std::runtime_error("Object added to store doesn't have valid hash"); + std::string sql = "INSERT INTO CommittedObjects (Hash,ObjType,LedgerIndex,Object) VALUES ('"; sql.append(hash.GetHex()); switch(type) @@ -51,32 +51,32 @@ bool HashedObject::store(HashedObjectType type, uint32 index, const std::vector< } sql.append(boost::lexical_cast(index)); sql.append("',"); - std::string obj; theApp->getHashNodeDB()->getDB()->escape(&(data.front()), data.size(), obj); sql.append(obj); sql.append(");"); std::string exists = - boost::str(boost::format("SELECT ObjType FROM CommittedObject WHERE Hash = '%s';") % hash.GetHex()); + boost::str(boost::format("SELECT ObjType FROM CommittedObjects WHERE Hash = '%s';") % hash.GetHex()); ScopedLock sl(theApp->getHashNodeDB()->getDBLock()); + if (mCache.canonicalize(hash, object)) + return false; Database* db = theApp->getHashNodeDB()->getDB(); if (SQL_EXISTS(db, exists)) return false; return db->executeSQL(sql); } -bool HashedObject::store() const +HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash) { -#ifdef DEBUG - assert(checkHash()); -#endif - return store(mType, mLedgerIndex, mData, mHash); -} + HashedObject::pointer obj; + { + ScopedLock sl(theApp->getHashNodeDB()->getDBLock()); + obj = mCache.fetch(hash); + if (obj) return obj; + } -HashedObject::pointer HashedObject::retrieve(const uint256& hash) -{ if (!theApp || !theApp->getHashNodeDB()) return HashedObject::pointer(); std::string sql = "SELECT * FROM CommittedObjects WHERE Hash='"; sql.append(hash.GetHex()); @@ -102,34 +102,37 @@ HashedObject::pointer HashedObject::retrieve(const uint256& hash) data.resize(size); db->getBinary("Object", &(data.front()), size); db->endIterRows(); - } - HashedObjectType htype = UNKNOWN; - switch(type[0]) - { - case 'L': htype = LEDGER; break; - case 'T': htype = TRANSACTION; break; - case 'A': htype = ACCOUNT_NODE; break; - case 'N': htype = TRANSACTION_NODE; break; - default: - Log(lsERROR) << "Invalid hashed object"; - return HashedObject::pointer(); - } + HashedObjectType htype = UNKNOWN; + switch(type[0]) + { + case 'L': htype = LEDGER; break; + case 'T': htype = TRANSACTION; break; + case 'A': htype = ACCOUNT_NODE; break; + case 'N': htype = TRANSACTION_NODE; break; + default: + Log(lsERROR) << "Invalid hashed object"; + return HashedObject::pointer(); + } - HashedObject::pointer obj = boost::make_shared(htype, index, data); - obj->mHash = hash; + obj = boost::make_shared(htype, index, data); + obj->mHash = hash; + mCache.canonicalize(hash, obj); + } #ifdef DEBUG assert(obj->checkHash()); #endif return obj; } -HashedObjectBulkWriter::HashedObjectBulkWriter() : sl(theApp->getHashNodeDB()->getDBLock()) +ScopedLock HashedObjectStore::beginBulk() { + ScopedLock sl(theApp->getHashNodeDB()->getDBLock()); theApp->getHashNodeDB()->getDB()->executeSQL("BEGIN TRANSACTION;"); + return sl; } -HashedObjectBulkWriter::~HashedObjectBulkWriter() +void HashedObjectStore::endBulk() { theApp->getHashNodeDB()->getDB()->executeSQL("END TRANSACTION;"); } diff --git a/src/HashedObject.h b/src/HashedObject.h index 6a0fa28693..0f66c1509e 100644 --- a/src/HashedObject.h +++ b/src/HashedObject.h @@ -6,6 +6,7 @@ #include "types.h" #include "uint256.h" #include "ScopedLock.h" +#include "TaggedCache.h" enum HashedObjectType { @@ -34,29 +35,41 @@ public: void setHash(); const std::vector& getData() { return mData; } + const uint256& getHash() { return mHash; } +}; - bool store() const; +class HashedObjectStore +{ +protected: + TaggedCache mCache; - static bool store(HashedObjectType type, uint32 index, const std::vector& data, +public: + + HashedObjectStore(int cacheSize, int cacheAge) : mCache(cacheSize, cacheAge) { ; } + + bool store(HashedObjectType type, uint32 index, const std::vector& data, const uint256& hash); - static HashedObject::pointer retrieve(const uint256& hash); + HashedObject::pointer retrieve(const uint256& hash); + + ScopedLock beginBulk(); + void endBulk(); }; class HashedObjectBulkWriter { protected: + HashedObjectStore& mStore; ScopedLock sl; public: + HashedObjectBulkWriter(HashedObjectStore& ostore) : mStore(ostore), sl(mStore.beginBulk()) { ; } + ~HashedObjectBulkWriter() { mStore.endBulk(); } - HashedObjectBulkWriter(); - ~HashedObjectBulkWriter(); + bool store(HashedObjectType type, uint32 index, const std::vector& data, + const uint256& hash) { return mStore.store(type, index, data, hash); } - bool store(HashedObjectType type, uint32 index, const std::vector& data, const uint256& hash) - { return HashedObject::store(type, index, data, hash); } - HashedObject::pointer retrieve(const uint256& hash) - { return HashedObject::retrieve(hash); } + HashedObject::pointer retrieve(const uint256& hash) { return mStore.retrieve(hash); } }; #endif diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index e440a77945..825045bf7e 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -11,8 +11,8 @@ #define LA_DEBUG #define LEDGER_ACQUIRE_TIMEOUT 2 -PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterval(interval), - mComplete(false), mFailed(false), mTimer(theApp->getIOService()) +PeerSet::PeerSet(const uint256& hash, int interval) : mHash(hash), mTimerInterval(interval), mTimeouts(0), + mComplete(false), mFailed(false), mProgress(true), mTimer(theApp->getIOService()) { ; } void PeerSet::peerHas(Peer::pointer ptr) @@ -61,11 +61,24 @@ void PeerSet::resetTimer() mTimer.async_wait(boost::bind(&PeerSet::TimerEntry, pmDowncast(), boost::asio::placeholders::error)); } +void PeerSet::invokeOnTimer() +{ + if (!mProgress) + { + ++mTimeouts; + Log(lsWARNING) << "Timeout " << mTimeouts << " acquiring " << mHash.GetHex(); + } + else + mProgress = false; + onTimer(); +} + void PeerSet::TimerEntry(boost::weak_ptr wptr, const boost::system::error_code& result) { if (result == boost::asio::error::operation_aborted) return; boost::shared_ptr ptr = wptr.lock(); - if (!!ptr) ptr->onTimer(); + if (!ptr) return; + ptr->invokeOnTimer(); } LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE_TIMEOUT), @@ -284,6 +297,7 @@ bool LedgerAcquire::takeBase(const std::string& data, Peer::pointer peer) return false; } mHaveBase = true; + progress(); if (!mLedger->getTransHash()) mHaveTransactions = true; if (!mLedger->getAccountHash()) mHaveState = true; mLedger->setAcquiring(); @@ -315,6 +329,7 @@ bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, if (mHaveState) mComplete = true; } trigger(peer); + progress(); return true; } @@ -345,6 +360,7 @@ bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, if (mHaveTransactions) mComplete = true; } trigger(peer); + progress(); return true; } diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index 681d4bd0e0..87e2c86b21 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -20,8 +20,8 @@ class PeerSet { protected: uint256 mHash; - int mTimerInterval; - bool mComplete, mFailed; + int mTimerInterval, mTimeouts; + bool mComplete, mFailed, mProgress; boost::recursive_mutex mLock; boost::asio::deadline_timer mTimer; @@ -37,6 +37,9 @@ public: const uint256& getHash() const { return mHash; } bool isComplete() const { return mComplete; } bool isFailed() const { return mFailed; } + int getTimeouts() const { return mTimeouts; } + + void progress() { mProgress = true; } void peerHas(Peer::pointer); void badPeer(Peer::pointer); @@ -49,6 +52,7 @@ protected: void setComplete() { mComplete = true; } void setFailed() { mFailed = true; } + void invokeOnTimer(); private: static void TimerEntry(boost::weak_ptr, const boost::system::error_code& result); diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 5f547a821b..5baeff0d6a 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -110,6 +110,7 @@ bool TransactionAcquire::takeNodes(const std::list& nodeIDs, ++nodeDatait; } trigger(peer); + progress(); return true; } catch (...) @@ -426,7 +427,6 @@ int LedgerConsensus::timerEntry() theApp->getOPs().switchLastClosedLedger(consensus); mPreviousLedger = consensus; mHaveCorrectLCL = true; - // FIXME: We need some kind of idea what the consensus transaction set is } } @@ -589,10 +589,7 @@ bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition) { assert(newPosition->getPeerID() == currentPosition->getPeerID()); if (newPosition->getProposeSeq() <= currentPosition->getProposeSeq()) - { - Log(lsINFO) << "Redundant/stale positon"; return false; - } if (newPosition->getCurrentHash() == currentPosition->getCurrentHash()) { // we missed an intermediary change Log(lsINFO) << "We missed an intermediary position"; @@ -672,7 +669,7 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, SerializedTran if (result > 0) { Log(lsINFO) << " retry"; -// assert(!ledger->hasTransaction(txn->getTransactionID())); FIXME: We get these (doPasswordSet) + assert(!ledger->hasTransaction(txn->getTransactionID())); failedTransactions.push_back(txn); } else if (result == 0) @@ -757,17 +754,6 @@ void LedgerConsensus::accept(SHAMap::pointer set) Ledger::pointer newLCL = boost::make_shared(false, boost::ref(*mPreviousLedger)); newLCL->armDirty(); -#ifdef DEBUG - Json::StyledStreamWriter ssw; - if (1) - { - Log(lsTRACE) << "newLCL before transactions"; - Json::Value p; - newLCL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE); - ssw.write(Log(lsTRACE).ref(), p); - } -#endif - CanonicalTXSet failedTransactions(set->getHash()); applyTransactions(set, newLCL, failedTransactions, true); newLCL->setClosed(); @@ -775,27 +761,23 @@ void LedgerConsensus::accept(SHAMap::pointer set) newLCL->updateHash(); uint256 newLCLHash = newLCL->getHash(); Log(lsTRACE) << "newLCL " << newLCLHash.GetHex(); - + 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(); + theApp->getValidations().addValidation(v); + std::vector validation = v->getSigned(); + newcoin::TMValidation val; + val.set_validation(&validation[0], validation.size()); + 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)); - -#ifdef DEBUG - if (1) - { - Log(lsTRACE) << "newOL before transactions"; - Json::Value p; - newOL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE); - ssw.write(Log(lsTRACE).ref(), p); - } - if (1) - { - Log(lsTRACE) << "current ledger"; - Json::Value p; - theApp->getMasterLedger().getCurrentLedger()->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE); - ssw.write(Log(lsTRACE).ref(), p); - } -#endif - ScopedLock sl = theApp->getMasterLedger().getLock(); // Apply disputed transactions that didn't get in @@ -825,35 +807,15 @@ void LedgerConsensus::accept(SHAMap::pointer set) sl.unlock(); #ifdef DEBUG + Json::StyledStreamWriter ssw; if (1) { - Log(lsTRACE) << "newOL after current ledger transactions"; + Log(lsTRACE) << "newLCL"; Json::Value p; - newOL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE); + newLCL->addJson(p, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE); ssw.write(Log(lsTRACE).ref(), p); - Log(lsINFO) << "newLCL after transactions"; - Json::Value p2; - newLCL->addJson(p2, LEDGER_JSON_DUMP_TXNS | LEDGER_JSON_DUMP_STATE); - ssw.write(Log(lsTRACE).ref(), p2); } #endif - - if (mValidating) - { - assert (theApp->getOPs().getNetworkTimeNC() > newLCL->getCloseTimeNC()); - SerializedValidation::pointer v = boost::make_shared - (newLCLHash, newLCL->getCloseTimeNC(), mOurPosition->peekSeed(), true); - v->setTrusted(); - // FIXME: If not proposing, set not full - theApp->getValidations().addValidation(v); - std::vector validation = v->getSigned(); - newcoin::TMValidation val; - val.set_validation(&validation[0], validation.size()); - theApp->getConnectionPool().relayMessage(NULL, boost::make_shared(val, newcoin::mtVALIDATION)); - Log(lsINFO) << "Validation sent " << newLCLHash.GetHex(); - } - else Log(lsWARNING) << "Not validating"; - statusChange(newcoin::neACCEPTED_LEDGER, newLCL); // FIXME: If necessary, change state to TRACKING/FULL } diff --git a/src/LedgerProposal.cpp b/src/LedgerProposal.cpp index 9f435415bd..7d79bf0b6b 100644 --- a/src/LedgerProposal.cpp +++ b/src/LedgerProposal.cpp @@ -22,7 +22,6 @@ LedgerProposal::LedgerProposal(const uint256& pLgr, uint32 seq, const uint256& t LedgerProposal::LedgerProposal(const NewcoinAddress& naSeed, const uint256& prevLgr, const uint256& position) : mPreviousLedger(prevLgr), mCurrentHash(position), mProposeSeq(0) { - mSeed = naSeed; mPublicKey = NewcoinAddress::createNodePublic(naSeed); mPrivateKey = NewcoinAddress::createNodePrivate(naSeed); mPeerID = mPublicKey.getNodeID(); @@ -46,9 +45,9 @@ uint256 LedgerProposal::getSigningHash() const return s.getSHA512Half(); } -bool LedgerProposal::checkSign(const std::string& signature) +bool LedgerProposal::checkSign(const std::string& signature, const uint256& signingHash) { - return mPublicKey.verifyNodePublic(getSigningHash(), signature); + return mPublicKey.verifyNodePublic(signingHash, signature); } void LedgerProposal::changePosition(const uint256& newPosition) diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index f7e50cc639..35557920c5 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -16,9 +16,8 @@ protected: uint32 mProposeSeq; uint160 mPeerID; - NewcoinAddress mPublicKey; // Peer - NewcoinAddress mPrivateKey; // Our's - NewcoinAddress mSeed; // Our's + NewcoinAddress mPublicKey; + NewcoinAddress mPrivateKey; // If ours static const uint32 sProposeMagic = 0x50525000; // PRP @@ -27,22 +26,24 @@ public: typedef boost::shared_ptr pointer; // proposal from peer - LedgerProposal(const uint256& prevLgr, uint32 proposeSeq, const uint256& propose, const NewcoinAddress& naPeerPublic); + LedgerProposal(const uint256& prevLgr, uint32 proposeSeq, const uint256& propose, + const NewcoinAddress& naPeerPublic); // our first proposal - LedgerProposal(const NewcoinAddress& naSeed, const uint256& prevLedger, const uint256& position); + LedgerProposal(const NewcoinAddress& privKey, const uint256& prevLedger, const uint256& position); // an unsigned proposal LedgerProposal(const uint256& prevLedger, const uint256& position); uint256 getSigningHash() const; - bool checkSign(const std::string& signature); + bool checkSign(const std::string& signature, const uint256& signingHash); + bool checkSign(const std::string& signature) { return checkSign(signature, getSigningHash()); } const uint160& getPeerID() const { return mPeerID; } const uint256& getCurrentHash() const { return mCurrentHash; } const uint256& getPrevLedger() const { return mPreviousLedger; } uint32 getProposeSeq() const { return mProposeSeq; } - const NewcoinAddress& peekSeed() const { return mSeed; } + const NewcoinAddress& peekPublic() const { return mPublicKey; } std::vector getPubKey() const { return mPublicKey.getNodePublic(); } std::vector sign(); diff --git a/src/LedgerTiming.h b/src/LedgerTiming.h index 5a2793aa86..d7e623844d 100644 --- a/src/LedgerTiming.h +++ b/src/LedgerTiming.h @@ -19,7 +19,7 @@ # define LEDGER_CONVERGE 14 // Maximum converge time -# define LEDGER_MAX_CONVERGE 22 +# define LEDGER_MAX_CONVERGE 20 #endif diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index ebf6284143..e4d8b4af42 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -98,7 +98,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, } Log(lsDEBUG) << "Status other than success " << r ; - if ((mMode != omFULL) && (theApp->suppress(trans->getID()))) + if ((mMode != omFULL) && (mMode != omTRACKING) && (theApp->isNew(trans->getID()))) { newcoin::TMTransaction tx; Serializer s; @@ -432,26 +432,26 @@ bool NetworkOPs::checkLastClosedLedger(const std::vector& peerLis } if (!acq->isComplete()) { // add more peers - //JED: seems like you need to do something here so it knows in beginConsensus that it isn't on the the right ledger - // switch to an empty ledger so we won't keep going - //Ledger::pointer emptyLedger(new Ledger()); - //switchLastClosedLedger(emptyLedger); - - // JED: just ask everyone + int count = 0; std::vector peers=theApp->getConnectionPool().getPeerVector(); - for(int n=0; nisConnected()) acq->peerHas(peers[n]); - } - - /* JED this wasn't adding any peers. This is also an optimization so we can do this later - // FIXME: A peer may not have a ledger just because it accepts it as the network's consensus for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); it != end; ++it) { if ((*it)->getClosedLedgerHash() == closedLedger) + { + ++count; acq->peerHas(*it); - }*/ + } + } + if (!count) + { // just ask everyone + for (std::vector::const_iterator it = peerList.begin(), end = peerList.end(); + it != end; ++it) + { + if ((*it)->isConnected()) + acq->peerHas(*it); + } + } return true; } consensus = acq->getLedger(); @@ -521,20 +521,28 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, // XXX Validate key. // XXX Take a vuc for pubkey. - NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey)); - if (mMode != omFULL) + // Get a preliminary hash to use to suppress duplicates + Serializer s; + s.add32(proposeSeq); + s.add32(getCurrentLedgerID()); + s.addRaw(pubKey); + if (!theApp->isNew(s.getSHA512Half())) + return false; + + if ((mMode != omFULL) && (mMode != omTRACKING)) { - Log(lsINFO) << "Received proposal when not full: " << mMode; - Serializer s(signature); - return theApp->suppress(s.getSHA512Half()); + Log(lsINFO) << "Received proposal when not full/tracking: " << mMode; + return true; } + if (!mConsensus) { Log(lsWARNING) << "Received proposal when full but not during consensus window"; return false; } + NewcoinAddress naPeerPublic = NewcoinAddress::createNodePublic(strCopy(pubKey)); LedgerProposal::pointer proposal = boost::make_shared(mConsensus->getLCL(), proposeSeq, proposeHash, naPeerPublic); if (!proposal->checkSign(signature)) @@ -545,15 +553,14 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, // Is this node on our UNL? // XXX Is this right? - if (!theApp->getUNL().nodeInUNL(naPeerPublic)) + if (!theApp->getUNL().nodeInUNL(proposal->peekPublic())) { - Log(lsINFO) << "Relay, but no process peer proposal " << proposal->getProposeSeq() << "/" - << proposal->getCurrentHash().GetHex(); + Log(lsINFO) << "Untrusted proposal: " << naPeerPublic.humanNodePublic() << " " << + proposal->getCurrentHash().GetHex(); return true; } return mConsensus->peerPosition(proposal); - } SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash) @@ -640,7 +647,6 @@ std::vector< std::pair > bool NetworkOPs::recvValidation(SerializedValidation::pointer val) { Log(lsINFO) << "recvValidation " << val->getLedgerHash().GetHex(); - return theApp->getValidations().addValidation(val); } diff --git a/src/Peer.cpp b/src/Peer.cpp index 038d6989a9..f4cbbcb0a9 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -730,16 +730,23 @@ void Peer::recvValidation(newcoin::TMValidation& packet) punishPeer(PP_UNKNOWN_REQUEST); return; } + try { Serializer s(packet.validation()); SerializerIterator sit(s); - SerializedValidation::pointer val = boost::make_shared(boost::ref(sit)); - if (!val->isValid()) + SerializedValidation::pointer val = boost::make_shared(boost::ref(sit), false); + + uint256 signingHash = val->getSigningHash(); + if (!theApp->isNew(signingHash)) + return; + + if (!val->isValid(signingHash)) { punishPeer(PP_UNKNOWN_REQUEST); return; } + if (theApp->getOPs().recvValidation(val)) { PackedMessage::pointer message = boost::make_shared(packet, newcoin::mtVALIDATION); @@ -852,7 +859,7 @@ void Peer::recvAccount(newcoin::TMAccount& packet) void Peer::recvStatus(newcoin::TMStatusChange& packet) { - Log(lsTRACE) << "Received status change from peer" << getIP(); + Log(lsTRACE) << "Received status change from peer " << getIP(); if (!packet.has_networktime()) packet.set_networktime(theApp->getOPs().getNetworkTimeNC()); mLastStatus = packet; diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index 987a088d31..e3961f5901 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -623,7 +623,7 @@ void SHAMapItem::dump() bool SHAMap::fetchNode(const uint256& hash, std::vector& data) { - HashedObject::pointer obj(HashedObject::retrieve(hash)); + HashedObject::pointer obj(theApp->getHashedObjectStore().retrieve(hash)); if(!obj) return false; data = obj->getData(); return true; @@ -642,7 +642,7 @@ int SHAMap::flushDirty(int maxNodes, HashedObjectType t, uint32 seq) if(mDirtyNodes) { - HashedObjectBulkWriter bw; + HashedObjectBulkWriter bw(theApp->getHashedObjectStore()); boost::unordered_map& dirtyNodes = *mDirtyNodes; boost::unordered_map::iterator it = dirtyNodes.begin(); while (it != dirtyNodes.end()) diff --git a/src/SerializedValidation.cpp b/src/SerializedValidation.cpp index 9c19bc7615..71c11c831c 100644 --- a/src/SerializedValidation.cpp +++ b/src/SerializedValidation.cpp @@ -16,7 +16,7 @@ const uint32 SerializedValidation::sValidationMagic = 0x4c575200; // "LGR" SerializedValidation::SerializedValidation(SerializerIterator& sit, bool checkSignature) : STObject(sValidationFormat, sit), mSignature(sit, "Signature"), mTrusted(false) { - if (!isValid()) throw std::runtime_error("Invalid validation"); + if (checkSignature && !isValid()) throw std::runtime_error("Invalid validation"); } SerializedValidation::SerializedValidation(const uint256& ledgerHash, uint64 closeTime, @@ -56,12 +56,16 @@ uint64 SerializedValidation::getCloseTime() const } bool SerializedValidation::isValid() const +{ + return isValid(getSigningHash()); +} + +bool SerializedValidation::isValid(const uint256& signingHash) const { try { NewcoinAddress naPublicKey = NewcoinAddress::createNodePublic(getValueFieldVL(sfSigningKey)); - - return naPublicKey.isValid() && naPublicKey.verifyNodePublic(getSigningHash(), mSignature.peekValue()); + return naPublicKey.isValid() && naPublicKey.verifyNodePublic(signingHash, mSignature.peekValue()); } catch (...) { diff --git a/src/SerializedValidation.h b/src/SerializedValidation.h index ab0886a6bf..863dea31b9 100644 --- a/src/SerializedValidation.h +++ b/src/SerializedValidation.h @@ -33,6 +33,7 @@ public: bool isTrusted() const { return mTrusted; } CKey::pointer getSigningKey() const; uint256 getSigningHash() const; + bool isValid(const uint256&) const; void setTrusted() { mTrusted = true; } void addSigned(Serializer&) const; diff --git a/src/TransactionEngine.h b/src/TransactionEngine.h index 805c879546..8a78ea6da0 100644 --- a/src/TransactionEngine.h +++ b/src/TransactionEngine.h @@ -31,6 +31,7 @@ enum TransactionEngineResult tenMSG_SET, // Can't change a message key. tenBAD_AUTH_MASTER, // Auth for unclaimed account needs correct master key. tenBAD_RIPPLE, // Ledger prevents ripple from succeeding. + terALREADY, // The exact transaction was already in this ledger // Other tenFAILED = -100, // Something broke horribly @@ -43,7 +44,6 @@ enum TransactionEngineResult // terFAILED_BUT_COULD_SUCCEED = >0 // Conflict with ledger database: Fee claimed // Might succeed if not conflict is not caused by transaction ordering. - terALREADY, // The transaction was already in the ledger terBAD_SEQ, // This sequence number should be zero for prepaid transactions. terCREATED, // Can not create a previously created account. terDIR_FULL, // Can not add entry to full dir. diff --git a/src/ValidationCollection.cpp b/src/ValidationCollection.cpp index a1ed90546c..5b53e46f25 100644 --- a/src/ValidationCollection.cpp +++ b/src/ValidationCollection.cpp @@ -36,7 +36,7 @@ bool ValidationCollection::addValidation(SerializedValidation::pointer val) Log(lsINFO) << "Val for " << hash.GetHex() << " from " << val->getSignerPublic().humanNodePublic() << " added " << (val->isTrusted() ? "trusted" : "UNtrusted"); - return true; + return isCurrent; } ValidationSet ValidationCollection::getValidations(const uint256& ledger)