diff --git a/js/remote.js b/js/remote.js index c98129d102..ffab43eaad 100644 --- a/js/remote.js +++ b/js/remote.js @@ -168,6 +168,8 @@ Remote.method('request', function(command, done) { }); Remote.method('ledger_closed', function(done) { + assert(this.trusted); // If not trusted, need to check proof. + this.request({ 'command' : 'ledger_closed' }, done); }); @@ -177,6 +179,17 @@ Remote.method('ledger_current', function(done) { this.request({ 'command' : 'ledger_current' }, done); }); +// <-> params: +// --> ledger : optional +// --> ledger_index : optional +Remote.method('ledger_entry', function(params, done) { + assert(this.trusted); // If not trusted, need to check proof, maybe talk packet protocol. + + params.command = 'ledger_entry'; + + this.request(params, done); +}); + // Submit a json transaction. // done(value) // <-> value: { 'status', status, 'result' : result, ... } @@ -186,16 +199,6 @@ Remote.method('submit', function(json, done) { // }); }); -// done(value) -// --> value: { 'status', status, 'result' : result, ... } -// done may be called up to 3 times. -Remote.method('account_root', function(account_id, done) { - this.request({ - 'command' : 'ledger_current', - }, function() { - }); -}); - exports.Remote = Remote; exports.remoteConfig = remoteConfig; diff --git a/newcoind.cfg b/newcoind.cfg index ac87d7aa8d..689b276923 100644 --- a/newcoind.cfg +++ b/newcoind.cfg @@ -119,7 +119,7 @@ 1 [debug_logfile] -debug.log +log/debug.log [sntp_servers] time.windows.com diff --git a/src/Amount.cpp b/src/Amount.cpp index 11711917ea..8bd2d96a02 100644 --- a/src/Amount.cpp +++ b/src/Amount.cpp @@ -12,6 +12,7 @@ uint64 STAmount::uRateOne = STAmount::getRate(STAmount(1), STAmount(1)); +// --> sCurrency: "", "XNS", or three letter ISO code. bool STAmount::currencyFromString(uint160& uDstCurrency, const std::string& sCurrency) { bool bSuccess = true; diff --git a/src/Log.cpp b/src/Log.cpp index bdd56959b2..948552cbf9 100644 --- a/src/Log.cpp +++ b/src/Log.cpp @@ -10,6 +10,8 @@ boost::recursive_mutex Log::sLock; LogSeverity Log::sMinSeverity = lsINFO; std::ofstream* Log::outStream = NULL; +boost::filesystem::path *Log::pathToLog = NULL; +uint32 Log::logRotateCounter = 0; Log::~Log() { @@ -31,6 +33,48 @@ Log::~Log() (*outStream) << logMsg << std::endl; } + +std::string Log::rotateLog(void) +{ + boost::recursive_mutex::scoped_lock sl(sLock); + boost::filesystem::path abs_path; + std::string abs_path_str; + + uint32 failsafe = 0; + + std::string abs_new_path_str; + do { + std::string s; + std::stringstream out; + + failsafe++; + if (failsafe == std::numeric_limits::max()) { + return "unable to create new log file; too many log files!"; + } + abs_path = boost::filesystem::absolute(""); + abs_path /= *pathToLog; + abs_path_str = abs_path.parent_path().string(); + out << logRotateCounter; + s = out.str(); + + + abs_new_path_str = abs_path_str + "/" + s + + "_" + pathToLog->filename().string(); + + logRotateCounter++; + + } while (boost::filesystem::exists(boost::filesystem::path(abs_new_path_str))); + + outStream->close(); + boost::filesystem::rename(abs_path, boost::filesystem::path(abs_new_path_str)); + + + + setLogFile(*pathToLog); + + return abs_new_path_str; + +} + void Log::setMinSeverity(LogSeverity s) { boost::recursive_mutex::scoped_lock sl(sLock); @@ -52,4 +96,6 @@ void Log::setLogFile(boost::filesystem::path path) outStream = newStream; if (outStream) Log(lsINFO) << "Starting up"; + + pathToLog = new boost::filesystem::path(path); } diff --git a/src/Log.h b/src/Log.h index 7153012226..fd3db13fd3 100644 --- a/src/Log.h +++ b/src/Log.h @@ -9,6 +9,9 @@ // Ensure that we don't get value.h without writer.h #include "../json/json.h" +#include "types.h" +#include + enum LogSeverity { lsTRACE = 0, @@ -33,6 +36,9 @@ protected: mutable std::ostringstream oss; LogSeverity mSeverity; + static boost::filesystem::path *pathToLog; + static uint32 logRotateCounter; + public: Log(LogSeverity s) : mSeverity(s) { ; } @@ -51,6 +57,7 @@ public: static void setMinSeverity(LogSeverity); static void setLogFile(boost::filesystem::path); + static std::string rotateLog(void); }; #endif diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index c22c6b63cd..cc84f9f89a 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -104,9 +104,15 @@ public: return mMode >= omTRACKING; } + Ledger::pointer getCurrentLedger() { return mLedgerMaster->getCurrentLedger(); } + Ledger::pointer getLedgerByHash(const uint256& hash) { return mLedgerMaster->getLedgerByHash(hash); } + Ledger::pointer getLedgerBySeq(const uint32 seq) { return mLedgerMaster->getLedgerBySeq(seq); } + uint256 getClosedLedger() { return mLedgerMaster->getClosedLedger()->getHash(); } + SLE::pointer getSLE(Ledger::pointer lpLedger, const uint256& uHash) { return lpLedger->getSLE(uHash); } + // // Transaction operations // diff --git a/src/NewcoinAddress.h b/src/NewcoinAddress.h index 369b609d04..707a976c52 100644 --- a/src/NewcoinAddress.h +++ b/src/NewcoinAddress.h @@ -73,6 +73,9 @@ public: bool setAccountID(const std::string& strAccountID); void setAccountID(const uint160& hash160In); + static NewcoinAddress createAccountID(const std::string& strAccountID) + { NewcoinAddress na; na.setAccountID(strAccountID); return na; } + static NewcoinAddress createAccountID(const uint160& uiAccountID); static std::string createHumanAccountID(const uint160& uiAccountID) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index a2d81512ab..7f44f1fe58 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -14,6 +14,11 @@ #include "Log.h" #include "RippleLines.h" +#include "Pathfinder.h" +#include "Conversion.h" + +extern uint160 humanTo160(const std::string& buf); + #include #include @@ -1779,6 +1784,16 @@ Json::Value RPCServer::doSend(const Json::Value& params) STPathSet spsPaths; + uint160 srcCurrencyID; + bool ret_b; + ret_b = false; + STAmount::currencyFromString(srcCurrencyID, sSrcCurrency); + + Pathfinder pf(naSrcAccountID, naDstAccountID, srcCurrencyID, saDstAmount); + + ret_b = pf.findPaths(5, 1, spsPaths); + // TODO: Nope; the above can't be right + trans = Transaction::sharedPayment( naAccountPublic, naAccountPrivate, naSrcAccountID, @@ -2499,6 +2514,11 @@ Json::Value RPCServer::doLogin(const Json::Value& params) } } +Json::Value RPCServer::doLogRotate(const Json::Value& params) +{ + return Log::rotateLog(); +} + Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params) { Log(lsTRACE) << "RPC:" << command; @@ -2524,6 +2544,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { "data_fetch", &RPCServer::doDataFetch, 1, 1, true }, { "data_store", &RPCServer::doDataStore, 2, 2, true }, { "ledger", &RPCServer::doLedger, 0, 2, false, optNetwork }, + { "logrotate", &RPCServer::doLogRotate, 0, 0, true, optCurrent }, { "nickname_info", &RPCServer::doNicknameInfo, 1, 1, false, optCurrent }, { "nickname_set", &RPCServer::doNicknameSet, 2, 3, false, optCurrent }, { "offer_create", &RPCServer::doOfferCreate, 9, 10, false, optCurrent }, diff --git a/src/RPCServer.h b/src/RPCServer.h index 33f9699b03..8d56ed55aa 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -141,6 +141,7 @@ private: Json::Value doDataFetch(const Json::Value& params); Json::Value doDataStore(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); Json::Value doNicknameSet(const Json::Value& params); Json::Value doOfferCreate(const Json::Value& params); @@ -184,6 +185,7 @@ private: Json::Value doLogin(const Json::Value& params); + public: static pointer create(boost::asio::io_service& io_service, NetworkOPs* mNetOps) { diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index a44ee9098e..7e6960b831 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -567,11 +567,48 @@ void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvR void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest) { - // Get from request. - uint256 uLedger; + NetworkOPs& noNetwork = theApp->getOPs(); + uint256 uLedger = jvRequest.isMember("ledger") ? uint256(jvRequest["ledger"].asString()) : 0; + uint32 uLedgerIndex = jvRequest.isMember("ledger_index") && jvRequest["ledger_index"].isNumeric() ? jvRequest["ledger_index"].asUInt() : 0; - jvResult["ledger_index"] = theApp->getOPs().getLedgerID(uLedger); - jvResult["ledger"] = uLedger.ToString(); + Ledger::pointer lpLedger; + + if (!!uLedger) + { + // Ledger directly specified. + lpLedger = noNetwork.getLedgerByHash(uLedger); + + if (!lpLedger) + { + jvResult["error"] = "ledgerNotFound"; + return; + } + + uLedgerIndex = lpLedger->getLedgerSeq(); // Set the current index, override if needed. + } + else if (!!uLedgerIndex) + { + lpLedger = noNetwork.getLedgerBySeq(uLedgerIndex); + + if (!lpLedger) + { + jvResult["error"] = "ledgerNotFound"; // ledger_index from future? + return; + } + } + else + { + // Default to current ledger. + lpLedger = noNetwork.getCurrentLedger(); + uLedgerIndex = lpLedger->getLedgerSeq(); // Set the current index. + } + + if (!!uLedger) + jvResult["ledger"] = uLedger.ToString(); + + jvResult["ledger_index"] = uLedgerIndex; + + uint256 uNodeIndex; if (jvRequest.isMember("index")) { @@ -579,7 +616,16 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("account_root")) { - jvResult["error"] = "notImplemented"; + NewcoinAddress naAccount; + + if (!naAccount.setAccountID(jvRequest["account_root"].asString())) + { + jvResult["error"] = "malformedAddress"; + } + else + { + uNodeIndex = Ledger::getAccountRootIndex(naAccount.getAccountID()); + } } else if (jvRequest.isMember("directory")) { @@ -595,12 +641,48 @@ void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvReq } else if (jvRequest.isMember("ripple_state")) { - jvResult["error"] = "notImplemented"; + NewcoinAddress naA; + NewcoinAddress naB; + uint160 uCurrency; + + if (!jvRequest.isMember("accounts") + || !jvRequest.isMember("currency") + || !jvRequest["accounts"].isArray() + || 2 != jvRequest["accounts"].size()) { + jvResult["error"] = "malformedRequest"; + } + else if (!naA.setAccountID(jvRequest["accounts"][0u].asString()) + || !naB.setAccountID(jvRequest["accounts"][1u].asString())) { + jvResult["error"] = "malformedAddress"; + } + else if (!STAmount::currencyFromString(uCurrency, jvRequest["currency"].asString())) { + jvResult["error"] = "malformedCurrency"; + } + else + { + uNodeIndex = Ledger::getRippleStateIndex(naA, naB, uCurrency); + } } else { jvResult["error"] = "unknownOption"; } + + if (!!uNodeIndex) + { + SLE::pointer sleNode = noNetwork.getSLE(lpLedger, uNodeIndex); + + if (!sleNode) + { + // Not found. + // XXX We should also provide proof. + jvResult["error"] = "entryNotFound"; + } + else + { + jvResult["node"] = sleNode->getJson(0); + } + } } void WSConnection::doTransactionSubcribe(Json::Value& jvResult, const Json::Value& jvRequest) diff --git a/src/main.cpp b/src/main.cpp index b9154261d1..4a69f9f2da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -51,6 +51,7 @@ void printHelp(const po::options_description& desc) cout << " data_fetch " << endl; cout << " data_store " << endl; cout << " ledger [|current|lastclosed] [full]" << endl; + cout << " logrotate " << endl; cout << " nickname_info " << endl; cout << " nickname_set [] []" << endl; cout << " offer_create [passive]" << endl; diff --git a/test/standalone-test.js b/test/standalone-test.js index ffa593840d..a3fb947498 100644 --- a/test/standalone-test.js +++ b/test/standalone-test.js @@ -1,5 +1,3 @@ -// console.log("standalone-test.js>"); - var fs = require("fs"); var buster = require("buster"); @@ -59,9 +57,6 @@ buster.testCase("WebSocket connection", { }, }); -// XXX Figure out a way to stuff this into the test case. -var alpha; - buster.testCase("Websocket commands", { 'setUp' : function(done) { @@ -92,16 +87,6 @@ buster.testCase("Websocket commands", { }); }, - 'ledger_closed' : - function(done) { - alpha.ledger_closed(function (r) { - console.log(r); - - buster.assert(r.ledger === 1); - done(); - }); - }, - 'ledger_current' : function(done) { alpha.ledger_current(function (r) { @@ -112,7 +97,7 @@ buster.testCase("Websocket commands", { }); }, - 'ledger_closed' : + '// ledger_closed' : function(done) { alpha.ledger_closed(function (r) { console.log("result: %s", JSON.stringify(r)); @@ -121,46 +106,63 @@ buster.testCase("Websocket commands", { done(); }); }, -}); -buster.testCase("// Work in progress", { - 'setUp' : + 'account_root success' : function(done) { - server.start("alpha", - function(e) { - buster.refute(e); + alpha.ledger_closed(function (r) { + // console.log("result: %s", JSON.stringify(r)); - alpha = remote.remoteConfig(config, "alpha"); + buster.refute('error' in r); - alpha.connect(function(stat) { - buster.assert(1 == stat); // OPEN + alpha.ledger_entry({ + 'ledger_index' : r.ledger_index, + 'account_root' : 'iHb9CJAWyB4ij91VRWn96DkukG4bwdtyTh' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); + buster.assert('node' in r); done(); - }, serverDelay); - }); - }, - - 'tearDown' : - function(done) { - alpha.disconnect(function(stat) { - buster.assert(3 == stat); // CLOSED - - server.stop("alpha", function(e) { - buster.refute(e); - - done(); - }); + }); }); }, - 'ledger_closed' : + 'account_root malformedAddress' : function(done) { alpha.ledger_closed(function (r) { - console.log("result: %s", JSON.stringify(r)); + // console.log("result: %s", JSON.stringify(r)); - buster.assert.equals(r.ledger_index, 2); - done(); + buster.refute('error' in r); + + alpha.ledger_entry({ + 'ledger_index' : r.ledger_index, + 'account_root' : 'foobar' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); + + buster.assert.equals(r.error, 'malformedAddress'); + done(); + }); + }); + }, + + 'account_root entryNotFound' : + function(done) { + alpha.ledger_closed(function (r) { + // console.log("result: %s", JSON.stringify(r)); + + buster.refute('error' in r); + + alpha.ledger_entry({ + 'ledger_index' : r.ledger_index, + 'account_root' : 'iG1QQv2nh2gi7RCZ1P8YYcBUKCCN633jCn' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); + + buster.assert.equals(r.error, 'entryNotFound'); + done(); + }); }); }, }); + // vim:ts=4 diff --git a/websocketpp b/websocketpp index f78b9df4ad..dd9899c34b 160000 --- a/websocketpp +++ b/websocketpp @@ -1 +1 @@ -Subproject commit f78b9df4adbc354f5fdf8c2c8b9e76549f977cb8 +Subproject commit dd9899c34bb1f86caf486735b136a5460b4760db