From 1bdc4914f5d12d46891d09ba1c51c51fe24fe3a0 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 15:48:17 -0700 Subject: [PATCH 01/22] Add InstanceCounter. --- newcoin.vcxproj | 1 + src/InstanceCounter.cpp | 15 ++++++++ src/InstanceCounter.h | 76 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+) create mode 100644 src/InstanceCounter.cpp create mode 100644 src/InstanceCounter.h diff --git a/newcoin.vcxproj b/newcoin.vcxproj index a2dd3bbb6..3109a074a 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -112,6 +112,7 @@ + diff --git a/src/InstanceCounter.cpp b/src/InstanceCounter.cpp new file mode 100644 index 000000000..564010282 --- /dev/null +++ b/src/InstanceCounter.cpp @@ -0,0 +1,15 @@ +#include "InstanceCounter.h" + +InstanceType* InstanceType::sHeadInstance = NULL; + +std::vector InstanceType::getInstanceCounts(int min) +{ + std::vector ret; + for (InstanceType* i = sHeadInstance; i != NULL; i = i->mNextInstance) + { + int c = i->getCount(); + if (c >= min) + ret.push_back(InstanceCount(i->getName(), c)); + } + return ret; +} diff --git a/src/InstanceCounter.h b/src/InstanceCounter.h new file mode 100644 index 000000000..62c8b91ba --- /dev/null +++ b/src/InstanceCounter.h @@ -0,0 +1,76 @@ +#ifndef INSTANCE_COUNTER__H +#define INSTANCE_COUNTER__H + +#include +#include + +#include + +#define DEFINE_INSTANCE(x) \ + extern InstanceType IT_##x; \ + class Instance_##x : private Instance \ + { \ + protected: \ + Instance_##x() : Instance(IT_##x) { ; } \ + } + +#define DECLARE_INSTANCE(x) \ + InstanceType IT_##x(#x); + +#define IS_INSTANCE(x) Instance_##x + +class InstanceType +{ +protected: + int mInstances; + std::string mName; + boost::mutex mLock; + + InstanceType* mNextInstance; + static InstanceType* sHeadInstance; + +public: + typedef std::pair InstanceCount; + + InstanceType(const char *n) : mInstances(0), mName(n) + { + mNextInstance = sHeadInstance; + sHeadInstance = this; + } + + void addInstance() + { + mLock.lock(); + ++mInstances; + mLock.unlock(); + } + void decInstance() + { + mLock.lock(); + --mInstances; + mLock.unlock(); + } + int getCount() + { + boost::mutex::scoped_lock(mLock); + return mInstances; + } + const std::string& getName() + { + return mName; + } + + static std::vector getInstanceCounts(int min = 1); +}; + +class Instance +{ +protected: + InstanceType& mType; + +public: + Instance(InstanceType& t) : mType(t) { mType.addInstance(); } + ~Instance() { mType.decInstance(); } +}; + +#endif From ce9dc18adea2dd5080c7a4d0b4446f24fcce74d1 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 15:48:38 -0700 Subject: [PATCH 02/22] Add get_counts RPC function. --- src/RPCHandler.cpp | 42 +++++++++++++++++++++++++++++------------- src/RPCHandler.h | 8 +++++++- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/RPCHandler.cpp b/src/RPCHandler.cpp index 2b8fe7225..36fcfdffd 100644 --- a/src/RPCHandler.cpp +++ b/src/RPCHandler.cpp @@ -7,6 +7,7 @@ #include "RippleAddress.h" #include "AccountState.h" #include "NicknameState.h" +#include "InstanceCounter.h" #include "Pathfinder.h" #include @@ -75,7 +76,7 @@ Json::Value RPCHandler::rpcError(int iError) for (i=NUMBER(errorInfoA); i-- && errorInfoA[i].iError != iError;) ; - Json::Value jsonResult = Json::Value(Json::objectValue); + Json::Value jsonResult(Json::objectValue); jsonResult["error"] = i >= 0 ? errorInfoA[i].pToken : lexical_cast_i(iError); jsonResult["error_message"] = i >= 0 ? errorInfoA[i].pMessage : lexical_cast_i(iError); @@ -2420,37 +2421,38 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param bool mAdminRequired; unsigned int iOptions; } commandsA[] = { - { "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true }, - { "account_domain_set", &RPCHandler::doAccountDomainSet, 2, 3, false, optCurrent }, + { "accept_ledger", &RPCHandler::doAcceptLedger, 0, 0, true }, + { "account_domain_set", &RPCHandler::doAccountDomainSet, 2, 3, false, optCurrent }, { "account_email_set", &RPCHandler::doAccountEmailSet, 2, 3, false, optCurrent }, { "account_info", &RPCHandler::doAccountInfo, 1, 2, false, optCurrent }, { "account_message_set", &RPCHandler::doAccountMessageSet, 3, 3, false, optCurrent }, { "account_publish_set", &RPCHandler::doAccountPublishSet, 4, 4, false, optCurrent }, { "account_rate_set", &RPCHandler::doAccountRateSet, 3, 3, false, optCurrent }, { "account_tx", &RPCHandler::doAccountTransactions, 2, 3, false, optNetwork }, - { "account_wallet_set", &RPCHandler::doAccountWalletSet, 2, 3, false, optCurrent }, + { "account_wallet_set", &RPCHandler::doAccountWalletSet, 2, 3, false, optCurrent }, { "connect", &RPCHandler::doConnect, 1, 2, true }, { "data_delete", &RPCHandler::doDataDelete, 1, 1, true }, { "data_fetch", &RPCHandler::doDataFetch, 1, 1, true }, { "data_store", &RPCHandler::doDataStore, 2, 2, true }, + { "get_counts", &RPCHandler::doGetCounts, 0, 1, true }, { "ledger", &RPCHandler::doLedger, 0, 2, false, optNetwork }, - { "log_level", &RPCHandler::doLogLevel, 0, 2, true }, + { "log_level", &RPCHandler::doLogLevel, 0, 2, true }, { "logrotate", &RPCHandler::doLogRotate, 0, 0, true }, - { "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, optCurrent }, + { "nickname_info", &RPCHandler::doNicknameInfo, 1, 1, false, optCurrent }, { "nickname_set", &RPCHandler::doNicknameSet, 2, 3, false, optCurrent }, { "offer_create", &RPCHandler::doOfferCreate, 9, 10, false, optCurrent }, { "offer_cancel", &RPCHandler::doOfferCancel, 3, 3, false, optCurrent }, { "owner_info", &RPCHandler::doOwnerInfo, 1, 2, false, optCurrent }, - { "password_fund", &RPCHandler::doPasswordFund, 2, 3, false, optCurrent }, + { "password_fund", &RPCHandler::doPasswordFund, 2, 3, false, optCurrent }, { "password_set", &RPCHandler::doPasswordSet, 2, 3, false, optNetwork }, { "peers", &RPCHandler::doPeers, 0, 0, true }, { "profile", &RPCHandler::doProfile, 1, 9, false, optCurrent }, { "ripple", &RPCHandler::doRipple, 9, -1, false, optCurrent|optClosed }, { "ripple_lines_get", &RPCHandler::doRippleLinesGet, 1, 2, false, optCurrent }, { "ripple_line_set", &RPCHandler::doRippleLineSet, 4, 7, false, optCurrent }, - { "send", &RPCHandler::doSend, 3, 9, false, optCurrent }, + { "send", &RPCHandler::doSend, 3, 9, false, optCurrent }, { "server_info", &RPCHandler::doServerInfo, 0, 0, true }, - { "stop", &RPCHandler::doStop, 0, 0, true }, + { "stop", &RPCHandler::doStop, 0, 0, true }, { "tx", &RPCHandler::doTx, 1, 1, true }, { "tx_history", &RPCHandler::doTxHistory, 1, 1, false, }, @@ -2459,16 +2461,16 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param { "unl_list", &RPCHandler::doUnlList, 0, 0, true }, { "unl_load", &RPCHandler::doUnlLoad, 0, 0, true }, { "unl_network", &RPCHandler::doUnlNetwork, 0, 0, true }, - { "unl_reset", &RPCHandler::doUnlReset, 0, 0, true }, - { "unl_score", &RPCHandler::doUnlScore, 0, 0, true }, + { "unl_reset", &RPCHandler::doUnlReset, 0, 0, true }, + { "unl_score", &RPCHandler::doUnlScore, 0, 0, true }, - { "validation_create", &RPCHandler::doValidationCreate, 0, 1, false }, + { "validation_create", &RPCHandler::doValidationCreate, 0, 1, false }, { "validation_seed", &RPCHandler::doValidationSeed, 0, 1, false }, { "wallet_accounts", &RPCHandler::doWalletAccounts, 1, 1, false, optCurrent }, { "wallet_add", &RPCHandler::doWalletAdd, 3, 5, false, optCurrent }, { "wallet_claim", &RPCHandler::doWalletClaim, 2, 4, false, optNetwork }, - { "wallet_create", &RPCHandler::doWalletCreate, 3, 4, false, optCurrent }, + { "wallet_create", &RPCHandler::doWalletCreate, 3, 4, false, optCurrent }, { "wallet_propose", &RPCHandler::doWalletPropose, 0, 1, false, }, { "wallet_seed", &RPCHandler::doWalletSeed, 0, 1, false, }, @@ -2603,6 +2605,20 @@ Json::Value RPCHandler::doLogin(const Json::Value& params) } } +Json::Value RPCHandler::doGetCounts(const Json::Value& params) +{ + int minCount = 1; + if (params.size() > 0) + minCount = params[0u].asInt(); + + std::vector count = InstanceType::getInstanceCounts(minCount); + + Json::Value ret(Json::objectValue); + BOOST_FOREACH(InstanceType::InstanceCount& it, count) + ret[it.first] = it.second; + return ret; +} + Json::Value RPCHandler::doLogLevel(const Json::Value& params) { if (params.size() == 0) diff --git a/src/RPCHandler.h b/src/RPCHandler.h index 4dfd7f80b..c001e7dff 100644 --- a/src/RPCHandler.h +++ b/src/RPCHandler.h @@ -1,3 +1,6 @@ +#ifndef RPCHANDLER__H +#define RPCHANDLER__H + // used by the RPCServer or WSDoor to carry out these RPC commands class NetworkOPs; @@ -37,6 +40,7 @@ class RPCHandler Json::Value doDataDelete(const Json::Value& params); Json::Value doDataFetch(const Json::Value& params); Json::Value doDataStore(const Json::Value& params); + Json::Value doGetCounts(const Json::Value& params); Json::Value doLedger(const Json::Value& params); Json::Value doLogRotate(const Json::Value& params); Json::Value doNicknameInfo(const Json::Value& params); @@ -156,4 +160,6 @@ public: Json::Value doCommand(const std::string& command, Json::Value& params,int role); Json::Value rpcError(int iError); -}; \ No newline at end of file +}; + +#endif From cd93bd0de3ac7914021c61b0c02d813396a74d3d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 15:49:47 -0700 Subject: [PATCH 03/22] Make sure TaggedCaches get sweeped. --- src/Application.cpp | 13 ++++++++++++- src/Application.h | 3 +++ src/HashedObject.h | 1 + src/LedgerHistory.h | 1 + src/TaggedCache.h | 4 ++-- src/TransactionMaster.h | 1 + 6 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 7c459fc12..8ec0b2bf3 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -42,11 +42,13 @@ Application::Application() : mNetOps(mIOService, &mMasterLedger), mTempNodeCache(16384, 90), mHashedObjectStore(16384, 300), mSNTPClient(mAuxService), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), - mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL) + mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mSweepTimer(mAuxService) { RAND_bytes(mNonce256.begin(), mNonce256.size()); RAND_bytes(reinterpret_cast(&mNonceST), sizeof(mNonceST)); mJobQueue.setThreadCount(); + mSweepTimer.expires_from_now(boost::posix_time::seconds(60)); + mSweepTimer.async_wait(boost::bind(&Application::sweep, this)); } extern const char *RpcDBInit[], *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], *HashNodeDBInit[], *NetNodeDBInit[]; @@ -183,6 +185,15 @@ void Application::run() std::cout << "Done." << std::endl; } +void Application::sweep() +{ + mMasterTransaction.sweep(); + mHashedObjectStore.sweep(); + mMasterLedger.sweep(); + mSweepTimer.expires_from_now(boost::posix_time::seconds(60)); + mSweepTimer.async_wait(boost::bind(&Application::sweep, this)); +} + Application::~Application() { delete mTxnDB; diff --git a/src/Application.h b/src/Application.h index ebb078492..819340832 100644 --- a/src/Application.h +++ b/src/Application.h @@ -66,6 +66,8 @@ class Application uint256 mNonce256; std::size_t mNonceST; + boost::asio::deadline_timer mSweepTimer; + std::map mPeerMap; boost::recursive_mutex mPeerMapLock; @@ -110,6 +112,7 @@ public: void run(); void stop(); + void sweep(); }; extern Application* theApp; diff --git a/src/HashedObject.h b/src/HashedObject.h index 5178af089..a3fb8cbe0 100644 --- a/src/HashedObject.h +++ b/src/HashedObject.h @@ -61,6 +61,7 @@ public: void bulkWrite(); void waitWrite(); + void sweep() { mCache.sweep(); } }; #endif diff --git a/src/LedgerHistory.h b/src/LedgerHistory.h index ed58f4fc9..51ecaf714 100644 --- a/src/LedgerHistory.h +++ b/src/LedgerHistory.h @@ -18,6 +18,7 @@ public: Ledger::pointer getLedgerBySeq(uint32 index); Ledger::pointer getLedgerByHash(const uint256& hash); Ledger::pointer canonicalizeLedger(Ledger::pointer, bool cache); + void sweep() { mLedgersByHash.sweep(); } }; #endif diff --git a/src/TaggedCache.h b/src/TaggedCache.h index ece2b3663..a6c56efa4 100644 --- a/src/TaggedCache.h +++ b/src/TaggedCache.h @@ -96,7 +96,7 @@ template void TaggedCache::sweep typename boost::unordered_map::iterator cit = mCache.begin(); while (cit != mCache.end()) { - if (cit->second->second.first < target) + if (cit->second.first < target) mCache.erase(cit++); else ++cit; @@ -106,7 +106,7 @@ template void TaggedCache::sweep typename boost::unordered_map::iterator mit = mMap.begin(); while (mit != mMap.end()) { - if (mit->second->expired()) + if (mit->second.expired()) mMap.erase(mit++); else ++mit; diff --git a/src/TransactionMaster.h b/src/TransactionMaster.h index 19fd8b64d..138c05c9c 100644 --- a/src/TransactionMaster.h +++ b/src/TransactionMaster.h @@ -20,6 +20,7 @@ public: // return value: true = we had the transaction already bool canonicalize(Transaction::pointer& txn, bool maybeNew); + void sweep(void) { mCache.sweep(); } }; #endif From f0eb8e79430cf7770ab701614692a6c4261b92a5 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 15:50:14 -0700 Subject: [PATCH 04/22] Add instance counts to core classes. --- src/Ledger.cpp | 1 + src/Ledger.h | 5 ++++- src/LedgerMaster.h | 2 ++ src/Peer.cpp | 1 + src/Peer.h | 5 ++++- src/SHAMap.cpp | 4 ++++ src/SHAMap.h | 13 +++++++++---- 7 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 1b6775232..69807417e 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -20,6 +20,7 @@ #include "Log.h" SETUP_LOG(); +DECLARE_INSTANCE(Ledger); Ledger::Ledger(const RippleAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(1), mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0), diff --git a/src/Ledger.h b/src/Ledger.h index 1074ec9fb..c033c59c4 100644 --- a/src/Ledger.h +++ b/src/Ledger.h @@ -18,6 +18,7 @@ #include "types.h" #include "BitcoinUtil.h" #include "SHAMap.h" +#include "InstanceCounter.h" enum LedgerStateParms { @@ -38,7 +39,9 @@ enum LedgerStateParms #define LEDGER_JSON_DUMP_STATE 0x20000000 #define LEDGER_JSON_FULL 0x40000000 -class Ledger : public boost::enable_shared_from_this +DEFINE_INSTANCE(Ledger); + +class Ledger : public boost::enable_shared_from_this, public IS_INSTANCE(Ledger) { // The basic Ledger structure, can be opened, closed, or synching friend class TransactionEngine; public: diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h index 967026fed..e3270710e 100644 --- a/src/LedgerMaster.h +++ b/src/LedgerMaster.h @@ -91,6 +91,8 @@ public: void setLedgerRangePresent(uint32 minV, uint32 maxV) { mCompleteLedgers.setRange(minV, maxV); } bool addHeldTransaction(const Transaction::pointer& trans); + + void sweep(void) { mLedgerHistory.sweep(); } }; #endif diff --git a/src/Peer.cpp b/src/Peer.cpp index 609bf90e5..491991c23 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -16,6 +16,7 @@ #include "Log.h" SETUP_LOG(); +DECLARE_INSTANCE(Peer); // Don't try to run past receiving nonsense from a peer #define TRUST_NETWORK diff --git a/src/Peer.h b/src/Peer.h index 76b11d092..cc3a525c5 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -11,6 +11,7 @@ #include "PackedMessage.h" #include "Ledger.h" #include "Transaction.h" +#include "InstanceCounter.h" enum PeerPunish { @@ -21,7 +22,9 @@ enum PeerPunish typedef std::pair ipPort; -class Peer : public boost::enable_shared_from_this +DEFINE_INSTANCE(Peer); + +class Peer : public boost::enable_shared_from_this, public IS_INSTANCE(Peer) { public: typedef boost::shared_ptr pointer; diff --git a/src/SHAMap.cpp b/src/SHAMap.cpp index b7a775778..e3de616d2 100644 --- a/src/SHAMap.cpp +++ b/src/SHAMap.cpp @@ -17,6 +17,10 @@ SETUP_LOG(); +DECLARE_INSTANCE(SHAMap); +DECLARE_INSTANCE(SHAMapItem); +DECLARE_INSTANCE(SHAMapTreeNode); + std::size_t hash_value(const SHAMapNode& mn) { std::size_t seed = theApp->getNonceST(); diff --git a/src/SHAMap.h b/src/SHAMap.h index 107d3d8b6..6acadf667 100644 --- a/src/SHAMap.h +++ b/src/SHAMap.h @@ -14,6 +14,11 @@ #include "ScopedLock.h" #include "Serializer.h" #include "HashedObject.h" +#include "InstanceCounter.h" + +DEFINE_INSTANCE(SHAMap); +DEFINE_INSTANCE(SHAMapItem); +DEFINE_INSTANCE(SHAMapTreeNode); class SHAMap; @@ -31,7 +36,7 @@ private: public: - static const int rootDepth=0; + static const int rootDepth = 0; SHAMapNode() : mDepth(0) { ; } SHAMapNode(int depth, const uint256& hash); @@ -77,7 +82,7 @@ extern std::size_t hash_value(const SHAMapNode& mn); inline std::ostream& operator<<(std::ostream& out, const SHAMapNode& node) { return out << node.getString(); } -class SHAMapItem +class SHAMapItem : public IS_INSTANCE(SHAMapItem) { // an item stored in a SHAMap public: typedef boost::shared_ptr pointer; @@ -135,7 +140,7 @@ enum SHAMapType smtFREE =3, // A tree not part of a ledger }; -class SHAMapTreeNode : public SHAMapNode +class SHAMapTreeNode : public SHAMapNode, public IS_INSTANCE(SHAMapTreeNode) { friend class SHAMap; @@ -276,7 +281,7 @@ public: extern std::ostream& operator<<(std::ostream&, const SHAMapMissingNode&); -class SHAMap +class SHAMap : public IS_INSTANCE(SHAMap) { public: typedef boost::shared_ptr pointer; From 9743b7cafae3ac562f5a100f1a6735ca8740f1dd Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 15:55:14 -0700 Subject: [PATCH 05/22] Add 'getTrackSize' --- src/TaggedCache.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/TaggedCache.h b/src/TaggedCache.h index a6c56efa4..fe7e03d24 100644 --- a/src/TaggedCache.h +++ b/src/TaggedCache.h @@ -44,6 +44,7 @@ public: int getTargetAge() const; int getCacheSize(); + int getTrackSize(); int getSweepAge(); void setTargetSize(int size); @@ -78,6 +79,12 @@ template int TaggedCache::getCac return mCache.size(); } +template int TaggedCache::getTrackSize() +{ + boost::recursive_mutex::scoped_lock sl(mLock); + return mMap.size(); +} + template void TaggedCache::sweep() { boost::recursive_mutex::scoped_lock sl(mLock); From a37c5d6314f3b1a0a97892c562bc623f187d6d64 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 16:01:59 -0700 Subject: [PATCH 06/22] Sweep the temp node cache. --- src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Application.cpp b/src/Application.cpp index 8ec0b2bf3..758fae4ae 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -190,6 +190,7 @@ void Application::sweep() mMasterTransaction.sweep(); mHashedObjectStore.sweep(); mMasterLedger.sweep(); + mTempNodeCache.sweep(); mSweepTimer.expires_from_now(boost::posix_time::seconds(60)); mSweepTimer.async_wait(boost::bind(&Application::sweep, this)); } From ca65e5ad8f1e6395c64f19f7cfea267d24f55bf3 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 16:02:21 -0700 Subject: [PATCH 07/22] Add transactions to the tracked class list. --- src/Transaction.cpp | 2 ++ src/Transaction.h | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 2fca62742..c4dbd435c 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -13,6 +13,8 @@ #include "SerializedTransaction.h" #include "Log.h" +DECLARE_INSTANCE(Transaction); + Transaction::Transaction(SerializedTransaction::ref sit, bool bValidate) : mInLedger(0), mStatus(INVALID), mResult(temUNCERTAIN), mTransaction(sit) { diff --git a/src/Transaction.h b/src/Transaction.h index 8d14654e2..ea049b527 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -21,6 +21,7 @@ #include "SHAMap.h" #include "SerializedTransaction.h" #include "TransactionErr.h" +#include "InstanceCounter.h" class Database; @@ -37,8 +38,10 @@ enum TransStatus INCOMPLETE = 8 // needs more signatures }; +DEFINE_INSTANCE(Transaction); + // This class is for constructing and examining transactions. Transactions are static so manipulation functions are unnecessary. -class Transaction : public boost::enable_shared_from_this +class Transaction : public boost::enable_shared_from_this, private IS_INSTANCE(Transaction) { public: typedef boost::shared_ptr pointer; From 7fa7a5e2cca6892ccb757468143582067bb2bcee Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 16:02:38 -0700 Subject: [PATCH 08/22] Add hashed objects to the tracked class list. --- src/HashedObject.cpp | 1 + src/HashedObject.h | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/HashedObject.cpp b/src/HashedObject.cpp index 997be4c23..bff9c34c6 100644 --- a/src/HashedObject.cpp +++ b/src/HashedObject.cpp @@ -9,6 +9,7 @@ #include "Log.h" SETUP_LOG(); +DECLARE_INSTANCE(HashedObject); HashedObjectStore::HashedObjectStore(int cacheSize, int cacheAge) : mCache(cacheSize, cacheAge), mWritePending(false) diff --git a/src/HashedObject.h b/src/HashedObject.h index a3fb8cbe0..7f3191254 100644 --- a/src/HashedObject.h +++ b/src/HashedObject.h @@ -10,6 +10,9 @@ #include "uint256.h" #include "ScopedLock.h" #include "TaggedCache.h" +#include "InstanceCounter.h" + +DEFINE_INSTANCE(HashedObject); enum HashedObjectType { @@ -20,7 +23,7 @@ enum HashedObjectType hotTRANSACTION_NODE = 4 }; -class HashedObject +class HashedObject : private IS_INSTANCE(HashedObject) { public: typedef boost::shared_ptr pointer; From 9098c3f73965b7a0e85f861fba6b07118fae2f9c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 16:09:22 -0700 Subject: [PATCH 09/22] Make the compiler happy. --- src/InstanceCounter.h | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/InstanceCounter.h b/src/InstanceCounter.h index 62c8b91ba..ffb3665f5 100644 --- a/src/InstanceCounter.h +++ b/src/InstanceCounter.h @@ -6,15 +6,19 @@ #include -#define DEFINE_INSTANCE(x) \ - extern InstanceType IT_##x; \ - class Instance_##x : private Instance \ - { \ - protected: \ - Instance_##x() : Instance(IT_##x) { ; } \ +#define DEFINE_INSTANCE(x) \ + extern InstanceType IT_##x; \ + class Instance_##x : private Instance \ + { \ + protected: \ + Instance_##x() : Instance(IT_##x) { ; } \ + Instance_##x(const Instance_##x &) : \ + Instance(IT_##x) { ; } \ + Instance_##x& operator=(const Instance_##x&) \ + { return *this; } \ } -#define DECLARE_INSTANCE(x) \ +#define DECLARE_INSTANCE(x) \ InstanceType IT_##x(#x); #define IS_INSTANCE(x) Instance_##x From 8e4b11b668d2560ae6d236bdfee3a5b97679921c Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 16:11:59 -0700 Subject: [PATCH 10/22] Add more counted types. --- src/SerializedLedger.cpp | 2 ++ src/SerializedLedger.h | 5 ++++- src/SerializedObject.cpp | 2 ++ src/SerializedObject.h | 8 ++++++-- src/SerializedTransaction.cpp | 2 ++ src/SerializedTransaction.h | 5 ++++- src/SerializedTypes.cpp | 1 + src/SerializedTypes.h | 6 ++++-- 8 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/SerializedLedger.cpp b/src/SerializedLedger.cpp index 359a93fa5..00a353987 100644 --- a/src/SerializedLedger.cpp +++ b/src/SerializedLedger.cpp @@ -5,6 +5,8 @@ #include "Ledger.h" #include "Log.h" +DECLARE_INSTANCE(SerializedLedgerEntry) + SerializedLedgerEntry::SerializedLedgerEntry(SerializerIterator& sit, const uint256& index) : STObject(sfLedgerEntry), mIndex(index) { diff --git a/src/SerializedLedger.h b/src/SerializedLedger.h index c02126db1..7bbdfaf99 100644 --- a/src/SerializedLedger.h +++ b/src/SerializedLedger.h @@ -4,8 +4,11 @@ #include "SerializedObject.h" #include "LedgerFormats.h" #include "RippleAddress.h" +#include "InstanceCounter.h" -class SerializedLedgerEntry : public STObject +DEFINE_INSTANCE(SerializedLedgerEntry); + +class SerializedLedgerEntry : public STObject, private IS_INSTANCE(SerializedLedgerEntry) { public: typedef boost::shared_ptr pointer; diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 1477a2393..7b6a51f94 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -14,6 +14,8 @@ #include "SerializedTransaction.h" SETUP_LOG(); +DECLARE_INSTANCE(SerializedObject); +DECLARE_INSTANCE(SerializedArray); std::auto_ptr STObject::makeDefaultObject(SerializedTypeID id, SField::ref name) { diff --git a/src/SerializedObject.h b/src/SerializedObject.h index 00c89ed1e..d0d3ce6af 100644 --- a/src/SerializedObject.h +++ b/src/SerializedObject.h @@ -8,6 +8,10 @@ #include "../json/value.h" #include "SerializedTypes.h" +#include "InstanceCounter.h" + +DEFINE_INSTANCE(SerializedObject); +DEFINE_INSTANCE(SerializedArray); // Serializable object/array types @@ -22,7 +26,7 @@ public: SOElement(SField::ref fi, SOE_Flags fl) : e_field(fi), flags(fl) { ; } }; -class STObject : public SerializedType +class STObject : public SerializedType, private IS_INSTANCE(SerializedObject) { protected: boost::ptr_vector mData; @@ -175,7 +179,7 @@ namespace boost -class STArray : public SerializedType +class STArray : public SerializedType, private IS_INSTANCE(SerializedArray) { public: typedef std::vector vector; diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index d6b7a0291..bdc26d77e 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -8,6 +8,8 @@ #include "Log.h" #include "HashPrefixes.h" +DECLARE_INSTANCE(SerializedTransaction); + SerializedTransaction::SerializedTransaction(TransactionType type) : STObject(sfTransaction), mType(type) { mFormat = TransactionFormat::getTxnFormat(type); diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index 185ca6cda..50d974db0 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -9,6 +9,7 @@ #include "SerializedObject.h" #include "TransactionFormats.h" #include "RippleAddress.h" +#include "InstanceCounter.h" #define TXN_SQL_NEW 'N' #define TXN_SQL_CONFLICT 'C' @@ -17,7 +18,9 @@ #define TXN_SQL_INCLUDED 'I' #define TXN_SQL_UNKNOWN 'U' -class SerializedTransaction : public STObject +DEFINE_INSTANCE(SerializedTransaction); + +class SerializedTransaction : public STObject, private IS_INSTANCE(SerializedTransaction) { public: typedef boost::shared_ptr pointer; diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 55fc7039b..5fc0ebbe3 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -14,6 +14,7 @@ #include "TransactionErr.h" SETUP_LOG(); +DECLARE_INSTANCE(SerializedEntry); STAmount saZero(CURRENCY_ONE, ACCOUNT_ONE, 0); STAmount saOne(CURRENCY_ONE, ACCOUNT_ONE, 1); diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 62f7347c8..6e1267448 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -9,7 +9,7 @@ #include "uint256.h" #include "Serializer.h" #include "FieldNames.h" - +#include "InstanceCounter.h" enum PathFlags { @@ -30,7 +30,9 @@ enum PathFlags #define ACCOUNT_XNS uint160(0) #define ACCOUNT_ONE uint160(1) // Used as a place holder -class SerializedType +DEFINE_INSTANCE(SerializedEntry); + +class SerializedType : private IS_INSTANCE(SerializedEntry) { protected: SField::ptr fName; From 5c39a6ce922f7ea9d2c493d6b661fe927a0ccdfa Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 31 Oct 2012 16:41:08 -0700 Subject: [PATCH 11/22] Fix JSON parsing of pathsets. --- src/SerializedObject.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/SerializedObject.cpp b/src/SerializedObject.cpp index 1477a2393..4cd59df27 100644 --- a/src/SerializedObject.cpp +++ b/src/SerializedObject.cpp @@ -1110,23 +1110,24 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r data.push_back(new STPathSet(field)); STPathSet* tail = dynamic_cast(&data.back()); assert(tail); - for (Json::UInt i = 0; !object.isValidIndex(i); ++i) + for (Json::UInt i = 0; value.isValidIndex(i); ++i) { STPath p; - if (!object[i].isArray()) + if (!value[i].isArray()) throw std::runtime_error("Path must be array"); - for (Json::UInt j = 0; !object[i].isValidIndex(j); ++j) + for (Json::UInt j = 0; value[i].isValidIndex(j); ++j) { // each element in this path has some combination of account, currency, or issuer - Json::Value pathEl = object[i][j]; + Json::Value pathEl = value[i][j]; if (!pathEl.isObject()) throw std::runtime_error("Path elements must be objects"); - const Json::Value& account = pathEl["account"]; - const Json::Value& currency = pathEl["currency"]; - const Json::Value& issuer = pathEl["issuer"]; + const Json::Value& account = pathEl["account"]; + const Json::Value& currency = pathEl["currency"]; + const Json::Value& issuer = pathEl["issuer"]; + bool hasCurrency = false; uint160 uAccount, uCurrency, uIssuer; - bool hasCurrency; + if (!account.isNull()) { // human account id if (!account.isString()) @@ -1136,7 +1137,7 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r uAccount.SetHex(strValue); { RippleAddress a; - if (!a.setAccountPublic(strValue)) + if (!a.setAccountID(strValue)) throw std::runtime_error("Account in path element invalid"); uAccount = a.getAccountID(); } @@ -1160,7 +1161,7 @@ std::auto_ptr STObject::parseJson(const Json::Value& object, SField::r else { RippleAddress a; - if (!a.setAccountPublic(issuer.asString())) + if (!a.setAccountID(issuer.asString())) throw std::runtime_error("path element issuer invalid"); uIssuer = a.getAccountID(); } From 8dde742bb1bc65c09a85e3e244f61697cb5f132c Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 31 Oct 2012 16:41:41 -0700 Subject: [PATCH 12/22] Fix ripple path expansion. --- src/RippleCalc.cpp | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/RippleCalc.cpp b/src/RippleCalc.cpp index 6cbbf46d8..3d14717d8 100644 --- a/src/RippleCalc.cpp +++ b/src/RippleCalc.cpp @@ -1421,6 +1421,8 @@ bool PathState::lessPriority(PathState::ref lhs, PathState::ref rhs) // Make sure the path delivers to uAccountID: uCurrencyID from uIssuerID. // +// If the unadded next node as specified by arguments would not work as is, then add the necessary nodes so it would work. +// // Rules: // - Currencies must be converted via an offer. // - A node names it's output. @@ -1449,13 +1451,14 @@ TER PathState::pushImply( ACCOUNT_ONE, // Placeholder for offers. uCurrencyID, // The offer's output is what is now wanted. uIssuerID); - } + const PaymentNode& pnBck = vpnNodes.back(); + // For ripple, non-stamps, ensure the issuer is on at least one side of the transaction. if (tesSUCCESS == terResult && !!uCurrencyID // Not stamps. - && (pnPrv.uAccountID != uIssuerID // Previous is not issuing own IOUs. + && (pnBck.uAccountID != uIssuerID // Previous is not issuing own IOUs. && uAccountID != uIssuerID)) // Current is not receiving own IOUs. { // Need to ripple through uIssuerID's account. @@ -1514,13 +1517,19 @@ TER PathState::pushNode( pnCur.saRevRedeem = STAmount(uCurrencyID, uAccountID); pnCur.saRevIssue = STAmount(uCurrencyID, uAccountID); - if (!bFirst) + if (bFirst) + { + // The first node is always correct as is. + + nothing(); + } + else { // Add required intermediate nodes to deliver to current account. terResult = pushImply( pnCur.uAccountID, // Current account. pnCur.uCurrencyID, // Wanted currency. - !!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as issuer. + !!pnCur.uCurrencyID ? uAccountID : ACCOUNT_XNS); // Account as wanted issuer. // Note: pnPrv may no longer be the immediately previous node. } @@ -1532,7 +1541,7 @@ TER PathState::pushNode( if (bBckAccount) { - SLE::pointer sleRippleState = mLedger->getSLE(Ledger::getRippleStateIndex(pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID)); + SLE::pointer sleRippleState = lesEntries.entryCache(ltRIPPLE_STATE, Ledger::getRippleStateIndex(pnBck.uAccountID, pnCur.uAccountID, pnPrv.uCurrencyID)); if (!sleRippleState) { @@ -1541,7 +1550,7 @@ TER PathState::pushNode( << " and " << RippleAddress::createHumanAccountID(pnCur.uAccountID) << " for " - << STAmount::createHumanCurrency(pnPrv.uCurrencyID) + << STAmount::createHumanCurrency(pnCur.uCurrencyID) << "." ; cLog(lsINFO) << getJson(); @@ -1555,12 +1564,12 @@ TER PathState::pushNode( << " and " << RippleAddress::createHumanAccountID(pnCur.uAccountID) << " for " - << STAmount::createHumanCurrency(pnPrv.uCurrencyID) + << STAmount::createHumanCurrency(pnCur.uCurrencyID) << "." ; - STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, uCurrencyID); + STAmount saOwed = lesEntries.rippleOwed(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID); - if (!saOwed.isPositive() && *saOwed.negate() >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, uCurrencyID)) + if (!saOwed.isPositive() && *saOwed.negate() >= lesEntries.rippleLimit(pnCur.uAccountID, pnBck.uAccountID, pnCur.uCurrencyID)) { terResult = tepPATH_DRY; } From 988bc7fe4d7c7669f46755239a1d09100fea025a Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 31 Oct 2012 16:42:22 -0700 Subject: [PATCH 13/22] JS: Add Currency.json_rewrite(). --- js/amount.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/js/amount.js b/js/amount.js index a9e6e839d..b5c542288 100644 --- a/js/amount.js +++ b/js/amount.js @@ -232,6 +232,11 @@ var Currency = function () { this.value = NaN; } +// Given "USD" return the json. +Currency.json_rewrite = function(j) { + return Currency.from_json(j).to_json(); +}; + Currency.from_json = function (j) { return (new Currency()).parse_json(j); }; From 227acf210a2f1ff3e8172be0c822349cb01c7070 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 31 Oct 2012 16:42:56 -0700 Subject: [PATCH 14/22] JS: Add support for paths to payments. --- js/remote.js | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/js/remote.js b/js/remote.js index 8313088f0..1b0fe5a2d 100644 --- a/js/remote.js +++ b/js/remote.js @@ -980,6 +980,43 @@ Transaction.prototype.submit = function () { // Set options for Transactions // +Transaction._path_rewrite = function (path) { + var path_new = []; + + for (var index in path) { + var node = path[index]; + var node_new = {}; + + if ('account' in node) + node_new.account = UInt160.json_rewrite(node.account); + if ('issuer' in node) + node_new.issuer = UInt160.json_rewrite(node.issuer); + if ('currency' in node) + node_new.currency = Currency.json_rewrite(node.currency); + + path_new.push(node_new); + } + + return path_new; +} + +Transaction.prototype.path_add = function (path) { + this.transaction.Paths = this.transaction.Paths || [] + this.transaction.Paths.push(Transaction._path_rewrite(path)); + + return this; +} + +// --> paths: undefined or array of path +// A path is an array of objects containing some combination of: account, currency, issuer +Transaction.prototype.paths = function (paths) { + for (var index in paths) { + this.path_add(paths[index]); + } + + return this; +} + // If the secret is in the config object, it does not need to be provided. Transaction.prototype.secret = function (secret) { this.secret = secret; @@ -987,7 +1024,7 @@ Transaction.prototype.secret = function (secret) { Transaction.prototype.send_max = function (send_max) { if (send_max) - this.transaction.SendMax = send_max.to_json(); + this.transaction.SendMax = Amount.json_rewrite(send_max); return this; } @@ -1105,6 +1142,13 @@ Transaction.prototype.password_set = function (src, authorized_key, generator, p // --> src : UInt160 or String // --> dst : UInt160 or String // --> deliver_amount : Amount or String. +// +// Options: +// .paths() +// .path_add() +// .secret() +// .send_max() +// .set_flags() Transaction.prototype.payment = function (src, dst, deliver_amount) { this.secret = this._account_secret(src); this.transaction.TransactionType = 'Payment'; From 76c7385cbb255d40c7082a3ce6fc9f8fbf172248 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 31 Oct 2012 16:43:15 -0700 Subject: [PATCH 15/22] UT: Add test for specifying a path. --- test/send-test.js | 59 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/test/send-test.js b/test/send-test.js index 13ca51376..bb42fbe2e 100644 --- a/test/send-test.js +++ b/test/send-test.js @@ -523,6 +523,65 @@ buster.testCase("Indirect ripple", { }); }, + "indirect ripple with path" : + function (done) { + var self = this; + + async.waterfall([ + function (callback) { + self.what = "Create accounts."; + + testutils.create_accounts(self.remote, "root", "10000", ["alice", "bob", "mtgox"], callback); + }, + function (callback) { + self.what = "Set alice's limit."; + + testutils.credit_limit(self.remote, "alice", "600/USD/mtgox", callback); + }, + function (callback) { + self.what = "Set bob's limit."; + + testutils.credit_limit(self.remote, "bob", "700/USD/mtgox", callback); + }, + function (callback) { + self.what = "Give alice some mtgox."; + + testutils.payment(self.remote, "mtgox", "alice", "70/USD/mtgox", callback); + }, + function (callback) { + self.what = "Give bob some mtgox."; + + testutils.payment(self.remote, "mtgox", "bob", "50/USD/mtgox", callback); + }, + function (callback) { + self.what = "Alice sends via a path"; + + self.remote.transaction() + .payment("alice", "bob", "5/USD/mtgox") + .path_add( [ { account: "mtgox" } ]) + .on('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + + callback(m.result != 'tesSUCCESS'); + }) + .submit(); + }, + function (callback) { + self.what = "Verify alice balance with mtgox."; + + testutils.verify_balance(self.remote, "alice", "65/USD/mtgox", callback); + }, + function (callback) { + self.what = "Verify bob balance with mtgox."; + + testutils.verify_balance(self.remote, "bob", "55/USD/mtgox", callback); + }, + ], function (error) { + buster.refute(error, self.what); + done(); + }); + }, + // Direct ripple without no liqudity. // Ripple without credit path. // Ripple with one-way credit path. From bcff9fad177a4711c8a4bca9b8f1ae1202c21b98 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 17:32:26 -0700 Subject: [PATCH 16/22] Next generation supression code. --- src/Application.h | 1 - src/Suppression.cpp | 75 +++++++++++++++++++++++++++++++-------------- src/Suppression.h | 38 ++++++++++++++++++++--- 3 files changed, 85 insertions(+), 29 deletions(-) diff --git a/src/Application.h b/src/Application.h index 819340832..288f505bc 100644 --- a/src/Application.h +++ b/src/Application.h @@ -96,7 +96,6 @@ public: ValidationCollection& getValidations() { return mValidations; } JobQueue& getJobQueue() { return mJobQueue; } bool isNew(const uint256& s) { return mSuppressions.addSuppression(s); } - bool isNew(const uint160& s) { return mSuppressions.addSuppression(s); } bool running() { return mTxnDB != NULL; } bool getSystemTimeOffset(int& offset) { return mSNTPClient.getOffset(offset); } diff --git a/src/Suppression.cpp b/src/Suppression.cpp index 4b7cad571..2576a2aed 100644 --- a/src/Suppression.cpp +++ b/src/Suppression.cpp @@ -1,39 +1,68 @@ + #include "Suppression.h" #include -bool SuppressionTable::addSuppression(const uint160& suppression) -{ - boost::mutex::scoped_lock sl(mSuppressionMutex); +DECLARE_INSTANCE(Suppression); - if (mSuppressionMap.find(suppression) != mSuppressionMap.end()) - return false; +Suppression& SuppressionTable::findCreateEntry(const uint256& index, bool& created) +{ + boost::unordered_map::iterator fit = mSuppressionMap.find(index); + + if (fit != mSuppressionMap.end()) + { + created = false; + return fit->second; + } + created = true; time_t now = time(NULL); time_t expireTime = now - mHoldTime; - boost::unordered_map< time_t, std::list >::iterator - it = mSuppressionTimes.begin(), end = mSuppressionTimes.end(); - while (it != end) + // See if any supressions need to be expired + std::map< time_t, std::list >::iterator it = mSuppressionTimes.begin(); + if ((it != mSuppressionTimes.end()) && (it->first <= expireTime)) { - if (it->first <= expireTime) - { - BOOST_FOREACH(const uint160& lit, it->second) - mSuppressionMap.erase(lit); - it = mSuppressionTimes.erase(it); - } - else ++it; + BOOST_FOREACH(const uint256& lit, it->second) + mSuppressionMap.erase(lit); + mSuppressionTimes.erase(it); } - mSuppressionMap[suppression] = now; - mSuppressionTimes[now].push_back(suppression); - - return true; + mSuppressionTimes[now].push_back(index); + return mSuppressionMap.insert(std::make_pair(index, Suppression())).first->second; } -bool SuppressionTable::addSuppression(const uint256& suppression) +bool SuppressionTable::addSuppression(const uint256& index) { - uint160 u; - memcpy(u.begin(), suppression.begin() + (suppression.size() - u.size()), u.size()); - return addSuppression(u); + boost::mutex::scoped_lock sl(mSuppressionMutex); + + bool created; + findCreateEntry(index, created); + return created; +} + +Suppression SuppressionTable::getEntry(const uint256& index) +{ + boost::mutex::scoped_lock sl(mSuppressionMutex); + + bool created; + return findCreateEntry(index, created); +} + +bool SuppressionTable::addSuppressionPeer(const uint256& index, uint64 peer) +{ + boost::mutex::scoped_lock sl(mSuppressionMutex); + + bool created; + findCreateEntry(index, created).addPeer(peer); + return created; +} + +bool SuppressionTable::addSuppressionFlags(const uint256& index, int flag) +{ + boost::mutex::scoped_lock sl(mSuppressionMutex); + + bool created; + findCreateEntry(index, created).setFlag(flag); + return created; } diff --git a/src/Suppression.h b/src/Suppression.h index 608a57d73..18abb3a98 100644 --- a/src/Suppression.h +++ b/src/Suppression.h @@ -1,14 +1,36 @@ #ifndef __SUPPRESSION__ #define __SUPPRESSION__ +#include +#include #include #include #include #include "uint256.h" +#include "types.h" +#include "InstanceCounter.h" -extern std::size_t hash_value(const uint160& u); +DEFINE_INSTANCE(Suppression); + +class Suppression : private IS_INSTANCE(Suppression) +{ +protected: + int mFlags; + std::set mPeers; + +public: + Suppression() : mFlags(0) { ; } + + const std::set& peekPeers() { return mPeers; } + void addPeer(uint64 peer) { mPeers.insert(peer); } + bool hasPeer(uint64 peer) { return mPeers.count(peer) > 0; } + + bool hasFlag(int f) { return (mFlags & f) != 0; } + void setFlag(int f) { mFlags |= f; } + void clearFlag(int f) { mFlags &= ~f; } +}; class SuppressionTable { @@ -17,18 +39,24 @@ protected: boost::mutex mSuppressionMutex; // Stores all suppressed hashes and their expiration time - boost::unordered_map mSuppressionMap; + boost::unordered_map mSuppressionMap; // Stores all expiration times and the hashes indexed for them - boost::unordered_map< time_t, std::list > mSuppressionTimes; + std::map< time_t, std::list > mSuppressionTimes; int mHoldTime; + Suppression& findCreateEntry(const uint256&, bool& created); + public: SuppressionTable(int holdTime = 120) : mHoldTime(holdTime) { ; } - bool addSuppression(const uint256& suppression); - bool addSuppression(const uint160& suppression); + bool addSuppression(const uint256& index); + + bool addSuppressionPeer(const uint256& index, uint64 peer); + bool addSuppressionFlags(const uint256& index, int flag); + + Suppression getEntry(const uint256&); }; #endif From 0830cf4ca8a94d36669526a654b8e8f7ee81495f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 19:25:05 -0700 Subject: [PATCH 17/22] Change count to 'SerializedValue' to better reflect what it is. --- src/SerializedTypes.cpp | 2 +- src/SerializedTypes.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 5fc0ebbe3..d147a3fdf 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -14,7 +14,7 @@ #include "TransactionErr.h" SETUP_LOG(); -DECLARE_INSTANCE(SerializedEntry); +DECLARE_INSTANCE(SerializedValue); STAmount saZero(CURRENCY_ONE, ACCOUNT_ONE, 0); STAmount saOne(CURRENCY_ONE, ACCOUNT_ONE, 1); diff --git a/src/SerializedTypes.h b/src/SerializedTypes.h index 6e1267448..4832b4621 100644 --- a/src/SerializedTypes.h +++ b/src/SerializedTypes.h @@ -30,9 +30,9 @@ enum PathFlags #define ACCOUNT_XNS uint160(0) #define ACCOUNT_ONE uint160(1) // Used as a place holder -DEFINE_INSTANCE(SerializedEntry); +DEFINE_INSTANCE(SerializedValue); -class SerializedType : private IS_INSTANCE(SerializedEntry) +class SerializedType : private IS_INSTANCE(SerializedValue) { protected: SField::ptr fName; From 41da9c740f253ecea6ce9695471f3364b19e805a Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 19:46:30 -0700 Subject: [PATCH 18/22] Support for 64-bit peer IDs. --- src/ConnectionPool.cpp | 27 ++++++++++++++++++++++++++- src/ConnectionPool.h | 9 ++++++++- src/Peer.cpp | 3 ++- src/Peer.h | 3 +++ 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/ConnectionPool.cpp b/src/ConnectionPool.cpp index a6e1a9924..79f0c82a8 100644 --- a/src/ConnectionPool.cpp +++ b/src/ConnectionPool.cpp @@ -29,6 +29,7 @@ void splitIpPort(const std::string& strIpPort, std::string& strIp, int& iPort) } ConnectionPool::ConnectionPool(boost::asio::io_service& io_service) : + mLastPeer(0), mCtx(boost::asio::ssl::context::sslv23), mScanTimer(io_service), mPolicyTimer(io_service) @@ -237,7 +238,7 @@ int ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& m BOOST_FOREACH(naPeer pair, mConnectedMap) { - Peer::pointer peer = pair.second; + Peer::ref peer = pair.second; if (!peer) std::cerr << "CP::RM null peer in list" << std::endl; else if ((!fromPeer || !(peer.get() == fromPeer)) && peer->isConnected()) @@ -250,6 +251,24 @@ int ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& m return sentTo; } +int ConnectionPool::relayMessage(const std::set& fromPeers, const PackedMessage::pointer& msg) +{ + int sentTo = 0; + boost::mutex::scoped_lock sl(mPeerLock); + + BOOST_FOREACH(naPeer pair, mConnectedMap) + { + Peer::ref peer = pair.second; + if (peer->isConnected() && (fromPeers.count(peer->getPeerId()) == 0)) + { + ++sentTo; + peer->sendPacket(msg); + } + } + + return sentTo; +} + // Schedule a connection via scanning. // // Add or modify into PeerIps as a manual entry for immediate scanning. @@ -354,6 +373,12 @@ std::vector ConnectionPool::getPeerVector() return ret; } +uint64 ConnectionPool::assignPeerId() +{ + boost::mutex::scoped_lock sl(mPeerLock); + return ++mLastPeer; +} + // Now know peer's node public key. Determine if we want to stay connected. // <-- bNew: false = redundant bool ConnectionPool::peerConnected(Peer::ref peer, const RippleAddress& naPeer, diff --git a/src/ConnectionPool.h b/src/ConnectionPool.h index 1b909f626..f230bd0ec 100644 --- a/src/ConnectionPool.h +++ b/src/ConnectionPool.h @@ -1,6 +1,8 @@ #ifndef __CONNECTION_POOL__ #define __CONNECTION_POOL__ +#include + #include #include @@ -14,7 +16,8 @@ class ConnectionPool { private: - boost::mutex mPeerLock; + boost::mutex mPeerLock; + uint64 mLastPeer; typedef std::pair naPeer; typedef std::pair pipPeer; @@ -59,6 +62,7 @@ public: // Send message to network. int relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg); + int relayMessage(const std::set& fromPeers, const PackedMessage::pointer& msg); // Manual connection request. // Queue for immediate scanning. @@ -87,6 +91,9 @@ public: Json::Value getPeersJson(); std::vector getPeerVector(); + // Peer 64-bit ID function + uint64 assignPeerId(); + // // Scanning // diff --git a/src/Peer.cpp b/src/Peer.cpp index 491991c23..3b8a10f88 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -30,7 +30,8 @@ Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx) mSocketSsl(io_service, ctx), mVerifyTimer(io_service) { - // cLog(lsDEBUG) << "CREATING PEER: " << ADDRESS(this); + cLog(lsDEBUG) << "CREATING PEER: " << ADDRESS(this); + mPeerId = theApp->getConnectionPool().assignPeerId(); } void Peer::handle_write(const boost::system::error_code& error, size_t bytes_transferred) diff --git a/src/Peer.h b/src/Peer.h index cc3a525c5..49857e3e6 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -46,6 +46,7 @@ private: ipPort mIpPort; ipPort mIpPortConnect; uint256 mCookieHash; + uint64 mPeerId; uint256 mClosedLedgerHash, mPreviousLedgerHash; std::list mRecentLedgers; @@ -162,6 +163,8 @@ public: uint256 getClosedLedgerHash() const { return mClosedLedgerHash; } bool hasLedger(const uint256& hash) const; bool hasTxSet(const uint256& hash) const; + uint64 getPeerId() const { return mPeerId; } + RippleAddress getNodePublic() const { return mNodePublic; } void cycleStatus() { mPreviousLedgerHash = mClosedLedgerHash; mClosedLedgerHash.zero(); } }; From 811eb8cf7c98050c34deccc431d94d6db7bd6030 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 31 Oct 2012 19:53:18 -0700 Subject: [PATCH 19/22] Fix STPathSet serialization for multiple paths. --- src/SerializedTypes.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/SerializedTypes.cpp b/src/SerializedTypes.cpp index 5fc0ebbe3..f72502e8d 100644 --- a/src/SerializedTypes.cpp +++ b/src/SerializedTypes.cpp @@ -540,7 +540,6 @@ void STPathSet::add(Serializer& s) const if (!bFirst) { s.add8(STPathElement::typeBoundary); - bFirst = false; } BOOST_FOREACH(const STPathElement& speElement, spPath) @@ -558,6 +557,8 @@ void STPathSet::add(Serializer& s) const if (iType & STPathElement::typeIssuer) s.add160(speElement.getIssuerID()); } + + bFirst = false; } s.add8(STPathElement::typeEnd); } From 127bceab5a9aa5b7295b134317e4c96fd0d5a495 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 31 Oct 2012 19:54:34 -0700 Subject: [PATCH 20/22] WS: Report back sterilization errors. --- src/NetworkOPs.cpp | 19 ++++++++++++++----- src/WSDoor.cpp | 6 ++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index dbeb8fd1d..088a717f2 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -88,17 +88,26 @@ Transaction::pointer NetworkOPs::submitTransaction(const Transaction::pointer& t tpTrans->getSTransaction()->add(s); Transaction::pointer tpTransNew = Transaction::sharedTransaction(s.getData(), true); - assert(tpTransNew); - if(!tpTransNew->getSTransaction()->isEquivalent(*tpTrans->getSTransaction())) + if (!tpTransNew) + { + // Could not construct transaction. + nothing(); + } + else if (tpTransNew->getSTransaction()->isEquivalent(*tpTrans->getSTransaction())) + { + (void) NetworkOPs::processTransaction(tpTransNew); + } + else { cLog(lsFATAL) << "Transaction reconstruction failure"; cLog(lsFATAL) << tpTransNew->getSTransaction()->getJson(0); cLog(lsFATAL) << tpTrans->getSTransaction()->getJson(0); - assert(false); - } - (void) NetworkOPs::processTransaction(tpTransNew); + assert(false); + + tpTransNew = Transaction::pointer(); + } return tpTransNew; } diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index 91b17e8aa..5d52859fb 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -1072,6 +1072,12 @@ void WSConnection::doSubmit(Json::Value& jvResult, const Json::Value& jvRequest) try { tpTrans = mNetwork.submitTransaction(tpTrans); + + if (!tpTrans) { + jvResult["error"] = "invalidTransaction"; + jvResult["error_exception"] = "Unable to sterilize transaction."; + return; + } } catch (std::exception& e) { From cc072b13c37bf089162ba4704c316315264cb35a Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 31 Oct 2012 20:04:59 -0700 Subject: [PATCH 21/22] JS: Improve error handling. --- js/amount.js | 8 +++++--- js/remote.js | 13 +++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/js/amount.js b/js/amount.js index b5c542288..10c9ffb39 100644 --- a/js/amount.js +++ b/js/amount.js @@ -136,8 +136,8 @@ UInt160.json_rewrite = function (j) { // Return a new UInt160 from j. UInt160.from_json = function (j) { return 'string' === typeof j - ? (new UInt160()).parse_json(j) - : j.clone(); + ? (new UInt160()).parse_json(j) + : j.clone(); }; UInt160.prototype.clone = function() { @@ -238,7 +238,9 @@ Currency.json_rewrite = function(j) { }; Currency.from_json = function (j) { - return (new Currency()).parse_json(j); + return 'string' === typeof j + ? (new Currency()).parse_json(j) + : j.clone(); }; Currency.prototype.clone = function() { diff --git a/js/remote.js b/js/remote.js index 1b0fe5a2d..9e0b4fedf 100644 --- a/js/remote.js +++ b/js/remote.js @@ -914,6 +914,17 @@ Transaction.prototype.submit = function () { var self = this; var transaction = this.transaction; + if ('string' !== typeof transaction.Account) + { + this.emit('error', { + 'error' : 'invalidAccount', + 'error_message' : 'Bad account.' + }); + return; + } + + // YYY Might check paths for invalid accounts. + if (undefined === transaction.Fee) { if ('Payment' === transaction.TransactionType && transaction.Flags & Remote.flags.Payment.CreateAccount) { @@ -989,8 +1000,10 @@ Transaction._path_rewrite = function (path) { if ('account' in node) node_new.account = UInt160.json_rewrite(node.account); + if ('issuer' in node) node_new.issuer = UInt160.json_rewrite(node.issuer); + if ('currency' in node) node_new.currency = Currency.json_rewrite(node.currency); From 40dc8e15c5ddeb486a736c7eeace8a635a8d9d43 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 31 Oct 2012 20:36:41 -0700 Subject: [PATCH 22/22] Begin using the new code. --- src/Application.h | 4 ++++ src/ConnectionPool.cpp | 22 +++++++++++++++------- src/ConnectionPool.h | 3 ++- src/Ledger.cpp | 2 +- src/LedgerConsensus.cpp | 2 +- src/NetworkOPs.cpp | 39 ++++++++++++++++++++------------------- src/NetworkOPs.h | 6 +++--- src/Peer.cpp | 12 ++++++++---- src/Suppression.cpp | 32 ++++++++++++++++++++++++++++++++ src/Suppression.h | 10 ++++++++++ 10 files changed, 96 insertions(+), 36 deletions(-) diff --git a/src/Application.h b/src/Application.h index 288f505bc..aeca10973 100644 --- a/src/Application.h +++ b/src/Application.h @@ -95,7 +95,11 @@ public: HashedObjectStore& getHashedObjectStore() { return mHashedObjectStore; } ValidationCollection& getValidations() { return mValidations; } JobQueue& getJobQueue() { return mJobQueue; } + SuppressionTable& getSuppression() { return mSuppressions; } + bool isNew(const uint256& s) { return mSuppressions.addSuppression(s); } + bool isNew(const uint256& s, uint64 p) { return mSuppressions.addSuppressionPeer(s, p); } + bool isNewFlag(const uint256& s, int f) { return mSuppressions.setFlag(s, f); } bool running() { return mTxnDB != NULL; } bool getSystemTimeOffset(int& offset) { return mSNTPClient.getOffset(offset); } diff --git a/src/ConnectionPool.cpp b/src/ConnectionPool.cpp index 79f0c82a8..f95c0a970 100644 --- a/src/ConnectionPool.cpp +++ b/src/ConnectionPool.cpp @@ -251,22 +251,30 @@ int ConnectionPool::relayMessage(Peer* fromPeer, const PackedMessage::pointer& m return sentTo; } -int ConnectionPool::relayMessage(const std::set& fromPeers, const PackedMessage::pointer& msg) -{ - int sentTo = 0; +void ConnectionPool::relayMessageBut(const std::set& fromPeers, const PackedMessage::pointer& msg) +{ // Relay message to all but the specified peers boost::mutex::scoped_lock sl(mPeerLock); BOOST_FOREACH(naPeer pair, mConnectedMap) { Peer::ref peer = pair.second; if (peer->isConnected() && (fromPeers.count(peer->getPeerId()) == 0)) - { - ++sentTo; peer->sendPacket(msg); - } } - return sentTo; +} + +void ConnectionPool::relayMessageTo(const std::set& fromPeers, const PackedMessage::pointer& msg) +{ // Relay message to the specified peers + boost::mutex::scoped_lock sl(mPeerLock); + + BOOST_FOREACH(naPeer pair, mConnectedMap) + { + Peer::ref peer = pair.second; + if (peer->isConnected() && (fromPeers.count(peer->getPeerId()) > 0)) + peer->sendPacket(msg); + } + } // Schedule a connection via scanning. diff --git a/src/ConnectionPool.h b/src/ConnectionPool.h index f230bd0ec..e3801ef73 100644 --- a/src/ConnectionPool.h +++ b/src/ConnectionPool.h @@ -62,7 +62,8 @@ public: // Send message to network. int relayMessage(Peer* fromPeer, const PackedMessage::pointer& msg); - int relayMessage(const std::set& fromPeers, const PackedMessage::pointer& msg); + void relayMessageTo(const std::set& fromPeers, const PackedMessage::pointer& msg); + void relayMessageBut(const std::set& fromPeers, const PackedMessage::pointer& msg); // Manual connection request. // Queue for immediate scanning. diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 69807417e..ec44a5dc9 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -1073,7 +1073,7 @@ int Ledger::getPendingSaves() void Ledger::pendSave(bool fromConsensus) { - if (!fromConsensus && !theApp->isNew(getHash())) + if (!fromConsensus && !theApp->isNewFlag(getHash(), SF_SAVED)) return; boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, shared_from_this(), fromConsensus)); diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index beeaaa400..9f55c2243 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -845,7 +845,7 @@ void LedgerConsensus::addDisputedTransaction(const uint256& txID, const std::vec txn->setVote(pit.first, cit->second->hasItem(txID)); } - if (!ourVote && theApp->isNew(txID)) + if (!ourVote && theApp->isNewFlag(txID, SF_RELAYED)) { ripple::TMTransaction msg; msg.set_rawtransaction(&(tx.front()), tx.size()); diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index dbeb8fd1d..f39faa6d8 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -103,7 +103,7 @@ Transaction::pointer NetworkOPs::submitTransaction(const Transaction::pointer& t return tpTransNew; } -Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, Peer* source) +Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans) { Transaction::pointer dbtx = theApp->getMasterTransaction().fetch(trans->getID(), true); if (dbtx) return dbtx; @@ -151,27 +151,28 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, trans->setStatus(INCLUDED); theApp->getMasterTransaction().canonicalize(trans, true); -// FIXME: Need code to get all accounts affected by a transaction and re-synch -// any of them that affect local accounts cached in memory. Or, we need to -// no cache the account balance information and always get it from the current ledger -// theApp->getWallet().applyTransaction(trans); + std::set peers; + if (theApp->getSuppression().swapSet(trans->getID(), peers, SF_RELAYED)) + { + ripple::TMTransaction tx; + Serializer s; + trans->getSTransaction()->add(s); + tx.set_rawtransaction(&s.getData().front(), s.getLength()); + tx.set_status(ripple::tsCURRENT); + tx.set_receivetimestamp(getNetworkTimeNC()); - ripple::TMTransaction tx; - Serializer s; - trans->getSTransaction()->add(s); - tx.set_rawtransaction(&s.getData().front(), s.getLength()); - tx.set_status(ripple::tsCURRENT); - tx.set_receivetimestamp(getNetworkTimeNC()); - - PackedMessage::pointer packet = boost::make_shared(tx, ripple::mtTRANSACTION); - int sentTo = theApp->getConnectionPool().relayMessage(source, packet); - cLog(lsINFO) << "Transaction relayed to " << sentTo << " node(s)"; + PackedMessage::pointer packet = boost::make_shared(tx, ripple::mtTRANSACTION); + theApp->getConnectionPool().relayMessageBut(peers, packet); + } return trans; } cLog(lsDEBUG) << "Status other than success " << r; - if ((mMode != omFULL) && (mMode != omTRACKING) && (theApp->isNew(trans->getID()))) + std::set peers; + + if ((mMode != omFULL) && (mMode != omTRACKING) && + theApp->getSuppression().swapSet(trans->getID(), peers, SF_RELAYED)) { ripple::TMTransaction tx; Serializer s; @@ -180,7 +181,7 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, tx.set_status(ripple::tsCURRENT); tx.set_receivetimestamp(getNetworkTimeNC()); PackedMessage::pointer packet = boost::make_shared(tx, ripple::mtTRANSACTION); - theApp->getConnectionPool().relayMessage(source, packet); + theApp->getConnectionPool().relayMessageTo(peers, packet); } trans->setStatus(INVALID); @@ -685,7 +686,7 @@ bool NetworkOPs::haveConsensusObject() } // <-- bool: true to relay -bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger, +bool NetworkOPs::recvPropose(uint64 peerId, uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger, uint32 closeTime, const std::string& pubKey, const std::string& signature, const RippleAddress& nodePublic) { // JED: does mConsensus need to be locked? @@ -701,7 +702,7 @@ bool NetworkOPs::recvPropose(uint32 proposeSeq, const uint256& proposeHash, cons s.add32(closeTime); s.addRaw(pubKey); s.addRaw(signature); - if (!theApp->isNew(s.getSHA512Half())) + if (!theApp->isNew(s.getSHA512Half(), peerId)) return false; RippleAddress naPeerPublic = RippleAddress::createNodePublic(strCopy(pubKey)); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 5c54c3a16..e2d476c43 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -121,7 +121,7 @@ public: // Transaction::pointer submitTransaction(const Transaction::pointer& tpTrans); - Transaction::pointer processTransaction(Transaction::pointer transaction, Peer* source = NULL); + Transaction::pointer processTransaction(Transaction::pointer transaction); Transaction::pointer findTransactionByID(const uint256& transactionID); int findTransactionsBySource(const uint256& uLedger, std::list&, const RippleAddress& sourceAccount, uint32 minSeq, uint32 maxSeq); @@ -168,8 +168,8 @@ public: const std::vector& myNode, std::list< std::vector >& newNodes); // ledger proposal/close functions - bool recvPropose(uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger, uint32 closeTime, - const std::string& pubKey, const std::string& signature, const RippleAddress& nodePublic); + bool recvPropose(uint64 peerId, uint32 proposeSeq, const uint256& proposeHash, const uint256& prevLedger, + uint32 closeTime, const std::string& pubKey, const std::string& signature, const RippleAddress& nodePublic); bool gotTXData(const boost::shared_ptr& peer, const uint256& hash, const std::list& nodeIDs, const std::list< std::vector >& nodeData); bool recvValidation(const SerializedValidation::pointer& val); diff --git a/src/Peer.cpp b/src/Peer.cpp index 3b8a10f88..d441876dc 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -708,8 +708,12 @@ void Peer::recvTransaction(ripple::TMTransaction& packet) SerializerIterator sit(s); SerializedTransaction::pointer stx = boost::make_shared(boost::ref(sit)); + if (!theApp->isNew(stx->getTransactionID(), mPeerId)) + return; + tx = boost::make_shared(stx, true); - if (tx->getStatus() == INVALID) throw(0); + if (tx->getStatus() == INVALID) + throw(0); #ifndef TRUST_NETWORK } catch (...) @@ -723,7 +727,7 @@ void Peer::recvTransaction(ripple::TMTransaction& packet) } #endif - tx = theApp->getOPs().processTransaction(tx, this); + tx = theApp->getOPs().processTransaction(tx); if(tx->getStatus() != INCLUDED) { // transaction wasn't accepted into ledger @@ -748,7 +752,7 @@ void Peer::recvPropose(ripple::TMProposeSet& packet) if ((packet.has_previousledger()) && (packet.previousledger().size() == 32)) memcpy(prevLedger.begin(), packet.previousledger().data(), 32); - if(theApp->getOPs().recvPropose(packet.proposeseq(), currentTxHash, prevLedger, packet.closetime(), + if(theApp->getOPs().recvPropose(mPeerId, packet.proposeseq(), currentTxHash, prevLedger, packet.closetime(), packet.nodepubkey(), packet.signature(), mNodePublic)) { // FIXME: Not all nodes will want proposals PackedMessage::pointer message = boost::make_shared(packet, ripple::mtPROPOSE_LEDGER); @@ -822,7 +826,7 @@ void Peer::recvValidation(const boost::shared_ptr& packet) SerializedValidation::pointer val = boost::make_shared(boost::ref(sit), false); uint256 signingHash = val->getSigningHash(); - if (!theApp->isNew(signingHash)) + if (!theApp->isNew(signingHash, mPeerId)) { cLog(lsTRACE) << "Validation is duplicate"; return; diff --git a/src/Suppression.cpp b/src/Suppression.cpp index 2576a2aed..ad96d4b15 100644 --- a/src/Suppression.cpp +++ b/src/Suppression.cpp @@ -66,3 +66,35 @@ bool SuppressionTable::addSuppressionFlags(const uint256& index, int flag) findCreateEntry(index, created).setFlag(flag); return created; } + +bool SuppressionTable::setFlag(const uint256& index, int flag) +{ // return: true = changed, false = unchanged + assert(flag != 0); + + boost::mutex::scoped_lock sl(mSuppressionMutex); + + bool created; + Suppression &s = findCreateEntry(index, created); + + if ((s.getFlags() & flag) == flag) + return false; + + s.setFlag(flag); + return true; +} + +bool SuppressionTable::swapSet(const uint256& index, std::set& peers, int flag) +{ + boost::mutex::scoped_lock sl(mSuppressionMutex); + + bool created; + Suppression &s = findCreateEntry(index, created); + + if ((s.getFlags() & flag) == flag) + return false; + + s.swapSet(peers); + s.setFlag(flag); + + return true; +} \ No newline at end of file diff --git a/src/Suppression.h b/src/Suppression.h index 18abb3a98..14b611ede 100644 --- a/src/Suppression.h +++ b/src/Suppression.h @@ -14,6 +14,11 @@ DEFINE_INSTANCE(Suppression); +#define SF_RELAYED 0x01 +#define SF_SIGBAD 0x02 +#define SF_SIGGOOD 0x04 +#define SF_SAVED 0x08 + class Suppression : private IS_INSTANCE(Suppression) { protected: @@ -27,9 +32,11 @@ public: void addPeer(uint64 peer) { mPeers.insert(peer); } bool hasPeer(uint64 peer) { return mPeers.count(peer) > 0; } + int getFlags(void) { return mFlags; } bool hasFlag(int f) { return (mFlags & f) != 0; } void setFlag(int f) { mFlags |= f; } void clearFlag(int f) { mFlags &= ~f; } + void swapSet(std::set& s) { mPeers.swap(s); } }; class SuppressionTable @@ -55,8 +62,11 @@ public: bool addSuppressionPeer(const uint256& index, uint64 peer); bool addSuppressionFlags(const uint256& index, int flag); + bool setFlag(const uint256& index, int flag); Suppression getEntry(const uint256&); + + bool swapSet(const uint256& index, std::set& peers, int flag); }; #endif