Merge branch 'master' of github.com:jedmccaleb/NewCoin

This commit is contained in:
Arthur Britto
2012-10-16 15:50:41 -07:00
23 changed files with 377 additions and 605 deletions

View File

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

View File

@@ -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

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)

View File

@@ -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();
};

View File

@@ -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.

View File

@@ -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(); }

View File

@@ -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

View File

@@ -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)
{

View File

@@ -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> >

View File

@@ -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

View File

@@ -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)

View File

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

View File

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

View File

@@ -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)

View File

@@ -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())

View File

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

View File

@@ -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();

View File

@@ -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 &it;
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

View File

@@ -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