From c08d0535bdb1190f68d5f85526bd49962b402832 Mon Sep 17 00:00:00 2001 From: jed Date: Sat, 26 Jan 2013 13:17:27 -0800 Subject: [PATCH 1/6] windows --- ripple2010.vcxproj | 11 +++++++---- ripple2010.vcxproj.filters | 23 +++++++++++++++-------- rippled-example.cfg | 2 -- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/ripple2010.vcxproj b/ripple2010.vcxproj index ed3106e81..ff66f7150 100644 --- a/ripple2010.vcxproj +++ b/ripple2010.vcxproj @@ -93,6 +93,7 @@ + @@ -106,6 +107,7 @@ + @@ -122,11 +124,13 @@ + + @@ -147,7 +151,6 @@ - @@ -180,7 +183,6 @@ - @@ -291,8 +293,9 @@ Designer - + + Document @@ -303,7 +306,7 @@ - + diff --git a/ripple2010.vcxproj.filters b/ripple2010.vcxproj.filters index 0f3ccb451..ae54851c7 100644 --- a/ripple2010.vcxproj.filters +++ b/ripple2010.vcxproj.filters @@ -189,9 +189,6 @@ Source Files - - Source Files - Source Files @@ -276,9 +273,6 @@ Source Files - - Source Files - Source Files @@ -351,6 +345,18 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -636,13 +642,14 @@ html - - + + + diff --git a/rippled-example.cfg b/rippled-example.cfg index 10aaf08db..6ca428b2f 100644 --- a/rippled-example.cfg +++ b/rippled-example.cfg @@ -161,8 +161,6 @@ time.apple.com time.nist.gov pool.ntp.org -[validation_seed] -shh1D4oj5czH3PUEjYES8c7Bay3tE [unl_default] validators.txt From a55b876477f2e892a02f86f61c7176da61f19e51 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 7 Mar 2013 14:57:08 -0800 Subject: [PATCH 2/6] Fix uptiming computing bug. --- src/cpp/ripple/RPCHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 412853584..3687fca00 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -2020,7 +2020,7 @@ Json::Value RPCHandler::doGetCounts(Json::Value jvRequest) int s = upTime(); textTime(uptime, s, "year", 365*24*60*60); textTime(uptime, s, "day", 24*60*60); - textTime(uptime, s, "hour", 24*60); + textTime(uptime, s, "hour", 60*60); textTime(uptime, s, "minute", 60); textTime(uptime, s, "second", 1); ret["uptime"] = uptime; From 7c3d732a0864b16f18db8bee7bb6576ad4fae6d5 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 7 Mar 2013 18:07:34 -0800 Subject: [PATCH 3/6] Name load source. Hook up load sources through WSConnection->RPCHandler. --- src/cpp/ripple/Application.cpp | 2 +- src/cpp/ripple/Application.h | 2 -- src/cpp/ripple/LoadManager.h | 18 ++++++++++++------ src/cpp/ripple/Peer.cpp | 3 +++ src/cpp/ripple/RPCHandler.cpp | 5 +++-- src/cpp/ripple/RPCHandler.h | 5 +++-- src/cpp/ripple/RPCServer.cpp | 8 ++++---- src/cpp/ripple/RPCServer.h | 4 +++- src/cpp/ripple/WSConnection.h | 9 ++++++--- src/cpp/ripple/main.cpp | 3 ++- 10 files changed, 37 insertions(+), 22 deletions(-) diff --git a/src/cpp/ripple/Application.cpp b/src/cpp/ripple/Application.cpp index cc417257c..9cbbdc766 100644 --- a/src/cpp/ripple/Application.cpp +++ b/src/cpp/ripple/Application.cpp @@ -45,7 +45,7 @@ DatabaseCon::~DatabaseCon() Application::Application() : mIOWork(mIOService), mAuxWork(mAuxService), mUNL(mIOService), mNetOps(mIOService, &mLedgerMaster), mTempNodeCache("NodeCache", 16384, 90), mHashedObjectStore(16384, 300), mSLECache("LedgerEntryCache", 4096, 120), - mSNTPClient(mAuxService), mRPCHandler(&mNetOps), mFeeTrack(), + mSNTPClient(mAuxService), mFeeTrack(), mRpcDB(NULL), mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL), mWSPublicDoor(NULL), mWSPrivateDoor(NULL), mSweepTimer(mAuxService), mShutdown(false) diff --git a/src/cpp/ripple/Application.h b/src/cpp/ripple/Application.h index cafa5b7c7..48e58d97a 100644 --- a/src/cpp/ripple/Application.h +++ b/src/cpp/ripple/Application.h @@ -64,7 +64,6 @@ class Application SLECache mSLECache; SNTPClient mSNTPClient; JobQueue mJobQueue; - RPCHandler mRPCHandler; ProofOfWorkGenerator mPOWGen; LoadManager mLoadMgr; LoadFeeTrack mFeeTrack; @@ -114,7 +113,6 @@ public: ValidationCollection& getValidations() { return mValidations; } JobQueue& getJobQueue() { return mJobQueue; } SuppressionTable& getSuppression() { return mSuppressions; } - RPCHandler& getRPCHandler() { return mRPCHandler; } boost::recursive_mutex& getMasterLock() { return mMasterLock; } ProofOfWorkGenerator& getPowGen() { return mPOWGen; } LoadManager& getLoadManager() { return mLoadMgr; } diff --git a/src/cpp/ripple/LoadManager.h b/src/cpp/ripple/LoadManager.h index 55796ea02..8899bf575 100644 --- a/src/cpp/ripple/LoadManager.h +++ b/src/cpp/ripple/LoadManager.h @@ -61,14 +61,20 @@ public: static const int lsfOutbound = 2; // outbound connection protected: - int mBalance; - int mFlags; - int mLastUpdate; - int mLastWarning; + std::string mName; + int mBalance; + int mFlags; + int mLastUpdate; + int mLastWarning; public: - LoadSource() : mBalance(0), mFlags(0), mLastWarning(0) - { mLastUpdate = upTime(); } + LoadSource(bool admin) : mBalance(0), mFlags(admin ? lsfPrivileged : 0), mLastUpdate(upTime()), mLastWarning(0) + { ; } + LoadSource(const std::string& name) : mName(name), mBalance(0), mFlags(0), mLastUpdate(upTime()), mLastWarning(0) + { ; } + + void rename(const std::string& name) + { mName = name; } bool isPrivileged() const { return (mFlags & lsfPrivileged) != 0; } void setPrivileged() { mFlags |= lsfPrivileged; } diff --git a/src/cpp/ripple/Peer.cpp b/src/cpp/ripple/Peer.cpp index 62bc160cf..991afb52d 100644 --- a/src/cpp/ripple/Peer.cpp +++ b/src/cpp/ripple/Peer.cpp @@ -34,6 +34,8 @@ Peer::Peer(boost::asio::io_service& io_service, boost::asio::ssl::context& ctx, mActive(2), mCluster(false), mPeerId(peerID), + mPrivate(false), + mLoad(""), mSocketSsl(io_service, ctx), mActivityTimer(io_service) { @@ -77,6 +79,7 @@ void Peer::handleWrite(const boost::system::error_code& error, size_t bytes_tran void Peer::setIpPort(const std::string& strIP, int iPort) { mIpPort = make_pair(strIP, iPort); + mLoad.rename(strIP); cLog(lsDEBUG) << "Peer: Set: " << ADDRESS(this) << "> " diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 9c8eb6c47..67ebec782 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -63,12 +63,13 @@ int iAdminGet(const Json::Value& jvRequest, const std::string& strRemoteIp) return iRole; } -RPCHandler::RPCHandler(NetworkOPs* netOps) +RPCHandler::RPCHandler(NetworkOPs* netOps, LoadSource &ls) : mLoadSource(ls) { mNetOps = netOps; } -RPCHandler::RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub) : mInfoSub(infoSub) +RPCHandler::RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub, LoadSource& ls) + : mInfoSub(infoSub), mLoadSource(ls) { mNetOps = netOps; } diff --git a/src/cpp/ripple/RPCHandler.h b/src/cpp/ripple/RPCHandler.h index 48fe696ce..9c8c3e288 100644 --- a/src/cpp/ripple/RPCHandler.h +++ b/src/cpp/ripple/RPCHandler.h @@ -18,6 +18,7 @@ class RPCHandler NetworkOPs* mNetOps; InfoSub::pointer mInfoSub; int mRole; + LoadSource& mLoadSource; typedef Json::Value (RPCHandler::*doFuncPtr)(Json::Value params); enum { @@ -113,8 +114,8 @@ public: enum { GUEST, USER, ADMIN, FORBID }; - RPCHandler(NetworkOPs* netOps); - RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub); + RPCHandler(NetworkOPs* netOps, LoadSource&); + RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub, LoadSource&); Json::Value doCommand(const Json::Value& jvRequest, int role); Json::Value doRpcCommand(const std::string& strCommand, Json::Value& jvParams, int iRole); diff --git a/src/cpp/ripple/RPCServer.cpp b/src/cpp/ripple/RPCServer.cpp index cd7474261..33185c3b7 100644 --- a/src/cpp/ripple/RPCServer.cpp +++ b/src/cpp/ripple/RPCServer.cpp @@ -24,7 +24,7 @@ SETUP_LOG(); #endif RPCServer::RPCServer(boost::asio::io_service& io_service , NetworkOPs* nopNetwork) - : mNetOps(nopNetwork), mSocket(io_service) + : mNetOps(nopNetwork), mLoadSource("rpc"), mSocket(io_service) { mRole = RPCHandler::GUEST; } @@ -51,7 +51,7 @@ void RPCServer::handle_read_req(const boost::system::error_code& e) if (!HTTPAuthorized(mHTTPRequest.peekHeaders())) mReplyStr = HTTPReply(403, "Forbidden"); else - mReplyStr = handleRequest(req); + mReplyStr = handleRequest(req, mLoadSource); boost::asio::async_write(mSocket, boost::asio::buffer(mReplyStr), boost::bind(&RPCServer::handle_write, shared_from_this(), boost::asio::placeholders::error)); @@ -110,7 +110,7 @@ void RPCServer::handle_read_line(const boost::system::error_code& e) } } -std::string RPCServer::handleRequest(const std::string& requestStr) +std::string RPCServer::handleRequest(const std::string& requestStr, LoadSource& ls) { cLog(lsTRACE) << "handleRequest " << requestStr; @@ -154,7 +154,7 @@ std::string RPCServer::handleRequest(const std::string& requestStr) return HTTPReply(403, "Forbidden"); } - RPCHandler mRPCHandler(mNetOps); + RPCHandler mRPCHandler(mNetOps, mLoadSource); cLog(lsTRACE) << valParams; Json::Value result = mRPCHandler.doRpcCommand(strMethod, valParams, mRole); diff --git a/src/cpp/ripple/RPCServer.h b/src/cpp/ripple/RPCServer.h index c96774354..bfc6a4c0e 100644 --- a/src/cpp/ripple/RPCServer.h +++ b/src/cpp/ripple/RPCServer.h @@ -13,6 +13,7 @@ #include "NetworkOPs.h" #include "SerializedLedger.h" #include "RPCHandler.h" +#include "LoadManager.h" class RPCServer : public boost::enable_shared_from_this { @@ -23,6 +24,7 @@ public: private: NetworkOPs* mNetOps; + LoadSource mLoadSource; boost::asio::ip::tcp::socket mSocket; @@ -44,7 +46,7 @@ private: void handle_read_line(const boost::system::error_code& ec); void handle_read_req(const boost::system::error_code& ec); - std::string handleRequest(const std::string& requestStr); + std::string handleRequest(const std::string& requestStr, LoadSource& ls); public: static pointer create(boost::asio::io_service& io_service, NetworkOPs* mNetOps) diff --git a/src/cpp/ripple/WSConnection.h b/src/cpp/ripple/WSConnection.h index 399c6a827..7ce02fba4 100644 --- a/src/cpp/ripple/WSConnection.h +++ b/src/cpp/ripple/WSConnection.h @@ -14,6 +14,7 @@ #include "CallRPC.h" #include "InstanceCounter.h" #include "Log.h" +#include "LoadManager.h" #include "RPCErr.h" DEFINE_INSTANCE(WebSocketConnection); @@ -45,6 +46,7 @@ protected: weak_connection_ptr mConnection; NetworkOPs& mNetwork; std::string mRemoteIP; + LoadSource mLoadSource; boost::asio::deadline_timer mPingTimer; bool mPinged; @@ -56,9 +58,9 @@ public: WSConnection(WSServerHandler* wshpHandler, const connection_ptr& cpConnection) : mHandler(wshpHandler), mConnection(cpConnection), mNetwork(theApp->getOPs()), - mPingTimer(cpConnection->get_io_service()), mPinged(false) + mRemoteIP(cpConnection->get_socket().lowest_layer().remote_endpoint().address().to_string()), + mLoadSource(mRemoteIP), mPingTimer(cpConnection->get_io_service()), mPinged(false) { - mRemoteIP = cpConnection->get_socket().lowest_layer().remote_endpoint().address().to_string(); cLog(lsDEBUG) << "Websocket connection from " << mRemoteIP; setPingTimer(); } @@ -103,7 +105,8 @@ public: return jvResult; } - RPCHandler mRPCHandler(&mNetwork, boost::shared_polymorphic_downcast(this->shared_from_this())); + RPCHandler mRPCHandler(&mNetwork, + boost::shared_polymorphic_downcast(this->shared_from_this()), mLoadSource); Json::Value jvResult(Json::objectValue); int iRole = mHandler->getPublic() diff --git a/src/cpp/ripple/main.cpp b/src/cpp/ripple/main.cpp index 88dc35a33..1c114aa07 100644 --- a/src/cpp/ripple/main.cpp +++ b/src/cpp/ripple/main.cpp @@ -43,7 +43,8 @@ void startServer() if (!theConfig.QUIET) std::cerr << "Startup RPC: " << jvCommand << std::endl; - RPCHandler rhHandler(&theApp->getOPs()); + LoadSource ls(true); + RPCHandler rhHandler(&theApp->getOPs(), ls); Json::Value jvResult = rhHandler.doCommand(jvCommand, RPCHandler::ADMIN); From 2fab33d5d73dacba7c220b0270f9a643942d97bc Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 7 Mar 2013 18:10:38 -0800 Subject: [PATCH 4/6] Test was always true. --- src/cpp/ripple/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cpp/ripple/Application.cpp b/src/cpp/ripple/Application.cpp index 9cbbdc766..f0c360265 100644 --- a/src/cpp/ripple/Application.cpp +++ b/src/cpp/ripple/Application.cpp @@ -26,9 +26,9 @@ Application* theApp = NULL; DatabaseCon::DatabaseCon(const std::string& strName, const char *initStrings[], int initCount) { - boost::filesystem::path pPath = theConfig.RUN_STANDALONE && !Config::LOAD + boost::filesystem::path pPath = (theConfig.RUN_STANDALONE && (!theConfig.START_UP != Config::LOAD)) ? "" // Use temporary files. - : theConfig.DATA_DIR / strName; // Use regular db files. + : (theConfig.DATA_DIR / strName); // Use regular db files. mDatabase = new SqliteDatabase(pPath.string().c_str()); mDatabase->connect(); From 2b2e93eef6ed63a30a28915a470cc6bc578aa71f Mon Sep 17 00:00:00 2001 From: jed Date: Thu, 7 Mar 2013 23:19:22 -0800 Subject: [PATCH 5/6] stray EOF and spelling --- src/cpp/ripple/RippleCalc.cpp | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/cpp/ripple/RippleCalc.cpp b/src/cpp/ripple/RippleCalc.cpp index 7fe6d8b4b..e518739dd 100644 --- a/src/cpp/ripple/RippleCalc.cpp +++ b/src/cpp/ripple/RippleCalc.cpp @@ -1,7 +1,7 @@ // TODO: // - Do automatic bridging via XRP. // -// OPTIMIZE: When calculating path increment, note if increment consumes all liquidity. No need to revesit path in the future if +// OPTIMIZE: When calculating path increment, note if increment consumes all liquidity. No need to revisit path in the future if // all liquidity is used. // @@ -270,7 +270,7 @@ TER PathState::pushNode( // Insert intermediary issuer account if needed. terResult = pushImply( - ACCOUNT_XRP, // Rippling, but offer's don't have an account. + ACCOUNT_XRP, // Rippling, but offers don't have an account. pnPrv.uCurrencyID, pnPrv.uIssuerID); } @@ -384,7 +384,7 @@ void PathState::setExpanded( if (tesSUCCESS == terStatus && !!uOutCurrencyID // Next is not XRP - && uOutIssuerID != uReceiverID // Out issuer is not reciever + && uOutIssuerID != uReceiverID // Out issuer is not receiver && (pnPrv.uCurrencyID != uOutCurrencyID // Previous will be an offer. || pnPrv.uAccountID != uOutIssuerID)) // Need the implied issuer. { @@ -491,7 +491,7 @@ void PathState::setCanonical( uint160 uCurrencyID = uMaxCurrencyID; uint160 uIssuerID = uMaxIssuerID; - // Node 0 is a composit of the sending account and saInAct. + // Node 0 is a composite of the sending account and saInAct. ++uNode; // skip node 0 // Last node is implied: Always skip last node @@ -531,8 +531,7 @@ void PathState::setCanonical( } else { - // Node 1 must be an account - + // Node 1 must be an account } } else @@ -2939,7 +2938,7 @@ void TransactionEngine::calcOfferBridgeNext( { // Offer fully funded. - // Account transfering funds in to offer always pays inbound fees. + // Account transferring funds in to offer always pays inbound fees. saOfferIn = saOfferGets; // XXX Add in fees? @@ -2978,26 +2977,26 @@ void TransactionEngine::calcOfferBridgeNext( // - reverse: prv is maximum to pay in (including fee) - cur is what is wanted: generally, minimizing prv // - forward: prv is actual amount to pay in (including fee) - cur is what is wanted: generally, minimizing cur // Value in is may be rippled or credited from limbo. Value out is put in limbo. -// If next is an offer, the amount needed is in cur reedem. +// If next is an offer, the amount needed is in cur redeem. // XXX What about account mentioned multiple times via offers? void TransactionEngine::calcNodeOffer( bool bForward, bool bMultiQuality, // True, if this is the only active path: we can do multiple qualities in this pass. - const uint160& uPrvAccountID, // If 0, then funds from previous offer's limbo + const uint160& uPrvAccountID, // If 0, then funds from previous offers limbo const uint160& uPrvCurrencyID, const uint160& uPrvIssuerID, const uint160& uCurCurrencyID, const uint160& uCurIssuerID, const STAmount& uPrvRedeemReq, // --> In limit. - STAmount& uPrvRedeemAct, // <-> In limit achived. + STAmount& uPrvRedeemAct, // <-> In limit achieved. const STAmount& uCurRedeemReq, // --> Out limit. Driver when uCurIssuerID == uNxtIssuerID (offer would redeem to next) - STAmount& uCurRedeemAct, // <-> Out limit achived. + STAmount& uCurRedeemAct, // <-> Out limit achieved. const STAmount& uCurIssueReq, // --> In limit. - STAmount& uCurIssueAct, // <-> In limit achived. + STAmount& uCurIssueAct, // <-> In limit achieved. const STAmount& uCurIssueReq, // --> Out limit. Driver when uCurIssueReq != uNxtIssuerID (offer would effectively issue or transfer to next) - STAmount& uCurIssueAct, // <-> Out limit achived. + STAmount& uCurIssueAct, // <-> Out limit achieved. STAmount& saPay, STAmount& saGot @@ -3051,13 +3050,13 @@ void TransactionEngine::calcNodeOffer( bool bRedeeming = false; bool bIssuing = false; - // The price varies as we change between issuing and transfering, so unless bMultiQuality, we must stick with a mode once it + // The price varies as we change between issuing and transferring, so unless bMultiQuality, we must stick with a mode once it // is determined. if (bBridge && (bInNext || bOutNext)) { // Bridging and need to calculate next bridge rate. - // A bridge can consist of multiple offers. As offer's are consumed, the effective rate changes. + // A bridge can consist of multiple offers. As offers are consumed, the effective rate changes. if (bInNext) { From 7621feda7b51c2c585cb302723f71c9666de15ff Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Fri, 8 Mar 2013 09:48:54 -0800 Subject: [PATCH 6/6] Updates to load monitoring and source load tracking. --- src/cpp/database/SqliteDatabase.cpp | 4 + src/cpp/ripple/LoadManager.cpp | 55 ++++++++---- src/cpp/ripple/LoadManager.h | 9 +- src/cpp/ripple/RPCHandler.cpp | 132 +++++++++++++++------------- src/cpp/ripple/RPCHandler.h | 123 +++++++++++++------------- src/cpp/ripple/RPCServer.cpp | 11 +-- src/cpp/ripple/RPCServer.h | 3 +- src/cpp/ripple/WSConnection.h | 18 +++- src/cpp/ripple/main.cpp | 6 +- 9 files changed, 203 insertions(+), 158 deletions(-) diff --git a/src/cpp/database/SqliteDatabase.cpp b/src/cpp/database/SqliteDatabase.cpp index 1033dcf4e..7db0a623f 100644 --- a/src/cpp/database/SqliteDatabase.cpp +++ b/src/cpp/database/SqliteDatabase.cpp @@ -234,6 +234,7 @@ void SqliteDatabase::runWal() std::set walSet; std::string name = sqlite3_db_filename(mConnection, "main"); + int pass = 1; while (1) { { @@ -255,8 +256,11 @@ void SqliteDatabase::runWal() cLog((ret == SQLITE_LOCKED) ? lsTRACE : lsWARNING) << "WAL " << mHost << ":" << db << " error " << ret; } + else + cLog(lsTRACE) << "WAL(" << mHost << "): pass=" << pass << ", frames=" << log << ", written=" << ckpt; } walSet.clear(); + ++pass; } } diff --git a/src/cpp/ripple/LoadManager.cpp b/src/cpp/ripple/LoadManager.cpp index 87b2237a4..1eaad6c6b 100644 --- a/src/cpp/ripple/LoadManager.cpp +++ b/src/cpp/ripple/LoadManager.cpp @@ -132,24 +132,31 @@ void LoadManager::canonicalize(LoadSource& source, int now) const bool LoadManager::shouldWarn(LoadSource& source) const { - boost::mutex::scoped_lock sl(mLock); + { + boost::mutex::scoped_lock sl(mLock); - int now = upTime(); - canonicalize(source, now); - if (source.isPrivileged() || (source.mBalance < mDebitWarn) || (source.mLastWarning == now)) - return false; + int now = upTime(); + canonicalize(source, now); + if (source.isPrivileged() || (source.mBalance < mDebitWarn) || (source.mLastWarning == now)) + return false; - source.mLastWarning = now; + source.mLastWarning = now; + } + logWarning(source.getName()); return true; } bool LoadManager::shouldCutoff(LoadSource& source) const { - boost::mutex::scoped_lock sl(mLock); - - int now = upTime(); - canonicalize(source, now); - return !source.isPrivileged() && (source.mBalance < mDebitLimit); + { + boost::mutex::scoped_lock sl(mLock); + int now = upTime(); + canonicalize(source, now); + if (!source.isPrivileged() || (source.mBalance > mDebitLimit)) + return false; + } + logDisconnect(source.getName()); + return true; } bool LoadManager::adjust(LoadSource& source, LoadType t) const @@ -160,7 +167,6 @@ bool LoadManager::adjust(LoadSource& source, LoadType t) const bool LoadManager::adjust(LoadSource& source, int credits) const { // return: true = need to warn/cutoff - boost::mutex::scoped_lock sl(mLock); // We do it this way in case we want to add exponential decay later int now = upTime(); @@ -172,13 +178,10 @@ bool LoadManager::adjust(LoadSource& source, int credits) const if (source.isPrivileged()) // privileged sources never warn/cutoff return false; - if (source.mBalance < mDebitLimit) // over-limit - return true; + if ((source.mBalance >= mDebitLimit) && (source.mLastWarning == now)) // no need to warn + return false; - if ((source.mBalance < mDebitWarn) && (source.mLastWarning != now)) // need to warn - return true; - - return false; + return true; } uint64 LoadFeeTrack::mulDiv(uint64 value, uint32 mul, uint64 div) @@ -345,6 +348,22 @@ void LoadManager::threadEntry() } } +void LoadManager::logWarning(const std::string& source) const +{ + if (source.empty()) + cLog(lsDEBUG) << "Load warning from empty source"; + else + cLog(lsINFO) << "Load warning: " << source; +} + +void LoadManager::logDisconnect(const std::string& source) const +{ + if (source.empty()) + cLog(lsINFO) << "Disconnect for empty source"; + else + cLog(lsWARNING) << "Disconnect for: " << source; +} + BOOST_AUTO_TEST_SUITE(LoadManager_test) BOOST_AUTO_TEST_CASE(LoadFeeTrack_test) diff --git a/src/cpp/ripple/LoadManager.h b/src/cpp/ripple/LoadManager.h index 8899bf575..070384d70 100644 --- a/src/cpp/ripple/LoadManager.h +++ b/src/cpp/ripple/LoadManager.h @@ -73,8 +73,8 @@ public: LoadSource(const std::string& name) : mName(name), mBalance(0), mFlags(0), mLastUpdate(upTime()), mLastWarning(0) { ; } - void rename(const std::string& name) - { mName = name; } + void rename(const std::string& name) { mName = name; } + const std::string& getName() { return mName; } bool isPrivileged() const { return (mFlags & lsfPrivileged) != 0; } void setPrivileged() { mFlags |= lsfPrivileged; } @@ -112,7 +112,7 @@ protected: public: - LoadManager(int creditRate = 10, int creditLimit = 50, int debitWarn = -50, int debitLimit = -100); + LoadManager(int creditRate = 100, int creditLimit = 500, int debitWarn = -500, int debitLimit = -1000); ~LoadManager(); void init(); @@ -130,6 +130,9 @@ public: bool adjust(LoadSource&, int credits) const; // return value: false=balance okay, true=warn/cutoff bool adjust(LoadSource&, LoadType l) const; + void logWarning(const std::string&) const; + void logDisconnect(const std::string&) const; + int getCost(LoadType t) { return mCosts[static_cast(t)].mCost; } int getUptime(); }; diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 67ebec782..76d135017 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -25,6 +25,10 @@ SETUP_LOG(); +static const int rpcCOST_DEFAULT = 10; +static const int rpcCOST_EXCEPTION = 20; +static const int rpcCOST_EXPENSIVE = 50; + int iAdminGet(const Json::Value& jvRequest, const std::string& strRemoteIp) { int iRole; @@ -63,16 +67,11 @@ int iAdminGet(const Json::Value& jvRequest, const std::string& strRemoteIp) return iRole; } -RPCHandler::RPCHandler(NetworkOPs* netOps, LoadSource &ls) : mLoadSource(ls) -{ - mNetOps = netOps; -} +RPCHandler::RPCHandler(NetworkOPs* netOps) : mNetOps(netOps) +{ ; } -RPCHandler::RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub, LoadSource& ls) - : mInfoSub(infoSub), mLoadSource(ls) -{ - mNetOps = netOps; -} +RPCHandler::RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub) : mNetOps(netOps), mInfoSub(infoSub) +{ ; } Json::Value RPCHandler::transactionSign(Json::Value jvRequest, bool bSubmit) { @@ -566,7 +565,7 @@ Json::Value RPCHandler::accountFromString(Ledger::ref lrLedger, RippleAddress& n // ledger_hash : // ledger_index : // } -Json::Value RPCHandler::doAccountInfo(Json::Value jvRequest) +Json::Value RPCHandler::doAccountInfo(Json::Value jvRequest, int& cost) { Ledger::pointer lpLedger; Json::Value jvResult = lookupLedger(jvRequest, lpLedger); @@ -611,7 +610,7 @@ Json::Value RPCHandler::doAccountInfo(Json::Value jvRequest) // port: // } // XXX Might allow domain for manual connections. -Json::Value RPCHandler::doConnect(Json::Value jvRequest) +Json::Value RPCHandler::doConnect(Json::Value jvRequest, int& cost) { if (theConfig.RUN_STANDALONE) return "cannot connect in standalone mode"; @@ -632,7 +631,7 @@ Json::Value RPCHandler::doConnect(Json::Value jvRequest) // { // key: // } -Json::Value RPCHandler::doDataDelete(Json::Value jvRequest) +Json::Value RPCHandler::doDataDelete(Json::Value jvRequest, int& cost) { if (!jvRequest.isMember("key")) return rpcError(rpcINVALID_PARAMS); @@ -658,7 +657,7 @@ Json::Value RPCHandler::doDataDelete(Json::Value jvRequest) // { // key: // } -Json::Value RPCHandler::doDataFetch(Json::Value jvRequest) +Json::Value RPCHandler::doDataFetch(Json::Value jvRequest, int& cost) { if (!jvRequest.isMember("key")) return rpcError(rpcINVALID_PARAMS); @@ -681,7 +680,7 @@ Json::Value RPCHandler::doDataFetch(Json::Value jvRequest) // key: // value: // } -Json::Value RPCHandler::doDataStore(Json::Value jvRequest) +Json::Value RPCHandler::doDataStore(Json::Value jvRequest, int& cost) { if (!jvRequest.isMember("key") || !jvRequest.isMember("value")) @@ -741,7 +740,7 @@ Json::Value RPCHandler::doNicknameInfo(Json::Value params) // 'account_index' : // optional // } // XXX This would be better if it took the ledger. -Json::Value RPCHandler::doOwnerInfo(Json::Value jvRequest) +Json::Value RPCHandler::doOwnerInfo(Json::Value jvRequest, int& cost) { if (!jvRequest.isMember("account") && !jvRequest.isMember("ident")) return rpcError(rpcINVALID_PARAMS); @@ -766,7 +765,7 @@ Json::Value RPCHandler::doOwnerInfo(Json::Value jvRequest) return ret; } -Json::Value RPCHandler::doPeers(Json::Value) +Json::Value RPCHandler::doPeers(Json::Value, int& cost) { Json::Value jvResult(Json::objectValue); @@ -775,7 +774,7 @@ Json::Value RPCHandler::doPeers(Json::Value) return jvResult; } -Json::Value RPCHandler::doPing(Json::Value) +Json::Value RPCHandler::doPing(Json::Value, int& cost) { return Json::Value(Json::objectValue); } @@ -785,7 +784,7 @@ Json::Value RPCHandler::doPing(Json::Value) // issuer is the offering account // --> submit: 'submit|true|false': defaults to false // Prior to running allow each to have a credit line of what they will be getting from the other account. -Json::Value RPCHandler::doProfile(Json::Value jvRequest) +Json::Value RPCHandler::doProfile(Json::Value jvRequest, int& cost) { /* need to fix now that sharedOfferCreate is gone int iArgs = jvRequest.size(); @@ -878,7 +877,7 @@ Json::Value RPCHandler::doProfile(Json::Value jvRequest) // ledger_hash : // ledger_index : // } -Json::Value RPCHandler::doAccountLines(Json::Value jvRequest) +Json::Value RPCHandler::doAccountLines(Json::Value jvRequest, int& cost) { Ledger::pointer lpLedger; Json::Value jvResult = lookupLedger(jvRequest, lpLedger); @@ -957,7 +956,7 @@ Json::Value RPCHandler::doAccountLines(Json::Value jvRequest) // ledger_hash : // ledger_index : // } -Json::Value RPCHandler::doAccountOffers(Json::Value jvRequest) +Json::Value RPCHandler::doAccountOffers(Json::Value jvRequest, int& cost) { Ledger::pointer lpLedger; Json::Value jvResult = lookupLedger(jvRequest, lpLedger); @@ -1028,7 +1027,7 @@ Json::Value RPCHandler::doAccountOffers(Json::Value jvRequest) // "limit" : integer, // Optional. // "proof" : boolean // Defaults to false. // } -Json::Value RPCHandler::doBookOffers(Json::Value jvRequest) +Json::Value RPCHandler::doBookOffers(Json::Value jvRequest, int& cost) { if (theApp->getJobQueue().getJobCountGE(jtCLIENT) > 200) { @@ -1125,7 +1124,7 @@ Json::Value RPCHandler::doBookOffers(Json::Value jvRequest) // { // random: // } -Json::Value RPCHandler::doRandom(Json::Value jvRequest) +Json::Value RPCHandler::doRandom(Json::Value jvRequest, int& cost) { uint256 uRandom; @@ -1151,7 +1150,7 @@ Json::Value RPCHandler::doRandom(Json::Value jvRequest) // - Allows clients to verify path exists. // - Return canonicalized path. // - From a trusted server, allows clients to use path without manipulation. -Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest) +Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest, int& cost) { RippleAddress raSrc; RippleAddress raDst; @@ -1231,6 +1230,7 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest) } } + cost = rpcCOST_EXPENSIVE; Ledger::pointer lSnapShot = boost::make_shared(boost::ref(*lpLedger), false); LedgerEntrySet lesSnapshot(lSnapShot); @@ -1364,8 +1364,9 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest) // tx_json: , // secret: // } -Json::Value RPCHandler::doSign(Json::Value jvRequest) +Json::Value RPCHandler::doSign(Json::Value jvRequest, int& cost) { + cost = rpcCOST_EXPENSIVE; return transactionSign(jvRequest, false); } @@ -1373,7 +1374,7 @@ Json::Value RPCHandler::doSign(Json::Value jvRequest) // tx_json: , // secret: // } -Json::Value RPCHandler::doSubmit(Json::Value jvRequest) +Json::Value RPCHandler::doSubmit(Json::Value jvRequest, int& cost) { if (!jvRequest.isMember("tx_blob")) { @@ -1388,6 +1389,7 @@ Json::Value RPCHandler::doSubmit(Json::Value jvRequest) { return rpcError(rpcINVALID_PARAMS); } + cost = rpcCOST_EXPENSIVE; Serializer sTrans(vucBlob); SerializerIterator sitTrans(sTrans); @@ -1459,7 +1461,7 @@ Json::Value RPCHandler::doSubmit(Json::Value jvRequest) } } -Json::Value RPCHandler::doConsensusInfo(Json::Value) +Json::Value RPCHandler::doConsensusInfo(Json::Value, int& cost) { Json::Value ret(Json::objectValue); @@ -1468,7 +1470,7 @@ Json::Value RPCHandler::doConsensusInfo(Json::Value) return ret; } -Json::Value RPCHandler::doServerInfo(Json::Value) +Json::Value RPCHandler::doServerInfo(Json::Value, int& cost) { Json::Value ret(Json::objectValue); @@ -1477,7 +1479,7 @@ Json::Value RPCHandler::doServerInfo(Json::Value) return ret; } -Json::Value RPCHandler::doServerState(Json::Value) +Json::Value RPCHandler::doServerState(Json::Value, int& cost) { Json::Value ret(Json::objectValue); @@ -1489,7 +1491,7 @@ Json::Value RPCHandler::doServerState(Json::Value) // { // start: // } -Json::Value RPCHandler::doTxHistory(Json::Value jvRequest) +Json::Value RPCHandler::doTxHistory(Json::Value jvRequest, int& cost) { if (!jvRequest.isMember("start")) return rpcError(rpcINVALID_PARAMS); @@ -1523,7 +1525,7 @@ Json::Value RPCHandler::doTxHistory(Json::Value jvRequest) // { // transaction: // } -Json::Value RPCHandler::doTx(Json::Value jvRequest) +Json::Value RPCHandler::doTx(Json::Value jvRequest, int& cost) { if (!jvRequest.isMember("transaction")) return rpcError(rpcINVALID_PARAMS); @@ -1583,7 +1585,7 @@ Json::Value RPCHandler::doTx(Json::Value jvRequest) return rpcError(rpcNOT_IMPL); } -Json::Value RPCHandler::doLedgerClosed(Json::Value) +Json::Value RPCHandler::doLedgerClosed(Json::Value, int& cost) { Json::Value jvResult; @@ -1596,7 +1598,7 @@ Json::Value RPCHandler::doLedgerClosed(Json::Value) return jvResult; } -Json::Value RPCHandler::doLedgerCurrent(Json::Value) +Json::Value RPCHandler::doLedgerCurrent(Json::Value, int& cost) { Json::Value jvResult; @@ -1610,7 +1612,7 @@ Json::Value RPCHandler::doLedgerCurrent(Json::Value) // ledger: 'current' | 'closed' | | , // optional // full: true | false // optional, defaults to false. // } -Json::Value RPCHandler::doLedger(Json::Value jvRequest) +Json::Value RPCHandler::doLedger(Json::Value jvRequest, int& cost) { if (!jvRequest.isMember("ledger")) { @@ -1656,7 +1658,7 @@ Json::Value RPCHandler::doLedger(Json::Value jvRequest) // FIXME: Require admin. // FIXME: Doesn't report database holes. // FIXME: For consistency change inputs to: ledger_index, ledger_index_min, ledger_index_max. -Json::Value RPCHandler::doAccountTransactions(Json::Value jvRequest) +Json::Value RPCHandler::doAccountTransactions(Json::Value jvRequest, int& cost) { RippleAddress raAccount; uint32 minLedger; @@ -1753,7 +1755,7 @@ Json::Value RPCHandler::doAccountTransactions(Json::Value jvRequest) // } // // This command requires admin access because it makes no sense to ask an untrusted server for this. -Json::Value RPCHandler::doValidationCreate(Json::Value jvRequest) { +Json::Value RPCHandler::doValidationCreate(Json::Value jvRequest, int& cost) { RippleAddress raSeed; Json::Value obj(Json::objectValue); @@ -1778,7 +1780,7 @@ Json::Value RPCHandler::doValidationCreate(Json::Value jvRequest) { // { // secret: // } -Json::Value RPCHandler::doValidationSeed(Json::Value jvRequest) { +Json::Value RPCHandler::doValidationSeed(Json::Value jvRequest, int& cost) { Json::Value obj(Json::objectValue); if (!jvRequest.isMember("secret")) @@ -1845,7 +1847,7 @@ Json::Value RPCHandler::accounts(Ledger::ref lrLedger, const RippleAddress& naMa // ledger_hash : // ledger_index : // } -Json::Value RPCHandler::doWalletAccounts(Json::Value jvRequest) +Json::Value RPCHandler::doWalletAccounts(Json::Value jvRequest, int& cost) { Ledger::pointer lpLedger; Json::Value jvResult = lookupLedger(jvRequest, lpLedger); @@ -1888,7 +1890,7 @@ Json::Value RPCHandler::doWalletAccounts(Json::Value jvRequest) } } -Json::Value RPCHandler::doLogRotate(Json::Value) +Json::Value RPCHandler::doLogRotate(Json::Value, int& cost) { return Log::rotateLog(); } @@ -1896,7 +1898,7 @@ Json::Value RPCHandler::doLogRotate(Json::Value) // { // passphrase: // } -Json::Value RPCHandler::doWalletPropose(Json::Value jvRequest) +Json::Value RPCHandler::doWalletPropose(Json::Value jvRequest, int& cost) { RippleAddress naSeed; RippleAddress naAccount; @@ -1926,7 +1928,7 @@ Json::Value RPCHandler::doWalletPropose(Json::Value jvRequest) // { // secret: // } -Json::Value RPCHandler::doWalletSeed(Json::Value jvRequest) +Json::Value RPCHandler::doWalletSeed(Json::Value jvRequest, int& cost) { RippleAddress raSeed; bool bSecret = jvRequest.isMember("secret"); @@ -1965,7 +1967,7 @@ Json::Value RPCHandler::doWalletSeed(Json::Value jvRequest) // username: , // password: // } -Json::Value RPCHandler::doLogin(Json::Value jvRequest) +Json::Value RPCHandler::doLogin(Json::Value jvRequest, int& cost) { if (!jvRequest.isMember("username") || !jvRequest.isMember("password")) @@ -2001,7 +2003,7 @@ static void textTime(std::string& text, int& seconds, const char *unitName, int // { // min_count: // optional, defaults to 10 // } -Json::Value RPCHandler::doGetCounts(Json::Value jvRequest) +Json::Value RPCHandler::doGetCounts(Json::Value jvRequest, int& cost) { int minCount = 10; @@ -2031,7 +2033,7 @@ Json::Value RPCHandler::doGetCounts(Json::Value jvRequest) return ret; } -Json::Value RPCHandler::doLogLevel(Json::Value jvRequest) +Json::Value RPCHandler::doLogLevel(Json::Value jvRequest, int& cost) { // log_level if (!jvRequest.isMember("severity")) @@ -2079,7 +2081,7 @@ Json::Value RPCHandler::doLogLevel(Json::Value jvRequest) // node: |, // comment: // optional // } -Json::Value RPCHandler::doUnlAdd(Json::Value jvRequest) +Json::Value RPCHandler::doUnlAdd(Json::Value jvRequest, int& cost) { std::string strNode = jvRequest.isMember("node") ? jvRequest["node"].asString() : ""; std::string strComment = jvRequest.isMember("comment") ? jvRequest["comment"].asString() : ""; @@ -2103,7 +2105,7 @@ Json::Value RPCHandler::doUnlAdd(Json::Value jvRequest) // { // node: | // } -Json::Value RPCHandler::doUnlDelete(Json::Value jvRequest) +Json::Value RPCHandler::doUnlDelete(Json::Value jvRequest, int& cost) { if (!jvRequest.isMember("node")) return rpcError(rpcINVALID_PARAMS); @@ -2126,7 +2128,7 @@ Json::Value RPCHandler::doUnlDelete(Json::Value jvRequest) } } -Json::Value RPCHandler::doUnlList(Json::Value) +Json::Value RPCHandler::doUnlList(Json::Value, int& cost) { Json::Value obj(Json::objectValue); @@ -2136,7 +2138,7 @@ Json::Value RPCHandler::doUnlList(Json::Value) } // Populate the UNL from a local validators.txt file. -Json::Value RPCHandler::doUnlLoad(Json::Value) +Json::Value RPCHandler::doUnlLoad(Json::Value, int& cost) { if (theConfig.VALIDATORS_FILE.empty() || !theApp->getUNL().nodeLoad(theConfig.VALIDATORS_FILE)) { @@ -2148,7 +2150,7 @@ Json::Value RPCHandler::doUnlLoad(Json::Value) // Populate the UNL from ripple.com's validators.txt file. -Json::Value RPCHandler::doUnlNetwork(Json::Value jvRequest) +Json::Value RPCHandler::doUnlNetwork(Json::Value jvRequest, int& cost) { theApp->getUNL().nodeNetwork(); @@ -2156,7 +2158,7 @@ Json::Value RPCHandler::doUnlNetwork(Json::Value jvRequest) } // unl_reset -Json::Value RPCHandler::doUnlReset(Json::Value jvRequest) +Json::Value RPCHandler::doUnlReset(Json::Value jvRequest, int& cost) { theApp->getUNL().nodeReset(); @@ -2164,21 +2166,21 @@ Json::Value RPCHandler::doUnlReset(Json::Value jvRequest) } // unl_score -Json::Value RPCHandler::doUnlScore(Json::Value) +Json::Value RPCHandler::doUnlScore(Json::Value, int& cost) { theApp->getUNL().nodeScore(); return "scoring requested"; } -Json::Value RPCHandler::doStop(Json::Value) +Json::Value RPCHandler::doStop(Json::Value, int& cost) { theApp->stop(); return SYSTEM_NAME " server stopping"; } -Json::Value RPCHandler::doLedgerAccept(Json::Value) +Json::Value RPCHandler::doLedgerAccept(Json::Value, int& cost) { Json::Value jvResult; @@ -2201,7 +2203,7 @@ Json::Value RPCHandler::doLedgerAccept(Json::Value) // ledger_index : // } // XXX In this case, not specify either ledger does not mean ledger current. It means any ledger. -Json::Value RPCHandler::doTransactionEntry(Json::Value jvRequest) +Json::Value RPCHandler::doTransactionEntry(Json::Value jvRequest, int& cost) { Ledger::pointer lpLedger; Json::Value jvResult = lookupLedger(jvRequest, lpLedger); @@ -2328,7 +2330,7 @@ Json::Value RPCHandler::lookupLedger(Json::Value jvRequest, Ledger::pointer& lpL // ledger_index : // ... // } -Json::Value RPCHandler::doLedgerEntry(Json::Value jvRequest) +Json::Value RPCHandler::doLedgerEntry(Json::Value jvRequest, int& cost) { Ledger::pointer lpLedger; Json::Value jvResult = lookupLedger(jvRequest, lpLedger); @@ -2535,7 +2537,7 @@ Json::Value RPCHandler::doLedgerEntry(Json::Value jvRequest) // ledger_hash : // ledger_index : // } -Json::Value RPCHandler::doLedgerHeader(Json::Value jvRequest) +Json::Value RPCHandler::doLedgerHeader(Json::Value jvRequest, int& cost) { Ledger::pointer lpLedger; Json::Value jvResult = lookupLedger(jvRequest, lpLedger); @@ -2585,7 +2587,7 @@ rt_transactions accounts rt_accounts */ -Json::Value RPCHandler::doSubscribe(Json::Value jvRequest) +Json::Value RPCHandler::doSubscribe(Json::Value jvRequest, int& cost) { InfoSub::pointer ispSub; Json::Value jvResult(Json::objectValue); @@ -2733,7 +2735,7 @@ Json::Value RPCHandler::doSubscribe(Json::Value jvRequest) } // FIXME: This leaks RPCSub objects for JSON-RPC. Shouldn't matter for anyone sane. -Json::Value RPCHandler::doUnsubscribe(Json::Value jvRequest) +Json::Value RPCHandler::doUnsubscribe(Json::Value jvRequest, int& cost) { InfoSub::pointer ispSub; Json::Value jvResult(Json::objectValue); @@ -2846,8 +2848,10 @@ Json::Value RPCHandler::doUnsubscribe(Json::Value jvRequest) // // JSON-RPC provides a method and an array of params. JSON-RPC is used as a transport for a command and a request object. The // command is the method. The request object is supplied as the first element of the params. -Json::Value RPCHandler::doRpcCommand(const std::string& strMethod, Json::Value& jvParams, int iRole) +Json::Value RPCHandler::doRpcCommand(const std::string& strMethod, Json::Value& jvParams, int iRole, int& cost) { + if (cost == 0) + cost = rpcCOST_DEFAULT; cLog(lsTRACE) << "doRpcCommand:" << strMethod << ":" << jvParams; if (!jvParams.isArray() || jvParams.size() > 1) @@ -2861,7 +2865,7 @@ Json::Value RPCHandler::doRpcCommand(const std::string& strMethod, Json::Value& // Provide the JSON-RPC method as the field "command" in the request. jvRequest["command"] = strMethod; - Json::Value jvResult = doCommand(jvRequest, iRole); + Json::Value jvResult = doCommand(jvRequest, iRole, cost); // Always report "status". On an error report the request as received. if (jvResult.isMember("error")) @@ -2876,15 +2880,17 @@ Json::Value RPCHandler::doRpcCommand(const std::string& strMethod, Json::Value& return jvResult; } -Json::Value RPCHandler::doInternal(Json::Value jvRequest) +Json::Value RPCHandler::doInternal(Json::Value jvRequest, int& cost) { // Used for debug or special-purpose RPC commands if (!jvRequest.isMember("internal_command")) return rpcError(rpcINVALID_PARAMS); return RPCInternalHandler::runHandler(jvRequest["internal_command"].asString(), jvRequest["params"]); } -Json::Value RPCHandler::doCommand(const Json::Value& jvRequest, int iRole) +Json::Value RPCHandler::doCommand(const Json::Value& jvRequest, int iRole, int &cost) { + if (cost == 0) + cost = rpcCOST_DEFAULT; if ((iRole != ADMIN) && (theApp->getJobQueue().getJobCountGE(jtCLIENT) > 500)) return rpcError(rpcTOO_BUSY); @@ -3003,7 +3009,7 @@ Json::Value RPCHandler::doCommand(const Json::Value& jvRequest, int iRole) else { try { - Json::Value jvRaw = (this->*(commandsA[i].dfpFunc))(jvRequest); + Json::Value jvRaw = (this->*(commandsA[i].dfpFunc))(jvRequest, cost); // Regularize result. if (jvRaw.isObject()) @@ -3024,6 +3030,8 @@ Json::Value RPCHandler::doCommand(const Json::Value& jvRequest, int iRole) catch (std::exception& e) { cLog(lsINFO) << "Caught throw: " << e.what(); + if (cost == rpcCOST_DEFAULT) + cost = rpcCOST_EXCEPTION; return rpcError(rpcINTERNAL); } diff --git a/src/cpp/ripple/RPCHandler.h b/src/cpp/ripple/RPCHandler.h index 9c8c3e288..641687ccf 100644 --- a/src/cpp/ripple/RPCHandler.h +++ b/src/cpp/ripple/RPCHandler.h @@ -18,9 +18,8 @@ class RPCHandler NetworkOPs* mNetOps; InfoSub::pointer mInfoSub; int mRole; - LoadSource& mLoadSource; - typedef Json::Value (RPCHandler::*doFuncPtr)(Json::Value params); + typedef Json::Value (RPCHandler::*doFuncPtr)(Json::Value params, int& cost); enum { optNone = 0, optNetwork = 1, // Need network @@ -44,81 +43,81 @@ class RPCHandler Json::Value accountFromString(Ledger::ref lrLedger, RippleAddress& naAccount, bool& bIndex, const std::string& strIdent, const int iIndex, const bool bStrict); - Json::Value doAccountInfo(Json::Value params); - Json::Value doAccountLines(Json::Value params); - Json::Value doAccountOffers(Json::Value params); - Json::Value doAccountTransactions(Json::Value params); - Json::Value doBookOffers(Json::Value params); - Json::Value doConnect(Json::Value params); - Json::Value doConsensusInfo(Json::Value params); + Json::Value doAccountInfo(Json::Value params, int& cost); + Json::Value doAccountLines(Json::Value params, int& cost); + Json::Value doAccountOffers(Json::Value params, int& cost); + Json::Value doAccountTransactions(Json::Value params, int& cost); + Json::Value doBookOffers(Json::Value params, int& cost); + Json::Value doConnect(Json::Value params, int& cost); + Json::Value doConsensusInfo(Json::Value params, int& cost); #if ENABLE_INSECURE - Json::Value doDataDelete(Json::Value params); - Json::Value doDataFetch(Json::Value params); - Json::Value doDataStore(Json::Value params); + Json::Value doDataDelete(Json::Value params, int& cost); + Json::Value doDataFetch(Json::Value params, int& cost); + Json::Value doDataStore(Json::Value params, int& cost); #endif - Json::Value doGetCounts(Json::Value params); - Json::Value doInternal(Json::Value params); - Json::Value doLedger(Json::Value params); - Json::Value doLogLevel(Json::Value params); - Json::Value doLogRotate(Json::Value params); - Json::Value doNicknameInfo(Json::Value params); - Json::Value doOwnerInfo(Json::Value params); - Json::Value doPeers(Json::Value params); - Json::Value doPing(Json::Value params); - Json::Value doProfile(Json::Value params); - Json::Value doRandom(Json::Value jvRequest); - Json::Value doRipplePathFind(Json::Value jvRequest); - Json::Value doServerInfo(Json::Value params); // for humans - Json::Value doServerState(Json::Value params); // for machines - Json::Value doSessionClose(Json::Value params); - Json::Value doSessionOpen(Json::Value params); - Json::Value doStop(Json::Value params); - Json::Value doSign(Json::Value params); - Json::Value doSubmit(Json::Value params); - Json::Value doTx(Json::Value params); - Json::Value doTxHistory(Json::Value params); - Json::Value doUnlAdd(Json::Value params); - Json::Value doUnlDelete(Json::Value params); - Json::Value doUnlFetch(Json::Value params); - Json::Value doUnlList(Json::Value params); - Json::Value doUnlLoad(Json::Value params); - Json::Value doUnlNetwork(Json::Value params); - Json::Value doUnlReset(Json::Value params); - Json::Value doUnlScore(Json::Value params); + Json::Value doGetCounts(Json::Value params, int& cost); + Json::Value doInternal(Json::Value params, int& cost); + Json::Value doLedger(Json::Value params, int& cost); + Json::Value doLogLevel(Json::Value params, int& cost); + Json::Value doLogRotate(Json::Value params, int& cost); + Json::Value doNicknameInfo(Json::Value params, int& cost); + Json::Value doOwnerInfo(Json::Value params, int& cost); + Json::Value doPeers(Json::Value params, int& cost); + Json::Value doPing(Json::Value params, int& cost); + Json::Value doProfile(Json::Value params, int& cost); + Json::Value doRandom(Json::Value jvRequest, int& cost); + Json::Value doRipplePathFind(Json::Value jvRequest, int& cost); + Json::Value doServerInfo(Json::Value params, int& cost); // for humans + Json::Value doServerState(Json::Value params, int& cost); // for machines + Json::Value doSessionClose(Json::Value params, int& cost); + Json::Value doSessionOpen(Json::Value params, int& cost); + Json::Value doStop(Json::Value params, int& cost); + Json::Value doSign(Json::Value params, int& cost); + Json::Value doSubmit(Json::Value params, int& cost); + Json::Value doTx(Json::Value params, int& cost); + Json::Value doTxHistory(Json::Value params, int& cost); + Json::Value doUnlAdd(Json::Value params, int& cost); + Json::Value doUnlDelete(Json::Value params, int& cost); + Json::Value doUnlFetch(Json::Value params, int& cost); + Json::Value doUnlList(Json::Value params, int& cost); + Json::Value doUnlLoad(Json::Value params, int& cost); + Json::Value doUnlNetwork(Json::Value params, int& cost); + Json::Value doUnlReset(Json::Value params, int& cost); + Json::Value doUnlScore(Json::Value params, int& cost); - Json::Value doValidationCreate(Json::Value params); - Json::Value doValidationSeed(Json::Value params); + Json::Value doValidationCreate(Json::Value params, int& cost); + Json::Value doValidationSeed(Json::Value params, int& cost); - Json::Value doWalletAccounts(Json::Value params); - Json::Value doWalletLock(Json::Value params); - Json::Value doWalletPropose(Json::Value params); - Json::Value doWalletSeed(Json::Value params); - Json::Value doWalletUnlock(Json::Value params); - Json::Value doWalletVerify(Json::Value params); + Json::Value doWalletAccounts(Json::Value params, int& cost); + Json::Value doWalletLock(Json::Value params, int& cost); + Json::Value doWalletPropose(Json::Value params, int& cost); + Json::Value doWalletSeed(Json::Value params, int& cost); + Json::Value doWalletUnlock(Json::Value params, int& cost); + Json::Value doWalletVerify(Json::Value params, int& cost); #if ENABLE_INSECURE - Json::Value doLogin(Json::Value params); + Json::Value doLogin(Json::Value params, int& cost); #endif - Json::Value doLedgerAccept(Json::Value params); - Json::Value doLedgerClosed(Json::Value params); - Json::Value doLedgerCurrent(Json::Value params); - Json::Value doLedgerEntry(Json::Value params); - Json::Value doLedgerHeader(Json::Value params); - Json::Value doTransactionEntry(Json::Value params); + Json::Value doLedgerAccept(Json::Value params, int& cost); + Json::Value doLedgerClosed(Json::Value params, int& cost); + Json::Value doLedgerCurrent(Json::Value params, int& cost); + Json::Value doLedgerEntry(Json::Value params, int& cost); + Json::Value doLedgerHeader(Json::Value params, int& cost); + Json::Value doTransactionEntry(Json::Value params, int& cost); - Json::Value doSubscribe(Json::Value params); - Json::Value doUnsubscribe(Json::Value params); + Json::Value doSubscribe(Json::Value params, int& cost); + Json::Value doUnsubscribe(Json::Value params, int& cost); public: enum { GUEST, USER, ADMIN, FORBID }; - RPCHandler(NetworkOPs* netOps, LoadSource&); - RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub, LoadSource&); + RPCHandler(NetworkOPs* netOps); + RPCHandler(NetworkOPs* netOps, InfoSub::pointer infoSub); - Json::Value doCommand(const Json::Value& jvRequest, int role); - Json::Value doRpcCommand(const std::string& strCommand, Json::Value& jvParams, int iRole); + Json::Value doCommand(const Json::Value& jvRequest, int role, int& cost); + Json::Value doRpcCommand(const std::string& strCommand, Json::Value& jvParams, int iRole, int& cost); }; class RPCInternalHandler diff --git a/src/cpp/ripple/RPCServer.cpp b/src/cpp/ripple/RPCServer.cpp index 33185c3b7..f3b81e577 100644 --- a/src/cpp/ripple/RPCServer.cpp +++ b/src/cpp/ripple/RPCServer.cpp @@ -24,7 +24,7 @@ SETUP_LOG(); #endif RPCServer::RPCServer(boost::asio::io_service& io_service , NetworkOPs* nopNetwork) - : mNetOps(nopNetwork), mLoadSource("rpc"), mSocket(io_service) + : mNetOps(nopNetwork), mSocket(io_service) { mRole = RPCHandler::GUEST; } @@ -51,7 +51,7 @@ void RPCServer::handle_read_req(const boost::system::error_code& e) if (!HTTPAuthorized(mHTTPRequest.peekHeaders())) mReplyStr = HTTPReply(403, "Forbidden"); else - mReplyStr = handleRequest(req, mLoadSource); + mReplyStr = handleRequest(req); boost::asio::async_write(mSocket, boost::asio::buffer(mReplyStr), boost::bind(&RPCServer::handle_write, shared_from_this(), boost::asio::placeholders::error)); @@ -110,7 +110,7 @@ void RPCServer::handle_read_line(const boost::system::error_code& e) } } -std::string RPCServer::handleRequest(const std::string& requestStr, LoadSource& ls) +std::string RPCServer::handleRequest(const std::string& requestStr) { cLog(lsTRACE) << "handleRequest " << requestStr; @@ -154,10 +154,11 @@ std::string RPCServer::handleRequest(const std::string& requestStr, LoadSource& return HTTPReply(403, "Forbidden"); } - RPCHandler mRPCHandler(mNetOps, mLoadSource); + RPCHandler mRPCHandler(mNetOps); cLog(lsTRACE) << valParams; - Json::Value result = mRPCHandler.doRpcCommand(strMethod, valParams, mRole); + int cost = 10; + Json::Value result = mRPCHandler.doRpcCommand(strMethod, valParams, mRole, cost); cLog(lsTRACE) << result; std::string strReply = JSONRPCReply(result, Json::Value(), id); diff --git a/src/cpp/ripple/RPCServer.h b/src/cpp/ripple/RPCServer.h index bfc6a4c0e..44ca235fd 100644 --- a/src/cpp/ripple/RPCServer.h +++ b/src/cpp/ripple/RPCServer.h @@ -24,7 +24,6 @@ public: private: NetworkOPs* mNetOps; - LoadSource mLoadSource; boost::asio::ip::tcp::socket mSocket; @@ -46,7 +45,7 @@ private: void handle_read_line(const boost::system::error_code& ec); void handle_read_req(const boost::system::error_code& ec); - std::string handleRequest(const std::string& requestStr, LoadSource& ls); + std::string handleRequest(const std::string& requestStr); public: static pointer create(boost::asio::io_service& io_service, NetworkOPs* mNetOps) diff --git a/src/cpp/ripple/WSConnection.h b/src/cpp/ripple/WSConnection.h index 7ce02fba4..25a7fcfe3 100644 --- a/src/cpp/ripple/WSConnection.h +++ b/src/cpp/ripple/WSConnection.h @@ -88,6 +88,14 @@ public: // Utilities Json::Value invokeCommand(Json::Value& jvRequest) { + if (theApp->getLoadManager().shouldCutoff(mLoadSource)) + { + connection_ptr ptr = mConnection.lock(); + if (ptr) + ptr->close(websocketpp::close::status::PROTOCOL_ERROR, "overload"); + return rpcError(rpcTOO_BUSY); + } + if (!jvRequest.isMember("command")) { Json::Value jvResult(Json::objectValue); @@ -102,11 +110,12 @@ public: jvResult["id"] = jvRequest["id"]; } + theApp->getLoadManager().adjust(mLoadSource, 5); return jvResult; } - RPCHandler mRPCHandler(&mNetwork, - boost::shared_polymorphic_downcast(this->shared_from_this()), mLoadSource); + int cost = 10; + RPCHandler mRPCHandler(&mNetwork, boost::shared_polymorphic_downcast(this->shared_from_this())); Json::Value jvResult(Json::objectValue); int iRole = mHandler->getPublic() @@ -119,9 +128,12 @@ public: } else { - jvResult["result"] = mRPCHandler.doCommand(jvRequest, iRole); + jvResult["result"] = mRPCHandler.doCommand(jvRequest, iRole, cost); } + if (theApp->getLoadManager().adjust(mLoadSource, cost) && theApp->getLoadManager().shouldWarn(mLoadSource)) + jvResult["warning"] = "load"; + // Currently we will simply unwrap errors returned by the RPC // API, in the future maybe we can make the responses // consistent. diff --git a/src/cpp/ripple/main.cpp b/src/cpp/ripple/main.cpp index 1c114aa07..4493786f9 100644 --- a/src/cpp/ripple/main.cpp +++ b/src/cpp/ripple/main.cpp @@ -43,10 +43,10 @@ void startServer() if (!theConfig.QUIET) std::cerr << "Startup RPC: " << jvCommand << std::endl; - LoadSource ls(true); - RPCHandler rhHandler(&theApp->getOPs(), ls); + RPCHandler rhHandler(&theApp->getOPs()); - Json::Value jvResult = rhHandler.doCommand(jvCommand, RPCHandler::ADMIN); + int cost = 10; + Json::Value jvResult = rhHandler.doCommand(jvCommand, RPCHandler::ADMIN, cost); if (!theConfig.QUIET) std::cerr << "Result: " << jvResult << std::endl;