From 96cb82ce1965f2e58eb7428f865fff5b6c230e95 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 9 Jun 2012 15:04:24 -0700 Subject: [PATCH 01/23] Have RPC send automatically create accounts. --- src/RPCServer.cpp | 67 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index b071c83c8..5070331c4 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -209,11 +209,13 @@ Json::Value RPCServer::getMasterGenerator(const uint256& uLedger, const NewcoinA } // Given a seed and a source account get the regular public and private key for authorizing transactions. +// - Make sure the source account can pay. // --> naRegularSeed : To find the generator // --> naSrcAccountID : Account we want the public and private regular keys to. // --> naVerifyGenerator : If provided, the found master public generator must match. // <-- naAccountPublic : Regular public key for naSrcAccountID // <-- naAccountPrivate : Regular private key for naSrcAccountID +// <-- saSrcBalance: Balance minus fee. Json::Value RPCServer::authorize(const uint256& uLedger, const NewcoinAddress& naRegularSeed, const NewcoinAddress& naSrcAccountID, NewcoinAddress& naAccountPublic, NewcoinAddress& naAccountPrivate, @@ -1235,11 +1237,11 @@ Json::Value RPCServer::doSend(Json::Value& params) } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { - return JSONRPCError(500, "source account id needed"); + return JSONRPCError(500, "source account id malformed"); } else if (!naDstAccountID.setAccountID(params[2u].asString())) { - return JSONRPCError(500, "create account id needed"); + return JSONRPCError(500, "destination account id malformed"); } else if (!saDstAmount.setValue(params[3u].asString(), sDstCurrency)) { @@ -1259,13 +1261,17 @@ Json::Value RPCServer::doSend(Json::Value& params) } else { + AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naSrcAccountID); + bool bCreate = !asDst; + STAmount saFee = bCreate ? theConfig.FEE_DEFAULT : theConfig.FEE_ACCOUNT_CREATE; + NewcoinAddress naMasterGenerator; NewcoinAddress naAccountPublic; NewcoinAddress naAccountPrivate; AccountState::pointer asSrc; STAmount saSrcBalance; - Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, - saSrcBalance, theConfig.FEE_DEFAULT, asSrc, naMasterGenerator); + Json::Value obj = authorize(uLedger, naSeed, naSrcAccountID, naAccountPublic, naAccountPrivate, + saSrcBalance, saFee, asSrc, naMasterGenerator); if (!obj.empty()) return obj; @@ -1273,25 +1279,54 @@ Json::Value RPCServer::doSend(Json::Value& params) if (params.size() < 6) saSrcAmount = saDstAmount; - // XXX Confirm saSrcAmount >= saDstAmount. + if (saSrcBalance < saDstAmount) + { + return JSONRPCError(500, "Insufficient funds."); + } - STPathSet spPaths; - Transaction::pointer trans = Transaction::sharedPayment( - naAccountPublic, naAccountPrivate, - naSrcAccountID, - asSrc->getSeq(), - theConfig.FEE_DEFAULT, - 0, // YYY No source tag - naDstAccountID, - saDstAmount, - saSrcAmount, - spPaths); + Transaction::pointer trans; + + if (asDst) { + // Ordinary send. + + STPathSet spPaths; + + trans = Transaction::sharedPayment( + naAccountPublic, naAccountPrivate, + naSrcAccountID, + asSrc->getSeq(), + saFee, + 0, // YYY No source tag + naDstAccountID, + saDstAmount, + saSrcAmount, + spPaths); + } + else if (!saDstAmount.isNative()) + { + return JSONRPCError(500, "Can only send XNS to accounts which are not created."); + } + else + { + // Create and send. + + trans = Transaction::sharedCreate( + naAccountPublic, naAccountPrivate, + naSrcAccountID, + asSrc->getSeq(), + saFee, + 0, // YYY No source tag + naDstAccountID, + saDstAmount); // Initial funds in XNC. + } (void) mNetOps->processTransaction(trans); obj["transaction"] = trans->getSTransaction()->getJson(0); obj["status"] = trans->getStatus(); obj["seed"] = naSeed.humanFamilySeed(); + obj["fee"] = saFee.getText(); + obj["create"] = bCreate; obj["srcAccountID"] = naSrcAccountID.humanAccountID(); obj["dstAccountID"] = naDstAccountID.humanAccountID(); obj["srcAmount"] = saSrcAmount.getText(); From 34b0a88b860a9c4841f9edadbe39b3dab8ac61d2 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 9 Jun 2012 15:23:44 -0700 Subject: [PATCH 02/23] Fix create on send. --- src/RPCServer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index ca9d9fa8c..c098ec507 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1261,9 +1261,9 @@ Json::Value RPCServer::doSend(Json::Value& params) } else { - AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naSrcAccountID); + AccountState::pointer asDst = mNetOps->getAccountState(uLedger, naDstAccountID); bool bCreate = !asDst; - STAmount saFee = bCreate ? theConfig.FEE_DEFAULT : theConfig.FEE_ACCOUNT_CREATE; + STAmount saFee = bCreate ? theConfig.FEE_ACCOUNT_CREATE : theConfig.FEE_DEFAULT; NewcoinAddress naMasterGenerator; NewcoinAddress naAccountPublic; From 380902536f54a23652d1efb8d8e6f2188d969999 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 16:58:04 -0700 Subject: [PATCH 03/23] Framework for account_tx command. --- src/NetworkOPs.cpp | 8 ++++++ src/NetworkOPs.h | 4 +++ src/RPCServer.cpp | 65 +++++++++++++++++++++++++++++++++++++++++----- src/RPCServer.h | 2 ++ 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 85508664f..624145d92 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -528,4 +528,12 @@ void NetworkOPs::setMode(OperatingMode om) mMode = om; } +std::vector< std::pair > + NetworkOPs::getAffectedAccounts(const NewcoinAddress& account, uint32 minLedger, uint32 maxLedger) +{ + // WRITEME + std::vector< std::pair > affectedAccounts; + return affectedAccounts; +} + // vim:ts=4 diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 005ef02a9..1dddca15e 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -125,6 +125,10 @@ public: int beginConsensus(Ledger::pointer closingLedger); void endConsensus(); void setStateTimer(int seconds); + + // client information retrieval functions + std::vector< std::pair > + getAffectedAccounts(const NewcoinAddress& account, uint32 minLedger, uint32 maxLedger); }; #endif diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 6ba9ad38d..b09f4d987 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -319,7 +319,7 @@ Json::Value RPCServer::accountFromString(const uint256& uLedger, NewcoinAddress& naRegular0Public.setAccountPublic(naGenerator, 0); naRegular0Private.setAccountPrivate(naGenerator, naSeed, 0); - uint160 uGeneratorID = naRegular0Public.getAccountID(); +// uint160 uGeneratorID = naRegular0Public.getAccountID(); SLE::pointer sleGen = mNetOps->getGenerator(uLedger, naRegular0Public.getAccountID()); if (!sleGen) { @@ -1145,7 +1145,7 @@ Json::Value RPCServer::doPasswordSet(Json::Value& params) naRegular0Private.setAccountPrivate(naRegularGenerator, naRegularSeed, 0); // Hash of regular account #0 public key. - uint160 uGeneratorID = naRegular0Public.getAccountID(); +// uint160 uGeneratorID = naRegular0Public.getAccountID(); std::vector vucGeneratorCipher = naRegular0Private.accountPrivateEncrypt(naRegular0Public, naMasterGenerator.getFamilyGenerator()); std::vector vucGeneratorSig; @@ -1418,7 +1418,7 @@ Json::Value RPCServer::doLedger(Json::Value& params) { return "invalid params"; } - else if (!mNetOps->available()) + if (!mNetOps->available()) { return JSONRPCError(503, "network not available"); } @@ -1464,6 +1464,59 @@ Json::Value RPCServer::doLedger(Json::Value& params) return ret; } +// account_tx +// account_tx +Json::Value RPCServer::doAccountTransactions(Json::Value& params) +{ + std::string param; + uint32 minLedger, maxLedger; + + if ((params.size() < 2) || (params.size() > 3) || !extractString(param, params, 0)) + return "invalid params"; + + if (!mNetOps->available()) + { + return JSONRPCError(503, "network not available"); + } + + NewcoinAddress account; + if (!account.setAccountID(param)) + return JSONRPCError(500, "invalid account"); + + if (!extractString(param, params, 1)) + minLedger = boost::lexical_cast(param); + + if ((params.size() == 3) && extractString(param, params, 2)) + maxLedger = boost::lexical_cast(param); + else + maxLedger = minLedger; + + if ((maxLedger < minLedger) || (minLedger == 0) || (maxLedger == 0)) + return JSONRPCError(500, "invalid ledger indexes"); + + try + { + std::vector< std::pair > txns = + mNetOps->getAffectedAccounts(account, minLedger, maxLedger); + Json::Value ret(Json::objectValue); + ret["Account"] = account.humanAccountID(); + Json::Value jtxns(Json::arrayValue); + for (std::vector< std::pair >::iterator it = txns.begin(), + end = txns.end(); it != end; ++it) + { + Json::Value txn = it->second->getJson(0); + txn["InLedger"] = it->first; + jtxns.append(txn); + } + ret["Transactions"] = jtxns; + return ret; + } + catch (...) + { + return JSONRPCError(500, "internal error"); + } +} + // unl_add | [] Json::Value RPCServer::doUnlAdd(Json::Value& params) { @@ -2143,13 +2196,13 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params if (command == "wallet_propose") return doWalletPropose(params); if (command == "wallet_seed") return doWalletSeed(params); - if (command=="ledger") return doLedger(params); - + if (command == "ledger") return doLedger(params); + if (command == "account_tx") return doAccountTransactions(params); // // Obsolete or need rewrite: // - if (command=="tx") return doTx(params); + if (command == "tx") return doTx(params); return "unknown command"; } diff --git a/src/RPCServer.h b/src/RPCServer.h index 4af47f84d..5a2af47d8 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -91,6 +91,8 @@ private: Json::Value doWalletUnlock(Json::Value& params); Json::Value doWalletVerify(Json::Value& params); + Json::Value doAccountTransactions(Json::Value& params); + void validatorsResponse(const boost::system::error_code& err, std::string strResponse); public: From e2288acfd1100211d3867a32a16b2e8798d474ec Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 17:59:24 -0700 Subject: [PATCH 04/23] More work on account_tx command. --- src/NetworkOPs.cpp | 25 ++++++++++++++++++++++--- src/NetworkOPs.h | 2 +- src/RPCServer.cpp | 33 ++++++++++++++++++++++++++------- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 624145d92..0e7c6c5ff 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -528,11 +528,30 @@ void NetworkOPs::setMode(OperatingMode om) mMode = om; } -std::vector< std::pair > +#define SQL_FOREACH(_db, _strQuery) \ + if ((_db)->executeSQL(_strQuery)) \ + for (bool _bMore = (db)->startIterRows(); _bMore; _bMore = (_db)->getNextRow()) + +std::vector< std::pair > NetworkOPs::getAffectedAccounts(const NewcoinAddress& account, uint32 minLedger, uint32 maxLedger) { - // WRITEME - std::vector< std::pair > affectedAccounts; + std::vector< std::pair > affectedAccounts; + + std::string sql = + str(boost::format("SELECT LedgerSeq,TransID FROM AccountTransactions INDEXED BY AcctTxIndex " + " WHERE Account = % AND LedgerSeq <= % AND LedgerSeq >= % ORDER BY LedgerSeq LIMIT 1000") + % account.humanAccountID() % minLedger % maxLedger); + + Database *db = theApp->getAcctTxnDB()->getDB(); + ScopedLock dbLock = theApp->getAcctTxnDB()->getDBLock(); + + SQL_FOREACH(db, sql) + { + std::string txID; + db->getStr("TransID", txID); + affectedAccounts.push_back(std::make_pair(db->getInt("LedgerSeq"), uint256(txID))); + } + return affectedAccounts; } diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 1dddca15e..0514a0902 100644 --- a/src/NetworkOPs.h +++ b/src/NetworkOPs.h @@ -127,7 +127,7 @@ public: void setStateTimer(int seconds); // client information retrieval functions - std::vector< std::pair > + std::vector< std::pair > getAffectedAccounts(const NewcoinAddress& account, uint32 minLedger, uint32 maxLedger); }; diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index b09f4d987..49812e0e7 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1496,19 +1496,38 @@ Json::Value RPCServer::doAccountTransactions(Json::Value& params) try { - std::vector< std::pair > txns = + std::vector< std::pair > txns = mNetOps->getAffectedAccounts(account, minLedger, maxLedger); Json::Value ret(Json::objectValue); ret["Account"] = account.humanAccountID(); - Json::Value jtxns(Json::arrayValue); - for (std::vector< std::pair >::iterator it = txns.begin(), + Json::Value ledgers(Json::arrayValue); + + uint32 currentLedger = 0; + Json::Value ledger, jtxns; + for (std::vector< std::pair >::iterator it = txns.begin(), end = txns.end(); it != end; ++it) { - Json::Value txn = it->second->getJson(0); - txn["InLedger"] = it->first; - jtxns.append(txn); + if (it->first != currentLedger) + { // new ledger + if (currentLedger != 0) // add old ledger + { + ledger["Transactions"] = jtxns; + ledgers.append(ledger); + ledger = Json::objectValue; + } + currentLedger = it->first; + ledger["ID"] = currentLedger; + jtxns = Json::arrayValue; + } + jtxns.append(it->second.GetHex()); } - ret["Transactions"] = jtxns; + if (currentLedger != 0) + { + ledger["Transactions"] = jtxns; + ledgers.append(ledger); + } + + ret["Ledgers"] = ledgers; return ret; } catch (...) From 20499106f045f3963f87a235651989f1ff6e6c73 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 18:04:44 -0700 Subject: [PATCH 05/23] Bugfixes. --- src/NetworkOPs.cpp | 2 +- src/RPCServer.cpp | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 0e7c6c5ff..d2e93f926 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -539,7 +539,7 @@ std::vector< std::pair > std::string sql = str(boost::format("SELECT LedgerSeq,TransID FROM AccountTransactions INDEXED BY AcctTxIndex " - " WHERE Account = % AND LedgerSeq <= % AND LedgerSeq >= % ORDER BY LedgerSeq LIMIT 1000") + " WHERE Account = %s AND LedgerSeq <= %d AND LedgerSeq >= %d ORDER BY LedgerSeq LIMIT 1000") % account.humanAccountID() % minLedger % maxLedger); Database *db = theApp->getAcctTxnDB()->getDB(); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 49812e0e7..d67425498 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1484,7 +1484,8 @@ Json::Value RPCServer::doAccountTransactions(Json::Value& params) return JSONRPCError(500, "invalid account"); if (!extractString(param, params, 1)) - minLedger = boost::lexical_cast(param); + return JSONRPCError(500, "invalid ledger index"); + minLedger = boost::lexical_cast(param); if ((params.size() == 3) && extractString(param, params, 2)) maxLedger = boost::lexical_cast(param); @@ -1492,10 +1493,15 @@ Json::Value RPCServer::doAccountTransactions(Json::Value& params) maxLedger = minLedger; if ((maxLedger < minLedger) || (minLedger == 0) || (maxLedger == 0)) + { + std::cerr << "minL=" << minLedger << ", maxL=" << maxLedger << std::endl; return JSONRPCError(500, "invalid ledger indexes"); + } +#ifndef DEBUG try { +#endif std::vector< std::pair > txns = mNetOps->getAffectedAccounts(account, minLedger, maxLedger); Json::Value ret(Json::objectValue); @@ -1529,11 +1535,13 @@ Json::Value RPCServer::doAccountTransactions(Json::Value& params) ret["Ledgers"] = ledgers; return ret; +#ifndef DEBUG } catch (...) { return JSONRPCError(500, "internal error"); } +#endif } // unl_add | [] From 9739eea860effcc26178eba1c332f45495045742 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 18:08:16 -0700 Subject: [PATCH 06/23] More sensible name --- src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Application.cpp b/src/Application.cpp index 5b27580c9..97e0f47d8 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -61,7 +61,7 @@ void Application::run() // Construct databases. // mTxnDB = new DatabaseCon("transaction.db", TxnDBInit, TxnDBCount); - mAcctTxnDB = new DatabaseCon("transacct.db", AcctTxnDBInit, AcctTxnDBCount); + mAcctTxnDB = new DatabaseCon("accttx.db", AcctTxnDBInit, AcctTxnDBCount); mLedgerDB = new DatabaseCon("ledger.db", LedgerDBInit, LedgerDBCount); mWalletDB = new DatabaseCon("wallet.db", WalletDBInit, WalletDBCount); mHashNodeDB = new DatabaseCon("hashnode.db", HashNodeDBInit, HashNodeDBCount); From 8d8d2c6691ad0ef4d1d96b263179ecb8d53ab5ee Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 18:14:32 -0700 Subject: [PATCH 07/23] Bugfixes. --- src/LedgerConsensus.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index bd15efe5f..ea148163e 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -731,7 +731,7 @@ void LedgerConsensus::accept(SHAMap::pointer set) // Insert the transactions in set into the AcctTxn database Database *db = theApp->getAcctTxnDB()->getDB(); ScopedLock dbLock = theApp->getAcctTxnDB()->getDBLock(); - db->executeSQL("BEGIN TRANSACTION"); + db->executeSQL("BEGIN TRANSACTION;"); for (SHAMapItem::pointer item = set->peekFirstItem(); !!item; item = set->peekNextItem(item->getTag())) { SerializerIterator sit(item->peekSerializer()); @@ -742,19 +742,25 @@ void LedgerConsensus::accept(SHAMap::pointer set) bool first = true; for (std::vector::iterator it = accts.begin(), end = accts.end(); it != end; ++it) { - if (!first) sql += ", ("; - else sql += "("; + if (!first) + sql += ", ("; + else + { + sql += "('"; + first = false; + } sql += txn.getTransactionID().GetHex(); - sql += ","; + sql += "','"; sql += it->humanAccountID(); - sql += ","; + sql += "','"; sql += boost::lexical_cast(newLedgerSeq); - sql += ")"; + sql += "')"; } sql += ";"; + Log(lsTRACE) << "ActTx: " << sql; db->executeSQL(sql); } - db->executeSQL("COMMIT TRANSACTION"); + db->executeSQL("COMMIT TRANSACTION;"); } void LedgerConsensus::endConsensus() From d888cc2da8dbbf267457308b0a053a2e82d3456d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 18:28:34 -0700 Subject: [PATCH 08/23] Bugfixes. --- src/DBInit.cpp | 8 +++----- src/LedgerConsensus.cpp | 8 ++++---- src/NetworkOPs.cpp | 4 ++-- src/RPCServer.cpp | 10 ++++------ 4 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/DBInit.cpp b/src/DBInit.cpp index 470d28fb3..0c9e45ff8 100644 --- a/src/DBInit.cpp +++ b/src/DBInit.cpp @@ -24,14 +24,12 @@ int TxnDBCount = sizeof(TxnDBInit) / sizeof(const char *); const char *AcctTxnDBInit[] = { "CREATE TABLE AccountTransactions ( \ - TransID CHARACTER964) PRIMARY KEY \ + TransID CHARACTER(64) PRIMARY KEY, \ Account CHARACTER(64), \ - LedgerSeq BIGINT UNSIGNED, \ + LedgerSeq BIGINT UNSIGNED \ );", "CREATE INDEX AcctTxindex ON \ - AccountTransactions(Account), \ - AccountTransactions(LedgerSeq), \ - AccountTransactions(TransID);" + AccountTransactions(Account, LedgerSeq, TransID);" }; int AcctTxnDBCount = sizeof(AcctTxnDBInit) / sizeof(const char *); diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index ea148163e..fa2ecb189 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -738,12 +738,12 @@ void LedgerConsensus::accept(SHAMap::pointer set) SerializedTransaction txn(sit); std::vector accts = txn.getAffectedAccounts(); - std::string sql = "INSERT INTO AccountTransactions (TransID,Account,LedgerSeq) VALUES "; + std::string sql = "INSERT INTO AccountTransactions (TransID, Account, LedgerSeq) VALUES "; bool first = true; for (std::vector::iterator it = accts.begin(), end = accts.end(); it != end; ++it) { if (!first) - sql += ", ("; + sql += ", ('"; else { sql += "('"; @@ -752,9 +752,9 @@ void LedgerConsensus::accept(SHAMap::pointer set) sql += txn.getTransactionID().GetHex(); sql += "','"; sql += it->humanAccountID(); - sql += "','"; + sql += "',"; sql += boost::lexical_cast(newLedgerSeq); - sql += "')"; + sql += ")"; } sql += ";"; Log(lsTRACE) << "ActTx: " << sql; diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index d2e93f926..0efcc2b30 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -539,8 +539,8 @@ std::vector< std::pair > std::string sql = str(boost::format("SELECT LedgerSeq,TransID FROM AccountTransactions INDEXED BY AcctTxIndex " - " WHERE Account = %s AND LedgerSeq <= %d AND LedgerSeq >= %d ORDER BY LedgerSeq LIMIT 1000") - % account.humanAccountID() % minLedger % maxLedger); + " WHERE Account = '%s' AND LedgerSeq <= '%d' AND LedgerSeq >= '%d' ORDER BY LedgerSeq LIMIT 1000") + % account.humanAccountID() % maxLedger % minLedger); Database *db = theApp->getAcctTxnDB()->getDB(); ScopedLock dbLock = theApp->getAcctTxnDB()->getDBLock(); diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index d67425498..3320ace8c 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1502,19 +1502,17 @@ Json::Value RPCServer::doAccountTransactions(Json::Value& params) try { #endif - std::vector< std::pair > txns = - mNetOps->getAffectedAccounts(account, minLedger, maxLedger); + std::vector< std::pair > txns = mNetOps->getAffectedAccounts(account, minLedger, maxLedger); Json::Value ret(Json::objectValue); ret["Account"] = account.humanAccountID(); Json::Value ledgers(Json::arrayValue); uint32 currentLedger = 0; Json::Value ledger, jtxns; - for (std::vector< std::pair >::iterator it = txns.begin(), - end = txns.end(); it != end; ++it) + for (std::vector< std::pair >::iterator it = txns.begin(), end = txns.end(); it != end; ++it) { - if (it->first != currentLedger) - { // new ledger + if (it->first != currentLedger) // different/new ledger + { if (currentLedger != 0) // add old ledger { ledger["Transactions"] = jtxns; From c1c64fe1c733d5cbe3e90df0c9e6993d799ff171 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 18:30:01 -0700 Subject: [PATCH 09/23] Fix. --- src/DBInit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DBInit.cpp b/src/DBInit.cpp index 0c9e45ff8..0c4826e94 100644 --- a/src/DBInit.cpp +++ b/src/DBInit.cpp @@ -24,7 +24,7 @@ int TxnDBCount = sizeof(TxnDBInit) / sizeof(const char *); const char *AcctTxnDBInit[] = { "CREATE TABLE AccountTransactions ( \ - TransID CHARACTER(64) PRIMARY KEY, \ + TransID CHARACTER(64), \ Account CHARACTER(64), \ LedgerSeq BIGINT UNSIGNED \ );", From 43d0e8bdb714ca3479675e5ea207347f84c3975f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 18:31:15 -0700 Subject: [PATCH 10/23] Cleanup. --- src/RPCServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 3320ace8c..778550827 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1520,7 +1520,7 @@ Json::Value RPCServer::doAccountTransactions(Json::Value& params) ledger = Json::objectValue; } currentLedger = it->first; - ledger["ID"] = currentLedger; + ledger["LedgerSeq"] = currentLedger; jtxns = Json::arrayValue; } jtxns.append(it->second.GetHex()); From 99fe81b4e9f865cb9ba482cabac7eb4ce23562b8 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 9 Jun 2012 18:36:49 -0700 Subject: [PATCH 11/23] Add NUMBER() to utils.h --- src/utils.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils.h b/src/utils.h index 54cb56c1c..ee5ef0b59 100644 --- a/src/utils.h +++ b/src/utils.h @@ -9,7 +9,8 @@ #include "types.h" #define nothing() do {} while (0) -#define fallthru() do {} while (0) +#define fallthru() do {} while (0) +#define NUMBER(x) (sizeof(x)/sizeof((x)[0])) #ifndef MAX #define MAX(x,y) ((x) < (y) ? (y) : (x)) From f9bdeebd86c51d5df0fec2b7b2e6a2de5d2e2344 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 9 Jun 2012 18:37:20 -0700 Subject: [PATCH 12/23] Most of rework for command dispatching and error messages for RPC. --- src/RPCServer.cpp | 860 +++++++++++++++++++--------------------------- src/RPCServer.h | 47 +++ 2 files changed, 395 insertions(+), 512 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index c098ec507..ac3098f26 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -38,6 +38,58 @@ RPCServer::RPCServer(boost::asio::io_service& io_service , NetworkOPs* nopNetwor { } +Json::Value RPCServer::RPCError(int iError) +{ + struct { + int iError; + const char* pToken; + const char* pMessage; + } errorInfoA[] = { + { rpcBAD_SEED, "badSeed", "Disallowed seed." }, + { rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." }, + { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." }, + { rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed." }, + { rpcINSUF_FUNDS, "insufFunds", "Insufficient funds." }, + { rpcINTERNAL, "internal", "Internal error." }, + { rpcINVALID_PARAMS, "invalidParams", "Invalid paramters." }, + { rpcNICKNAME_MALFORMED,"nicknameMalformed","Nickname is malformed." }, + { rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist." }, + { rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname." }, + { rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable." }, + { rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable." }, + { rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." }, + { rpcNO_NETWORK, "noNetwork", "Network not available." }, + { rpcNOT_IMPL, "notImpl", "Not implemented." }, + { rpcPASSWD_CHANGED, "passwdChanged", "Wrong key, password changed." }, + { rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed." }, + { rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." }, + { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency is malformed." }, + { rpcSRC_MISSING, "srcMissing", "Source account does not exist." }, + { rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." }, + { rpcSUCCESS, "success", "Success." }, + { rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown command." }, + { rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key." }, + }; + + int i; + + for (i=NUMBER(errorInfoA); i-- && errorInfoA[i].iError != iError;) + ; + + Json::Value jsonResult = Json::Value(Json::objectValue); + + jsonResult["error"] = iError; + if (i >= 0) { + std::cerr << "RPCError: " + << errorInfoA[i].pToken << ": " << errorInfoA[i].pMessage << std::endl; + + jsonResult["error_token"] = errorInfoA[i].pToken; + jsonResult["error_message"] = errorInfoA[i].pMessage; + } + + return jsonResult; +} + void RPCServer::connected() { //BOOST_LOG_TRIVIAL(info) << "RPC request"; @@ -226,13 +278,13 @@ Json::Value RPCServer::authorize(const uint256& uLedger, asSrc = mNetOps->getAccountState(uLedger, naSrcAccountID); if (!asSrc) { - return JSONRPCError(500, "source account does not exist"); + return RPCError(rpcSRC_MISSING); } // Source must have been claimed. if (!asSrc->bHaveAuthorizedKey()) { - return JSONRPCError(500, "source account has not been claimed"); + return RPCError(rpcSRC_UNCLAIMED); } NewcoinAddress naMasterGenerator; @@ -245,9 +297,7 @@ Json::Value RPCServer::authorize(const uint256& uLedger, // If naVerifyGenerator is provided, make sure it is the master generator. if (naVerifyGenerator.isValid() && naMasterGenerator != naVerifyGenerator) { - std::cerr << "naAccountPublic: wrong seed" << std::endl; - - return JSONRPCError(500, "wrong seed"); + return RPCError(rpcWRONG_SEED); } // Find the index of the account from the master generator, so we can generate the public and private keys. @@ -275,14 +325,14 @@ Json::Value RPCServer::authorize(const uint256& uLedger, std::cerr << "sfAuthorizedKey: " << strHex(asSrc->getAuthorizedKey().getAccountID()) << std::endl; std::cerr << "naAccountPublic: " << strHex(naAccountPublic.getAccountID()) << std::endl; - return JSONRPCError(500, "wrong password (changed)"); + return RPCError(rpcPASSWD_CHANGED); } saSrcBalance = asSrc->getBalance(); if (saSrcBalance < saFee) { - return JSONRPCError(500, "insufficent funds"); + return RPCError(rpcINSUF_FUNDS); } else { @@ -306,7 +356,7 @@ Json::Value RPCServer::accountFromString(const uint256& uLedger, NewcoinAddress& // Must be a seed. else if (!naSeed.setFamilySeedGeneric(strIdent)) { - return "disallowed seed"; + return RPCError(rpcBAD_SEED); } else { @@ -335,7 +385,7 @@ Json::Value RPCServer::accountFromString(const uint256& uLedger, NewcoinAddress& std::vector vucMasterGenerator = naRegular0Private.accountPrivateDecrypt(naRegular0Public, vucCipher); if (vucMasterGenerator.empty()) { - return "internal error: password failed to decrypt master public generator"; + RPCError(rpcNO_GEN_DECRPYT); } naGenerator.setFamilyGenerator(vucMasterGenerator); @@ -354,27 +404,15 @@ Json::Value RPCServer::doAccountEmailSet(Json::Value ¶ms) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger; + uint256 uLedger = mNetOps->getCurrentLedger(); - if (params.size() < 2 || params.size() > 3) + if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { - return "invalid params"; - } - else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) - { - return "disallowed seed"; + return RPCError(rpcBAD_SEED); } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { - return "source account id needed"; - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no closed ledger"); + return RPCError(rpcSRC_ACT_MALFORMED); } NewcoinAddress naMasterGenerator; @@ -429,202 +467,160 @@ Json::Value RPCServer::doAccountEmailSet(Json::Value ¶ms) // account_info || [] Json::Value RPCServer::doAccountInfo(Json::Value ¶ms) { - if (params.size() < 1 || params.size() > 2) + std::string strIdent = params[0u].asString(); + bool bIndex; + int iIndex = 2 == params.size()? boost::lexical_cast(params[1u].asString()) : 0; + NewcoinAddress naAccount; + + Json::Value ret; + + // Get info on account. + + uint256 uClosed = mNetOps->getClosedLedger(); + Json::Value jClosed = accountFromString(uClosed, naAccount, bIndex, strIdent, iIndex); + + if (jClosed.empty()) { - return "invalid params"; + AccountState::pointer asClosed = mNetOps->getAccountState(uClosed, naAccount); + + if (asClosed) + asClosed->addJson(jClosed); } - else if (!mNetOps->available()) + + ret["closed"] = jClosed; + + uint256 uCurrent = mNetOps->getCurrentLedger(); + Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + + if (jCurrent.empty()) { - return JSONRPCError(503, "network not available"); + AccountState::pointer asCurrent = mNetOps->getAccountState(uCurrent, naAccount); + + if (asCurrent) + asCurrent->addJson(jCurrent); } - else - { - std::string strIdent = params[0u].asString(); - bool bIndex; - int iIndex = 2 == params.size()? boost::lexical_cast(params[1u].asString()) : 0; - NewcoinAddress naAccount; - Json::Value ret; - - // Get info on account. - - uint256 uClosed = mNetOps->getClosedLedger(); - Json::Value jClosed = accountFromString(uClosed, naAccount, bIndex, strIdent, iIndex); - - if (jClosed.empty()) - { - AccountState::pointer asClosed = mNetOps->getAccountState(uClosed, naAccount); - - if (asClosed) - asClosed->addJson(jClosed); - } - - ret["closed"] = jClosed; - - uint256 uCurrent = mNetOps->getCurrentLedger(); - Json::Value jCurrent = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); - - if (jCurrent.empty()) - { - AccountState::pointer asCurrent = mNetOps->getAccountState(uCurrent, naAccount); - - if (asCurrent) - asCurrent->addJson(jCurrent); - } - - ret["current"] = jCurrent; + ret["current"] = jCurrent; #if 0 - if (!jClosed && !asCurrent) - { - ret["account"] = naAccount.humanAccountID(); - ret["status"] = "NotFound"; - if (bIndex) - ret["index"] = iIndex; - } -#endif - return ret; + if (!jClosed && !asCurrent) + { + ret["account"] = naAccount.humanAccountID(); + ret["status"] = "NotFound"; + if (bIndex) + ret["index"] = iIndex; } +#endif + return ret; } // account_lines || [] Json::Value RPCServer::doAccountLines(Json::Value ¶ms) { - uint256 uClosed; - uint256 uCurrent; + uint256 uClosed = mNetOps->getClosedLedger(); + uint256 uCurrent = mNetOps->getCurrentLedger(); - if (params.size() < 1 || params.size() > 2) + std::string strIdent = params[0u].asString(); + bool bIndex; + int iIndex = 2 == params.size()? boost::lexical_cast(params[1u].asString()) : 0; + + NewcoinAddress naAccount; + + Json::Value ret; + + ret = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); + + if (!ret.empty()) + return ret; + + // Get info on account. + ret = Json::Value(Json::objectValue); + + ret["account"] = naAccount.humanAccountID(); + if (bIndex) + ret["index"] = iIndex; + + AccountState::pointer as = mNetOps->getAccountState(uCurrent, naAccount); + if (as) { - return "invalid params"; - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uCurrent = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); - } - else if ((uClosed = mNetOps->getClosedLedger()).isZero()) - { - return JSONRPCError(503, "no closed ledger"); - } - else - { - std::string strIdent = params[0u].asString(); - bool bIndex; - int iIndex = 2 == params.size()? boost::lexical_cast(params[1u].asString()) : 0; - - NewcoinAddress naAccount; - - Json::Value ret; - - ret = accountFromString(uCurrent, naAccount, bIndex, strIdent, iIndex); - - if (!ret.empty()) - return ret; - - // Get info on account. - ret = Json::Value(Json::objectValue); + Json::Value jsonLines = Json::Value(Json::objectValue); ret["account"] = naAccount.humanAccountID(); - if (bIndex) - ret["index"] = iIndex; - AccountState::pointer as = mNetOps->getAccountState(uCurrent, naAccount); - if (as) + // We access a committed ledger and need not worry about changes. + uint256 uDirLineNodeFirst; + uint256 uDirLineNodeLast; + + if (mNetOps->getDirLineInfo(uCurrent, naAccount, uDirLineNodeFirst, uDirLineNodeLast)) { - Json::Value jsonLines = Json::Value(Json::objectValue); - - ret["account"] = naAccount.humanAccountID(); - - // We access a committed ledger and need not worry about changes. - uint256 uDirLineNodeFirst; - uint256 uDirLineNodeLast; - - if (mNetOps->getDirLineInfo(uCurrent, naAccount, uDirLineNodeFirst, uDirLineNodeLast)) + for (; uDirLineNodeFirst <= uDirLineNodeLast; uDirLineNodeFirst++) { - for (; uDirLineNodeFirst <= uDirLineNodeLast; uDirLineNodeFirst++) + STVector256 svRippleNodes = mNetOps->getDirNode(uCurrent, uDirLineNodeFirst); + + BOOST_FOREACH(uint256& uNode, svRippleNodes.peekValue()) { - STVector256 svRippleNodes = mNetOps->getDirNode(uCurrent, uDirLineNodeFirst); + NewcoinAddress naAccountPeer; + STAmount saBalance; + STAmount saLimit; + STAmount saLimitPeer; - BOOST_FOREACH(uint256& uNode, svRippleNodes.peekValue()) + RippleState::pointer rsLine = mNetOps->getRippleState(uCurrent, uNode); + + if (rsLine) { - NewcoinAddress naAccountPeer; - STAmount saBalance; - STAmount saLimit; - STAmount saLimitPeer; + rsLine->setViewAccount(naAccount); - RippleState::pointer rsLine = mNetOps->getRippleState(uCurrent, uNode); + naAccountPeer = rsLine->getAccountIDPeer(); + saBalance = rsLine->getBalance(); + saLimit = rsLine->getLimit(); + saLimitPeer = rsLine->getLimitPeer(); - if (rsLine) - { - rsLine->setViewAccount(naAccount); + Json::Value jPeer = Json::Value(Json::objectValue); - naAccountPeer = rsLine->getAccountIDPeer(); - saBalance = rsLine->getBalance(); - saLimit = rsLine->getLimit(); - saLimitPeer = rsLine->getLimitPeer(); + jPeer["node"] = uNode.ToString(); - Json::Value jPeer = Json::Value(Json::objectValue); + jPeer["balance"] = saBalance.getText(); + jPeer["currency"] = saBalance.getCurrencyHuman(); + jPeer["limit"] = saLimit.getJson(0); + jPeer["limit_peer"] = saLimitPeer.getJson(0); - jPeer["node"] = uNode.ToString(); - - jPeer["balance"] = saBalance.getText(); - jPeer["currency"] = saBalance.getCurrencyHuman(); - jPeer["limit"] = saLimit.getJson(0); - jPeer["limit_peer"] = saLimitPeer.getJson(0); - - jsonLines[naAccountPeer.humanAccountID()] = jPeer; - } - else - { - std::cerr << "doAccountLines: Bad index: " << uNode.ToString() << std::endl; - } + jsonLines[naAccountPeer.humanAccountID()] = jPeer; + } + else + { + std::cerr << "doAccountLines: Bad index: " << uNode.ToString() << std::endl; } } } - ret["lines"] = jsonLines; } - else - { - ret["status"] = "NotFound"; - } - - return ret; + ret["lines"] = jsonLines; } + else + { + ret["status"] = "NotFound"; + } + + return ret; } // account_message_set Json::Value RPCServer::doAccountMessageSet(Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger; + uint256 uLedger = mNetOps->getCurrentLedger(); NewcoinAddress naMessagePubKey; - if (params.size() != 3) + if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { - return "invalid params"; - } - else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) - { - return "disallowed seed"; + return RPCError(rpcBAD_SEED); } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { - return "source account id needed"; + return RPCError(rpcSRC_ACT_MALFORMED); } else if (!naMessagePubKey.setAccountPublic(params[2u].asString())) { - return "public key needed"; - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); + return RPCError(rpcPUBLIC_MALFORMED); } NewcoinAddress naMasterGenerator; @@ -663,27 +659,15 @@ Json::Value RPCServer::doAccountMessageSet(Json::Value& params) { Json::Value RPCServer::doAccountWalletSet(Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger; + uint256 uLedger = mNetOps->getCurrentLedger(); - if (params.size() < 2 || params.size() > 3) + if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { - return "invalid params"; - } - else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) - { - return "disallowed seed"; + return RPCError(rpcBAD_SEED); } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { - return "source account id needed"; - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); + return RPCError(rpcSRC_ACT_MALFORMED); } NewcoinAddress naMasterGenerator; @@ -731,12 +715,9 @@ Json::Value RPCServer::doConnect(Json::Value& params) std::string strIp; int iPort = -1; - if (!params.isArray() || !params.size() || params.size() > 2) - return JSONRPCError(500, "Invalid parameters"); - // XXX Might allow domain for manual connections. if (!extractString(strIp, params, 0)) - return JSONRPCError(500, "Host IP required"); + return RPCError(rpcHOST_IP_MALFORMED); if (params.size() == 2) { @@ -762,36 +743,24 @@ Json::Value RPCServer::doCreditSet(Json::Value& params) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; STAmount saLimitAmount; - uint256 uLedger; + uint256 uLedger = mNetOps->getCurrentLedger(); uint32 uAcceptRate = params.size() >= 6 ? boost::lexical_cast(params[5u].asString()) : 0; - if (params.size() < 4 || params.size() > 6) + if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { - return JSONRPCError(500, "invalid parameters"); - } - else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) - { - return JSONRPCError(500, "disallowed seed"); + return RPCError(rpcBAD_SEED); } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { - return JSONRPCError(500, "source account id needed"); + return RPCError(rpcSRC_ACT_MALFORMED); } else if (!naDstAccountID.setAccountID(params[2u].asString())) { - return JSONRPCError(500, "destination account id needed"); + return RPCError(rpcDST_ACT_MALFORMED); } else if (!saLimitAmount.setValue(params[3u].asString(), params.size() >= 5 ? params[4u].asString() : "")) { - return JSONRPCError(400, "bad src amount/currency"); - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); + return RPCError(rpcSRC_AMT_MALFORMED); } else { @@ -833,11 +802,6 @@ Json::Value RPCServer::doCreditSet(Json::Value& params) // data_delete Json::Value RPCServer::doDataDelete(Json::Value& params) { - if (params.size() != 1) - { - return JSONRPCError(400, "invalid params"); - } - std::string strKey = params[0u].asString(); Json::Value ret = Json::Value(Json::objectValue); @@ -848,7 +812,7 @@ Json::Value RPCServer::doDataDelete(Json::Value& params) } else { - ret = JSONRPCError(500, "internal error"); + ret = RPCError(rpcINTERNAL); } return ret; @@ -857,11 +821,6 @@ Json::Value RPCServer::doDataDelete(Json::Value& params) // data_fetch Json::Value RPCServer::doDataFetch(Json::Value& params) { - if (params.size() != 1) - { - return JSONRPCError(400, "invalid params"); - } - std::string strKey = params[0u].asString(); std::string strValue; @@ -877,11 +836,6 @@ Json::Value RPCServer::doDataFetch(Json::Value& params) // data_store Json::Value RPCServer::doDataStore(Json::Value& params) { - if (params.size() != 2) - { - return JSONRPCError(400, "invalid params"); - } - std::string strKey = params[0u].asString(); std::string strValue = params[1u].asString(); @@ -894,7 +848,7 @@ Json::Value RPCServer::doDataStore(Json::Value& params) } else { - ret = JSONRPCError(500, "internal error"); + ret = RPCError(rpcINTERNAL); } return ret; @@ -904,33 +858,20 @@ Json::Value RPCServer::doDataStore(Json::Value& params) // Note: Nicknames are not automatically looked up by commands as they are advisory and can be changed. Json::Value RPCServer::doNicknameInfo(Json::Value& params) { - uint256 uLedger; - - if (params.size() != 1) - { - return JSONRPCError(400, "invalid params"); - } + uint256 uLedger = mNetOps->getCurrentLedger(); std::string strNickname = params[0u].asString(); boost::trim(strNickname); if (strNickname.empty()) { - return JSONRPCError(400, "invalid nickname (zero length)"); - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); + return RPCError(rpcNICKNAME_MALFORMED); } NicknameState::pointer nsSrc = mNetOps->getNicknameState(uLedger, strNickname); if (!nsSrc) { - return JSONRPCError(500, "nickname does not exist"); + return RPCError(rpcNICKNAME_MISSING); } Json::Value ret(Json::objectValue); @@ -947,19 +888,15 @@ Json::Value RPCServer::doNicknameSet(Json::Value& params) { NewcoinAddress naSrcAccountID; NewcoinAddress naSeed; - uint256 uLedger; + uint256 uLedger = mNetOps->getCurrentLedger(); - if (params.size() < 2 || params.size() > 3) + if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { - return JSONRPCError(400, "invalid params"); - } - else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) - { - return "disallowed seed"; + return RPCError(rpcBAD_SEED); } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { - return "bad source account id needed"; + return RPCError(rpcSRC_ACT_MALFORMED); } STAmount saMinimumOffer; @@ -971,19 +908,11 @@ Json::Value RPCServer::doNicknameSet(Json::Value& params) if (strNickname.empty()) { - return JSONRPCError(400, "invalid nickname (zero length)"); + return RPCError(rpcNICKNAME_MALFORMED); } else if (params.size() >= 4 && !saMinimumOffer.setValue(params[3u].asString(), strOfferCurrency)) { - return JSONRPCError(400, "bad dst amount/currency"); - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); + return RPCError(rpcDST_AMT_MALFORMED); } STAmount saFee; @@ -997,7 +926,7 @@ Json::Value RPCServer::doNicknameSet(Json::Value& params) else if (naSrcAccountID != nsSrc->getAccountID()) { // We don't own the nickname. - return JSONRPCError(400, "account does not control nickname"); + return RPCError(rpcNICKNAME_PERM); } else { @@ -1045,31 +974,19 @@ Json::Value RPCServer::doPasswordFund(Json::Value ¶ms) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; NewcoinAddress naSeed; - uint256 uLedger; + uint256 uLedger = mNetOps->getCurrentLedger(); - if (params.size() < 2 || params.size() > 3) + if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { - return "invalid params"; - } - else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) - { - return "disallowed seed"; + return RPCError(rpcBAD_SEED); } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { - return "bad source account id needed"; + return RPCError(rpcSRC_ACT_MALFORMED); } else if (!naDstAccountID.setAccountID(params[params.size() == 3 ? 2u : 1u].asString())) { - return "bad destination account id needed"; - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); + return RPCError(rpcDST_ACT_MALFORMED); } NewcoinAddress naMasterGenerator; @@ -1108,11 +1025,7 @@ Json::Value RPCServer::doPasswordSet(Json::Value& params) NewcoinAddress naRegularSeed; NewcoinAddress naAccountID; - if (params.size() < 2 || params.size() > 3) - { - return "invalid params"; - } - else if (!naMasterSeed.setFamilySeedGeneric(params[0u].asString())) + if (!naMasterSeed.setFamilySeedGeneric(params[0u].asString())) { // Should also not allow account id's as seeds. return "master seed expected"; @@ -1219,7 +1132,7 @@ Json::Value RPCServer::doSend(Json::Value& params) STAmount saDstAmount; std::string sSrcCurrency; std::string sDstCurrency; - uint256 uLedger; + uint256 uLedger = mNetOps->getCurrentLedger(); if (params.size() >= 5) sDstCurrency = params[4u].asString(); @@ -1227,37 +1140,25 @@ Json::Value RPCServer::doSend(Json::Value& params) if (params.size() >= 7) sSrcCurrency = params[6u].asString(); - if (!params.isArray() || params.size() < 3 || params.size() > 7) + if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { - return JSONRPCError(500, "Invalid parameters"); - } - else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) - { - return JSONRPCError(500, "disallowed seed"); + return RPCError(rpcBAD_SEED); } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { - return JSONRPCError(500, "source account id malformed"); + return RPCError(rpcSRC_ACT_MALFORMED); } else if (!naDstAccountID.setAccountID(params[2u].asString())) { - return JSONRPCError(500, "destination account id malformed"); + return RPCError(rpcDST_ACT_MALFORMED); } else if (!saDstAmount.setValue(params[3u].asString(), sDstCurrency)) { - return JSONRPCError(400, "bad dst amount/currency"); + return RPCError(rpcDST_AMT_MALFORMED); } else if (params.size() >= 6 && !saSrcAmount.setValue(params[5u].asString(), sSrcCurrency)) { - return JSONRPCError(400, "bad src amount/currency"); - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); + return RPCError(rpcSRC_AMT_MALFORMED); } else { @@ -1281,7 +1182,7 @@ Json::Value RPCServer::doSend(Json::Value& params) if (saSrcBalance < saDstAmount) { - return JSONRPCError(500, "Insufficient funds."); + return RPCError(rpcINSUF_FUNDS); } Transaction::pointer trans; @@ -1349,7 +1250,7 @@ Json::Value RPCServer::doTransitSet(Json::Value& params) uint32 uTransitRate; uint32 uTransitStart; uint32 uTransitExpire; - uint256 uLedger; + uint256 uLedger = mNetOps->getCurrentLedger(); if (params.size() >= 6) sTransitRate = params[6u].asString(); @@ -1360,25 +1261,13 @@ Json::Value RPCServer::doTransitSet(Json::Value& params) if (params.size() >= 8) sTransitExpire = params[8u].asString(); - if (params.size() != 5) + if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { - return JSONRPCError(500, "invalid parameters"); - } - else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) - { - return JSONRPCError(500, "disallowed seed"); + return RPCError(rpcBAD_SEED); } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { - return JSONRPCError(500, "source account id needed"); - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); + return RPCError(rpcSRC_ACT_MALFORMED); } else { @@ -1429,7 +1318,7 @@ Json::Value RPCServer::doTx(Json::Value& params) std::string param1, param2; if (!extractString(param1, params, 0)) { - return "bad params"; + return RPCError(rpcINVALID_PARAMS); } if (Transaction::isHexTxID(param1)) @@ -1442,22 +1331,13 @@ Json::Value RPCServer::doTx(Json::Value& params) return txn->getJson(true); } - return JSONRPCError(501, "not implemented"); + return RPCError(rpcNOT_IMPL); } // ledger [id|current|lastclosed] [full] Json::Value RPCServer::doLedger(Json::Value& params) { - if (params.size() > 2) - { - return "invalid params"; - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - if (getParamCount(params) == 0) { Json::Value ret(Json::objectValue), current(Json::objectValue), closed(Json::objectValue); @@ -1502,26 +1382,24 @@ Json::Value RPCServer::doLedger(Json::Value& params) // unl_add | [] Json::Value RPCServer::doUnlAdd(Json::Value& params) { - if (params.size() == 1 || params.size() == 2) + std::string strNode = params[0u].asString(); + std::string strComment = (params.size() == 2) ? "" : params[1u].asString(); + + NewcoinAddress nodePublic; + + if (nodePublic.setNodePublic(strNode)) { - std::string strNode = params[0u].asString(); - std::string strComment = (params.size() == 2) ? "" : params[1u].asString(); + theApp->getUNL().nodeAddPublic(nodePublic, strComment); - NewcoinAddress nodePublic; - - if (nodePublic.setNodePublic(strNode)) - { - theApp->getUNL().nodeAddPublic(nodePublic, strComment); - - return "adding node by public key"; - } - else - { - theApp->getUNL().nodeAddDomain(strNode, UniqueNodeList::vsManual, strComment); - - return "adding node by domain"; - } + return "adding node by public key"; } + else + { + theApp->getUNL().nodeAddDomain(strNode, UniqueNodeList::vsManual, strComment); + + return "adding node by domain"; + } + return "invalid params"; } @@ -1538,11 +1416,7 @@ Json::Value RPCServer::doValidatorCreate(Json::Value& params) { NewcoinAddress nodePublicKey; NewcoinAddress nodePrivateKey; - if (params.size() > 1) - { - return "invalid params"; - } - else if (params.empty()) + if (params.empty()) { std::cerr << "Creating random validation seed." << std::endl; @@ -1550,7 +1424,7 @@ Json::Value RPCServer::doValidatorCreate(Json::Value& params) { } else if (!familySeed.setFamilySeedGeneric(params[0u].asString())) { - return "disallowed seed"; + return RPCError(rpcBAD_SEED); } // Derive generator from seed. @@ -1607,24 +1481,12 @@ Json::Value RPCServer::accounts(const uint256& uLedger, const NewcoinAddress& na Json::Value RPCServer::doWalletAccounts(Json::Value& params) { NewcoinAddress naSeed; - uint256 uLedger; + uint256 uLedger = mNetOps->getCurrentLedger(); - if (params.size() != 1) - { - return "invalid params"; - } - else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) + if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { return "seed expected"; } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); - } NewcoinAddress naMasterGenerator; @@ -1664,13 +1526,9 @@ Json::Value RPCServer::doWalletAdd(Json::Value& params) NewcoinAddress naSrcAccountID; STAmount saAmount; std::string sDstCurrency; - uint256 uLedger; + uint256 uLedger = mNetOps->getCurrentLedger(); - if (params.size() < 3 || params.size() > 5) - { - return "invalid params"; - } - else if (!naRegularSeed.setFamilySeedGeneric(params[0u].asString())) + if (!naRegularSeed.setFamilySeedGeneric(params[0u].asString())) { return "regular seed expected"; } @@ -1684,15 +1542,7 @@ Json::Value RPCServer::doWalletAdd(Json::Value& params) } else if (params.size() >= 4 && !saAmount.setValue(params[3u].asString(), sDstCurrency)) { - return JSONRPCError(400, "bad dst amount/currency"); - } - else if (!mNetOps->available()) - { - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); + return RPCError(rpcDST_AMT_MALFORMED); } else { @@ -1714,7 +1564,7 @@ Json::Value RPCServer::doWalletAdd(Json::Value& params) if (saSrcBalance < saAmount) { - return JSONRPCError(500, "insufficent funds"); + return RPCError(rpcINSUF_FUNDS); } else { @@ -1782,11 +1632,7 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params) NewcoinAddress naMasterSeed; NewcoinAddress naRegularSeed; - if (params.size() < 2 || params.size() > 4) - { - return "invalid params"; - } - else if (!naMasterSeed.setFamilySeedGeneric(params[0u].asString())) + if (!naMasterSeed.setFamilySeedGeneric(params[0u].asString())) { // Should also not allow account id's as seeds. return "master seed expected"; @@ -1874,33 +1720,20 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params) NewcoinAddress naSrcAccountID; NewcoinAddress naDstAccountID; NewcoinAddress naSeed; - uint256 uLedger; + uint256 uLedger = mNetOps->getCurrentLedger(); - if (params.size() < 3 || params.size() > 4) + if (!naSeed.setFamilySeedGeneric(params[0u].asString())) { - return "invalid params"; - } - else if (!naSeed.setFamilySeedGeneric(params[0u].asString())) - { - return "disallowed seed"; + return RPCError(rpcBAD_SEED); } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { - return "source account id needed"; + return RPCError(rpcSRC_ACT_MALFORMED); } else if (!naDstAccountID.setAccountID(params[2u].asString())) { return "create account id needed"; } - else if (!mNetOps->available()) - { - // We require access to the paying account's sequence number and key information. - return JSONRPCError(503, "network not available"); - } - else if ((uLedger = mNetOps->getCurrentLedger()).isZero()) - { - return JSONRPCError(503, "no current ledger"); - } else if (mNetOps->getAccountState(uLedger, naDstAccountID)) { return "account already exists"; @@ -1923,7 +1756,7 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params) STAmount saInitialFunds = (params.size() < 4) ? 0 : boost::lexical_cast(params[3u].asString()); if (saSrcBalance < saInitialFunds) - return JSONRPCError(500, "insufficent funds"); + return RPCError(rpcINSUF_FUNDS); Transaction::pointer trans = Transaction::sharedCreate( naAccountPublic, naAccountPrivate, @@ -1945,37 +1778,30 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params) // wallet_propose Json::Value RPCServer::doWalletPropose(Json::Value& params) { - if (params.size()) - { - return "invalid params"; - } - else - { - NewcoinAddress naSeed; - NewcoinAddress naGenerator; - NewcoinAddress naAccount; + NewcoinAddress naSeed; + NewcoinAddress naGenerator; + NewcoinAddress naAccount; - naSeed.setFamilySeedRandom(); - naGenerator.setFamilyGenerator(naSeed); - naAccount.setAccountPublic(naGenerator, 0); + naSeed.setFamilySeedRandom(); + naGenerator.setFamilyGenerator(naSeed); + naAccount.setAccountPublic(naGenerator, 0); - // - // Extra functionality: generate a key pair - // - CKey key; + // + // Extra functionality: generate a key pair + // + CKey key; - key.MakeNewKey(); + key.MakeNewKey(); - Json::Value obj(Json::objectValue); + Json::Value obj(Json::objectValue); - obj["master_seed"] = naSeed.humanFamilySeed(); - obj["master_key"] = naSeed.humanFamilySeed1751(); - obj["account_id"] = naAccount.humanAccountID(); - obj["extra_public"] = NewcoinAddress::createHumanAccountPublic(key.GetPubKey()); - obj["extra_private"] = NewcoinAddress::createHumanAccountPrivate(key.GetSecret()); + obj["master_seed"] = naSeed.humanFamilySeed(); + obj["master_key"] = naSeed.humanFamilySeed1751(); + obj["account_id"] = naAccount.humanAccountID(); + obj["extra_public"] = NewcoinAddress::createHumanAccountPublic(key.GetPubKey()); + obj["extra_private"] = NewcoinAddress::createHumanAccountPrivate(key.GetSecret()); - return obj; - } + return obj; } // wallet_seed [||] @@ -1983,14 +1809,10 @@ Json::Value RPCServer::doWalletSeed(Json::Value& params) { NewcoinAddress naSeed; - if (params.size() > 1) - { - return "invalid params"; - } - else if (params.size() + if (params.size() && !naSeed.setFamilySeedGeneric(params[0u].asString())) { - return "disallowed seed"; + return RPCError(rpcBAD_SEED); } else { @@ -2078,29 +1900,26 @@ Json::Value RPCServer::doUnlDefault(Json::Value& params) { return "processing " VALIDATORS_FILE_NAME; } } - else return "invalid params"; + else + return RPCError(rpcINVALID_PARAMS); } // unl_delete Json::Value RPCServer::doUnlDelete(Json::Value& params) { - if (1 == params.size()) + std::string strNodePublic = params[0u].asString(); + + NewcoinAddress naNodePublic; + + if (naNodePublic.setNodePublic(strNodePublic)) { - std::string strNodePublic = params[0u].asString(); + theApp->getUNL().nodeRemove(naNodePublic); - NewcoinAddress naNodePublic; - - if (naNodePublic.setNodePublic(strNodePublic)) - { - theApp->getUNL().nodeRemove(naNodePublic); - - return "removing node"; - } - else - { - return "invalid public key"; - } + return "removing node"; + } + else + { + return "invalid public key"; } - else return "invalid params"; } Json::Value RPCServer::doUnlList(Json::Value& params) { @@ -2109,84 +1928,101 @@ Json::Value RPCServer::doUnlList(Json::Value& params) { // unl_reset Json::Value RPCServer::doUnlReset(Json::Value& params) { - if (!params.size()) - { - theApp->getUNL().nodeReset(); + theApp->getUNL().nodeReset(); - return "removing nodes"; - } - else return "invalid params"; + return "removing nodes"; } // unl_score Json::Value RPCServer::doUnlScore(Json::Value& params) { - if (!params.size()) - { - theApp->getUNL().nodeScore(); + theApp->getUNL().nodeScore(); - return "scoring requested"; - } - else return "invalid params"; + return "scoring requested"; } Json::Value RPCServer::doStop(Json::Value& params) { - if (!params.size()) - { - theApp->stop(); + theApp->stop(); - return SYSTEM_NAME " server stopping"; - } - else return "invalid params"; + return SYSTEM_NAME " server stopping"; } Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params) { std::cerr << "RPC:" << command << std::endl; + struct { + const char* pCommand; + doFuncPtr dfpFunc; + int iMinParams; + int iMaxParams; + unsigned int iOptions; + } commandsA[] = { + { "account_email_set", &RPCServer::doAccountEmailSet, 2, 3, optCurrent }, + { "account_info", &RPCServer::doAccountInfo, 1, 2, optCurrent }, + { "account_lines", &RPCServer::doAccountLines, 1, 2, optCurrent|optClosed }, + { "account_message_set", &RPCServer::doAccountMessageSet, 3, 3, optCurrent }, + { "account_wallet_set", &RPCServer::doAccountWalletSet, 2, 3, optCurrent }, + { "connect", &RPCServer::doConnect, 1, 2, }, + { "credit_set", &RPCServer::doCreditSet, 4, 6, optCurrent }, + { "data_delete", &RPCServer::doDataDelete, 1, 1, }, + { "data_fetch", &RPCServer::doDataFetch, 1, 1, }, + { "data_store", &RPCServer::doDataStore, 2, 2, }, + { "ledger", &RPCServer::doLedger, 0, 2, optNetwork }, + { "nickname_info", &RPCServer::doNicknameInfo, 1, 1, optCurrent }, + { "nickname_set", &RPCServer::doNicknameSet, 2, 3, optCurrent }, + { "password_fund", &RPCServer::doPasswordFund, 2, 3, optCurrent }, + { "password_set", &RPCServer::doPasswordSet, 2, 3, optNetwork }, + { "peers", &RPCServer::doPeers, 0, 0, }, + { "send", &RPCServer::doSend, 3, 7, optCurrent }, + { "stop", &RPCServer::doStop, 0, 0, }, + { "transit_set", &RPCServer::doTransitSet, 5, 5, optCurrent }, + { "tx", &RPCServer::doTx, 1, 1, }, - if (command == "account_email_set") return doAccountEmailSet(params); - if (command == "account_info") return doAccountInfo(params); - if (command == "account_lines") return doAccountLines(params); - if (command == "account_message_set") return doAccountMessageSet(params); - if (command == "account_wallet_set") return doAccountWalletSet(params); - if (command == "connect") return doConnect(params); - if (command == "credit_set") return doCreditSet(params); - if (command == "data_delete") return doDataDelete(params); - if (command == "data_fetch") return doDataFetch(params); - if (command == "data_store") return doDataStore(params); - if (command == "nickname_info") return doNicknameInfo(params); - if (command == "nickname_set") return doNicknameSet(params); - if (command == "password_fund") return doPasswordFund(params); - if (command == "password_set") return doPasswordSet(params); - if (command == "peers") return doPeers(params); - if (command == "send") return doSend(params); - if (command == "stop") return doStop(params); - if (command == "transit_set") return doTransitSet(params); + { "unl_add", &RPCServer::doUnlAdd, 1, 2, }, + { "unl_default", &RPCServer::doUnlDefault, 0, 1, }, + { "unl_delete", &RPCServer::doUnlDelete, 1, 1, }, + { "unl_list", &RPCServer::doUnlList, 0, 0, }, + { "unl_reset", &RPCServer::doUnlReset, 0, 0, }, + { "unl_score", &RPCServer::doUnlScore, 0, 0, }, - if (command == "unl_add") return doUnlAdd(params); - if (command == "unl_default") return doUnlDefault(params); - if (command == "unl_delete") return doUnlDelete(params); - if (command == "unl_list") return doUnlList(params); - if (command == "unl_reset") return doUnlReset(params); - if (command == "unl_score") return doUnlScore(params); + { "validation_create", &RPCServer::doValidatorCreate, 0, 1, }, - if (command == "validation_create") return doValidatorCreate(params); + { "wallet_accounts", &RPCServer::doWalletAccounts, 1, 1, optCurrent }, + { "wallet_add", &RPCServer::doWalletAdd, 3, 5, optCurrent }, + { "wallet_claim", &RPCServer::doWalletClaim, 2, 4, optNetwork }, + { "wallet_create", &RPCServer::doWalletCreate, 3, 4, optCurrent }, + { "wallet_propose", &RPCServer::doWalletPropose, 0, 0, }, + { "wallet_seed", &RPCServer::doWalletSeed, 0, 1, }, + }; - if (command == "wallet_accounts") return doWalletAccounts(params); - if (command == "wallet_add") return doWalletAdd(params); - if (command == "wallet_claim") return doWalletClaim(params); - if (command == "wallet_create") return doWalletCreate(params); - if (command == "wallet_propose") return doWalletPropose(params); - if (command == "wallet_seed") return doWalletSeed(params); + int i = NUMBER(commandsA); - if (command=="ledger") return doLedger(params); + while (i-- && command != commandsA[i].pCommand) + ; - // - // Obsolete or need rewrite: - // - - if (command=="tx") return doTx(params); - - return "unknown command"; + if (i < 0) + { + return RPCError(rpcUNKNOWN_COMMAND); + } + else if (params.size() < commandsA[i].iMinParams || params.size() > commandsA[i].iMaxParams) + { + return RPCError(rpcINVALID_PARAMS); + } + else if ((commandsA[i].iOptions & optNetwork) && !mNetOps->available()) + { + return RPCError(rpcNO_NETWORK); + } + else if ((commandsA[i].iOptions & optCurrent) && mNetOps->getCurrentLedger().isZero()) + { + return RPCError(rpcNO_CURRENT); + } + else if ((commandsA[i].iOptions & optClosed) && mNetOps->getClosedLedger().isZero()) + { + return RPCError(rpcNO_CLOSED); + } + else + { + return (this->*(commandsA[i].dfpFunc))(params); + } } void RPCServer::sendReply() diff --git a/src/RPCServer.h b/src/RPCServer.h index 4af47f84d..bafb75f3e 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -13,7 +13,54 @@ class RPCServer : public boost::enable_shared_from_this { +public: + enum { + rpcSUCCESS, + + // Networking + rpcNO_NETWORK, + rpcNO_CLOSED, + rpcNO_CURRENT, + + // Ledger state + rpcINSUF_FUNDS, + rpcPASSWD_CHANGED, + rpcSRC_MISSING, + rpcSRC_UNCLAIMED, + rpcWRONG_SEED, + rpcNICKNAME_MISSING, + + // Malformed command + rpcINVALID_PARAMS, + rpcUNKNOWN_COMMAND, + + // Bad paramater + rpcBAD_SEED, + rpcSRC_ACT_MALFORMED, + rpcDST_ACT_MALFORMED, + rpcPUBLIC_MALFORMED, + rpcHOST_IP_MALFORMED, + rpcSRC_AMT_MALFORMED, + rpcDST_AMT_MALFORMED, + rpcNICKNAME_MALFORMED, + rpcNICKNAME_PERM, + + // Internal error (should never happen) + rpcINTERNAL, // Generic internal error. + rpcNO_GEN_DECRPYT, + rpcNOT_IMPL, + }; + + Json::Value RPCError(int iError); + private: + typedef Json::Value (RPCServer::*doFuncPtr)(Json::Value ¶ms); + enum { + optNetwork = 1, // Need network + optCurrent = 2+optNetwork, // Need current ledger + optClosed = 4+optNetwork, // Need closed ledger + }; + NetworkOPs* mNetOps; boost::asio::ip::tcp::socket mSocket; From 7a511d36ef006d074e984a117ba80de4ac824567 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 18:38:08 -0700 Subject: [PATCH 13/23] Suppress duplicates. --- src/SerializedTransaction.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index daadbd5b3..d5b7aac3e 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -85,8 +85,22 @@ std::vector SerializedTransaction::getAffectedAccounts() const end = mInnerTxn.peekData().end(); it != end ; ++it) { const STAccount* sa = dynamic_cast(&*it); - if (sa != NULL) // FIXME: Should we check for duplicates? - accounts.push_back(sa->getValueNCA()); + if (sa != NULL) + { + bool found = false; + NewcoinAddress na = sa->getValueNCA(); + for (std::vector::iterator it = accounts.begin(), end = accounts.end(); + it != end; ++it) + { + if (*it == na) + { + found = true; + break; + } + } + if (!found) + accounts.push_back(na); + } } return accounts; } From 34b4e1ea61a915ee0d7f30a28c20122c6b98b197 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 9 Jun 2012 18:50:25 -0700 Subject: [PATCH 14/23] Minor clean up. --- src/RPCServer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 648f34994..a641cf772 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -40,7 +40,7 @@ RPCServer::RPCServer(boost::asio::io_service& io_service , NetworkOPs* nopNetwor Json::Value RPCServer::RPCError(int iError) { - struct { + static struct { int iError; const char* pToken; const char* pMessage; @@ -51,7 +51,7 @@ Json::Value RPCServer::RPCError(int iError) { rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed." }, { rpcINSUF_FUNDS, "insufFunds", "Insufficient funds." }, { rpcINTERNAL, "internal", "Internal error." }, - { rpcINVALID_PARAMS, "invalidParams", "Invalid paramters." }, + { rpcINVALID_PARAMS, "invalidParams", "Invalid parameters." }, { rpcNICKNAME_MALFORMED,"nicknameMalformed","Nickname is malformed." }, { rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist." }, { rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname." }, @@ -2022,7 +2022,7 @@ Json::Value RPCServer::doCommand(const std::string& command, Json::Value& params { std::cerr << "RPC:" << command << std::endl; - struct { + static struct { const char* pCommand; doFuncPtr dfpFunc; int iMinParams; From 197a19b996888984018a6bff53058e54b1a50244 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 19:12:06 -0700 Subject: [PATCH 15/23] Beginning transaction persistance. --- src/DBInit.cpp | 5 +---- src/SerializedTransaction.cpp | 30 ++++++++++++++++++++++++++++++ src/SerializedTransaction.h | 8 ++++++++ src/Transaction.cpp | 1 + 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/DBInit.cpp b/src/DBInit.cpp index 0c4826e94..a2b5be277 100644 --- a/src/DBInit.cpp +++ b/src/DBInit.cpp @@ -7,10 +7,7 @@ const char *TxnDBInit[] = { TransType CHARACTER(24) \ FromAcct CHARACTER(35), \ FromSeq BIGINT UNSIGNED, \ - OtherAcct CHARACTER(40), \ - Amount BIGINT UNSIGNED, \ - FirstSeen TEXT, \ - CommitSeq BIGINT UNSIGNED, \ + LedgerSeq BIGINT UNSIGNED, \ Status CHARACTER(1), \ RawTxn BLOB \ );", diff --git a/src/SerializedTransaction.cpp b/src/SerializedTransaction.cpp index d5b7aac3e..a5fce40f2 100644 --- a/src/SerializedTransaction.cpp +++ b/src/SerializedTransaction.cpp @@ -1,5 +1,6 @@ #include "SerializedTransaction.h" +#include "Application.h" #include "Log.h" @@ -297,4 +298,33 @@ Json::Value SerializedTransaction::getJson(int options) const ret["Inner"] = mInnerTxn.getJson(options); return ret; } + +std::string SerializedTransaction::getSQLValueHeader() +{ + return "(TransID, TransType, FromAcct, FromSeq, CommitSeq, Status, RawTxn)"; +} + +std::string SerializedTransaction::getSQLInsertHeader() +{ + return "INSERT INTO Transactions " + getSQLValueHeader() + " VALUES "; +} + +std::string SerializedTransaction::getSQL(uint32 inLedger, char status) const +{ + Serializer s; + add(s); + return getSQL(s, inLedger, status); +} + +std::string SerializedTransaction::getSQL(Serializer rawTxn, uint32 inLedger, char status) const +{ + std::string rTxn; + theApp->getTxnDB()->getDB()->escape( + reinterpret_cast(rawTxn.getDataPtr()), rawTxn.getLength(), rTxn); + return str(boost::format("('%s', '%s', '%s', %d, %d, %c, '%s')") + % getTransactionID().GetHex() % getTransactionType() % getSourceAccount().humanAccountID() + % getSequence() % inLedger % status % rTxn); +} + + // vim:ts=4 diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index 024bbfa54..07b1dca83 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -116,6 +116,14 @@ public: bool sign(const NewcoinAddress& naAccountPrivate); bool checkSign(const NewcoinAddress& naAccountPublic) const; + + // SQL Functions + static std::string getSQLValueHeader(); + static std::string getSQLInsertHeader(); + std::string getSQL(std::string& sql, uint32 inLedger, char status) const; + std::string getSQL(uint32 inLedger, char status) const; + std::string getSQL(Serializer rawTxn, uint32 inLedger, char status) const; + }; #endif diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 328a7aa6f..a724516a1 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -510,6 +510,7 @@ void Transaction::saveTransaction(Transaction::pointer txn) bool Transaction::save() const { // This code needs to be fixed to support new-style transactions - FIXME + // This code is going away. It will be handled from SerializedTransaction #if 0 // Identify minimums fields to write for now. // Also maybe write effected accounts for use later. From 16f68296c4d49e6a9d705d7ef1939b93c22ec02d Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 19:13:09 -0700 Subject: [PATCH 16/23] Avoid warnings. --- src/RPCServer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index a641cf772..a2f161e69 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -517,7 +517,7 @@ Json::Value RPCServer::doAccountInfo(Json::Value ¶ms) // account_lines || [] Json::Value RPCServer::doAccountLines(Json::Value ¶ms) { - uint256 uClosed = mNetOps->getClosedLedger(); +// uint256 uClosed = mNetOps->getClosedLedger(); uint256 uCurrent = mNetOps->getCurrentLedger(); std::string strIdent = params[0u].asString(); From 2d49cacd2961efe429bbd8ed24f1af95dabb6d85 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sat, 9 Jun 2012 22:01:31 -0700 Subject: [PATCH 17/23] Move all SQL operations on ledger close into the ledger code so we can accept ledgers without having to participate in the consensus process. We'll need this when we implement "catch up". Move AcctTx into the same connection as Txn so they can be part of a single transaction. Dispatch ledger accept synchronization functions into a detached thread so it doesn't stall our I/O engine. --- src/Application.cpp | 9 +++------ src/Application.h | 3 +-- src/DBInit.cpp | 9 ++------- src/Ledger.cpp | 36 ++++++++++++++++++++++++++++++++++++ src/LedgerConsensus.cpp | 34 ---------------------------------- src/LedgerHistory.cpp | 4 +++- src/NetworkOPs.cpp | 4 ++-- src/SerializedTransaction.h | 5 +++++ 8 files changed, 52 insertions(+), 52 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 97e0f47d8..2f05c3944 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -35,16 +35,15 @@ DatabaseCon::~DatabaseCon() Application::Application() : mUNL(mIOService), mNetOps(mIOService, &mMasterLedger), mNodeCache(16384, 600), - mTxnDB(NULL), mAcctTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), + mTxnDB(NULL), mLedgerDB(NULL), mWalletDB(NULL), mHashNodeDB(NULL), mNetNodeDB(NULL), mConnectionPool(mIOService), mPeerDoor(NULL), mRPCDoor(NULL) { RAND_bytes(mNonce256.begin(), mNonce256.size()); RAND_bytes(reinterpret_cast(&mNonceST), sizeof(mNonceST)); } -extern const char *AcctTxnDBInit[], *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], - *HashNodeDBInit[], *NetNodeDBInit[]; -extern int TxnDBCount, AcctTxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount, NetNodeDBCount; +extern const char *TxnDBInit[], *LedgerDBInit[], *WalletDBInit[], *HashNodeDBInit[], *NetNodeDBInit[]; +extern int TxnDBCount, LedgerDBCount, WalletDBCount, HashNodeDBCount, NetNodeDBCount; void Application::stop() { @@ -61,7 +60,6 @@ void Application::run() // Construct databases. // mTxnDB = new DatabaseCon("transaction.db", TxnDBInit, TxnDBCount); - mAcctTxnDB = new DatabaseCon("accttx.db", AcctTxnDBInit, AcctTxnDBCount); mLedgerDB = new DatabaseCon("ledger.db", LedgerDBInit, LedgerDBCount); mWalletDB = new DatabaseCon("wallet.db", WalletDBInit, WalletDBCount); mHashNodeDB = new DatabaseCon("hashnode.db", HashNodeDBInit, HashNodeDBCount); @@ -140,7 +138,6 @@ void Application::run() Application::~Application() { delete mTxnDB; - delete mAcctTxnDB; delete mLedgerDB; delete mWalletDB; delete mHashNodeDB; diff --git a/src/Application.h b/src/Application.h index 546d0aad5..1771aa63e 100644 --- a/src/Application.h +++ b/src/Application.h @@ -45,7 +45,7 @@ class Application NetworkOPs mNetOps; NodeCache mNodeCache; - DatabaseCon *mTxnDB, *mAcctTxnDB, *mLedgerDB, *mWalletDB, *mHashNodeDB, *mNetNodeDB; + DatabaseCon *mTxnDB, *mLedgerDB, *mWalletDB, *mHashNodeDB, *mNetNodeDB; ConnectionPool mConnectionPool; PeerDoor* mPeerDoor; @@ -76,7 +76,6 @@ public: NodeCache& getNodeCache() { return mNodeCache; } DatabaseCon* getTxnDB() { return mTxnDB; } - DatabaseCon* getAcctTxnDB() { return mAcctTxnDB; } DatabaseCon* getLedgerDB() { return mLedgerDB; } DatabaseCon* getWalletDB() { return mWalletDB; } DatabaseCon* getHashNodeDB() { return mHashNodeDB; } diff --git a/src/DBInit.cpp b/src/DBInit.cpp index a2b5be277..66a87f8af 100644 --- a/src/DBInit.cpp +++ b/src/DBInit.cpp @@ -14,12 +14,7 @@ const char *TxnDBInit[] = { "CREATE TABLE PubKeys ( \ ID CHARACTER(35) PRIMARY KEY, \ PubKey BLOB \ - );" -}; - -int TxnDBCount = sizeof(TxnDBInit) / sizeof(const char *); - -const char *AcctTxnDBInit[] = { + );", "CREATE TABLE AccountTransactions ( \ TransID CHARACTER(64), \ Account CHARACTER(64), \ @@ -29,7 +24,7 @@ const char *AcctTxnDBInit[] = { AccountTransactions(Account, LedgerSeq, TransID);" }; -int AcctTxnDBCount = sizeof(AcctTxnDBInit) / sizeof(const char *); +int TxnDBCount = sizeof(TxnDBInit) / sizeof(const char *); // Ledger database holds ledgers and ledger confirmations const char *LedgerDBInit[] = { diff --git a/src/Ledger.cpp b/src/Ledger.cpp index a77b0e649..278fa7c22 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -16,6 +16,7 @@ #include "Wallet.h" #include "BinaryFormats.h" #include "LedgerTiming.h" +#include "Log.h" Ledger::Ledger(const NewcoinAddress& masterID, uint64 startAmount) : mTotCoins(startAmount), mCloseTime(0), mLedgerSeq(0), mLedgerInterval(LEDGER_INTERVAL), mClosed(false), mValidHash(false), @@ -261,6 +262,41 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger) while(ledger->mAccountStateMap->flushDirty(64, ACCOUNT_NODE, ledger->mLedgerSeq)) { ; } + SHAMap& txSet = *ledger->peekAccountStateMap(); + Database *db = theApp->getTxnDB()->getDB(); + ScopedLock dbLock = theApp->getTxnDB()->getDBLock(); + db->executeSQL("BEGIN TRANSACTION;"); + for (SHAMapItem::pointer item = txSet.peekFirstItem(); !!item; item = txSet.peekNextItem(item->getTag())) + { + SerializerIterator sit(item->peekSerializer()); + SerializedTransaction txn(sit); + std::vector accts = txn.getAffectedAccounts(); + + std::string sql = "INSERT INTO AccountTransactions (TransID, Account, LedgerSeq) VALUES "; + bool first = true; + for (std::vector::iterator it = accts.begin(), end = accts.end(); it != end; ++it) + { + if (!first) + sql += ", ('"; + else + { + sql += "('"; + first = false; + } + sql += txn.getTransactionID().GetHex(); + sql += "','"; + sql += it->humanAccountID(); + sql += "',"; + sql += boost::lexical_cast(ledger->getLedgerSeq()); + sql += ")"; + } + sql += ";"; + Log(lsTRACE) << "ActTx: " << sql; + db->executeSQL(sql); + db->executeSQL(txn.getSQLInsertHeader() + txn.getSQL(ledger->getLedgerSeq(), TXN_SQL_VALIDATED) + ";"); + // FIXME: If above updates no rows, modify seq/status + } + db->executeSQL("COMMIT TRANSACTION;"); } Ledger::pointer Ledger::getSQL(const std::string& sql) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index fa2ecb189..0fcc1ee13 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -727,40 +727,6 @@ void LedgerConsensus::accept(SHAMap::pointer set) theApp->getConnectionPool().relayMessage(NULL, boost::make_shared(val, newcoin::mtVALIDATION)); Log(lsINFO) << "Validation sent " << newLCL->getHash().GetHex(); statusChange(newcoin::neACCEPTED_LEDGER, newOL); - - // Insert the transactions in set into the AcctTxn database - Database *db = theApp->getAcctTxnDB()->getDB(); - ScopedLock dbLock = theApp->getAcctTxnDB()->getDBLock(); - db->executeSQL("BEGIN TRANSACTION;"); - for (SHAMapItem::pointer item = set->peekFirstItem(); !!item; item = set->peekNextItem(item->getTag())) - { - SerializerIterator sit(item->peekSerializer()); - SerializedTransaction txn(sit); - std::vector accts = txn.getAffectedAccounts(); - - std::string sql = "INSERT INTO AccountTransactions (TransID, Account, LedgerSeq) VALUES "; - bool first = true; - for (std::vector::iterator it = accts.begin(), end = accts.end(); it != end; ++it) - { - if (!first) - sql += ", ('"; - else - { - sql += "('"; - first = false; - } - sql += txn.getTransactionID().GetHex(); - sql += "','"; - sql += it->humanAccountID(); - sql += "',"; - sql += boost::lexical_cast(newLedgerSeq); - sql += ")"; - } - sql += ";"; - Log(lsTRACE) << "ActTx: " << sql; - db->executeSQL(sql); - } - db->executeSQL("COMMIT TRANSACTION;"); } void LedgerConsensus::endConsensus() diff --git a/src/LedgerHistory.cpp b/src/LedgerHistory.cpp index 3ea397d83..ad357139a 100644 --- a/src/LedgerHistory.cpp +++ b/src/LedgerHistory.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "LedgerHistory.h" #include "Config.h" @@ -32,7 +33,8 @@ void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger) boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex()); mLedgersByHash.canonicalize(h, ledger); mLedgersByIndex.insert(std::make_pair(ledger->getLedgerSeq(), ledger)); - theApp->getIOService().post(boost::bind(&Ledger::saveAcceptedLedger, ledger)); + boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, ledger)); + thread.detach(); } Ledger::pointer LedgerHistory::getLedgerBySeq(uint32 index) diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 0efcc2b30..db14bbf94 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -542,8 +542,8 @@ std::vector< std::pair > " WHERE Account = '%s' AND LedgerSeq <= '%d' AND LedgerSeq >= '%d' ORDER BY LedgerSeq LIMIT 1000") % account.humanAccountID() % maxLedger % minLedger); - Database *db = theApp->getAcctTxnDB()->getDB(); - ScopedLock dbLock = theApp->getAcctTxnDB()->getDBLock(); + Database *db = theApp->getTxnDB()->getDB(); + ScopedLock dbLock = theApp->getTxnDB()->getDBLock(); SQL_FOREACH(db, sql) { diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index 07b1dca83..ddb78a699 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -10,6 +10,11 @@ #include "TransactionFormats.h" #include "NewcoinAddress.h" +#define TXN_SQL_NEW 'N' +#define TXN_SQL_CONFLICT 'C' +#define TXN_SQL_HELD 'H' +#define TXN_SQL_VALIDATED 'V' + class SerializedTransaction : public SerializedType { public: From c15d7129cb383f2a5863154625adfd9ba0a8a0ca Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Sat, 9 Jun 2012 23:59:46 -0700 Subject: [PATCH 18/23] Convert more RPC errors to token format. --- src/RPCServer.cpp | 56 +++++++++++++++++++++++++++++------------------ src/RPCServer.h | 25 +++++++++++++++------ 2 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index a641cf772..ab8785ff7 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -45,29 +45,40 @@ Json::Value RPCServer::RPCError(int iError) const char* pToken; const char* pMessage; } errorInfoA[] = { + { rpcACT_EXISTS, "actExists", "Account already exists." }, + { rpcACT_MALFORMED, "actMalformed", "Account malformed." }, + { rpcACT_NOT_FOUND, "actNotFound", "Account not found." }, { rpcBAD_SEED, "badSeed", "Disallowed seed." }, { rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." }, { rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency is malformed." }, + { rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." }, { rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed." }, { rpcINSUF_FUNDS, "insufFunds", "Insufficient funds." }, { rpcINTERNAL, "internal", "Internal error." }, { rpcINVALID_PARAMS, "invalidParams", "Invalid parameters." }, + { rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid." }, + { rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed." }, + { rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found." }, + { rpcMUST_SEND_XNS, "mustSendXns", "Can only send XNS to accounts which are not created." }, { rpcNICKNAME_MALFORMED,"nicknameMalformed","Nickname is malformed." }, { rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist." }, { rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname." }, + { rpcNOT_IMPL, "notImpl", "Not implemented." }, { rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable." }, { rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable." }, { rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." }, { rpcNO_NETWORK, "noNetwork", "Network not available." }, - { rpcNOT_IMPL, "notImpl", "Not implemented." }, { rpcPASSWD_CHANGED, "passwdChanged", "Wrong key, password changed." }, + { rpcPORT_MALFORMED, "portMalformed", "Port is malformed." }, { rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed." }, { rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." }, { rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency is malformed." }, { rpcSRC_MISSING, "srcMissing", "Source account does not exist." }, { rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." }, { rpcSUCCESS, "success", "Success." }, + { rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." }, { rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown command." }, + { rpcWRONG_PASSWORD, "wrongPassword", "Wrong password." }, { rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key." }, }; @@ -245,14 +256,14 @@ Json::Value RPCServer::getMasterGenerator(const uint256& uLedger, const NewcoinA if (!sleGen) { // No account has been claimed or has had it password set for seed. - return JSONRPCError(500, "wrong password"); + return RPCError(rpcWRONG_PASSWORD); } std::vector vucCipher = sleGen->getIFieldVL(sfGenerator); std::vector vucMasterGenerator = na0Private.accountPrivateDecrypt(na0Public, vucCipher); if (vucMasterGenerator.empty()) { - return JSONRPCError(500, "internal error: password failed to decrypt master public generator"); + return RPCError(rpcFAIL_GEN_DECRPYT); } naMasterGenerator.setFamilyGenerator(vucMasterGenerator); @@ -725,7 +736,7 @@ Json::Value RPCServer::doConnect(Json::Value& params) // YYY Should make an extract int. if (!extractString(strPort, params, 1)) - return JSONRPCError(500, "Bad port"); + return RPCError(rpcPORT_MALFORMED); iPort = boost::lexical_cast(strPort); } @@ -1028,17 +1039,17 @@ Json::Value RPCServer::doPasswordSet(Json::Value& params) if (!naMasterSeed.setFamilySeedGeneric(params[0u].asString())) { // Should also not allow account id's as seeds. - return "master seed expected"; + return RPCError(rpcBAD_SEED); } else if (!naRegularSeed.setFamilySeedGeneric(params[1u].asString())) { // Should also not allow account id's as seeds. - return "regular seed expected"; + return RPCError(rpcBAD_SEED); } // YYY Might use account from string to be more flexible. else if (params.size() >= 3 && !naAccountID.setAccountID(params[2u].asString())) { - return "bad account"; + return RPCError(rpcACT_MALFORMED); } else { @@ -1088,7 +1099,7 @@ Json::Value RPCServer::doPasswordSet(Json::Value& params) if (!iMax) { - return "account not found"; + return RPCError(rpcACT_NOT_FOUND); } Transaction::pointer trns = Transaction::sharedPasswordSet( @@ -1205,7 +1216,7 @@ Json::Value RPCServer::doSend(Json::Value& params) } else if (!saDstAmount.isNative()) { - return JSONRPCError(500, "Can only send XNS to accounts which are not created."); + return RPCError(rpcMUST_SEND_XNS); } else { @@ -1327,7 +1338,9 @@ Json::Value RPCServer::doTx(Json::Value& params) uint256 txid(param1); Transaction::pointer txn=theApp->getMasterTransaction().fetch(txid, true); - if (!txn) return JSONRPCError(500, "Transaction not found"); + + if (!txn) return RPCError(rpcTXN_NOT_FOUND); + return txn->getJson(true); } @@ -1364,7 +1377,7 @@ Json::Value RPCServer::doLedger(Json::Value& params) ledger = theApp->getMasterLedger().getLedgerBySeq(boost::lexical_cast(param)); if (!ledger) - return JSONRPCError(503, "Unable to locate ledger"); + return RPCError(rpcLGR_NOT_FOUND); bool full = false; if (extractString(param, params, 1)) @@ -1390,10 +1403,11 @@ Json::Value RPCServer::doAccountTransactions(Json::Value& params) NewcoinAddress account; if (!account.setAccountID(param)) - return JSONRPCError(500, "invalid account"); + return RPCError(rpcACT_MALFORMED); if (!extractString(param, params, 1)) - return JSONRPCError(500, "invalid ledger index"); + return RPCError(rpcLGR_IDX_MALFORMED); + minLedger = boost::lexical_cast(param); if ((params.size() == 3) && extractString(param, params, 2)) @@ -1404,7 +1418,7 @@ Json::Value RPCServer::doAccountTransactions(Json::Value& params) if ((maxLedger < minLedger) || (minLedger == 0) || (maxLedger == 0)) { std::cerr << "minL=" << minLedger << ", maxL=" << maxLedger << std::endl; - return JSONRPCError(500, "invalid ledger indexes"); + return RPCError(rpcLGR_IDXS_INVALID); } #ifndef DEBUG @@ -1446,7 +1460,7 @@ Json::Value RPCServer::doAccountTransactions(Json::Value& params) } catch (...) { - return JSONRPCError(500, "internal error"); + return RPCError(rpcINTERNAL); } #endif } @@ -1606,11 +1620,11 @@ Json::Value RPCServer::doWalletAdd(Json::Value& params) } else if (!naSrcAccountID.setAccountID(params[1u].asString())) { - return JSONRPCError(500, "source account id needed"); + return RPCError(rpcSRC_ACT_MALFORMED); } else if (!naMasterSeed.setFamilySeedGeneric(params[2u].asString())) { - return "master seed expected"; + return RPCError(rpcBAD_SEED); } else if (params.size() >= 4 && !saAmount.setValue(params[3u].asString(), sDstCurrency)) { @@ -1707,12 +1721,12 @@ Json::Value RPCServer::doWalletClaim(Json::Value& params) if (!naMasterSeed.setFamilySeedGeneric(params[0u].asString())) { // Should also not allow account id's as seeds. - return "master seed expected"; + return RPCError(rpcBAD_SEED); } else if (!naRegularSeed.setFamilySeedGeneric(params[1u].asString())) { // Should also not allow account id's as seeds. - return "regular seed expected"; + return RPCError(rpcBAD_SEED); } else { @@ -1804,11 +1818,11 @@ Json::Value RPCServer::doWalletCreate(Json::Value& params) } else if (!naDstAccountID.setAccountID(params[2u].asString())) { - return "create account id needed"; + return RPCError(rpcDST_ACT_MALFORMED); } else if (mNetOps->getAccountState(uLedger, naDstAccountID)) { - return "account already exists"; + return RPCError(rpcACT_EXISTS); } // Trying to build: diff --git a/src/RPCServer.h b/src/RPCServer.h index 3058760e8..8eea5c60b 100644 --- a/src/RPCServer.h +++ b/src/RPCServer.h @@ -18,37 +18,48 @@ public: rpcSUCCESS, // Networking - rpcNO_NETWORK, rpcNO_CLOSED, rpcNO_CURRENT, + rpcNO_NETWORK, // Ledger state + rpcACT_EXISTS, + rpcACT_NOT_FOUND, rpcINSUF_FUNDS, + rpcLGR_NOT_FOUND, + rpcMUST_SEND_XNS, + rpcNICKNAME_MISSING, rpcPASSWD_CHANGED, rpcSRC_MISSING, rpcSRC_UNCLAIMED, + rpcTXN_NOT_FOUND, + rpcWRONG_PASSWORD, rpcWRONG_SEED, - rpcNICKNAME_MISSING, // Malformed command rpcINVALID_PARAMS, rpcUNKNOWN_COMMAND, // Bad paramater + rpcACT_MALFORMED, rpcBAD_SEED, - rpcSRC_ACT_MALFORMED, rpcDST_ACT_MALFORMED, - rpcPUBLIC_MALFORMED, - rpcHOST_IP_MALFORMED, - rpcSRC_AMT_MALFORMED, rpcDST_AMT_MALFORMED, + rpcHOST_IP_MALFORMED, + rpcLGR_IDXS_INVALID, + rpcLGR_IDX_MALFORMED, rpcNICKNAME_MALFORMED, rpcNICKNAME_PERM, + rpcPORT_MALFORMED, + rpcPUBLIC_MALFORMED, + rpcSRC_ACT_MALFORMED, + rpcSRC_AMT_MALFORMED, // Internal error (should never happen) rpcINTERNAL, // Generic internal error. - rpcNO_GEN_DECRPYT, + rpcFAIL_GEN_DECRPYT, rpcNOT_IMPL, + rpcNO_GEN_DECRPYT, }; Json::Value RPCError(int iError); From 97d9cb9bc97e8080ded3f1727e09f03f80ba1bff Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 10 Jun 2012 00:43:11 -0700 Subject: [PATCH 19/23] Oops. --- src/Ledger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 278fa7c22..0c5929082 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -262,7 +262,7 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger) while(ledger->mAccountStateMap->flushDirty(64, ACCOUNT_NODE, ledger->mLedgerSeq)) { ; } - SHAMap& txSet = *ledger->peekAccountStateMap(); + SHAMap& txSet = *ledger->peekTransactionMap(); Database *db = theApp->getTxnDB()->getDB(); ScopedLock dbLock = theApp->getTxnDB()->getDBLock(); db->executeSQL("BEGIN TRANSACTION;"); From 191cb59b003ffb539dacc8826344eb725d9109e3 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 10 Jun 2012 01:03:37 -0700 Subject: [PATCH 20/23] Set these in stone. --- src/LedgerFormats.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/LedgerFormats.h b/src/LedgerFormats.h index d90d0114d..53da1d617 100644 --- a/src/LedgerFormats.h +++ b/src/LedgerFormats.h @@ -18,16 +18,16 @@ enum LedgerEntryType // Used as a prefix for computing ledger indexes (keys). enum LedgerNameSpace { - spaceAccount, - spaceGenerator, - spaceNickname, - spaceRipple, - spaceRippleDir, - spaceOffer, - spaceOfferDir, - spaceBond, - spaceInvoice, - spaceMultiSig, + spaceAccount = 0, + spaceGenerator = 1, + spaceNickname = 2, + spaceRipple = 3, + spaceRippleDir = 4, + spaceOffer = 5, + spaceOfferDir = 6, + spaceBond = 7, + spaceInvoice = 8, + spaceMultiSig = 9, }; enum LedgerSpecificFlags From 7a114e7d84f81a937a7430d16fad84ebc67e98ec Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 10 Jun 2012 01:05:24 -0700 Subject: [PATCH 21/23] Make the account state tag more readable. --- src/Ledger.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 0c5929082..146ccd1a4 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -401,7 +401,16 @@ void Ledger::addJson(Json::Value& ret, int options) SerializedLedgerEntry sle(sit, item->getTag()); state.append(sle.getJson(0)); } - else state.append(item->getTag().GetHex()); + else + { // 16-bit namespace, 160-bit tag, 80-bit index + const uint256& tag = item->getTag(); + uint160 account; + memcpy(account.begin(), tag.begin() + 4, account.size()); + NewcoinAddress naAccount; + naAccount.setAccountID(account); + state.append(strHex(tag.begin(), 4) + ":" + naAccount.humanAccountID() + ":" + + strHex(tag.begin() + 4 + account.size(), tag.size() - (account.size() + 4))); + } } ledger["AccountState"] = state; } From a37d203d9bd3cf44661438f9922a2461bee79a0f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 10 Jun 2012 01:05:48 -0700 Subject: [PATCH 22/23] Dead line. --- src/LedgerConsensus.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/LedgerConsensus.cpp b/src/LedgerConsensus.cpp index 0fcc1ee13..58385ca93 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -654,7 +654,6 @@ void LedgerConsensus::accept(SHAMap::pointer set) Log(lsDEBUG) << "Previous LCL " << mPreviousLedger->getHash().GetHex(); Ledger::pointer newLCL = boost::make_shared(false, boost::ref(*mPreviousLedger)); - uint32 newLedgerSeq = newLCL->getLedgerSeq(); #ifdef DEBUG Json::StyledStreamWriter ssw; From 014684be0736f3b39cd9d7987e1efdc1fddbc667 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Sun, 10 Jun 2012 01:09:53 -0700 Subject: [PATCH 23/23] Nevermind. --- src/Ledger.cpp | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 146ccd1a4..108757eee 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -402,15 +402,7 @@ void Ledger::addJson(Json::Value& ret, int options) state.append(sle.getJson(0)); } else - { // 16-bit namespace, 160-bit tag, 80-bit index - const uint256& tag = item->getTag(); - uint160 account; - memcpy(account.begin(), tag.begin() + 4, account.size()); - NewcoinAddress naAccount; - naAccount.setAccountID(account); - state.append(strHex(tag.begin(), 4) + ":" + naAccount.humanAccountID() + ":" + - strHex(tag.begin() + 4 + account.size(), tag.size() - (account.size() + 4))); - } + state.append(item->getTag().GetHex()); } ledger["AccountState"] = state; }