Include unit test, Wallet<->SQL updates.

This commit is contained in:
JoelKatz
2011-12-26 21:37:43 -08:00
parent 5cec2e9a11
commit 67a5544458
5 changed files with 193 additions and 52 deletions

View File

@@ -1,13 +1,16 @@
#include <iostream>
//#include <boost/log/trivial.hpp>
#include "database/SqliteDatabase.h"
#include "Application.h" #include "Application.h"
#include "Config.h" #include "Config.h"
#include "PeerDoor.h" #include "PeerDoor.h"
#include "RPCDoor.h" #include "RPCDoor.h"
#include "BitcoinUtil.h" #include "BitcoinUtil.h"
#include "key.h" #include "key.h"
#include "database/SqliteDatabase.h"
//#include <boost/log/trivial.hpp>
#include <iostream>
using namespace std;
Application* theApp=NULL; Application* theApp=NULL;
@@ -25,9 +28,7 @@ What needs to happen:
Application::Application() Application::Application()
{ {
theConfig.load(); theConfig.load();
mKnownNodes.load();
//mUNL.load(); //mUNL.load();
mWallet.load();
mPeerDoor=NULL; mPeerDoor=NULL;
mRPCDoor=NULL; mRPCDoor=NULL;
mDatabase=NULL; mDatabase=NULL;
@@ -52,7 +53,7 @@ Application::Application()
void Application::run() 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())); theApp->setDB(new SqliteDatabase(filename.c_str()));
mDatabase->connect(); mDatabase->connect();
@@ -70,9 +71,11 @@ void Application::run()
mConnectionPool.connectToNetwork(mKnownNodes, mIOService); mConnectionPool.connectToNetwork(mKnownNodes, mIOService);
mTimingService.start(mIOService); mTimingService.start(mIOService);
cout << "Before Run." << endl; std::cout << "Before Run." << std::endl;
mIOService.run(); // This blocks mIOService.run(); // This blocks
mWallet.load();
//BOOST_LOG_TRIVIAL(info) << "Done."; //BOOST_LOG_TRIVIAL(info) << "Done.";
cout << "Done." << endl; std::cout << "Done." << std::endl;
} }

View File

@@ -23,6 +23,12 @@ EC_KEY* CKey::GenerateRootDeterministicKey(const uint256& key)
if(!ctx) return NULL; if(!ctx) return NULL;
EC_KEY* pkey=EC_KEY_new_by_curve_name(NID_secp256k1); 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(); BIGNUM* order=BN_new();
if(!order) if(!order)
@@ -118,6 +124,7 @@ EC_KEY* CKey::GeneratePublicDeterministicKey(const uint160& family, EC_POINT* ro
BN_CTX_free(ctx); BN_CTX_free(ctx);
return NULL; return NULL;
} }
EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
EC_POINT *newPoint=EC_POINT_new(EC_KEY_get0_group(pkey)); EC_POINT *newPoint=EC_POINT_new(EC_KEY_get0_group(pkey));
if(newPoint==NULL) if(newPoint==NULL)
@@ -159,6 +166,7 @@ EC_KEY* CKey::GeneratePrivateDeterministicKey(const uint160& family, BIGNUM* roo
BN_CTX_free(ctx); BN_CTX_free(ctx);
return NULL; return NULL;
} }
EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
BIGNUM* order=BN_new(); BIGNUM* order=BN_new();
if(order==NULL) if(order==NULL)

View File

@@ -71,7 +71,7 @@ CREATE INDEX ObjectLocate ON CommittedObjects(LedgerIndex, ObjType);
CREATE TABLE LocalAcctFamilies ( -- a family of accounts that share a payphrase CREATE TABLE LocalAcctFamilies ( -- a family of accounts that share a payphrase
FamilyName CHARACTER(40) PRIMARY KEY, FamilyName CHARACTER(40) PRIMARY KEY,
RootPubKey CHARACTER(66), RootPubKey CHARACTER(66),
Seq BIGINT UNSIGNED, -- last one issued Seq BIGINT UNSIGNED, -- next one to issue
Name TEXT, Name TEXT,
Comment TEXT Comment TEXT
) )

View File

@@ -14,7 +14,7 @@ LocalAccountEntry::LocalAccountEntry(const uint160& accountFamily, int accountSe
mBalance(0), mLedgerSeq(0), mTxnSeq(0) mBalance(0), mLedgerSeq(0), mTxnSeq(0)
{ {
mAcctID=mPublicKey->GetAddress().GetHash160(); mAcctID=mPublicKey->GetAddress().GetHash160();
mPublicKey=theApp->getPubKeyCache().store(mAcctID, mPublicKey); if(theApp!=NULL) mPublicKey=theApp->getPubKeyCache().store(mAcctID, mPublicKey);
} }
void LocalAccountEntry::unlock(BIGNUM* rootPrivKey) void LocalAccountEntry::unlock(BIGNUM* rootPrivKey)
@@ -34,13 +34,13 @@ std::string LocalAccountEntry::getLocalAccountName() const
} }
LocalAccountFamily::LocalAccountFamily(const uint160& family, EC_POINT* pubKey) : LocalAccountFamily::LocalAccountFamily(const uint160& family, EC_POINT* pubKey) :
mFamily(family), rootPubKey(pubKey), rootPrivateKey(NULL) mFamily(family), mRootPubKey(pubKey), mLastSeq(0), mRootPrivateKey(NULL)
{ ; } { ; }
LocalAccountFamily::~LocalAccountFamily() LocalAccountFamily::~LocalAccountFamily()
{ {
lock(); lock();
if(rootPubKey!=NULL) EC_POINT_free(rootPubKey); if(mRootPubKey!=NULL) EC_POINT_free(mRootPubKey);
} }
uint160 LocalAccountFamily::getAccount(int seq) uint160 LocalAccountFamily::getAccount(int seq)
@@ -48,7 +48,7 @@ uint160 LocalAccountFamily::getAccount(int seq)
std::map<int, LocalAccountEntry::pointer>::iterator ait=mAccounts.find(seq); std::map<int, LocalAccountEntry::pointer>::iterator ait=mAccounts.find(seq);
if(ait!=mAccounts.end()) return ait->second->getAccountID(); 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)); mAccounts.insert(std::make_pair(seq, lae));
return lae->getAccountID(); return lae->getAccountID();
@@ -56,27 +56,72 @@ uint160 LocalAccountFamily::getAccount(int seq)
void LocalAccountFamily::unlock(BIGNUM* privateKey) void LocalAccountFamily::unlock(BIGNUM* privateKey)
{ {
if(rootPrivateKey!=NULL) BN_free(rootPrivateKey); if(mRootPrivateKey!=NULL) BN_free(mRootPrivateKey);
rootPrivateKey=privateKey; mRootPrivateKey=privateKey;
} }
void LocalAccountFamily::lock() void LocalAccountFamily::lock()
{ {
if(rootPrivateKey!=NULL) if(mRootPrivateKey!=NULL)
{ {
BN_free(rootPrivateKey); BN_free(mRootPrivateKey);
rootPrivateKey=NULL; mRootPrivateKey=NULL;
for(std::map<int, LocalAccountEntry::pointer>::iterator it=mAccounts.begin(); it!=mAccounts.end(); ++it) for(std::map<int, LocalAccountEntry::pointer>::iterator it=mAccounts.begin(); it!=mAccounts.end(); ++it)
it->second->lock(); 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<std::string>(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) LocalAccountEntry::pointer LocalAccountFamily::get(int seq)
{ {
std::map<int, LocalAccountEntry::pointer>::iterator act=mAccounts.find(seq); std::map<int, LocalAccountEntry::pointer>::iterator act=mAccounts.find(seq);
if(act!=mAccounts.end()) return act->second; 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)); mAccounts.insert(std::make_pair(seq, ret));
return ret; return ret;
} }
@@ -86,54 +131,39 @@ uint160 Wallet::addFamily(const std::string& payPhrase, bool lock)
return doPrivate(CKey::PassPhraseToKey(payPhrase), true, !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<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(familyName); std::map<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(family);
if(fit!=families.end()) // already added if(fit!=families.end()) // already added
return true; return fit->second;
EC_GROUP *grp=EC_GROUP_new_by_curve_name(NID_secp256k1); EC_GROUP *grp=EC_GROUP_new_by_curve_name(NID_secp256k1);
if(!grp) return false; if(!grp) return LocalAccountFamily::pointer();
BIGNUM* pbn=NULL; BIGNUM* pbn=NULL;
BN_hex2bn(&pbn, pubKey.c_str()); BN_hex2bn(&pbn, pubKey.c_str());
if(!pbn) if(!pbn)
{ {
EC_GROUP_free(grp); EC_GROUP_free(grp);
return false; return LocalAccountFamily::pointer();
} }
EC_POINT* rootPub=EC_POINT_bn2point(grp, pbn, NULL, NULL); EC_POINT* rootPub=EC_POINT_bn2point(grp, pbn, NULL, NULL);
EC_GROUP_free(grp); EC_GROUP_free(grp);
BN_free(pbn); BN_free(pbn);
if(!rootPub) if(!rootPub)
{ {
assert(false); assert(false);
return false; return LocalAccountFamily::pointer();
} }
LocalAccountFamily::pointer fam(new LocalAccountFamily(familyName, rootPub)); LocalAccountFamily::pointer fam(new LocalAccountFamily(family, rootPub));
families.insert(std::make_pair(familyName, fam)); families.insert(std::make_pair(family, fam));
return true; return fam;
} }
std::string Wallet::getPubKey(const uint160& famBase) bool Wallet::addFamily(const uint160& familyName, const std::string& pubKey)
{ {
std::map<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(famBase); return !!getFamily(familyName, pubKey);
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 uint160 LocalAccount::getAddress() const
@@ -173,6 +203,40 @@ CKey::pointer LocalAccount::getPrivateKey()
void Wallet::load() 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<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(famBase);
if(fit==families.end()) return "";
return fit->second->getPubKeyHex();
} }
LocalAccount::pointer Wallet::getLocalAccount(const uint160& family, int seq) 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); EC_KEY_free(base);
return family; 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;
}

View File

@@ -67,9 +67,12 @@ protected:
std::map<int, LocalAccountEntry::pointer> mAccounts; std::map<int, LocalAccountEntry::pointer> mAccounts;
uint160 mFamily; // the name for this account family 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: public:
@@ -77,17 +80,22 @@ public:
~LocalAccountFamily(); ~LocalAccountFamily();
const uint160& getFamily() { return mFamily; } const uint160& getFamily() { return mFamily; }
bool isLocked() const { return rootPrivateKey==NULL; } bool isLocked() const { return mRootPrivateKey==NULL; }
void unlock(BIGNUM* privateKey); void unlock(BIGNUM* privateKey);
void lock(); 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); LocalAccountEntry::pointer get(int seq);
uint160 getAccount(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 std::string getShortName() const; // The text name for the family
static std::string getSQLFields();
std::string getSQL() const;
}; };
class LocalAccount class LocalAccount
@@ -125,6 +133,11 @@ protected:
uint160 doPrivate(const uint256& passPhrase, bool create, bool unlock); 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: public:
Wallet() { ; } Wallet() { ; }
@@ -140,7 +153,9 @@ public:
LocalAccount::pointer getLocalAccount(const uint160& famBase, int seq); LocalAccount::pointer getLocalAccount(const uint160& famBase, int seq);
LocalAccount::pointer getLocalAccount(const uint160& acctID); LocalAccount::pointer getLocalAccount(const uint160& acctID);
std::string getPubKey(const uint160& famBase); std::string getPubKeyHex(const uint160& famBase);
static bool unitTest();
}; };
#endif #endif