diff --git a/src/Ledger.cpp b/src/Ledger.cpp index 108757eeef..168c97cd56 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -294,7 +294,7 @@ void Ledger::saveAcceptedLedger(Ledger::pointer ledger) 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 + // FIXME: If above updates no rows, modify seq/status (upsert) } db->executeSQL("COMMIT TRANSACTION;"); } diff --git a/src/RPCServer.cpp b/src/RPCServer.cpp index 95675b9cfe..53064f3114 100644 --- a/src/RPCServer.cpp +++ b/src/RPCServer.cpp @@ -1340,7 +1340,7 @@ Json::Value RPCServer::doTx(Json::Value& params) Json::Value ret; uint256 txid(param1); - Transaction::pointer txn=theApp->getMasterTransaction().fetch(txid, true); + Transaction::pointer txn = theApp->getMasterTransaction().fetch(txid, true); if (!txn) return RPCError(rpcTXN_NOT_FOUND); @@ -1372,7 +1372,7 @@ Json::Value RPCServer::doLedger(Json::Value& params) Ledger::pointer ledger; if (param == "current") ledger = theApp->getMasterLedger().getCurrentLedger(); - else if (param == "lastclosed") + else if ((param == "lastclosed") || (param == "lastaccepted")) ledger = theApp->getMasterLedger().getClosedLedger(); else if (param.size() > 12) ledger = theApp->getMasterLedger().getLedgerByHash(uint256(param)); @@ -1382,13 +1382,7 @@ Json::Value RPCServer::doLedger(Json::Value& params) if (!ledger) return RPCError(rpcLGR_NOT_FOUND); - bool full = false; - if (extractString(param, params, 1)) - { - if (param == "full") - full = true; - } - + bool full = extractString(param, params, 1) && (param == "full"); Json::Value ret(Json::objectValue); ledger->addJson(ret, full ? LEDGER_JSON_FULL : 0); return ret; diff --git a/src/SerializedTransaction.h b/src/SerializedTransaction.h index ddb78a6997..2ec1bced89 100644 --- a/src/SerializedTransaction.h +++ b/src/SerializedTransaction.h @@ -14,6 +14,8 @@ #define TXN_SQL_CONFLICT 'C' #define TXN_SQL_HELD 'H' #define TXN_SQL_VALIDATED 'V' +#define TXN_SQL_INCLUDED 'I' +#define TXN_SQL_UNKNOWN 'U' class SerializedTransaction : public SerializedType { diff --git a/src/Serializer.cpp b/src/Serializer.cpp index cae1962967..09536bb557 100644 --- a/src/Serializer.cpp +++ b/src/Serializer.cpp @@ -508,7 +508,7 @@ void Serializer::TestSerializer() int SerializerIterator::getBytesLeft() { - return mSerializer.getLength()-mPos; + return mSerializer.size() - mPos; } unsigned char SerializerIterator::get8() diff --git a/src/Serializer.h b/src/Serializer.h index e747a4fd57..f21940cf8a 100644 --- a/src/Serializer.h +++ b/src/Serializer.h @@ -21,7 +21,7 @@ protected: std::vector mData; public: - Serializer(int n=256) { mData.reserve(n); } + Serializer(int n = 256) { mData.reserve(n); } Serializer(const std::vector &data) : mData(data) { ; } Serializer(const std::string& data) : mData(data.data(), (data.data()) + data.size()) { ; } @@ -72,23 +72,29 @@ public: static uint256 getSHA512Half(const std::string& strData); // totality functions - int getLength() const { return mData.size(); } - const void* getDataPtr() const { return &mData.front(); } - void* getDataPtr() { return &mData.front(); } + int getCapacity() const { return mData.capacity(); } + int getDataLength() const { return mData.size(); } + const void* getDataPtr() const { return &mData.front(); } + void* getDataPtr() { return &mData.front(); } + int getLength() { return mData.size(); } const std::vector& peekData() const { return mData; } std::vector getData() const { return mData; } - std::string getString() const { return std::string(static_cast(getDataPtr()), getLength()); } + std::string getString() const { return std::string(static_cast(getDataPtr()), size()); } void secureErase() { memset(&(mData.front()), 0, mData.size()); erase(); } void erase() { mData.clear(); } int removeLastByte(); bool chop(int num); // vector-like functions - std::vector::iterator begin() { return mData.begin(); } - std::vector::iterator end() { return mData.end(); } + std::vector::iterator begin() { return mData.begin(); } + std::vector::iterator end() { return mData.end(); } std::vector::const_iterator begin() const { return mData.begin(); } - std::vector::const_iterator end() const { return mData.end(); } - std::vector::size_type size() const { return mData.size(); } + std::vector::const_iterator end() const { return mData.end(); } + std::vector::size_type size() const { return mData.size(); } + void reserve(size_t n) { mData.reserve(n); } + void resize(size_t n) { mData.resize(n); } + size_t capacity() const { return mData.capacity(); } + bool operator==(const std::vector& v) { return v == mData; } bool operator!=(const std::vector& v) { return v != mData; } diff --git a/src/Transaction.cpp b/src/Transaction.cpp index a724516a16..75ff15a111 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -508,61 +508,34 @@ void Transaction::saveTransaction(Transaction::pointer txn) txn->save(); } -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. +bool Transaction::save() +{ if ((mStatus == INVALID) || (mStatus == REMOVED)) return false; - std::string sql = "INSERT INTO Transactions " - "(TransID,TransType,FromAcct,FromSeq,OtherAcct,Amount,FirstSeen,CommitSeq,Status,RawTxn)" - " VALUES ('"; - sql.append(mTransactionID.GetHex()); - sql.append("','"); - sql.append(mTransaction->getTransactionType()); - sql.append("','"); - sql.append(mAccountFrom.humanAccountID()); - sql.append("','"); - sql.append(boost::lexical_cast(mTransaction->getSequence())); - sql.append("','"); - sql.append(mTransaction->getITFieldString(sfDestination)); - sql.append("','"); - sql.append(mTransaction->getITFieldString(sfAmount)); - sql.append("',now(),'"); - sql.append(boost::lexical_cast(mInLedger)); + char status; switch(mStatus) { - case NEW: sql.append("','N',"); break; - case INCLUDED: sql.append("','A',"); break; - case CONFLICTED: sql.append("','C',"); break; - case COMMITTED: sql.append("','D',"); break; - case HELD: sql.append("','H',"); break; - default: sql.append("','U',"); break; + case NEW: status = TXN_SQL_NEW; break; + case INCLUDED: status = TXN_SQL_INCLUDED; break; + case CONFLICTED: status = TXN_SQL_CONFLICT; break; + case COMMITTED: status = TXN_SQL_VALIDATED; break; + case HELD: status = TXN_SQL_HELD; break; + default: status = TXN_SQL_UNKNOWN; } - Serializer s; - mTransaction->getTransaction(s, false); - - std::string rawTxn; - theApp->getTxnDB()->getDB()->escape(static_cast(s.getDataPtr()), s.getLength(), rawTxn); - sql.append(rawTxn); - sql.append(");"); - - ScopedLock sl(theApp->getTxnDB()->getDBLock()); - Database* db = theApp->getTxnDB()->getDB(); - return db->executeSQL(sql); -#endif - return true; + // FIXME: This needs to check if the transaction is already there and not + // de-confirm it + Database *db = theApp->getTxnDB()->getDB(); + ScopedLock dbLock = theApp->getTxnDB()->getDBLock(); + return db->executeSQL(mTransaction->getSQLInsertHeader() + mTransaction->getSQL(getLedger(), status) + ";"); } Transaction::pointer Transaction::transactionFromSQL(const std::string& sql) -{ // This code needs to be fixed to support new-style transactions - FIXME - std::vector rawTxn; +{ + Serializer rawTxn(2048); std::string status; + uint32 inLedger; - rawTxn.reserve(2048); { ScopedLock sl(theApp->getTxnDB()->getDBLock()); Database* db = theApp->getTxnDB()->getDB(); @@ -571,34 +544,38 @@ Transaction::pointer Transaction::transactionFromSQL(const std::string& sql) return Transaction::pointer(); db->getStr("Status", status); - int txSize = db->getBinary("RawTxn", &(rawTxn.front()), rawTxn.size()); - rawTxn.resize(txSize); - if (txSize>rawTxn.size()) db->getBinary("RawTxn", &(rawTxn.front()), rawTxn.size()); + inLedger = db->getInt("LedgerSeq"); + int txSize = db->getBinary("RawTxn", &*rawTxn.begin(), rawTxn.capacity()); + if (txSize > rawTxn.size()) + { + rawTxn.resize(txSize); + db->getBinary("RawTxn", &*rawTxn.begin(), rawTxn.capacity()); + } + else rawTxn.resize(txSize); db->endIterRows(); } - Serializer s(rawTxn); - SerializerIterator it(s); + SerializerIterator it(rawTxn); SerializedTransaction::pointer txn = boost::make_shared(boost::ref(it)); Transaction::pointer tr = boost::make_shared(txn, true); TransStatus st(INVALID); switch (status[0]) { - case 'N': st = NEW; break; + case TXN_SQL_NEW: st = NEW; break; case 'A': st = INCLUDED; break; case 'C': st = CONFLICTED; break; case 'D': st = COMMITTED; break; case 'H': st = HELD; break; } tr->setStatus(st); - + tr->setLedger(inLedger); return tr; } Transaction::pointer Transaction::load(const uint256& id) { - std::string sql = "SELECT Status,RawTxn FROM Transactions WHERE TransID='"; + std::string sql = "SELECT LedgerSeq,Status,RawTxn FROM Transactions WHERE TransID='"; sql.append(id.GetHex()); sql.append("';"); return transactionFromSQL(sql); @@ -606,7 +583,7 @@ Transaction::pointer Transaction::load(const uint256& id) Transaction::pointer Transaction::findFrom(const NewcoinAddress& fromID, uint32 seq) { - std::string sql = "SELECT Status,RawTxn FROM Transactions WHERE FromID='"; + std::string sql = "SELECT LedgerSeq,Status,RawTxn FROM Transactions WHERE FromID='"; sql.append(fromID.humanAccountID()); sql.append("' AND FromSeq='"); sql.append(boost::lexical_cast(seq)); diff --git a/src/Transaction.h b/src/Transaction.h index 2510a04e64..c87b18d19d 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -248,10 +248,11 @@ public: void setStatus(TransStatus status, uint32 ledgerSeq); void setStatus(TransStatus status) { mStatus=status; } + void setLedger(uint32 ledger) { mInLedger = ledger; } // database functions static void saveTransaction(Transaction::pointer); - bool save() const; + bool save(); static Transaction::pointer load(const uint256& id); static Transaction::pointer findFrom(const NewcoinAddress& fromID, uint32 seq); diff --git a/src/TransactionMaster.cpp b/src/TransactionMaster.cpp index 8cddedf819..2ed33f8de0 100644 --- a/src/TransactionMaster.cpp +++ b/src/TransactionMaster.cpp @@ -21,7 +21,7 @@ TransactionMaster::TransactionMaster() : mCache(CACHED_TRANSACTION_NUM, CACHED_T Transaction::pointer TransactionMaster::fetch(const uint256& txnID, bool checkDisk) { Transaction::pointer txn = mCache.fetch(txnID); - if( !checkDisk || txn) return txn; + if (!checkDisk || txn) return txn; txn = Transaction::load(txnID); if (!txn) return txn; diff --git a/src/main.cpp b/src/main.cpp index 7d2e6df332..4c6bc5213e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -48,7 +48,7 @@ void printHelp(const po::options_description& desc) cout << " data_delete " << endl; cout << " data_fetch " << endl; cout << " data_store " << endl; - cout << " ledger" << endl; + cout << " ledger [|current|lastclosed] [full]" << endl; cout << " nickname_info " << endl; cout << " nickname_set [] []" << endl; cout << " password_fund []" << endl; @@ -57,7 +57,7 @@ void printHelp(const po::options_description& desc) cout << " send [] [] []" << endl; cout << " stop" << endl; cout << " transit_set " << endl; - cout << " tx" << endl; + cout << " tx " << endl; cout << " unl_add | []" << endl; cout << " unl_delete " << endl; cout << " unl_list" << endl;