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;
+}
+