New wallet system. Still missing unit tests, ledger synchronization,

and SQL code. This uses some of the 'magic' properties of elliptic
curves to create related families of public and private keys.
Wallet encryption is not needed because the private keys do not
need to be stored.
This commit is contained in:
JoelKatz
2011-12-26 18:42:50 -08:00
parent 780f94798e
commit 5cec2e9a11
11 changed files with 477 additions and 242 deletions

View File

@@ -32,9 +32,14 @@ Application::Application()
mRPCDoor=NULL;
mDatabase=NULL;
CKey::pointer account_key(new CKey(CKey::GetBaseFromString("This is my payphrase."), 0, false));
Ledger::pointer firstLedger(new Ledger(account_key->GetAddress().GetHash160(), 1000000));
uint160 rootFamily=mWallet.addFamily("This is my payphrase.", true);
LocalAccount::pointer rootAccount=mWallet.getLocalAccount(rootFamily, 0);
assert(!!rootAccount);
uint160 rootAddress=rootAccount->getAddress();
assert(!!rootAddress);
Ledger::pointer firstLedger(new Ledger(rootAddress, 1000000));
firstLedger->setClosed();
firstLedger->setAccepted();
mMasterLedger.pushLedger(firstLedger);

View File

@@ -8,16 +8,16 @@
#include "Serializer.h"
uint256 CKey::GetBaseFromString(const std::string& phrase)
uint256 CKey::PassPhraseToKey(const std::string& passPhrase)
{
Serializer s;
s.addRaw((const void *) phrase.c_str(), phrase.length());
uint256 base(s.getSHA512Half());
s.addRaw(passPhrase.c_str(), passPhrase.size());
uint256 ret(s.getSHA512Half());
s.secureErase();
return base;
return ret;
}
EC_KEY* CKey::GenerateDeterministicKey(const uint256& base, uint32 n, bool private_key)
EC_KEY* CKey::GenerateRootDeterministicKey(const uint256& key)
{
BN_CTX* ctx=BN_CTX_new();
if(!ctx) return NULL;
@@ -44,9 +44,8 @@ EC_KEY* CKey::GenerateDeterministicKey(const uint256& base, uint32 n, bool priva
int seq=0;
do
{ // private key must be non-zero and less than the curve's order
Serializer s;
s.add32(n);
s.add256(base);
Serializer s(72);
s.add256(key);
s.add32(seq++);
uint256 root=s.getSHA512Half();
s.secureErase();
@@ -62,7 +61,7 @@ EC_KEY* CKey::GenerateDeterministicKey(const uint256& base, uint32 n, bool priva
BN_free(order);
if(private_key && !EC_KEY_set_private_key(pkey, privKey))
if(!EC_KEY_set_private_key(pkey, privKey))
{ // set the random point as the private key
assert(false);
EC_KEY_free(pkey);
@@ -98,8 +97,91 @@ EC_KEY* CKey::GenerateDeterministicKey(const uint256& base, uint32 n, bool priva
return pkey;
}
uint256 CKey::GetRandomBase(void)
static BIGNUM* makeHash(const uint160& family, int seq)
{
uint256 r;
return (RAND_bytes((unsigned char *) &r, sizeof(uint256)) == 1) ? r : 0;
Serializer s;
s.add160(family);
s.add32(seq);
uint256 root=s.getSHA512Half();
s.secureErase();
return BN_bin2bn((const unsigned char *) &root, sizeof(root), NULL);
}
EC_KEY* CKey::GeneratePublicDeterministicKey(const uint160& family, EC_POINT* rootPubKey, int seq)
{ // publicKey(n) = rootPublicKey EC_POINT_+ Hash(pubHash|seq)*point
BN_CTX* ctx=BN_CTX_new();
if(ctx==NULL) return NULL;
EC_KEY* pkey=EC_KEY_new_by_curve_name(NID_secp256k1);
if(pkey==NULL)
{
BN_CTX_free(ctx);
return NULL;
}
EC_POINT *newPoint=EC_POINT_new(EC_KEY_get0_group(pkey));
if(newPoint==NULL)
{
EC_KEY_free(pkey);
BN_CTX_free(ctx);
return NULL;
}
BIGNUM* hash=makeHash(family, seq);
if(hash==NULL)
{
EC_POINT_free(newPoint);
BN_CTX_free(ctx);
EC_KEY_free(pkey);
return NULL;
}
EC_POINT_mul(EC_KEY_get0_group(pkey), newPoint, hash, NULL, NULL, ctx);
BN_free(hash);
EC_POINT_add(EC_KEY_get0_group(pkey), newPoint, newPoint, rootPubKey, ctx);
EC_KEY_set_public_key(pkey, newPoint);
EC_POINT_free(newPoint);
BN_CTX_free(ctx);
return pkey;
}
EC_KEY* CKey::GeneratePrivateDeterministicKey(const uint160& family, BIGNUM* rootPrivKey, int seq)
{ // privateKey(n) = (rootPrivateKey + Hash(pubHash|seq)) % order
BN_CTX* ctx=BN_CTX_new();
if(ctx==NULL) return NULL;
EC_KEY* pkey=EC_KEY_new_by_curve_name(NID_secp256k1);
if(pkey==NULL)
{
BN_CTX_free(ctx);
return NULL;
}
BIGNUM* order=BN_new();
if(order==NULL)
{
BN_CTX_free(ctx);
EC_KEY_free(pkey);
}
EC_GROUP_get_order(EC_KEY_get0_group(pkey), order, ctx);
BIGNUM* privKey=makeHash(family, seq);
BN_mod_add(privKey, privKey, rootPrivKey, order, ctx);
BN_free(order);
EC_KEY_set_private_key(pkey, privKey);
EC_POINT* pubKey=EC_POINT_new(EC_KEY_get0_group(pkey));
EC_POINT_mul(EC_KEY_get0_group(pkey), pubKey, privKey, NULL, NULL, ctx);
BN_free(privKey);
EC_KEY_set_public_key(pkey, pubKey);
EC_POINT_free(pubKey);
BN_CTX_free(ctx);
return pkey;
}

View File

@@ -260,17 +260,20 @@ Ledger::pointer Ledger::closeLedger(uint64 timeStamp)
bool Ledger::unitTest()
{
LocalAccount l1(true), l2(true);
assert(l1.peekPubKey());
uint160 la1=theApp->getWallet().addFamily(CKey::PassPhraseToKey("This is my payphrase!"), false);
uint160 la2=theApp->getWallet().addFamily(CKey::PassPhraseToKey("Another payphrase"), false);
LocalAccount::pointer l1=theApp->getWallet().getLocalAccount(la1, 0);
LocalAccount::pointer l2=theApp->getWallet().getLocalAccount(la2, 0);
assert(l1->getAddress()==la1);
uint160 la1(l1.getAddress()), la2(l2.getAddress());
#ifdef DEBUG
std::cerr << "Account1: " << la1.GetHex() << std::endl;
std::cerr << "Account2: " << la2.GetHex() << std::endl;
#endif
Ledger::pointer ledger(new Ledger(la1, 100000));
l1.mAmount=100000;
ledger=Ledger::pointer(new Ledger(*ledger, 0));
@@ -281,7 +284,7 @@ bool Ledger::unitTest()
as=ledger->getAccountState(la2);
assert(!as);
Transaction::pointer t(new Transaction(NEW, l1, l1.mSeqNum, l2.getAddress(), 2500, 0, 1));
Transaction::pointer t(new Transaction(NEW, l1, l1->getAcctSeq(), l2->getAddress(), 2500, 0, 1));
assert(!!t->getID());
Ledger::TransResult tr=ledger->applyTransaction(t);

View File

@@ -4,7 +4,6 @@
#include <assert.h>
bool NewcoinAddress::SetHash160(const uint160& hash160)
{
SetData(51, &hash160, 20);
@@ -25,7 +24,7 @@ NewcoinAddress::NewcoinAddress()
{
}
NewcoinAddress::NewcoinAddress(uint160& hash160In)
NewcoinAddress::NewcoinAddress(const uint160& hash160In)
{
SetHash160(hash160In);
}
@@ -53,3 +52,7 @@ uint160 NewcoinAddress::GetHash160() const
return hash160;
}
std::string NewcoinAddress::GetString() const
{
return ToString();
}

View File

@@ -11,7 +11,7 @@ class NewcoinAddress : public CBase58Data
{
public:
NewcoinAddress();
NewcoinAddress(uint160& hash160In);
NewcoinAddress(const uint160& hash160In);
NewcoinAddress(const std::vector<unsigned char>& vchPubKey);
NewcoinAddress(const std::string& strAddress);
NewcoinAddress(const char* pszAddress);

View File

@@ -35,7 +35,6 @@ CREATE TABLE Ledgers ( -- closed/accepted ledgers
CREATE INDEX SeqLedger ON Ledgers(LedgerSeq);
CREATE TABLE LedgerConfirmations (
LedgerSeq BIGINT UNSIGNED,
LedgerHash CHARACTER(64),
@@ -69,12 +68,22 @@ CREATE TABLE CommittedObjects ( -- used to synch nodes
CREATE INDEX ObjectLocate ON CommittedObjects(LedgerIndex, ObjType);
CREATE TABLE LocalAccounts ( -- wallet
CREATE TABLE LocalAcctFamilies ( -- a family of accounts that share a payphrase
FamilyName CHARACTER(40) PRIMARY KEY,
RootPubKey CHARACTER(66),
Seq BIGINT UNSIGNED, -- last one issued
Name TEXT,
Comment TEXT
)
CREATE TABLE LocalAccounts ( -- an individual account
ID CHARACTER(40) PRIMARY KEY,
DKID CHARACTER(40), -- root determinstic key
DKSeq BIGINT UNSIGNED, -- sequence number
Seq BIGINT UNSIGNED, -- last transaction seen/issued
Balance BIGINT UNSIGNED,
LedgerSeq BIGINT UNSIGNED, -- ledger this balance is from
KeyFormat CHARACTER(1), -- can be encrypted
PrivateKey BLOB,
Comment TEXT
);
CREATE UNIQUE INDEX AccountLocate ON LocalAccounts(DKID, DKSeq);

View File

@@ -14,14 +14,13 @@ Transaction::Transaction() : mTransactionID(0), mAccountFrom(0), mAccountTo(0),
{
}
Transaction::Transaction(TransStatus status, LocalAccount& fromLocalAccount, uint32 fromSeq,
Transaction::Transaction(TransStatus status, LocalAccount::pointer fromLocalAccount, 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)
{
assert(fromLocalAccount.mAmount>=amount);
mAccountFrom=fromLocalAccount.getAddress();
mFromPubKey=fromLocalAccount.peekPubKey();
mAccountFrom=fromLocalAccount->getAddress();
mFromPubKey=fromLocalAccount->getPublicKey();
assert(mFromPubKey);
updateFee();
sign(fromLocalAccount);
@@ -51,24 +50,27 @@ Transaction::Transaction(const std::vector<unsigned char> &t, bool validate) : m
mStatus=NEW;
}
bool Transaction::sign(LocalAccount& fromLocalAccount)
bool Transaction::sign(LocalAccount::pointer fromLocalAccount)
{
CKey::pointer privateKey=fromLocalAccount->getPrivateKey();
if(!privateKey) return false;
if( (mAmount==0) || (mSourceLedger==0) || (mAccountTo==0) )
{
assert(false);
return false;
}
if(mAccountFrom!=fromLocalAccount.mAddress.GetHash160())
if(mAccountFrom!=fromLocalAccount->getAddress())
{
assert(false);
return false;
}
Serializer::pointer signBuf=getRaw(true);
assert(signBuf->getLength()==73+4);
if(!signBuf->makeSignature(mSignature, fromLocalAccount.peekPrivKey()))
if(!signBuf->makeSignature(mSignature, *privateKey))
{
assert(false);
return false;
return false;
}
assert(mSignature.size()==72);
updateID();

View File

@@ -10,6 +10,7 @@
#include "newcoin.pb.h"
#include "Hanko.h"
#include "Serializer.h"
#include "Wallet.h"
#include "SHAMap.h"
/*
@@ -29,9 +30,6 @@ enum TransStatus
INCOMPLETE =8 // needs more signatures
};
class Account;
class LocalAccount;
class Transaction : public boost::enable_shared_from_this<Transaction>
{
public:
@@ -54,10 +52,10 @@ private:
public:
Transaction();
Transaction(const std::vector<unsigned char>& rawTransaction, bool validate);
Transaction(TransStatus Status, LocalAccount& fromLocal, uint32 fromSeq, const uint160& to, uint64 amount,
Transaction(TransStatus Status, LocalAccount::pointer fromLocal, uint32 fromSeq, const uint160& to, uint64 amount,
uint32 ident, uint32 ledger);
bool sign(LocalAccount& fromLocalAccount);
bool sign(LocalAccount::pointer fromLocalAccount);
bool checkSign() const;
void updateID();
void updateFee();

View File

@@ -1,185 +1,224 @@
#include <string>
#include "boost/lexical_cast.hpp"
#include "Wallet.h"
#include "NewcoinAddress.h"
#include "Application.h"
#include <string>
#include <boost/foreach.hpp>
LocalAccount::LocalAccount(bool) : mPublicKey(new CKey()), mAmount(0), mSeqNum(0)
LocalAccountEntry::LocalAccountEntry(const uint160& accountFamily, int accountSeq, EC_POINT* rootPubKey) :
mAccountFamily(accountFamily), mAccountSeq(accountSeq),
mPublicKey(new CKey(accountFamily, rootPubKey, accountSeq)),
mBalance(0), mLedgerSeq(0), mTxnSeq(0)
{
mPrivateKey.MakeNewKey();
mPublicKey->SetPubKey(mPrivateKey.GetPubKey());
acctID=Hash160(mPublicKey->GetPubKey());
mPublicKey=theApp->getPubKeyCache().store(acctID, mPublicKey);
assert(mPublicKey);
mAddress.SetHash160(acctID);
mAcctID=mPublicKey->GetAddress().GetHash160();
mPublicKey=theApp->getPubKeyCache().store(mAcctID, mPublicKey);
}
Wallet::Wallet()
void LocalAccountEntry::unlock(BIGNUM* rootPrivKey)
{
if((mPrivateKey==NULL) && (rootPrivKey!=NULL))
mPrivateKey=CKey::pointer(new CKey(mAccountFamily, rootPrivKey, mAccountSeq));
}
std::string LocalAccountEntry::getAccountName() const
{
return mPublicKey->GetAddress().GetString();
}
std::string LocalAccountEntry::getLocalAccountName() const
{
return NewcoinAddress(mAccountFamily).GetString() + ":" + boost::lexical_cast<std::string>(mAccountSeq);
}
LocalAccountFamily::LocalAccountFamily(const uint160& family, EC_POINT* pubKey) :
mFamily(family), rootPubKey(pubKey), rootPrivateKey(NULL)
{ ; }
LocalAccountFamily::~LocalAccountFamily()
{
lock();
if(rootPubKey!=NULL) EC_POINT_free(rootPubKey);
}
uint160 LocalAccountFamily::getAccount(int seq)
{
std::map<int, LocalAccountEntry::pointer>::iterator ait=mAccounts.find(seq);
if(ait!=mAccounts.end()) return ait->second->getAccountID();
LocalAccountEntry::pointer lae(new LocalAccountEntry(mFamily, seq, rootPubKey));
mAccounts.insert(std::make_pair(seq, lae));
return lae->getAccountID();
}
void LocalAccountFamily::unlock(BIGNUM* privateKey)
{
if(rootPrivateKey!=NULL) BN_free(rootPrivateKey);
rootPrivateKey=privateKey;
}
void LocalAccountFamily::lock()
{
if(rootPrivateKey!=NULL)
{
BN_free(rootPrivateKey);
rootPrivateKey=NULL;
for(std::map<int, LocalAccountEntry::pointer>::iterator it=mAccounts.begin(); it!=mAccounts.end(); ++it)
it->second->lock();
}
}
LocalAccountEntry::pointer LocalAccountFamily::get(int seq)
{
std::map<int, LocalAccountEntry::pointer>::iterator act=mAccounts.find(seq);
if(act!=mAccounts.end()) return act->second;
LocalAccountEntry::pointer ret(new LocalAccountEntry(mFamily, seq, rootPubKey));
mAccounts.insert(std::make_pair(seq, ret));
return ret;
}
uint160 Wallet::addFamily(const std::string& payPhrase, bool lock)
{
return doPrivate(CKey::PassPhraseToKey(payPhrase), true, !lock);
}
bool Wallet::addFamily(const uint160& familyName, const std::string& pubKey)
{
std::map<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(familyName);
if(fit!=families.end()) // already added
return true;
EC_GROUP *grp=EC_GROUP_new_by_curve_name(NID_secp256k1);
if(!grp) return false;
BIGNUM* pbn=NULL;
BN_hex2bn(&pbn, pubKey.c_str());
if(!pbn)
{
EC_GROUP_free(grp);
return false;
}
EC_POINT* rootPub=EC_POINT_bn2point(grp, pbn, NULL, NULL);
EC_GROUP_free(grp);
BN_free(pbn);
if(!rootPub)
{
assert(false);
return false;
}
LocalAccountFamily::pointer fam(new LocalAccountFamily(familyName, rootPub));
families.insert(std::make_pair(familyName, fam));
return true;
}
std::string Wallet::getPubKey(const uint160& famBase)
{
std::map<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(famBase);
if(fit==families.end()) return "";
EC_GROUP *grp=EC_GROUP_new_by_curve_name(NID_secp256k1);
if(!grp) return "";
BIGNUM* pubBase=EC_POINT_point2bn(grp, fit->second->peekPubKey(), POINT_CONVERSION_COMPRESSED, NULL, NULL);
EC_GROUP_free(grp);
if(!pubBase) return "";
char *hex=BN_bn2hex(pubBase);
BN_free(pubBase);
if(!hex) return "";
std::string ret(hex);
OPENSSL_free(hex);
return ret;
}
uint160 LocalAccount::getAddress() const
{
LocalAccountEntry::pointer la(mFamily->get(mSeq));
if(!la) return uint160();
return la->getAccountID();
}
uint32 LocalAccount::getAcctSeq() const
{
LocalAccountEntry::pointer la(mFamily->get(mSeq));
if(!la) return 0;
return la->getAccountSeq();
}
uint64 LocalAccount::getBalance() const
{
LocalAccountEntry::pointer la(mFamily->get(mSeq));
if(!la) return 0;
return la->getBalance();
}
CKey::pointer LocalAccount::getPublicKey()
{
LocalAccountEntry::pointer la(mFamily->get(mSeq));
if(!la) return CKey::pointer();
return la->getPubKey();
}
CKey::pointer LocalAccount::getPrivateKey()
{
LocalAccountEntry::pointer la(mFamily->get(mSeq));
if(!la) return CKey::pointer();
return la->getPrivKey();
}
void Wallet::load()
{
// WRITEME
}
#if 0
int64 Wallet::getBalance()
LocalAccount::pointer Wallet::getLocalAccount(const uint160& family, int seq)
{
int64 total = 0;
LedgerMaster& ledgerMaster=theApp->getLedgerMaster();
BOOST_FOREACH(Account& account, mYourAccounts)
{
total += ledgerMaster.getAmountHeld(account.mAddress);
}
return total;
std::map<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(family);
if(fit==families.end()) return LocalAccount::pointer();
uint160 acct=fit->second->getAccount(seq);
std::map<uint160, LocalAccount::pointer>::iterator ait=accounts.find(acct);
if(ait!=accounts.end()) return ait->second;
LocalAccount::pointer lac(new LocalAccount(fit->second, seq));
accounts.insert(std::make_pair(acct, lac));
return lac;
}
void Wallet::refreshAccounts()
uint160 Wallet::doPrivate(const uint256& passPhrase, bool create, bool unlock)
{
LedgerMaster& ledgerMaster=theApp->getLedgerMaster();
// Generate root key
EC_KEY *base=CKey::GenerateRootDeterministicKey(passPhrase);
BOOST_FOREACH(Account& account, mYourAccounts)
{
Ledger::Account* ledgerAccount=ledgerMaster.getAccount(account.mAddress);
if(ledgerAccount)
// Extract family name
std::vector<unsigned char> rootPubKey(33, 0);
unsigned char *begin=&rootPubKey[0];
i2o_ECPublicKey(base, &begin);
while(rootPubKey.size()<33) rootPubKey.push_back((unsigned char)0);
uint160 family=NewcoinAddress(rootPubKey).GetHash160();
LocalAccountFamily::pointer fam;
std::map<uint160, LocalAccountFamily::pointer>::iterator it=families.find(family);
if(it==families.end())
{ // family not found
if(!create)
{
account.mAmount= ledgerAccount->first;
account.mSeqNum= ledgerAccount->second;
}else
{
account.mAmount=0;
account.mSeqNum=0;
EC_KEY_free(base);
return family;
}
fam=LocalAccountFamily::pointer(new LocalAccountFamily(family,
EC_POINT_dup(EC_KEY_get0_public_key(base), EC_KEY_get0_group(base))));
families[family]=fam;
}
else fam=it->second;
if(unlock && fam->isLocked())
fam->unlock(BN_dup(EC_KEY_get0_private_key(base)));
EC_KEY_free(base);
return family;
}
void Wallet::transactionChanged(TransactionPtr trans)
{
BOOST_FOREACH(Account& account, mYourAccounts)
{
if( account.mAddress == protobufTo160(trans->from()) ||
account.mAddress == protobufTo160(trans->dest()) )
{
Ledger::Account* ledgerAccount=theApp->getLedgerMaster().getAccount(account.mAddress);
if(ledgerAccount)
{
account.mAmount= ledgerAccount->first;
account.mSeqNum= ledgerAccount->second;
}else
{
account.mAmount=0;
account.mSeqNum=0;
}
}
}
}
Wallet::Account* Wallet::consolidateAccountOfSize(int64 amount)
{
int64 total=0;
BOOST_FOREACH(Account& account, mYourAccounts)
{
if(account.mAmount>=amount) return(&account);
total += account.mAmount;
}
if(total<amount) return(NULL);
Account* firstAccount=NULL;
uint160* firstAddr=NULL;
total=0;
BOOST_FOREACH(Account& account, mYourAccounts)
{
total += account.mAmount;
if(firstAccount)
{
TransactionPtr trans=createTransaction(account,firstAccount->mAddress,account.mAmount);
commitTransaction(trans);
}else firstAccount=&account;
if(total>=amount) return(firstAccount);
}
assert(0);
return(NULL);
}
string Wallet::sendMoneyToAddress(uint160& destAddress, int64 amount)
{
// we may have to bundle up money in order to send this amount
Account* fromAccount=consolidateAccountOfSize(amount);
if(fromAccount)
{
TransactionPtr trans=createTransaction(*fromAccount,destAddress,amount);
if(trans)
{
if(!commitTransaction(trans))
return("Error: The transaction was rejected. This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here.");
}
}else return("Insufficient funds");
return "";
}
TransactionPtr Wallet::createTransaction(Account& fromAccount, uint160& destAddr, int64 amount)
{
TransactionPtr trans(new newcoin::Transaction());
trans->set_amount(amount);
trans->set_seqnum(fromAccount.mSeqNum);
trans->set_from(fromAccount.mAddress.begin(), fromAccount.mAddress.GetSerializeSize());
trans->set_dest(destAddr.begin(),destAddr.GetSerializeSize());
trans->set_ledgerindex(theApp->getLedgerMaster().getCurrentLedgerIndex());
// TODO: trans->set_pubkey(fromAccount.mPublicKey);
fromAccount.signTransaction(trans);
return(trans);
}
bool Wallet::Account::signTransaction(TransactionPtr trans)
{
/* TODO:
uint256 hash = Transaction::calcHash(trans);
CKey key;
if(!GetKey(input.from(), key))
return false;
if(hash != 0)
{
vector<unsigned char> vchSig;
if(!key.Sign(hash, retSig))
return false;
}
*/
return(true);
}
bool Wallet::commitTransaction(TransactionPtr trans)
{
if(trans)
{
if(theApp->getLedgerMaster().addTransaction(trans))
{
ConnectionPool& pool=theApp->getConnectionPool();
PackedMessage::pointer packet(new PackedMessage(PackedMessage::MessagePointer(new newcoin::Transaction(*(trans.get()))),newcoin::TRANSACTION));
pool.relayMessage(NULL,packet);
}else cout << "Problem adding the transaction to your local ledger" << endl;
}
return(false);
}
#endif

156
Wallet.h
View File

@@ -1,64 +1,146 @@
#ifndef __WALLET__
#define __WALLET__
#include "keystore.h"
#include "Serializer.h"
#include "Transaction.h"
#include <list>
#include <vector>
#include <map>
#include <string>
class NewcoinAddress;
#include <boost/shared_ptr.hpp>
#include "openssl/ec.h"
#include "uint256.h"
#include "Serializer.h"
class LocalAccountEntry
{ // tracks keys for local accounts
public:
typedef boost::shared_ptr<LocalAccountEntry> pointer;
protected:
// family informaiton
uint160 mAccountFamily;
int mAccountSeq;
// core account information
CKey::pointer mPublicKey;
CKey::pointer mPrivateKey;
uint160 mAcctID;
// local usage tracking
uint64 mBalance; // The balance, last we checked/updated
uint32 mLedgerSeq; // The ledger seq when we updated the balance
uint32 mTxnSeq; // The sequence number of the next transaction
public:
LocalAccountEntry(const uint160& accountFamily, int accountSeq, EC_POINT* rootPubKey);
void unlock(BIGNUM* rootPrivKey);
void lock() { mPrivateKey=CKey::pointer(); }
void write();
void read();
const uint160& getAccountID() const { return mAcctID; }
int getAccountSeq() const { return mAccountSeq; }
std::string getLocalAccountName() const; // The name used locally to identify this account
std::string getAccountName() const; // The normal account name used to send to this account
CKey::pointer getPubKey() { return mPublicKey; }
CKey::pointer getPrivKey() { return mPrivateKey; }
void update(uint64 balance, uint32 seq);
uint32 getTxnSeq() const { return mTxnSeq; }
uint32 incTxnSeq() { return mTxnSeq++; }
uint64 getBalance() const { return mBalance; }
void credit(uint64 amount) { mBalance+=amount; }
void debit(uint64 amount) { assert(mBalance>=amount); mBalance-=amount; }
};
class LocalAccountFamily
{ // tracks families of local accounts
public:
typedef boost::shared_ptr<LocalAccountFamily> pointer;
protected:
std::map<int, LocalAccountEntry::pointer> mAccounts;
uint160 mFamily; // the name for this account family
EC_POINT* rootPubKey;
BIGNUM* rootPrivateKey;
public:
LocalAccountFamily(const uint160& family, EC_POINT* pubKey);
~LocalAccountFamily();
const uint160& getFamily() { return mFamily; }
bool isLocked() const { return rootPrivateKey==NULL; }
void unlock(BIGNUM* privateKey);
void lock();
const EC_POINT* peekPubKey() const { return rootPubKey; }
LocalAccountEntry::pointer get(int seq);
uint160 getAccount(int seq);
std::string getPubName() const; // The text name of the public key
std::string getShortName() const; // The text name for the family
};
/*
Keeps track of all the public/private keys you have created
*/
class LocalAccount
{
{ // tracks a single local account
public:
typedef boost::shared_ptr<LocalAccount> pointer;
//CKey mKey;
//std::string mHumanAddress;
NewcoinAddress mAddress;
CKey::pointer mPublicKey;
CKey mPrivateKey;
uint160 acctID;
int64 mAmount;
uint32 mSeqNum;
protected:
LocalAccountFamily::pointer mFamily;
int mSeq;
LocalAccount(bool); // create a new local acount
public:
LocalAccount(LocalAccountFamily::pointer fam, int seq) : mFamily(fam), mSeq(seq) { ; }
uint160 getAddress() const;
bool isLocked() const;
bool signRaw(Serializer::pointer);
bool signRaw(Serializer::pointer, std::vector<unsigned char>& signature);
bool checkSignRaw(Serializer::pointer, int signaturePosition=-1, int signedData=-1);
CKey& peekPrivKey() { return mPrivateKey; }
CKey::pointer peekPubKey() { return mPublicKey; }
bool checkSignRaw(Serializer::pointer data, std::vector<unsigned char>& signature);
uint160 getAddress() const { return mAddress.GetHash160(); }
uint32 getAcctSeq() const;
uint64 getBalance() const;
void incAcctSeq(uint32 transAcctSeq);
CKey::pointer getPublicKey();
CKey::pointer getPrivateKey();
};
class Wallet : public CBasicKeyStore
class Wallet
{
std::map<uint160, LocalAccount::pointer> mYourAccounts;
protected:
std::map<uint160, LocalAccountFamily::pointer> families;
std::map<uint160, LocalAccount::pointer> accounts;
Transaction::pointer createTransaction(LocalAccount& fromAccount, const uint160& destAddr, uint64 amount);
bool commitTransaction(Transaction::pointer trans);
LocalAccount* consolidateAccountOfSize(int64 amount);
uint160 doPrivate(const uint256& passPhrase, bool create, bool unlock);
public:
Wallet();
void refreshAccounts();
void load();
Wallet() { ; }
uint64 getBalance();
uint160 addFamily(const std::string& passPhrase, bool lock);
uint160 addFamily(const uint256& passPhrase, bool lock) { return doPrivate(passPhrase, true, !lock); }
bool addFamily(const uint160& familyName, const std::string& pubKey);
// returns some human error str?
std::string sendMoneyToAddress(const uint160& destAddress, uint64 amount);
uint160 unlock(const uint256& passPhrase) { return doPrivate(passPhrase, false, true); }
// you may need to update your balances
void transactionChanged(Transaction::pointer trans);
bool lock(const uint160& familyName);
void load(void);
LocalAccount::pointer getLocalAccount(const uint160& famBase, int seq);
LocalAccount::pointer getLocalAccount(const uint160& acctID);
std::string getPubKey(const uint160& famBase);
};
#endif
#endif

24
key.h
View File

@@ -86,7 +86,6 @@ protected:
EC_KEY* pkey;
bool fSet;
static EC_KEY* GenerateDeterministicKey(const uint256& base, uint32 n, bool private_key);
public:
typedef boost::shared_ptr<CKey> pointer;
@@ -123,13 +122,26 @@ public:
EC_KEY_free(pkey);
}
CKey(const uint256& base, uint32 seq, bool private_key) : fSet(true)
static uint256 PassPhraseToKey(const std::string& passPhrase);
static EC_KEY* GenerateRootDeterministicKey(const uint256& passPhrase);
static EC_KEY* GeneratePublicDeterministicKey(const uint160& family, EC_POINT* rootPub, int n);
static EC_KEY* GeneratePrivateDeterministicKey(const uint160& family, BIGNUM* rootPriv, int n);
CKey(const uint256& passPhrase) : fSet(true)
{
pkey=GenerateDeterministicKey(base, seq, private_key);
pkey = GenerateRootDeterministicKey(passPhrase);
}
static uint256 GetBaseFromString(const std::string& base);
static uint256 GetRandomBase(void);
CKey(const uint160& base, EC_POINT* rootPubKey, int n) : fSet(true)
{ // public deterministic key
pkey = GeneratePublicDeterministicKey(base, rootPubKey, n);
}
CKey(const uint160& base, BIGNUM* rootPrivKey, int n) : fSet(true)
{ // private deterministic key
pkey = GeneratePrivateDeterministicKey(base, rootPrivKey, n);
}
bool IsNull() const
{
@@ -184,7 +196,7 @@ public:
int n=BN_bn2bin(bn,&vchRet[32 - nBytes]);
if (n != nBytes)
throw key_error("CKey::GetSecret(): BN_bn2bin failed");
return vchRet;
return vchRet;
}
CPrivKey GetPrivKey() const