diff --git a/newcoin.vcxproj b/newcoin.vcxproj
index b6093c53a0..67586127c6 100644
--- a/newcoin.vcxproj
+++ b/newcoin.vcxproj
@@ -49,7 +49,7 @@
Level3
Disabled
BOOST_TEST_ALTERNATIVE_INIT_API;BOOST_TEST_NO_MAIN;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0501;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
- ..\OpenSSL\include;..\boost_1_47_0;..\protobuf-2.4.1\src\
+ .\obj;..\OpenSSL\include;..\boost_1_47_0;..\protobuf-2.4.1\src\
ProgramDatabase
@@ -93,7 +93,7 @@
-
+
@@ -268,13 +268,13 @@
Designer
-
- Document
- ..\protoc-2.4.1-win32\protoc -I=..\newcoin\src --cpp_out=..\newcoin\obj\src ..\newcoin\src\newcoin.proto
- obj\src\newcoin.pb.h
-
+
+ Document
+ d:/code/protoc-2.4.1-win32/protoc -I=..\newcoin --cpp_out=D:\code\newcoin\obj\ ..\newcoin/src/ripple.proto
+ D:\code\newcoin\obj\src\ripple.pb.h
+
diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters
index b638955b76..7941c68ec6 100644
--- a/newcoin.vcxproj.filters
+++ b/newcoin.vcxproj.filters
@@ -201,9 +201,6 @@
Source Files\database
-
- Source Files
-
Source Files
@@ -303,6 +300,9 @@
Source Files
+
+ Source Files
+
@@ -567,8 +567,12 @@
+
+
+
+
-
+
\ No newline at end of file
diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp
index 837a518a66..c1df0b3fad 100644
--- a/src/HashedObject.cpp
+++ b/src/HashedObject.cpp
@@ -36,7 +36,7 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index,
if (!mCache.canonicalize(hash, object))
{
// cLog(lsTRACE) << "Queuing write for " << hash;
- boost::recursive_mutex::scoped_lock sl(mWriteMutex);
+ boost::mutex::scoped_lock sl(mWriteMutex);
mWriteSet.push_back(object);
if (!mWritePending)
{
@@ -50,6 +50,13 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index,
return true;
}
+void HashedObjectStore::waitWrite()
+{
+ boost::unique_lock sl(mWriteMutex);
+ while (mWritePending)
+ mWriteCondition.wait(sl);
+}
+
void HashedObjectStore::bulkWrite()
{
std::vector< boost::shared_ptr > set;
@@ -59,11 +66,12 @@ void HashedObjectStore::bulkWrite()
set.reserve(128);
{
- boost::recursive_mutex::scoped_lock sl(mWriteMutex);
+ boost::unique_lock sl(mWriteMutex);
mWriteSet.swap(set);
if (set.empty())
{
mWritePending = false;
+ mWriteCondition.notify_all();
return;
}
}
diff --git a/src/HashedObject.h b/src/HashedObject.h
index f403d5042a..5178af0896 100644
--- a/src/HashedObject.h
+++ b/src/HashedObject.h
@@ -3,6 +3,9 @@
#include
+#include
+#include
+
#include "types.h"
#include "uint256.h"
#include "ScopedLock.h"
@@ -41,7 +44,9 @@ class HashedObjectStore
protected:
TaggedCache mCache;
- boost::recursive_mutex mWriteMutex;
+ boost::mutex mWriteMutex;
+ boost::condition_variable mWriteCondition;
+
std::vector< boost::shared_ptr > mWriteSet;
bool mWritePending;
@@ -55,6 +60,7 @@ public:
HashedObject::pointer retrieve(const uint256& hash);
void bulkWrite();
+ void waitWrite();
};
#endif
diff --git a/src/Ledger.cpp b/src/Ledger.cpp
index b21958e58c..697e0eb1e2 100644
--- a/src/Ledger.cpp
+++ b/src/Ledger.cpp
@@ -35,8 +35,7 @@ Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(s
mAccountStateMap->armDirty();
writeBack(lepCREATE, startAccount->getSLE());
- mAccountStateMap->flushDirty(256, hotACCOUNT_NODE, mLedgerSeq);
- mAccountStateMap->disarmDirty();
+ SHAMap::flushDirty(*mAccountStateMap->disarmDirty(), 256, hotACCOUNT_NODE, mLedgerSeq);
}
Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
@@ -318,7 +317,7 @@ bool Ledger::getTransaction(const uint256& txID, Transaction::pointer& txn, Tran
txn = Transaction::sharedTransaction(it.getVL(), true);
else
it.getVL(); // skip transaction
- meta = boost::make_shared(mLedgerSeq, it.getVL());
+ meta = boost::make_shared(txID, mLedgerSeq, it.getVL());
}
else
return false;
@@ -329,11 +328,6 @@ bool Ledger::getTransaction(const uint256& txID, Transaction::pointer& txn, Tran
return true;
}
-bool Ledger::unitTest()
-{
- return true;
-}
-
uint256 Ledger::getHash()
{
if (!mValidHash)
@@ -363,21 +357,9 @@ void Ledger::saveAcceptedLedger()
{
ScopedLock sl(theApp->getLedgerDB()->getDBLock());
+
if (SQL_EXISTS(theApp->getLedgerDB()->getDB(), boost::str(ledgerExists % mLedgerSeq)))
theApp->getLedgerDB()->getDB()->executeSQL(boost::str(deleteLedger % mLedgerSeq));
- theApp->getLedgerDB()->getDB()->executeSQL(boost::str(addLedger %
- getHash().GetHex() % mLedgerSeq % mParentHash.GetHex() %
- boost::lexical_cast(mTotCoins) % mCloseTime % mParentCloseTime %
- mCloseResolution % mCloseFlags %
- mAccountHash.GetHex() % mTransHash.GetHex()));
-
- // write out dirty nodes
- int fc;
- while ((fc = mTransactionMap->flushDirty(256, hotTRANSACTION_NODE, mLedgerSeq)) > 0)
- { cLog(lsINFO) << "Flushed " << fc << " dirty transaction nodes"; }
- while ((fc = mAccountStateMap->flushDirty(256, hotACCOUNT_NODE, mLedgerSeq)) > 0)
- { cLog(lsINFO) << "Flushed " << fc << " dirty state nodes"; }
- disarmDirty();
SHAMap& txSet = *peekTransactionMap();
Database *db = theApp->getTxnDB()->getDB();
@@ -435,6 +417,13 @@ void Ledger::saveAcceptedLedger()
}
}
db->executeSQL("COMMIT TRANSACTION;");
+
+ theApp->getHashedObjectStore().waitWrite(); // wait until all nodes are written
+ theApp->getLedgerDB()->getDB()->executeSQL(boost::str(addLedger %
+ getHash().GetHex() % mLedgerSeq % mParentHash.GetHex() %
+ boost::lexical_cast(mTotCoins) % mCloseTime % mParentCloseTime %
+ mCloseResolution % mCloseFlags %
+ mAccountHash.GetHex() % mTransHash.GetHex()));
}
theApp->getOPs().pubLedger(shared_from_this());
@@ -565,7 +554,7 @@ Json::Value Ledger::getJson(int options)
SerializerIterator tsit(sTxn);
SerializedTransaction txn(tsit);
- TransactionMetaSet meta(mLedgerSeq, sit.getVL());
+ TransactionMetaSet meta(item->getTag(), mLedgerSeq, sit.getVL());
Json::Value txJson = txn.getJson(0);
txJson["metaData"] = meta.getJson(0);
txns.append(txJson);
diff --git a/src/Ledger.h b/src/Ledger.h
index 0c201d12fe..aa9cc9f142 100644
--- a/src/Ledger.h
+++ b/src/Ledger.h
@@ -109,8 +109,6 @@ public:
bool isClosed() { return mClosed; }
bool isAccepted() { return mAccepted; }
bool isImmutable() { return mImmutable; }
- void armDirty() { mTransactionMap->armDirty(); mAccountStateMap->armDirty(); }
- void disarmDirty() { mTransactionMap->disarmDirty(); mAccountStateMap->disarmDirty(); }
// ledger signature operations
void addRaw(Serializer &s) const;
@@ -283,8 +281,6 @@ public:
bool walkLedger();
bool assertSane();
-
- static bool unitTest();
};
inline LedgerStateParms operator|(const LedgerStateParms& l1, const LedgerStateParms& l2)
diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp
index 83dcbefefe..f241934ed9 100644
--- a/src/LedgerConsensus.cpp
+++ b/src/LedgerConsensus.cpp
@@ -259,7 +259,7 @@ void LedgerConsensus::checkLCL()
uint256 netLgr = mPrevLedgerHash;
int netLgrCount = 0;
- uint256 favoredLedger = (mState == lcsPRE_CLOSE) ? uint256() : mPrevLedgerHash; // Don't get stuck one ledger behind
+ uint256 favoredLedger = (mState == lcsPRE_CLOSE) ? uint256() : mPrevLedgerHash; // Don't get stuck one ledger back
boost::unordered_map vals =
theApp->getValidations().getCurrentValidations(favoredLedger);
@@ -287,15 +287,18 @@ void LedgerConsensus::checkLCL()
<< status << ", " << (mHaveCorrectLCL ? "CorrectLCL" : "IncorrectLCL");
cLog(lsWARNING) << mPrevLedgerHash << " to " << netLgr;
-#ifdef DEBUG
- BOOST_FOREACH(u256_cvc_pair& it, vals)
- cLog(lsDEBUG) << "V: " << it.first << ", " << it.second.first;
-#endif
+ if (sLog(lsDEBUG))
+ {
+ BOOST_FOREACH(u256_cvc_pair& it, vals)
+ cLog(lsDEBUG) << "V: " << it.first << ", " << it.second.first;
+ }
if (mHaveCorrectLCL)
theApp->getOPs().consensusViewChange();
handleLCL(netLgr);
}
+ else if (mPreviousLedger->getHash() != mPrevLedgerHash)
+ handleLCL(netLgr);
}
void LedgerConsensus::handleLCL(const uint256& lclHash)
@@ -356,6 +359,7 @@ void LedgerConsensus::handleLCL(const uint256& lclHash)
cLog(lsINFO) << "Acquired the consensus ledger " << mPrevLedgerHash;
mHaveCorrectLCL = true;
mAcquiringLedger = LedgerAcquire::pointer();
+ theApp->getOPs().clearNeedNetworkLedger();
mCloseResolution = ContinuousLedgerTiming::getNextLedgerTimeResolution(
mPreviousLedger->getCloseResolution(), mPreviousLedger->getCloseAgree(),
mPreviousLedger->getLedgerSeq() + 1);
@@ -810,7 +814,9 @@ void LedgerConsensus::propose()
{
cLog(lsTRACE) << "We propose: " << mOurPosition->getCurrentHash();
ripple::TMProposeSet prop;
+
prop.set_currenttxhash(mOurPosition->getCurrentHash().begin(), 256 / 8);
+ prop.set_previousledger(mOurPosition->getPrevLedger().begin(), 256 / 8);
prop.set_proposeseq(mOurPosition->getProposeSeq());
prop.set_closetime(mOurPosition->getCloseTime());
@@ -958,18 +964,12 @@ void LedgerConsensus::Saccept(boost::shared_ptr This, SHAMap::p
This->accept(txSet);
}
-void LedgerConsensus::deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic)
-{
- std::list& props = mDeferredProposals[peerPublic.getNodeID()];
- if (props.size() >= (mPreviousProposers + 10))
- props.pop_front();
- props.push_back(proposal);
-}
-
void LedgerConsensus::playbackProposals()
{
+ boost::unordered_map >& storedProposals = theApp->getOPs().peekStoredProposals();
for (boost::unordered_map< uint160, std::list >::iterator
- it = mDeferredProposals.begin(), end = mDeferredProposals.end(); it != end; ++it)
+ it = storedProposals.begin(), end = storedProposals.end(); it != end; ++it)
{
BOOST_FOREACH(const LedgerProposal::pointer& proposal, it->second)
{
@@ -978,7 +978,7 @@ void LedgerConsensus::playbackProposals()
proposal->setPrevLedger(mPrevLedgerHash);
if (proposal->checkSign())
{
- cLog(lsINFO) << "Applying deferred proposal";
+ cLog(lsINFO) << "Applying stored proposal";
peerPosition(proposal);
}
}
@@ -1098,12 +1098,23 @@ void LedgerConsensus::accept(SHAMap::ref set)
cLog(lsINFO) << "CNF mode " << theApp->getOPs().getOperatingMode() << ", oldLCL " << mPrevLedgerHash;
}
- Ledger::pointer newLCL = boost::make_shared(false, boost::ref(*mPreviousLedger));
- newLCL->armDirty();
-
CanonicalTXSet failedTransactions(set->getHash());
+
+ Ledger::pointer newLCL = boost::make_shared(false, boost::ref(*mPreviousLedger));
+
+ newLCL->peekTransactionMap()->armDirty();
+ newLCL->peekAccountStateMap()->armDirty();
applyTransactions(set, newLCL, newLCL, failedTransactions, false);
newLCL->setClosed();
+ boost::shared_ptr acctNodes = newLCL->peekAccountStateMap()->disarmDirty();
+ boost::shared_ptr txnNodes = newLCL->peekTransactionMap()->disarmDirty();
+
+ // write out dirty nodes (temporarily done here) Most come before setAccepted
+ int fc;
+ while ((fc = SHAMap::flushDirty(*acctNodes, 256, hotACCOUNT_NODE, newLCL->getLedgerSeq())) > 0)
+ { cLog(lsINFO) << "Flushed " << fc << " dirty state nodes"; }
+ while ((fc = SHAMap::flushDirty(*txnNodes, 256, hotTRANSACTION_NODE, newLCL->getLedgerSeq())) > 0)
+ { cLog(lsINFO) << "Flushed " << fc << " dirty transaction nodes"; }
bool closeTimeCorrect = true;
if (closeTime == 0)
diff --git a/src/LedgerConsensus.h b/src/LedgerConsensus.h
index ffe8db5d3c..a88aee0792 100644
--- a/src/LedgerConsensus.h
+++ b/src/LedgerConsensus.h
@@ -113,9 +113,6 @@ protected:
// Close time estimates
std::map mCloseTimes;
- // deferred proposals (node ID -> proposals from that peer)
- boost::unordered_map< uint160, std::list > mDeferredProposals;
-
// nodes that have bowed out of this consensus process
boost::unordered_set mDeadNodes;
@@ -180,16 +177,12 @@ public:
bool haveConsensus();
bool peerPosition(const LedgerProposal::pointer&);
- void deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic);
bool peerHasSet(Peer::ref peer, const uint256& set, ripple::TxSetStatus status);
bool peerGaveNodes(Peer::ref peer, const uint256& setHash,
const std::list& nodeIDs, const std::list< std::vector >& nodeData);
- void swapDefer(boost::unordered_map< uint160, std::list > &n)
- { mDeferredProposals.swap(n); }
-
// test/debug
void simulate();
};
diff --git a/src/LedgerEntrySet.cpp b/src/LedgerEntrySet.cpp
index e804f33c25..d074f902d1 100644
--- a/src/LedgerEntrySet.cpp
+++ b/src/LedgerEntrySet.cpp
@@ -318,7 +318,8 @@ bool LedgerEntrySet::threadTx(SLE::ref threadTo, Ledger::ref ledger,
uint32 prevLgrID;
if (!threadTo->thread(mSet.getTxID(), mSet.getLgrSeq(), prevTxID, prevLgrID))
return false;
- if (mSet.getAffectedNode(threadTo->getIndex(), TMNModifiedNode, false).thread(prevTxID, prevLgrID))
+ if (TransactionMetaSet::thread(mSet.getAffectedNode(threadTo->getIndex(), sfModifiedNode, false),
+ prevTxID, prevLgrID))
return true;
assert(false);
return false;
@@ -347,7 +348,7 @@ bool LedgerEntrySet::threadOwners(SLE::ref node, Ledger::ref ledger,
return false;
}
-void LedgerEntrySet::calcRawMeta(Serializer& s)
+void LedgerEntrySet::calcRawMeta(Serializer& s, TER result)
{ // 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
@@ -356,7 +357,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
for (std::map::const_iterator it = mEntries.begin(),
end = mEntries.end(); it != end; ++it)
{
- int nType = TMNEndOfMetadata;
+ SField::ptr type = &sfGeneric;
switch (it->second.mAction)
{
@@ -364,28 +365,28 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
#ifdef META_DEBUG
cLog(lsTRACE) << "Modified Node " << it->first;
#endif
- nType = TMNModifiedNode;
+ type = &sfModifiedNode;
break;
case taaDELETE:
#ifdef META_DEBUG
cLog(lsTRACE) << "Deleted Node " << it->first;
#endif
- nType = TMNDeletedNode;
+ type = &sfDeletedNode;
break;
case taaCREATE:
#ifdef META_DEBUG
cLog(lsTRACE) << "Created Node " << it->first;
#endif
- nType = TMNCreatedNode;
+ type = &sfCreatedNode;
break;
default: // ignore these
break;
}
- if (nType == TMNEndOfMetadata)
+ if (type == &sfGeneric)
continue;
SLE::pointer origNode = mLedger->getSLE(it->first);
@@ -394,9 +395,9 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
continue;
SLE::pointer curNode = it->second.mEntry;
- TransactionMetaNode &metaNode = mSet.getAffectedNode(it->first, nType, true);
+ STObject &metaNode = mSet.getAffectedNode(it->first, *type, true);
- if (nType == TMNDeletedNode)
+ if (type == &sfDeletedNode)
{
assert(origNode);
threadOwners(origNode, mLedger, newMod);
@@ -405,16 +406,16 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
{ // node has an amount, covers ripple state nodes
STAmount amount = origNode->getFieldAmount(sfAmount);
if (amount.isNonZero())
- metaNode.addAmount(TMSPrevBalance, amount);
+ metaNode.setFieldAmount(sfPreviousBalance, amount);
amount = curNode->getFieldAmount(sfAmount);
if (amount.isNonZero())
- metaNode.addAmount(TMSFinalBalance, amount);
+ metaNode.setFieldAmount(sfFinalBalance, amount);
if (origNode->getType() == ltRIPPLE_STATE)
{
- metaNode.addAccount(TMSLowID,
+ metaNode.setFieldAccount(sfLowID,
NewcoinAddress::createAccountID(origNode->getFieldAmount(sfLowLimit).getIssuer()));
- metaNode.addAccount(TMSHighID,
+ metaNode.setFieldAccount(sfHighID,
NewcoinAddress::createAccountID(origNode->getFieldAmount(sfHighLimit).getIssuer()));
}
}
@@ -423,44 +424,44 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
{ // check for non-zero balances
STAmount amount = origNode->getFieldAmount(sfTakerPays);
if (amount.isNonZero())
- metaNode.addAmount(TMSFinalTakerPays, amount);
+ metaNode.setFieldAmount(sfFinalTakerPays, amount);
amount = origNode->getFieldAmount(sfTakerGets);
if (amount.isNonZero())
- metaNode.addAmount(TMSFinalTakerGets, amount);
+ metaNode.setFieldAmount(sfFinalTakerGets, amount);
}
}
- if (nType == TMNCreatedNode) // if created, thread to owner(s)
+ if (type == &sfCreatedNode) // if created, thread to owner(s)
{
assert(!origNode);
threadOwners(curNode, mLedger, newMod);
}
- if ((nType == TMNCreatedNode) || (nType == TMNModifiedNode))
+ if ((type == &sfCreatedNode) || (type == &sfModifiedNode))
{
if (curNode->isThreadedType()) // always thread to self
threadTx(curNode, mLedger, newMod);
}
- if (nType == TMNModifiedNode)
+ if (type == &sfModifiedNode)
{
assert(origNode);
if (origNode->isFieldPresent(sfAmount))
{ // node has an amount, covers account root nodes and ripple nodes
STAmount amount = origNode->getFieldAmount(sfAmount);
if (amount != curNode->getFieldAmount(sfAmount))
- metaNode.addAmount(TMSPrevBalance, amount);
+ metaNode.setFieldAmount(sfPreviousBalance, amount);
}
if (origNode->getType() == ltOFFER)
{
STAmount amount = origNode->getFieldAmount(sfTakerPays);
if (amount != curNode->getFieldAmount(sfTakerPays))
- metaNode.addAmount(TMSPrevTakerPays, amount);
+ metaNode.setFieldAmount(sfPreviousTakerPays, amount);
amount = origNode->getFieldAmount(sfTakerGets);
if (amount != curNode->getFieldAmount(sfTakerGets))
- metaNode.addAmount(TMSPrevTakerGets, amount);
+ metaNode.setFieldAmount(sfPreviousTakerGets, amount);
}
}
@@ -475,7 +476,7 @@ void LedgerEntrySet::calcRawMeta(Serializer& s)
cLog(lsINFO) << "Metadata:" << mSet.getJson(0);
#endif
- mSet.addRaw(s);
+ mSet.addRaw(s, result);
}
// <-- uNodeDir: For deletion, present to make dirDelete efficient.
diff --git a/src/LedgerEntrySet.h b/src/LedgerEntrySet.h
index 11192c363d..2558f12881 100644
--- a/src/LedgerEntrySet.h
+++ b/src/LedgerEntrySet.h
@@ -120,7 +120,7 @@ public:
STAmount accountFunds(const uint160& uAccountID, const STAmount& saDefault);
Json::Value getJson(int) const;
- void calcRawMeta(Serializer&);
+ void calcRawMeta(Serializer&, TER result);
// iterator functions
bool isEmpty() const { return mEntries.empty(); }
diff --git a/src/LedgerHistory.cpp b/src/LedgerHistory.cpp
index 2c1563d639..75519538a2 100644
--- a/src/LedgerHistory.cpp
+++ b/src/LedgerHistory.cpp
@@ -99,7 +99,9 @@ Ledger::pointer LedgerHistory::canonicalizeLedger(Ledger::pointer ledger, bool s
// save input ledger in map if not in map, otherwise return corresponding map ledger
boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex());
mLedgersByHash.canonicalize(h, ledger);
- if (ledger->isAccepted()) mLedgersByIndex[ledger->getLedgerSeq()] = ledger;
+ if (ledger->isAccepted())
+ mLedgersByIndex[ledger->getLedgerSeq()] = ledger;
return ledger;
}
+
// vim:ts=4
diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp
index c594c086f1..477cca2275 100644
--- a/src/NetworkOPs.cpp
+++ b/src/NetworkOPs.cpp
@@ -646,8 +646,11 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo
Ledger::pointer prevLedger = mLedgerMaster->getLedgerByHash(closingLedger->getParentHash());
if (!prevLedger)
{ // this shouldn't happen unless we jump ledgers
- cLog(lsWARNING) << "Don't have LCL, going to tracking";
- setMode(omTRACKING);
+ if (mMode == omFULL)
+ {
+ cLog(lsWARNING) << "Don't have LCL, going to tracking";
+ setMode(omTRACKING);
+ }
return 3;
}
assert(prevLedger->getHash() == closingLedger->getParentHash());
@@ -658,7 +661,6 @@ int NetworkOPs::beginConsensus(const uint256& networkClosed, Ledger::pointer clo
prevLedger->setImmutable();
mConsensus = boost::make_shared(
networkClosed, prevLedger, mLedgerMaster->getCurrentLedger()->getCloseTimeNC());
- mConsensus->swapDefer(mDeferredProposals);
cLog(lsDEBUG) << "Initiating consensus engine";
return mConsensus->startup();
@@ -728,7 +730,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, cons
}
if (prevLedger == mConsensus->getLCL())
return mConsensus->peerPosition(proposal);
- mConsensus->deferProposal(proposal, nodePublic);
+ storeProposal(proposal, nodePublic);
return false;
}
@@ -738,7 +740,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, cons
{ // Note that if the LCL is different, the signature check will fail
cLog(lsWARNING) << "Ledger proposal fails signature check";
proposal->setSignature(signature);
- mConsensus->deferProposal(proposal, nodePublic);
+ storeProposal(proposal, nodePublic);
return false;
}
return mConsensus->peerPosition(proposal);
@@ -785,7 +787,6 @@ void NetworkOPs::endConsensus(bool correctLCL)
cLog(lsTRACE) << "Killing obsolete peer status";
it->cycleStatus();
}
- mConsensus->swapDefer(mDeferredProposals);
mConsensus = boost::shared_ptr();
}
@@ -874,8 +875,13 @@ Json::Value NetworkOPs::getServerInfo()
default: info["serverState"] = "unknown";
}
- if (!theConfig.VALIDATION_SEED.isValid()) info["serverState"] = "none";
- else info["validationPKey"] = NewcoinAddress::createNodePublic(theConfig.VALIDATION_SEED).humanNodePublic();
+ if (!theConfig.VALIDATION_SEED.isValid())
+ info["serverState"] = "none";
+ else
+ info["validationPKey"] = NewcoinAddress::createNodePublic(theConfig.VALIDATION_SEED).humanNodePublic();
+
+ if (mNeedNetworkLedger)
+ info["networkLedger"] = "waiting";
Json::Value lastClose = Json::objectValue;
lastClose["proposers"] = theApp->getOPs().getPreviousProposers();
@@ -1244,6 +1250,14 @@ uint32 NetworkOPs::acceptLedger()
return mLedgerMaster->getCurrentLedger()->getLedgerSeq();
}
+void NetworkOPs::storeProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic)
+{
+ std::list& props = mStoredProposals[peerPublic.getNodeID()];
+ if (props.size() >= (mLastCloseProposers + 10))
+ props.pop_front();
+ props.push_back(proposal);
+}
+
#if 0
void NetworkOPs::subAccountChanges(InfoSub* ispListener, const uint256 uLedgerHash)
{
diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h
index 931364054f..cd2e8bede0 100644
--- a/src/NetworkOPs.h
+++ b/src/NetworkOPs.h
@@ -57,7 +57,7 @@ protected:
boost::asio::deadline_timer mNetTimer;
boost::shared_ptr mConsensus;
boost::unordered_map > mDeferredProposals;
+ std::list > mStoredProposals;
LedgerMaster* mLedgerMaster;
LedgerAcquire::pointer mAcquiringLedger;
@@ -186,6 +186,8 @@ public:
void setStateTimer();
void newLCL(int proposers, int convergeTime, const uint256& ledgerHash);
void needNetworkLedger() { mNeedNetworkLedger = true; }
+ void clearNeedNetworkLedger() { mNeedNetworkLedger = false; }
+ bool isNeedNetworkLedger() { return mNeedNetworkLedger; }
void consensusViewChange();
int getPreviousProposers() { return mLastCloseProposers; }
int getPreviousConvergeTime() { return mLastCloseConvergeTime; }
@@ -193,6 +195,9 @@ public:
void setLastCloseTime(uint32 t) { mLastCloseTime = t; }
Json::Value getServerInfo();
uint32 acceptLedger();
+ boost::unordered_map >& peekStoredProposals() { return mStoredProposals; }
+ void storeProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic);
// client information retrieval functions
std::vector< std::pair >
diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp
index 1c88bb2082..07d8376cb8 100644
--- a/src/RPCServer.cpp
+++ b/src/RPCServer.cpp
@@ -133,7 +133,7 @@ void RPCServer::handle_read(const boost::system::error_code& e,
}
else if (!result)
{ // bad request
- std::cout << "bad request" << std::endl;
+ std::cout << "bad request: " << mIncomingRequest.mBody <(mSeq, SHAMapNode(0, uint256()));
root->makeInner();
@@ -138,7 +138,8 @@ void SHAMap::dirtyUp(std::stack& stack, const uint256&
SHAMapTreeNode::pointer SHAMap::checkCacheNode(const SHAMapNode& iNode)
{
boost::unordered_map::iterator it = mTNByID.find(iNode);
- if (it == mTNByID.end()) return SHAMapTreeNode::pointer();
+ if (it == mTNByID.end())
+ return SHAMapTreeNode::pointer();
return it->second;
}
@@ -209,6 +210,7 @@ SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& id, const uint256& has
node = fetchNodeExternal(id, hash);
if (!mTNByID.insert(std::make_pair(id, node)).second)
assert(false);
+ trackNewNode(node);
return node;
}
@@ -221,6 +223,7 @@ SHAMapTreeNode* SHAMap::getNodePointer(const SHAMapNode& id, const uint256& hash
SHAMapTreeNode::pointer node = fetchNodeExternal(id, hash);
if (!mTNByID.insert(std::make_pair(id, node)).second)
assert(false);
+ trackNewNode(node);
return node.get();
}
@@ -230,16 +233,25 @@ void SHAMap::returnNode(SHAMapTreeNode::pointer& node, bool modify)
assert(node->getSeq() <= mSeq);
if (node && modify && (node->getSeq() != mSeq))
{ // have a CoW
- node = boost::make_shared(*node, mSeq);
- if (mDirtyNodes)
- (*mDirtyNodes)[*node] = node;
+ assert(node->getSeq() < mSeq);
+
+ node = boost::make_shared(*node, mSeq); // here's to the new node, same as the old node
assert(node->isValid());
+
mTNByID[*node] = node;
if (node->isRoot())
root = node;
+ if (mDirtyNodes)
+ (*mDirtyNodes)[*node] = node;
}
}
+void SHAMap::trackNewNode(SHAMapTreeNode::pointer& node)
+{
+ if (mDirtyNodes)
+ (*mDirtyNodes)[*node] = node;
+}
+
SHAMapItem::SHAMapItem(const uint256& tag, const std::vector& data)
: mTag(tag), mData(data)
{ ; }
@@ -594,6 +606,7 @@ bool SHAMap::addGiveItem(SHAMapItem::ref item, bool isTransaction, bool hasMeta)
assert(false);
throw std::runtime_error("invalid inner node");
}
+ trackNewNode(newNode);
node->setChildHash(branch, newNode->getNodeHash());
}
else
@@ -622,6 +635,7 @@ bool SHAMap::addGiveItem(SHAMapItem::ref item, bool isTransaction, bool hasMeta)
assert(false);
stack.push(node);
node = newNode;
+ trackNewNode(node);
}
// we can add the two leaf nodes here
@@ -632,12 +646,14 @@ bool SHAMap::addGiveItem(SHAMapItem::ref item, bool isTransaction, bool hasMeta)
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
assert(false);
node->setChildHash(b1, newNode->getNodeHash()); // OPTIMIZEME hash op not needed
+ trackNewNode(newNode);
newNode = boost::make_shared(node->getChildNodeID(b2), otherItem, type, mSeq);
assert(newNode->isValid() && newNode->isLeaf());
if (!mTNByID.insert(std::make_pair(SHAMapNode(*newNode), newNode)).second)
assert(false);
node->setChildHash(b2, newNode->getNodeHash());
+ trackNewNode(newNode);
}
dirtyUp(stack, tag, node->getNodeHash());
@@ -703,8 +719,19 @@ SHAMapTreeNode::pointer SHAMap::fetchNodeExternal(const SHAMapNode& id, const ui
try
{
- SHAMapTreeNode::pointer ret = boost::make_shared(id, obj->getData(), mSeq, snfPREFIX);
- assert((ret->getNodeHash() == hash) && (id == *ret));
+ SHAMapTreeNode::pointer ret = boost::make_shared(id, obj->getData(), mSeq - 1, snfPREFIX);
+#ifdef DEBUG
+ if (id != *ret)
+ {
+ Log(lsFATAL) << "id:" << id << ", got:" << *ret;
+ assert(false);
+ }
+ if (ret->getNodeHash() != hash)
+ {
+ Log(lsFATAL) << "Hashes don't match";
+ assert(false);
+ }
+#endif
return ret;
}
catch (...)
@@ -730,40 +757,43 @@ void SHAMap::fetchRoot(const uint256& hash)
assert(root->getNodeHash() == hash);
}
-void SHAMap::armDirty()
+int SHAMap::armDirty()
{ // begin saving dirty nodes
- ++mSeq;
mDirtyNodes = boost::make_shared< boost::unordered_map >();
+ return ++mSeq;
}
-int SHAMap::flushDirty(int maxNodes, HashedObjectType t, uint32 seq)
+int SHAMap::flushDirty(SHADirtyMap& map, int maxNodes, HashedObjectType t, uint32 seq)
{
int flushed = 0;
Serializer s;
- if (mDirtyNodes)
+ for(SHADirtyMap::iterator it = map.begin(); it != map.end(); it = map.erase(it))
{
- boost::unordered_map& dirtyNodes = *mDirtyNodes;
- boost::unordered_map::iterator it = dirtyNodes.begin();
- while (it != dirtyNodes.end())
+// tLog(t == hotTRANSACTION_NODE, lsDEBUG) << "TX node write " << it->first;
+// tLog(t == hotACCOUNT_NODE, lsDEBUG) << "STATE node write " << it->first;
+ s.erase();
+ it->second->addRaw(s, snfPREFIX);
+ if (s.getSHA512Half() != it->second->getNodeHash())
{
-// tLog(mType == smtTRANSACTION, lsDEBUG) << "TX node write " << it->first;
-// tLog(mType == smtSTATE, lsDEBUG) << "STATE node write " << it->first;
- s.erase();
- it->second->addRaw(s, snfPREFIX);
- theApp->getHashedObjectStore().store(t, seq, s.peekData(), s.getSHA512Half());
- if (flushed++ >= maxNodes)
- return flushed;
- it = dirtyNodes.erase(it);
+ cLog(lsFATAL) << *(it->second);
+ cLog(lsFATAL) << lexical_cast_i(s.getDataLength());
+ cLog(lsFATAL) << s.getSHA512Half() << " != " << it->second->getNodeHash();
+ assert(false);
}
+ theApp->getHashedObjectStore().store(t, seq, s.peekData(), it->second->getNodeHash());
+ if (flushed++ >= maxNodes)
+ return flushed;
}
return flushed;
}
-void SHAMap::disarmDirty()
+boost::shared_ptr SHAMap::disarmDirty()
{ // stop saving dirty nodes
- mDirtyNodes = boost::shared_ptr< boost::unordered_map >();
+ boost::shared_ptr ret;
+ ret.swap(mDirtyNodes);
+ return ret;
}
SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& nodeID)
diff --git a/src/SHAMap.h b/src/SHAMap.h
index 6d579a918d..a30c1f8808 100644
--- a/src/SHAMap.h
+++ b/src/SHAMap.h
@@ -283,13 +283,14 @@ public:
typedef const boost::shared_ptr& ref;
typedef std::map > SHAMapDiff;
+ typedef boost::unordered_map SHADirtyMap;
private:
uint32 mSeq;
mutable boost::recursive_mutex mLock;
boost::unordered_map mTNByID;
- boost::shared_ptr< boost::unordered_map > mDirtyNodes;
+ boost::shared_ptr mDirtyNodes;
SHAMapTreeNode::pointer root;
@@ -305,6 +306,7 @@ protected:
SHAMapTreeNode* walkToPointer(const uint256& id);
SHAMapTreeNode::pointer checkCacheNode(const SHAMapNode&);
void returnNode(SHAMapTreeNode::pointer&, bool modify);
+ void trackNewNode(SHAMapTreeNode::pointer&);
SHAMapTreeNode::pointer getNode(const SHAMapNode& id);
SHAMapTreeNode::pointer getNode(const SHAMapNode& id, const uint256& hash, bool modify);
@@ -321,7 +323,7 @@ protected:
public:
// build new map
- SHAMap(SHAMapType t, uint32 seq = 0);
+ SHAMap(SHAMapType t, uint32 seq = 1);
SHAMap(SHAMapType t, const uint256& hash);
~SHAMap() { mState = smsInvalid; }
@@ -384,9 +386,9 @@ public:
// return value: true=successfully completed, false=too different
bool compare(SHAMap::ref otherMap, SHAMapDiff& differences, int maxCount);
- void armDirty();
- int flushDirty(int maxNodes, HashedObjectType t, uint32 seq);
- void disarmDirty();
+ int armDirty();
+ static int flushDirty(SHADirtyMap& dirtyMap, int maxNodes, HashedObjectType t, uint32 seq);
+ boost::shared_ptr disarmDirty();
void setSeq(uint32 seq) { mSeq = seq; }
uint32 getSeq() { return mSeq; }
diff --git a/src/SHAMapNodes.cpp b/src/SHAMapNodes.cpp
index 6c02b79a3b..2eaa0ed806 100644
--- a/src/SHAMapNodes.cpp
+++ b/src/SHAMapNodes.cpp
@@ -300,7 +300,9 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector(mHashes), sizeof(mHashes));
}
- else if (mType == tnACCOUNT_STATE)
- {
- Serializer s((256 + 32) / 8 + mItem->peekData().size());
- s.add32(sHP_LeafNode);
- mItem->addRaw(s);
- s.add256(mItem->getTag());
- nh = s.getSHA512Half();
- }
else if (mType == tnTRANSACTION_NM)
{
nh = Serializer::getPrefixHash(sHP_TransactionID, mItem->peekData());
}
+ else if (mType == tnACCOUNT_STATE)
+ {
+ Serializer s(mItem->peekSerializer().getDataLength() + (256 + 32) / 8);
+ s.add32(sHP_LeafNode);
+ s.addRaw(mItem->peekData());
+ s.add256(mItem->getTag());
+ nh = s.getSHA512Half();
+ }
else if (mType == tnTRANSACTION_MD)
{
- nh = Serializer::getPrefixHash(sHP_TransactionNode, mItem->peekData());
+ Serializer s(mItem->peekSerializer().getDataLength() + (256 + 32) / 8);
+ s.add32(sHP_TransactionNode);
+ s.addRaw(mItem->peekData());
+ s.add256(mItem->getTag());
+ nh = s.getSHA512Half();
}
else
assert(false);
@@ -427,6 +433,7 @@ void SHAMapTreeNode::addRaw(Serializer& s, SHANodeFormat format)
{
s.add32(sHP_TransactionNode);
mItem->addRaw(s);
+ s.add256(mItem->getTag());
}
else
{
@@ -505,11 +512,21 @@ std::string SHAMapTreeNode::getString() const
}
if (isLeaf())
{
- ret += ",leaf\n";
+ if (mType == tnTRANSACTION_NM)
+ ret += ",txn\n";
+ else if (mType == tnTRANSACTION_MD)
+ ret += ",txn+md\n";
+ else if (mType == tnACCOUNT_STATE)
+ ret += ",as\n";
+ else
+ ret += ",leaf\n";
+
ret += " Tag=";
ret += getTag().GetHex();
ret += "\n Hash=";
ret += mHash.GetHex();
+ ret += "/";
+ ret += lexical_cast_i(mItem->peekSerializer().getDataLength());
}
return ret;
}
diff --git a/src/SerializeProto.h b/src/SerializeProto.h
index df7d2f6d5c..f7d46a50fd 100644
--- a/src/SerializeProto.h
+++ b/src/SerializeProto.h
@@ -25,6 +25,7 @@
// 8-bit integers
FIELD(CloseResolution, UINT8, 1)
FIELD(TemplateEntryType, UINT8, 2)
+ FIELD(TransactionResult, UINT8, 3)
// 16-bit integers
FIELD(LedgerEntryType, UINT16, 1)
@@ -92,8 +93,14 @@
FIELD(SendMax, AMOUNT, 9)
// currency amount (uncommon)
- FIELD(MinimumOffer, AMOUNT, 16)
- FIELD(RippleEscrow, AMOUNT, 17)
+ FIELD(MinimumOffer, AMOUNT, 16)
+ FIELD(RippleEscrow, AMOUNT, 17)
+ FIELD(PreviousBalance, AMOUNT, 18)
+ FIELD(FinalBalance, AMOUNT, 19)
+ FIELD(PreviousTakerPays, AMOUNT, 20)
+ FIELD(PreviousTakerGets, AMOUNT, 21)
+ FIELD(FinalTakerPays, AMOUNT, 22)
+ FIELD(FinalTakerGets, AMOUNT, 23)
// variable length
FIELD(PublicKey, VL, 1)
@@ -116,6 +123,11 @@
FIELD(Target, ACCOUNT, 7)
FIELD(AuthorizedKey, ACCOUNT, 8)
+ // account (uncommon)
+ FIELD(PreviousAccount, ACCOUNT, 16)
+ FIELD(LowID, ACCOUNT, 17)
+ FIELD(HighID, ACCOUNT, 18)
+
// path set
FIELD(Paths, PATHSET, 1)
@@ -125,9 +137,14 @@
// inner object
// OBJECT/1 is reserved for end of object
FIELD(TemplateEntry, OBJECT, 1)
+ FIELD(TransactionMetaData, OBJECT, 2)
+ FIELD(CreatedNode, OBJECT, 3)
+ FIELD(DeletedNode, OBJECT, 4)
+ FIELD(ModifiedNode, OBJECT, 5)
// array of objects
// ARRAY/1 is reserved for end of array
+ FIELD(AffectedNodes, ARRAY, 1)
FIELD(SigningAccounts, ARRAY, 2)
FIELD(TxnSignatures, ARRAY, 3)
FIELD(Signatures, ARRAY, 4)
diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp
index 678b1add3c..6bcae3c067 100644
--- a/src/SerializedObject.cpp
+++ b/src/SerializedObject.cpp
@@ -24,6 +24,9 @@ std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, S
case STI_NOTPRESENT:
return std::auto_ptr(new SerializedType(name));
+ case STI_UINT8:
+ return std::auto_ptr(new STUInt8(name));
+
case STI_UINT16:
return std::auto_ptr(new STUInt16(name));
@@ -64,6 +67,8 @@ std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, S
return std::auto_ptr(new STArray(name));
default:
+ cLog(lsFATAL) << "Object type: " << lexical_cast_i(id);
+ assert(false);
throw std::runtime_error("Unknown object type");
}
}
@@ -76,6 +81,9 @@ std::auto_ptr STObject::makeDeserializedObject(SerializedTypeID
case STI_NOTPRESENT:
return SerializedType::deserialize(name);
+ case STI_UINT8:
+ return STUInt8::deserialize(sit, name);
+
case STI_UINT16:
return STUInt16::deserialize(sit, name);
@@ -396,6 +404,19 @@ bool STObject::isFieldPresent(SField::ref field) const
return peekAtIndex(index).getSType() != STI_NOTPRESENT;
}
+STObject& STObject::peekFieldObject(SField::ref field)
+{
+ SerializedType* rf = getPField(field, true);
+ if (!rf)
+ throw std::runtime_error("Field not found");
+ if (rf->getSType() == STI_NOTPRESENT)
+ rf = makeFieldPresent(field);
+ STObject* cf = dynamic_cast(rf);
+ if (!cf)
+ throw std::runtime_error("Wrong field type");
+ return *cf;
+}
+
bool STObject::setFlag(uint32 f)
{
STUInt32* t = dynamic_cast(getPField(sfFlags, true));
@@ -818,8 +839,20 @@ std::string STArray::getText() const
Json::Value STArray::getJson(int p) const
{
Json::Value v = Json::arrayValue;
- BOOST_FOREACH(const STObject& o, value)
- v.append(o.getJson(p));
+ int index = 1;
+ BOOST_FOREACH(const STObject& object, value)
+ {
+ if (object.getSType() != STI_NOTPRESENT)
+ {
+ Json::Value inner = Json::objectValue;
+ if (!object.getFName().hasName())
+ inner[lexical_cast_i(index)] = object.getJson(p);
+ else
+ inner[object.getName()] = object.getJson(p);
+ v.append(inner);
+ index++;
+ }
+ }
return v;
}
@@ -866,6 +899,11 @@ STArray* STArray::construct(SerializerIterator& sit, SField::ref field)
return new STArray(field, value);
}
+void STArray::sort(bool (*compare)(const STObject&, const STObject&))
+{
+ std::sort(value.begin(), value.end(), compare);
+}
+
std::auto_ptr STObject::parseJson(const Json::Value& object, SField::ref inName, int depth)
{
if (!object.isObject())
diff --git a/src/SerializedObject.h b/src/SerializedObject.h
index 7ecd539eb3..69683ed497 100644
--- a/src/SerializedObject.h
+++ b/src/SerializedObject.h
@@ -132,6 +132,8 @@ public:
void setFieldPathSet(SField::ref field, const STPathSet&);
void setFieldV256(SField::ref field, const STVector256& v);
+ STObject& peekFieldObject(SField::ref field);
+
bool isFieldPresent(SField::ref field) const;
SerializedType* makeFieldPresent(SField::ref field);
void makeFieldAbsent(SField::ref field);
@@ -152,9 +154,9 @@ class STArray : public SerializedType
{
public:
typedef std::vector vector;
- typedef std::vector::iterator iterator;
+ typedef std::vector::iterator iterator;
typedef std::vector::const_iterator const_iterator;
- typedef std::vector::reverse_iterator reverse_iterator;
+ typedef std::vector::reverse_iterator reverse_iterator;
typedef std::vector::const_reverse_iterator const_reverse_iterator;
typedef std::vector::size_type size_type;
@@ -199,12 +201,15 @@ public:
void pop_back() { value.pop_back(); }
bool empty() const { return value.empty(); }
void clear() { value.clear(); }
+ void swap(STArray& a) { value.swap(a.value); }
virtual std::string getFullText() const;
virtual std::string getText() const;
virtual Json::Value getJson(int) const;
virtual void add(Serializer& s) const;
+ void sort(bool (*compare)(const STObject& o1, const STObject& o2));
+
bool operator==(const STArray &s) { return value == s.value; }
bool operator!=(const STArray &s) { return value != s.value; }
diff --git a/src/TransactionEngine.cpp b/src/TransactionEngine.cpp
index 36712c6a30..167b275bab 100644
--- a/src/TransactionEngine.cpp
+++ b/src/TransactionEngine.cpp
@@ -457,7 +457,7 @@ TER TransactionEngine::applyTransaction(const SerializedTransaction& txn, Transa
{
// Transaction succeeded fully or (retries are not allowed and the transaction succeeded partially).
Serializer m;
- mNodes.calcRawMeta(m);
+ mNodes.calcRawMeta(m, terResult);
txnWrite();
diff --git a/src/TransactionMeta.cpp b/src/TransactionMeta.cpp
index d1372ebdc7..213542dd0f 100644
--- a/src/TransactionMeta.cpp
+++ b/src/TransactionMeta.cpp
@@ -6,314 +6,55 @@
#include
#include
-bool TransactionMetaNodeEntry::operator<(const TransactionMetaNodeEntry& e) const
-{
- if (mType < e.mType) return true;
- if (mType > e.mType) return false;
- return compare(e) < 0;
-}
-
-bool TransactionMetaNodeEntry::operator<=(const TransactionMetaNodeEntry& e) const
-{
- if (mType < e.mType) return true;
- if (mType > e.mType) return false;
- return compare(e) <= 0;
-}
-
-bool TransactionMetaNodeEntry::operator>(const TransactionMetaNodeEntry& e) const
-{
- if (mType > e.mType) return true;
- if (mType < e.mType) return false;
- return compare(e) > 0;
-}
-
-bool TransactionMetaNodeEntry::operator>=(const TransactionMetaNodeEntry& e) const
-{
- if (mType > e.mType) return true;
- if (mType < e.mType) return false;
- return compare(e) >= 0;
-}
-
-TMNEThread::TMNEThread(SerializerIterator& sit) : TransactionMetaNodeEntry(TMSThread)
-{
- mPrevTxID = sit.get256();
- mPrevLgrSeq = sit.get32();
-}
-
-void TMNEThread::addRaw(Serializer& sit) const
-{
- sit.add8(mType);
- sit.add256(mPrevTxID);
- sit.add32(mPrevLgrSeq);
-}
-
-int TMNEThread::compare(const TransactionMetaNodeEntry&) const
-{
- assert(false); // should never be two entries for the same node (as of now)
- return 0;
-}
-
-Json::Value TMNEThread::getJson(int) const
-{
- Json::Value inner(Json::objectValue);
- inner["prev_transaction"] = mPrevTxID.GetHex();
- inner["prev_ledger_seq"] = mPrevLgrSeq;
-
- Json::Value outer(Json::objectValue);
- outer["thread"] = inner;
- return outer;
-}
-
-TMNEAmount::TMNEAmount(int type, SerializerIterator& sit) : TransactionMetaNodeEntry(type)
-{
- mAmount = *dynamic_cast(STAmount::deserialize(sit, sfAmount).get()); // Ouch
-}
-
-void TMNEAmount::addRaw(Serializer& s) const
-{
- s.add8(mType);
- mAmount.add(s);
-}
-
-Json::Value TMNEAmount::getJson(int v) const
-{
- Json::Value outer(Json::objectValue);
- switch (mType)
- {
- case TMSPrevBalance: outer["prev_balance"] = mAmount.getJson(v); break;
- case TMSFinalBalance: outer["final_balance"] = mAmount.getJson(v); break;
- case TMSPrevTakerPays: outer["prev_taker_pays"] = mAmount.getJson(v); break;
- case TMSPrevTakerGets: outer["prev_taker_gets"] = mAmount.getJson(v); break;
- case TMSFinalTakerPays: outer["final_taker_pays"] = mAmount.getJson(v); break;
- case TMSFinalTakerGets: outer["final_taker_gets"] = mAmount.getJson(v); break;
- default: assert(false);
- }
- return outer;
-}
-
-int TMNEAmount::compare(const TransactionMetaNodeEntry& e) const
-{
- assert(false); // can't be two changed amounts of same type
- return 0;
-}
-
-TMNEAccount::TMNEAccount(int type, SerializerIterator& sit)
- : TransactionMetaNodeEntry(type), mAccount(STAccount(sit.getVL()).getValueNCA())
-{ ; }
-
-void TMNEAccount::addRaw(Serializer& sit) const
-{
- sit.add8(mType);
-
- STAccount sta;
- sta.setValueNCA(mAccount);
- sta.add(sit);
-}
-
-Json::Value TMNEAccount::getJson(int) const
-{
- Json::Value outer(Json::objectValue);
- switch (mType)
- {
- case TMSPrevAccount: outer["prev_account"] = mAccount.humanAccountID(); break;
- case TMSLowID: outer["lowID"] = mAccount.humanAccountID(); break;
- case TMSHighID: outer["highID"] = mAccount.humanAccountID(); break;
- default: assert(false);
- }
- return outer;
-}
-
-int TMNEAccount::compare(const TransactionMetaNodeEntry&) const
-{
- assert(false); // Can't be two modified accounts of same type for same node
- return 0;
-}
-
-TransactionMetaNode::TransactionMetaNode(int type, const uint256& node, SerializerIterator& sit)
- : mType(type), mNode(node)
-{
- while (1)
- {
- int nType = sit.get8();
- switch (nType)
- {
- case TMSEndOfNode:
- return;
-
- case TMSThread:
- mEntries.push_back(new TMNEThread(sit));
- break;
-
- // Nodes that contain an amount
- case TMSPrevBalance:
- case TMSPrevTakerPays:
- case TMSPrevTakerGets:
- case TMSFinalTakerPays:
- case TMSFinalTakerGets:
- mEntries.push_back(new TMNEAmount(nType, sit));
-
- case TMSPrevAccount:
- mEntries.push_back(new TMNEAccount(nType, sit));
- }
- }
-}
-
-void TransactionMetaNode::addRaw(Serializer& s)
-{
- s.add8(mType);
- s.add256(mNode);
- mEntries.sort();
- BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries)
- it.addRaw(s);
- s.add8(TMSEndOfNode);
-}
-
-TransactionMetaNodeEntry* TransactionMetaNode::findEntry(int nodeType)
-{
- BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries)
- if (it.getType() == nodeType)
- return ⁢
- return NULL;
-}
-
-TMNEAmount* TransactionMetaNode::findAmount(int nType)
-{
- BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries)
- if (it.getType() == nType)
- return dynamic_cast(&it);
- TMNEAmount* node = new TMNEAmount(nType);
- mEntries.push_back(node);
- return node;
-}
-
-void TransactionMetaNode::addNode(TransactionMetaNodeEntry* node)
-{
- mEntries.push_back(node);
-}
-
-bool TransactionMetaNode::thread(const uint256& prevTx, uint32 prevLgr)
-{
- BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries)
- if (it.getType() == TMSThread)
- {
- TMNEThread* a = dynamic_cast(&it);
- assert(a && (a->getPrevTxID() == prevTx) && (a->getPrevLgr() == prevLgr));
- return false;
- }
- addNode(new TMNEThread(prevTx, prevLgr));
- return true;
-}
-
-bool TransactionMetaNode::addAmount(int nodeType, const STAmount& amount)
-{
- BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries)
- if (it.getType() == nodeType)
- {
- TMNEAmount* a = dynamic_cast(&it);
- assert(a && (a->getAmount() == amount));
- return false;
- }
- addNode(new TMNEAmount(nodeType, amount));
- return true;
-}
-
-bool TransactionMetaNode::addAccount(int nodeType, const NewcoinAddress& account)
-{
- BOOST_FOREACH(TransactionMetaNodeEntry& it, mEntries)
- if (it.getType() == nodeType)
- {
- TMNEAccount* a = dynamic_cast(&it);
- assert(a && (a->getAccount() == account));
- return false;
- }
- addNode(new TMNEAccount(nodeType, account));
- return true;
-}
-
-Json::Value TransactionMetaNode::getJson(int v) const
-{
- Json::Value ret = Json::objectValue;
-
- switch (mType)
- {
- case TMNCreatedNode: ret["action"] = "create"; break;
- case TMNDeletedNode: ret["action"] = "delete"; break;
- case TMNModifiedNode: ret["action"] = "modify"; break;
- default:
- assert(false);
- }
-
- ret["node"] = mNode.GetHex();
-
- Json::Value e = Json::arrayValue;
- BOOST_FOREACH(const TransactionMetaNodeEntry& it, mEntries)
- e.append(it.getJson(v));
- ret["entries"] = e;
-
- return ret;
-}
-
-TransactionMetaSet::TransactionMetaSet(uint32 ledger, const std::vector& vec) : mLedger(ledger)
+TransactionMetaSet::TransactionMetaSet(const uint256& txid, uint32 ledger, const std::vector& vec) :
+ mTransactionID(txid), mLedger(ledger), mNodes(sfAffectedNodes)
{
Serializer s(vec);
SerializerIterator sit(s);
- mTransactionID = sit.get256();
+ std::auto_ptr pobj = STObject::deserialize(sit, sfAffectedNodes);
+ STObject *obj = static_cast(pobj.get());
+ if (!obj)
+ throw std::runtime_error("bad metadata");
- int type;
- while ((type = sit.get8()) != TMNEndOfMetadata)
- {
- uint256 node = sit.get256();
- mNodes.insert(std::make_pair(node, TransactionMetaNode(type, node, sit)));
- }
-}
-
-void TransactionMetaSet::addRaw(Serializer& s)
-{
- s.add256(mTransactionID);
- for (std::map::iterator it = mNodes.begin(), end = mNodes.end(); it != end; ++it)
- it->second.addRaw(s);
- s.add8(TMNEndOfMetadata);
-}
-
-Json::Value TransactionMetaSet::getJson(int v) const
-{
- Json::Value ret = Json::objectValue;
-
- ret["hash"] = mTransactionID.GetHex();
- ret["ledger"] = mLedger;
-
- Json::Value e = Json::arrayValue;
- for (std::map::const_iterator it = mNodes.begin(), end = mNodes.end();
- it != end; ++it)
- e.append(it->second.getJson(v));
- ret["nodes_affected"] = e;
-
- return ret;
+ mResult = obj->getFieldU8(sfTransactionResult);
+ mNodes = * dynamic_cast(&obj->getField(sfAffectedNodes));
}
bool TransactionMetaSet::isNodeAffected(const uint256& node) const
{
- return mNodes.find(node) != mNodes.end();
+ for (STArray::const_iterator it = mNodes.begin(); it != mNodes.end(); ++it)
+ if (it->getFieldH256(sfLedgerIndex) == node)
+ return true;
+ return false;
}
-TransactionMetaNode& TransactionMetaSet::getAffectedNode(const uint256& node, int type, bool overrideType)
+STObject& TransactionMetaSet::getAffectedNode(const uint256& node, SField::ref type, bool overrideType)
{
- std::map::iterator it = mNodes.find(node);
- if (it != mNodes.end())
+ for (STArray::iterator it = mNodes.begin(); it != mNodes.end(); ++it)
{
- if (overrideType)
- it->second.setType(type);
- return it->second;
+ if (it->getFieldH256(sfLedgerIndex) == node)
+ {
+ if (overrideType)
+ it->setFName(type);
+ return *it;
+ }
}
- return mNodes.insert(std::make_pair(node, TransactionMetaNode(node, type))).first->second;
+
+ mNodes.push_back(STObject(type));
+ STObject& obj = mNodes.back();
+
+ assert(obj.getFName() == type);
+ obj.setFieldH256(sfLedgerIndex, node);
+
+ return mNodes.back();
}
-const TransactionMetaNode& TransactionMetaSet::peekAffectedNode(const uint256& node) const
+const STObject& TransactionMetaSet::peekAffectedNode(const uint256& node) const
{
- std::map::const_iterator it = mNodes.find(node);
- if (it != mNodes.end())
- return it->second;
+ for (STArray::const_iterator it = mNodes.begin(); it != mNodes.end(); ++it)
+ if (it->getFieldH256(sfLedgerIndex) == node)
+ return *it;
throw std::runtime_error("Affected node not found");
}
@@ -321,7 +62,7 @@ void TransactionMetaSet::init(const uint256& id, uint32 ledger)
{
mTransactionID = id;
mLedger = ledger;
- mNodes.clear();
+ mNodes = STArray(sfAffectedNodes);
}
void TransactionMetaSet::swap(TransactionMetaSet& s)
@@ -330,4 +71,47 @@ void TransactionMetaSet::swap(TransactionMetaSet& s)
mNodes.swap(s.mNodes);
}
+bool TransactionMetaSet::thread(STObject& node, const uint256& prevTxID, uint32 prevLgrID)
+{
+ if (node.getFieldIndex(sfLastTxnID) == -1)
+ {
+ assert(node.getFieldIndex(sfLastTxnSeq) == -1);
+ node.setFieldH256(sfLastTxnID, prevTxID);
+ node.setFieldU32(sfLastTxnSeq, prevLgrID);
+ return true;
+ }
+ assert(node.getFieldH256(sfLastTxnID) == prevTxID);
+ assert(node.getFieldU32(sfLastTxnSeq) == prevLgrID);
+ return false;
+}
+
+static bool compare(const STObject& o1, const STObject& o2)
+{
+ return o1.getFieldH256(sfLedgerIndex) < o2.getFieldH256(sfLedgerIndex);
+}
+
+STObject TransactionMetaSet::getAsObject() const
+{
+ STObject metaData(sfTransactionMetaData);
+ metaData.setFieldU8(sfTransactionResult, mResult);
+ metaData.addObject(mNodes);
+ return metaData;
+}
+
+void TransactionMetaSet::addRaw(Serializer& s, TER result)
+{
+ mResult = 255;
+
+ if (result == tesSUCCESS)
+ mResult = 0;
+ else if (result == tepPATH_DRY)
+ mResult = 1;
+ else if (result == tepPATH_PARTIAL)
+ mResult = 2;
+
+ mNodes.sort(compare);
+
+ getAsObject().add(s);
+}
+
// vim:ts=4
diff --git a/src/TransactionMeta.h b/src/TransactionMeta.h
index b329fdb61c..78f3378f5b 100644
--- a/src/TransactionMeta.h
+++ b/src/TransactionMeta.h
@@ -11,164 +11,8 @@
#include "uint256.h"
#include "Serializer.h"
#include "SerializedTypes.h"
-
-// master record types
-static const int TMNEndOfMetadata = 0x00;
-static const int TMNCreatedNode = 0x10; // This transaction created this node
-static const int TMNDeletedNode = 0x11;
-static const int TMNModifiedNode = 0x12;
-
-// sub record types - special
-static const int TMSEndOfNode = 0x00;
-static const int TMSThread = 0x01; // Holds previous TxID and LgrSeq for threading
-
-// sub record types - containing an amount
-static const int TMSPrevBalance = 0x11; // Balances prior to the transaction
-static const int TMSFinalBalance = 0x12; // deleted with non-zero balance
-static const int TMSPrevTakerPays = 0x13;
-static const int TMSPrevTakerGets = 0x14;
-static const int TMSFinalTakerPays = 0x15; // Balances at node deletion time
-static const int TMSFinalTakerGets = 0x16;
-
-// sub record types - containing an account (for example, for when a nickname is transferred)
-static const int TMSPrevAccount = 0x20;
-static const int TMSLowID = 0x21;
-static const int TMSHighID = 0x22;
-
-
-class TransactionMetaNodeEntry
-{ // a way that a transaction has affected a node
-public:
- typedef boost::shared_ptr pointer;
-
-protected:
- int mType;
-
-public:
- TransactionMetaNodeEntry(int type) : mType(type) { ; }
- virtual ~TransactionMetaNodeEntry() { ; }
-
- int getType() const { return mType; }
- virtual Json::Value getJson(int) const = 0;
- virtual void addRaw(Serializer&) const = 0;
-
- bool operator<(const TransactionMetaNodeEntry&) const;
- bool operator<=(const TransactionMetaNodeEntry&) const;
- bool operator>(const TransactionMetaNodeEntry&) const;
- bool operator>=(const TransactionMetaNodeEntry&) const;
-
- virtual std::auto_ptr clone() const
- { return std::auto_ptr(duplicate()); }
-
-protected:
- virtual int compare(const TransactionMetaNodeEntry&) const = 0;
- virtual TransactionMetaNodeEntry* duplicate(void) const = 0;
-};
-
-class TMNEThread : public TransactionMetaNodeEntry
-{
-protected:
- uint256 mPrevTxID;
- uint32 mPrevLgrSeq;
-
-public:
- TMNEThread() : TransactionMetaNodeEntry(TMSThread), mPrevLgrSeq(0) { ; }
- TMNEThread(uint256 prevTx, uint32 prevLgrSeq)
- : TransactionMetaNodeEntry(TMSThread), mPrevTxID(prevTx), mPrevLgrSeq(prevLgrSeq)
- { ; }
- TMNEThread(SerializerIterator&);
-
- virtual void addRaw(Serializer&) const;
- virtual Json::Value getJson(int) const;
-
- const uint256& getPrevTxID() const { return mPrevTxID; }
- uint32 getPrevLgr() const { return mPrevLgrSeq; }
-
-protected:
- virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEThread(*this); }
- virtual int compare(const TransactionMetaNodeEntry&) const;
-};
-
-class TMNEAmount : public TransactionMetaNodeEntry
-{ // a transaction affected the balance of a node
-protected:
- STAmount mAmount;
-
-public:
- TMNEAmount(int type) : TransactionMetaNodeEntry(type) { ; }
- TMNEAmount(int type, const STAmount &a) : TransactionMetaNodeEntry(type), mAmount(a) { ; }
-
- TMNEAmount(int type, SerializerIterator&);
- virtual void addRaw(Serializer&) const;
-
- const STAmount& getAmount() const { return mAmount; }
- void setAmount(const STAmount& a) { mAmount = a; }
-
- virtual Json::Value getJson(int) const;
-
-protected:
- virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEAmount(*this); }
- virtual int compare(const TransactionMetaNodeEntry&) const;
-};
-
-class TMNEAccount : public TransactionMetaNodeEntry
-{ // node was deleted because it was unfunded
-protected:
- NewcoinAddress mAccount;
-
-public:
- TMNEAccount(int type, const NewcoinAddress& acct) : TransactionMetaNodeEntry(type), mAccount(acct) { ; }
- TMNEAccount(int type, SerializerIterator&);
- virtual void addRaw(Serializer&) const;
- virtual Json::Value getJson(int) const;
-
- const NewcoinAddress& getAccount() const { return mAccount; }
- void setAccount(const NewcoinAddress& a) { mAccount = a; }
-
-protected:
- virtual TransactionMetaNodeEntry* duplicate(void) const { return new TMNEAccount(*this); }
- virtual int compare(const TransactionMetaNodeEntry&) const;
-};
-
-inline TransactionMetaNodeEntry* new_clone(const TransactionMetaNodeEntry& s) { return s.clone().release(); }
-inline void delete_clone(const TransactionMetaNodeEntry* s) { boost::checked_delete(s); }
-
-class TransactionMetaNode
-{ // a node that has been affected by a transaction
-public:
- typedef boost::shared_ptr pointer;
-
-protected:
- int mType;
- uint256 mNode;
- boost::ptr_vector mEntries;
-
-public:
- TransactionMetaNode(const uint256 &node, int type) : mType(type), mNode(node) { ; }
-
- const uint256& getNode() const { return mNode; }
- const boost::ptr_vector& peekEntries() const { return mEntries; }
-
- TransactionMetaNodeEntry* findEntry(int nodeType);
- void addNode(TransactionMetaNodeEntry*);
-
- bool operator<(const TransactionMetaNode& n) const { return mNode < n.mNode; }
- bool operator<=(const TransactionMetaNode& n) const { return mNode <= n.mNode; }
- bool operator>(const TransactionMetaNode& n) const { return mNode > n.mNode; }
- bool operator>=(const TransactionMetaNode& n) const { return mNode >= n.mNode; }
-
- bool thread(const uint256& prevTx, uint32 prevLgr);
-
- TransactionMetaNode(int type, const uint256& node, SerializerIterator&);
- void addRaw(Serializer&);
- void setType(int t) { mType = t; }
- Json::Value getJson(int) const;
-
- bool addAmount(int nodeType, const STAmount& amount);
- bool addAccount(int nodeType, const NewcoinAddress& account);
- TMNEAmount* findAmount(int nodeType);
-};
-
+#include "SerializedObject.h"
+#include "TransactionErr.h"
class TransactionMetaSet
{
@@ -176,14 +20,16 @@ public:
typedef boost::shared_ptr pointer;
protected:
- uint256 mTransactionID;
- uint32 mLedger;
- std::map mNodes; // must be an ordered set
+ uint256 mTransactionID;
+ uint32 mLedger;
+ int mResult;
+
+ STArray mNodes;
public:
- TransactionMetaSet() : mLedger(0) { ; }
+ TransactionMetaSet() : mLedger(0), mResult(255) { ; }
TransactionMetaSet(const uint256& txID, uint32 ledger) : mTransactionID(txID), mLedger(ledger) { ; }
- TransactionMetaSet(uint32 ledger, const std::vector&);
+ TransactionMetaSet(const uint256& txID, uint32 ledger, const std::vector&);
void init(const uint256& transactionID, uint32 ledger);
void clear() { mNodes.clear(); }
@@ -193,11 +39,15 @@ public:
uint32 getLgrSeq() { return mLedger; }
bool isNodeAffected(const uint256&) const;
- TransactionMetaNode& getAffectedNode(const uint256&, int type, bool overrideType);
- const TransactionMetaNode& peekAffectedNode(const uint256&) const;
+ STObject& getAffectedNode(const uint256&, SField::ref type, bool overrideType);
+ const STObject& peekAffectedNode(const uint256&) const;
- Json::Value getJson(int) const;
- void addRaw(Serializer&);
+ Json::Value getJson(int p) const { return getAsObject().getJson(p); }
+ void addRaw(Serializer&, TER);
+
+ STObject getAsObject() const;
+
+ static bool thread(STObject& node, const uint256& prevTxID, uint32 prevLgrID);
};
#endif