Transaction Infrastructure Work:

Raw account class (address + public key)
Account State class (account + balance + ledgers valid)
Raw Hanko class
Low-level tranasaction class
Small wallet and key bits
Misc updates to the protocol.
Protocol addition to allow code to wait for replies, but that may not be a good idea.
This commit is contained in:
JoelKatz
2011-11-11 14:13:25 -08:00
parent fd7e41501b
commit e9ae645e3b
11 changed files with 238 additions and 116 deletions

17
Account.h Normal file
View File

@@ -0,0 +1,17 @@
#ifndef __ACCOUNT__
#define __ACCOUNT__
class Account
{
private:
uint160 mAddress;
CKey pubKey;
public:
bool CheckSignRaw(const std::vector<unsigned char> &toSign,
const std::vector<unsigned char> &signature) const;
const uint160& GetAddress(void) const { return mAddress; }
};
#endif

16
AccountState.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef __ACCOUNTSTATE__
#define __ACCOUNTSTATE__
// An account's state in one or more accepted ledgers
class AccountState
{
private:
int160 mAccountID;
uint64 mBalance;
uint32 mAccountSeq, mFirstValidLedger, mLastValidLedger;
public:
};
#endif

64
Hanko.h Normal file
View File

@@ -0,0 +1,64 @@
#ifndef __HANKO__
#define __HANKO__
// We use SECP256K1 http://www.secg.org/collateral/sec2_final.pdf
#include "key.h"
enum HankoFormat
{
TEXT, // Hanko in text form
RAW, // Hanko in raw binary form
CONTACT, // Hanko contact block
};
class Hanko
{
public:
static const int smPubKeySize= 65;
static const int smPrivKeySize = 279;
static const int smSigSize = 57;
private:
std::string mHanko;
std::vector<unsigned char> mContactBlock;
CKey mPubKey;
public:
Hanko();
Hanko(const std::string& TextHanko);
Hanko(const std::vector<unsigned char>& Data, HankoFormat format);
Hanko(const CKey &pubKey);
Hanko(const Hanko &);
std::string GetHankoString(HankoFormat format) const;
std::vector<unsigned char> GetHankoBinary(HankoFormat format) const;
const std::vector<unsigned char>& GetContactBlock(void) const { return mContactBlock; }
const CKey& GetPublicKey(void) const { return mPubKey; }
int UpdateContact(std::vector<unsigned char>& Contact);
bool CheckHashSign(const uint256& hash, const std::vector<unsigned char>& Signature);
bool CheckPrefixSign(const std::vector<unsigned char>& data, uint64 type,
const std::vector<unsigned char> &signature);
};
class LocalHanko : public Hanko
{
private:
CKey mPrivKey;
public:
LocalHanko(std::vector<unsigned char> &PrivKey);
LocalHanko(const CKey &Privkey);
LocalHanko(const LocalHanko &);
~LocalHanko();
bool HashSign(const uint256& hash, std::vector<unsigned char>& Signature);
bool PrefixSign(std::vector<unsigned char> data, uint64 type, std::vector<unsigned char> &Signature);
};
#endif

View File

@@ -4,6 +4,7 @@
#include "Transaction.h"
#include "types.h"
#include "BitcoinUtil.h"
#include "Hanko.h"
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
@@ -18,39 +19,20 @@ public:
typedef boost::shared_ptr<Ledger> pointer;
typedef std::pair<int64,uint32> Account;
private:
bool mValidSig;
bool mValidHash;
uint32 mIndex;
bool mValidHash, mValidLedger, mOpen;
uint256 mHash;
uint256 mSignature;
uint256 mParentHash;
uint32 mValidationSeqNum;
uint64 mFeeHeld;
std::map<uint160, Account > mAccounts;
std::list<TransactionPtr> mTransactions;
std::list<TransactionPtr> mDiscardedTransactions;
uint256 mParentHash, mTransHash, mAccountHash;
uint64 mFeeHeld, mTimeStamp;
uint32 mLedgerSeq;
//TransactionBundle mBundle;
// these can be NULL
// we need to keep track in case there are changes in this ledger that effect either the parent or child.
Ledger::pointer mParent;
Ledger::pointer mChild;
void sign();
void hash();
void addTransactionAllowNeg(TransactionPtr trans);
void correctAccounts();
void correctAccount(const uint160& address);
public:
Ledger();
Ledger(uint32 index);
Ledger(newcoin::FullLedger& ledger);
Ledger(Ledger::pointer other);
std::vector<unsigned char> Sign(uint64 timestamp, LocalHanko &Hanko);
#if 0
void setTo(newcoin::FullLedger& ledger);
void mergeIn(Ledger::pointer other);
@@ -61,8 +43,6 @@ public:
void publishValidation();
std::list<TransactionPtr>& getTransactions(){ return(mTransactions); }
bool hasTransaction(TransactionPtr trans);
int64 getAmountHeld(const uint160& address);
void parentAddedTransaction(TransactionPtr cause);
@@ -82,7 +62,7 @@ public:
Ledger::pointer getParent();
Ledger::pointer getChild();
bool isCompatible(Ledger::pointer other);
#endif
};

View File

@@ -67,7 +67,8 @@ HEADERS = \
Wallet.h
SRCS= \
Application.cpp HttpReply.cpp main.cpp RPCCommands.cpp Transaction.cpp \
Hanko.cpp Transaction.cpp \
Application.cpp HttpReply.cpp main.cpp RPCCommands.cpp \
BitcoinUtil.cpp keystore.cpp NewcoinAddress.cpp rpc.cpp UniqueNodeList.cpp \
CallRPC.cpp KnownNodeList.cpp PackedMessage.cpp RPCDoor.cpp ValidationCollection.cpp \
Config.cpp Ledger.cpp Peer.cpp RPCServer.cpp Wallet.cpp \

View File

@@ -18,15 +18,11 @@ public:
bool SetHash160(const uint160& hash160);
bool SetPubKey(const std::vector<unsigned char>& vchPubKey);
bool IsValid();
uint160 GetHash160();
std::string GetString();
};
#endif

View File

@@ -209,7 +209,7 @@ void Peer::processReadBuffer()
int type=PackedMessage::getType(mReadbuf);
switch(type)
{
case newcoin::HELLO:
case newcoin::HELLO:
{
newcoin::Hello hello;
if(hello.ParseFromArray(&mReadbuf[HEADER_SIZE], mReadbuf.size() - HEADER_SIZE))

View File

@@ -1,42 +1,67 @@
#include "Transaction.h"
#include "Wallet.h"
#include "Account.h"
#include "BitcoinUtil.h"
using namespace std;
// sort by from address and then seqnum
bool gTransactionSorter(const TransactionPtr& lhs, const TransactionPtr& rhs)
Transaction::Transaction() : mTransactionID(0), mAccountFrom(0), mAccountTo(0),
mAmount(0), mFromAccountSeq(0), mSourceLedger(0), mIdent(0),
mInLedger(0), mStatus(INVALID)
{
if(lhs->from() == rhs->from())
{
return(lhs->seqnum() < rhs->seqnum() );
}else return lhs->from() < rhs->from();
}
// I don't think we need to bother checking the sig or public key
bool Transaction::isEqual(TransactionPtr t1,TransactionPtr t2)
Transaction::Transaction(TransStatus status, LocalAccount &fromLocalAccount, const Account &fromAccount,
uint32 fromSeq, const uint160 &toAccount, uint64 amount, uint32 ident, uint32 ledger) :
mAccountTo(toAccount), mAmount(amount), mFromAccountSeq(fromSeq), mSourceLedger(ledger),
mIdent(ident), mInLedger(0), mStatus(NEW)
{
if(t1->amount() != t2->amount()) return(false);
if(t1->seqnum() != t2->seqnum()) return(false);
if(t1->ledgerindex() != t2->ledgerindex()) return(false);
if(t1->from() != t2->from()) return(false);
if(t1->dest() != t2->dest()) return(false);
assert(fromAccount.GetAddress()==fromLocalAccount.mAddress);
assert(fromLocalAccount.mAmount>=amount);
assert((fromSeq+1)==fromLocalAccount.mSeqNum);
return(true);
mAccountFrom=fromAccount.GetAddress();
Sign(fromLocalAccount, fromAccount);
}
uint256 Transaction::calcHash(TransactionPtr trans)
bool Transaction::Sign(LocalAccount &fromLocalAccount, const Account &fromAccount)
{
vector<unsigned char> buffer;
buffer.resize(trans->ByteSize());
trans->SerializeToArray(&(buffer[0]),buffer.size());
return Hash(buffer.begin(), buffer.end());
if( (mAmount==0) || (mSourceLedger==0) || (mAccountTo==0) )
return false;
if((mAccountFrom!=fromLocalAccount.mAddress)||(mAccountFrom!=fromAccount.GetAddress()))
return false;
UpdateHash();
std::vector<unsigned char> toSign, Signature;
if(!GetRawUnsigned(toSign, fromAccount)) return false;
if(!fromLocalAccount.SignRaw(toSign, Signature)) return false;
mSignature=Signature;
return true;
}
bool Transaction::isSigValid(TransactionPtr trans)
bool Transaction::CheckSign(const Account &fromAccount) const
{
// TODO: Transaction::isSigValid
return(true);
}
if(mAccountFrom!=fromAccount.GetAddress()) return false;
std::vector<unsigned char> toSign;
if(!GetRawUnsigned(toSign, fromAccount)) return false;
return fromAccount.CheckSignRaw(toSign, mSignature);
}
bool Transaction::GetRawUnsigned(std::vector<unsigned char> &raw, const Account &fromAccount) const
{
raw.clear();
}
#if 0
void Transaction::UpdateHash()
{ // FIXME
vector<unsigned char> buffer;
buffer.resize(trans->ByteSize());
trans->SerializeToArray(&(buffer[0]),buffer.size());
return Hash(buffer.begin(), buffer.end());
}
#endif

View File

@@ -3,7 +3,10 @@
#include "uint256.h"
#include "newcoin.pb.h"
#include "Hanko.h"
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/cstdint.hpp>
/*
We could have made something that inherited from the protobuf transaction but this seemed simpler
@@ -11,6 +14,7 @@ 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
@@ -18,11 +22,13 @@ enum TransStatus
HELD, // not valid now, maybe later
};
class Account;
class LocalAccount;
class Transaction
class Transaction : public boost::enable_shared_from_this<Transaction>
{
public:
typedef boost::shared_ptr<Transaction> pointer;
static const uint32 TransSignMagic=0x54584E00; // "TXN"
private:
uint256 mTransactionID;
@@ -34,17 +40,20 @@ private:
uint32 mInLedger;
TransStatus mStatus;
void UpdateHash(void);
public:
Transaction();
Transaction(const uint256 &id);
Transaction(const std::vector<unsigned char> rawTransaction);
Transaction(const std::string sqlReply);
Transaction(Account &from, Account &to, uint64 amount, uint32 ident, uint32 ledger);
bool Sign(const std::vector<unsigned char>& privKey);
Transaction(TransStatus Status, LocalAccount &fromLocal, const Account &from,
uint32 fromSeq, const uint160 &to, uint64 amount, uint32 ident, uint32 ledger);
const std::string getSQL() const;
bool checkSignature(void) const;
bool Sign(LocalAccount &fromLocalAccount, const Account &fromAccount);
bool CheckSign(const Account &fromAccount) const;
bool GetRawUnsigned(std::vector<unsigned char> &raw, const Account &from) const;
bool GetRawSigned(std::vector<unsigned char> &raw, const Account &from) const;
const uint256& GetID() const { return mTransactionID; }
const uint160& GetFromAccount() const { return mAccountFrom; }
@@ -58,6 +67,7 @@ public:
TransStatus GetStatus() const { return mStatus; }
void SetStatus(TransStatus st);
void SetLedger(uint32 Ledger);
bool operator<(const Transaction &) const;
bool operator>(const Transaction &) const;
@@ -67,4 +77,6 @@ public:
bool operator>=(const Transaction &) const;
};
typedef boost::shared_ptr<Transaction> TransactionPtr;
#endif

View File

@@ -12,31 +12,30 @@ class NewcoinAddress;
/*
Keeps track of all the public/private keys you have created
*/
class LocalAccount
{
public:
//CKey mKey;
//std::string mHumanAddress;
uint160 mAddress;
CKey mPublicKey, mPrivateKey;
int64 mAmount;
uint32 mSeqNum;
bool SignRaw(const std::vector<unsigned char> &toSign, std::vector<unsigned char> &signature);
bool CheckSignRaw(const std::vector<unsigned char> &toSign, const std::vector<unsigned char> &signature);
};
class Wallet : public CBasicKeyStore
{
class Account
{
public:
//CKey mKey;
//std::string mHumanAddress;
uint160 mAddress;
std::vector<unsigned char> mPublicKey;
std::vector<unsigned char> mPrivateKey;
int64 mAmount;
uint32 mSeqNum;
Account(){}
bool signTransaction(TransactionPtr input);
};
std::list<Account> mYourAccounts;
std::list<LocalAccount> mYourAccounts;
TransactionPtr createTransaction(Account& fromAccount, uint160& destAddr, int64 amount);
TransactionPtr createTransaction(LocalAccount& fromAccount, uint160& destAddr, int64 amount);
bool commitTransaction(TransactionPtr trans);
Account* consolidateAccountOfSize(int64 amount);
LocalAccount* consolidateAccountOfSize(int64 amount);
public:
Wallet();
@@ -51,7 +50,6 @@ public:
// you may need to update your balances
void transactionChanged(TransactionPtr trans);
};
#endif

View File

@@ -1,33 +1,46 @@
package newcoin;
enum Type {
// abnormal
enum MessageType {
// core
HELLO= 0;
ERROR_MSG= 1;
PING= 2;
// session management
HELLO= 10;
PING= 11;
// network presence detection
GET_CONTACTS= 10;
CONTACT= 11;
// transaction processing
TRANSACTION= 20;
// ledger closing
PROPOSE_LEDGER= 30;
CLOSE_LEDGER= 31;
// operations for 'small' nodes
SEARCH_TRANSACTION= 20;
GET_ACCOUNT= 21;
ACCOUNT= 22;
// transaction and ledger processing
TRANSACTION= 30;
GET_LEDGER= 31;
LEDGER= 32;
PROPOSE_LEDGER= 33;
CLOSE_LEDGER= 34;
// data replication and synchronization
GET_VALIDATIONS= 40;
VALIDATION= 41;
GET_CONTACTS= 42;
CONTACT= 43;
GET_OBJECT= 44;
OBJECT= 45;
GET_OBJECT= 42;
OBJECT= 43;
}
message TMBaseMessage {
required MessageType type = 1;
optional uint32 seq = 2;
optional uint32 querySeq = 3; // if this is a reply
required bytes innerMessage = 4;
}
// Sent on connect
message Hello {
message TMHello {
required uint32 version = 1;
optional uint32 ledgerIndex = 2;
optional uint64 netTime = 3;
@@ -41,7 +54,7 @@ If you want to send an amount that is greater than any single address of yours
you must first combine coins from one address to another.
*/
message Transaction {
message TMTransaction {
required bytes from = 1;
required bytes dest = 2;
required uint64 amount = 3;
@@ -55,7 +68,7 @@ message Transaction {
// Used to propose/validate during ledger close
message Validation {
message TMValidation {
required uint32 ledgerIndex = 1;
required bytes ledgerHash = 2;
optional uint64 timestamp = 3; // only in proposed ledgers
@@ -66,7 +79,7 @@ message Validation {
message GetValidations {
message TMGetValidations {
required uint32 ledgerIndex = 1;
repeated bytes hanko = 2;
optional uint32 count = 3; // get random validations
@@ -74,7 +87,7 @@ message GetValidations {
message Contact {
message TMContact {
required bytes pubKey = 1;
required uint32 softwareVersion = 2;
required uint32 protoVersion = 3;
@@ -85,14 +98,14 @@ message Contact {
}
// request node information
message GetContacts {
message TMGetContacts {
repeated bytes nodeIDs =1; // specific nodes we want
optional uint32 nodeCount =2; // get some random nodes
}
message IndexedObject
message TMIndexedObject
{
enum ObjectType {
TRANSACTION = 1;
@@ -110,23 +123,23 @@ message IndexedObject
message GetObjectByHash
message TMGetObjectByHash
{
required IndexedObject object = 1;
required TMIndexedObject object = 1;
}
message ObjectByHash
message TMObjectByHash
{
required IndexedObject object = 1;
required TMIndexedObject object = 1;
required bytes data = 2;
}
message Ping {
message TMPing {
enum pingType {
PING = 0; // we want a reply
PONG = 1; // this is a reply
@@ -138,7 +151,7 @@ message Ping {
}
message ErrorMsg {
message TMErrorMsg {
optional int32 errorCode = 1;
optional string message = 2;
}