diff --git a/Application.cpp b/Application.cpp index 360a3c342..97854f894 100644 --- a/Application.cpp +++ b/Application.cpp @@ -1,13 +1,16 @@ + +#include + +//#include + +#include "database/SqliteDatabase.h" + #include "Application.h" #include "Config.h" #include "PeerDoor.h" #include "RPCDoor.h" #include "BitcoinUtil.h" #include "key.h" -#include "database/SqliteDatabase.h" -//#include -#include -using namespace std; Application* theApp=NULL; @@ -25,9 +28,7 @@ What needs to happen: Application::Application() { theConfig.load(); - mKnownNodes.load(); //mUNL.load(); - mWallet.load(); mPeerDoor=NULL; mRPCDoor=NULL; mDatabase=NULL; @@ -52,7 +53,7 @@ Application::Application() void Application::run() { - string filename=strprintf("%sdata.db",theConfig.DATA_DIR.c_str()); + std::string filename=strprintf("%sdata.db",theConfig.DATA_DIR.c_str()); theApp->setDB(new SqliteDatabase(filename.c_str())); mDatabase->connect(); @@ -70,9 +71,11 @@ void Application::run() mConnectionPool.connectToNetwork(mKnownNodes, mIOService); mTimingService.start(mIOService); - cout << "Before Run." << endl; + std::cout << "Before Run." << std::endl; mIOService.run(); // This blocks + mWallet.load(); + //BOOST_LOG_TRIVIAL(info) << "Done."; - cout << "Done." << endl; + std::cout << "Done." << std::endl; } diff --git a/DeterministicKeys.cpp b/DeterministicKeys.cpp index 24e9dc5b5..2a190a14e 100644 --- a/DeterministicKeys.cpp +++ b/DeterministicKeys.cpp @@ -23,6 +23,12 @@ EC_KEY* CKey::GenerateRootDeterministicKey(const uint256& key) if(!ctx) return NULL; EC_KEY* pkey=EC_KEY_new_by_curve_name(NID_secp256k1); + if(!pkey) + { + BN_CTX_free(ctx); + return NULL; + } + EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); BIGNUM* order=BN_new(); if(!order) @@ -118,6 +124,7 @@ EC_KEY* CKey::GeneratePublicDeterministicKey(const uint160& family, EC_POINT* ro BN_CTX_free(ctx); return NULL; } + EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); EC_POINT *newPoint=EC_POINT_new(EC_KEY_get0_group(pkey)); if(newPoint==NULL) @@ -159,6 +166,7 @@ EC_KEY* CKey::GeneratePrivateDeterministicKey(const uint160& family, BIGNUM* roo BN_CTX_free(ctx); return NULL; } + EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED); BIGNUM* order=BN_new(); if(order==NULL) diff --git a/SQLiteDatabases.sql b/SQLiteDatabases.sql index 6a4d33791..e3ff911de 100644 --- a/SQLiteDatabases.sql +++ b/SQLiteDatabases.sql @@ -71,7 +71,7 @@ CREATE INDEX ObjectLocate ON CommittedObjects(LedgerIndex, ObjType); 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 + Seq BIGINT UNSIGNED, -- next one to issue Name TEXT, Comment TEXT ) diff --git a/Wallet.cpp b/Wallet.cpp index e19a26778..4195f44de 100644 --- a/Wallet.cpp +++ b/Wallet.cpp @@ -14,7 +14,7 @@ LocalAccountEntry::LocalAccountEntry(const uint160& accountFamily, int accountSe mBalance(0), mLedgerSeq(0), mTxnSeq(0) { mAcctID=mPublicKey->GetAddress().GetHash160(); - mPublicKey=theApp->getPubKeyCache().store(mAcctID, mPublicKey); + if(theApp!=NULL) mPublicKey=theApp->getPubKeyCache().store(mAcctID, mPublicKey); } void LocalAccountEntry::unlock(BIGNUM* rootPrivKey) @@ -34,13 +34,13 @@ std::string LocalAccountEntry::getLocalAccountName() const } LocalAccountFamily::LocalAccountFamily(const uint160& family, EC_POINT* pubKey) : - mFamily(family), rootPubKey(pubKey), rootPrivateKey(NULL) + mFamily(family), mRootPubKey(pubKey), mLastSeq(0), mRootPrivateKey(NULL) { ; } LocalAccountFamily::~LocalAccountFamily() { lock(); - if(rootPubKey!=NULL) EC_POINT_free(rootPubKey); + if(mRootPubKey!=NULL) EC_POINT_free(mRootPubKey); } uint160 LocalAccountFamily::getAccount(int seq) @@ -48,7 +48,7 @@ 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)); + LocalAccountEntry::pointer lae(new LocalAccountEntry(mFamily, seq, mRootPubKey)); mAccounts.insert(std::make_pair(seq, lae)); return lae->getAccountID(); @@ -56,27 +56,72 @@ uint160 LocalAccountFamily::getAccount(int seq) void LocalAccountFamily::unlock(BIGNUM* privateKey) { - if(rootPrivateKey!=NULL) BN_free(rootPrivateKey); - rootPrivateKey=privateKey; + if(mRootPrivateKey!=NULL) BN_free(mRootPrivateKey); + mRootPrivateKey=privateKey; } void LocalAccountFamily::lock() { - if(rootPrivateKey!=NULL) + if(mRootPrivateKey!=NULL) { - BN_free(rootPrivateKey); - rootPrivateKey=NULL; + BN_free(mRootPrivateKey); + mRootPrivateKey=NULL; for(std::map::iterator it=mAccounts.begin(); it!=mAccounts.end(); ++it) it->second->lock(); } } + +std::string LocalAccountFamily::getPubKeyHex() const +{ + EC_GROUP *grp=EC_GROUP_new_by_curve_name(NID_secp256k1); + if(!grp) return ""; + + BIGNUM* pubBase=EC_POINT_point2bn(grp, mRootPubKey, 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; +} + +std::string LocalAccountFamily::getSQLFields() +{ + return "(FamilyName,RootPubKey,Seq,Name,Comment)"; +} + +std::string LocalAccountFamily::getSQL() const +{ // familyname(40), pubkey(66), seq, name, comment + std::string ret("('"); + ret.append(mFamily.GetHex()); + ret+="','"; + ret.append(getPubKeyHex()); + ret.append("','"); + ret.append(boost::lexical_cast(mLastSeq)); + ret.append("',"); + + std::string esc; + theApp->getDB()->escape((const unsigned char *) mName.c_str(), mName.size(), esc); + ret.append(esc); + ret.append(","); + theApp->getDB()->escape((const unsigned char *) mComment.c_str(), mComment.size(), esc); + ret.append(esc); + + ret.append(")"); + return ret; +} + 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)); + LocalAccountEntry::pointer ret(new LocalAccountEntry(mFamily, seq, mRootPubKey)); mAccounts.insert(std::make_pair(seq, ret)); return ret; } @@ -86,54 +131,39 @@ 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) +LocalAccountFamily::pointer Wallet::getFamily(const uint160& family, const std::string& pubKey) { - std::map::iterator fit=families.find(familyName); + std::map::iterator fit=families.find(family); if(fit!=families.end()) // already added - return true; + return fit->second; EC_GROUP *grp=EC_GROUP_new_by_curve_name(NID_secp256k1); - if(!grp) return false; + if(!grp) return LocalAccountFamily::pointer(); BIGNUM* pbn=NULL; BN_hex2bn(&pbn, pubKey.c_str()); if(!pbn) { EC_GROUP_free(grp); - return false; + return LocalAccountFamily::pointer(); } - EC_POINT* rootPub=EC_POINT_bn2point(grp, pbn, NULL, NULL); EC_GROUP_free(grp); BN_free(pbn); if(!rootPub) { assert(false); - return false; + return LocalAccountFamily::pointer(); } - LocalAccountFamily::pointer fam(new LocalAccountFamily(familyName, rootPub)); - families.insert(std::make_pair(familyName, fam)); - return true; + LocalAccountFamily::pointer fam(new LocalAccountFamily(family, rootPub)); + families.insert(std::make_pair(family, fam)); + return fam; } -std::string Wallet::getPubKey(const uint160& famBase) +bool Wallet::addFamily(const uint160& familyName, const std::string& pubKey) { - 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; + return !!getFamily(familyName, pubKey); } uint160 LocalAccount::getAddress() const @@ -173,6 +203,40 @@ CKey::pointer LocalAccount::getPrivateKey() void Wallet::load() { + std::string sql("SELECT * FROM LocalAcctFamilies"); + + ScopedLock sl(theApp->getDBLock()); + Database *db=theApp->getDB(); + if(!db->executeSQL(sql.c_str())) return; + + while(db->getNextRow()) + { + std::string family, rootpub, name, comment; + db->getStr("FamilyName", family); + db->getStr("RootPubKey", rootpub); + db->getStr("Name", name); + db->getStr("Comment", comment); + int seq=db->getBigInt("Seq"); + + uint160 fb; + fb.SetHex(family); + + LocalAccountFamily::pointer f(getFamily(fb, rootpub)); + if(f) + { + f->setSeq(seq); + f->setName(name); + f->setComment(comment); + } + else assert(false); + } +} + +std::string Wallet::getPubKeyHex(const uint160& famBase) +{ + std::map::iterator fit=families.find(famBase); + if(fit==families.end()) return ""; + return fit->second->getPubKeyHex(); } LocalAccount::pointer Wallet::getLocalAccount(const uint160& family, int seq) @@ -222,3 +286,54 @@ uint160 Wallet::doPrivate(const uint256& passPhrase, bool create, bool unlock) EC_KEY_free(base); return family; } + +bool Wallet::unitTest() +{ // Create 100 keys for each of 1,000 families Ensure all keys match + Wallet pub, priv; + + uint256 privBase; + privBase.SetHex("102031459e"); + + for(int i=0; i<1000; i++, privBase++) + { + uint160 fam=priv.addFamily(privBase, false); + +#ifdef DEBUG + std::cerr << "Priv: " << privBase.GetHex() << " Fam: " << fam.GetHex() << std::endl; +#endif + + std::string pubkey=priv.getPubKeyHex(fam); +#ifdef DEBUG + std::cerr << "Pub: " << pubkey << std::endl; +#endif + + if(!pub.addFamily(fam, pubkey)) + { + assert(false); + return false; + } + + for(int j=0; j<100; j++) + { + LocalAccount::pointer lpub=pub.getLocalAccount(fam, j); + LocalAccount::pointer lpriv=priv.getLocalAccount(fam, j); + if(!lpub || !lpriv) + { + assert(false); + return false; + } + uint160 lpuba=lpub->getAddress(); + uint160 lpriva=lpriv->getAddress(); +#ifdef DEBUG + std::cerr << "pubA(" << j << "): " << lpuba.GetHex() << std::endl; + std::cerr << "prvA(" << j << "): " << lpriva.GetHex() << std::endl; +#endif + if(!lpuba || (lpuba!=lpriva)) + { + assert(false); + return false; + } + } + } + return true; +} diff --git a/Wallet.h b/Wallet.h index f4e414da7..5b1a18f2d 100644 --- a/Wallet.h +++ b/Wallet.h @@ -67,9 +67,12 @@ protected: std::map mAccounts; uint160 mFamily; // the name for this account family - EC_POINT* rootPubKey; + EC_POINT* mRootPubKey; - BIGNUM* rootPrivateKey; + uint32 mLastSeq; + std::string mName, mComment; + + BIGNUM* mRootPrivateKey; public: @@ -77,17 +80,22 @@ public: ~LocalAccountFamily(); const uint160& getFamily() { return mFamily; } - bool isLocked() const { return rootPrivateKey==NULL; } + bool isLocked() const { return mRootPrivateKey==NULL; } void unlock(BIGNUM* privateKey); void lock(); - const EC_POINT* peekPubKey() const { return rootPubKey; } + void setSeq(uint32 s) { mLastSeq=s; } + void setName(const std::string& n) { mName=n; } + void setComment(const std::string& c) { mComment=c; } LocalAccountEntry::pointer get(int seq); uint160 getAccount(int seq); - std::string getPubName() const; // The text name of the public key + std::string getPubKeyHex() const; // The text name of the public key std::string getShortName() const; // The text name for the family + + static std::string getSQLFields(); + std::string getSQL() const; }; class LocalAccount @@ -125,6 +133,11 @@ protected: uint160 doPrivate(const uint256& passPhrase, bool create, bool unlock); + LocalAccountFamily::pointer getFamily(const uint160& family, const std::string& pubKey); + + void addFamily(const uint160& family, const std::string& pubKey, int seq, + const std::string& name, const std::string& comment); + public: Wallet() { ; } @@ -140,7 +153,9 @@ public: LocalAccount::pointer getLocalAccount(const uint160& famBase, int seq); LocalAccount::pointer getLocalAccount(const uint160& acctID); - std::string getPubKey(const uint160& famBase); + std::string getPubKeyHex(const uint160& famBase); + + static bool unitTest(); }; #endif