mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Merge branch 'master' of github.com:jedmccaleb/NewCoin
This commit is contained in:
@@ -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<boost::mutex> sl(mWriteMutex);
|
||||
while (mWritePending)
|
||||
mWriteCondition.wait(sl);
|
||||
}
|
||||
|
||||
void HashedObjectStore::bulkWrite()
|
||||
{
|
||||
std::vector< boost::shared_ptr<HashedObject> > set;
|
||||
@@ -59,11 +66,12 @@ void HashedObjectStore::bulkWrite()
|
||||
set.reserve(128);
|
||||
|
||||
{
|
||||
boost::recursive_mutex::scoped_lock sl(mWriteMutex);
|
||||
boost::unique_lock<boost::mutex> sl(mWriteMutex);
|
||||
mWriteSet.swap(set);
|
||||
if (set.empty())
|
||||
{
|
||||
mWritePending = false;
|
||||
mWriteCondition.notify_all();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
#include "types.h"
|
||||
#include "uint256.h"
|
||||
#include "ScopedLock.h"
|
||||
@@ -41,7 +44,9 @@ class HashedObjectStore
|
||||
protected:
|
||||
TaggedCache<uint256, HashedObject> mCache;
|
||||
|
||||
boost::recursive_mutex mWriteMutex;
|
||||
boost::mutex mWriteMutex;
|
||||
boost::condition_variable mWriteCondition;
|
||||
|
||||
std::vector< boost::shared_ptr<HashedObject> > mWriteSet;
|
||||
bool mWritePending;
|
||||
|
||||
@@ -55,6 +60,7 @@ public:
|
||||
HashedObject::pointer retrieve(const uint256& hash);
|
||||
|
||||
void bulkWrite();
|
||||
void waitWrite();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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<TransactionMetaSet>(mLedgerSeq, it.getVL());
|
||||
meta = boost::make_shared<TransactionMetaSet>(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<std::string>(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<std::string>(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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<uint256, currentValidationCount> 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<LedgerConsensus> This, SHAMap::p
|
||||
This->accept(txSet);
|
||||
}
|
||||
|
||||
void LedgerConsensus::deferProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic)
|
||||
{
|
||||
std::list<LedgerProposal::pointer>& props = mDeferredProposals[peerPublic.getNodeID()];
|
||||
if (props.size() >= (mPreviousProposers + 10))
|
||||
props.pop_front();
|
||||
props.push_back(proposal);
|
||||
}
|
||||
|
||||
void LedgerConsensus::playbackProposals()
|
||||
{
|
||||
boost::unordered_map<uint160,
|
||||
std::list<LedgerProposal::pointer> >& storedProposals = theApp->getOPs().peekStoredProposals();
|
||||
for (boost::unordered_map< uint160, std::list<LedgerProposal::pointer> >::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<Ledger>(false, boost::ref(*mPreviousLedger));
|
||||
newLCL->armDirty();
|
||||
|
||||
CanonicalTXSet failedTransactions(set->getHash());
|
||||
|
||||
Ledger::pointer newLCL = boost::make_shared<Ledger>(false, boost::ref(*mPreviousLedger));
|
||||
|
||||
newLCL->peekTransactionMap()->armDirty();
|
||||
newLCL->peekAccountStateMap()->armDirty();
|
||||
applyTransactions(set, newLCL, newLCL, failedTransactions, false);
|
||||
newLCL->setClosed();
|
||||
boost::shared_ptr<SHAMap::SHADirtyMap> acctNodes = newLCL->peekAccountStateMap()->disarmDirty();
|
||||
boost::shared_ptr<SHAMap::SHADirtyMap> 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)
|
||||
|
||||
@@ -113,9 +113,6 @@ protected:
|
||||
// Close time estimates
|
||||
std::map<uint32, int> mCloseTimes;
|
||||
|
||||
// deferred proposals (node ID -> proposals from that peer)
|
||||
boost::unordered_map< uint160, std::list<LedgerProposal::pointer> > mDeferredProposals;
|
||||
|
||||
// nodes that have bowed out of this consensus process
|
||||
boost::unordered_set<uint160> 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<SHAMapNode>& nodeIDs, const std::list< std::vector<unsigned char> >& nodeData);
|
||||
|
||||
void swapDefer(boost::unordered_map< uint160, std::list<LedgerProposal::pointer> > &n)
|
||||
{ mDeferredProposals.swap(n); }
|
||||
|
||||
// test/debug
|
||||
void simulate();
|
||||
};
|
||||
|
||||
@@ -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<uint256, LedgerEntrySetEntry>::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.
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<LedgerConsensus>(
|
||||
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<LedgerConsensus>();
|
||||
}
|
||||
|
||||
@@ -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<LedgerProposal::pointer>& 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)
|
||||
{
|
||||
|
||||
@@ -57,7 +57,7 @@ protected:
|
||||
boost::asio::deadline_timer mNetTimer;
|
||||
boost::shared_ptr<LedgerConsensus> mConsensus;
|
||||
boost::unordered_map<uint160,
|
||||
std::list<LedgerProposal::pointer> > mDeferredProposals;
|
||||
std::list<LedgerProposal::pointer> > 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<uint160,
|
||||
std::list<LedgerProposal::pointer> >& peekStoredProposals() { return mStoredProposals; }
|
||||
void storeProposal(const LedgerProposal::pointer& proposal, const NewcoinAddress& peerPublic);
|
||||
|
||||
// client information retrieval functions
|
||||
std::vector< std::pair<uint32, uint256> >
|
||||
|
||||
@@ -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 <<std::endl;
|
||||
}
|
||||
else
|
||||
{ // not done keep reading
|
||||
|
||||
@@ -48,7 +48,7 @@ SHAMap::SHAMap(SHAMapType t, uint32 seq) : mSeq(seq), mState(smsModifying), mTyp
|
||||
mTNByID[*root] = root;
|
||||
}
|
||||
|
||||
SHAMap::SHAMap(SHAMapType t, const uint256& hash) : mSeq(0), mState(smsSynching), mType(t)
|
||||
SHAMap::SHAMap(SHAMapType t, const uint256& hash) : mSeq(1), mState(smsSynching), mType(t)
|
||||
{ // FIXME: Need to acquire root node
|
||||
root = boost::make_shared<SHAMapTreeNode>(mSeq, SHAMapNode(0, uint256()));
|
||||
root->makeInner();
|
||||
@@ -138,7 +138,8 @@ void SHAMap::dirtyUp(std::stack<SHAMapTreeNode::pointer>& stack, const uint256&
|
||||
SHAMapTreeNode::pointer SHAMap::checkCacheNode(const SHAMapNode& iNode)
|
||||
{
|
||||
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::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<SHAMapTreeNode>(*node, mSeq);
|
||||
if (mDirtyNodes)
|
||||
(*mDirtyNodes)[*node] = node;
|
||||
assert(node->getSeq() < mSeq);
|
||||
|
||||
node = boost::make_shared<SHAMapTreeNode>(*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<unsigned char>& 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<SHAMapTreeNode>(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<SHAMapTreeNode>(id, obj->getData(), mSeq, snfPREFIX);
|
||||
assert((ret->getNodeHash() == hash) && (id == *ret));
|
||||
SHAMapTreeNode::pointer ret = boost::make_shared<SHAMapTreeNode>(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<SHAMapNode, SHAMapTreeNode::pointer> >();
|
||||
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<SHAMapNode, SHAMapTreeNode::pointer>& dirtyNodes = *mDirtyNodes;
|
||||
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer>::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::SHADirtyMap> SHAMap::disarmDirty()
|
||||
{ // stop saving dirty nodes
|
||||
mDirtyNodes = boost::shared_ptr< boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer> >();
|
||||
boost::shared_ptr<SHADirtyMap> ret;
|
||||
ret.swap(mDirtyNodes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SHAMapTreeNode::pointer SHAMap::getNode(const SHAMapNode& nodeID)
|
||||
|
||||
12
src/SHAMap.h
12
src/SHAMap.h
@@ -283,13 +283,14 @@ public:
|
||||
typedef const boost::shared_ptr<SHAMap>& ref;
|
||||
|
||||
typedef std::map<uint256, std::pair<SHAMapItem::pointer, SHAMapItem::pointer> > SHAMapDiff;
|
||||
typedef boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer> SHADirtyMap;
|
||||
|
||||
private:
|
||||
uint32 mSeq;
|
||||
mutable boost::recursive_mutex mLock;
|
||||
boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer> mTNByID;
|
||||
|
||||
boost::shared_ptr< boost::unordered_map<SHAMapNode, SHAMapTreeNode::pointer> > mDirtyNodes;
|
||||
boost::shared_ptr<SHADirtyMap> 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<SHADirtyMap> disarmDirty();
|
||||
|
||||
void setSeq(uint32 seq) { mSeq = seq; }
|
||||
uint32 getSeq() { return mSeq; }
|
||||
|
||||
@@ -300,7 +300,9 @@ SHAMapTreeNode::SHAMapTreeNode(const SHAMapNode& id, const std::vector<unsigned
|
||||
mType = tnINNER;
|
||||
}
|
||||
else if (prefix == sHP_TransactionNode)
|
||||
{
|
||||
{ // transaction with metadata
|
||||
if (s.getLength() < 32)
|
||||
throw std::runtime_error("short TXN node");
|
||||
uint256 txID;
|
||||
s.get256(txID, s.getLength() - 32);
|
||||
s.chop(32);
|
||||
@@ -333,21 +335,25 @@ bool SHAMapTreeNode::updateHash()
|
||||
if(!empty)
|
||||
nh = Serializer::getPrefixHash(sHP_InnerNode, reinterpret_cast<unsigned char *>(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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -24,6 +24,9 @@ std::auto_ptr<SerializedType> STObject::makeDefaultObject(SerializedTypeID id, S
|
||||
case STI_NOTPRESENT:
|
||||
return std::auto_ptr<SerializedType>(new SerializedType(name));
|
||||
|
||||
case STI_UINT8:
|
||||
return std::auto_ptr<SerializedType>(new STUInt8(name));
|
||||
|
||||
case STI_UINT16:
|
||||
return std::auto_ptr<SerializedType>(new STUInt16(name));
|
||||
|
||||
@@ -64,6 +67,8 @@ std::auto_ptr<SerializedType> STObject::makeDefaultObject(SerializedTypeID id, S
|
||||
return std::auto_ptr<SerializedType>(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<SerializedType> 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<STObject*>(rf);
|
||||
if (!cf)
|
||||
throw std::runtime_error("Wrong field type");
|
||||
return *cf;
|
||||
}
|
||||
|
||||
bool STObject::setFlag(uint32 f)
|
||||
{
|
||||
STUInt32* t = dynamic_cast<STUInt32*>(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> STObject::parseJson(const Json::Value& object, SField::ref inName, int depth)
|
||||
{
|
||||
if (!object.isObject())
|
||||
|
||||
@@ -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<STObject> vector;
|
||||
typedef std::vector<STObject>::iterator iterator;
|
||||
typedef std::vector<STObject>::iterator iterator;
|
||||
typedef std::vector<STObject>::const_iterator const_iterator;
|
||||
typedef std::vector<STObject>::reverse_iterator reverse_iterator;
|
||||
typedef std::vector<STObject>::reverse_iterator reverse_iterator;
|
||||
typedef std::vector<STObject>::const_reverse_iterator const_reverse_iterator;
|
||||
typedef std::vector<STObject>::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; }
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -6,314 +6,55 @@
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
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*>(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<TMNEAmount *>(&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<TMNEThread *>(&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<TMNEAmount *>(&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<TMNEAccount *>(&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<unsigned char>& vec) : mLedger(ledger)
|
||||
TransactionMetaSet::TransactionMetaSet(const uint256& txid, uint32 ledger, const std::vector<unsigned char>& vec) :
|
||||
mTransactionID(txid), mLedger(ledger), mNodes(sfAffectedNodes)
|
||||
{
|
||||
Serializer s(vec);
|
||||
SerializerIterator sit(s);
|
||||
|
||||
mTransactionID = sit.get256();
|
||||
std::auto_ptr<SerializedType> pobj = STObject::deserialize(sit, sfAffectedNodes);
|
||||
STObject *obj = static_cast<STObject*>(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<uint256, TransactionMetaNode>::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<uint256, TransactionMetaNode>::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<STArray*>(&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<uint256, TransactionMetaNode>::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<uint256, TransactionMetaNode>::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
|
||||
|
||||
@@ -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<TransactionMetaNodeEntry> 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<TransactionMetaNodeEntry> clone() const
|
||||
{ return std::auto_ptr<TransactionMetaNodeEntry>(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<TransactionMetaNode> pointer;
|
||||
|
||||
protected:
|
||||
int mType;
|
||||
uint256 mNode;
|
||||
boost::ptr_vector<TransactionMetaNodeEntry> mEntries;
|
||||
|
||||
public:
|
||||
TransactionMetaNode(const uint256 &node, int type) : mType(type), mNode(node) { ; }
|
||||
|
||||
const uint256& getNode() const { return mNode; }
|
||||
const boost::ptr_vector<TransactionMetaNodeEntry>& 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<TransactionMetaSet> pointer;
|
||||
|
||||
protected:
|
||||
uint256 mTransactionID;
|
||||
uint32 mLedger;
|
||||
std::map<uint256, TransactionMetaNode> 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<unsigned char>&);
|
||||
TransactionMetaSet(const uint256& txID, uint32 ledger, const std::vector<unsigned char>&);
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user