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 "Config.h"
#include "PeerDoor.h"
#include "RPCDoor.h"
#include "BitcoinUtil.h"
#include "key.h"
#include "database/SqliteDatabase.h"
//#include <boost/log/trivial.hpp>
#include <iostream>
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;
}

View File

@@ -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)

View File

@@ -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
)

View File

@@ -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<int, LocalAccountEntry::pointer>::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<int, LocalAccountEntry::pointer>::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<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)
{
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));
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<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(familyName);
std::map<uint160, LocalAccountFamily::pointer>::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<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;
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<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)
@@ -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;
}

View File

@@ -67,9 +67,12 @@ protected:
std::map<int, LocalAccountEntry::pointer> 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