More work on core ledger and transaction processing code.

This commit is contained in:
JoelKatz
2011-11-22 15:42:03 -08:00
parent 41309b6f72
commit 6c7fd5f195
10 changed files with 253 additions and 106 deletions

View File

@@ -12,9 +12,20 @@ public:
private: private:
uint160 mAccountID; uint160 mAccountID;
uint64 mBalance; uint64 mBalance;
uint32 mAccountSeq, mFirstValidLedger, mLastValidLedger; uint32 mAccountSeq;
bool mValid;
public: public:
AccountState(const uint160& mAccountID); // new account
AccountState(const std::vector<unsigned char>&); // raw form
const uint160& getAccountID() const { return mAccountID; }
uint64 getBalance() const { return mBalance; }
uint32 getSeq() const { return mAccountSeq; }
bool charge(uint64 a) { mBalance+=a; }
bool credit(uint64 a) { mBalance-=a; }
void incSeq(void) { mAccountSeq++; }
}; };
#endif #endif

View File

@@ -31,15 +31,13 @@ use public keys in compressed form using
EC_KEY_set_conv_form(POINT_CONVERSION_COMPRESS) -- so our public keys are EC_KEY_set_conv_form(POINT_CONVERSION_COMPRESS) -- so our public keys are
actually 33 bytes. actually 33 bytes.
Account IDs are based on the uncompressed public key. Form a 65-byte Account IDs are based on the compressed public key. Apply SHA512 to the
quantity consisting of a single byte with the value 4, the 32-byte X of the 33-byte public key. Apply RIPEMD160 to the first 256 bits of the result.
public key followed by the 32-byte Y of the public key. Apply SHA256 to this
65-byte quantity. Apply RIPEMD160 to the result.
The resulting 20-byte value is the account ID. The resulting 20-byte value is the account ID.
2) Transaction (source/signed format) 148-bytes 2) Transaction (source/signed format) 145-bytes
Fields: Fields:
1) 20-byte destination account 1) 20-byte destination account
@@ -48,10 +46,9 @@ Fields:
4) 4-byte source ledger index, unsigned BE integer 4) 4-byte source ledger index, unsigned BE integer
5) 4-byte arbitrary source tag, unsigned BE integer 5) 4-byte arbitrary source tag, unsigned BE integer
6) 33-byte source public key 6) 33-byte source public key
7) 3-byte padding (must be zero on send, ignore on receive) 8) 72-byte prefix 0x54584E00 signature of 73-byte contents of fields 1-6
8) 72-byte prefix 0x54584E00 signature of 76-byte contents of fields 1-6
The transaction ID is the first 256-bits of the SHA512 hash of the 148 byte The transaction ID is the first 256-bits of the SHA512 hash of the 145 byte
signed transaction. signed transaction.
3) Transaction (ledger format) 3) Transaction (ledger format)

View File

@@ -11,14 +11,14 @@
using namespace boost; using namespace boost;
using namespace std; using namespace std;
Ledger::Ledger(uint32 index) : mFeeHeld(0), mTimeStamp(0), mLedgerSeq(index) Ledger::Ledger(uint32 index) : mFeeHeld(0), mTimeStamp(0), mLedgerSeq(index), mCurrent(true)
{ {
} }
Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash, Ledger::Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
uint64 feeHeld, uint64 timeStamp, uint32 ledgerSeq) uint64 feeHeld, uint64 timeStamp, uint32 ledgerSeq)
: mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash), : mParentHash(parentHash), mTransHash(transHash), mAccountHash(accountHash),
mFeeHeld(feeHeld), mTimeStamp(timeStamp), mLedgerSeq(ledgerSeq) mFeeHeld(feeHeld), mTimeStamp(timeStamp), mLedgerSeq(ledgerSeq), mCurrent(false)
{ {
updateHash(); updateHash();
} }
@@ -40,8 +40,83 @@ void Ledger::addRaw(Serializer &s)
s.add64(mTimeStamp); s.add64(mTimeStamp);
} }
Ledger::TransResult Ledger::applyTransaction(TransactionPtr &trans) AccountState::pointer Ledger::getAccountState(const uint160& accountID)
{ {
ScopedLock l(mTransactionMap->Lock());
SHAMapItem::pointer item=mTransactionMap->getItem(uint160to256(accountID));
if(item==NULL) return AccountState::pointer();
return AccountState::pointer(new AccountState(item->getData()));
}
Transaction::pointer Ledger::getTransaction(const uint256& transID)
{
ScopedLock l(mTransactionMap->Lock());
SHAMapItem::pointer item=mTransactionMap->getItem(transID);
if(item==NULL) return Transaction::pointer();
Transaction *t=new Transaction(item->getData(), true);
if(t->getStatus()==NEW) t->setStatus(mCurrent ? INCLUDED : COMMITTED, mLedgerSeq);
return Transaction::pointer(t);
}
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((mTransactionMap==NULL) || (mAccountStateMap==NULL)) return TR_ERROR;
try
{
// already applied?
Transaction::pointer dupTrans=getTransaction(trans->getID());
if(dupTrans!=NULL) return TR_ALREADY;
// accounts exist?
AccountState::pointer fromAccount=getAccountState(trans->getFromAccount());
AccountState::pointer toAccount=getAccountState(trans->getToAccount());
if((fromAccount==NULL)||(toAccount==NULL)) return TR_BADACCT;
// pass sanity checks?
if(fromAccount->getBalance()<trans->getAmount()) return TR_INSUFF;
if(fromAccount->getSeq()>trans->getFromAccountSeq()) return TR_PASTASEQ;
if(fromAccount->getSeq()<trans->getFromAccountSeq()) return TR_PREASEQ;
// apply
fromAccount->charge(trans->getAmount());
fromAccount->incSeq();
toAccount->credit(trans->getAmount()-trans->getFee());
mFeeHeld+=trans->getFee();
trans->setStatus(INCLUDED, mLedgerSeq);
updateAccountState(fromAccount);
updateAccountState(toAccount);
addTransaction(trans);
return TR_SUCCESS;
}
catch (SHAMapException)
{
return TR_ERROR;
}
}
Ledger::TransResult Ledger::removeTransaction(Transaction::pointer trans)
{
}
Ledger::TransResult Ledger::hasTransaction(Transaction::pointer trans)
{
ScopedLock l(mLock);
if(mTransactionMap==NULL) return TR_ERROR;
try
{
Transaction::pointer t=getTransaction(trans->getID());
if(t==NULL) return TR_NOTFOUND;
return TR_SUCCESS;
}
catch (SHAMapException)
{
return TR_ERROR;
}
} }
#if 0 #if 0
@@ -86,7 +161,7 @@ void Ledger::setTo(newcoin::FullLedger& ledger)
for(int n=0; n<numTrans; n++) for(int n=0; n<numTrans; n++)
{ {
const newcoin::Transaction& trans=ledger.transactions(n); const newcoin::Transaction& trans=ledger.transactions(n);
mTransactions.push_back(TransactionPtr(new newcoin::Transaction(trans))); mTransactions.push_back(Transaction::pointer(new newcoin::Transaction(trans)));
} }
} }
@@ -134,7 +209,7 @@ bool Ledger::load(const uint256& hash)
unsigned char tbuf[1000]; unsigned char tbuf[1000];
while(db->getNextRow()) while(db->getNextRow())
{ {
TransactionPtr trans=TransactionPtr(new newcoin::Transaction()); Transaction::pointer trans=Transaction::pointer(new newcoin::Transaction());
trans->set_amount( db->getBigInt("Amount")); trans->set_amount( db->getBigInt("Amount"));
trans->set_seqnum( db->getInt("seqnum")); trans->set_seqnum( db->getInt("seqnum"));
trans->set_ledgerindex( db->getInt("ledgerIndex")); trans->set_ledgerindex( db->getInt("ledgerIndex"));
@@ -262,7 +337,7 @@ uint64 Ledger::getAmount(std::string address)
}*/ }*/
// returns true if the from account has enough for the transaction and seq num is correct // returns true if the from account has enough for the transaction and seq num is correct
bool Ledger::addTransaction(TransactionPtr trans,bool checkDuplicate) bool Ledger::addTransaction(Transaction::pointer trans,bool checkDuplicate)
{ {
if(checkDuplicate && hasTransaction(trans)) return(false); if(checkDuplicate && hasTransaction(trans)) return(false);
@@ -316,7 +391,7 @@ bool Ledger::addTransaction(TransactionPtr trans,bool checkDuplicate)
} }
// Don't check the amounts. We will do this at the end. // Don't check the amounts. We will do this at the end.
void Ledger::addTransactionAllowNeg(TransactionPtr trans) void Ledger::addTransactionAllowNeg(Transaction::pointer trans)
{ {
uint160 fromAddress=protobufTo160(trans->from()); uint160 fromAddress=protobufTo160(trans->from());
@@ -376,8 +451,8 @@ void Ledger::recalculate(bool recursive)
mAccounts.clear(); mAccounts.clear();
mAccounts=mParent->getAccounts(); mAccounts=mParent->getAccounts();
list<TransactionPtr> firstTransactions=mTransactions; list<Transaction::pointer> firstTransactions=mTransactions;
list<TransactionPtr> secondTransactions=mDiscardedTransactions; list<Transaction::pointer> secondTransactions=mDiscardedTransactions;
mTransactions.clear(); mTransactions.clear();
mDiscardedTransactions.clear(); mDiscardedTransactions.clear();
@@ -386,12 +461,12 @@ void Ledger::recalculate(bool recursive)
secondTransactions.sort(gTransactionSorter); secondTransactions.sort(gTransactionSorter);
// don't check balances until the end // don't check balances until the end
BOOST_FOREACH(TransactionPtr trans,firstTransactions) BOOST_FOREACH(Transaction::pointer trans,firstTransactions)
{ {
addTransactionAllowNeg(trans); addTransactionAllowNeg(trans);
} }
BOOST_FOREACH(TransactionPtr trans,secondTransactions) BOOST_FOREACH(Transaction::pointer trans,secondTransactions)
{ {
addTransactionAllowNeg(trans); addTransactionAllowNeg(trans);
} }
@@ -408,7 +483,7 @@ void Ledger::recalculate(bool recursive)
void Ledger::parentAddedTransaction(TransactionPtr cause) void Ledger::parentAddedTransaction(Transaction::pointer cause)
{ {
// TODO: optimize we can make this more efficient at some point. For now just redo everything // TODO: optimize we can make this more efficient at some point. For now just redo everything
@@ -452,18 +527,18 @@ void Ledger::parentAddedTransaction(TransactionPtr cause)
} }
// look for discarded transactions // look for discarded transactions
BOOST_FOREACH(TransactionPtr trans,) BOOST_FOREACH(Transaction::pointer trans,)
*/ */
} }
bool Ledger::hasTransaction(TransactionPtr needle) bool Ledger::hasTransaction(Transaction::pointer needle)
{ {
BOOST_FOREACH(TransactionPtr trans,mTransactions) BOOST_FOREACH(Transaction::pointer trans,mTransactions)
{ {
if( Transaction::isEqual(needle,trans) ) return(true); if( Transaction::isEqual(needle,trans) ) return(true);
} }
BOOST_FOREACH(TransactionPtr disTrans,mDiscardedTransactions) BOOST_FOREACH(Transaction::pointer disTrans,mDiscardedTransactions)
{ {
if( Transaction::isEqual(needle,disTrans) ) return(true); if( Transaction::isEqual(needle,disTrans) ) return(true);
} }
@@ -489,8 +564,8 @@ bool Ledger::isCompatible(Ledger::pointer other)
void Ledger::mergeIn(Ledger::pointer other) void Ledger::mergeIn(Ledger::pointer other)
{ {
list<TransactionPtr>& otherTransactions=other->getTransactions(); list<Transaction::pointer>& otherTransactions=other->getTransactions();
BOOST_FOREACH(TransactionPtr trans,otherTransactions) BOOST_FOREACH(Transaction::pointer trans,otherTransactions)
{ {
addTransactionAllowNeg(trans); addTransactionAllowNeg(trans);
} }
@@ -516,9 +591,9 @@ void Ledger::correctAccount(const uint160& address)
list<uint160> effected; list<uint160> effected;
// do this in reverse so we take of the higher seqnum first // do this in reverse so we take of the higher seqnum first
for( list<TransactionPtr>::reverse_iterator iter=mTransactions.rbegin(); iter != mTransactions.rend(); ) for( list<Transaction::pointer>::reverse_iterator iter=mTransactions.rbegin(); iter != mTransactions.rend(); )
{ {
TransactionPtr trans= *iter; Transaction::pointer trans= *iter;
if(protobufTo160(trans->from()) == address) if(protobufTo160(trans->from()) == address)
{ {
Account fromAccount=mAccounts[address]; Account fromAccount=mAccounts[address];
@@ -536,10 +611,10 @@ void Ledger::correctAccount(const uint160& address)
mAccounts[destAddress]=destAccount; mAccounts[destAddress]=destAccount;
if(destAccount.first<0) effected.push_back(destAddress); if(destAccount.first<0) effected.push_back(destAddress);
list<TransactionPtr>::iterator temp=mTransactions.erase( --iter.base() ); list<Transaction::pointer>::iterator temp=mTransactions.erase( --iter.base() );
if(fromAccount.first>=0) break; if(fromAccount.first>=0) break;
iter=list<TransactionPtr>::reverse_iterator(temp); iter=list<Transaction::pointer>::reverse_iterator(temp);
}else break; }else break;
}else iter--; }else iter--;
} }

View File

@@ -17,37 +17,58 @@
class Ledger : public boost::enable_shared_from_this<Ledger> class Ledger : public boost::enable_shared_from_this<Ledger>
{ // The basic Ledger structure, can be opened, closed, or synching { // The basic Ledger structure, can be opened, closed, or synching
public:
typedef boost::shared_ptr<Ledger> pointer;
enum TransResult enum TransResult
{ {
TR_ERROR =-1, TR_ERROR =-1,
TR_SUCCESS =0, TR_SUCCESS =0,
TR_NOTFOUND =1, TR_NOTFOUND =1,
TR_ALREADY =2 TR_ALREADY =2,
TR_BADTRANS =3, // the transaction itself is corrupt
TR_BADACCT =4, // one of the accounts is invalid
TR_INSUFF =5, // the sending account is broke
TR_PASTASEQ =6, // account is past this transaction
TR_PREASEQ =7, // account is missing transactions before this
TR_BADLSEQ =8, // ledger too early
TR_TOOSMALL =9, // amount is less than Tx fee
}; };
public:
typedef boost::shared_ptr<Ledger> pointer;
private: private:
uint256 mHash, mParentHash, mTransHash, mAccountHash; uint256 mHash, mParentHash, mTransHash, mAccountHash;
uint64 mFeeHeld, mTimeStamp; uint64 mFeeHeld, mTimeStamp;
uint32 mLedgerSeq; uint32 mLedgerSeq;
bool mCurrent;
SHAMap::pointer mTransactionMap, mAccountStateMap; SHAMap::pointer mTransactionMap, mAccountStateMap;
mutable boost::recursive_mutex mLock;
protected: protected:
void updateHash(); void updateHash();
bool addAccountState(AccountState::pointer);
bool updateAccountState(AccountState::pointer);
bool addTransaction(Transaction::pointer);
bool delTransaction(const uint256& id);
public: public:
Ledger(uint32 index); // used for the starting bootstrap ledger Ledger(uint32 index); // used for the starting bootstrap ledger
Ledger(const Ledger &ledger); Ledger(const Ledger &ledger);
Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash, Ledger(const uint256 &parentHash, const uint256 &transHash, const uint256 &accountHash,
uint64 feeHeld, uint64 timeStamp, uint32 ledgerSeq); // used for received ledgers uint64 feeHeld, uint64 timeStamp, uint32 ledgerSeq); // used for received ledgers
void setCurrent(void) { mCurrent=true; }
void clearCurrent(void) { mCurrent=false; }
bool isCurrent(void) { return mCurrent; }
// ledger signature operations // ledger signature operations
void addRaw(Serializer &s); void addRaw(Serializer &s);
virtual uint256 getHash() const; uint256 getHash() const;
const uint256& getParentHash() const { return mParentHash; } const uint256& getParentHash() const { return mParentHash; }
const uint256& getTransHash() const { return mTransHash; } const uint256& getTransHash() const { return mTransHash; }
const uint256& getAccountHash() const { return mAccountHash; } const uint256& getAccountHash() const { return mAccountHash; }
@@ -55,15 +76,21 @@ public:
uint64 getTimeStamp() const { return mTimeStamp; } uint64 getTimeStamp() const { return mTimeStamp; }
uint32 getLedgerSeq() const { return mLedgerSeq; } uint32 getLedgerSeq() const { return mLedgerSeq; }
// low level functions
SHAMap::pointer getTransactionMap() { return mTransactionMap; } SHAMap::pointer getTransactionMap() { return mTransactionMap; }
SHAMap::pointer getAccountStateMap() { return mAccountStateMap; } SHAMap::pointer getAccountStateMap() { return mAccountStateMap; }
TransResult applyTransaction(TransactionPtr& trans); // mid level functions
TransResult removeTransaction(TransactionPtr& trans); AccountState::pointer getAccountState(const uint160& acctID);
TransResult hasTransaction(TransactionPtr& trans); Transaction::pointer getTransaction(const uint256& transID);
// high level functions
TransResult applyTransaction(Transaction::pointer trans);
TransResult removeTransaction(Transaction::pointer trans);
TransResult hasTransaction(Transaction::pointer trans);
bool closeLedger(); bool closeLedger();
bool isCompatible(Ledger::pointer other); bool isCompatible(boost::shared_ptr<Ledger> other);
bool signLedger(std::vector<unsigned char> &signature, const LocalHanko &hanko, int32 confidence); bool signLedger(std::vector<unsigned char> &signature, const LocalHanko &hanko, int32 confidence);
}; };

View File

@@ -19,6 +19,10 @@ class SHAMap;
class SHAMapNode class SHAMapNode
{ // Identifies a node in a SHA256 hash { // Identifies a node in a SHA256 hash
public:
typedef boost::shared_ptr<SHAMapNode> pointer;
private: private:
static uint256 smMasks[11]; // AND with hash to get node id static uint256 smMasks[11]; // AND with hash to get node id
@@ -59,7 +63,7 @@ public:
}; };
class SHAMapItem : public boost::enable_shared_from_this<SHAMapItem> class SHAMapItem
{ // an item stored in a SHAMap { // an item stored in a SHAMap
public: public:
typedef boost::shared_ptr<SHAMapItem> pointer; typedef boost::shared_ptr<SHAMapItem> pointer;
@@ -98,7 +102,6 @@ public:
virtual void dump(void); virtual void dump(void);
}; };
class SHAMapLeafNode : public SHAMapNode class SHAMapLeafNode : public SHAMapNode
{ {
friend class SHAMap; friend class SHAMap;
@@ -166,6 +169,12 @@ public:
virtual void dump(void); virtual void dump(void);
}; };
enum SHAMapException
{
MissingNode=1,
InvalidNode=2
};
class SHAMap class SHAMap
{ {

View File

@@ -11,65 +11,83 @@ Transaction::Transaction() : mTransactionID(0), mAccountFrom(0), mAccountTo(0),
{ {
} }
Transaction::Transaction(TransStatus status, LocalAccount& fromLocalAccount, Account& fromAccount, Transaction::Transaction(TransStatus status, LocalAccount& fromLocalAccount, uint32 fromSeq,
uint32 fromSeq, const uint160& toAccount, uint64 amount, uint32 ident, uint32 ledger) : const uint160& toAccount, uint64 amount, uint32 ident, uint32 ledger) :
mAccountTo(toAccount), mAmount(amount), mFromAccountSeq(fromSeq), mSourceLedger(ledger), mAccountTo(toAccount), mAmount(amount), mFromAccountSeq(fromSeq), mSourceLedger(ledger),
mIdent(ident), mInLedger(0), mStatus(NEW) mIdent(ident), mInLedger(0), mStatus(NEW)
{ {
assert(fromAccount.getAddress()==fromLocalAccount.mAddress);
assert(fromLocalAccount.mAmount>=amount); assert(fromLocalAccount.mAmount>=amount);
assert((fromSeq+1)==fromLocalAccount.mSeqNum); mAccountFrom=fromLocalAccount.getAddress();
updateFee();
mAccountFrom=fromAccount.getAddress(); mFromPubKey.SetPubKey(fromLocalAccount.peekPubKey().GetPubKey());
sign(fromLocalAccount); sign(fromLocalAccount);
} }
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;
std::vector<unsigned char> pubKey;
if(!s.getRaw(pubKey, 40, 33)) return;
if(!mFromPubKey.SetPubKey(pubKey)) return;
updateID();
if(validate && !checkSign()) return;
mStatus=NEW;
}
bool Transaction::sign(LocalAccount& fromLocalAccount) bool Transaction::sign(LocalAccount& fromLocalAccount)
{ {
if( (mAmount==0) || (mSourceLedger==0) || (mAccountTo==0) ) if( (mAmount==0) || (mSourceLedger==0) || (mAccountTo==0) )
return false; return false;
if(mpAccountFrom == Account::pointer()) if(mAccountFrom!=fromLocalAccount.mAddress)
return false; return false;
if((mpAccountFrom->getAddress()!=fromLocalAccount.mAddress) || (mAccountFrom!=mpAccountFrom->getAddress())) Serializer::pointer signBuf=getRaw(true);
return false;
Serializer::pointer signBuf(getRawUnsigned());
if(!signBuf->makeSignature(mSignature, fromLocalAccount.peekPrivKey())) if(!signBuf->makeSignature(mSignature, fromLocalAccount.peekPrivKey()))
return false; return false;
signBuf->addRaw(mSignature); updateID();
mTransactionID=signBuf->getSHA512Half(); return true;
}
void Transaction::updateFee()
{ // for now, all transactions have a 1,000 unit fee
mFee=1000;
} }
bool Transaction::checkSign() const bool Transaction::checkSign() const
{ {
if(mpAccountFrom == Account::pointer()) return false; return mFromPubKey.Verify(getRaw(true)->getSHA512Half(), mSignature);
if(mpAccountFrom->getAddress()!=mAccountFrom) return false;
Serializer::pointer toSign(getRawUnsigned());
return toSign->checkSignature(mSignature, mpAccountFrom->peekPubKey());
} }
Serializer::pointer Transaction::getRawUnsigned() const Serializer::pointer Transaction::getRaw(bool prefix) const
{ {
Serializer::pointer ret(new Serializer(104)); Serializer::pointer ret(new Serializer(77));
ret->add32(0x54584e00u); if(prefix) ret->add32(0x54584e00u);
ret->addRaw(mpAccountFrom->peekPubKey().GetPubKey()); ret->addRaw(mFromPubKey.GetPubKey());
ret->add64(mAmount); ret->add64(mAmount);
ret->add32(mFromAccountSeq); ret->add32(mFromAccountSeq);
ret->add32(mInLedger); ret->add32(mInLedger);
ret->add32(mIdent); ret->add32(mIdent);
assert( (prefix&&(ret->getLength()==77)) || (!prefix&&(ret->getLength()==73)) );
return ret; return ret;
} }
Serializer::pointer Transaction::getRawSigned() const Serializer::pointer Transaction::getSigned() const
{ {
Serializer::pointer ret(getRawUnsigned()); Serializer::pointer ret(getRaw(false));
ret->addRaw(mSignature); ret->addRaw(mSignature);
return ret; return ret;
} }
void Transaction::updateID() void Transaction::updateID()
{ {
if( (mpAccountFrom!=Account::pointer()) && (mpAccountFrom->getAddress()==mAccountFrom)) mTransactionID=getSigned()->getSHA512Half();
mTransactionID=getRawSigned()->getSHA512Half();
} }

View File

@@ -5,6 +5,7 @@
#include <boost/enable_shared_from_this.hpp> #include <boost/enable_shared_from_this.hpp>
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include "key.h"
#include "uint256.h" #include "uint256.h"
#include "newcoin.pb.h" #include "newcoin.pb.h"
#include "Hanko.h" #include "Hanko.h"
@@ -31,40 +32,42 @@ class LocalAccount;
class Transaction : public boost::enable_shared_from_this<Transaction> class Transaction : public boost::enable_shared_from_this<Transaction>
{ {
public: public:
typedef boost::shared_ptr<Transaction> pointer;
static const uint32 TransSignMagic=0x54584E00; // "TXN" static const uint32 TransSignMagic=0x54584E00; // "TXN"
private: private:
uint256 mTransactionID; uint256 mTransactionID;
uint160 mAccountFrom, mAccountTo; uint160 mAccountFrom, mAccountTo;
uint64 mAmount; uint64 mAmount, mFee;
uint32 mFromAccountSeq, mSourceLedger, mIdent; uint32 mFromAccountSeq, mSourceLedger, mIdent;
CKey mFromPubKey;
std::vector<unsigned char> mSignature; std::vector<unsigned char> mSignature;
uint32 mInLedger; uint32 mInLedger;
TransStatus mStatus; TransStatus mStatus;
Account::pointer mpAccountFrom;
public: public:
Transaction(); Transaction();
Transaction(const std::vector<unsigned char> rawTransaction); Transaction(const std::vector<unsigned char>& rawTransaction, bool validate);
Transaction(const std::string sqlReply); Transaction(TransStatus Status, LocalAccount& fromLocal, uint32 fromSeq, const uint160& to, uint64 amount,
Transaction(TransStatus Status, LocalAccount& fromLocal, Account& from, uint32 ident, uint32 ledger);
uint32 fromSeq, const uint160& to, uint64 amount, uint32 ident, uint32 ledger);
void setFromAccountPointer(Account::pointer af) { mpAccountFrom=af; }
bool sign(LocalAccount& fromLocalAccount); bool sign(LocalAccount& fromLocalAccount);
bool checkSign() const; bool checkSign() const;
void updateID(); void updateID();
void updateFee();
Serializer::pointer getRawUnsigned() const; Serializer::pointer getRaw(bool prefix) const;
Serializer::pointer getRawSigned() const; Serializer::pointer getSigned() const;
const uint256& getID() const { return mTransactionID; } const uint256& getID() const { return mTransactionID; }
const uint160& getFromAccount() const { return mAccountFrom; } const uint160& getFromAccount() const { return mAccountFrom; }
const uint160& getToAccount() const { return mAccountTo; } const uint160& getToAccount() const { return mAccountTo; }
uint64 getAmount() const { return mAmount; } uint64 getAmount() const { return mAmount; }
uint64 getFee() const { return mFee; }
uint32 getFromAccountSeq() const { return mFromAccountSeq; } uint32 getFromAccountSeq() const { return mFromAccountSeq; }
uint32 getSourceLedger() const { return mSourceLedger; } uint32 getSourceLedger() const { return mSourceLedger; }
uint32 getIdent() const { return mIdent; } uint32 getIdent() const { return mIdent; }
@@ -72,8 +75,7 @@ public:
uint32 getLedger() const { return mInLedger; } uint32 getLedger() const { return mInLedger; }
TransStatus getStatus() const { return mStatus; } TransStatus getStatus() const { return mStatus; }
void setStatus(TransStatus st); void setStatus(TransStatus status, uint32 ledgerSeq);
void setLedger(uint32 Ledger);
bool operator<(const Transaction &) const; bool operator<(const Transaction &) const;
bool operator>(const Transaction &) const; bool operator>(const Transaction &) const;
@@ -83,6 +85,4 @@ public:
bool operator>=(const Transaction &) const; bool operator>=(const Transaction &) const;
}; };
typedef boost::shared_ptr<Transaction> TransactionPtr;
#endif #endif

View File

@@ -27,6 +27,9 @@ public:
bool signRaw(Serializer::pointer, std::vector<unsigned char>& signature); bool signRaw(Serializer::pointer, std::vector<unsigned char>& signature);
bool checkSignRaw(Serializer::pointer, int signaturePosition=-1, int signedData=-1); bool checkSignRaw(Serializer::pointer, int signaturePosition=-1, int signedData=-1);
CKey& peekPrivKey() { return mPrivateKey; } CKey& peekPrivKey() { return mPrivateKey; }
CKey& peekPubKey() { return mPublicKey; }
const uint160& getAddress(void) const { return mAddress; }
}; };
class Wallet : public CBasicKeyStore class Wallet : public CBasicKeyStore
@@ -35,8 +38,8 @@ class Wallet : public CBasicKeyStore
TransactionPtr createTransaction(LocalAccount& fromAccount, uint160& destAddr, int64 amount); Transaction::pointer createTransaction(LocalAccount& fromAccount, uint160& destAddr, int64 amount);
bool commitTransaction(TransactionPtr trans); bool commitTransaction(Transaction::pointer trans);
LocalAccount* consolidateAccountOfSize(int64 amount); LocalAccount* consolidateAccountOfSize(int64 amount);
@@ -51,7 +54,7 @@ public:
std::string sendMoneyToAddress(uint160& destAddress, int64 amount); std::string sendMoneyToAddress(uint160& destAddress, int64 amount);
// you may need to update your balances // you may need to update your balances
void transactionChanged(TransactionPtr trans); void transactionChanged(Transaction::pointer trans);
}; };

27
key.h
View File

@@ -17,24 +17,10 @@
#include "uint256.h" #include "uint256.h"
#include "base58.h" #include "base58.h"
// secp160k1
// const unsigned int PRIVATE_KEY_SIZE = 192;
// const unsigned int PUBLIC_KEY_SIZE = 41;
// const unsigned int SIGNATURE_SIZE = 48;
//
// secp192k1
// const unsigned int PRIVATE_KEY_SIZE = 222;
// const unsigned int PUBLIC_KEY_SIZE = 49;
// const unsigned int SIGNATURE_SIZE = 57;
//
// secp224k1
// const unsigned int PRIVATE_KEY_SIZE = 250;
// const unsigned int PUBLIC_KEY_SIZE = 57;
// const unsigned int SIGNATURE_SIZE = 66;
//
// secp256k1: // secp256k1:
// const unsigned int PRIVATE_KEY_SIZE = 279; // const unsigned int PRIVATE_KEY_SIZE = 279;
// const unsigned int PUBLIC_KEY_SIZE = 65; // const unsigned int PUBLIC_KEY_SIZE = 65; // but we don't use full keys
// const unsigned int COMPUB_KEY_SIZE = 33;
// const unsigned int SIGNATURE_SIZE = 72; // const unsigned int SIGNATURE_SIZE = 72;
// //
// see www.keylength.com // see www.keylength.com
@@ -61,6 +47,7 @@ int static inline EC_KEY_regenerate_key(EC_KEY *eckey, BIGNUM *priv_key)
if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx)) if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, ctx))
goto err; goto err;
EC_KEY_set_conv_form(eckey,POINT_CONVERSION_COMPRESSED);
EC_KEY_set_private_key(eckey,priv_key); EC_KEY_set_private_key(eckey,priv_key);
EC_KEY_set_public_key(eckey,pub_key); EC_KEY_set_public_key(eckey,pub_key);
@@ -100,6 +87,7 @@ public:
CKey() CKey()
{ {
pkey = EC_KEY_new_by_curve_name(NID_secp256k1); pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
EC_KEY_set_conv_form(pkey,POINT_CONVERSION_COMPRESSED);
if (pkey == NULL) if (pkey == NULL)
throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed"); throw key_error("CKey::CKey() : EC_KEY_new_by_curve_name failed");
fSet = false; fSet = false;
@@ -108,6 +96,7 @@ public:
CKey(const CKey& b) CKey(const CKey& b)
{ {
pkey = EC_KEY_dup(b.pkey); pkey = EC_KEY_dup(b.pkey);
EC_KEY_set_conv_form(pkey,POINT_CONVERSION_COMPRESSED);
if (pkey == NULL) if (pkey == NULL)
throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed"); throw key_error("CKey::CKey(const CKey&) : EC_KEY_dup failed");
fSet = b.fSet; fSet = b.fSet;
@@ -135,6 +124,7 @@ public:
{ {
if (!EC_KEY_generate_key(pkey)) if (!EC_KEY_generate_key(pkey))
throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed"); throw key_error("CKey::MakeNewKey() : EC_KEY_generate_key failed");
EC_KEY_set_conv_form(pkey,POINT_CONVERSION_COMPRESSED);
fSet = true; fSet = true;
} }
@@ -143,6 +133,7 @@ public:
const unsigned char* pbegin = &vchPrivKey[0]; const unsigned char* pbegin = &vchPrivKey[0];
if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size())) if (!d2i_ECPrivateKey(&pkey, &pbegin, vchPrivKey.size()))
return false; return false;
EC_KEY_set_conv_form(pkey,POINT_CONVERSION_COMPRESSED);
fSet = true; fSet = true;
return true; return true;
} }
@@ -161,6 +152,7 @@ public:
if (!EC_KEY_regenerate_key(pkey,bn)) if (!EC_KEY_regenerate_key(pkey,bn))
throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed"); throw key_error("CKey::SetSecret() : EC_KEY_regenerate_key failed");
BN_clear_free(bn); BN_clear_free(bn);
EC_KEY_set_conv_form(pkey,POINT_CONVERSION_COMPRESSED);
fSet = true; fSet = true;
return true; return true;
} }
@@ -196,6 +188,7 @@ public:
const unsigned char* pbegin = &vchPubKey[0]; const unsigned char* pbegin = &vchPubKey[0];
if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size())) if (!o2i_ECPublicKey(&pkey, &pbegin, vchPubKey.size()))
return false; return false;
EC_KEY_set_conv_form(pkey,POINT_CONVERSION_COMPRESSED);
fSet = true; fSet = true;
return true; return true;
} }
@@ -224,7 +217,7 @@ public:
return true; return true;
} }
bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig) bool Verify(uint256 hash, const std::vector<unsigned char>& vchSig) const
{ {
// -1 = error, 0 = bad sig, 1 = good // -1 = error, 0 = bad sig, 1 = good
if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1) if (ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey) != 1)

View File

@@ -2,8 +2,8 @@
// Copyright (c) 2011 The Bitcoin developers // Copyright (c) 2011 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php. // file license.txt or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_UINT256_H #ifndef NEWCOIN_UINT256_H
#define BITCOIN_UINT256_H #define NEWCOIN_UINT256_H
#include <limits.h> #include <limits.h>
@@ -584,6 +584,7 @@ public:
} }
}; };
inline bool operator==(const uint256& a, uint64 b) { return (base_uint256)a == b; } inline bool operator==(const uint256& a, uint64 b) { return (base_uint256)a == b; }
inline bool operator!=(const uint256& a, uint64 b) { return (base_uint256)a != b; } inline bool operator!=(const uint256& a, uint64 b) { return (base_uint256)a != b; }
inline const uint256 operator<<(const base_uint256& a, unsigned int shift) { return uint256(a) <<= shift; } inline const uint256 operator<<(const base_uint256& a, unsigned int shift) { return uint256(a) <<= shift; }
@@ -633,6 +634,19 @@ inline const uint256 operator|(const uint256& a, const uint256& b) { return
inline const uint256 operator+(const uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; } inline const uint256 operator+(const uint256& a, const uint256& b) { return (base_uint256)a + (base_uint256)b; }
inline const uint256 operator-(const uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; } inline const uint256 operator-(const uint256& a, const uint256& b) { return (base_uint256)a - (base_uint256)b; }
static uint256 uint160to256(const uint160& u)
{
uint256 m;
memcpy(((char *) &m)+(sizeof(m)-sizeof(u)), &u, sizeof(u));
return m;
}
static uint160 uint256to160(const uint256& u)
{
uint160 m;
memcpy((char *) &m, &u, sizeof(m));
return m;
}