From 441a27dffdc2e242d0b909f988ca9935b9859320 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 22 May 2012 02:35:47 -0700 Subject: [PATCH] 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;