diff --git a/src/DBInit.cpp b/src/DBInit.cpp index 3bc64d4f9e..116df78874 100644 --- a/src/DBInit.cpp +++ b/src/DBInit.cpp @@ -4,17 +4,15 @@ const char *TxnDBInit[] = { "CREATE TABLE Transactions ( \ TransID CHARACTER(64) PRIMARY KEY, \ + TransType CHARACTER(24) \ FromAcct CHARACTER(35), \ FromSeq BIGINT UNSIGNED, \ - FromLedger BIGINT UNSIGNED, \ - Identifier BIGINT UNSIGNED, \ - ToAcct CHARACTER(35), \ + OtherAcct CHARACTER(40), \ Amount BIGINT UNSIGNED, \ - Fee BIGINT UNSIGNED, \ FirstSeen TEXT, \ CommitSeq BIGINT UNSIGNED, \ Status CHARACTER(1), \ - Signature BLOB \ + RawTxn BLOB \ );", "CREATE TABLE PubKeys ( \ ID CHARACTER(35) PRIMARY KEY, \ diff --git a/src/Ledger.cpp b/src/Ledger.cpp index a6d3bd57a1..7779e72fc5 100644 --- a/src/Ledger.cpp +++ b/src/Ledger.cpp @@ -154,7 +154,9 @@ bool Ledger::addTransaction(Transaction::pointer trans) { // low-level - just add to table assert(!mAccepted); assert(!!trans->getID()); - SHAMapItem::pointer item=boost::make_shared(trans->getID(), trans->getSigned()->getData()); + Serializer s; + trans->getSTransaction()->getTransaction(s, false); + SHAMapItem::pointer item=boost::make_shared(trans->getID(), s.peekData()); return mTransactionMap->addGiveItem(item, true); } diff --git a/src/NetworkOPs.cpp b/src/NetworkOPs.cpp index e5a1279c60..5ef3a0e8c9 100644 --- a/src/NetworkOPs.cpp +++ b/src/NetworkOPs.cpp @@ -71,7 +71,8 @@ Transaction::pointer NetworkOPs::processTransaction(Transaction::pointer trans, newcoin::TMTransaction *tx=new newcoin::TMTransaction(); - Serializer::pointer s(trans->getSigned()); + Serializer::pointer s; + trans->getSTransaction()->getTransaction(*s, false); tx->set_rawtransaction(&s->getData().front(), s->getLength()); tx->set_status(newcoin::tsCURRENT); tx->set_receivetimestamp(getNetworkTime()); diff --git a/src/Peer.cpp b/src/Peer.cpp index c032b77f4f..14e1900048 100644 --- a/src/Peer.cpp +++ b/src/Peer.cpp @@ -5,6 +5,7 @@ //#include #include #include +#include #include "../json/writer.h" @@ -13,6 +14,7 @@ #include "Config.h" #include "Application.h" #include "Conversion.h" +#include "SerializedTransaction.h" Peer::Peer(boost::asio::io_service& io_service) : mSocket(io_service) @@ -335,12 +337,20 @@ void Peer::recvTransaction(newcoin::TMTransaction& packet) std::cerr << "Got transaction from peer" << std::endl; #endif - std::string rawTx=packet.rawtransaction(); - std::vector rTx(rawTx.begin(), rawTx.end()); - Transaction::pointer tx=boost::make_shared(rTx, true); + Transaction::pointer tx; + try + { + std::string rawTx=packet.rawtransaction(); + Serializer s(std::vector(rawTx.begin(), rawTx.end())); + SerializerIterator sit(s); + SerializedTransaction::pointer stx=boost::make_shared(boost::ref(sit), -1); - if(tx->getStatus()==INVALID) - { // transaction fails basic validity tests + if(stx->getTxnType()!=ttMAKE_PAYMENT) throw(0); // FIXME to support other transaction + tx=boost::make_shared(stx, true); + if(tx->getStatus()==INVALID) throw(0); + } + catch (...) + { #ifdef DEBUG std::cerr << "Transaction from peer fails validity tests" << std::endl; Json::StyledStreamWriter w; diff --git a/src/Transaction.cpp b/src/Transaction.cpp index 01f27b37bb..d05e0e9b13 100644 --- a/src/Transaction.cpp +++ b/src/Transaction.cpp @@ -2,45 +2,45 @@ #include "boost/lexical_cast.hpp" #include "boost/make_shared.hpp" +#include "boost/ref.hpp" #include "Application.h" #include "Transaction.h" #include "Wallet.h" #include "BitcoinUtil.h" -#include "BinaryFormats.h" - -using namespace std; - -Transaction::Transaction() : mTransactionID(0), mAccountFrom(), mAccountTo(), - mAmount(0), mFee(0), mFromAccountSeq(0), mSourceLedger(0), mIdent(0), - mInLedger(0), mStatus(INVALID) -{ -} +#include "Serializer.h" +#include "SerializedTransaction.h" Transaction::Transaction(LocalAccount::pointer fromLocalAccount, const NewcoinAddress& toAccount, uint64 amount, - uint32 ident, uint32 ledger) : - mAccountTo(toAccount), mAmount(amount), mSourceLedger(ledger), mIdent(ident), mInLedger(0), mStatus(NEW) + uint32 ident, uint32 ledger) : mInLedger(0), mStatus(NEW) { mAccountFrom=fromLocalAccount->getAddress(); + mAccountTo=toAccount; + + mTransaction=boost::make_shared(ttMAKE_PAYMENT); + mFromPubKey=fromLocalAccount->getPublicKey(); assert(mFromPubKey); - mFromAccountSeq=fromLocalAccount->getTxnSeq(); + mTransaction->setSigningAccount(mFromPubKey->GetPubKey()); -#ifdef DEBUG - std::cerr << "Construct local Txn" << std::endl; - std::cerr << "ledger(" << ledger << "), fromseq(" << mFromAccountSeq << ")" << std::endl; -#endif + mTransaction->setSequence(fromLocalAccount->getTxnSeq()); + assert(mTransaction->getSequence()!=0); + mTransaction->setTransactionFee(100); // for now - if(!mFromAccountSeq) + mTransaction->setITFieldVL(sfDestination, toAccount.getAccountPublic()); + mTransaction->setITFieldU64(sfAmount, amount); + if(ledger!=0) { -#ifdef DEBUG - std::cerr << "Bad source account sequence" << std::endl; - assert(false); -#endif - mStatus=INCOMPLETE; + mTransaction->makeITFieldPresent(sfTargetLedger); + mTransaction->setITFieldU32(sfTargetLedger, ledger); } + if(ident!=0) + { + mTransaction->makeITFieldPresent(sfSourceTag); + mTransaction->setITFieldU32(sfSourceTag, ident); + } + assert(mFromPubKey); - updateFee(); if(!sign(fromLocalAccount)) { #ifdef DEBUG @@ -50,22 +50,22 @@ Transaction::Transaction(LocalAccount::pointer fromLocalAccount, const NewcoinAd } } -Transaction::Transaction(const std::vector &t, bool validate) : mStatus(INVALID) +Transaction::Transaction(SerializedTransaction::pointer sit, bool validate) : mStatus(INVALID), mTransaction(sit) { uint160 toAccountID; uint160 fromAccountID; - - Serializer s(t); - if(s.getLength() pubKey; - if(!s.getRaw(pubKey, BTxPSPubK, BTxLSPubK)) { assert(false); return; } + + try + { + toAccountID=mTransaction->getITFieldH160(sfDestination); + pubKey=mTransaction->getSigningAccount(); + mTransactionID=mTransaction->getTransactionID(); + } + catch(...) + { + return; + } mAccountTo.setAccountID(toAccountID); mAccountFrom.setAccountID(fromAccountID); @@ -75,13 +75,63 @@ Transaction::Transaction(const std::vector &t, bool validate) : m mAccountFrom.setAccountPublic(pubKey); mFromPubKey=theApp->getPubKeyCache().store(mAccountFrom, mFromPubKey); - updateID(); - updateFee(); - if(!validate || checkSign()) mStatus=NEW; } +Transaction::Transaction(const std::vector& raw, bool validate) : mStatus(INVALID) +{ + uint160 toAccountID; + uint160 fromAccountID; + std::vector pubKey; + + try + { + Serializer s(raw); + SerializerIterator sit(s); + mTransaction=boost::make_shared(boost::ref(sit), -1); + + mFromPubKey=boost::make_shared(); + if(!mFromPubKey->SetPubKey(pubKey)) return; + mAccountFrom.setAccountPublic(pubKey); + mFromPubKey=theApp->getPubKeyCache().store(mAccountFrom, mFromPubKey); + if(!mFromPubKey->SetPubKey(pubKey)) return; + mAccountFrom.setAccountPublic(pubKey); + mFromPubKey=theApp->getPubKeyCache().store(mAccountFrom, mFromPubKey); + } + catch(...) + { + return; + } + if(!validate || checkSign()) + mStatus=NEW; +} + +Transaction::Transaction(const NewcoinAddress& fromID, const NewcoinAddress& toID, + CKey::pointer pubKey, uint64 amount, uint64 fee, uint32 fromSeq, uint32 fromLedger, + uint32 ident, const std::vector& signature, uint32 ledgerSeq, TransStatus st) : + mAccountFrom(fromID), mAccountTo(toID), mFromPubKey(pubKey), mInLedger(ledgerSeq), mStatus(st) +{ + mTransaction=boost::make_shared(ttMAKE_PAYMENT); + mTransaction->setSignature(signature); + mTransaction->setTransactionFee(fee); + mTransaction->setSigningAccount(pubKey->GetPubKey()); + mTransaction->setSequence(fromSeq); + if(fromLedger!=0) + { + mTransaction->makeITFieldPresent(sfTargetLedger); + mTransaction->setITFieldU32(sfTargetLedger, fromLedger); + } + if(ident!=0) + { + mTransaction->makeITFieldPresent(sfSourceTag); + mTransaction->setITFieldU32(sfSourceTag, ident); + } + mTransaction->setValueFieldU64(sfAmount, amount); + updateID(); +} + + bool Transaction::sign(LocalAccount::pointer fromLocalAccount) { CKey::pointer privateKey=fromLocalAccount->getPrivateKey(); @@ -93,10 +143,10 @@ bool Transaction::sign(LocalAccount::pointer fromLocalAccount) return false; } - if( (mAmount==0) || (mSourceLedger==0) || !mAccountTo.IsValid() ) + if( (mTransaction->getITFieldU64(sfAmount)==0) || !mAccountTo.IsValid() ) { #ifdef DEBUG - std::cerr << "Bad amount, source ledger, or destination" << std::endl; + std::cerr << "Bad amount or destination" << std::endl; #endif assert(false); return false; @@ -110,7 +160,8 @@ bool Transaction::sign(LocalAccount::pointer fromLocalAccount) assert(false); return false; } - if(!getRaw(true)->makeSignature(mSignature, *privateKey)) + + if(!getSTransaction()->sign(*privateKey)) { #ifdef DEBUG std::cerr << "Failed to make signature" << std::endl; @@ -118,50 +169,14 @@ bool Transaction::sign(LocalAccount::pointer fromLocalAccount) assert(false); return false; } - assert(mSignature.size()==72); updateID(); return true; } -void Transaction::updateFee() -{ // for now, all transactions have a 1,000 unit fee - mFee=1000; -} - bool Transaction::checkSign() const { assert(mFromPubKey); - Serializer::pointer signBuf=getRaw(true); - return getRaw(true)->checkSignature(mSignature, *mFromPubKey); -} - -Serializer::pointer Transaction::getRaw(bool prefix) const -{ - uint160 toAccountID = mAccountTo.getAccountID(); - - Serializer::pointer ret=boost::make_shared(77); - if(prefix) ret->add32(0x54584e00u); - ret->add160(toAccountID); - ret->add64(mAmount); - ret->add32(mFromAccountSeq); - ret->add32(mSourceLedger); - ret->add32(mIdent); - ret->addRaw(mFromPubKey->GetPubKey()); - assert( (prefix&&(ret->getLength()==77)) || (!prefix&&(ret->getLength()==73)) ); - return ret; -} - -Serializer::pointer Transaction::getSigned() const -{ - Serializer::pointer ret(getRaw(false)); - ret->addRaw(mSignature); - assert(ret->getLength()==BTxSize); - return ret; -} - -void Transaction::updateID() -{ - mTransactionID=getSigned()->getSHA512Half(); + return mTransaction->checkSign(*mFromPubKey); } void Transaction::setStatus(TransStatus ts, uint32 lseq) @@ -176,29 +191,26 @@ void Transaction::saveTransaction(Transaction::pointer txn) } bool Transaction::save() const -{ +{ // This code needs to be fixed to support new-style transactions - FIXME if((mStatus==INVALID)||(mStatus==REMOVED)) return false; std::string sql="INSERT INTO Transactions " - "(TransID,FromAcct,FromSeq,FromLedger,Identifier,ToAcct,Amount,Fee,FirstSeen,CommitSeq,Status, Signature)" + "(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(mFromAccountSeq)); + sql.append(boost::lexical_cast(mTransaction->getSequence())); sql.append("','"); - sql.append(boost::lexical_cast(mSourceLedger)); + sql.append(mTransaction->getITFieldString(sfDestination)); sql.append("','"); - sql.append(boost::lexical_cast(mIdent)); - sql.append("','"); - sql.append(mAccountTo.humanAccountID()); - sql.append("','"); - sql.append(boost::lexical_cast(mAmount)); - sql.append("','"); - sql.append(boost::lexical_cast(mFee)); + sql.append(mTransaction->getITFieldString(sfAmount)); sql.append("',now(),'"); - sql.append(boost::lexical_cast(mInLedger)); switch(mStatus) + sql.append(boost::lexical_cast(mInLedger)); + switch(mStatus) { case NEW: sql.append("','N',"); break; case INCLUDED: sql.append("','A',"); break; @@ -207,9 +219,13 @@ bool Transaction::save() const case HELD: sql.append("','H',"); break; default: sql.append("','U',"); break; } - std::string signature; - theApp->getTxnDB()->getDB()->escape(&(mSignature.front()), mSignature.size(), signature); - sql.append(signature); + + 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()); @@ -218,12 +234,11 @@ bool Transaction::save() const } Transaction::pointer Transaction::transactionFromSQL(const std::string& sql) -{ - std::string transID, fromID, toID, status; - uint64 amount, fee; - uint32 ledgerSeq, fromSeq, fromLedger, ident; - std::vector signature; - signature.reserve(78); +{ // This code needs to be fixed to support new-style transactions - FIXME + std::vector rawTxn; + std::string status; + + rawTxn.reserve(2048); if(1) { ScopedLock sl(theApp->getTxnDB()->getDBLock()); @@ -232,29 +247,17 @@ Transaction::pointer Transaction::transactionFromSQL(const std::string& sql) if(!db->executeSQL(sql.c_str(), true) || !db->startIterRows() || !db->getNextRow()) return Transaction::pointer(); - db->getStr("TransID", transID); - db->getStr("FromID", fromID); - fromSeq=db->getBigInt("FromSeq"); - fromLedger=db->getBigInt("FromLedger"); - db->getStr("ToID", toID); - amount=db->getBigInt("Amount"); - fee=db->getBigInt("Fee"); - ledgerSeq=db->getBigInt("CommitSeq"); - ident=db->getBigInt("Identifier"); db->getStr("Status", status); - int sigSize=db->getBinary("Signature", &(signature.front()), signature.size()); - signature.resize(sigSize); + int txSize=db->getBinary("RawTxn", &(rawTxn.front()), rawTxn.size()); + rawTxn.resize(txSize); + if(txSize>rawTxn.size()) db->getBinary("RawTxn", &(rawTxn.front()), rawTxn.size()); db->endIterRows(); } - uint256 trID; - NewcoinAddress frID, tID; - trID.SetHex(transID); - frID.setAccountID(fromID); - tID.setAccountID(toID); - - CKey::pointer pubkey=theApp->getPubKeyCache().locate(frID); - if(!pubkey) return Transaction::pointer(); + Serializer s(rawTxn); + SerializerIterator it(s); + SerializedTransaction::pointer txn=boost::make_shared(boost::ref(it), -1); + Transaction::pointer tr=boost::make_shared(txn, true); TransStatus st(INVALID); switch(status[0]) @@ -265,15 +268,15 @@ Transaction::pointer Transaction::transactionFromSQL(const std::string& sql) case 'D': st=COMMITTED; break; case 'H': st=HELD; break; } - - return Transaction::pointer(new Transaction(trID, frID, tID, pubkey, amount, fee, fromSeq, fromLedger, - ident, signature, ledgerSeq, st)); + tr->setStatus(st); + + return tr; } Transaction::pointer Transaction::load(const uint256& id) { - std::string sql="SELECT * FROM Transactions WHERE TransID='"; + std::string sql="SELECT Status,RawTxn FROM Transactions WHERE TransID='"; sql.append(id.GetHex()); sql.append("';"); return transactionFromSQL(sql); @@ -281,7 +284,7 @@ Transaction::pointer Transaction::load(const uint256& id) Transaction::pointer Transaction::findFrom(const NewcoinAddress& fromID, uint32 seq) { - std::string sql="SELECT * FROM Transactions WHERE FromID='"; + std::string sql="SELECT Status,RawTxn FROM Transactions WHERE FromID='"; sql.append(fromID.humanAccountID()); sql.append("' AND FromSeq='"); sql.append(boost::lexical_cast(seq)); @@ -304,6 +307,8 @@ bool Transaction::convertToTransactions(uint32 firstLedgerSeq, uint32 secondLedg Transaction::pointer firstTrans, secondTrans; if(!!first) { // transaction in our table + Serializer s(first->getData()); + SerializerIterator sit(s); firstTrans=boost::make_shared(first->getData(), checkFirstTransactions); if( (firstTrans->getStatus()==INVALID) || (firstTrans->getID()!=id) ) { @@ -350,10 +355,7 @@ bool Transaction::isHexTxID(const std::string& txid) Json::Value Transaction::getJson(bool decorate, bool paid, bool credited) const { - Json::Value ret(Json::objectValue); - ret["TransactionID"]=mTransactionID.GetHex(); - ret["Amount"]=boost::lexical_cast(mAmount); - ret["Fee"]=boost::lexical_cast(mFee); + Json::Value ret(mTransaction->getJson(0)); if(mInLedger) ret["InLedger"]=mInLedger; switch(mStatus) @@ -371,11 +373,7 @@ Json::Value Transaction::getJson(bool decorate, bool paid, bool credited) const } Json::Value source(Json::objectValue); - source["AccountID"]=mAccountFrom.humanAccountID(); - source["AccountSeq"]=mFromAccountSeq; - source["Ledger"]=mSourceLedger; - if(!!mIdent) source["Identifier"]=mIdent; Json::Value destination(Json::objectValue); destination["AccountID"]=mAccountTo.humanAccountID(); @@ -393,4 +391,3 @@ Json::Value Transaction::getJson(bool decorate, bool paid, bool credited) const ret["Destination"]=destination; return ret; } - diff --git a/src/Transaction.h b/src/Transaction.h index e3495c943d..66c490eede 100644 --- a/src/Transaction.h +++ b/src/Transaction.h @@ -16,10 +16,7 @@ #include "Serializer.h" #include "SHAMap.h" #include "LocalAccount.h" - -/* -We could have made something that inherited from the protobuf transaction but this seemed simpler -*/ +#include "SerializedTransaction.h" enum TransStatus { @@ -40,41 +37,42 @@ public: typedef boost::shared_ptr pointer; - static const uint32 TransSignMagic=0x54584E00; // "TXN" - private: uint256 mTransactionID; - NewcoinAddress mAccountFrom, mAccountTo; - uint64 mAmount, mFee; - uint32 mFromAccountSeq, mSourceLedger, mIdent; + NewcoinAddress mAccountFrom, mAccountTo; CKey::pointer mFromPubKey; - std::vector mSignature; uint32 mInLedger; TransStatus mStatus; + SerializedTransaction::pointer mTransaction; + public: - Transaction(); - Transaction(const std::vector& rawTransaction, bool validate); - Transaction(LocalAccount::pointer fromLocal, const NewcoinAddress& to, uint64 amount, uint32 ident, uint32 ledger); + Transaction(const std::vector&, bool validate); + Transaction(SerializedTransaction::pointer st, bool validate); + + Transaction(LocalAccount::pointer fromLocal, const NewcoinAddress& to, uint64 amount, + uint32 ident, uint32 ledger); + + Transaction(const NewcoinAddress& fromID, const NewcoinAddress& toID, + CKey::pointer pubKey, uint64 amount, uint64 fee, uint32 fromSeq, uint32 fromLedger, + uint32 ident, const std::vector& signature, uint32 ledgerSeq, TransStatus st); bool sign(LocalAccount::pointer fromLocalAccount); bool checkSign() const; - void updateID(); - void updateFee(); + void updateID() { mTransactionID=mTransaction->getTransactionID(); } - Serializer::pointer getRaw(bool prefix) const; - Serializer::pointer getSigned() const; + SerializedTransaction::pointer getSTransaction() { return mTransaction; } const uint256& getID() const { return mTransactionID; } const NewcoinAddress& getFromAccount() const { return mAccountFrom; } const NewcoinAddress& getToAccount() const { return mAccountTo; } - uint64 getAmount() const { return mAmount; } - uint64 getFee() const { return mFee; } - uint32 getFromAccountSeq() const { return mFromAccountSeq; } - uint32 getSourceLedger() const { return mSourceLedger; } - uint32 getIdent() const { return mIdent; } - const std::vector& getSignature() const { return mSignature; } + uint64 getAmount() const { return mTransaction->getITFieldU64(sfAmount); } + uint64 getFee() const { return mTransaction->getTransactionFee(); } + uint32 getFromAccountSeq() const { return mTransaction->getSequence(); } + uint32 getSourceLedger() const { return mTransaction->getITFieldU32(sfTargetLedger); } + uint32 getIdent() const { return mTransaction->getITFieldU32(sfSourceTag); } + std::vector getSignature() const { return mTransaction->getSignature(); } uint32 getLedger() const { return mInLedger; } TransStatus getStatus() const { return mStatus; } @@ -107,12 +105,7 @@ protected: static Transaction::pointer transactionFromSQL(const std::string& statement); Transaction(const uint256& transactionID, const NewcoinAddress& accountFrom, const NewcoinAddress& accountTo, CKey::pointer key, uint64 amount, uint64 fee, uint32 fromAccountSeq, uint32 sourceLedger, - uint32 ident, const std::vector& signature, uint32 inLedger, TransStatus status) : - mTransactionID(transactionID), mAccountFrom(accountFrom), mAccountTo(accountTo), - mAmount(amount), mFee(fee), mFromAccountSeq(fromAccountSeq), mSourceLedger(sourceLedger), - mIdent(ident), mFromPubKey(key), mSignature(signature), mInLedger(inLedger), mStatus(status) - { ; } - + uint32 ident, const std::vector& signature, uint32 inLedger, TransStatus status); }; #endif