diff --git a/.gitignore b/.gitignore index f3cda28c5b..41a4891b8d 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,9 @@ *.o build tags +bin/rippled +Debug/*.* +Release/*.* # Ignore locally installed node_modules node_modules @@ -30,11 +33,6 @@ tmp db/*.db db/*.db-* -# Ignore obj files -bin/rippled -Debug/*.* -Release/*.* - # Ignore customized configs rippled.cfg validators.txt diff --git a/src/cpp/database/SqliteDatabase.cpp b/src/cpp/database/SqliteDatabase.cpp index 7db0a623f6..aa3195daf8 100644 --- a/src/cpp/database/SqliteDatabase.cpp +++ b/src/cpp/database/SqliteDatabase.cpp @@ -239,25 +239,25 @@ void SqliteDatabase::runWal() { { boost::mutex::scoped_lock sl(walMutex); - walDBs.swap(walSet); - if (walSet.empty()) + if (walDBs.empty()) { walRunning = false; return; } + walDBs.swap(walSet); } BOOST_FOREACH(const std::string& db, walSet) { - int log, ckpt; + int log = 0, ckpt = 0; int ret = sqlite3_wal_checkpoint_v2(mConnection, db.c_str(), SQLITE_CHECKPOINT_PASSIVE, &log, &ckpt); if (ret != SQLITE_OK) { - cLog((ret == SQLITE_LOCKED) ? lsTRACE : lsWARNING) << "WAL " << mHost << ":" + cLog((ret == SQLITE_LOCKED) ? lsTRACE : lsWARNING) << "WAL " << name << ":" << db << " error " << ret; } else - cLog(lsTRACE) << "WAL(" << mHost << "): pass=" << pass << ", frames=" << log << ", written=" << ckpt; + cLog(lsTRACE) << "WAL(" << name << "): pass=" << pass << ", frames=" << log << ", written=" << ckpt; } walSet.clear(); ++pass; diff --git a/src/cpp/ripple/AcceptedLedger.h b/src/cpp/ripple/AcceptedLedger.h index e3237cd238..4b6297e559 100644 --- a/src/cpp/ripple/AcceptedLedger.h +++ b/src/cpp/ripple/AcceptedLedger.h @@ -40,7 +40,7 @@ class AcceptedLedger public: typedef boost::shared_ptr pointer; typedef const pointer& ret; - typedef std::map map_t; + typedef std::map map_t; // Must be an ordered map! typedef map_t::value_type value_type; typedef map_t::const_iterator const_iterator; diff --git a/src/cpp/ripple/Application.cpp b/src/cpp/ripple/Application.cpp index f0c3602658..a9ff4ce797 100644 --- a/src/cpp/ripple/Application.cpp +++ b/src/cpp/ripple/Application.cpp @@ -26,7 +26,7 @@ Application* theApp = NULL; DatabaseCon::DatabaseCon(const std::string& strName, const char *initStrings[], int initCount) { - boost::filesystem::path pPath = (theConfig.RUN_STANDALONE && (!theConfig.START_UP != 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. diff --git a/src/cpp/ripple/PaymentTransactor.cpp b/src/cpp/ripple/PaymentTransactor.cpp index ed46b8253a..707b0ecf02 100644 --- a/src/cpp/ripple/PaymentTransactor.cpp +++ b/src/cpp/ripple/PaymentTransactor.cpp @@ -21,8 +21,8 @@ TER PaymentTransactor::doApply() const STAmount saMaxAmount = bMax ? mTxn.getFieldAmount(sfSendMax) : saDstAmount.isNative() - ? saDstAmount - : STAmount(saDstAmount.getCurrency(), mTxnAccountID, saDstAmount.getMantissa(), saDstAmount.getExponent(), saDstAmount.isNegative()); + ? saDstAmount + : STAmount(saDstAmount.getCurrency(), mTxnAccountID, saDstAmount.getMantissa(), saDstAmount.getExponent(), saDstAmount.isNegative()); const uint160 uSrcCurrency = saMaxAmount.getCurrency(); const uint160 uDstCurrency = saDstAmount.getCurrency(); const bool bXRPDirect = uSrcCurrency.isZero() && uDstCurrency.isZero(); diff --git a/src/cpp/ripple/RPCErr.cpp b/src/cpp/ripple/RPCErr.cpp index 4696300604..de0216f2cb 100644 --- a/src/cpp/ripple/RPCErr.cpp +++ b/src/cpp/ripple/RPCErr.cpp @@ -72,6 +72,7 @@ Json::Value rpcError(int iError, Json::Value jvResult) { rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method." }, { rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key." }, { rpcTOO_BUSY, "tooBusy", "The server is too busy to help you now." }, + { rpcSLOW_DOWN, "slowDown", "You are placing too much load on the server." }, }; int i; diff --git a/src/cpp/ripple/RPCErr.h b/src/cpp/ripple/RPCErr.h index 0da8f82be1..67ad2de4ae 100644 --- a/src/cpp/ripple/RPCErr.h +++ b/src/cpp/ripple/RPCErr.h @@ -18,6 +18,7 @@ enum { rpcNO_EVENTS, rpcNOT_STANDALONE, rpcTOO_BUSY, + rpcSLOW_DOWN, // Networking rpcNO_CLOSED, diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 5a1f8edf85..ebf310da53 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -1152,6 +1152,13 @@ Json::Value RPCHandler::doRandom(Json::Value jvRequest, int& cost) // - From a trusted server, allows clients to use path without manipulation. Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest, int& cost) { + int jc = theApp->getJobQueue().getJobCountGE(jtCLIENT); + if (jc > 200) + { + cLog(lsDEBUG) << "Too busy for RPF: " << jc; + return rpcError(rpcTOO_BUSY); + } + RippleAddress raSrc; RippleAddress raDst; STAmount saDstAmount; @@ -1161,11 +1168,7 @@ Json::Value RPCHandler::doRipplePathFind(Json::Value jvRequest, int& cost) if (!lpLedger) return jvResult; - if (theApp->getJobQueue().getJobCountGE(jtCLIENT) > 200) - { - jvResult = rpcError(rpcTOO_BUSY); - } - else if (!jvRequest.isMember("source_account")) + if (!jvRequest.isMember("source_account")) { jvResult = rpcError(rpcSRC_ACT_MISSING); } @@ -2895,8 +2898,15 @@ Json::Value RPCHandler::doCommand(const Json::Value& jvRequest, int iRole, int & { if (cost == 0) cost = rpcCOST_DEFAULT; - if ((iRole != ADMIN) && (theApp->getJobQueue().getJobCountGE(jtCLIENT) > 500)) - return rpcError(rpcTOO_BUSY); + if (iRole != ADMIN) + { + int jc = theApp->getJobQueue().getJobCountGE(jtCLIENT); + if (jc > 500) + { + cLog(lsDEBUG) << "Too busy for command: " << jc; + return rpcError(rpcTOO_BUSY); + } + } if (!jvRequest.isMember("command")) return rpcError(rpcCOMMAND_MISSING); diff --git a/src/cpp/ripple/WSConnection.h b/src/cpp/ripple/WSConnection.h index 25a7fcfe3e..10b8be406b 100644 --- a/src/cpp/ripple/WSConnection.h +++ b/src/cpp/ripple/WSConnection.h @@ -93,7 +93,7 @@ public: connection_ptr ptr = mConnection.lock(); if (ptr) ptr->close(websocketpp::close::status::PROTOCOL_ERROR, "overload"); - return rpcError(rpcTOO_BUSY); + return rpcError(rpcSLOW_DOWN); } if (!jvRequest.isMember("command")) diff --git a/test/send-test.js b/test/send-test.js index c3055f7083..e80964fc28 100644 --- a/test/send-test.js +++ b/test/send-test.js @@ -493,8 +493,8 @@ buster.testCase("Sending future", { }); buster.testCase("Gateway", { - // 'setUp' : testutils.build_setup({ verbose: true }), 'setUp' : testutils.build_setup(), + // 'setUp' : testutils.build_setup({ verbose: true }), 'tearDown' : testutils.build_teardown(), "customer to customer with and without transfer fee" : @@ -603,6 +603,157 @@ buster.testCase("Gateway", { }); }, + "customer to customer, transfer fee, default path with and without specific issuer for Amount and SendMax" : + function (done) { + var self = this; + + // self.remote.set_trace(); + + async.waterfall([ + function (callback) { + self.what = "Create accounts."; + + testutils.create_accounts(self.remote, "root", "10000.0", ["alice", "bob", "mtgox"], callback); + }, + function (callback) { + self.what = "Set transfer rate."; + + self.remote.transaction() + .account_set("mtgox") + .transfer_rate(1e9*1.1) + .once('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + callback(m.result !== 'tesSUCCESS'); + }) + .submit(); + }, + function (callback) { + self.what = "Set credit limits."; + + testutils.credit_limits(self.remote, + { + "alice" : "100/AUD/mtgox", + "bob" : "100/AUD/mtgox", + }, + callback); + }, + function (callback) { + self.what = "Distribute funds."; + + testutils.payments(self.remote, + { + "mtgox" : [ "4.4/AUD/alice" ], + }, + callback); + }, + function (callback) { + self.what = "Verify balances."; + + testutils.verify_balances(self.remote, + { + "alice" : "4.4/AUD/mtgox", + }, + callback); + }, + function (callback) { + self.what = "Alice sends 1.1/AUD/mtgox Bob 1/AUD/mtgox"; + + self.remote.transaction() + .payment("alice", "bob", "1/AUD/mtgox") + .send_max("1.1/AUD/mtgox") + .on('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + + callback(m.result !== 'tesSUCCESS'); + }) + .submit(); + }, + function (callback) { + self.what = "Verify balances 2."; + + testutils.verify_balances(self.remote, + { + "alice" : "3.3/AUD/mtgox", + "bob" : "1/AUD/mtgox", + }, + callback); + }, + function (callback) { + self.what = "Alice sends 1.1/AUD/mtgox Bob 1/AUD/bob"; + + self.remote.transaction() + .payment("alice", "bob", "1/AUD/bob") + .send_max("1.1/AUD/mtgox") + .on('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + + callback(m.result !== 'tesSUCCESS'); + }) + .submit(); + }, + function (callback) { + self.what = "Verify balances 3."; + + testutils.verify_balances(self.remote, + { + "alice" : "2.2/AUD/mtgox", + "bob" : "2/AUD/mtgox", + }, + callback); + }, + function (callback) { + self.what = "Alice sends 1.1/AUD/alice Bob 1/AUD/mtgox"; + + self.remote.transaction() + .payment("alice", "bob", "1/AUD/mtgox") + .send_max("1.1/AUD/alice") + .on('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + + callback(m.result !== 'tesSUCCESS'); + }) + .submit(); + }, + function (callback) { + self.what = "Verify balances 4."; + + testutils.verify_balances(self.remote, + { + "alice" : "1.1/AUD/mtgox", + "bob" : "3/AUD/mtgox", + }, + callback); + }, + function (callback) { + // Must fail, doesn't know to use the mtgox + self.what = "Alice sends 1.1/AUD/alice Bob 1/AUD/bob"; + + self.remote.transaction() + .payment("alice", "bob", "1/AUD/bob") + .send_max("1.1/AUD/alice") + .on('proposed', function (m) { + // console.log("proposed: %s", JSON.stringify(m)); + + callback(m.result !== 'terNO_LINE'); + }) + .submit(); + }, + function (callback) { + self.what = "Verify balances 5."; + + testutils.verify_balances(self.remote, + { + "alice" : "1.1/AUD/mtgox", + "bob" : "3/AUD/mtgox", + }, + callback); + }, + ], function (error) { + buster.refute(error, self.what); + done(); + }); + }, + "subscribe test: customer to customer with and without transfer fee" : function (done) { var self = this;