mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 10:35:50 +00:00
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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
13
Ledger.cpp
13
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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
359
Wallet.cpp
359
Wallet.cpp
@@ -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
156
Wallet.h
@@ -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
24
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<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
|
||||
|
||||
Reference in New Issue
Block a user