diff --git a/Application.cpp b/Application.cpp index cd062455f1..360a3c3425 100644 --- a/Application.cpp +++ b/Application.cpp @@ -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); diff --git a/DeterministicKeys.cpp b/DeterministicKeys.cpp index 5c417c1845..24e9dc5b5c 100644 --- a/DeterministicKeys.cpp +++ b/DeterministicKeys.cpp @@ -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; } diff --git a/Ledger.cpp b/Ledger.cpp index b3439188d7..54e77f2082 100644 --- a/Ledger.cpp +++ b/Ledger.cpp @@ -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); diff --git a/NewcoinAddress.cpp b/NewcoinAddress.cpp index 816985a014..01b2036488 100644 --- a/NewcoinAddress.cpp +++ b/NewcoinAddress.cpp @@ -4,7 +4,6 @@ #include - 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(); +} diff --git a/NewcoinAddress.h b/NewcoinAddress.h index 59a8881f9b..9b1a299a19 100644 --- a/NewcoinAddress.h +++ b/NewcoinAddress.h @@ -11,7 +11,7 @@ class NewcoinAddress : public CBase58Data { public: NewcoinAddress(); - NewcoinAddress(uint160& hash160In); + NewcoinAddress(const uint160& hash160In); NewcoinAddress(const std::vector& vchPubKey); NewcoinAddress(const std::string& strAddress); NewcoinAddress(const char* pszAddress); diff --git a/SQLiteDatabases.sql b/SQLiteDatabases.sql index 57d47e1374..6a4d337914 100644 --- a/SQLiteDatabases.sql +++ b/SQLiteDatabases.sql @@ -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); diff --git a/Transaction.cpp b/Transaction.cpp index 2c58cec1a4..1cb7a4febe 100644 --- a/Transaction.cpp +++ b/Transaction.cpp @@ -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 &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(); diff --git a/Transaction.h b/Transaction.h index 8cdd3cc2cc..dac0fa145f 100644 --- a/Transaction.h +++ b/Transaction.h @@ -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 { public: @@ -54,10 +52,10 @@ private: public: Transaction(); Transaction(const std::vector& 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(); diff --git a/Wallet.cpp b/Wallet.cpp index 2273bb96ee..e19a26778b 100644 --- a/Wallet.cpp +++ b/Wallet.cpp @@ -1,185 +1,224 @@ + +#include + +#include "boost/lexical_cast.hpp" + #include "Wallet.h" #include "NewcoinAddress.h" #include "Application.h" -#include -#include -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(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::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::iterator it=mAccounts.begin(); it!=mAccounts.end(); ++it) + it->second->lock(); + } +} + +LocalAccountEntry::pointer LocalAccountFamily::get(int seq) +{ + std::map::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::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::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::iterator fit=families.find(family); + if(fit==families.end()) return LocalAccount::pointer(); + uint160 acct=fit->second->getAccount(seq); + + std::map::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 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::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(totalmAddress,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 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 - diff --git a/Wallet.h b/Wallet.h index 813b8c05dc..f4e414da7c 100644 --- a/Wallet.h +++ b/Wallet.h @@ -1,64 +1,146 @@ #ifndef __WALLET__ #define __WALLET__ -#include "keystore.h" -#include "Serializer.h" -#include "Transaction.h" -#include #include +#include +#include -class NewcoinAddress; +#include + +#include "openssl/ec.h" + +#include "uint256.h" +#include "Serializer.h" + +class LocalAccountEntry +{ // tracks keys for local accounts +public: + typedef boost::shared_ptr 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 pointer; + +protected: + std::map 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 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& 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& 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 mYourAccounts; +protected: + std::map families; + std::map 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 \ No newline at end of file +#endif diff --git a/key.h b/key.h index c093aa0d3d..64e485d035 100644 --- a/key.h +++ b/key.h @@ -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 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