mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "Ledger.h"
|
||||
#include "Serializer.h"
|
||||
#include "Log.h"
|
||||
|
||||
AccountState::AccountState(const NewcoinAddress& naAccountID) : mAccountID(naAccountID), mValid(false)
|
||||
{
|
||||
@@ -59,11 +60,8 @@ void AccountState::addJson(Json::Value& val)
|
||||
void AccountState::dump()
|
||||
{
|
||||
Json::Value j(Json::objectValue);
|
||||
|
||||
addJson(j);
|
||||
|
||||
Json::StyledStreamWriter ssw;
|
||||
ssw.write(std::cerr, j);
|
||||
Log(lsINFO) << j;
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -78,6 +78,7 @@ public:
|
||||
NetworkOPs& getOPs() { return mNetOps; }
|
||||
|
||||
boost::asio::io_service& getIOService() { return mIOService; }
|
||||
boost::asio::io_service& getAuxService() { return mAuxService; }
|
||||
|
||||
LedgerMaster& getMasterLedger() { return mMasterLedger; }
|
||||
LedgerAcquireMaster& getMasterLedgerAcquire() { return mMasterLedgerAcquire; }
|
||||
|
||||
@@ -14,6 +14,7 @@ const char *TxnDBInit[] = {
|
||||
LedgerSeq BIGINT UNSIGNED, \
|
||||
Status CHARACTER(1), \
|
||||
RawTxn BLOB \
|
||||
TxnMeta BLOB \
|
||||
);",
|
||||
"CREATE TABLE PubKeys ( \
|
||||
ID CHARACTER(35) PRIMARY KEY, \
|
||||
|
||||
109
src/Ledger.cpp
109
src/Ledger.cpp
@@ -211,35 +211,51 @@ RippleState::pointer Ledger::accessRippleState(const uint256& uNode)
|
||||
return boost::make_shared<RippleState>(sle);
|
||||
}
|
||||
|
||||
bool Ledger::addTransaction(const Transaction::pointer& trans)
|
||||
bool Ledger::addTransaction(const uint256& txID, const Serializer& txn)
|
||||
{ // low-level - just add to table
|
||||
assert(!mAccepted);
|
||||
assert(trans->getID().isNonZero());
|
||||
Serializer s;
|
||||
trans->getSTransaction()->add(s);
|
||||
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(trans->getID(), s.peekData());
|
||||
if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata
|
||||
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(txID, txn.peekData());
|
||||
if (!mTransactionMap->addGiveItem(item, true, false))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ledger::addTransaction(const uint256& txID, const Serializer& txn)
|
||||
bool Ledger::addTransaction(const uint256& txID, const Serializer& txn, const Serializer& md)
|
||||
{ // low-level - just add to table
|
||||
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(txID, txn.peekData());
|
||||
if (!mTransactionMap->addGiveItem(item, true, false)) // FIXME: TX metadata
|
||||
Serializer s(txn.getDataLength() + md.getDataLength() + 64);
|
||||
s.addVL(txn.peekData());
|
||||
s.addVL(md.peekData());
|
||||
SHAMapItem::pointer item = boost::make_shared<SHAMapItem>(txID, s.peekData());
|
||||
if (!mTransactionMap->addGiveItem(item, true, true))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Transaction::pointer Ledger::getTransaction(const uint256& transID) const
|
||||
{
|
||||
SHAMapItem::pointer item = mTransactionMap->peekItem(transID);
|
||||
SHAMapTreeNode::TNType type;
|
||||
SHAMapItem::pointer item = mTransactionMap->peekItem(transID, type);
|
||||
if (!item) return Transaction::pointer();
|
||||
|
||||
Transaction::pointer txn = theApp->getMasterTransaction().fetch(transID, false);
|
||||
if (txn) return txn;
|
||||
if (txn)
|
||||
return txn;
|
||||
|
||||
if (type == SHAMapTreeNode::tnTRANSACTION_NM)
|
||||
txn = Transaction::sharedTransaction(item->getData(), true);
|
||||
else if (type == SHAMapTreeNode::tnTRANSACTION_MD)
|
||||
{
|
||||
std::vector<unsigned char> txnData;
|
||||
int txnLength;
|
||||
if (!item->peekSerializer().getVL(txnData, 0, txnLength))
|
||||
return Transaction::pointer();
|
||||
txn = Transaction::sharedTransaction(txnData, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
return Transaction::pointer();
|
||||
}
|
||||
|
||||
txn = Transaction::sharedTransaction(item->getData(), true);
|
||||
if (txn->getStatus() == NEW)
|
||||
txn->setStatus(mClosed ? COMMITTED : INCLUDED, mLedgerSeq);
|
||||
|
||||
@@ -247,6 +263,39 @@ Transaction::pointer Ledger::getTransaction(const uint256& transID) const
|
||||
return txn;
|
||||
}
|
||||
|
||||
bool Ledger::getTransaction(const uint256& txID, Transaction::pointer& txn, TransactionMetaSet::pointer& meta)
|
||||
{
|
||||
SHAMapTreeNode::TNType type;
|
||||
SHAMapItem::pointer item = mTransactionMap->peekItem(txID, type);
|
||||
if (!item)
|
||||
return false;
|
||||
|
||||
if (type == SHAMapTreeNode::tnTRANSACTION_NM)
|
||||
{ // in tree with no metadata
|
||||
txn = theApp->getMasterTransaction().fetch(txID, false);
|
||||
meta = TransactionMetaSet::pointer();
|
||||
if (!txn)
|
||||
txn = Transaction::sharedTransaction(item->getData(), true);
|
||||
}
|
||||
else if (type == SHAMapTreeNode::tnTRANSACTION_MD)
|
||||
{ // in tree with metadata
|
||||
SerializerIterator it(item->getData());
|
||||
txn = theApp->getMasterTransaction().fetch(txID, false);
|
||||
if (!txn)
|
||||
txn = Transaction::sharedTransaction(it.getVL(), true);
|
||||
else
|
||||
it.getVL(); // skip transaction
|
||||
meta = boost::make_shared<TransactionMetaSet>(mLedgerSeq, it.getVL());
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
if (txn->getStatus() == NEW)
|
||||
txn->setStatus(mClosed ? COMMITTED : INCLUDED, mLedgerSeq);
|
||||
theApp->getMasterTransaction().canonicalize(txn, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Ledger::unitTest()
|
||||
{
|
||||
return true;
|
||||
@@ -440,14 +489,38 @@ void Ledger::addJson(Json::Value& ret, int options)
|
||||
if (mTransactionMap && (full || ((options & LEDGER_JSON_DUMP_TXNS) != 0)))
|
||||
{
|
||||
Json::Value txns(Json::arrayValue);
|
||||
for (SHAMapItem::pointer item = mTransactionMap->peekFirstItem(); !!item;
|
||||
item = mTransactionMap->peekNextItem(item->getTag()))
|
||||
SHAMapTreeNode::TNType type;
|
||||
for (SHAMapItem::pointer item = mTransactionMap->peekFirstItem(type); !!item;
|
||||
item = mTransactionMap->peekNextItem(item->getTag(), type))
|
||||
{
|
||||
if (full)
|
||||
{
|
||||
SerializerIterator sit(item->peekSerializer());
|
||||
SerializedTransaction txn(sit);
|
||||
txns.append(txn.getJson(0));
|
||||
if (type == SHAMapTreeNode::tnTRANSACTION_NM)
|
||||
{
|
||||
SerializerIterator sit(item->peekSerializer());
|
||||
SerializedTransaction txn(sit);
|
||||
txns.append(txn.getJson(0));
|
||||
}
|
||||
else if (type == SHAMapTreeNode::tnTRANSACTION_MD)
|
||||
{
|
||||
SerializerIterator sit(item->peekSerializer());
|
||||
Serializer sTxn(sit.getVL());
|
||||
Serializer sMeta(sit.getVL());
|
||||
|
||||
SerializerIterator tsit(sTxn);
|
||||
SerializedTransaction txn(tsit);
|
||||
|
||||
TransactionMetaSet meta(mLedgerSeq, sit.getVL());
|
||||
Json::Value txJson = txn.getJson(0);
|
||||
txJson["metaData"] = meta.getJson(0);
|
||||
txns.append(txJson);
|
||||
}
|
||||
else
|
||||
{
|
||||
Json::Value error = Json::objectValue;
|
||||
error[item->getTag().GetHex()] = type;
|
||||
txns.append(error);
|
||||
}
|
||||
}
|
||||
else txns.append(item->getTag().GetHex());
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "../json/value.h"
|
||||
|
||||
#include "Transaction.h"
|
||||
#include "TransactionMeta.h"
|
||||
#include "AccountState.h"
|
||||
#include "RippleState.h"
|
||||
#include "NicknameState.h"
|
||||
@@ -56,7 +57,7 @@ public:
|
||||
TR_PASTASEQ = 6, // account is past this transaction
|
||||
TR_PREASEQ = 7, // account is missing transactions before this
|
||||
TR_BADLSEQ = 8, // ledger too early
|
||||
TR_TOOSMALL = 9, // amount is less than Tx fee
|
||||
TR_TOOSMALL = 9, // amount is less than Tx fee
|
||||
};
|
||||
|
||||
// ledger close flags
|
||||
@@ -82,8 +83,6 @@ private:
|
||||
|
||||
protected:
|
||||
|
||||
bool addTransaction(const Transaction::pointer&);
|
||||
bool addTransaction(const uint256& id, const Serializer& txn);
|
||||
|
||||
static Ledger::pointer getSQL(const std::string& sqlStatement);
|
||||
|
||||
@@ -152,8 +151,11 @@ public:
|
||||
bool isAcquiringAS(void);
|
||||
|
||||
// Transaction Functions
|
||||
bool addTransaction(const uint256& id, const Serializer& txn);
|
||||
bool addTransaction(const uint256& id, const Serializer& txn, const Serializer& metaData);
|
||||
bool hasTransaction(const uint256& TransID) const { return mTransactionMap->hasItem(TransID); }
|
||||
Transaction::pointer getTransaction(const uint256& transID) const;
|
||||
bool getTransaction(const uint256& transID, Transaction::pointer& txn, TransactionMetaSet::pointer& txMeta);
|
||||
|
||||
// high-level functions
|
||||
AccountState::pointer getAccountState(const NewcoinAddress& acctID);
|
||||
|
||||
@@ -84,9 +84,8 @@ void PeerSet::TimerEntry(boost::weak_ptr<PeerSet> wptr, const boost::system::err
|
||||
if (result == boost::asio::error::operation_aborted)
|
||||
return;
|
||||
boost::shared_ptr<PeerSet> ptr = wptr.lock();
|
||||
if (!ptr)
|
||||
return;
|
||||
ptr->invokeOnTimer();
|
||||
if (ptr)
|
||||
ptr->invokeOnTimer();
|
||||
}
|
||||
|
||||
LedgerAcquire::LedgerAcquire(const uint256& hash) : PeerSet(hash, LEDGER_ACQUIRE_TIMEOUT),
|
||||
@@ -109,7 +108,7 @@ void LedgerAcquire::onTimer()
|
||||
|
||||
boost::weak_ptr<PeerSet> LedgerAcquire::pmDowncast()
|
||||
{
|
||||
return boost::shared_polymorphic_downcast<PeerSet, LedgerAcquire>(shared_from_this());
|
||||
return boost::shared_polymorphic_downcast<PeerSet>(shared_from_this());
|
||||
}
|
||||
|
||||
void LedgerAcquire::done()
|
||||
|
||||
@@ -78,6 +78,7 @@ protected:
|
||||
|
||||
public:
|
||||
LedgerAcquire(const uint256& hash);
|
||||
virtual ~LedgerAcquire() { ; }
|
||||
|
||||
bool isBase() const { return mHaveBase; }
|
||||
bool isAcctStComplete() const { return mHaveState; }
|
||||
|
||||
@@ -25,24 +25,26 @@ typedef std::pair<const uint256, LCTransaction::pointer> u256_lct_pair;
|
||||
|
||||
TransactionAcquire::TransactionAcquire(const uint256& hash) : PeerSet(hash, TX_ACQUIRE_TIMEOUT), mHaveRoot(false)
|
||||
{
|
||||
mMap = boost::make_shared<SHAMap>();
|
||||
mMap->setSynching();
|
||||
mMap = boost::make_shared<SHAMap>(hash);
|
||||
}
|
||||
|
||||
void TransactionAcquire::done()
|
||||
{
|
||||
if (mFailed)
|
||||
{
|
||||
Log(lsWARNING) << "Failed to acqiure TXs " << mHash;
|
||||
Log(lsWARNING) << "Failed to acquire TXs " << mHash;
|
||||
theApp->getOPs().mapComplete(mHash, SHAMap::pointer());
|
||||
}
|
||||
else
|
||||
{
|
||||
mMap->setImmutable();
|
||||
theApp->getOPs().mapComplete(mHash, mMap);
|
||||
}
|
||||
}
|
||||
|
||||
boost::weak_ptr<PeerSet> TransactionAcquire::pmDowncast()
|
||||
{
|
||||
return boost::shared_polymorphic_downcast<PeerSet, TransactionAcquire>(shared_from_this());
|
||||
return boost::shared_polymorphic_downcast<PeerSet>(shared_from_this());
|
||||
}
|
||||
|
||||
void TransactionAcquire::trigger(Peer::ref peer, bool timer)
|
||||
@@ -109,7 +111,8 @@ bool TransactionAcquire::takeNodes(const std::list<SHAMapNode>& nodeIDs,
|
||||
}
|
||||
if (!mMap->addRootNode(getHash(), *nodeDatait, snfWIRE))
|
||||
return false;
|
||||
else mHaveRoot = true;
|
||||
else
|
||||
mHaveRoot = true;
|
||||
}
|
||||
else if (!mMap->addKnownNode(*nodeIDit, *nodeDatait, &sf))
|
||||
return false;
|
||||
@@ -174,37 +177,41 @@ void LCTransaction::unVote(const uint160& peer)
|
||||
}
|
||||
}
|
||||
|
||||
bool LCTransaction::updatePosition(int percentTime, bool proposing)
|
||||
bool LCTransaction::updateVote(int percentTime, bool proposing)
|
||||
{
|
||||
if (mOurPosition && (mNays == 0))
|
||||
if (mOurVote && (mNays == 0))
|
||||
return false;
|
||||
if (!mOurPosition && (mYays == 0))
|
||||
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)
|
||||
int weight = (mYays * 100 + (mOurPosition ? 100 : 0)) / (mNays + mYays + 1);
|
||||
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 newPosition = weight > AV_LATE_CONSENSUS_PCT;
|
||||
}
|
||||
else // don't let us outweight a proposing node, just recognize consensus
|
||||
else // don't let us outweigh a proposing node, just recognize consensus
|
||||
{
|
||||
weight = -1;
|
||||
newPosition = mYays > mNays;
|
||||
}
|
||||
|
||||
if (newPosition == mOurPosition)
|
||||
if (newPosition == mOurVote)
|
||||
{
|
||||
#ifdef LC_DEBUG
|
||||
Log(lsTRACE) << "No change (" << (mOurPosition ? "YES" : "NO") << ") : weight "
|
||||
Log(lsTRACE) << "No change (" << (mOurVote ? "YES" : "NO") << ") : weight "
|
||||
<< weight << ", percent " << percentTime;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
mOurPosition = newPosition;
|
||||
Log(lsTRACE) << "We now vote " << (mOurPosition ? "YES" : "NO") << " on " << mTransactionID;
|
||||
mOurVote = newPosition;
|
||||
Log(lsTRACE) << "We now vote " << (mOurVote ? "YES" : "NO") << " on " << mTransactionID;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -333,6 +340,7 @@ void LedgerConsensus::handleLCL(const uint256& lclHash)
|
||||
mPeerPositions.clear();
|
||||
mDisputes.clear();
|
||||
mDeadNodes.clear();
|
||||
playbackProposals();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -357,9 +365,9 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger)
|
||||
{
|
||||
uint256 set = it.second->getCurrentHash();
|
||||
if (found.insert(set).second)
|
||||
{
|
||||
boost::unordered_map<uint256, SHAMap::pointer>::iterator iit = mComplete.find(set);
|
||||
if (iit != mComplete.end())
|
||||
{ // OPTIMIZEME: Don't process the same set more than once
|
||||
boost::unordered_map<uint256, SHAMap::pointer>::iterator iit = mAcquired.find(set);
|
||||
if (iit != mAcquired.end())
|
||||
createDisputes(initialSet, iit->second);
|
||||
}
|
||||
}
|
||||
@@ -374,7 +382,7 @@ void LedgerConsensus::takeInitialPosition(Ledger& initialLedger)
|
||||
propose();
|
||||
}
|
||||
|
||||
void LedgerConsensus::createDisputes(const SHAMap::pointer& m1, const SHAMap::pointer& m2)
|
||||
void LedgerConsensus::createDisputes(SHAMap::ref m1, SHAMap::ref m2)
|
||||
{
|
||||
SHAMap::SHAMapDiff differences;
|
||||
m1->compare(m2, differences, 16384);
|
||||
@@ -394,33 +402,36 @@ void LedgerConsensus::createDisputes(const SHAMap::pointer& m1, const SHAMap::po
|
||||
}
|
||||
}
|
||||
|
||||
void LedgerConsensus::mapComplete(const uint256& hash, const SHAMap::pointer& map, bool acquired)
|
||||
void LedgerConsensus::mapComplete(const uint256& hash, SHAMap::ref map, bool acquired)
|
||||
{
|
||||
if (acquired)
|
||||
Log(lsINFO) << "We have acquired TXS " << hash;
|
||||
mAcquiring.erase(hash);
|
||||
|
||||
if (!map)
|
||||
{ // this is an invalid/corrupt map
|
||||
mComplete[hash] = map;
|
||||
mAcquired[hash] = map;
|
||||
mAcquiring.erase(hash);
|
||||
Log(lsWARNING) << "A trusted node directed us to acquire an invalid TXN map";
|
||||
return;
|
||||
}
|
||||
assert(hash == map->getHash());
|
||||
|
||||
if (mComplete.find(hash) != mComplete.end())
|
||||
if (mAcquired.find(hash) != mAcquired.end())
|
||||
return; // we already have this map
|
||||
|
||||
if (mOurPosition && (map->getHash() != mOurPosition->getCurrentHash()))
|
||||
if (mOurPosition && (!mOurPosition->isBowOut()) && (hash != mOurPosition->getCurrentHash()))
|
||||
{ // this could create disputed transactions
|
||||
boost::unordered_map<uint256, SHAMap::pointer>::iterator it2 = mComplete.find(mOurPosition->getCurrentHash());
|
||||
if (it2 != mComplete.end())
|
||||
boost::unordered_map<uint256, SHAMap::pointer>::iterator it2 = mAcquired.find(mOurPosition->getCurrentHash());
|
||||
if (it2 != mAcquired.end())
|
||||
{
|
||||
assert((it2->first == mOurPosition->getCurrentHash()) && it2->second);
|
||||
createDisputes(it2->second, map);
|
||||
}
|
||||
else assert(false); // We don't have our own position?!
|
||||
else
|
||||
assert(false); // We don't have our own position?!
|
||||
}
|
||||
mComplete[map->getHash()] = map;
|
||||
mAcquired[hash] = map;
|
||||
mAcquiring.erase(hash);
|
||||
|
||||
// Adjust tracking for each peer that takes this position
|
||||
std::vector<uint160> peers;
|
||||
@@ -446,7 +457,7 @@ void LedgerConsensus::sendHaveTxSet(const uint256& hash, bool direct)
|
||||
theApp->getConnectionPool().relayMessage(NULL, packet);
|
||||
}
|
||||
|
||||
void LedgerConsensus::adjustCount(const SHAMap::pointer& map, const std::vector<uint160>& peers)
|
||||
void LedgerConsensus::adjustCount(SHAMap::ref map, const std::vector<uint160>& peers)
|
||||
{ // Adjust the counts on all disputed transactions based on the set of peers taking this position
|
||||
BOOST_FOREACH(u256_lct_pair& it, mDisputes)
|
||||
{
|
||||
@@ -594,14 +605,15 @@ void LedgerConsensus::updateOurPositions()
|
||||
|
||||
BOOST_FOREACH(u256_lct_pair& it, mDisputes)
|
||||
{
|
||||
if (it.second->updatePosition(mClosePercent, mProposing))
|
||||
if (it.second->updateVote(mClosePercent, mProposing))
|
||||
{
|
||||
if (!changes)
|
||||
{
|
||||
ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true);
|
||||
ourPosition = mAcquired[mOurPosition->getCurrentHash()]->snapShot(true);
|
||||
assert(ourPosition);
|
||||
changes = true;
|
||||
}
|
||||
if (it.second->getOurPosition()) // now a yes
|
||||
if (it.second->getOurVote()) // now a yes
|
||||
{
|
||||
ourPosition->addItem(SHAMapItem(it.first, it.second->peekTransaction()), true, false);
|
||||
// addedTx.push_back(it.first);
|
||||
@@ -662,41 +674,53 @@ void LedgerConsensus::updateOurPositions()
|
||||
((closeTime != (roundCloseTime(mOurPosition->getCloseTime()))) ||
|
||||
(mOurPosition->isStale(ourCutoff))))
|
||||
{ // close time changed or our position is stale
|
||||
ourPosition = mComplete[mOurPosition->getCurrentHash()]->snapShot(true);
|
||||
ourPosition = mAcquired[mOurPosition->getCurrentHash()]->snapShot(true);
|
||||
assert(ourPosition);
|
||||
changes = true;
|
||||
}
|
||||
|
||||
if (changes)
|
||||
{
|
||||
uint256 newHash = ourPosition->getHash();
|
||||
mOurPosition->changePosition(newHash, closeTime);
|
||||
if (mProposing)
|
||||
propose();
|
||||
mapComplete(newHash, ourPosition, false);
|
||||
Log(lsINFO) << "Position change: CTime " << closeTime << ", tx " << newHash;
|
||||
if (mOurPosition->changePosition(newHash, closeTime))
|
||||
{
|
||||
if (mProposing)
|
||||
propose();
|
||||
mapComplete(newHash, ourPosition, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LedgerConsensus::haveConsensus()
|
||||
{
|
||||
{ // FIXME: Should check for a supermajority on each disputed transaction
|
||||
// counting unacquired TX sets as disagreeing
|
||||
int agree = 0, disagree = 0;
|
||||
uint256 ourPosition = mOurPosition->getCurrentHash();
|
||||
BOOST_FOREACH(u160_prop_pair& it, mPeerPositions)
|
||||
{
|
||||
if (it.second->getCurrentHash() == ourPosition)
|
||||
++agree;
|
||||
else
|
||||
++disagree;
|
||||
if (!it.second->isBowOut())
|
||||
{
|
||||
if (it.second->getCurrentHash() == ourPosition)
|
||||
++agree;
|
||||
else
|
||||
++disagree;
|
||||
}
|
||||
}
|
||||
int currentValidations = theApp->getValidations().getCurrentValidationCount(mPreviousLedger->getCloseTimeNC());
|
||||
int currentValidations = theApp->getValidations().getNodesAfter(mPrevLedgerHash);
|
||||
|
||||
#ifdef LC_DEBUG
|
||||
Log(lsINFO) << "Checking for TX consensus: agree=" << agree << ", disagree=" << disagree;
|
||||
#endif
|
||||
|
||||
return ContinuousLedgerTiming::haveConsensus(mPreviousProposers, agree + disagree, agree, currentValidations,
|
||||
mPreviousMSeconds, mCurrentMSeconds);
|
||||
}
|
||||
|
||||
SHAMap::pointer LedgerConsensus::getTransactionTree(const uint256& hash, bool doAcquire)
|
||||
{
|
||||
boost::unordered_map<uint256, SHAMap::pointer>::iterator it = mComplete.find(hash);
|
||||
if (it == mComplete.end())
|
||||
boost::unordered_map<uint256, SHAMap::pointer>::iterator it = mAcquired.find(hash);
|
||||
if (it == mAcquired.end())
|
||||
{ // we have not completed acquiring this ledger
|
||||
|
||||
if (mState == lcsPRE_CLOSE)
|
||||
@@ -780,10 +804,11 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec
|
||||
bool ourPosition = false;
|
||||
if (mOurPosition)
|
||||
{
|
||||
boost::unordered_map<uint256, SHAMap::pointer>::iterator mit = mComplete.find(mOurPosition->getCurrentHash());
|
||||
if (mit != mComplete.end())
|
||||
boost::unordered_map<uint256, SHAMap::pointer>::iterator mit = mAcquired.find(mOurPosition->getCurrentHash());
|
||||
if (mit != mAcquired.end())
|
||||
ourPosition = mit->second->hasItem(txID);
|
||||
else assert(false); // We don't have our own position?
|
||||
else
|
||||
assert(false); // We don't have our own position?
|
||||
}
|
||||
|
||||
LCTransaction::pointer txn = boost::make_shared<LCTransaction>(txID, tx, ourPosition);
|
||||
@@ -792,8 +817,8 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec
|
||||
BOOST_FOREACH(u160_prop_pair& pit, mPeerPositions)
|
||||
{
|
||||
boost::unordered_map<uint256, SHAMap::pointer>::const_iterator cit =
|
||||
mComplete.find(pit.second->getCurrentHash());
|
||||
if (cit != mComplete.end() && cit->second)
|
||||
mAcquired.find(pit.second->getCurrentHash());
|
||||
if (cit != mAcquired.end() && cit->second)
|
||||
txn->setVote(pit.first, cit->second->hasItem(txID));
|
||||
}
|
||||
}
|
||||
@@ -867,13 +892,15 @@ bool LedgerConsensus::peerGaveNodes(Peer::ref peer, const uint256& setHash,
|
||||
const std::list<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData)
|
||||
{
|
||||
boost::unordered_map<uint256, TransactionAcquire::pointer>::iterator acq = mAcquiring.find(setHash);
|
||||
if (acq == mAcquiring.end()) return false;
|
||||
return acq->second->takeNodes(nodeIDs, nodeData, peer);
|
||||
if (acq == mAcquiring.end())
|
||||
return false;
|
||||
TransactionAcquire::pointer set = acq->second; // We must keep the set around during the function
|
||||
return set->takeNodes(nodeIDs, nodeData, peer);
|
||||
}
|
||||
|
||||
void LedgerConsensus::beginAccept()
|
||||
{
|
||||
SHAMap::pointer consensusSet = mComplete[mOurPosition->getCurrentHash()];
|
||||
SHAMap::pointer consensusSet = mAcquired[mOurPosition->getCurrentHash()];
|
||||
if (!consensusSet)
|
||||
{
|
||||
Log(lsFATAL) << "We don't have a consensus set";
|
||||
@@ -882,8 +909,7 @@ void LedgerConsensus::beginAccept()
|
||||
}
|
||||
|
||||
theApp->getOPs().newLCL(mPeerPositions.size(), mCurrentMSeconds, mNewLedgerHash);
|
||||
boost::thread thread(boost::bind(&LedgerConsensus::Saccept, shared_from_this(), consensusSet));
|
||||
thread.detach();
|
||||
theApp->getIOService().post(boost::bind(&LedgerConsensus::Saccept, shared_from_this(), consensusSet));
|
||||
}
|
||||
|
||||
void LedgerConsensus::Saccept(boost::shared_ptr<LedgerConsensus> This, SHAMap::pointer txSet)
|
||||
@@ -954,7 +980,7 @@ void LedgerConsensus::applyTransaction(TransactionEngine& engine, const Serializ
|
||||
#endif
|
||||
}
|
||||
|
||||
void LedgerConsensus::applyTransactions(const SHAMap::pointer& set, Ledger::ref applyLedger,
|
||||
void LedgerConsensus::applyTransactions(SHAMap::ref set, Ledger::ref applyLedger,
|
||||
Ledger::ref checkLedger, CanonicalTXSet& failedTransactions, bool openLgr)
|
||||
{
|
||||
TransactionEngineParams parms = openLgr ? tapOPEN_LEDGER : tapNONE;
|
||||
@@ -1016,7 +1042,7 @@ uint32 LedgerConsensus::roundCloseTime(uint32 closeTime)
|
||||
return closeTime - (closeTime % mCloseResolution);
|
||||
}
|
||||
|
||||
void LedgerConsensus::accept(const SHAMap::pointer& set)
|
||||
void LedgerConsensus::accept(SHAMap::ref set)
|
||||
{
|
||||
assert(set->getHash() == mOurPosition->getCurrentHash());
|
||||
|
||||
@@ -1070,7 +1096,7 @@ void LedgerConsensus::accept(const SHAMap::pointer& set)
|
||||
TransactionEngine engine(newOL);
|
||||
BOOST_FOREACH(u256_lct_pair& it, mDisputes)
|
||||
{
|
||||
if (!it.second->getOurPosition())
|
||||
if (!it.second->getOurVote())
|
||||
{ // we voted NO
|
||||
try
|
||||
{
|
||||
|
||||
@@ -37,11 +37,11 @@ protected:
|
||||
public:
|
||||
|
||||
TransactionAcquire(const uint256& hash);
|
||||
virtual ~TransactionAcquire() { ; }
|
||||
|
||||
SHAMap::pointer getMap() { return mMap; }
|
||||
|
||||
bool takeNodes(const std::list<SHAMapNode>& IDs, const std::list< std::vector<unsigned char> >& data,
|
||||
Peer::ref);
|
||||
bool takeNodes(const std::list<SHAMapNode>& IDs, const std::list< std::vector<unsigned char> >& data, Peer::ref);
|
||||
};
|
||||
|
||||
class LCTransaction
|
||||
@@ -49,24 +49,24 @@ class LCTransaction
|
||||
protected:
|
||||
uint256 mTransactionID;
|
||||
int mYays, mNays;
|
||||
bool mOurPosition;
|
||||
bool mOurVote;
|
||||
Serializer transaction;
|
||||
boost::unordered_map<uint160, bool> mVotes;
|
||||
|
||||
public:
|
||||
typedef boost::shared_ptr<LCTransaction> pointer;
|
||||
|
||||
LCTransaction(const uint256 &txID, const std::vector<unsigned char>& tx, bool ourPosition) :
|
||||
mTransactionID(txID), mYays(0), mNays(0), mOurPosition(ourPosition), transaction(tx) { ; }
|
||||
LCTransaction(const uint256 &txID, const std::vector<unsigned char>& tx, bool ourVote) :
|
||||
mTransactionID(txID), mYays(0), mNays(0), mOurVote(ourVote), transaction(tx) { ; }
|
||||
|
||||
const uint256& getTransactionID() const { return mTransactionID; }
|
||||
bool getOurPosition() const { return mOurPosition; }
|
||||
bool getOurVote() const { return mOurVote; }
|
||||
Serializer& peekTransaction() { return transaction; }
|
||||
|
||||
void setVote(const uint160& peer, bool votesYes);
|
||||
void unVote(const uint160& peer);
|
||||
|
||||
bool updatePosition(int percentTime, bool proposing);
|
||||
bool updateVote(int percentTime, bool proposing);
|
||||
};
|
||||
|
||||
enum LCState
|
||||
@@ -100,7 +100,7 @@ protected:
|
||||
boost::unordered_map<uint160, LedgerProposal::pointer> mPeerPositions;
|
||||
|
||||
// Transaction Sets, indexed by hash of transaction tree
|
||||
boost::unordered_map<uint256, SHAMap::pointer> mComplete;
|
||||
boost::unordered_map<uint256, SHAMap::pointer> mAcquired;
|
||||
boost::unordered_map<uint256, TransactionAcquire::pointer> mAcquiring;
|
||||
|
||||
// Peer sets
|
||||
@@ -120,21 +120,21 @@ protected:
|
||||
|
||||
// final accept logic
|
||||
static void Saccept(boost::shared_ptr<LedgerConsensus> This, SHAMap::pointer txSet);
|
||||
void accept(const SHAMap::pointer& txSet);
|
||||
void accept(SHAMap::ref txSet);
|
||||
|
||||
void weHave(const uint256& id, Peer::ref avoidPeer);
|
||||
void startAcquiring(const TransactionAcquire::pointer&);
|
||||
SHAMap::pointer find(const uint256& hash);
|
||||
|
||||
void createDisputes(const SHAMap::pointer&, const SHAMap::pointer&);
|
||||
void createDisputes(SHAMap::ref, SHAMap::ref);
|
||||
void addDisputedTransaction(const uint256&, const std::vector<unsigned char>& transaction);
|
||||
void adjustCount(const SHAMap::pointer& map, const std::vector<uint160>& peers);
|
||||
void adjustCount(SHAMap::ref map, const std::vector<uint160>& peers);
|
||||
void propose();
|
||||
|
||||
void addPosition(LedgerProposal&, bool ours);
|
||||
void removePosition(LedgerProposal&, bool ours);
|
||||
void sendHaveTxSet(const uint256& set, bool direct);
|
||||
void applyTransactions(const SHAMap::pointer& transactionSet, Ledger::ref targetLedger,
|
||||
void applyTransactions(SHAMap::ref transactionSet, Ledger::ref targetLedger,
|
||||
Ledger::ref checkLedger, CanonicalTXSet& failedTransactions, bool openLgr);
|
||||
void applyTransaction(TransactionEngine& engine, const SerializedTransaction::pointer& txn,
|
||||
Ledger::ref targetLedger, CanonicalTXSet& failedTransactions, bool openLgr);
|
||||
@@ -162,7 +162,7 @@ public:
|
||||
|
||||
SHAMap::pointer getTransactionTree(const uint256& hash, bool doAcquire);
|
||||
TransactionAcquire::pointer getAcquiring(const uint256& hash);
|
||||
void mapComplete(const uint256& hash, const SHAMap::pointer& map, bool acquired);
|
||||
void mapComplete(const uint256& hash, SHAMap::ref map, bool acquired);
|
||||
void checkLCL();
|
||||
void handleLCL(const uint256& lclHash);
|
||||
|
||||
|
||||
@@ -257,6 +257,8 @@ Json::Value LedgerEntrySet::getJson(int) const
|
||||
}
|
||||
ret["nodes" ] = nodes;
|
||||
|
||||
ret["metaData"] = mSet.getJson(0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -292,9 +294,13 @@ SLE::pointer LedgerEntrySet::getForMod(const uint256& node, Ledger::ref ledger,
|
||||
bool LedgerEntrySet::threadTx(TransactionMetaNode& metaNode, const NewcoinAddress& threadTo, Ledger::ref ledger,
|
||||
boost::unordered_map<uint256, SLE::pointer>& newMods)
|
||||
{
|
||||
Log(lsTRACE) << "Thread to " << threadTo.getAccountID();
|
||||
SLE::pointer sle = getForMod(Ledger::getAccountRootIndex(threadTo.getAccountID()), ledger, newMods);
|
||||
if (!sle)
|
||||
{
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
return threadTx(metaNode, sle, ledger, newMods);
|
||||
}
|
||||
|
||||
@@ -325,7 +331,7 @@ bool LedgerEntrySet::threadOwners(TransactionMetaNode& metaNode, SLE::ref node,
|
||||
return false;
|
||||
}
|
||||
|
||||
void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger)
|
||||
void LedgerEntrySet::calcRawMeta(Serializer& s)
|
||||
{ // calculate the raw meta data and return it. This must be called before the set is committed
|
||||
|
||||
// Entries modified only as a result of building the transaction metadata
|
||||
@@ -350,21 +356,25 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger)
|
||||
nType = TMNCreatedNode;
|
||||
break;
|
||||
|
||||
default:
|
||||
// ignore these
|
||||
default: // ignore these
|
||||
break;
|
||||
}
|
||||
|
||||
if (nType == TMNEndOfMetadata)
|
||||
continue;
|
||||
|
||||
SLE::pointer origNode = origLedger->getSLE(it->first);
|
||||
SLE::pointer origNode = mLedger->getSLE(it->first);
|
||||
|
||||
if (origNode && (origNode->getType() == ltDIR_NODE)) // No metadata for dir nodes
|
||||
continue;
|
||||
|
||||
SLE::pointer curNode = it->second.mEntry;
|
||||
TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType);
|
||||
|
||||
if (nType == TMNDeletedNode)
|
||||
{
|
||||
threadOwners(metaNode, origNode, origLedger, newMod);
|
||||
assert(origNode);
|
||||
threadOwners(metaNode, origNode, mLedger, newMod);
|
||||
|
||||
if (origNode->getIFieldPresent(sfAmount))
|
||||
{ // node has an amount, covers ripple state nodes
|
||||
@@ -396,16 +406,20 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger)
|
||||
}
|
||||
|
||||
if (nType == TMNCreatedNode) // if created, thread to owner(s)
|
||||
threadOwners(metaNode, curNode, origLedger, newMod);
|
||||
{
|
||||
assert(!origNode);
|
||||
threadOwners(metaNode, curNode, mLedger, newMod);
|
||||
}
|
||||
|
||||
if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode))
|
||||
{
|
||||
if (curNode->isThreadedType()) // always thread to self
|
||||
threadTx(metaNode, curNode, origLedger, newMod);
|
||||
threadTx(metaNode, curNode, mLedger, newMod);
|
||||
}
|
||||
|
||||
if (nType == TMNModifiedNode)
|
||||
{
|
||||
assert(origNode);
|
||||
if (origNode->getIFieldPresent(sfAmount))
|
||||
{ // node has an amount, covers account root nodes and ripple nodes
|
||||
STAmount amount = origNode->getIValueFieldAmount(sfAmount);
|
||||
@@ -429,7 +443,11 @@ void LedgerEntrySet::calcRawMeta(Serializer& s, Ledger::ref origLedger)
|
||||
// add any new modified nodes to the modification set
|
||||
for (boost::unordered_map<uint256, SLE::pointer>::iterator it = newMod.begin(), end = newMod.end();
|
||||
it != end; ++it)
|
||||
entryCache(it->second);
|
||||
entryModify(it->second);
|
||||
|
||||
#ifdef DEBUG
|
||||
Log(lsINFO) << "Metadata:" << mSet.getJson(0);
|
||||
#endif
|
||||
|
||||
mSet.addRaw(s);
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ public:
|
||||
STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault);
|
||||
|
||||
Json::Value getJson(int) const;
|
||||
void calcRawMeta(Serializer&, Ledger::ref originalLedger);
|
||||
void calcRawMeta(Serializer&);
|
||||
|
||||
// iterator functions
|
||||
bool isEmpty() const { return mEntries.empty(); }
|
||||
|
||||
@@ -80,8 +80,7 @@ Ledger::pointer LedgerMaster::closeLedger()
|
||||
return closingLedger;
|
||||
}
|
||||
|
||||
TER LedgerMaster::doTransaction(const SerializedTransaction& txn, uint32 targetLedger,
|
||||
TransactionEngineParams params)
|
||||
TER LedgerMaster::doTransaction(const SerializedTransaction& txn, TransactionEngineParams params)
|
||||
{
|
||||
TER result = mEngine.applyTransaction(txn, params);
|
||||
theApp->getOPs().pubTransaction(mEngine.getLedger(), txn, result);
|
||||
|
||||
@@ -45,8 +45,7 @@ public:
|
||||
|
||||
void runStandAlone() { mFinalizedLedger = mCurrentLedger; }
|
||||
|
||||
TER doTransaction(const SerializedTransaction& txn, uint32 targetLedger,
|
||||
TransactionEngineParams params);
|
||||
TER doTransaction(const SerializedTransaction& txn, TransactionEngineParams params);
|
||||
|
||||
void pushLedger(Ledger::ref newLedger);
|
||||
void pushLedger(Ledger::ref newLCL, Ledger::ref newOL);
|
||||
|
||||
@@ -54,17 +54,20 @@ bool LedgerProposal::checkSign(const std::string& signature, const uint256& sign
|
||||
return mPublicKey.verifyNodePublic(signingHash, signature);
|
||||
}
|
||||
|
||||
void LedgerProposal::changePosition(const uint256& newPosition, uint32 closeTime)
|
||||
bool LedgerProposal::changePosition(const uint256& newPosition, uint32 closeTime)
|
||||
{
|
||||
if (mProposeSeq == seqLeave)
|
||||
return false;
|
||||
|
||||
mCurrentHash = newPosition;
|
||||
mCloseTime = closeTime;
|
||||
mTime = boost::posix_time::second_clock::universal_time();
|
||||
++mProposeSeq;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LedgerProposal::bowOut()
|
||||
{
|
||||
mCurrentHash = uint256();
|
||||
mTime = boost::posix_time::second_clock::universal_time();
|
||||
mProposeSeq = seqLeave;
|
||||
}
|
||||
|
||||
@@ -59,11 +59,12 @@ public:
|
||||
void setSignature(const std::string& signature) { mSignature = signature; }
|
||||
bool hasSignature() { return !mSignature.empty(); }
|
||||
bool isPrevLedger(const uint256& pl) { return mPreviousLedger == pl; }
|
||||
bool isBowOut() { return mProposeSeq == seqLeave; }
|
||||
|
||||
const boost::posix_time::ptime getCreateTime() { return mTime; }
|
||||
bool isStale(boost::posix_time::ptime cutoff) { return mTime <= cutoff; }
|
||||
|
||||
void changePosition(const uint256& newPosition, uint32 newCloseTime);
|
||||
bool changePosition(const uint256& newPosition, uint32 newCloseTime);
|
||||
void bowOut();
|
||||
Json::Value getJson() const;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
// How often we check state or change positions (in milliseconds)
|
||||
# define LEDGER_GRANULARITY 1000
|
||||
|
||||
// The percentage of active trusted validators that must be able to
|
||||
// keep up with the network or we consider the network overloaded
|
||||
# define LEDGER_NET_RATIO 70
|
||||
|
||||
// How long we consider a proposal fresh
|
||||
# define PROPOSE_FRESHNESS 20
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
// Ensure that we don't get value.h without writer.h
|
||||
#include "../json/json.h"
|
||||
|
||||
enum LogSeverity
|
||||
{
|
||||
lsTRACE = 0,
|
||||
|
||||
@@ -93,7 +93,7 @@ Transaction::pointer NetworkOPs::submitTransaction(const Transaction::pointer& t
|
||||
return tpTransNew;
|
||||
}
|
||||
|
||||
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, uint32 tgtLedger, Peer* source)
|
||||
Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, Peer* source)
|
||||
{
|
||||
Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true);
|
||||
if (dbtx) return dbtx;
|
||||
@@ -105,7 +105,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
||||
return trans;
|
||||
}
|
||||
|
||||
TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tgtLedger, tapOPEN_LEDGER);
|
||||
TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tapOPEN_LEDGER);
|
||||
if (r == tefFAILURE) throw Fault(IO_ERROR);
|
||||
|
||||
if (r == terPRE_SEQ)
|
||||
@@ -140,7 +140,6 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
||||
tx.set_rawtransaction(&s.getData().front(), s.getLength());
|
||||
tx.set_status(newcoin::tsCURRENT);
|
||||
tx.set_receivetimestamp(getNetworkTimeNC());
|
||||
tx.set_ledgerindexpossible(trans->getLedger());
|
||||
|
||||
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tx, newcoin::mtTRANSACTION);
|
||||
theApp->getConnectionPool().relayMessage(source, packet);
|
||||
@@ -157,7 +156,6 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans,
|
||||
tx.set_rawtransaction(&s.getData().front(), s.getLength());
|
||||
tx.set_status(newcoin::tsCURRENT);
|
||||
tx.set_receivetimestamp(getNetworkTimeNC());
|
||||
tx.set_ledgerindexpossible(tgtLedger);
|
||||
PackedMessage::pointer packet = boost::make_shared<PackedMessage>(tx, newcoin::mtTRANSACTION);
|
||||
theApp->getConnectionPool().relayMessage(source, packet);
|
||||
}
|
||||
@@ -213,7 +211,11 @@ SLE::pointer NetworkOPs::getGenerator(const uint256& uLedger, const uint160& uGe
|
||||
{
|
||||
LedgerStateParms qry = lepNONE;
|
||||
|
||||
return mLedgerMaster->getLedgerByHash(uLedger)->getGenerator(qry, uGeneratorID);
|
||||
Ledger::pointer ledger = mLedgerMaster->getLedgerByHash(uLedger);
|
||||
if (!ledger)
|
||||
return SLE::pointer();
|
||||
else
|
||||
return ledger->getGenerator(qry, uGeneratorID);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -714,7 +716,7 @@ bool NetworkOPs::hasTXSet(const boost::shared_ptr<Peer>& peer, const uint256& se
|
||||
return mConsensus->peerHasSet(peer, set, status);
|
||||
}
|
||||
|
||||
void NetworkOPs::mapComplete(const uint256& hash, const SHAMap::pointer& map)
|
||||
void NetworkOPs::mapComplete(const uint256& hash, SHAMap::ref map)
|
||||
{
|
||||
if (mConsensus)
|
||||
mConsensus->mapComplete(hash, map, true);
|
||||
|
||||
@@ -116,8 +116,7 @@ public:
|
||||
//
|
||||
Transaction::pointer submitTransaction(const Transaction::pointer& tpTrans);
|
||||
|
||||
Transaction::pointer processTransaction(Transaction::pointer transaction, uint32 targetLedger = 0,
|
||||
Peer* source = NULL);
|
||||
Transaction::pointer processTransaction(Transaction::pointer transaction, Peer* source = NULL);
|
||||
Transaction::pointer findTransactionByID(const uint256& transactionID);
|
||||
int findTransactionsBySource(const uint256& uLedger, std::list<Transaction::pointer>&, const NewcoinAddress& sourceAccount,
|
||||
uint32 minSeq, uint32 maxSeq);
|
||||
@@ -172,7 +171,7 @@ public:
|
||||
bool recvValidation(const SerializedValidation::pointer& val);
|
||||
SHAMap::pointer getTXMap(const uint256& hash);
|
||||
bool hasTXSet(const boost::shared_ptr<Peer>& peer, const uint256& set, newcoin::TxSetStatus status);
|
||||
void mapComplete(const uint256& hash, const SHAMap::pointer& map);
|
||||
void mapComplete(const uint256& hash, SHAMap::ref map);
|
||||
|
||||
// network state machine
|
||||
void checkState(const boost::system::error_code& result);
|
||||
|
||||
@@ -12,6 +12,8 @@ public:
|
||||
virtual bool work(Interpreter* interpreter)=0;
|
||||
|
||||
virtual int getFee();
|
||||
|
||||
virtual ~Operation() { ; }
|
||||
};
|
||||
|
||||
// this is just an Int in the code
|
||||
|
||||
@@ -702,13 +702,7 @@ void Peer::recvTransaction(newcoin::TMTransaction& packet)
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32 targetLedger = 0;
|
||||
if (packet.has_ledgerindexfinal())
|
||||
targetLedger = packet.ledgerindexfinal();
|
||||
else if (packet.has_ledgerindexpossible())
|
||||
targetLedger = packet.ledgerindexpossible();
|
||||
|
||||
tx = theApp->getOPs().processTransaction(tx, targetLedger, this);
|
||||
tx = theApp->getOPs().processTransaction(tx, this);
|
||||
|
||||
if(tx->getStatus() != INCLUDED)
|
||||
{ // transaction wasn't accepted into ledger
|
||||
|
||||
@@ -39,14 +39,14 @@ std::size_t hash_value(const uint160& u)
|
||||
}
|
||||
|
||||
|
||||
SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(Modifying)
|
||||
SHAMap::SHAMap(uint32 seq) : mSeq(seq), mState(smsModifying)
|
||||
{
|
||||
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
|
||||
root->makeInner();
|
||||
mTNByID[*root] = root;
|
||||
}
|
||||
|
||||
SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(Synching)
|
||||
SHAMap::SHAMap(const uint256& hash) : mSeq(0), mState(smsSynching)
|
||||
{ // FIXME: Need to acquire root node
|
||||
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
|
||||
root->makeInner();
|
||||
@@ -62,7 +62,7 @@ SHAMap::pointer SHAMap::snapShot(bool isMutable)
|
||||
newMap.mTNByID = mTNByID;
|
||||
newMap.root = root;
|
||||
if (!isMutable)
|
||||
newMap.mState = Immutable;
|
||||
newMap.mState = smsImmutable;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ void SHAMap::dirtyUp(std::stack<SHAMapTreeNode::pointer>& stack, const uint256&
|
||||
{ // walk the tree up from through the inner nodes to the root
|
||||
// update linking hashes and add nodes to dirty list
|
||||
|
||||
assert((mState != Synching) && (mState != Immutable));
|
||||
assert((mState != smsSynching) && (mState != smsImmutable));
|
||||
|
||||
while (!stack.empty())
|
||||
{
|
||||
@@ -238,7 +238,7 @@ SHAMapItem::SHAMapItem(const uint256& tag, const Serializer& data)
|
||||
: mTag(tag), mData(data.peekData())
|
||||
{ ; }
|
||||
|
||||
SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node)
|
||||
SHAMapTreeNode* SHAMap::firstBelow(SHAMapTreeNode* node)
|
||||
{
|
||||
// Return the first item below this node
|
||||
#ifdef ST_DEBUG
|
||||
@@ -246,7 +246,7 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node)
|
||||
#endif
|
||||
do
|
||||
{ // Walk down the tree
|
||||
if (node->hasItem()) return node->peekItem();
|
||||
if (node->hasItem()) return node;
|
||||
|
||||
bool foundNode = false;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
@@ -261,11 +261,12 @@ SHAMapItem::pointer SHAMap::firstBelow(SHAMapTreeNode* node)
|
||||
foundNode = true;
|
||||
break;
|
||||
}
|
||||
if (!foundNode) return SHAMapItem::pointer();
|
||||
if (!foundNode)
|
||||
return NULL;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node)
|
||||
SHAMapTreeNode* SHAMap::lastBelow(SHAMapTreeNode* node)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "lastBelow(" << *node << ")" << std::endl;
|
||||
@@ -273,7 +274,8 @@ SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node)
|
||||
|
||||
do
|
||||
{ // Walk down the tree
|
||||
if (node->hasItem()) return node->peekItem();
|
||||
if (node->hasItem())
|
||||
return node;
|
||||
|
||||
bool foundNode = false;
|
||||
for (int i = 15; i >= 0; ++i)
|
||||
@@ -283,7 +285,8 @@ SHAMapItem::pointer SHAMap::lastBelow(SHAMapTreeNode* node)
|
||||
foundNode = true;
|
||||
break;
|
||||
}
|
||||
if (!foundNode) return SHAMapItem::pointer();
|
||||
if (!foundNode)
|
||||
return NULL;
|
||||
} while (true);
|
||||
}
|
||||
|
||||
@@ -345,16 +348,39 @@ void SHAMap::eraseChildren(SHAMapTreeNode::pointer node)
|
||||
SHAMapItem::pointer SHAMap::peekFirstItem()
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
return firstBelow(root.get());
|
||||
SHAMapTreeNode *node = firstBelow(root.get());
|
||||
if (!node)
|
||||
return SHAMapItem::pointer();
|
||||
return node->peekItem();
|
||||
}
|
||||
|
||||
SHAMapItem::pointer SHAMap::peekFirstItem(SHAMapTreeNode::TNType& type)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
SHAMapTreeNode *node = firstBelow(root.get());
|
||||
if (!node)
|
||||
return SHAMapItem::pointer();
|
||||
type = node->getType();
|
||||
return node->peekItem();
|
||||
}
|
||||
|
||||
SHAMapItem::pointer SHAMap::peekLastItem()
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
return lastBelow(root.get());
|
||||
SHAMapTreeNode *node = lastBelow(root.get());
|
||||
if (!node)
|
||||
return SHAMapItem::pointer();
|
||||
return node->peekItem();
|
||||
}
|
||||
|
||||
SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id)
|
||||
{
|
||||
SHAMapTreeNode::TNType type;
|
||||
return peekNextItem(id, type);
|
||||
}
|
||||
|
||||
|
||||
SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id, SHAMapTreeNode::TNType& type)
|
||||
{ // Get a pointer to the next item in the tree after a given item - item must be in tree
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
|
||||
@@ -367,17 +393,24 @@ SHAMapItem::pointer SHAMap::peekNextItem(const uint256& id)
|
||||
if (node->isLeaf())
|
||||
{
|
||||
if (node->peekItem()->getTag() > id)
|
||||
return node->peekItem();
|
||||
}
|
||||
else for (int i = node->selectBranch(id) + 1; i < 16; ++i)
|
||||
if (!node->isEmptyBranch(i))
|
||||
{
|
||||
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
|
||||
SHAMapItem::pointer item = firstBelow(node.get());
|
||||
if (!item)
|
||||
throw std::runtime_error("missing node");
|
||||
return item;
|
||||
type = node->getType();
|
||||
return node->peekItem();
|
||||
}
|
||||
}
|
||||
else
|
||||
for (int i = node->selectBranch(id) + 1; i < 16; ++i)
|
||||
if (!node->isEmptyBranch(i))
|
||||
{
|
||||
SHAMapTreeNode *firstNode = getNodePointer(node->getChildNodeID(i), node->getChildHash(i));
|
||||
if (!firstNode)
|
||||
throw std::runtime_error("missing node");
|
||||
firstNode = firstBelow(firstNode);
|
||||
if (!firstNode)
|
||||
throw std::runtime_error("missing node");
|
||||
type = firstNode->getType();
|
||||
return firstNode->peekItem();
|
||||
}
|
||||
}
|
||||
// must be last item
|
||||
return SHAMapItem::pointer();
|
||||
@@ -402,10 +435,10 @@ SHAMapItem::pointer SHAMap::peekPrevItem(const uint256& id)
|
||||
if (!node->isEmptyBranch(i))
|
||||
{
|
||||
node = getNode(node->getChildNodeID(i), node->getChildHash(i), false);
|
||||
SHAMapItem::pointer item = firstBelow(node.get());
|
||||
SHAMapTreeNode* item = firstBelow(node.get());
|
||||
if (!item)
|
||||
throw std::runtime_error("missing node");
|
||||
return item;
|
||||
return item->peekItem();
|
||||
}
|
||||
}
|
||||
// must be last item
|
||||
@@ -421,6 +454,16 @@ SHAMapItem::pointer SHAMap::peekItem(const uint256& id)
|
||||
return leaf->peekItem();
|
||||
}
|
||||
|
||||
SHAMapItem::pointer SHAMap::peekItem(const uint256& id, SHAMapTreeNode::TNType& type)
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
SHAMapTreeNode* leaf = walkToPointer(id);
|
||||
if (!leaf)
|
||||
return SHAMapItem::pointer();
|
||||
type = leaf->getType();
|
||||
return leaf->peekItem();
|
||||
}
|
||||
|
||||
bool SHAMap::hasItem(const uint256& id)
|
||||
{ // does the tree have an item with this ID
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
@@ -432,7 +475,7 @@ bool SHAMap::hasItem(const uint256& id)
|
||||
bool SHAMap::delItem(const uint256& id)
|
||||
{ // delete the item with this ID
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
assert(mState != Immutable);
|
||||
assert(mState != smsImmutable);
|
||||
|
||||
std::stack<SHAMapTreeNode::pointer> stack = getStack(id, true, false);
|
||||
if (stack.empty())
|
||||
@@ -509,7 +552,7 @@ bool SHAMap::addGiveItem(const SHAMapItem::pointer& item, bool isTransaction, bo
|
||||
(hasMeta ? SHAMapTreeNode::tnTRANSACTION_MD : SHAMapTreeNode::tnTRANSACTION_NM);
|
||||
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
assert(mState != Immutable);
|
||||
assert(mState != smsImmutable);
|
||||
|
||||
std::stack<SHAMapTreeNode::pointer> stack = getStack(tag, true, false);
|
||||
if (stack.empty())
|
||||
@@ -601,7 +644,7 @@ bool SHAMap::updateGiveItem(const SHAMapItem::pointer& item, bool isTransaction,
|
||||
uint256 tag = item->getTag();
|
||||
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
assert(mState != Immutable);
|
||||
assert(mState != smsImmutable);
|
||||
|
||||
std::stack<SHAMapTreeNode::pointer> stack = getStack(tag, true, false);
|
||||
if (stack.empty()) throw std::runtime_error("missing node");
|
||||
|
||||
43
src/SHAMap.h
43
src/SHAMap.h
@@ -24,7 +24,8 @@ class SHAMap;
|
||||
class SHAMapNode
|
||||
{ // Identifies a node in a SHA256 hash
|
||||
public:
|
||||
typedef boost::shared_ptr<SHAMapNode> pointer;
|
||||
typedef boost::shared_ptr<SHAMapNode> pointer;
|
||||
typedef const boost::shared_ptr<SHAMapNode>& ref;
|
||||
|
||||
private:
|
||||
static uint256 smMasks[65]; // AND with hash to get node id
|
||||
@@ -216,11 +217,11 @@ public:
|
||||
|
||||
enum SHAMapState
|
||||
{
|
||||
Modifying = 0, // Objects can be added and removed (like an open ledger)
|
||||
Immutable = 1, // Map cannot be changed (like a closed ledger)
|
||||
Synching = 2, // Map's hash is locked in, valid nodes can be added (like a peer's closing ledger)
|
||||
Floating = 3, // Map is free to change hash (like a synching open ledger)
|
||||
Invalid = 4, // Map is known not to be valid (usually synching a corrupt ledger)
|
||||
smsModifying = 0, // Objects can be added and removed (like an open ledger)
|
||||
smsImmutable = 1, // Map cannot be changed (like a closed ledger)
|
||||
smsSynching = 2, // Map's hash is locked in, valid nodes can be added (like a peer's closing ledger)
|
||||
smsFloating = 3, // Map is free to change hash (like a synching open ledger)
|
||||
smsInvalid = 4, // Map is known not to be valid (usually synching a corrupt ledger)
|
||||
};
|
||||
|
||||
class SHAMapSyncFilter
|
||||
@@ -228,9 +229,11 @@ class SHAMapSyncFilter
|
||||
public:
|
||||
SHAMapSyncFilter() { ; }
|
||||
virtual ~SHAMapSyncFilter() { ; }
|
||||
|
||||
virtual void gotNode(const SHAMapNode& id, const uint256& nodeHash,
|
||||
const std::vector<unsigned char>& nodeData, bool isLeaf)
|
||||
{ ; }
|
||||
|
||||
virtual bool haveNode(const SHAMapNode& id, const uint256& nodeHash, std::vector<unsigned char>& nodeData)
|
||||
{ return false; }
|
||||
};
|
||||
@@ -247,6 +250,7 @@ public:
|
||||
{ ; }
|
||||
virtual ~SHAMapMissingNode() throw()
|
||||
{ ; }
|
||||
|
||||
const SHAMapNode& getNodeID() const { return mNodeID; }
|
||||
const uint256& getNodeHash() const { return mNodeHash; }
|
||||
};
|
||||
@@ -255,6 +259,8 @@ class SHAMap
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<SHAMap> pointer;
|
||||
typedef const boost::shared_ptr<SHAMap>& ref;
|
||||
|
||||
typedef std::map<uint256, std::pair<SHAMapItem::pointer, SHAMapItem::pointer> > SHAMapDiff;
|
||||
|
||||
private:
|
||||
@@ -280,9 +286,9 @@ protected:
|
||||
SHAMapTreeNode::pointer getNode(const SHAMapNode& id);
|
||||
SHAMapTreeNode::pointer getNode(const SHAMapNode& id, const uint256& hash, bool modify);
|
||||
SHAMapTreeNode* getNodePointer(const SHAMapNode& id, const uint256& hash);
|
||||
SHAMapTreeNode* firstBelow(SHAMapTreeNode*);
|
||||
SHAMapTreeNode* lastBelow(SHAMapTreeNode*);
|
||||
|
||||
SHAMapItem::pointer firstBelow(SHAMapTreeNode*);
|
||||
SHAMapItem::pointer lastBelow(SHAMapTreeNode*);
|
||||
SHAMapItem::pointer onlyBelow(SHAMapTreeNode*);
|
||||
void eraseChildren(SHAMapTreeNode::pointer);
|
||||
|
||||
@@ -295,6 +301,8 @@ public:
|
||||
SHAMap(uint32 seq = 0);
|
||||
SHAMap(const uint256& hash);
|
||||
|
||||
~SHAMap() { mState = smsInvalid; }
|
||||
|
||||
// Returns a new map that's a snapshot of this one. Force CoW
|
||||
SHAMap::pointer snapShot(bool isMutable);
|
||||
|
||||
@@ -318,11 +326,14 @@ public:
|
||||
|
||||
// save a copy if you only need a temporary
|
||||
SHAMapItem::pointer peekItem(const uint256& id);
|
||||
SHAMapItem::pointer peekItem(const uint256& id, SHAMapTreeNode::TNType& type);
|
||||
|
||||
// traverse functions
|
||||
SHAMapItem::pointer peekFirstItem();
|
||||
SHAMapItem::pointer peekFirstItem(SHAMapTreeNode::TNType& type);
|
||||
SHAMapItem::pointer peekLastItem();
|
||||
SHAMapItem::pointer peekNextItem(const uint256&);
|
||||
SHAMapItem::pointer peekNextItem(const uint256&, SHAMapTreeNode::TNType& type);
|
||||
SHAMapItem::pointer peekPrevItem(const uint256&);
|
||||
|
||||
// comparison/sync functions
|
||||
@@ -337,17 +348,17 @@ public:
|
||||
SHAMapSyncFilter* filter);
|
||||
|
||||
// status functions
|
||||
void setImmutable(void) { assert(mState != Invalid); mState = Immutable; }
|
||||
void clearImmutable(void) { mState = Modifying; }
|
||||
bool isSynching(void) const { return (mState == Floating) || (mState == Synching); }
|
||||
void setSynching(void) { mState = Synching; }
|
||||
void setFloating(void) { mState = Floating; }
|
||||
void clearSynching(void) { mState = Modifying; }
|
||||
bool isValid(void) { return mState != Invalid; }
|
||||
void setImmutable() { assert(mState != smsInvalid); mState = smsImmutable; }
|
||||
void clearImmutable() { mState = smsModifying; }
|
||||
bool isSynching() const { return (mState == smsFloating) || (mState == smsSynching); }
|
||||
void setSynching() { mState = smsSynching; }
|
||||
void setFloating() { mState = smsFloating; }
|
||||
void clearSynching() { mState = smsModifying; }
|
||||
bool isValid() { return mState != smsInvalid; }
|
||||
|
||||
// caution: otherMap must be accessed only by this function
|
||||
// return value: true=successfully completed, false=too different
|
||||
bool compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, int maxCount);
|
||||
bool compare(SHAMap::ref otherMap, SHAMapDiff& differences, int maxCount);
|
||||
|
||||
void armDirty();
|
||||
int flushDirty(int maxNodes, HashedObjectType t, uint32 seq);
|
||||
|
||||
@@ -91,17 +91,22 @@ bool SHAMap::walkBranch(SHAMapTreeNode* node, SHAMapItem::pointer otherMapItem,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SHAMap::compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, int maxCount)
|
||||
bool SHAMap::compare(SHAMap::ref otherMap, SHAMapDiff& differences, int maxCount)
|
||||
{ // compare two hash trees, add up to maxCount differences to the difference table
|
||||
// return value: true=complete table of differences given, false=too many differences
|
||||
// throws on corrupt tables or missing nodes
|
||||
// CAUTION: otherMap is not locked and must be immutable
|
||||
|
||||
assert(isValid() && otherMap && otherMap->isValid());
|
||||
|
||||
std::stack<SHAMapDiffNode> nodeStack; // track nodes we've pushed
|
||||
|
||||
ScopedLock sl(Lock());
|
||||
if (getHash() == otherMap->getHash()) return true;
|
||||
nodeStack.push(SHAMapDiffNode(SHAMapNode(), getHash(), otherMap->getHash()));
|
||||
boost::recursive_mutex::scoped_lock sl(mLock);
|
||||
|
||||
if (getHash() == otherMap->getHash())
|
||||
return true;
|
||||
|
||||
nodeStack.push(SHAMapDiffNode(SHAMapNode(), getHash(), otherMap->getHash()));
|
||||
while (!nodeStack.empty())
|
||||
{
|
||||
SHAMapDiffNode dNode(nodeStack.top());
|
||||
@@ -109,6 +114,11 @@ bool SHAMap::compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, i
|
||||
|
||||
SHAMapTreeNode* ourNode = getNodePointer(dNode.mNodeID, dNode.mOurHash);
|
||||
SHAMapTreeNode* otherNode = otherMap->getNodePointer(dNode.mNodeID, dNode.mOtherHash);
|
||||
if (!ourNode || !otherNode)
|
||||
{
|
||||
assert(false);
|
||||
throw SHAMapMissingNode(dNode.mNodeID, uint256());
|
||||
}
|
||||
|
||||
if (ourNode->isLeaf() && otherNode->isLeaf())
|
||||
{ // two leaves
|
||||
@@ -118,17 +128,20 @@ bool SHAMap::compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, i
|
||||
{
|
||||
differences.insert(std::make_pair(ourNode->getTag(),
|
||||
std::make_pair(ourNode->getItem(), otherNode->getItem())));
|
||||
if (--maxCount <= 0) return false;
|
||||
if (--maxCount <= 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
differences.insert(std::make_pair(ourNode->getTag(),
|
||||
std::make_pair(ourNode->getItem(), SHAMapItem::pointer())));
|
||||
if (--maxCount <= 0) return false;
|
||||
if (--maxCount <= 0)
|
||||
return false;
|
||||
differences.insert(std::make_pair(otherNode->getTag(),
|
||||
std::make_pair(SHAMapItem::pointer(), otherNode->getItem())));
|
||||
if (--maxCount <= 0) return false;
|
||||
if (--maxCount <= 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (ourNode->isInner() && otherNode->isLeaf())
|
||||
@@ -164,7 +177,8 @@ bool SHAMap::compare(const SHAMap::pointer& otherMap, SHAMapDiff& differences, i
|
||||
ourNode->getChildHash(i), otherNode->getChildHash(i)));
|
||||
}
|
||||
}
|
||||
else assert(false);
|
||||
else
|
||||
assert(false);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -296,8 +296,9 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
|
||||
}
|
||||
else if (prefix == sHP_TransactionNode)
|
||||
{
|
||||
uint256 txID; // WRITEME: Need code to extract transaction ID from TX+MD
|
||||
assert(false);
|
||||
uint256 txID;
|
||||
s.get256(txID, s.getLength() - 32);
|
||||
s.chop(32);
|
||||
mItem = boost::make_shared<SHAMapItem>(txID, s.peekData());
|
||||
mType = tnTRANSACTION_MD;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ class Data
|
||||
public:
|
||||
typedef boost::shared_ptr<Data> pointer;
|
||||
|
||||
virtual ~Data(){ ; }
|
||||
|
||||
virtual bool isInt32(){ return(false); }
|
||||
virtual bool isFloat(){ return(false); }
|
||||
virtual bool isUint160(){ return(false); }
|
||||
|
||||
@@ -102,7 +102,7 @@ bool SerializedLedgerEntry::thread(const uint256& txID, uint32 ledgerSeq, uint25
|
||||
if (oldPrevTxID == txID)
|
||||
return false;
|
||||
prevTxID = oldPrevTxID;
|
||||
prevLedgerID = getIFieldU32(sfLastTxnID);
|
||||
prevLedgerID = getIFieldU32(sfLastTxnSeq);
|
||||
assert(prevTxID != txID);
|
||||
setIFieldH256(sfLastTxnID, txID);
|
||||
setIFieldU32(sfLastTxnSeq, ledgerSeq);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "../json/writer.h"
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
std::auto_ptr<SerializedType> STObject::makeDefaultObject(SerializedTypeID id, const char *name)
|
||||
{
|
||||
switch(id)
|
||||
@@ -713,8 +715,7 @@ void STObject::unitTest()
|
||||
copy.setValueFieldU32(sfTest3, 1);
|
||||
if (object1.getSerializer() == copy.getSerializer()) throw std::runtime_error("STObject error");
|
||||
#ifdef DEBUG
|
||||
Json::StyledStreamWriter ssw;
|
||||
ssw.write(std::cerr, copy.getJson(0));
|
||||
Log(lsDEBUG) << copy.getJson(0);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
|
||||
@@ -106,7 +106,6 @@ enum SOE_Field
|
||||
sfTakerGets,
|
||||
sfTakerPays,
|
||||
sfTarget,
|
||||
sfTargetLedger,
|
||||
sfTransferRate,
|
||||
sfVersion,
|
||||
sfWalletLocator,
|
||||
|
||||
@@ -28,7 +28,7 @@ protected:
|
||||
TransactionType mType;
|
||||
STVariableLength mSignature;
|
||||
STObject mMiddleTxn, mInnerTxn;
|
||||
TransactionFormat* mFormat;
|
||||
const TransactionFormat* mFormat;
|
||||
|
||||
SerializedTransaction* duplicate() const { return new SerializedTransaction(*this); }
|
||||
|
||||
|
||||
@@ -281,7 +281,6 @@ public:
|
||||
STAmount getAmount() const { return mTransaction->getITFieldU64(sfAmount); }
|
||||
STAmount getFee() const { return mTransaction->getTransactionFee(); }
|
||||
uint32 getFromAccountSeq() const { return mTransaction->getSequence(); }
|
||||
uint32 getSourceLedger() const { return mTransaction->getITFieldU32(sfTargetLedger); }
|
||||
uint32 getIdent() const { return mTransaction->getITFieldU32(sfSourceTag); }
|
||||
std::vector<unsigned char> getSignature() const { return mTransaction->getSignature(); }
|
||||
uint32 getLedger() const { return mInLedger; }
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
void TransactionEngine::txnWrite()
|
||||
{
|
||||
// Write back the account states and add the transaction to the ledger
|
||||
// Write back the account states
|
||||
for (boost::unordered_map<uint256, LedgerEntrySetEntry>::iterator it = mNodes.begin(), end = mNodes.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
@@ -430,10 +430,10 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
|
||||
break;
|
||||
|
||||
case ttCONTRACT:
|
||||
terResult= doContractAdd(txn);
|
||||
terResult = doContractAdd(txn);
|
||||
break;
|
||||
case ttCONTRACT_REMOVE:
|
||||
terResult=doContractRemove(txn);
|
||||
terResult = doContractRemove(txn);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -458,17 +458,27 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
|
||||
if (tesSUCCESS == terResult || isTepPartial(terResult))
|
||||
{
|
||||
// Transaction succeeded fully or (retries are not allowed and the transaction succeeded partially).
|
||||
Serializer m;
|
||||
mNodes.calcRawMeta(m);
|
||||
|
||||
txnWrite();
|
||||
|
||||
Serializer s;
|
||||
|
||||
txn.add(s);
|
||||
|
||||
if (!mLedger->addTransaction(txID, s))
|
||||
assert(false);
|
||||
if (isSetBit(params, tapOPEN_LEDGER))
|
||||
{
|
||||
if (!mLedger->addTransaction(txID, s))
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mLedger->addTransaction(txID, s, m))
|
||||
assert(false);
|
||||
|
||||
// Charge whatever fee they specified.
|
||||
mLedger->destroyCoins(saPaid.getNValue());
|
||||
// Charge whatever fee they specified.
|
||||
mLedger->destroyCoins(saPaid.getNValue());
|
||||
}
|
||||
}
|
||||
|
||||
mTxnAccount = SLE::pointer();
|
||||
|
||||
@@ -160,11 +160,6 @@ TransactionMetaNode::TransactionMetaNode(int type, const uint256& node, Serializ
|
||||
|
||||
void TransactionMetaNode::addRaw(Serializer& s)
|
||||
{
|
||||
if (mEntries.empty())
|
||||
{ // ack, an empty node
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
s.add8(mType);
|
||||
s.add256(mNode);
|
||||
mEntries.sort();
|
||||
|
||||
@@ -46,6 +46,7 @@ protected:
|
||||
|
||||
public:
|
||||
TransactionMetaNodeEntry(int type) : mType(type) { ; }
|
||||
virtual ~TransactionMetaNodeEntry() { ; }
|
||||
|
||||
int getType() const { return mType; }
|
||||
virtual Json::Value getJson(int) const = 0;
|
||||
@@ -167,6 +168,9 @@ public:
|
||||
|
||||
class TransactionMetaSet
|
||||
{
|
||||
public:
|
||||
typedef boost::shared_ptr<TransactionMetaSet> pointer;
|
||||
|
||||
protected:
|
||||
uint256 mTransactionID;
|
||||
uint32 mLedger;
|
||||
|
||||
@@ -116,19 +116,40 @@ int ValidationCollection::getTrustedValidationCount(const uint256& ledger)
|
||||
return trusted;
|
||||
}
|
||||
|
||||
int ValidationCollection::getCurrentValidationCount(uint32 afterTime)
|
||||
{
|
||||
int ValidationCollection::getNodesAfter(const uint256& ledger)
|
||||
{ // Number of trusted nodes that have moved past this ledger
|
||||
int count = 0;
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
for (boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin(),
|
||||
end = mCurrentValidations.end(); it != end; ++it)
|
||||
{
|
||||
if (it->second->isTrusted() && (it->second->getSignTime() > afterTime))
|
||||
if (it->second->isTrusted() && it->second->isPreviousHash(ledger))
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int ValidationCollection::getLoadRatio(bool overLoaded)
|
||||
{ // how many trusted nodes are able to keep up, higher is better
|
||||
int goodNodes = overLoaded ? 1 : 0;
|
||||
int badNodes = overLoaded ? 0 : 1;
|
||||
{
|
||||
boost::mutex::scoped_lock sl(mValidationLock);
|
||||
for (boost::unordered_map<uint160, SerializedValidation::pointer>::iterator it = mCurrentValidations.begin(),
|
||||
end = mCurrentValidations.end(); it != end; ++it)
|
||||
{
|
||||
if (it->second->isTrusted())
|
||||
{
|
||||
if (it->second->isFull())
|
||||
++goodNodes;
|
||||
else
|
||||
++badNodes;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (goodNodes * 100) / (goodNodes + badNodes);
|
||||
}
|
||||
|
||||
boost::unordered_map<uint256, int> ValidationCollection::getCurrentValidations(uint256 currentLedger)
|
||||
{
|
||||
uint32 cutoff = theApp->getOPs().getNetworkTimeNC() - LEDGER_VAL_INTERVAL;
|
||||
|
||||
@@ -34,7 +34,9 @@ public:
|
||||
void getValidationCount(const uint256& ledger, bool currentOnly, int& trusted, int& untrusted);
|
||||
|
||||
int getTrustedValidationCount(const uint256& ledger);
|
||||
int getCurrentValidationCount(uint32 afterTime);
|
||||
|
||||
int getNodesAfter(const uint256& ledger);
|
||||
int getLoadRatio(bool overLoaded);
|
||||
|
||||
boost::unordered_map<uint256, int> getCurrentValidations(uint256 currentLedger = uint256());
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
//
|
||||
|
||||
#define SERVER_VERSION_MAJOR 0
|
||||
#define SERVER_VERSION_MINOR 4
|
||||
#define SERVER_VERSION_MINOR 5
|
||||
#define SERVER_VERSION_SUB "-a"
|
||||
#define SERVER_NAME "NewCoin"
|
||||
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
// Version we prefer to speak:
|
||||
#define PROTO_VERSION_MAJOR 0
|
||||
#define PROTO_VERSION_MINOR 6
|
||||
#define PROTO_VERSION_MINOR 7
|
||||
|
||||
// Version we will speak to:
|
||||
#define MIN_PROTO_MAJOR 0
|
||||
#define MIN_PROTO_MINOR 6
|
||||
#define MIN_PROTO_MINOR 7
|
||||
|
||||
#define MAKE_VERSION_INT(maj,min) ((maj << 16) | min)
|
||||
#define GET_VERSION_MAJOR(ver) (ver >> 16)
|
||||
|
||||
@@ -27,7 +27,7 @@ private:
|
||||
|
||||
protected:
|
||||
BN_CTX* pctx;
|
||||
BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; }
|
||||
CAutoBN_CTX& operator=(BN_CTX* pnew) { pctx = pnew; return *this; }
|
||||
|
||||
public:
|
||||
CAutoBN_CTX()
|
||||
|
||||
@@ -69,9 +69,6 @@ message TMTransaction {
|
||||
required bytes rawTransaction = 1;
|
||||
required TransactionStatus status = 2;
|
||||
optional uint64 receiveTimestamp = 3;
|
||||
optional uint32 ledgerIndexPossible = 4; // the node may not know
|
||||
optional uint32 ledgerIndexFinal = 5;
|
||||
optional bytes conflictingTransaction = 6;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user