From f243286bc95d05ea2cdcbc0d99cc353f279e227f Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 30 Nov 2011 12:19:48 -0800 Subject: [PATCH] Bugfixes and new code. Ledger unit test now successfully creates a local account, creates an initial ledger, closes the initial ledger and opens a new ledger, creates a second account, and adds a transaction to transfer funds to the open ledger. --- AccountState.cpp | 17 +++++++++-- Ledger.cpp | 50 +++++++++++++++++++++++++++----- Serializer.cpp | 75 +++++++++++++++++++++--------------------------- Transaction.cpp | 32 ++++++++++++++------- Transaction.h | 14 ++++----- Wallet.cpp | 2 +- key.h | 17 +++++++++-- 7 files changed, 135 insertions(+), 72 deletions(-) diff --git a/AccountState.cpp b/AccountState.cpp index 7f6da807a1..a8e1cef71d 100644 --- a/AccountState.cpp +++ b/AccountState.cpp @@ -5,9 +5,13 @@ AccountState::AccountState(const std::vector& v) { Serializer s(v); mValid=false; - if(!s.get160(mAccountID, 0)) return; - if(!s.get64(mBalance, 20)) return; - if(!s.get32(mAccountSeq, 28)) return; + if(!s.get160(mAccountID, 0)) { assert(false); return; } + if(!s.get64(mBalance, 20)) { assert(false); return; } + if(!s.get32(mAccountSeq, 28)) { assert(false); return; } +#ifdef DEBUG + std::cerr << "SerializeAccount >> " << mAccountID.GetHex() << ", " << mBalance << ", " << mAccountSeq << + std::endl; +#endif mValid=true; } @@ -20,5 +24,12 @@ std::vector AccountState::getRaw() const s.add160(mAccountID); s.add64(mBalance); s.add32(mAccountSeq); +#ifdef DEBUG + std::cerr << "SerializeAccount << " << mAccountID.GetHex() << ", " << mBalance << ", " << mAccountSeq << + std::endl; + uint64 test; + assert(s.get64(test, 20)); + assert(test==mBalance); +#endif return s.getData(); } diff --git a/Ledger.cpp b/Ledger.cpp index c5537e09c3..110316cc4c 100644 --- a/Ledger.cpp +++ b/Ledger.cpp @@ -32,7 +32,8 @@ Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint25 updateHash(); } -Ledger::Ledger(Ledger &prevLedger, uint64 ts) : mTimeStamp(ts), mClosed(false) +Ledger::Ledger(Ledger &prevLedger, uint64 ts) : mTimeStamp(ts), mClosed(false), + mTransactionMap(new SHAMap()), mAccountStateMap(prevLedger.mAccountStateMap) { prevLedger.updateHash(); mParentHash=prevLedger.mHash; @@ -87,6 +88,7 @@ bool Ledger::addAccountState(AccountState::pointer state) bool Ledger::addTransaction(Transaction::pointer trans) { // low-level - just add to table + assert(!!trans->getID()); SHAMapItem::pointer item(new SHAMapItem(trans->getID(), trans->getSigned()->getData())); return mTransactionMap->addGiveItem(item); } @@ -109,8 +111,17 @@ Transaction::pointer Ledger::getTransaction(const uint256& transID) Ledger::TransResult Ledger::applyTransaction(Transaction::pointer trans) { ScopedLock l(mLock); - if(trans->getSourceLedger()getAmount()getFee()) return TR_TOOSMALL; + if(trans->getSourceLedger()>mLedgerSeq) return TR_BADLSEQ; + + if(trans->getAmount()getFee()) + { +#ifdef DEBUG + std::cerr << "Transaction for " << trans->getAmount() << ", but fee is " << + trans->getFee() << std::endl; +#endif + return TR_TOOSMALL; + } + if(!mTransactionMap || !mAccountStateMap) return TR_ERROR; try { @@ -132,7 +143,18 @@ Ledger::TransResult Ledger::applyTransaction(Transaction::pointer trans) if(!fromAccount || !toAccount) return TR_BADACCT; // pass sanity checks? - if(fromAccount->getBalance()getAmount()) return TR_INSUFF; + if(fromAccount->getBalance()getAmount()) + { +#ifdef DEBUG + std::cerr << "Transaction for " << trans->getAmount() << ", but account has " << + fromAccount->getBalance() << std::endl; +#endif + return TR_INSUFF; + } +#ifdef DEBUG + if(fromAccount->getSeq()!=trans->getFromAccountSeq()) + std::cerr << "aSeq=" << fromAccount->getSeq() << ", tSeq=" << trans->getFromAccountSeq() << std::endl; +#endif if(fromAccount->getSeq()>trans->getFromAccountSeq()) return TR_PASTASEQ; if(fromAccount->getSeq()getFromAccountSeq()) return TR_PREASEQ; @@ -226,13 +248,27 @@ bool Ledger::unitTest(void) std::cerr << "Account2: " << la2.GetHex() << std::endl; #endif - Ledger newLedger(la1, 10000); + Ledger::pointer ledger(new Ledger(la1, 100000)); + l1.mAmount=100000; + + ledger=Ledger::pointer(new Ledger(*ledger, 0)); - AccountState::pointer as=newLedger.getAccountState(la1); + AccountState::pointer as=ledger->getAccountState(la1); assert(as); - as=newLedger.getAccountState(la2); + assert(as->getBalance()==100000); + assert(as->getSeq()==0); + as=ledger->getAccountState(la2); assert(!as); + Transaction::pointer t(new Transaction(NEW, l1, l1.mSeqNum, l2.getAddress(), 2500, 0, 1)); + assert(!!t->getID()); + + Ledger::TransResult tr=ledger->applyTransaction(t); +#ifdef DEBUG + std::cerr << "Transaction: " << tr << std::endl; +#endif + assert(tr==TR_SUCCESS); + return true; } diff --git a/Serializer.cpp b/Serializer.cpp index f2156ea227..9dea65629e 100644 --- a/Serializer.cpp +++ b/Serializer.cpp @@ -7,33 +7,32 @@ int Serializer::add16(uint16 i) { int ret=mData.size(); - for(int j=0; j>=8; - } + mData.push_back((unsigned char)(i>>8)); + mData.push_back((unsigned char)(i&0xff)); return ret; } int Serializer::add32(uint32 i) { int ret=mData.size(); - for(int j=0; j>=8; - } + mData.push_back((unsigned char)(i>>24)); + mData.push_back((unsigned char)((i>>16)&0xff)); + mData.push_back((unsigned char)((i>>8)&0xff)); + mData.push_back((unsigned char)(i&0xff)); return ret; } int Serializer::add64(uint64 i) { int ret=mData.size(); - for(int j=0; j>=8; - } + mData.push_back((unsigned char)(i>>56)); + mData.push_back((unsigned char)((i>>48)&0xff)); + mData.push_back((unsigned char)((i>>40)&0xff)); + mData.push_back((unsigned char)((i>>32)&0xff)); + mData.push_back((unsigned char)((i>>24)&0xff)); + mData.push_back((unsigned char)((i>>16)&0xff)); + mData.push_back((unsigned char)((i>>8)&0xff)); + mData.push_back((unsigned char)(i&0xff)); return ret; } @@ -60,59 +59,51 @@ int Serializer::addRaw(const std::vector &vector) bool Serializer::get16(uint16& o, int offset) const { - o=0; - if((offset+sizeof(o))>mData.size()) return false; - for(int i=0, o=0; imData.size()) return false; + o=mData.at(offset++); + o<<=8; o|=mData.at(offset); return true; } bool Serializer::get32(uint32& o, int offset) const { - o=0; - if((offset+sizeof(o))>mData.size()) return false; - for(int i=0, o=0; imData.size()) return false; + o=mData.at(offset++); + o<<=8; o|=mData.at(offset++); o<<=8; o|=mData.at(offset++); + o<<=8; o|=mData.at(offset); return true; } bool Serializer::get64(uint64& o, int offset) const { - o=0; - if((offset+sizeof(o))>mData.size()) return false; - for(int i=0, o=0; imData.size()) return false; + o=mData.at(offset++); + o<<=8; o|=mData.at(offset++); o<<=8; o|=mData.at(offset++); + o<<=8; o|=mData.at(offset++); o<<=8; o|=mData.at(offset++); + o<<=8; o|=mData.at(offset++); o<<=8; o|=mData.at(offset++); + o<<=8; o|=mData.at(offset); return true; } bool Serializer::get160(uint160& o, int offset) const { - if((offset+sizeof(o))>mData.size()) return false; - memcpy(&o, &(mData.front())+offset, sizeof(o)); + if((offset+20)>mData.size()) return false; + memcpy(&o, &(mData.front())+offset, 20); return true; } bool Serializer::get256(uint256& o, int offset) const { - if((offset+sizeof(o))>mData.size()) return false; - memcpy(&o, &(mData.front())+offset, sizeof(o)); + if((offset+32)>mData.size()) return false; + memcpy(&o, &(mData.front())+offset, 32); return true; } uint256 Serializer::get256(int offset) const { uint256 ret; - if((offset+sizeof(ret))>mData.size()) return ret; - memcpy(&ret, &(mData.front())+offset, sizeof(ret)); + if((offset+32)>mData.size()) return ret; + memcpy(&ret, &(mData.front())+offset, 32); return ret; } diff --git a/Transaction.cpp b/Transaction.cpp index effe080b39..665f4c390a 100644 --- a/Transaction.cpp +++ b/Transaction.cpp @@ -26,20 +26,20 @@ Transaction::Transaction(TransStatus status, LocalAccount& fromLocalAccount, uin Transaction::Transaction(const std::vector &t, bool validate) : mStatus(INVALID) { Serializer s(t); - if(s.getLength()<145) return; - if(!s.get160(mAccountTo, 0)) return; - if(!s.get64(mAmount, 20)) return; - if(!s.get32(mFromAccountSeq, 28)) return; - if(!s.get32(mSourceLedger, 32)) return; - if(!s.get32(mIdent, 36)) return; - if(!s.getRaw(mSignature, 69, 72)) return; + if(s.getLength()<145) { assert(false); return; } + if(!s.get160(mAccountTo, 0)) { assert(false); return; } + if(!s.get64(mAmount, 20)) { assert(false); return; } + if(!s.get32(mFromAccountSeq, 28)) { assert(false); return; } + if(!s.get32(mSourceLedger, 32)) { assert(false); return; } + if(!s.get32(mIdent, 36)) { assert(false); return; } + if(!s.getRaw(mSignature, 69, 72)) { assert(false); return; } std::vector pubKey; - if(!s.getRaw(pubKey, 40, 33)) return; - if(!mFromPubKey.SetPubKey(pubKey)) return; + if(!s.getRaw(pubKey, 40, 33)) { assert(false); return; } + if(!mFromPubKey.SetPubKey(pubKey)) { assert(false); return; } updateID(); - if(validate && !checkSign()) return; + if(validate && !checkSign()) { assert(false); return; } mStatus=NEW; } @@ -47,12 +47,23 @@ Transaction::Transaction(const std::vector &t, bool validate) : m bool Transaction::sign(LocalAccount& fromLocalAccount) { if( (mAmount==0) || (mSourceLedger==0) || (mAccountTo==0) ) + { + assert(false); return false; + } if(mAccountFrom!=fromLocalAccount.mAddress.GetHash160()) + { + assert(false); return false; + } Serializer::pointer signBuf=getRaw(true); + assert(signBuf->getLength()==73+4); if(!signBuf->makeSignature(mSignature, fromLocalAccount.peekPrivKey())) + { + assert(false); return false; + } + assert(mSignature.size()==72); updateID(); return true; } @@ -71,6 +82,7 @@ Serializer::pointer Transaction::getRaw(bool prefix) const { Serializer::pointer ret(new Serializer(77)); if(prefix) ret->add32(0x54584e00u); + ret->add160(mAccountTo); ret->addRaw(mFromPubKey.GetPubKey()); ret->add64(mAmount); ret->add32(mFromAccountSeq); diff --git a/Transaction.h b/Transaction.h index c3756cd016..f22b64570a 100644 --- a/Transaction.h +++ b/Transaction.h @@ -18,13 +18,13 @@ We could have made something that inherited from the protobuf transaction but th enum TransStatus { - NEW, // just received / generated - INVALID, // no valid signature, insufficient funds - INCLUDED, // added to the current ledger - CONFLICTED, // losing to a conflicting transaction - COMMITTED, // known to be in a ledger - HELD, // not valid now, maybe later - REMOVED // taken out of a ledger + NEW =0, // just received / generated + INVALID =1, // no valid signature, insufficient funds + INCLUDED =2, // added to the current ledger + CONFLICTED =3, // losing to a conflicting transaction + COMMITTED =4, // known to be in a ledger + HELD =5, // not valid now, maybe later + REMOVED =6 // taken out of a ledger }; class Account; diff --git a/Wallet.cpp b/Wallet.cpp index ec42a9217f..70d8044097 100644 --- a/Wallet.cpp +++ b/Wallet.cpp @@ -3,7 +3,7 @@ #include #include -LocalAccount::LocalAccount(bool) +LocalAccount::LocalAccount(bool) : mAmount(0), mSeqNum(0) { mPrivateKey.MakeNewKey(); mPublicKey.SetPubKey(mPrivateKey.GetPubKey()); diff --git a/key.h b/key.h index dcf3542b75..7b83b8bc8e 100644 --- a/key.h +++ b/key.h @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -176,10 +177,13 @@ public: unsigned int nSize = i2d_ECPrivateKey(pkey, NULL); if (!nSize) throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey failed"); - CPrivKey vchPrivKey(nSize, 0); + assert(nSize<=279); + CPrivKey vchPrivKey(279, 0); unsigned char* pbegin = &vchPrivKey[0]; if (i2d_ECPrivateKey(pkey, &pbegin) != nSize) throw key_error("CKey::GetPrivKey() : i2d_ECPrivateKey returned unexpected size"); + assert(vchPrivKey.size()<=279); + while(vchPrivKey.size()<279) vchPrivKey.push_back((unsigned char)0); return vchPrivKey; } @@ -196,12 +200,15 @@ public: std::vector GetPubKey() const { unsigned int nSize = i2o_ECPublicKey(pkey, NULL); + assert(nSize<=33); if (!nSize) throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed"); - std::vector vchPubKey(nSize, 0); + std::vector vchPubKey(33, 0); unsigned char* pbegin = &vchPubKey[0]; if (i2o_ECPublicKey(pkey, &pbegin) != nSize) throw key_error("CKey::GetPubKey() : i2o_ECPublicKey returned unexpected size"); + assert(vchPubKey.size()<=33); + while(vchPubKey.size()<33) vchPubKey.push_back((unsigned char)0); return vchPubKey; } @@ -212,6 +219,12 @@ public: unsigned int nSize = 0; if (!ECDSA_sign(0, (unsigned char*)&hash, sizeof(hash), pchSig, &nSize, pkey)) return false; + while(nSize<72) + { // enlarge to 72 bytes + pchSig[nSize]=0; + nSize++; + } + assert(nSize==72); vchSig.resize(nSize); memcpy(&vchSig[0], pchSig, nSize); return true;