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.
This commit is contained in:
JoelKatz
2011-11-30 12:19:48 -08:00
parent b301fe2846
commit f243286bc9
7 changed files with 135 additions and 72 deletions

View File

@@ -5,9 +5,13 @@ AccountState::AccountState(const std::vector<unsigned char>& 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<unsigned char> 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();
}

View File

@@ -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()<mLedgerSeq) return TR_BADLSEQ;
if(trans->getAmount()<trans->getFee()) return TR_TOOSMALL;
if(trans->getSourceLedger()>mLedgerSeq) return TR_BADLSEQ;
if(trans->getAmount()<trans->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()<trans->getAmount()) return TR_INSUFF;
if(fromAccount->getBalance()<trans->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()<trans->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;
}

View File

@@ -7,33 +7,32 @@
int Serializer::add16(uint16 i)
{
int ret=mData.size();
for(int j=0; j<sizeof(i); j++)
{
mData.push_back((unsigned char) (i&0xff));
i>>=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<sizeof(i); j++)
{
mData.push_back((unsigned char) (i&0xff));
i>>=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<sizeof(i); j++)
{
mData.push_back((unsigned char) (i&0xff));
i>>=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<unsigned char> &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; i<sizeof(o); i++)
{
o<<=8;
o|=mData.at(offset++);
}
if((offset+2)>mData.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; i<sizeof(o); i++)
{
o<<=8;
o|=mData.at(offset++);
}
if((offset+4)>mData.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; i<sizeof(o); i++)
{
o<<=8;
o|=mData.at(offset++);
}
if((offset+8)>mData.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;
}

View File

@@ -26,20 +26,20 @@ Transaction::Transaction(TransStatus status, LocalAccount& fromLocalAccount, uin
Transaction::Transaction(const std::vector<unsigned char> &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<unsigned char> 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<unsigned char> &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);

View File

@@ -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;

View File

@@ -3,7 +3,7 @@
#include <string>
#include <boost/foreach.hpp>
LocalAccount::LocalAccount(bool)
LocalAccount::LocalAccount(bool) : mAmount(0), mSeqNum(0)
{
mPrivateKey.MakeNewKey();
mPublicKey.SetPubKey(mPrivateKey.GetPubKey());

17
key.h
View File

@@ -7,6 +7,7 @@
#include <stdexcept>
#include <vector>
#include <cassert>
#include <openssl/ec.h>
#include <openssl/ecdsa.h>
@@ -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<unsigned char> GetPubKey() const
{
unsigned int nSize = i2o_ECPublicKey(pkey, NULL);
assert(nSize<=33);
if (!nSize)
throw key_error("CKey::GetPubKey() : i2o_ECPublicKey failed");
std::vector<unsigned char> vchPubKey(nSize, 0);
std::vector<unsigned char> 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;