From de59306fec5ac47e883397467568418310b62f59 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 21 May 2012 19:38:30 -0700 Subject: [PATCH 01/10] Fix some const-correctness issues. Add a Verify helper that takes a string. --- src/key.h | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/key.h b/src/key.h index 999bc1e81b..2233c63b31 100644 --- a/src/key.h +++ b/src/key.h @@ -188,7 +188,7 @@ public: return true; } - CSecret GetSecret() const + CSecret GetSecret() { CSecret vchRet; vchRet.resize(32); @@ -207,7 +207,7 @@ public: return BN_dup(EC_KEY_get0_private_key(pkey)); } - CPrivKey GetPrivKey() const + CPrivKey GetPrivKey() { unsigned int nSize = i2d_ECPrivateKey(pkey, NULL); if (!nSize) @@ -260,7 +260,7 @@ public: vchSig.clear(); unsigned char pchSig[10000]; unsigned int nSize = 0; - if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), pchSig, &nSize, pkey)) + if (!ECDSA_sign(0, (unsigned char*)hash.begin(), hash.size(), pchSig, &nSize, pkey)) return false; vchSig.resize(nSize); @@ -268,14 +268,24 @@ public: return true; } - bool Verify(const uint256& hash, const std::vector& vchSig) const + bool Verify(const uint256& hash, const void *sig, size_t sigLen) const { // -1 = error, 0 = bad sig, 1 = good - if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) + if (ECDSA_verify(0, hash.begin(), hash.size(), (const unsigned char *) sig, sigLen, pkey) != 1) return false; return true; } + bool Verify(const uint256& hash, const std::vector& vchSig) const + { + return Verify(hash, &vchSig[0], vchSig.size()); + } + + bool Verify(const uint256& hash, const std::string sig) const + { + return Verify(hash, sig.data(), sig.size()); + } + // ECIES functions. These throw on failure // returns a 32-byte secret unique to these two keys. At least one private key must be known. From a6273613a508e2207eddabd4dc9e94dc5cac712a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Mon, 21 May 2012 19:39:32 -0700 Subject: [PATCH 02/10] Fix this class. --- src/LedgerProposal.cpp | 61 +++++++++++++++++------------------------- src/LedgerProposal.h | 6 ++--- 2 files changed, 27 insertions(+), 40 deletions(-) diff --git a/src/LedgerProposal.cpp b/src/LedgerProposal.cpp index dba8532917..5ad65ffb5f 100644 --- a/src/LedgerProposal.cpp +++ b/src/LedgerProposal.cpp @@ -3,59 +3,46 @@ #include -LedgerProposal::LedgerProposal(SerializerIterator& it) : mKey(boost::make_shared()) +#include "key.h" +#include "Application.h" + +LedgerProposal::LedgerProposal(uint32 closingSeq, uint32 proposeSeq, const uint256& prevTx, const uint256& proposeTx, + const std::string& pubKey) : mPrevHash(prevTx), mCurrentHash(proposeTx), + mProposeSeq(proposeSeq), mKey(boost::make_shared()) { - if (it.get32() != sProposeMagic) - throw std::runtime_error("Not a ledger proposal"); - - mPreviousLedger = it.get256(); - mCurrentHash = it.get256(); - mPrevHash = it.get256(); - mProposeSeq = it.get32(); - if (mKey->SetPubKey(it.getVL())) - throw std::runtime_error("Unable to set public key"); - mSignature = it.getVL(); - + if (!mKey->SetPubKey(pubKey)) + throw std::runtime_error("Invalid public key in proposal"); + mPreviousLedger = theApp->getMasterLedger().getClosedLedger()->getHash(); mPeerID = Serializer::getSHA512Half(mKey->GetPubKey()); - - if (!mKey->Verify(getSigningHash(), mSignature)) - throw std::runtime_error("Ledger proposal invalid"); } + LedgerProposal::LedgerProposal(CKey::pointer mPrivateKey, const uint256& prevLgr, const uint256& position) : mPreviousLedger(prevLgr), mCurrentHash(position), mProposeSeq(0), mKey(mPrivateKey) { mPeerID = Serializer::getSHA512Half(mKey->GetPubKey()); - if (!mKey->Sign(getSigningHash(), mSignature)) - throw std::runtime_error("Unable to sign proposal"); } LedgerProposal::LedgerProposal(LedgerProposal::pointer previous, const uint256& newp) : - mPeerID(previous->mPeerID), mPreviousLedger(previous->mPreviousLedger), mPrevHash(previous->mCurrentHash), - mCurrentHash(newp), mProposeSeq(previous->mProposeSeq + 1), mKey(previous->mKey) + mPeerID(previous->mPeerID), mPreviousLedger(previous->mPreviousLedger), + mPrevHash(previous->mCurrentHash), mCurrentHash(newp), + mProposeSeq(previous->mProposeSeq + 1), mKey(previous->mKey) { - if (!mKey->Sign(getSigningHash(), mSignature)) - throw std::runtime_error("Unable to sign proposal"); -} - -void LedgerProposal::add(Serializer& s, bool for_signature) const -{ - s.add32(sProposeMagic); - s.add256(mPreviousLedger); - s.add256(mCurrentHash); - s.add256(mPrevHash); - s.add32(mProposeSeq); - - if (for_signature) - return; - - s.addVL(mKey->GetPubKey()); - s.addVL(mSignature); + ; } uint256 LedgerProposal::getSigningHash() const { Serializer s(104); - add(s, true); + s.add32(sProposeMagic); + s.add32(mProposeSeq); + s.add256(mPreviousLedger); + s.add256(mCurrentHash); + s.add256(mPrevHash); return s.getSHA512Half(); } + +bool LedgerProposal::checkSign(const std::string& signature) +{ + return mKey->Verify(getSigningHash(), signature); +} diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index a36c3a77f9..82e101c3f8 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -16,7 +16,6 @@ protected: uint256 mPeerID, mPreviousLedger, mPrevHash, mCurrentHash; uint32 mProposeSeq; CKey::pointer mKey; - std::vector mSignature; // std::vector mAddedTx, mRemovedTx; static const uint32 sProposeMagic = 0x50525000; // PRP @@ -26,7 +25,8 @@ public: typedef boost::shared_ptr pointer; // proposal from peer - LedgerProposal(SerializerIterator& it); + LedgerProposal(uint32 closingSeq, uint32 proposeSeq, const uint256& prevTx, const uint256& propose, + const std::string& pubKey); // our first proposal LedgerProposal(CKey::pointer privateKey, const uint256& prevLedger, const uint256& position); @@ -34,8 +34,8 @@ public: // our following proposals LedgerProposal(LedgerProposal::pointer previous, const uint256& newPosition); - void add(Serializer&, bool for_signature) const; uint256 getSigningHash() const; + bool checkSign(const std::string& signature); const uint256& getPeerID() const { return mPeerID; } const uint256& getPrevHash() const { return mPrevHash; } From fbce5dafc54306dc60d9e1d9af73d5e60c3bdf42 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 22 May 2012 02:34:20 -0700 Subject: [PATCH 03/10] Move some PeerSet structures. --- src/LedgerAcquire.cpp | 4 ++-- src/LedgerAcquire.h | 28 +++------------------------- 2 files changed, 5 insertions(+), 27 deletions(-) diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index fe5e72c1e4..5bf98283f7 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -238,12 +238,12 @@ void LedgerAcquire::trigger(Peer::pointer peer) resetTimer(); } -void LedgerAcquire::sendRequest(boost::shared_ptr tmGL, Peer::pointer peer) +void PeerSet::sendRequest(boost::shared_ptr tmGL, Peer::pointer peer) { peer->sendPacket(boost::make_shared(tmGL, newcoin::mtGET_LEDGER)); } -void LedgerAcquire::sendRequest(boost::shared_ptr tmGL) +void PeerSet::sendRequest(boost::shared_ptr tmGL) { boost::recursive_mutex::scoped_lock sl(mLock); if (mPeers.empty()) return; diff --git a/src/LedgerAcquire.h b/src/LedgerAcquire.h index c2e3f74a6e..47b2915826 100644 --- a/src/LedgerAcquire.h +++ b/src/LedgerAcquire.h @@ -29,6 +29,9 @@ protected: PeerSet(const uint256& hash, int interval); virtual ~PeerSet() { ; } + void sendRequest(boost::shared_ptr message); + void sendRequest(boost::shared_ptr message, Peer::pointer peer); + public: const uint256& getHash() const { return mHash; } bool isComplete() const { return mComplete; } @@ -64,8 +67,6 @@ protected: void done(); void onTimer() { trigger(Peer::pointer()); } - void sendRequest(boost::shared_ptr message); - void sendRequest(boost::shared_ptr message, Peer::pointer peer); void newPeer(Peer::pointer peer) { trigger(peer); } void trigger(Peer::pointer); @@ -88,29 +89,6 @@ public: Peer::pointer); }; -class TransactionAcquire : public PeerSet, public boost::enable_shared_from_this -{ // A transaction set we are trying to acquire -public: - typedef boost::shared_ptr pointer; - -protected: - SHAMap::pointer mMap; - - void onTimer() { trigger(Peer::pointer()); } - void newPeer(Peer::pointer peer) { trigger(peer); } - - void done(); - void trigger(Peer::pointer); - boost::weak_ptr pmDowncast(); - -public: - TransactionAcquire(const uint256& hash); - SHAMap::pointer getMap(); - - bool takeNode(const std::list& IDs, const std::list >& data, - Peer::pointer); -}; - class LedgerAcquireMaster { protected: From 485a8a709d29b6721cd234705972b33bfd6151d0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 22 May 2012 02:35:11 -0700 Subject: [PATCH 04/10] The 'previous hash' logic isn't needed. --- src/newcoin.proto | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/newcoin.proto b/src/newcoin.proto index fda095465f..c2c99811e4 100644 --- a/src/newcoin.proto +++ b/src/newcoin.proto @@ -103,12 +103,11 @@ message TMStatusChange { message TMProposeSet { required uint32 closingSeq = 1; required uint32 proposeSeq = 2; - required bytes previousTxHash = 3; // 0 if first proposal, hash we no longer propose - required bytes currentTxHash = 4; // the hash of the ledger we are proposing - required bytes nodePubKey = 5; - required bytes signature = 6; // signature of above fields - repeated bytes addedTransactions = 7; // not required if number is large - repeated bytes removedTransactions = 8; // not required if number is large + required bytes currentTxHash = 3; // the hash of the ledger we are proposing + required bytes nodePubKey = 4; + required bytes signature = 5; // signature of above fields + repeated bytes addedTransactions = 6; // not required if number is large + repeated bytes removedTransactions = 7; // not required if number is large } // Announce to a peer that we have fully acquired a transaction set From 441a27dffdc2e242d0b909f988ca9935b9859320 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 22 May 2012 02:35:47 -0700 Subject: [PATCH 05/10] Ledger consensus work. --- src/LedgerConsensus.cpp | 159 +++++++++++++++++++++++++++++++++++++++- src/LedgerConsensus.h | 69 +++++++++-------- src/LedgerProposal.cpp | 10 +-- src/LedgerProposal.h | 6 +- src/NetworkOPs.cpp | 32 ++++++-- src/NetworkOPs.h | 3 +- src/Peer.cpp | 32 ++++++-- 7 files changed, 248 insertions(+), 63 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 9e069aff94..50d58973b0 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -1,16 +1,169 @@ #include "LedgerConsensus.h" +TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, 1), mHaveRoot(false) +{ + mMap = boost::make_shared(); + mMap->setSynching(); +} + +void TransactionAcquire::done() +{ + // insert SHAMap in finished set (as valid or invalid), remove ourselves from current set + // WRITEME +} + +boost::weak_ptr TransactionAcquire::pmDowncast() +{ + return boost::shared_polymorphic_downcast(shared_from_this()); +} + +void TransactionAcquire::trigger(Peer::pointer peer) +{ + if (mComplete || mFailed) + return; + if (!mHaveRoot) + { + boost::shared_ptr tmGL = boost::make_shared(); + tmGL->set_ledgerhash(mHash.begin(), mHash.size()); + tmGL->set_itype(newcoin::liTS_CANDIDATE); + *(tmGL->add_nodeids()) = SHAMapNode().getRawString(); + sendRequest(tmGL); + } + if (mHaveRoot) + { + std::vector nodeIDs; + std::vector nodeHashes; + mMap->getMissingNodes(nodeIDs, nodeHashes, 256); + if (nodeIDs.empty()) + { + if (mMap->isValid()) + mComplete = true; + else + mFailed = true; + } + else + { + boost::shared_ptr tmGL = boost::make_shared(); + tmGL->set_ledgerhash(mHash.begin(), mHash.size()); + tmGL->set_itype(newcoin::liTS_CANDIDATE); + for (std::vector::iterator it = nodeIDs.begin(); it != nodeIDs.end(); ++it) + *(tmGL->add_nodeids()) = it->getRawString(); + if (peer) + sendRequest(tmGL, peer); + else + sendRequest(tmGL); + return; + } + } + if (mComplete || mFailed) + done(); + else + resetTimer(); +} + +bool TransactionAcquire::takeNode(const std::list& nodeIDs, + const std::list< std::vector >& data, Peer::pointer peer) +{ + if (mComplete || mFailed) + return true; + std::list::const_iterator nodeIDit = nodeIDs.begin(); + std::list< std::vector >::const_iterator nodeDatait = data.begin(); + while (nodeIDit != nodeIDs.end()) + { + if (nodeIDit->isRoot()) + { + if (!mMap->addRootNode(getHash(), *nodeDatait)) + return false; + } + else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait)) + return false; + ++nodeIDit; + ++nodeDatait; + } + trigger(peer); + return true; +} + void LedgerConsensus::abort() { } int LedgerConsensus::startup() { - return 5; + return 1; } int LedgerConsensus::timerEntry() { - return 5; -} \ No newline at end of file + return 1; +} + +SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool doAcquire) +{ + boost::unordered_map::iterator it = mComplete.find(hash); + if (it == mComplete.end()) + { // we have not completed acuiqiring this ledger + if (doAcquire) + { + TransactionAcquire::pointer& acquiring = mAcquiring[hash]; + if (!acquiring) + { + acquiring = boost::make_shared(hash); + startAcquiring(acquiring); + } + } + return SHAMap::pointer(); + } + return it->second; +} + +void LedgerConsensus::startAcquiring(TransactionAcquire::pointer acquire) +{ + boost::unordered_map< uint256, std::vector< boost::weak_ptr > >::iterator it = + mPeerData.find(acquire->getHash()); + + if (it != mPeerData.end()) + { // Add any peers we already know have his transaction set + std::vector< boost::weak_ptr >& peerList = it->second; + std::vector< boost::weak_ptr >::iterator pit = peerList.begin(); + while (pit != peerList.end()) + { + Peer::pointer pr = pit->lock(); + if (!pr) + pit = peerList.erase(pit); + else + { + acquire->peerHas(pr); + ++pit; + } + } + } +} + +void LedgerConsensus::removePosition(LedgerProposal& position) +{ + // WRITEME +} + +void LedgerConsensus::addPosition(LedgerProposal& position) +{ + // WRITEME +} + +bool LedgerConsensus::peerPosition(LedgerProposal::pointer newPosition) +{ + LedgerProposal::pointer& currentPosition = mPeerPositions[newPosition->getPeerID()]; + if (!currentPosition) + { + if (newPosition->getProposeSeq() <= currentPosition->getProposeSeq()) + return false; + + // change in position + removePosition(*currentPosition); + } + + currentPosition = newPosition; + addPosition(*currentPosition); + return true; +} diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index c6f3b36936..f2ef4110ef 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -12,36 +12,32 @@ #include "LedgerProposal.h" #include "Peer.h" -class LCPosition -{ // A position taken by one of our trusted peers +class TransactionAcquire : public PeerSet, public boost::enable_shared_from_this +{ // A transaction set we are trying to acquire +public: + typedef boost::shared_ptr pointer; + protected: - uint256 mPubKeyHash; - CKey::pointer mPubKey; - uint256 mPreviousPosition, mCurrentPosition; - uint32 mSequence; + SHAMap::pointer mMap; + bool mHaveRoot; + + void onTimer() { trigger(Peer::pointer()); } + void newPeer(Peer::pointer peer) { trigger(peer); } + + void done(); + void trigger(Peer::pointer); + boost::weak_ptr pmDowncast(); public: - typedef boost::shared_ptr pointer; - // for remote positions - LCPosition(uint32 closingSeq, uint32 proposeSeq, const uint256& previousTxHash, - const uint256& currentTxHash, CKey::pointer nodePubKey, const std::string& signature); + TransactionAcquire(const uint256& hash); - // for our initial position - LCPosition(CKey::pointer privKey, uint32 ledgerSeq, const uint256& currentPosition); + SHAMap::pointer getMap() { return mMap; } - // for our subsequent positions - LCPosition(LCPosition::pointer previousPosition, CKey::pointer privKey, const uint256& newPosition); - - const uint256& getPubKeyHash() const { return mPubKeyHash; } - const uint256& getCurrentPosition() const { return mCurrentPosition; } - uint32 getSeq() const { return mSequence; } - - bool verifySignature(const uint256& hash, const std::vector& signature) const; - void setPosition(const uint256& position, uint32 sequence); + bool takeNode(const std::list& IDs, const std::list >& data, + Peer::pointer); }; - class LCTransaction { // A transaction that may be disputed protected: @@ -75,19 +71,24 @@ protected: Ledger::pointer mPreviousLedger, mCurrentLedger; LedgerProposal::pointer mCurrentProposal; - LCPosition::pointer mOurPosition; + LedgerProposal::pointer mOurPosition; // Convergence tracking, trusted peers indexed by hash of public key - boost::unordered_map mPeerPositions; + boost::unordered_map mPeerPositions; // Transaction Sets, indexed by hash of transaction tree - boost::unordered_map mComplete; - boost::unordered_map mAcquiring; + boost::unordered_map mComplete; + boost::unordered_map mAcquiring; // Peer sets - boost::unordered_map > > mPeerData; + boost::unordered_map >, hash_SMN> mPeerData; void weHave(const uint256& id, Peer::pointer avoidPeer); + void startAcquiring(TransactionAcquire::pointer); + SHAMap::pointer find(const uint256& hash); + + void addPosition(LedgerProposal&); + void removePosition(LedgerProposal&); public: LedgerConsensus(Ledger::pointer previousLedger, Ledger::pointer currentLedger) : @@ -98,21 +99,19 @@ public: Ledger::pointer peekPreviousLedger() { return mPreviousLedger; } Ledger::pointer peekCurrentLedger() { return mCurrentLedger; } - LCPosition::pointer getCreatePeerPosition(const uint256& pubKeyHash); - - SHAMap::pointer getTransactionTree(const uint256& hash); + SHAMap::pointer getTransactionTree(const uint256& hash, bool doAcquire); TransactionAcquire::pointer getAcquiring(const uint256& hash); void acquireComplete(const uint256& hash); - LCPosition::pointer getPeerPosition(const uint256& peer); - - // high-level functions void abort(); - bool peerPosition(Peer::pointer peer, const Serializer& report); + int timerEntry(void); + + bool peerPosition(LedgerProposal::pointer); + bool peerHasSet(Peer::pointer peer, const std::vector& sets); + bool peerGaveNodes(Peer::pointer peer, const uint256& setHash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); - int timerEntry(void); }; diff --git a/src/LedgerProposal.cpp b/src/LedgerProposal.cpp index 5ad65ffb5f..0c855d5d26 100644 --- a/src/LedgerProposal.cpp +++ b/src/LedgerProposal.cpp @@ -6,8 +6,8 @@ #include "key.h" #include "Application.h" -LedgerProposal::LedgerProposal(uint32 closingSeq, uint32 proposeSeq, const uint256& prevTx, const uint256& proposeTx, - const std::string& pubKey) : mPrevHash(prevTx), mCurrentHash(proposeTx), +LedgerProposal::LedgerProposal(uint32 closingSeq, uint32 proposeSeq, const uint256& proposeTx, + const std::string& pubKey) : mCurrentHash(proposeTx), mProposeSeq(proposeSeq), mKey(boost::make_shared()) { if (!mKey->SetPubKey(pubKey)) @@ -25,20 +25,18 @@ LedgerProposal::LedgerProposal(CKey::pointer mPrivateKey, const uint256& prevLgr LedgerProposal::LedgerProposal(LedgerProposal::pointer previous, const uint256& newp) : mPeerID(previous->mPeerID), mPreviousLedger(previous->mPreviousLedger), - mPrevHash(previous->mCurrentHash), mCurrentHash(newp), - mProposeSeq(previous->mProposeSeq + 1), mKey(previous->mKey) + mCurrentHash(newp), mProposeSeq(previous->mProposeSeq + 1), mKey(previous->mKey) { ; } uint256 LedgerProposal::getSigningHash() const { - Serializer s(104); + Serializer s(72); s.add32(sProposeMagic); s.add32(mProposeSeq); s.add256(mPreviousLedger); s.add256(mCurrentHash); - s.add256(mPrevHash); return s.getSHA512Half(); } diff --git a/src/LedgerProposal.h b/src/LedgerProposal.h index 82e101c3f8..f2e501aee9 100644 --- a/src/LedgerProposal.h +++ b/src/LedgerProposal.h @@ -13,7 +13,7 @@ class LedgerProposal { protected: - uint256 mPeerID, mPreviousLedger, mPrevHash, mCurrentHash; + uint256 mPeerID, mPreviousLedger, mCurrentHash; uint32 mProposeSeq; CKey::pointer mKey; // std::vector mAddedTx, mRemovedTx; @@ -25,8 +25,7 @@ public: typedef boost::shared_ptr pointer; // proposal from peer - LedgerProposal(uint32 closingSeq, uint32 proposeSeq, const uint256& prevTx, const uint256& propose, - const std::string& pubKey); + LedgerProposal(uint32 closingSeq, uint32 proposeSeq, const uint256& propose, const std::string& pubKey); // our first proposal LedgerProposal(CKey::pointer privateKey, const uint256& prevLedger, const uint256& position); @@ -38,7 +37,6 @@ public: bool checkSign(const std::string& signature); const uint256& getPeerID() const { return mPeerID; } - const uint256& getPrevHash() const { return mPrevHash; } const uint256& getCurrentHash() const { return mCurrentHash; } const uint256& getPrevLedger() const { return mPreviousLedger; } uint32 getProposeSeq() const { return mProposeSeq; } diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 9b665f25da..199c35de24 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -386,18 +386,36 @@ int NetworkOPs::beginConsensus(Ledger::pointer closingLedger) return mConsensus->startup(); } -bool NetworkOPs::proposeLedger(uint32 closingSeq, uint32 proposeSeq, - const uint256& prevHash, const uint256& proposeHash, const std::string& pubKey, const std::string& signature) +bool NetworkOPs::proposeLedger(uint32 closingSeq, uint32 proposeSeq, const uint256& proposeHash, + const std::string& pubKey, const std::string& signature) { - uint256 nodeID = Serializer::getSHA512Half(pubKey); + if (mMode != omFULL) + return true; + + LedgerProposal::pointer proposal = + boost::make_shared(closingSeq, proposeSeq, proposeHash, pubKey); + if (!proposal->checkSign(signature)) + { + std::cerr << "Ledger proposal fails signature check" << std::endl; + return false; + } // Is this node on our UNL? // WRITEME - // Are we currently closing? + Ledger::pointer currentLedger = theApp->getMasterLedger().getCurrentLedger(); - // Yes: Is it an update? - // WRITEME + if (!mConsensus) + { + if ((getNetworkTimeNC() + 2) >= currentLedger->getCloseTimeNC()) + setStateTimer(beginConsensus(currentLedger)); + if (!mConsensus) return true; + } - return true; + return mConsensus->peerPosition(proposal); +} + +SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash) +{ // WRITEME + return SHAMap::pointer(); } diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index f679a2df92..b926b058df 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -71,8 +71,9 @@ public: const std::vector& myNode, std::list >& newNodes); // ledger proposal/close functions - bool proposeLedger(uint32 closingSeq, uint32 proposeSeq, const uint256& prevHash, const uint256& proposeHash, + bool proposeLedger(uint32 closingSeq, uint32 proposeSeq, const uint256& proposeHash, const std::string& pubKey, const std::string& signature); + SHAMap::pointer getTXMap(const uint256& hash); // network state machine void checkState(const boost::system::error_code& result); diff --git a/src/Peer.cpp b/src/Peer.cpp index f5b15abd47..172c420294 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -603,16 +603,15 @@ void Peer::recvTransaction(newcoin::TMTransaction& packet) void Peer::recvPropose(boost::shared_ptr packet) { - if ((packet->previoustxhash().size() != 32) || (packet->currenttxhash().size() != 32) || - (packet->nodepubkey().size() < 28) || (packet->signature().size() < 56)) + if ((packet->currenttxhash().size() != 32) || (packet->nodepubkey().size() < 28) || + (packet->signature().size() < 56)) return; uint32 closingSeq = packet->closingseq(), proposeSeq = packet->proposeseq(); - uint256 previousTxHash, currentTxHash; - memcpy(previousTxHash.begin(), packet->previoustxhash().data(), 32); + uint256 currentTxHash; memcpy(currentTxHash.begin(), packet->currenttxhash().data(), 32); - if(theApp->getOPs().proposeLedger(closingSeq, proposeSeq, previousTxHash, currentTxHash, + if(theApp->getOPs().proposeLedger(closingSeq, proposeSeq, currentTxHash, packet->nodepubkey(), packet->signature())) { // FIXME: Not all nodes will want proposals PackedMessage::pointer message = boost::make_shared(packet, newcoin::mtPROPOSE_LEDGER); @@ -693,6 +692,25 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet) void Peer::recvGetLedger(newcoin::TMGetLedger& packet) { + if (packet.itype() == newcoin::liTS_CANDIDATE) + { + Ledger::pointer ledger; + if ((!packet.has_ledgerhash() || packet.ledgerhash().size() != 32)) + { + punishPeer(PP_INVALID_REQUEST); + return; + } + uint256 txHash; + memcpy(txHash.begin(), packet.ledgerhash().data(), 32); + SHAMap::pointer txMap = theApp->getOPs().getTXMap(txHash); + if (!txMap) + { + punishPeer(PP_INVALID_REQUEST); + return; + } + // WRITEME + } + // Figure out what ledger they want Ledger::pointer ledger; if (packet.has_ledgerhash()) @@ -703,7 +721,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) punishPeer(PP_INVALID_REQUEST); return; } - memcpy(&ledgerhash, packet.ledgerhash().data(), 32); + memcpy(ledgerhash.begin(), packet.ledgerhash().data(), 32); ledger = theApp->getMasterLedger().getLedgerByHash(ledgerhash); } else if (packet.has_ledgerseq()) @@ -750,7 +768,7 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) SHAMap::pointer map=(packet.itype()==newcoin::liTX_NODE) ? ledger->peekTransactionMap() : ledger->peekAccountStateMap(); if(!map) return; - if(packet.nodeids_size()==0) + if(packet.nodeids_size() == 0) { punishPeer(PP_INVALID_REQUEST); return; From 56a780e5c3c65253b4367d769ca9cda8fa2dbc8b Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 22 May 2012 07:56:38 -0700 Subject: [PATCH 06/10] Cleanups. --- src/Conversion.cpp | 2 +- src/LedgerAcquire.cpp | 12 ++++++------ src/LedgerConsensus.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Conversion.cpp b/src/Conversion.cpp index f1588f188c..a0ac3c1e91 100644 --- a/src/Conversion.cpp +++ b/src/Conversion.cpp @@ -23,7 +23,7 @@ uint160 humanTo160(const std::string& buf) vector retVec; DecodeBase58(buf,retVec); uint160 ret; - memcpy(reinterpret_cast(&ret), &retVec[0], ret.GetSerializeSize()); + memcpy(ret.begin(), &retVec[0], ret.GetSerializeSize()); return(ret); diff --git a/src/LedgerAcquire.cpp b/src/LedgerAcquire.cpp index 5bf98283f7..3228bbe488 100644 --- a/src/LedgerAcquire.cpp +++ b/src/LedgerAcquire.cpp @@ -250,7 +250,7 @@ void PeerSet::sendRequest(boost::shared_ptr tmGL) PackedMessage::pointer packet = boost::make_shared(tmGL, newcoin::mtGET_LEDGER); - std::vector >::iterator it = mPeers.begin(); + std::vector< boost::weak_ptr >::iterator it = mPeers.begin(); while (it != mPeers.end()) { if (it->expired()) @@ -291,11 +291,11 @@ bool LedgerAcquire::takeBase(const std::string& data, Peer::pointer peer) } bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, - const std::list >& data, Peer::pointer peer) + const std::list< std::vector >& data, Peer::pointer peer) { if (!mHaveBase) return false; std::list::const_iterator nodeIDit = nodeIDs.begin(); - std::list >::const_iterator nodeDatait = data.begin(); + std::list< std::vector >::const_iterator nodeDatait = data.begin(); while (nodeIDit != nodeIDs.end()) { if (nodeIDit->isRoot()) @@ -318,7 +318,7 @@ bool LedgerAcquire::takeTxNode(const std::list& nodeIDs, } bool LedgerAcquire::takeAsNode(const std::list& nodeIDs, - const std::list >& data, Peer::pointer peer) + const std::list< std::vector >& data, Peer::pointer peer) { #ifdef DEBUG std::cerr << "got ASdata acquiring ledger " << mHash.GetHex() << std::endl; @@ -391,7 +391,7 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi #endif return false; } - memcpy(&hash, packet.ledgerhash().data(), 32); + memcpy(hash.begin(), packet.ledgerhash().data(), 32); #ifdef DEBUG std::cerr << hash.GetHex() << std::endl; #endif @@ -409,7 +409,7 @@ bool LedgerAcquireMaster::gotLedgerData(newcoin::TMLedgerData& packet, Peer::poi else if ((packet.type() == newcoin::liTX_NODE) || (packet.type() == newcoin::liAS_NODE)) { std::list nodeIDs; - std::list > nodeData; + std::list< std::vector > nodeData; if (packet.nodes().size() <= 0) return false; for (int i = 0; i < packet.nodes().size(); ++i) diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h index f2ef4110ef..67ef0cd921 100644 --- a/src/LedgerConsensus.h +++ b/src/LedgerConsensus.h @@ -34,7 +34,7 @@ public: SHAMap::pointer getMap() { return mMap; } - bool takeNode(const std::list& IDs, const std::list >& data, + bool takeNode(const std::list& IDs, const std::list< std::vector >& data, Peer::pointer); }; From 00077bff16d29b4400b085cd9b868cd75b46bbe7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 22 May 2012 07:56:53 -0700 Subject: [PATCH 07/10] Missing stubs. --- src/NetworkOPs.cpp | 6 ++++++ src/NetworkOPs.h | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 199c35de24..894a092ab9 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -419,3 +419,9 @@ SHAMap::pointer NetworkOPs::getTXMap(const uint256& hash) { // WRITEME return SHAMap::pointer(); } + +bool NetworkOPs::gotTXData(boost::shared_ptr peer, const uint256& hash, + const std::list& nodeIDs, const std::list< std::vector >& nodeData) +{ // WRITEME + return true; +} diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index b926b058df..4bf636ad97 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -66,13 +66,15 @@ public: // tree synchronization operations bool getTransactionTreeNodes(uint32 ledgerSeq, const uint256& myNodeID, - const std::vector& myNode, std::list >& newNodes); + const std::vector& myNode, std::list< std::vector >& newNodes); bool getAccountStateNodes(uint32 ledgerSeq, const uint256& myNodeId, - const std::vector& myNode, std::list >& newNodes); + const std::vector& myNode, std::list< std::vector >& newNodes); // ledger proposal/close functions bool proposeLedger(uint32 closingSeq, uint32 proposeSeq, const uint256& proposeHash, const std::string& pubKey, const std::string& signature); + bool gotTXData(boost::shared_ptr peer, const uint256& hash, + const std::list& nodeIDs, const std::list< std::vector >& nodeData); SHAMap::pointer getTXMap(const uint256& hash); // network state machine From b17109ccac9c9fcd8ed72d1842fcfde00d921551 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 22 May 2012 07:57:11 -0700 Subject: [PATCH 08/10] Cleanup. --- src/Serializer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Serializer.cpp b/src/Serializer.cpp index 91b8dcf755..df891070bf 100644 --- a/src/Serializer.cpp +++ b/src/Serializer.cpp @@ -144,7 +144,7 @@ uint256 Serializer::get256(int offset) const { uint256 ret; if ((offset + (256 / 8)) > mData.size()) return ret; - memcpy(&ret, &(mData.front()) + offset, (256 / 8)); + memcpy(ret.begin(), &(mData.front()) + offset, (256 / 8)); return ret; } From 495be805048ee465970f34281fc639ceb71457b7 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 22 May 2012 07:57:15 -0700 Subject: [PATCH 09/10] Remove ltCLOSING, it's not needed. --- src/newcoin.proto | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/newcoin.proto b/src/newcoin.proto index c2c99811e4..17d7bde493 100644 --- a/src/newcoin.proto +++ b/src/newcoin.proto @@ -220,13 +220,12 @@ enum TMLedgerInfoType { enum TMLedgerType { ltACCEPTED = 0; ltCURRENT = 1; - ltCLOSING = 2; - ltCLOSED = 3; + ltCLOSED = 2; } message TMGetLedger { optional TMLedgerType ltype = 1; - optional bytes ledgerHash = 2; + optional bytes ledgerHash = 2; // Can also be the transaction set hash if liTS_CANDIDATE optional uint32 ledgerSeq = 3; required TMLedgerInfoType itype = 4; repeated bytes nodeIDs = 5; From 0c821d176cd4b6b74320ddc95efa7735c17b60c2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 22 May 2012 07:57:33 -0700 Subject: [PATCH 10/10] Peer logic for handling requests and responses for TX set data during ledger consensus building. --- src/Peer.cpp | 210 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 123 insertions(+), 87 deletions(-) diff --git a/src/Peer.cpp b/src/Peer.cpp index 172c420294..a39e5224b4 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -692,8 +692,11 @@ void Peer::recvStatus(newcoin::TMStatusChange& packet) void Peer::recvGetLedger(newcoin::TMGetLedger& packet) { + SHAMap::pointer map; + boost::shared_ptr reply = boost::make_shared(); + if (packet.itype() == newcoin::liTS_CANDIDATE) - { + { // Request is for a transaction candidate set Ledger::pointer ledger; if ((!packet.has_ledgerhash() || packet.ledgerhash().size() != 32)) { @@ -702,115 +705,148 @@ void Peer::recvGetLedger(newcoin::TMGetLedger& packet) } uint256 txHash; memcpy(txHash.begin(), packet.ledgerhash().data(), 32); - SHAMap::pointer txMap = theApp->getOPs().getTXMap(txHash); - if (!txMap) + map = theApp->getOPs().getTXMap(txHash); + if (!map) { punishPeer(PP_INVALID_REQUEST); return; } - // WRITEME - } - - // Figure out what ledger they want - Ledger::pointer ledger; - if (packet.has_ledgerhash()) - { - uint256 ledgerhash; - if (packet.ledgerhash().size() != 32) - { - punishPeer(PP_INVALID_REQUEST); - return; - } - memcpy(ledgerhash.begin(), packet.ledgerhash().data(), 32); - ledger = theApp->getMasterLedger().getLedgerByHash(ledgerhash); - } - else if (packet.has_ledgerseq()) - ledger = theApp->getMasterLedger().getLedgerBySeq(packet.ledgerseq()); - else if (packet.has_ltype() && (packet.ltype() == newcoin::ltCURRENT)) - ledger = theApp->getMasterLedger().getCurrentLedger(); - else if (packet.has_ltype() && (packet.ltype() == newcoin::ltCLOSING)) - { - ledger = theApp->getMasterLedger().getClosedLedger(); - } - else if (packet.has_ltype() && (packet.ltype() == newcoin::ltCLOSED) ) - { - ledger = theApp->getMasterLedger().getClosedLedger(); - if (ledger && !ledger->isClosed()) - ledger = theApp->getMasterLedger().getLedgerBySeq(ledger->getLedgerSeq() - 1); + reply->set_ledgerhash(txHash.begin(), txHash.size()); + reply->set_type(newcoin::liTS_CANDIDATE); } else - { - punishPeer(PP_INVALID_REQUEST); - return; - } - - if( (!ledger) || (packet.has_ledgerseq() && (packet.ledgerseq()!=ledger->getLedgerSeq())) ) - { - punishPeer(PP_UNKNOWN_REQUEST); - return; - } - - // Figure out what information they want - boost::shared_ptr data = boost::make_shared(); - uint256 lHash = ledger->getHash(); - data->set_ledgerhash(lHash.begin(), lHash.size()); - data->set_ledgerseq(ledger->getLedgerSeq()); - data->set_type(packet.itype()); - - if(packet.itype() == newcoin::liBASE) - { - Serializer nData(116); - ledger->addRaw(nData); - data->add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength()); - } - else if ( (packet.itype()==newcoin::liTX_NODE) || (packet.itype()==newcoin::liAS_NODE) ) - { - SHAMap::pointer map=(packet.itype()==newcoin::liTX_NODE) ? ledger->peekTransactionMap() - : ledger->peekAccountStateMap(); - if(!map) return; - if(packet.nodeids_size() == 0) + { // Figure out what ledger they want + Ledger::pointer ledger; + if (packet.has_ledgerhash()) { - punishPeer(PP_INVALID_REQUEST); - return; - } - for(int i=0; i nodeIDs; - std::list > rawNodes; - if(map->getNodeFat(mn, nodeIDs, rawNodes)) - { - std::vector::iterator nodeIDIterator; - std::list >::iterator rawNodeIterator; - for(nodeIDIterator = nodeIDs.begin(), rawNodeIterator = rawNodes.begin(); - nodeIDIterator != nodeIDs.end(); ++nodeIDIterator, ++rawNodeIterator) - { - Serializer nID(33); - nodeIDIterator->addIDRaw(nID); - newcoin::TMLedgerNode* node = data->add_nodes(); - node->set_nodeid(nID.getDataPtr(), nID.getLength()); - node->set_nodedata(&rawNodeIterator->front(), rawNodeIterator->size()); - } - } + memcpy(ledgerhash.begin(), packet.ledgerhash().data(), 32); + ledger = theApp->getMasterLedger().getLedgerByHash(ledgerhash); } + else if (packet.has_ledgerseq()) + ledger = theApp->getMasterLedger().getLedgerBySeq(packet.ledgerseq()); + else if (packet.has_ltype() && (packet.ltype() == newcoin::ltCURRENT)) + ledger = theApp->getMasterLedger().getCurrentLedger(); + else if (packet.has_ltype() && (packet.ltype() == newcoin::ltCLOSED) ) + { + ledger = theApp->getMasterLedger().getClosedLedger(); + if (ledger && !ledger->isClosed()) + ledger = theApp->getMasterLedger().getLedgerBySeq(ledger->getLedgerSeq() - 1); + } + else + { + punishPeer(PP_INVALID_REQUEST); + return; + } + + if( (!ledger) || (packet.has_ledgerseq() && (packet.ledgerseq()!=ledger->getLedgerSeq())) ) + { + punishPeer(PP_UNKNOWN_REQUEST); + return; + } + + // Fill out the reply + uint256 lHash = ledger->getHash(); + reply->set_ledgerhash(lHash.begin(), lHash.size()); + reply->set_ledgerseq(ledger->getLedgerSeq()); + reply->set_type(packet.itype()); + + if(packet.itype() == newcoin::liBASE) + { // they want the ledger base data + Serializer nData(128); + ledger->addRaw(nData); + reply->add_nodes()->set_nodedata(nData.getDataPtr(), nData.getLength()); + PackedMessage::pointer oPacket = boost::make_shared + (PackedMessage::MessagePointer(reply), newcoin::mtLEDGER); + sendPacket(oPacket); + return; + } + + if ((packet.itype() == newcoin::liTX_NODE) || (packet.itype() == newcoin::liAS_NODE)) + map = (packet.itype() == newcoin::liTX_NODE) ? + ledger->peekTransactionMap() : ledger->peekAccountStateMap(); } - else + + if ((!map) || (packet.nodeids_size() == 0)) { punishPeer(PP_INVALID_REQUEST); return; } + + for(int i = 0; i nodeIDs; + std::list< std::vector > rawNodes; + if(map->getNodeFat(mn, nodeIDs, rawNodes)) + { + std::vector::iterator nodeIDIterator; + std::list< std::vector >::iterator rawNodeIterator; + for(nodeIDIterator = nodeIDs.begin(), rawNodeIterator = rawNodes.begin(); + nodeIDIterator != nodeIDs.end(); ++nodeIDIterator, ++rawNodeIterator) + { + Serializer nID(33); + nodeIDIterator->addIDRaw(nID); + newcoin::TMLedgerNode* node = reply->add_nodes(); + node->set_nodeid(nID.getDataPtr(), nID.getLength()); + node->set_nodedata(&rawNodeIterator->front(), rawNodeIterator->size()); + } + } + } PackedMessage::pointer oPacket = boost::make_shared - (PackedMessage::MessagePointer(data), newcoin::mtLEDGER); + (PackedMessage::MessagePointer(reply), newcoin::mtLEDGER); sendPacket(oPacket); } void Peer::recvLedger(newcoin::TMLedgerData& packet) { + if (packet.nodes().size() <= 0) + { + punishPeer(PP_INVALID_REQUEST); + return; + } + + if (packet.type() == newcoin::liTS_CANDIDATE) + { // got data for a candidate transaction set + uint256 hash; + if(packet.ledgerhash().size() != 32) + { + punishPeer(PP_INVALID_REQUEST); + return; + } + memcpy(hash.begin(), packet.ledgerhash().data(), 32); + + + std::list nodeIDs; + std::list< std::vector > nodeData; + + for (int i = 0; i < packet.nodes().size(); ++i) + { + const newcoin::TMLedgerNode& node = packet.nodes(i); + if (!node.has_nodeid() || !node.has_nodedata()) + { + punishPeer(PP_INVALID_REQUEST); + return; + } + + nodeIDs.push_back(SHAMapNode(node.nodeid().data(), node.nodeid().size())); + nodeData.push_back(std::vector(node.nodedata().begin(), node.nodedata().end())); + } + if (!theApp->getOPs().gotTXData(shared_from_this(), hash, nodeIDs, nodeData)) + punishPeer(PP_UNWANTED_DATA); + return; + } + if (!theApp->getMasterLedgerAcquire().gotLedgerData(packet, shared_from_this())) punishPeer(PP_UNWANTED_DATA); }