diff --git a/js/remote.js b/js/remote.js index d1fa4430cc..ffab43eaad 100644 --- a/js/remote.js +++ b/js/remote.js @@ -82,7 +82,7 @@ Remote.method('connect_helper', function() { self.done(ws.readyState); }; - // XXX Why doesn't onmessage work? + // Node's ws module doesn't pass arguments to onmessage. ws.on('message', function(json, flags) { var message = JSON.parse(json); // console.log("message: %s", json); @@ -167,11 +167,28 @@ Remote.method('request', function(command, done) { ws.send(JSON.stringify(command)); }); -// Get the current ledger entry (may be live or not). +Remote.method('ledger_closed', function(done) { + assert(this.trusted); // If not trusted, need to check proof. + + this.request({ 'command' : 'ledger_closed' }, done); +}); + +// Get the current proposed ledger entry. May be closed (and revised) at any time (even before returning). +// Only for use by unit tests. 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) @@ -182,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/src/Amount.cpp b/src/Amount.cpp index f0692f2af7..637d4ef52d 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/Ledger.cpp b/src/Ledger.cpp index b419a493fc..e650f9b94f 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -21,7 +21,7 @@ #include "Log.h" -Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(0), +Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mLedgerSeq(1), mCloseTime(0), mParentCloseTime(0), mCloseResolution(LEDGER_TIME_ACCURACY), mCloseFlags(0), mClosed(false), mValidHash(false), mAccepted(false), mImmutable(false), mTransactionMap(new SHAMap()), mAccountStateMap(new SHAMap()) diff --git a/src/LedgerMaster.h b/src/LedgerMaster.h index 37db69c5c2..76e6327381 100644 --- a/src/LedgerMaster.h +++ b/src/LedgerMaster.h @@ -66,10 +66,15 @@ public: Ledger::pointer getLedgerByHash(const uint256& hash) { + if (!hash) + return mCurrentLedger; + if (mCurrentLedger && (mCurrentLedger->getHash() == hash)) return mCurrentLedger; + if (mFinalizedLedger && (mFinalizedLedger->getHash() == hash)) return mFinalizedLedger; + return mLedgerHistory.getLedgerByHash(hash); } diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 0433892263..9988a03925 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -67,6 +67,13 @@ void NetworkOPs::closeTimeOffset(int offset) Log(lsINFO) << "Close time offset now " << mCloseTimeOffset; } +uint32 NetworkOPs::getLedgerID(const uint256& hash) +{ + Ledger::ref lrLedger = mLedgerMaster->getLedgerByHash(hash); + + return lrLedger ? lrLedger->getLedgerSeq() : 0; +} + uint32 NetworkOPs::getCurrentLedgerID() { return mLedgerMaster->getCurrentLedger()->getLedgerSeq(); diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 43b7da9f4e..cc84f9f89a 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -96,6 +96,7 @@ public: uint32 getValidationTimeNC(); void closeTimeOffset(int); boost::posix_time::ptime getNetworkTimePT(); + uint32 getLedgerID(const uint256& hash); uint32 getCurrentLedgerID(); OperatingMode getOperatingMode() { return mMode; } inline bool available() { @@ -103,13 +104,14 @@ 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(); } - // FIXME: This function is basically useless since the hash is constantly changing and the ledger - // is ephemeral and mutable. - uint256 getCurrentLedger() - { return mLedgerMaster->getCurrentLedger()->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 ad845ac8f9..7f44f1fe58 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -427,7 +427,6 @@ Json::Value RPCServer::doAccountDomainSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -443,7 +442,7 @@ Json::Value RPCServer::doAccountDomainSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -481,7 +480,6 @@ Json::Value RPCServer::doAccountEmailSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -497,7 +495,7 @@ Json::Value RPCServer::doAccountEmailSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -574,12 +572,11 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) ret["accepted"] = jAccepted; - uint256 uCurrent = mNetOps->getCurrentLedger(); - Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + Json::Value jCurrent = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex); if (jCurrent.empty()) { - AccountState::pointer asCurrent = mNetOps->getAccountState(uCurrent, naAccount); + AccountState::pointer asCurrent = mNetOps->getAccountState(uint256(0), naAccount); if (asCurrent) asCurrent->addJson(jCurrent); @@ -603,7 +600,6 @@ Json::Value RPCServer::doAccountInfo(const Json::Value ¶ms) Json::Value RPCServer::doAccountMessageSet(const Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); NewcoinAddress naMessagePubKey; if (!naSeed.setSeedGeneric(params[0u].asString())) @@ -624,7 +620,7 @@ Json::Value RPCServer::doAccountMessageSet(const Json::Value& params) { NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); std::vector vucDomain; @@ -664,7 +660,6 @@ Json::Value RPCServer::doAccountPublishSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -680,7 +675,7 @@ Json::Value RPCServer::doAccountPublishSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -722,7 +717,6 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -738,7 +732,7 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -778,7 +772,6 @@ Json::Value RPCServer::doAccountRateSet(const Json::Value ¶ms) Json::Value RPCServer::doAccountWalletSet(const Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -794,7 +787,7 @@ Json::Value RPCServer::doAccountWalletSet(const Json::Value& params) { NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); std::vector vucDomain; @@ -926,8 +919,6 @@ Json::Value RPCServer::doDataStore(const Json::Value& params) // Note: Nicknames are not automatically looked up by commands as they are advisory and can be changed. Json::Value RPCServer::doNicknameInfo(const Json::Value& params) { - uint256 uLedger = mNetOps->getCurrentLedger(); - std::string strNickname = params[0u].asString(); boost::trim(strNickname); @@ -936,7 +927,7 @@ Json::Value RPCServer::doNicknameInfo(const Json::Value& params) return RPCError(rpcNICKNAME_MALFORMED); } - NicknameState::pointer nsSrc = mNetOps->getNicknameState(uLedger, strNickname); + NicknameState::pointer nsSrc = mNetOps->getNicknameState(uint256(0), strNickname); if (!nsSrc) { return RPCError(rpcNICKNAME_MISSING); @@ -956,7 +947,6 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -984,7 +974,7 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) } STAmount saFee; - NicknameState::pointer nsSrc = mNetOps->getNicknameState(uLedger, strNickname); + NicknameState::pointer nsSrc = mNetOps->getNicknameState(uint256(0), strNickname); if (!nsSrc) { @@ -1007,7 +997,7 @@ Json::Value RPCServer::doNicknameSet(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, saFee, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1073,7 +1063,7 @@ Json::Value RPCServer::doOfferCreate(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(mNetOps->getCurrentLedger(), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1119,7 +1109,7 @@ Json::Value RPCServer::doOfferCancel(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(mNetOps->getCurrentLedger(), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1159,10 +1149,9 @@ Json::Value RPCServer::doOwnerInfo(const Json::Value& params) ret["accepted"] = jAccepted.empty() ? mNetOps->getOwnerInfo(uAccepted, naAccount) : jAccepted; - uint256 uCurrent = mNetOps->getCurrentLedger(); - Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + Json::Value jCurrent = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex); - ret["current"] = jCurrent.empty() ? mNetOps->getOwnerInfo(uCurrent, naAccount) : jCurrent; + ret["current"] = jCurrent.empty() ? mNetOps->getOwnerInfo(uint256(0), naAccount) : jCurrent; return ret; } @@ -1173,7 +1162,6 @@ Json::Value RPCServer::doPasswordFund(const Json::Value ¶ms) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -1193,7 +1181,7 @@ Json::Value RPCServer::doPasswordFund(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1499,8 +1487,7 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) return RPCError(rpcDST_AMT_MALFORMED); } - uint256 uLedger = mNetOps->getCurrentLedger(); - AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID); + AccountState::pointer asDst = mNetOps->getAccountState(uint256(0), naDstAccountID); STAmount saFee = theConfig.FEE_DEFAULT; NewcoinAddress naVerifyGenerator; @@ -1508,7 +1495,7 @@ Json::Value RPCServer::doRipple(const Json::Value ¶ms) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, saFee, asSrc, naVerifyGenerator); if (!obj.empty()) @@ -1561,7 +1548,6 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; STAmount saLimitAmount; - uint256 uLedger = mNetOps->getCurrentLedger(); bool bLimitAmount = true; bool bQualityIn = params.size() >= 6; bool bQualityOut = params.size() >= 7; @@ -1599,7 +1585,7 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); if (!obj.empty()) @@ -1632,7 +1618,6 @@ Json::Value RPCServer::doRippleLineSet(const Json::Value& params) Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) { // uint256 uAccepted = mNetOps->getClosedLedger(); - uint256 uCurrent = mNetOps->getCurrentLedger(); std::string strIdent = params[0u].asString(); bool bIndex; @@ -1642,7 +1627,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) Json::Value ret; - ret = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + ret = accountFromString(uint256(0), naAccount, bIndex, strIdent, iIndex); if (!ret.empty()) return ret; @@ -1654,7 +1639,7 @@ Json::Value RPCServer::doRippleLinesGet(const Json::Value ¶ms) if (bIndex) ret["index"] = iIndex; - AccountState::pointer as = mNetOps->getAccountState(uCurrent, naAccount); + AccountState::pointer as = mNetOps->getAccountState(uint256(0), naAccount); if (as) { Json::Value jsonLines(Json::arrayValue); @@ -1744,8 +1729,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) } else { - uint256 uLedger = mNetOps->getCurrentLedger(); - AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID); + AccountState::pointer asDst = mNetOps->getAccountState(uint256(0), naDstAccountID); bool bCreate = !asDst; STAmount saFee = bCreate ? theConfig.FEE_ACCOUNT_CREATE : theConfig.FEE_DEFAULT; @@ -1754,7 +1738,7 @@ Json::Value RPCServer::doSend(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, saFee, asSrc, naVerifyGenerator); // Log(lsINFO) << boost::str(boost::format("doSend: sSrcIssuer=%s sDstIssuer=%s saSrcAmountMax=%s saDstAmount=%s") @@ -2096,7 +2080,6 @@ Json::Value RPCServer::accounts(const uint256& uLedger, const NewcoinAddress& na Json::Value RPCServer::doWalletAccounts(const Json::Value& params) { NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -2106,17 +2089,17 @@ Json::Value RPCServer::doWalletAccounts(const Json::Value& params) // Try the seed as a master seed. NewcoinAddress naMasterGenerator = NewcoinAddress::createGeneratorPublic(naSeed); - Json::Value jsonAccounts = accounts(uLedger, naMasterGenerator); + Json::Value jsonAccounts = accounts(uint256(0), naMasterGenerator); if (jsonAccounts.empty()) { // No account via seed as master, try seed a regular. - Json::Value ret = getMasterGenerator(uLedger, naSeed, naMasterGenerator); + Json::Value ret = getMasterGenerator(uint256(0), naSeed, naMasterGenerator); if (!ret.empty()) return ret; - ret["accounts"] = accounts(uLedger, naMasterGenerator); + ret["accounts"] = accounts(uint256(0), naMasterGenerator); return ret; } @@ -2139,7 +2122,6 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params) NewcoinAddress naSrcAccountID; STAmount saAmount; std::string sDstCurrency; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naRegularSeed.setSeedGeneric(params[0u].asString())) { @@ -2166,7 +2148,7 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naRegularSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naRegularSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_ACCOUNT_CREATE, asSrc, naMasterGenerator); if (!obj.empty()) @@ -2192,7 +2174,7 @@ Json::Value RPCServer::doWalletAdd(const Json::Value& params) ++iIndex; naNewAccountPublic.setAccountPublic(naMasterGenerator, iIndex); - asNew = mNetOps->getAccountState(uLedger, naNewAccountPublic); + asNew = mNetOps->getAccountState(uint256(0), naNewAccountPublic); if (!asNew) bAgain = false; } while (bAgain); @@ -2327,7 +2309,6 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; NewcoinAddress naSeed; - uint256 uLedger = mNetOps->getCurrentLedger(); if (!naSeed.setSeedGeneric(params[0u].asString())) { @@ -2341,7 +2322,7 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) { return RPCError(rpcDST_ACT_MALFORMED); } - else if (mNetOps->getAccountState(uLedger, naDstAccountID)) + else if (mNetOps->getAccountState(uint256(0), naDstAccountID)) { return RPCError(rpcACT_EXISTS); } @@ -2354,7 +2335,7 @@ Json::Value RPCServer::doWalletCreate(const Json::Value& params) NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + Json::Value obj = authorize(uint256(0), naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, saSrcBalance, theConfig.FEE_ACCOUNT_CREATE, asSrc, naMasterGenerator); if (!obj.empty()) @@ -2623,7 +2604,8 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { return RPCError(rpcNO_NETWORK); } - else if ((commandsA[i].iOptions & optCurrent) && mNetOps->getCurrentLedger().isZero()) + // XXX Should verify we have a current ledger. + else if ((commandsA[i].iOptions & optCurrent) && false) { return RPCError(rpcNO_CURRENT); } diff --git a/src/WSDoor.cpp b/src/WSDoor.cpp index bea4e7ed27..7e6960b831 100644 --- a/src/WSDoor.cpp +++ b/src/WSDoor.cpp @@ -76,7 +76,9 @@ public: boost::unordered_set parseAccountIds(const Json::Value& jvArray); // Request-Response Commands + void doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRequest); void doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest); + void doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest); // Streaming Commands void doAccountInfoSubscribe(Json::Value& jvResult, const Json::Value& jvRequest); @@ -297,7 +299,9 @@ Json::Value WSConnection::invokeCommand(const Json::Value& jvRequest) doFuncPtr dfpFunc; } commandsA[] = { // Request-Response Commands: - { "ledger_current", &WSConnection::doLedgerCurrent }, + { "ledger_closed", &WSConnection::doLedgerClosed }, + { "ledger_current", &WSConnection::doLedgerCurrent }, + { "ledger_entry", &WSConnection::doLedgerEntry }, // Streaming commands: { "account_info_subscribe", &WSConnection::doAccountInfoSubscribe }, @@ -548,9 +552,137 @@ void WSConnection::doLedgerAccountsUnsubscribe(Json::Value& jvResult, const Json } } +void WSConnection::doLedgerClosed(Json::Value& jvResult, const Json::Value& jvRequest) +{ + uint256 uLedger = theApp->getOPs().getClosedLedger(); + + jvResult["ledger_index"] = theApp->getOPs().getLedgerID(uLedger); + jvResult["ledger"] = uLedger.ToString(); +} + void WSConnection::doLedgerCurrent(Json::Value& jvResult, const Json::Value& jvRequest) { - jvResult["ledger"] = theApp->getOPs().getCurrentLedgerID(); + jvResult["ledger_index"] = theApp->getOPs().getCurrentLedgerID(); +} + +void WSConnection::doLedgerEntry(Json::Value& jvResult, const Json::Value& jvRequest) +{ + 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; + + 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")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("account_root")) + { + NewcoinAddress naAccount; + + if (!naAccount.setAccountID(jvRequest["account_root"].asString())) + { + jvResult["error"] = "malformedAddress"; + } + else + { + uNodeIndex = Ledger::getAccountRootIndex(naAccount.getAccountID()); + } + } + else if (jvRequest.isMember("directory")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("generator")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("offer")) + { + jvResult["error"] = "notImplemented"; + } + else if (jvRequest.isMember("ripple_state")) + { + 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/test/standalone-test.js b/test/standalone-test.js index 2a725dffac..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,15 +87,82 @@ buster.testCase("Websocket commands", { }); }, - "ledger_current" : + 'ledger_current' : function(done) { alpha.ledger_current(function (r) { console.log(r); - buster.assert(r.ledger === 2); + buster.assert.equals(r.ledger_index, 3); done(); }); - } + }, + + '// ledger_closed' : + function(done) { + alpha.ledger_closed(function (r) { + console.log("result: %s", JSON.stringify(r)); + + buster.assert.equals(r.ledger_index, 2); + done(); + }); + }, + + 'account_root success' : + 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' : 'iHb9CJAWyB4ij91VRWn96DkukG4bwdtyTh' + } , function (r) { + // console.log("account_root: %s", JSON.stringify(r)); + + buster.assert('node' in r); + done(); + }); + }); + }, + + 'account_root malformedAddress' : + 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' : '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