diff --git a/newcoin.vcxproj b/newcoin.vcxproj index 21c419eb19..fbd79cb56d 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -174,6 +174,7 @@ + diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index e828b851f2..961347ae6f 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -243,6 +243,9 @@ Source Files + + Source Files + Source Files diff --git a/ripple2010.vcxproj b/ripple2010.vcxproj index e785bc9c3c..843c6f9dcf 100644 --- a/ripple2010.vcxproj +++ b/ripple2010.vcxproj @@ -174,6 +174,7 @@ + diff --git a/ripple2010.vcxproj.filters b/ripple2010.vcxproj.filters index bec881141d..0ef380379d 100644 --- a/ripple2010.vcxproj.filters +++ b/ripple2010.vcxproj.filters @@ -240,6 +240,9 @@ Source Files + + Source Files + Source Files diff --git a/src/cpp/ripple/LedgerConsensus.cpp b/src/cpp/ripple/LedgerConsensus.cpp index d4fc7d97fa..cabccb7e0a 100644 --- a/src/cpp/ripple/LedgerConsensus.cpp +++ b/src/cpp/ripple/LedgerConsensus.cpp @@ -14,8 +14,6 @@ #include "Log.h" #include "SHAMapSync.h" -#define TX_ACQUIRE_TIMEOUT 250 - #define LEDGER_TOTAL_PASSES 8 #define LEDGER_RETRY_PASSES 5 @@ -28,270 +26,6 @@ typedef std::map::value_type u256_lct_pair; SETUP_LOG(); DECLARE_INSTANCE(LedgerConsensus); -DECLARE_INSTANCE(TransactionAcquire); - -TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false) -{ - mMap = boost::make_shared(smtTRANSACTION, hash); -} - -void TransactionAcquire::done() -{ - if (mFailed) - { - cLog(lsWARNING) << "Failed to acquire TX set " << mHash; - theApp->getOPs().mapComplete(mHash, SHAMap::pointer()); - } - else - { - cLog(lsINFO) << "Acquired TX set " << mHash; - mMap->setImmutable(); - theApp->getOPs().mapComplete(mHash, mMap); - } - theApp->getMasterLedgerAcquire().dropLedger(mHash); -} - -void TransactionAcquire::onTimer(bool progress) -{ - if (!getPeerCount()) - { // out of peers - cLog(lsWARNING) << "Out of peers for TX set " << getHash(); - - bool found = false; - std::vector peerList = theApp->getConnectionPool().getPeerVector(); - BOOST_FOREACH(Peer::ref peer, peerList) - { - if (peer->hasTxSet(getHash())) - { - found = true; - peerHas(peer); - } - } - if (!found) - { - BOOST_FOREACH(Peer::ref peer, peerList) - peerHas(peer); - } - } - else if (!progress) - trigger(Peer::pointer()); -} - -boost::weak_ptr TransactionAcquire::pmDowncast() -{ - return boost::shared_polymorphic_downcast(shared_from_this()); -} - -void TransactionAcquire::trigger(Peer::ref peer) -{ - if (mComplete || mFailed) - { - cLog(lsINFO) << "complete or failed"; - return; - } - if (!mHaveRoot) - { - cLog(lsTRACE) << "TransactionAcquire::trigger " << (peer ? "havePeer" : "noPeer") << " no root"; - ripple::TMGetLedger tmGL; - tmGL.set_ledgerhash(mHash.begin(), mHash.size()); - tmGL.set_itype(ripple::liTS_CANDIDATE); - if (getTimeouts() != 0) - tmGL.set_querytype(ripple::qtINDIRECT); - *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); - sendRequest(tmGL, peer); - } - else - { - std::vector nodeIDs; - std::vector nodeHashes; - ConsensusTransSetSF sf; - mMap->getMissingNodes(nodeIDs, nodeHashes, 256, &sf); - if (nodeIDs.empty()) - { - if (mMap->isValid()) - mComplete = true; - else - mFailed = true; - done(); - return; - } - ripple::TMGetLedger tmGL; - tmGL.set_ledgerhash(mHash.begin(), mHash.size()); - tmGL.set_itype(ripple::liTS_CANDIDATE); - if (getTimeouts() != 0) - tmGL.set_querytype(ripple::qtINDIRECT); - BOOST_FOREACH(SHAMapNode& it, nodeIDs) - *(tmGL.add_nodeids()) = it.getRawString(); - sendRequest(tmGL, peer); - } -} - -SMAddNode TransactionAcquire::takeNodes(const std::list& nodeIDs, - const std::list< std::vector >& data, Peer::ref peer) -{ - if (mComplete) - { - cLog(lsTRACE) << "TX set complete"; - return SMAddNode(); - } - if (mFailed) - { - cLog(lsTRACE) << "TX set failed"; - return SMAddNode(); - } - try - { - if (nodeIDs.empty()) - return SMAddNode::invalid(); - std::list::const_iterator nodeIDit = nodeIDs.begin(); - std::list< std::vector >::const_iterator nodeDatait = data.begin(); - ConsensusTransSetSF sf; - while (nodeIDit != nodeIDs.end()) - { - if (nodeIDit->isRoot()) - { - if (mHaveRoot) - { - cLog(lsWARNING) << "Got root TXS node, already have it"; - return SMAddNode(); - } - if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE, NULL)) - { - cLog(lsWARNING) << "TX acquire got bad root node"; - return SMAddNode::invalid(); - } - else - mHaveRoot = true; - } - else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait, &sf)) - { - cLog(lsWARNING) << "TX acquire got bad non-root node"; - return SMAddNode::invalid(); - } - ++nodeIDit; - ++nodeDatait; - } - trigger(peer); - progress(); - return SMAddNode::useful(); - } - catch (...) - { - cLog(lsERROR) << "Peer sends us junky transaction node data"; - return SMAddNode::invalid(); - } -} - -void LCTransaction::setVote(const uint160& peer, bool votesYes) -{ // Track a peer's yes/no vote on a particular disputed transaction - std::pair::iterator, bool> res = - mVotes.insert(std::pair(peer, votesYes)); - - if (res.second) - { // new vote - if (votesYes) - { - cLog(lsDEBUG) << "Peer " << peer << " votes YES on " << mTransactionID; - ++mYays; - } - else - { - cLog(lsDEBUG) << "Peer " << peer << " votes NO on " << mTransactionID; - ++mNays; - } - } - else if (votesYes && !res.first->second) - { // changes vote to yes - cLog(lsDEBUG) << "Peer " << peer << " now votes YES on " << mTransactionID; - --mNays; - ++mYays; - res.first->second = true; - } - else if (!votesYes && res.first->second) - { // changes vote to no - cLog(lsDEBUG) << "Peer " << peer << " now votes NO on " << mTransactionID; - ++mNays; - --mYays; - res.first->second = false; - } -} - -void LCTransaction::unVote(const uint160& peer) -{ // Remove a peer's vote on this disputed transasction - boost::unordered_map::iterator it = mVotes.find(peer); - if (it != mVotes.end()) - { - if (it->second) - --mYays; - else - --mNays; - mVotes.erase(it); - } -} - -bool LCTransaction::updateVote(int percentTime, bool proposing) -{ - if (mOurVote && (mNays == 0)) - return false; - if (!mOurVote && (mYays == 0)) - return false; - - bool newPosition; - int weight; - if (proposing) // give ourselves full weight - { - // This is basically the percentage of nodes voting 'yes' (including us) - weight = (mYays * 100 + (mOurVote ? 100 : 0)) / (mNays + mYays + 1); - - // To prevent avalanche stalls, we increase the needed weight slightly over time - if (percentTime < AV_MID_CONSENSUS_TIME) - newPosition = weight > AV_INIT_CONSENSUS_PCT; - else if (percentTime < AV_LATE_CONSENSUS_TIME) - newPosition = weight > AV_MID_CONSENSUS_PCT; - else if (percentTime < AV_STUCK_CONSENSUS_TIME) - newPosition = weight > AV_LATE_CONSENSUS_PCT; - else - newPosition = weight > AV_STUCK_CONSENSUS_PCT; - } - else // don't let us outweigh a proposing node, just recognize consensus - { - weight = -1; - newPosition = mYays > mNays; - } - - if (newPosition == mOurVote) - { - cLog(lsINFO) << - "No change (" << (mOurVote ? "YES" : "NO") << ") : weight " << weight << ", percent " << percentTime; - cLog(lsDEBUG) << getJson(); - return false; - } - - mOurVote = newPosition; - cLog(lsDEBUG) << "We now vote " << (mOurVote ? "YES" : "NO") << " on " << mTransactionID; - cLog(lsDEBUG) << getJson(); - return true; -} - -Json::Value LCTransaction::getJson() -{ - Json::Value ret(Json::objectValue); - - ret["yays"] = mYays; - ret["nays"] = mNays; - ret["our_vote"] = mOurVote; - if (!mVotes.empty()) - { - Json::Value votesj(Json::objectValue); - typedef boost::unordered_map::value_type vt; - BOOST_FOREACH(vt& vote, mVotes) - { - votesj[vote.first.GetHex()] = vote.second; - } - ret["votes"] = votesj; - } - return ret; -} LedgerConsensus::LedgerConsensus(const uint256& prevLCLHash, Ledger::ref previousLedger, uint32 closeTime) : mState(lcsPRE_CLOSE), mCloseTime(closeTime), mPrevLedgerHash(prevLCLHash), mPreviousLedger(previousLedger), diff --git a/src/cpp/ripple/TransactionAcquire.cpp b/src/cpp/ripple/TransactionAcquire.cpp new file mode 100644 index 0000000000..b8e53a7d02 --- /dev/null +++ b/src/cpp/ripple/TransactionAcquire.cpp @@ -0,0 +1,287 @@ +#include "LedgerConsensus.h" + +#include +#include +#include +#include + +#include "../json/writer.h" + +#include "Application.h" +#include "NetworkOPs.h" +#include "LedgerTiming.h" +#include "SerializedValidation.h" +#include "Log.h" +#include "SHAMapSync.h" + +#define TX_ACQUIRE_TIMEOUT 250 + +typedef std::map::value_type u160_prop_pair; +typedef std::map::value_type u256_lct_pair; + +SETUP_LOG(); +DECLARE_INSTANCE(TransactionAcquire); + +TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false) +{ + mMap = boost::make_shared(smtTRANSACTION, hash); +} + +void TransactionAcquire::done() +{ + if (mFailed) + { + cLog(lsWARNING) << "Failed to acquire TX set " << mHash; + theApp->getOPs().mapComplete(mHash, SHAMap::pointer()); + } + else + { + cLog(lsINFO) << "Acquired TX set " << mHash; + mMap->setImmutable(); + theApp->getOPs().mapComplete(mHash, mMap); + } + theApp->getMasterLedgerAcquire().dropLedger(mHash); +} + +void TransactionAcquire::onTimer(bool progress) +{ + if (!getPeerCount()) + { // out of peers + cLog(lsWARNING) << "Out of peers for TX set " << getHash(); + + bool found = false; + std::vector peerList = theApp->getConnectionPool().getPeerVector(); + BOOST_FOREACH(Peer::ref peer, peerList) + { + if (peer->hasTxSet(getHash())) + { + found = true; + peerHas(peer); + } + } + if (!found) + { + BOOST_FOREACH(Peer::ref peer, peerList) + peerHas(peer); + } + } + else if (!progress) + trigger(Peer::pointer()); +} + +boost::weak_ptr TransactionAcquire::pmDowncast() +{ + return boost::shared_polymorphic_downcast(shared_from_this()); +} + +void TransactionAcquire::trigger(Peer::ref peer) +{ + if (mComplete || mFailed) + { + cLog(lsINFO) << "complete or failed"; + return; + } + if (!mHaveRoot) + { + cLog(lsTRACE) << "TransactionAcquire::trigger " << (peer ? "havePeer" : "noPeer") << " no root"; + ripple::TMGetLedger tmGL; + tmGL.set_ledgerhash(mHash.begin(), mHash.size()); + tmGL.set_itype(ripple::liTS_CANDIDATE); + if (getTimeouts() != 0) + tmGL.set_querytype(ripple::qtINDIRECT); + *(tmGL.add_nodeids()) = SHAMapNode().getRawString(); + sendRequest(tmGL, peer); + } + else + { + std::vector nodeIDs; + std::vector nodeHashes; + ConsensusTransSetSF sf; + mMap->getMissingNodes(nodeIDs, nodeHashes, 256, &sf); + if (nodeIDs.empty()) + { + if (mMap->isValid()) + mComplete = true; + else + mFailed = true; + done(); + return; + } + ripple::TMGetLedger tmGL; + tmGL.set_ledgerhash(mHash.begin(), mHash.size()); + tmGL.set_itype(ripple::liTS_CANDIDATE); + if (getTimeouts() != 0) + tmGL.set_querytype(ripple::qtINDIRECT); + BOOST_FOREACH(SHAMapNode& it, nodeIDs) + *(tmGL.add_nodeids()) = it.getRawString(); + sendRequest(tmGL, peer); + } +} + +SMAddNode TransactionAcquire::takeNodes(const std::list& nodeIDs, + const std::list< std::vector >& data, Peer::ref peer) +{ + if (mComplete) + { + cLog(lsTRACE) << "TX set complete"; + return SMAddNode(); + } + if (mFailed) + { + cLog(lsTRACE) << "TX set failed"; + return SMAddNode(); + } + try + { + if (nodeIDs.empty()) + return SMAddNode::invalid(); + std::list::const_iterator nodeIDit = nodeIDs.begin(); + std::list< std::vector >::const_iterator nodeDatait = data.begin(); + ConsensusTransSetSF sf; + while (nodeIDit != nodeIDs.end()) + { + if (nodeIDit->isRoot()) + { + if (mHaveRoot) + { + cLog(lsWARNING) << "Got root TXS node, already have it"; + return SMAddNode(); + } + if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE, NULL)) + { + cLog(lsWARNING) << "TX acquire got bad root node"; + return SMAddNode::invalid(); + } + else + mHaveRoot = true; + } + else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait, &sf)) + { + cLog(lsWARNING) << "TX acquire got bad non-root node"; + return SMAddNode::invalid(); + } + ++nodeIDit; + ++nodeDatait; + } + trigger(peer); + progress(); + return SMAddNode::useful(); + } + catch (...) + { + cLog(lsERROR) << "Peer sends us junky transaction node data"; + return SMAddNode::invalid(); + } +} + +void LCTransaction::setVote(const uint160& peer, bool votesYes) +{ // Track a peer's yes/no vote on a particular disputed transaction + std::pair::iterator, bool> res = + mVotes.insert(std::pair(peer, votesYes)); + + if (res.second) + { // new vote + if (votesYes) + { + cLog(lsDEBUG) << "Peer " << peer << " votes YES on " << mTransactionID; + ++mYays; + } + else + { + cLog(lsDEBUG) << "Peer " << peer << " votes NO on " << mTransactionID; + ++mNays; + } + } + else if (votesYes && !res.first->second) + { // changes vote to yes + cLog(lsDEBUG) << "Peer " << peer << " now votes YES on " << mTransactionID; + --mNays; + ++mYays; + res.first->second = true; + } + else if (!votesYes && res.first->second) + { // changes vote to no + cLog(lsDEBUG) << "Peer " << peer << " now votes NO on " << mTransactionID; + ++mNays; + --mYays; + res.first->second = false; + } +} + +void LCTransaction::unVote(const uint160& peer) +{ // Remove a peer's vote on this disputed transasction + boost::unordered_map::iterator it = mVotes.find(peer); + if (it != mVotes.end()) + { + if (it->second) + --mYays; + else + --mNays; + mVotes.erase(it); + } +} + +bool LCTransaction::updateVote(int percentTime, bool proposing) +{ + if (mOurVote && (mNays == 0)) + return false; + if (!mOurVote && (mYays == 0)) + return false; + + bool newPosition; + int weight; + if (proposing) // give ourselves full weight + { + // This is basically the percentage of nodes voting 'yes' (including us) + weight = (mYays * 100 + (mOurVote ? 100 : 0)) / (mNays + mYays + 1); + + // To prevent avalanche stalls, we increase the needed weight slightly over time + if (percentTime < AV_MID_CONSENSUS_TIME) + newPosition = weight > AV_INIT_CONSENSUS_PCT; + else if (percentTime < AV_LATE_CONSENSUS_TIME) + newPosition = weight > AV_MID_CONSENSUS_PCT; + else if (percentTime < AV_STUCK_CONSENSUS_TIME) + newPosition = weight > AV_LATE_CONSENSUS_PCT; + else + newPosition = weight > AV_STUCK_CONSENSUS_PCT; + } + else // don't let us outweigh a proposing node, just recognize consensus + { + weight = -1; + newPosition = mYays > mNays; + } + + if (newPosition == mOurVote) + { + cLog(lsINFO) << + "No change (" << (mOurVote ? "YES" : "NO") << ") : weight " << weight << ", percent " << percentTime; + cLog(lsDEBUG) << getJson(); + return false; + } + + mOurVote = newPosition; + cLog(lsDEBUG) << "We now vote " << (mOurVote ? "YES" : "NO") << " on " << mTransactionID; + cLog(lsDEBUG) << getJson(); + return true; +} + +Json::Value LCTransaction::getJson() +{ + Json::Value ret(Json::objectValue); + + ret["yays"] = mYays; + ret["nays"] = mNays; + ret["our_vote"] = mOurVote; + if (!mVotes.empty()) + { + Json::Value votesj(Json::objectValue); + typedef boost::unordered_map::value_type vt; + BOOST_FOREACH(vt& vote, mVotes) + { + votesj[vote.first.GetHex()] = vote.second; + } + ret["votes"] = votesj; + } + return ret; +} +