diff --git a/newcoin.vcxproj b/newcoin.vcxproj index 72e758a47..bf9067b2a 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -96,6 +96,7 @@ + @@ -205,6 +206,7 @@ + diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index 365cb7109..98c8ac463 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -345,6 +345,9 @@ Source Files + + Source Files + Source Files @@ -662,6 +665,9 @@ Header Files + + Header Files + Header Files diff --git a/ripple2010.vcxproj b/ripple2010.vcxproj index 18e3ea1d2..dbb3dd84b 100644 --- a/ripple2010.vcxproj +++ b/ripple2010.vcxproj @@ -94,6 +94,7 @@ + diff --git a/ripple2010.vcxproj.filters b/ripple2010.vcxproj.filters index 77ef08370..6ad621db5 100644 --- a/ripple2010.vcxproj.filters +++ b/ripple2010.vcxproj.filters @@ -345,6 +345,9 @@ Source Files + + Source Files + Source Files diff --git a/src/cpp/ripple/AcceptedLedger.cpp b/src/cpp/ripple/AcceptedLedger.cpp index 9fdbf1fb7..0043d332d 100644 --- a/src/cpp/ripple/AcceptedLedger.cpp +++ b/src/cpp/ripple/AcceptedLedger.cpp @@ -1,13 +1,59 @@ #include "AcceptedLedger.h" +#include + +TaggedCache AcceptedLedger::ALCache("AcceptedLedger", 4, 60); + ALTransaction::ALTransaction(uint32 seq, SerializerIterator& sit) { Serializer txnSer(sit.getVL()); SerializerIterator txnIt(txnSer); mTxn = boost::make_shared(boost::ref(txnIt)); - mMeta = boost::make_shared(mTxn->getTransactionID(), seq, sit.getVL()); + mRawMeta= sit.getVL(); + mMeta = boost::make_shared(mTxn->getTransactionID(), seq, mRawMeta); mAffected = mMeta->getAffectedAccounts(); + mResult = mMeta->getResultTER(); +} + +ALTransaction::ALTransaction(SerializedTransaction::ref txn, TransactionMetaSet::ref met) : + mTxn(txn), mMeta(met), mAffected(met->getAffectedAccounts()) +{ + mResult = mMeta->getResultTER(); +} + +ALTransaction::ALTransaction(SerializedTransaction::ref txn, TER result) : + mTxn(txn), mResult(result), mAffected(txn->getMentionedAccounts()) +{ ; } + +std::string ALTransaction::getEscMeta() const +{ + assert(!mRawMeta.empty()); + return sqlEscape(mRawMeta); +} + +Json::Value ALTransaction::getJson(int j) const +{ + Json::Value ret(Json::objectValue); + ret["transaction"] = mTxn->getJson(j); + if (mMeta) + { + ret["meta"] = mMeta->getJson(j); + ret["raw_meta"] = strHex(mRawMeta); + } + ret["result"] = transHuman(mResult); + + if (!mAffected.empty()) + { + Json::Value affected(Json::arrayValue); + BOOST_FOREACH(const RippleAddress& ra, mAffected) + { + affected.append(ra.humanAccountID()); + } + ret["affected"] = affected; + } + + return ret; } AcceptedLedger::AcceptedLedger(Ledger::ref ledger) : mLedger(ledger) @@ -20,6 +66,16 @@ AcceptedLedger::AcceptedLedger(Ledger::ref ledger) : mLedger(ledger) } } +AcceptedLedger::pointer AcceptedLedger::makeAcceptedLedger(Ledger::ref ledger) +{ + AcceptedLedger::pointer ret = ALCache.fetch(ledger->getHash()); + if (ret) + return ret; + ret = AcceptedLedger::pointer(new AcceptedLedger(ledger)); + ALCache.canonicalize(ledger->getHash(), ret); + return ret; +} + void AcceptedLedger::insert(const ALTransaction& at) { assert(mMap.find(at.getIndex()) == mMap.end()); @@ -32,4 +88,4 @@ const ALTransaction* AcceptedLedger::getTxn(int i) const if (it == mMap.end()) return NULL; return &it->second; -} \ No newline at end of file +} diff --git a/src/cpp/ripple/AcceptedLedger.h b/src/cpp/ripple/AcceptedLedger.h index 59ba4425d..e3237cd23 100644 --- a/src/cpp/ripple/AcceptedLedger.h +++ b/src/cpp/ripple/AcceptedLedger.h @@ -11,25 +11,38 @@ class ALTransaction protected: SerializedTransaction::pointer mTxn; TransactionMetaSet::pointer mMeta; + TER mResult; std::vector mAffected; + std::vector mRawMeta; public: ALTransaction(uint32 ledgerSeq, SerializerIterator& sit); + ALTransaction(SerializedTransaction::ref, TransactionMetaSet::ref); + ALTransaction(SerializedTransaction::ref, TER result); SerializedTransaction::ref getTxn() const { return mTxn; } TransactionMetaSet::ref getMeta() const { return mMeta; } const std::vector& getAffected() const { return mAffected; } - int getIndex() const { return mMeta->getIndex(); } - TER getResult() const { return mMeta->getResultTER(); } + + uint256 getTransactionID() const { return mTxn->getTransactionID(); } + TransactionType getTxnType() const { return mTxn->getTxnType(); } + TER getResult() const { return mResult; } + + bool isApplied() const { return !!mMeta; } + int getIndex() const { return mMeta ? mMeta->getIndex() : 0; } + std::string getEscMeta() const; + Json::Value getJson(int) const; }; class AcceptedLedger { public: - typedef std::map map_t; - typedef map_t::value_type value_type; - typedef map_t::const_iterator const_iterator; + typedef boost::shared_ptr pointer; + typedef const pointer& ret; + typedef std::map map_t; + typedef map_t::value_type value_type; + typedef map_t::const_iterator const_iterator; protected: Ledger::pointer mLedger; @@ -37,9 +50,14 @@ protected: void insert(const ALTransaction&); -public: + static TaggedCache ALCache; AcceptedLedger(Ledger::ref ledger); +public: + + static pointer makeAcceptedLedger(Ledger::ref ledger); + static void sweep() { ALCache.sweep(); } + Ledger::ref getLedger() const { return mLedger; } const map_t& getMap() const { return mMap; } diff --git a/src/cpp/ripple/Application.cpp b/src/cpp/ripple/Application.cpp index fac0ce76a..1d6773dca 100644 --- a/src/cpp/ripple/Application.cpp +++ b/src/cpp/ripple/Application.cpp @@ -1,5 +1,6 @@ #include "Application.h" +#include "AcceptedLedger.h" #include "Config.h" #include "PeerDoor.h" #include "RPCDoor.h" @@ -303,6 +304,7 @@ void Application::sweep() mValidations.sweep(); getMasterLedgerAcquire().sweep(); mSLECache.sweep(); + AcceptedLedger::sweep(); mSweepTimer.expires_from_now(boost::posix_time::seconds(theConfig.getSize(siSweepInterval))); mSweepTimer.async_wait(boost::bind(&Application::sweep, this)); } diff --git a/src/cpp/ripple/Ledger.cpp b/src/cpp/ripple/Ledger.cpp index e34b6d678..3937964eb 100644 --- a/src/cpp/ripple/Ledger.cpp +++ b/src/cpp/ripple/Ledger.cpp @@ -428,6 +428,8 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event) addRaw(s); theApp->getHashedObjectStore().store(hotLEDGER, mLedgerSeq, s.peekData(), mHash); + AcceptedLedger::pointer aLedger = AcceptedLedger::makeAcceptedLedger(shared_from_this()); + { { ScopedLock sl(theApp->getLedgerDB()->getDBLock()); @@ -435,33 +437,22 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event) theApp->getLedgerDB()->getDB()->executeSQL(boost::str(deleteLedger % mLedgerSeq)); } - SHAMap& txSet = *peekTransactionMap(); Database *db = theApp->getTxnDB()->getDB(); { ScopedLock dbLock(theApp->getTxnDB()->getDBLock()); db->executeSQL("BEGIN TRANSACTION;"); - SHAMapTreeNode::TNType type; - for (SHAMapItem::pointer item = txSet.peekFirstItem(type); !!item; - item = txSet.peekNextItem(item->getTag(), type)) + + BOOST_FOREACH(const AcceptedLedger::value_type& vt, aLedger->getMap()) { - assert(type == SHAMapTreeNode::tnTRANSACTION_MD); - SerializerIterator sit(item->peekSerializer()); - Serializer rawTxn(sit.getVL()); - Serializer rawMeta(sit.getVL()); - std::string escMeta(sqlEscape(rawMeta.peekData())); - - SerializerIterator txnIt(rawTxn); - - SerializedTransaction txn(txnIt); - assert(txn.getTransactionID() == item->getTag()); - TransactionMetaSet meta(item->getTag(), mLedgerSeq, rawMeta.peekData()); - theApp->getMasterTransaction().inLedger(item->getTag(), mLedgerSeq); + cLog(lsTRACE) << "Saving: " << vt.second.getJson(0); + uint256 txID = vt.second.getTransactionID(); + theApp->getMasterTransaction().inLedger(txID, mLedgerSeq); // Make sure transaction is in AccountTransactions. - if (!SQL_EXISTS(db, boost::str(AcctTransExists % item->getTag().GetHex()))) + if (!SQL_EXISTS(db, boost::str(AcctTransExists % txID.GetHex()))) { // Transaction not in AccountTransactions - const std::vector accts = meta.getAffectedAccounts(); + const std::vector& accts = vt.second.getAffected(); if (!accts.empty()) { @@ -476,7 +467,7 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event) sql += "('"; first = false; } - sql += txn.getTransactionID().GetHex(); + sql += txID.GetHex(); sql += "','"; sql += it->humanAccountID(); sql += "',"; @@ -491,20 +482,21 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event) cLog(lsWARNING) << "Transaction in ledger " << mLedgerSeq << " affects no accounts"; } - if (SQL_EXISTS(db, boost::str(transExists % txn.getTransactionID().GetHex()))) + if (SQL_EXISTS(db, boost::str(transExists % txID.GetHex()))) { // In Transactions, update LedgerSeq, metadata and Status. db->executeSQL(boost::str(updateTx % getLedgerSeq() % TXN_SQL_VALIDATED - % escMeta - % txn.getTransactionID().GetHex())); + % vt.second.getEscMeta() + % txID.GetHex())); } else { // Not in Transactions, insert the whole thing.. db->executeSQL( - txn.getMetaSQLInsertHeader() + txn.getMetaSQL(getLedgerSeq(), escMeta) + ";"); + SerializedTransaction::getMetaSQLInsertHeader() + + vt.second.getTxn()->getMetaSQL(getLedgerSeq(), vt.second.getEscMeta()) + ";"); } } db->executeSQL("COMMIT TRANSACTION;"); diff --git a/src/cpp/ripple/LedgerMaster.cpp b/src/cpp/ripple/LedgerMaster.cpp index ab87238da..fcafae0cb 100644 --- a/src/cpp/ripple/LedgerMaster.cpp +++ b/src/cpp/ripple/LedgerMaster.cpp @@ -119,11 +119,11 @@ Ledger::pointer LedgerMaster::closeLedger(bool recover) return closingLedger; } -TER LedgerMaster::doTransaction(const SerializedTransaction& txn, TransactionEngineParams params, bool& didApply) +TER LedgerMaster::doTransaction(SerializedTransaction::ref txn, TransactionEngineParams params, bool& didApply) { - TER result = mEngine.applyTransaction(txn, params, didApply); - // CHECKME: Should we call this even on gross failures? - theApp->getOPs().pubProposedTransaction(mEngine.getLedger(), txn, result); + TER result = mEngine.applyTransaction(*txn, params, didApply); +// if (didApply) + theApp->getOPs().pubProposedTransaction(mEngine.getLedger(), txn, result); return result; } diff --git a/src/cpp/ripple/LedgerMaster.h b/src/cpp/ripple/LedgerMaster.h index d14ab11e4..c79c7e470 100644 --- a/src/cpp/ripple/LedgerMaster.h +++ b/src/cpp/ripple/LedgerMaster.h @@ -75,7 +75,7 @@ public: // The published ledger is the last fully validated ledger Ledger::ref getValidatedLedger() { return mPubLedger; } - TER doTransaction(const SerializedTransaction& txn, TransactionEngineParams params, bool& didApply); + TER doTransaction(SerializedTransaction::ref txn, TransactionEngineParams params, bool& didApply); void pushLedger(Ledger::ref newLedger); void pushLedger(Ledger::ref newLCL, Ledger::ref newOL, bool fromConsensus); diff --git a/src/cpp/ripple/NetworkOPs.cpp b/src/cpp/ripple/NetworkOPs.cpp index a3106768d..93b87b086 100644 --- a/src/cpp/ripple/NetworkOPs.cpp +++ b/src/cpp/ripple/NetworkOPs.cpp @@ -267,7 +267,7 @@ void NetworkOPs::runTransactionQueue() assert(dbtx); bool didApply; - TER r = mLedgerMaster->doTransaction(*dbtx->getSTransaction(), + TER r = mLedgerMaster->doTransaction(dbtx->getSTransaction(), tapOPEN_LEDGER | tapNO_CHECK_SIGN, didApply); dbtx->setResult(r); @@ -352,7 +352,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, boost::recursive_mutex::scoped_lock sl(theApp->getMasterLock()); Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true); bool didApply; - TER r = mLedgerMaster->doTransaction(*trans->getSTransaction(), tapOPEN_LEDGER | tapNO_CHECK_SIGN, didApply); + TER r = mLedgerMaster->doTransaction(trans->getSTransaction(), tapOPEN_LEDGER | tapNO_CHECK_SIGN, didApply); trans->setResult(r); if (isTemMalformed(r)) // malformed, cache bad @@ -1289,9 +1289,9 @@ Json::Value NetworkOPs::pubBootstrapAccountInfo(Ledger::ref lpAccepted, const Ri return jvObj; } -void NetworkOPs::pubProposedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult) +void NetworkOPs::pubProposedTransaction(Ledger::ref lpCurrent, SerializedTransaction::ref stTxn, TER terResult) { - Json::Value jvObj = transJson(stTxn, terResult, false, lpCurrent, "transaction"); + Json::Value jvObj = transJson(*stTxn, terResult, false, lpCurrent, "transaction"); { boost::recursive_mutex::scoped_lock sl(mMonitorLock); @@ -1308,15 +1308,19 @@ void NetworkOPs::pubProposedTransaction(Ledger::ref lpCurrent, const SerializedT it = mSubRTTransactions.erase(it); } } - TransactionMetaSet::pointer ret; - pubAccountTransaction(lpCurrent,stTxn,terResult,false,ret); + ALTransaction alt(stTxn, terResult); + cLog(lsTRACE) << "pubProposed: " << alt.getJson(0); + pubAccountTransaction(lpCurrent, ALTransaction(stTxn, terResult)); } -void NetworkOPs::pubLedger(Ledger::ref lpAccepted) +void NetworkOPs::pubLedger(Ledger::ref accepted) { // Ledgers are published only when they acquire sufficient validations // Holes are filled across connection loss or other catastrophe + AcceptedLedger::pointer alpAccepted = AcceptedLedger::makeAcceptedLedger(accepted); + Ledger::ref lpAccepted = alpAccepted->getLedger(); + { boost::recursive_mutex::scoped_lock sl(mMonitorLock); @@ -1334,6 +1338,8 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted) jvObj["reserve_base"] = Json::UInt(lpAccepted->getReserve(0)); jvObj["reserve_inc"] = Json::UInt(lpAccepted->getReserveInc()); + jvObj["txn_count"] = Json::UInt(alpAccepted->getTxnCount()); + NetworkOPs::subMapType::const_iterator it = mSubLedger.begin(); while (it != mSubLedger.end()) { @@ -1352,21 +1358,10 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted) // Don't lock since pubAcceptedTransaction is locking. if (!mSubTransactions.empty() || !mSubRTTransactions.empty() || !mSubAccount.empty() || !mSubRTAccount.empty()) { - SHAMap& txSet = *lpAccepted->peekTransactionMap(); - - for (SHAMapItem::pointer item = txSet.peekFirstItem(); !!item; item = txSet.peekNextItem(item->getTag())) + BOOST_FOREACH(const AcceptedLedger::value_type& vt, alpAccepted->getMap()) { - SerializerIterator it(item->peekSerializer()); - - // OPTIMIZEME: Could get transaction from txn master, but still must call getVL - Serializer txnSer(it.getVL()); - SerializerIterator txnIt(txnSer); - SerializedTransaction stTxn(txnIt); - - TransactionMetaSet::pointer meta = boost::make_shared( - stTxn.getTransactionID(), lpAccepted->getLedgerSeq(), it.getVL()); - - pubAcceptedTransaction(lpAccepted, stTxn, meta->getResultTER(), meta); + cLog(lsTRACE) << "pubAccepted: " << vt.second.getJson(0); + pubAcceptedTransaction(lpAccepted, vt.second); } } } @@ -1407,11 +1402,10 @@ Json::Value NetworkOPs::transJson(const SerializedTransaction& stTxn, TER terRes return jvObj; } -void NetworkOPs::pubAcceptedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult,TransactionMetaSet::pointer& meta) +void NetworkOPs::pubAcceptedTransaction(Ledger::ref alAccepted, const ALTransaction& alTx) { - Json::Value jvObj = transJson(stTxn, terResult, true, lpCurrent, "transaction"); - - if (meta) jvObj["meta"] = meta->getJson(0); + Json::Value jvObj = transJson(*alTx.getTxn(), alTx.getResult(), true, alAccepted, "transaction"); + jvObj["meta"] = alTx.getMeta()->getJson(0); { boost::recursive_mutex::scoped_lock sl(mMonitorLock); @@ -1442,14 +1436,14 @@ void NetworkOPs::pubAcceptedTransaction(Ledger::ref lpCurrent, const SerializedT it = mSubRTTransactions.erase(it); } } - theApp->getOrderBookDB().processTxn(stTxn, terResult, meta, jvObj); - - pubAccountTransaction(lpCurrent, stTxn, terResult, true, meta); + theApp->getOrderBookDB().processTxn(alAccepted, alTx, jvObj); + pubAccountTransaction(alAccepted, alTx); } -void NetworkOPs::pubAccountTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult, bool bAccepted, TransactionMetaSet::pointer& meta) +void NetworkOPs::pubAccountTransaction(Ledger::ref lpCurrent, const ALTransaction& alTx) { boost::unordered_set notify; + bool bAccepted = alTx.isApplied(); int iProposed = 0; int iAccepted = 0; @@ -1460,8 +1454,7 @@ void NetworkOPs::pubAccountTransaction(Ledger::ref lpCurrent, const SerializedTr if (!mSubAccount.empty() || (!mSubRTAccount.empty()) ) { - std::vector accounts = meta ? meta->getAffectedAccounts() : stTxn.getMentionedAccounts(); - BOOST_FOREACH(const RippleAddress& affectedAccount, accounts) + BOOST_FOREACH(const RippleAddress& affectedAccount, alTx.getAffected()) { subInfoMapIterator simiIt = mSubRTAccount.find(affectedAccount.getAccountID()); @@ -1510,9 +1503,10 @@ void NetworkOPs::pubAccountTransaction(Ledger::ref lpCurrent, const SerializedTr if (!notify.empty()) { - Json::Value jvObj = transJson(stTxn, terResult, bAccepted, lpCurrent, "account"); + Json::Value jvObj = transJson(*alTx.getTxn(), alTx.getResult(), bAccepted, lpCurrent, "account"); - if (meta) jvObj["meta"] = meta->getJson(0); + if (alTx.isApplied()) + jvObj["meta"] = alTx.getMeta()->getJson(0); BOOST_FOREACH(InfoSub::ref isrListener, notify) { diff --git a/src/cpp/ripple/NetworkOPs.h b/src/cpp/ripple/NetworkOPs.h index 188543d7c..01d502ae0 100644 --- a/src/cpp/ripple/NetworkOPs.h +++ b/src/cpp/ripple/NetworkOPs.h @@ -14,6 +14,7 @@ #include "LedgerAcquire.h" #include "LedgerProposal.h" #include "JobQueue.h" +#include "AcceptedLedger.h" // Operations that clients may wish to perform against the network // Master operational handler, server sequencer, network tracker @@ -140,8 +141,8 @@ protected: Json::Value pubBootstrapAccountInfo(Ledger::ref lpAccepted, const RippleAddress& naAccountID); - void pubAcceptedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult,TransactionMetaSet::pointer& meta); - void pubAccountTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult,bool accepted,TransactionMetaSet::pointer& meta); + void pubAcceptedTransaction(Ledger::ref alAccepted, const ALTransaction& alTransaction); + void pubAccountTransaction(Ledger::ref lpCurrent, const ALTransaction& alTransaction); void pubServer(); @@ -306,7 +307,7 @@ public: // Monitoring: publisher side // void pubLedger(Ledger::ref lpAccepted); - void pubProposedTransaction(Ledger::ref lpCurrent, const SerializedTransaction& stTxn, TER terResult); + void pubProposedTransaction(Ledger::ref lpCurrent, SerializedTransaction::ref stTxn, TER terResult); // diff --git a/src/cpp/ripple/OrderBookDB.cpp b/src/cpp/ripple/OrderBookDB.cpp index e58757dec..b17c98ab9 100644 --- a/src/cpp/ripple/OrderBookDB.cpp +++ b/src/cpp/ripple/OrderBookDB.cpp @@ -187,15 +187,14 @@ BookListeners::pointer OrderBookDB::getBookListeners(const uint160& currencyIn, */ // Based on the meta, send the meta to the streams that are listening // We need to determine which streams a given meta effects -void OrderBookDB::processTxn(const SerializedTransaction& stTxn, TER terResult, - TransactionMetaSet::pointer& meta, Json::Value& jvObj) +void OrderBookDB::processTxn(Ledger::ref ledger, const ALTransaction& alTx, Json::Value& jvObj) { boost::recursive_mutex::scoped_lock sl(mLock); - if (terResult == tesSUCCESS) + if (alTx.getResult() == tesSUCCESS) { // check if this is an offer or an offer cancel or a payment that consumes an offer //check to see what the meta looks like - BOOST_FOREACH(STObject& node, meta->getNodes()) + BOOST_FOREACH(STObject& node, alTx.getMeta()->getNodes()) { try { diff --git a/src/cpp/ripple/OrderBookDB.h b/src/cpp/ripple/OrderBookDB.h index 768ca05a5..f5119e88b 100644 --- a/src/cpp/ripple/OrderBookDB.h +++ b/src/cpp/ripple/OrderBookDB.h @@ -6,6 +6,7 @@ #include #include "Ledger.h" +#include "AcceptedLedger.h" #include "OrderBook.h" @@ -66,7 +67,7 @@ public: const uint160& issuerIn, const uint160& issuerOut); // see if this txn effects any orderbook - void processTxn(const SerializedTransaction& stTxn, TER terResult,TransactionMetaSet::pointer& meta,Json::Value& jvObj); + void processTxn(Ledger::ref ledger, const ALTransaction& alTx, Json::Value& jvObj); };