Add wallet privkey encryption.
[novacoin.git] / src / wallet.cpp
index a9fc92f..c3d793d 100644 (file)
 #include "headers.h"
 #include "db.h"
 #include "cryptopp/sha.h"
+#include "crypter.h"
 
 using namespace std;
 
 
-
 //////////////////////////////////////////////////////////////////////////////
 //
 // mapWallet
 //
 
-void WalletUpdateSpent(const COutPoint& prevout)
+bool CWallet::AddKey(const CKey& key)
+{
+    if (!CCryptoKeyStore::AddKey(key))
+        return false;
+    if (!fFileBacked)
+        return true;
+    if (!IsCrypted())
+        return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
+}
+
+bool CWallet::AddCryptedKey(const vector<unsigned char> &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
+{
+    if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
+        return false;
+    if (!fFileBacked)
+        return true;
+    return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
+}
+
+bool CWallet::Unlock(const string& strWalletPassphrase)
+{
+    CRITICAL_BLOCK(cs_vMasterKey)
+    {
+        if (!IsLocked())
+            return false;
+
+        CCrypter crypter;
+        CKeyingMaterial vMasterKey;
+
+        BOOST_FOREACH(const MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
+        {
+            if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
+                return false;
+            if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
+                return false;
+            if (CCryptoKeyStore::Unlock(vMasterKey))
+                return true;
+        }
+    }
+    return false;
+}
+
+bool CWallet::ChangeWalletPassphrase(const string& strOldWalletPassphrase, const string& strNewWalletPassphrase)
+{
+    CRITICAL_BLOCK(cs_vMasterKey)
+    {
+        bool fWasLocked = IsLocked();
+
+        Lock();
+
+        CCrypter crypter;
+        CKeyingMaterial vMasterKey;
+        BOOST_FOREACH(MasterKeyMap::value_type& pMasterKey, mapMasterKeys)
+        {
+            if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
+                return false;
+            if(!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
+                return false;
+            if (CCryptoKeyStore::Unlock(vMasterKey))
+            {
+                if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
+                    return false;
+                if (!crypter.Encrypt(vMasterKey, pMasterKey.second.vchCryptedKey))
+                    return false;
+                CWalletDB(strWalletFile).WriteMasterKey(pMasterKey.first, pMasterKey.second);
+                if (fWasLocked)
+                    Lock();
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+bool CWallet::EncryptWallet(const string& strWalletPassphrase)
+{
+    //TODO: use db commits
+    CRITICAL_BLOCK(cs_mapPubKeys)
+    CRITICAL_BLOCK(cs_KeyStore)
+    CRITICAL_BLOCK(cs_vMasterKey)
+    {
+        if (IsCrypted())
+            return false;
+
+        CKeyingMaterial vMasterKey;
+        RandAddSeedPerfmon();
+
+        vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE);
+        RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE);
+
+        CMasterKey kMasterKey;
+
+        RandAddSeedPerfmon();
+        kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE);
+        RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
+
+        CCrypter crypter;
+        if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod))
+            return false;
+        if (!crypter.Encrypt(vMasterKey, kMasterKey.vchCryptedKey))
+            return false;
+
+        mapMasterKeys[++nMasterKeyMaxID] = kMasterKey;
+        if (fFileBacked)
+        {
+            DBFlush(false);
+            CWalletDB(strWalletFile).WriteMasterKey(nMasterKeyMaxID, kMasterKey);
+            DBFlush(false);
+        }
+
+        if (!EncryptKeys(vMasterKey))
+            exit(1); //We now probably have half of our keys encrypted, and half not...die and let the user ask someone with experience to recover their wallet.
+
+        Lock();
+    }
+    return true;
+}
+
+void CWallet::WalletUpdateSpent(const CTransaction &tx)
 {
     // Anytime a signature is successfully verified, it's proof the outpoint is spent.
     // Update the wallet spent flag if it doesn't know due to wallet.dat being
     // restored from backup or the user making copies of wallet.dat.
     CRITICAL_BLOCK(cs_mapWallet)
     {
-        map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
-        if (mi != mapWallet.end())
+        BOOST_FOREACH(const CTxIn& txin, tx.vin)
         {
-            CWalletTx& wtx = (*mi).second;
-            if (!wtx.IsSpent(prevout.n) && wtx.vout[prevout.n].IsMine())
+            map<uint256, CWalletTx>::iterator mi = mapWallet.find(txin.prevout.hash);
+            if (mi != mapWallet.end())
             {
-                printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
-                wtx.MarkSpent(prevout.n);
-                wtx.WriteToDisk();
-                vWalletUpdated.push_back(prevout.hash);
+                CWalletTx& wtx = (*mi).second;
+                if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n]))
+                {
+                    printf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str());
+                    wtx.MarkSpent(txin.prevout.n);
+                    wtx.WriteToDisk();
+                    vWalletUpdated.push_back(txin.prevout.hash);
+                }
             }
         }
     }
 }
 
-bool AddToWallet(const CWalletTx& wtxIn)
+bool CWallet::AddToWallet(const CWalletTx& wtxIn)
 {
     uint256 hash = wtxIn.GetHash();
     CRITICAL_BLOCK(cs_mapWallet)
@@ -45,6 +166,7 @@ bool AddToWallet(const CWalletTx& wtxIn)
         // Inserts only if not already there, returns tx inserted or tx found
         pair<map<uint256, CWalletTx>::iterator, bool> ret = mapWallet.insert(make_pair(hash, wtxIn));
         CWalletTx& wtx = (*ret.first).second;
+        wtx.pwallet = this;
         bool fInsertedNew = ret.second;
         if (fInsertedNew)
             wtx.nTimeReceived = GetAdjustedTime();
@@ -86,16 +208,14 @@ bool AddToWallet(const CWalletTx& wtxIn)
         BOOST_FOREACH(const CTxOut& txout, wtx.vout)
         {
             if (txout.scriptPubKey == scriptDefaultKey)
-            {
-                CWalletDB walletdb;
-                vchDefaultKey = GetKeyFromKeyPool();
-                walletdb.WriteDefaultKey(vchDefaultKey);
-                walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
-            }
+                SetDefaultKey(GetOrReuseKeyFromPool());
         }
 
         // Notify UI
         vWalletUpdated.push_back(hash);
+
+        // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
+        WalletUpdateSpent(wtx);
     }
 
     // Refresh UI
@@ -103,60 +223,64 @@ bool AddToWallet(const CWalletTx& wtxIn)
     return true;
 }
 
-bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
+bool CWallet::AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate)
 {
     uint256 hash = tx.GetHash();
     bool fExisted = mapWallet.count(hash);
     if (fExisted && !fUpdate) return false;
-    if (fExisted || tx.IsMine() || tx.IsFromMe())
+    if (fExisted || IsMine(tx) || IsFromMe(tx))
     {
-        CWalletTx wtx(tx);
+        CWalletTx wtx(this,tx);
         // Get merkle branch if transaction was found in a block
         if (pblock)
             wtx.SetMerkleBranch(pblock);
         return AddToWallet(wtx);
     }
+    else
+        WalletUpdateSpent(tx);
     return false;
 }
 
-bool EraseFromWallet(uint256 hash)
+bool CWallet::EraseFromWallet(uint256 hash)
 {
+    if (!fFileBacked)
+        return false;
     CRITICAL_BLOCK(cs_mapWallet)
     {
         if (mapWallet.erase(hash))
-            CWalletDB().EraseTx(hash);
+            CWalletDB(strWalletFile).EraseTx(hash);
     }
     return true;
 }
 
 
-bool CTxIn::IsMine() const
+bool CWallet::IsMine(const CTxIn &txin) const
 {
     CRITICAL_BLOCK(cs_mapWallet)
     {
-        map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
+        map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
         if (mi != mapWallet.end())
         {
             const CWalletTx& prev = (*mi).second;
-            if (prevout.n < prev.vout.size())
-                if (prev.vout[prevout.n].IsMine())
+            if (txin.prevout.n < prev.vout.size())
+                if (IsMine(prev.vout[txin.prevout.n]))
                     return true;
         }
     }
     return false;
 }
 
-int64 CTxIn::GetDebit() const
+int64 CWallet::GetDebit(const CTxIn &txin) const
 {
     CRITICAL_BLOCK(cs_mapWallet)
     {
-        map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
+        map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash);
         if (mi != mapWallet.end())
         {
             const CWalletTx& prev = (*mi).second;
-            if (prevout.n < prev.vout.size())
-                if (prev.vout[prevout.n].IsMine())
-                    return prev.vout[prevout.n].nValue;
+            if (txin.prevout.n < prev.vout.size())
+                if (IsMine(prev.vout[txin.prevout.n]))
+                    return prev.vout[txin.prevout.n].nValue;
         }
     }
     return 0;
@@ -184,31 +308,31 @@ int CWalletTx::GetRequestCount() const
 {
     // Returns -1 if it wasn't being tracked
     int nRequests = -1;
-    CRITICAL_BLOCK(cs_mapRequestCount)
+    CRITICAL_BLOCK(pwallet->cs_mapRequestCount)
     {
         if (IsCoinBase())
         {
             // Generated block
             if (hashBlock != 0)
             {
-                map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
-                if (mi != mapRequestCount.end())
+                map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
+                if (mi != pwallet->mapRequestCount.end())
                     nRequests = (*mi).second;
             }
         }
         else
         {
             // Did anyone request this transaction?
-            map<uint256, int>::iterator mi = mapRequestCount.find(GetHash());
-            if (mi != mapRequestCount.end())
+            map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(GetHash());
+            if (mi != pwallet->mapRequestCount.end())
             {
                 nRequests = (*mi).second;
 
                 // How about the block it's in?
                 if (nRequests == 0 && hashBlock != 0)
                 {
-                    map<uint256, int>::iterator mi = mapRequestCount.find(hashBlock);
-                    if (mi != mapRequestCount.end())
+                    map<uint256, int>::const_iterator mi = pwallet->mapRequestCount.find(hashBlock);
+                    if (mi != pwallet->mapRequestCount.end())
                         nRequests = (*mi).second;
                     else
                         nRequests = 1; // If it's in someone else's block it must have got out
@@ -230,7 +354,7 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l
     if (IsCoinBase())
     {
         if (GetBlocksToMaturity() > 0)
-            nGeneratedImmature = CTransaction::GetCredit();
+            nGeneratedImmature = pwallet->GetCredit(*this);
         else
             nGeneratedMature = GetCredit();
         return;
@@ -253,7 +377,7 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l
         vector<unsigned char> vchPubKey;
         if (ExtractHash160(txout.scriptPubKey, hash160))
             address = Hash160ToAddress(hash160);
-        else if (ExtractPubKey(txout.scriptPubKey, false, vchPubKey))
+        else if (ExtractPubKey(txout.scriptPubKey, NULL, vchPubKey))
             address = PubKeyToAddress(vchPubKey);
         else
         {
@@ -263,13 +387,13 @@ void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, l
         }
 
         // Don't report 'change' txouts
-        if (nDebit > 0 && txout.IsChange())
+        if (nDebit > 0 && pwallet->IsChange(txout))
             continue;
 
         if (nDebit > 0)
             listSent.push_back(make_pair(address, txout.nValue));
 
-        if (txout.IsMine())
+        if (pwallet->IsMine(txout))
             listReceived.push_back(make_pair(address, txout.nValue));
     }
 
@@ -295,16 +419,15 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, i
             nSent += s.second;
         nFee = allFee;
     }
-    CRITICAL_BLOCK(cs_mapAddressBook)
+    CRITICAL_BLOCK(pwallet->cs_mapAddressBook)
     {
         BOOST_FOREACH(const PAIRTYPE(string,int64)& r, listReceived)
         {
-            if (mapAddressBook.count(r.first))
+            if (pwallet->mapAddressBook.count(r.first))
             {
-                if (mapAddressBook[r.first] == strAccount)
-                {
+                map<string, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first);
+                if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount)
                     nReceived += r.second;
-                }
             }
             else if (strAccount.empty())
             {
@@ -326,7 +449,7 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
             vWorkQueue.push_back(txin.prevout.hash);
 
         // This critsect is OK because txdb is already open
-        CRITICAL_BLOCK(cs_mapWallet)
+        CRITICAL_BLOCK(pwallet->cs_mapWallet)
         {
             map<uint256, const CMerkleTx*> mapWalletPrev;
             set<uint256> setAlreadyDone;
@@ -338,10 +461,11 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
                 setAlreadyDone.insert(hash);
 
                 CMerkleTx tx;
-                if (mapWallet.count(hash))
+                map<uint256, CWalletTx>::const_iterator mi = pwallet->mapWallet.find(hash);
+                if (mi != pwallet->mapWallet.end())
                 {
-                    tx = mapWallet[hash];
-                    BOOST_FOREACH(const CMerkleTx& txWalletPrev, mapWallet[hash].vtxPrev)
+                    tx = (*mi).second;
+                    BOOST_FOREACH(const CMerkleTx& txWalletPrev, (*mi).second.vtxPrev)
                         mapWalletPrev[txWalletPrev.GetHash()] = &txWalletPrev;
                 }
                 else if (mapWalletPrev.count(hash))
@@ -373,10 +497,10 @@ void CWalletTx::AddSupportingTransactions(CTxDB& txdb)
 
 bool CWalletTx::WriteToDisk()
 {
-    return CWalletDB().WriteTx(GetHash(), *this);
+    return CWalletDB(pwallet->strWalletFile).WriteTx(GetHash(), *this);
 }
 
-int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
+int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
 {
     int ret = 0;
 
@@ -398,7 +522,7 @@ int ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
     return ret;
 }
 
-void ReacceptWalletTransactions()
+void CWallet::ReacceptWalletTransactions()
 {
     CTxDB txdb("r");
     bool fRepeat = true;
@@ -426,7 +550,7 @@ void ReacceptWalletTransactions()
                 {
                     if (wtx.IsSpent(i))
                         continue;
-                    if (!txindex.vSpent[i].IsNull() && wtx.vout[i].IsMine())
+                    if (!txindex.vSpent[i].IsNull() && IsMine(wtx.vout[i]))
                     {
                         wtx.MarkSpent(i);
                         fUpdated = true;
@@ -484,7 +608,7 @@ void CWalletTx::RelayWalletTransaction()
    RelayWalletTransaction(txdb);
 }
 
-void ResendWalletTransactions()
+void CWallet::ResendWalletTransactions()
 {
     // Do this infrequently and randomly to avoid giving away
     // that these are our transactions.
@@ -536,16 +660,16 @@ void ResendWalletTransactions()
 //
 
 
-int64 GetBalance()
+int64 CWallet::GetBalance() const
 {
     int64 nStart = GetTimeMillis();
 
     int64 nTotal = 0;
     CRITICAL_BLOCK(cs_mapWallet)
     {
-        for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+        for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
         {
-            CWalletTx* pcoin = &(*it).second;
+            const CWalletTx* pcoin = &(*it).second;
             if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
                 continue;
             nTotal += pcoin->GetAvailableCredit();
@@ -557,27 +681,27 @@ int64 GetBalance()
 }
 
 
-bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet)
+bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
 {
     setCoinsRet.clear();
     nValueRet = 0;
 
     // List of values less than target
-    pair<int64, pair<CWalletTx*,unsigned int> > coinLowestLarger;
+    pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
     coinLowestLarger.first = INT64_MAX;
     coinLowestLarger.second.first = NULL;
-    vector<pair<int64, pair<CWalletTx*,unsigned int> > > vValue;
+    vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
     int64 nTotalLower = 0;
 
     CRITICAL_BLOCK(cs_mapWallet)
     {
-       vector<CWalletTx*> vCoins;
+       vector<const CWalletTx*> vCoins;
        vCoins.reserve(mapWallet.size());
-       for (map<uint256, CWalletTx>::iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
+       for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
            vCoins.push_back(&(*it).second);
        random_shuffle(vCoins.begin(), vCoins.end(), GetRandInt);
 
-       BOOST_FOREACH(CWalletTx* pcoin, vCoins)
+       BOOST_FOREACH(const CWalletTx* pcoin, vCoins)
        {
             if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
                 continue;
@@ -591,7 +715,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
 
             for (int i = 0; i < pcoin->vout.size(); i++)
             {
-                if (pcoin->IsSpent(i) || !pcoin->vout[i].IsMine())
+                if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
                     continue;
 
                 int64 n = pcoin->vout[i].nValue;
@@ -599,7 +723,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
                 if (n <= 0)
                     continue;
 
-                pair<int64,pair<CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
+                pair<int64,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin,i));
 
                 if (n == nTargetValue)
                 {
@@ -702,7 +826,7 @@ bool SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfTheirs, set<
     return true;
 }
 
-bool SelectCoins(int64 nTargetValue, set<pair<CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet)
+bool CWallet::SelectCoins(int64 nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64& nValueRet) const
 {
     return (SelectCoinsMinConf(nTargetValue, 1, 6, setCoinsRet, nValueRet) ||
             SelectCoinsMinConf(nTargetValue, 1, 1, setCoinsRet, nValueRet) ||
@@ -712,7 +836,7 @@ bool SelectCoins(int64 nTargetValue, set<pair<CWalletTx*,unsigned int> >& setCoi
 
 
 
-bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
+bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
 {
     int64 nValue = 0;
     BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
@@ -724,6 +848,8 @@ bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx&
     if (vecSend.empty() || nValue < 0)
         return false;
 
+    wtxNew.pwallet = this;
+
     CRITICAL_BLOCK(cs_main)
     {
         // txdb must be opened before the mapWallet lock
@@ -744,11 +870,11 @@ bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx&
                     wtxNew.vout.push_back(CTxOut(s.second, s.first));
 
                 // Choose coins to use
-                set<pair<CWalletTx*,unsigned int> > setCoins;
+                set<pair<const CWalletTx*,unsigned int> > setCoins;
                 int64 nValueIn = 0;
                 if (!SelectCoins(nTotalValue, setCoins, nValueIn))
                     return false;
-                BOOST_FOREACH(PAIRTYPE(CWalletTx*, unsigned int) pcoin, setCoins)
+                BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
                 {
                     int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
                     dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
@@ -767,7 +893,7 @@ bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx&
 
                     // Reserve a new key pair from key pool
                     vector<unsigned char> vchPubKey = reservekey.GetReservedKey();
-                    assert(mapKeys.count(vchPubKey));
+                    // assert(mapKeys.count(vchPubKey));
 
                     // Fill a vout to ourself, using same address type as the payment
                     CScript scriptChange;
@@ -784,13 +910,13 @@ bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx&
                     reservekey.ReturnKey();
 
                 // Fill vin
-                BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins)
+                BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
                     wtxNew.vin.push_back(CTxIn(coin.first->GetHash(),coin.second));
 
                 // Sign
                 int nIn = 0;
-                BOOST_FOREACH(const PAIRTYPE(CWalletTx*,unsigned int)& coin, setCoins)
-                    if (!SignSignature(*coin.first, wtxNew, nIn++))
+                BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins)
+                    if (!SignSignature(*this, *coin.first, wtxNew, nIn++))
                         return false;
 
                 // Limit size
@@ -820,7 +946,7 @@ bool CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx&
     return true;
 }
 
-bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
+bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
 {
     vector< pair<CScript, int64> > vecSend;
     vecSend.push_back(make_pair(scriptPubKey, nValue));
@@ -828,7 +954,7 @@ bool CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CR
 }
 
 // Call after CreateTransaction unless you want to abort
-bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
+bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
 {
     CRITICAL_BLOCK(cs_main)
     {
@@ -838,7 +964,7 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
             // This is only to keep the database open to defeat the auto-flush for the
             // duration of this scope.  This is the only place where this optimization
             // maybe makes sense; please don't do it anywhere else.
-            CWalletDB walletdb("r");
+            CWalletDB* pwalletdb = fFileBacked ? new CWalletDB(strWalletFile,"r") : NULL;
 
             // Take key pair from key pool so it won't be used again
             reservekey.KeepKey();
@@ -851,11 +977,15 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
             set<CWalletTx*> setCoins;
             BOOST_FOREACH(const CTxIn& txin, wtxNew.vin)
             {
-                CWalletTx &pcoin = mapWallet[txin.prevout.hash];
-                pcoin.MarkSpent(txin.prevout.n);
-                pcoin.WriteToDisk();
-                vWalletUpdated.push_back(pcoin.GetHash());
+                CWalletTx &coin = mapWallet[txin.prevout.hash];
+                coin.pwallet = this;
+                coin.MarkSpent(txin.prevout.n);
+                coin.WriteToDisk();
+                vWalletUpdated.push_back(coin.GetHash());
             }
+
+            if (fFileBacked)
+                delete pwalletdb;
         }
 
         // Track how many getdata requests our transaction gets
@@ -879,19 +1009,28 @@ bool CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
 
 
 // requires cs_main lock
-string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
+string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
 {
-    CReserveKey reservekey;
+    CReserveKey reservekey(this);
     int64 nFeeRequired;
-    if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
+    CRITICAL_BLOCK(cs_vMasterKey)
     {
-        string strError;
-        if (nValue + nFeeRequired > GetBalance())
-            strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds  "), FormatMoney(nFeeRequired).c_str());
-        else
-            strError = _("Error: Transaction creation failed  ");
-        printf("SendMoney() : %s", strError.c_str());
-        return strError;
+        if (IsLocked())
+        {
+            string strError = _("Error: Wallet locked, unable to create transaction  ");
+            printf("SendMoney() : %s", strError.c_str());
+            return strError;
+        }
+        if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired))
+        {
+            string strError;
+            if (nValue + nFeeRequired > GetBalance())
+                strError = strprintf(_("Error: This transaction requires a transaction fee of at least %s because of its amount, complexity, or use of recently received funds  "), FormatMoney(nFeeRequired).c_str());
+            else
+                strError = _("Error: Transaction creation failed  ");
+            printf("SendMoney() : %s", strError.c_str());
+            return strError;
+        }
     }
 
     if (fAskFee && !ThreadSafeAskFee(nFeeRequired, _("Sending..."), NULL))
@@ -907,7 +1046,7 @@ string SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAs
 
 
 // requires cs_main lock
-string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
+string CWallet::SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
 {
     // Check amount
     if (nValue <= 0)
@@ -926,42 +1065,105 @@ string SendMoneyToBitcoinAddress(string strAddress, int64 nValue, CWalletTx& wtx
 
 
 
-bool LoadWallet(bool& fFirstRunRet)
+bool CWallet::LoadWallet(bool& fFirstRunRet)
 {
+    if (!fFileBacked)
+        return false;
     fFirstRunRet = false;
-    if (!CWalletDB("cr+").LoadWallet())
+    if (!CWalletDB(strWalletFile,"cr+").LoadWallet(this))
         return false;
     fFirstRunRet = vchDefaultKey.empty();
 
-    if (mapKeys.count(vchDefaultKey))
-    {
-        // Set keyUser
-        keyUser.SetPubKey(vchDefaultKey);
-        keyUser.SetPrivKey(mapKeys[vchDefaultKey]);
-    }
-    else
+    if (!HaveKey(vchDefaultKey))
     {
         // Create new keyUser and set as default key
         RandAddSeedPerfmon();
 
-        CWalletDB walletdb;
-        vchDefaultKey = GetKeyFromKeyPool();
-        walletdb.WriteDefaultKey(vchDefaultKey);
-        walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
+        SetDefaultKey(GetOrReuseKeyFromPool());
+        if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), ""))
+            return false;
     }
 
-    CreateThread(ThreadFlushWalletDB, NULL);
+    CreateThread(ThreadFlushWalletDB, &strWalletFile);
     return true;
 }
 
-void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
+
+bool CWallet::SetAddressBookName(const string& strAddress, const string& strName)
+{
+    mapAddressBook[strAddress] = strName;
+    if (!fFileBacked)
+        return false;
+    return CWalletDB(strWalletFile).WriteName(strAddress, strName);
+}
+
+bool CWallet::DelAddressBookName(const string& strAddress)
+{
+    mapAddressBook.erase(strAddress);
+    if (!fFileBacked)
+        return false;
+    return CWalletDB(strWalletFile).EraseName(strAddress);
+}
+
+
+void CWallet::PrintWallet(const CBlock& block)
+{
+    CRITICAL_BLOCK(cs_mapWallet)
+    {
+        if (mapWallet.count(block.vtx[0].GetHash()))
+        {
+            CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()];
+            printf("    mine:  %d  %d  %d", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit());
+        }
+    }
+    printf("\n");
+}
+
+bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx)
+{
+    CRITICAL_BLOCK(cs_mapWallet)
+    {
+        map<uint256, CWalletTx>::iterator mi = mapWallet.find(hashTx);
+        if (mi != mapWallet.end())
+        {
+            wtx = (*mi).second;
+            return true;
+        }
+    }
+    return false;
+}
+
+bool CWallet::SetDefaultKey(const std::vector<unsigned char> &vchPubKey)
+{
+    if (fFileBacked)
+    {
+        if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey))
+            return false;
+    }
+    vchDefaultKey = vchPubKey;
+    return true;
+}
+
+bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut)
+{
+    if (!pwallet->fFileBacked)
+        return false;
+    strWalletFileOut = pwallet->strWalletFile;
+    return true;
+}
+
+bool CWallet::TopUpKeyPool()
 {
-    nIndex = -1;
-    keypool.vchPubKey.clear();
     CRITICAL_BLOCK(cs_main)
     CRITICAL_BLOCK(cs_mapWallet)
     CRITICAL_BLOCK(cs_setKeyPool)
+    CRITICAL_BLOCK(cs_vMasterKey)
     {
+        if (IsLocked())
+            return false;
+
+        CWalletDB walletdb(strWalletFile);
+
         // Top up key pool
         int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
         while (setKeyPool.size() < nTargetSize+1)
@@ -969,37 +1171,58 @@ void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
             int64 nEnd = 1;
             if (!setKeyPool.empty())
                 nEnd = *(--setKeyPool.end()) + 1;
-            if (!Write(make_pair(string("pool"), nEnd), CKeyPool(GenerateNewKey())))
-                throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed");
+            if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
+                throw runtime_error("TopUpKeyPool() : writing generated key failed");
             setKeyPool.insert(nEnd);
             printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
         }
+    }
+    return true;
+}
+
+void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
+{
+    nIndex = -1;
+    keypool.vchPubKey.clear();
+    CRITICAL_BLOCK(cs_main)
+    CRITICAL_BLOCK(cs_mapWallet)
+    CRITICAL_BLOCK(cs_setKeyPool)
+    {
+        if (!IsLocked())
+            TopUpKeyPool();
 
         // Get the oldest key
-        assert(!setKeyPool.empty());
+        if(setKeyPool.empty())
+            return;
+
+        CWalletDB walletdb(strWalletFile);
+
         nIndex = *(setKeyPool.begin());
         setKeyPool.erase(setKeyPool.begin());
-        if (!Read(make_pair(string("pool"), nIndex), keypool))
+        if (!walletdb.ReadPool(nIndex, keypool))
             throw runtime_error("ReserveKeyFromKeyPool() : read failed");
-        if (!mapKeys.count(keypool.vchPubKey))
+        if (!HaveKey(keypool.vchPubKey))
             throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool");
         assert(!keypool.vchPubKey.empty());
         printf("keypool reserve %"PRI64d"\n", nIndex);
     }
 }
 
-void CWalletDB::KeepKey(int64 nIndex)
+void CWallet::KeepKey(int64 nIndex)
 {
     // Remove from key pool
-    CRITICAL_BLOCK(cs_main)
-    CRITICAL_BLOCK(cs_mapWallet)
+    if (fFileBacked)
     {
-        Erase(make_pair(string("pool"), nIndex));
+        CWalletDB walletdb(strWalletFile);
+        CRITICAL_BLOCK(cs_main)
+        {
+            walletdb.ErasePool(nIndex);
+        }
     }
     printf("keypool keep %"PRI64d"\n", nIndex);
 }
 
-void CWalletDB::ReturnKey(int64 nIndex)
+void CWallet::ReturnKey(int64 nIndex)
 {
     // Return to key pool
     CRITICAL_BLOCK(cs_setKeyPool)
@@ -1007,32 +1230,34 @@ void CWalletDB::ReturnKey(int64 nIndex)
     printf("keypool return %"PRI64d"\n", nIndex);
 }
 
-vector<unsigned char> GetKeyFromKeyPool()
+vector<unsigned char> CWallet::GetOrReuseKeyFromPool()
 {
-    CWalletDB walletdb;
     int64 nIndex = 0;
     CKeyPool keypool;
-    walletdb.ReserveKeyFromKeyPool(nIndex, keypool);
-    walletdb.KeepKey(nIndex);
+    ReserveKeyFromKeyPool(nIndex, keypool);
+    if(nIndex == -1)
+        return vchDefaultKey;
+    KeepKey(nIndex);
     return keypool.vchPubKey;
 }
 
-int64 GetOldestKeyPoolTime()
+int64 CWallet::GetOldestKeyPoolTime()
 {
-    CWalletDB walletdb;
     int64 nIndex = 0;
     CKeyPool keypool;
-    walletdb.ReserveKeyFromKeyPool(nIndex, keypool);
-    walletdb.ReturnKey(nIndex);
+    ReserveKeyFromKeyPool(nIndex, keypool);
+    if (nIndex == -1)
+        return GetTime();
+    ReturnKey(nIndex);
     return keypool.nTime;
 }
 
-std::vector<unsigned char> CReserveKey::GetReservedKey()
+vector<unsigned char> CReserveKey::GetReservedKey()
 {
     if (nIndex == -1)
     {
         CKeyPool keypool;
-        CWalletDB().ReserveKeyFromKeyPool(nIndex, keypool);
+        pwallet->ReserveKeyFromKeyPool(nIndex, keypool);
         vchPubKey = keypool.vchPubKey;
     }
     assert(!vchPubKey.empty());
@@ -1042,7 +1267,7 @@ std::vector<unsigned char> CReserveKey::GetReservedKey()
 void CReserveKey::KeepKey()
 {
     if (nIndex != -1)
-        CWalletDB().KeepKey(nIndex);
+        pwallet->KeepKey(nIndex);
     nIndex = -1;
     vchPubKey.clear();
 }
@@ -1050,7 +1275,8 @@ void CReserveKey::KeepKey()
 void CReserveKey::ReturnKey()
 {
     if (nIndex != -1)
-        CWalletDB::ReturnKey(nIndex);
+        pwallet->ReturnKey(nIndex);
     nIndex = -1;
     vchPubKey.clear();
 }
+