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); diff --git a/src/DBInit.cpp b/src/DBInit.cpp index 470d28fb3..0c4826e94 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), \ 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 bd15efe5f..fa2ecb189 100644 --- a/src/LedgerConsensus.cpp +++ b/src/LedgerConsensus.cpp @@ -731,30 +731,36 @@ 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()); 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 += ", ("; - 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 += ";"; + Log(lsTRACE) << "ActTx: " << sql; db->executeSQL(sql); } - db->executeSQL("COMMIT TRANSACTION"); + db->executeSQL("COMMIT TRANSACTION;"); } void LedgerConsensus::endConsensus() diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index 85508664f..0efcc2b30 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -528,4 +528,31 @@ void NetworkOPs::setMode(OperatingMode om) mMode = om; } +#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) +{ + std::vector< std::pair > affectedAccounts; + + 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() % maxLedger % minLedger); + + 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; +} + // vim:ts=4 diff --git a/src/NetworkOPs.h b/src/NetworkOPs.h index 005ef02a9..0514a0902 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 c098ec507..130fdd806 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -321,7 +321,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) { @@ -1147,7 +1147,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; @@ -1453,7 +1453,7 @@ Json::Value RPCServer::doLedger(Json::Value& params) { return "invalid params"; } - else if (!mNetOps->available()) + if (!mNetOps->available()) { return JSONRPCError(503, "network not available"); } @@ -1499,6 +1499,84 @@ 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)) + return JSONRPCError(500, "invalid ledger index"); + 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)) + { + 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); + 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) + { + if (it->first != currentLedger) // different/new ledger + { + if (currentLedger != 0) // add old ledger + { + ledger["Transactions"] = jtxns; + ledgers.append(ledger); + ledger = Json::objectValue; + } + currentLedger = it->first; + ledger["LedgerSeq"] = currentLedger; + jtxns = Json::arrayValue; + } + jtxns.append(it->second.GetHex()); + } + if (currentLedger != 0) + { + ledger["Transactions"] = jtxns; + ledgers.append(ledger); + } + + ret["Ledgers"] = ledgers; + return ret; +#ifndef DEBUG + } + catch (...) + { + return JSONRPCError(500, "internal error"); + } +#endif +} + // unl_add | [] Json::Value RPCServer::doUnlAdd(Json::Value& params) { @@ -2178,13 +2256,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: