Add wallet privkey encryption.
[novacoin.git] / src / db.cpp
index b3ce00a..e639a34 100644 (file)
@@ -5,12 +5,12 @@
 #include "headers.h"
 #include "db.h"
 #include "net.h"
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
 
 using namespace std;
 using namespace boost;
 
-void ThreadFlushWalletDB(void* parg);
-
 
 unsigned int nWalletDBUpdated;
 uint64 nAccountingEntryNumber = 0;
@@ -149,7 +149,7 @@ void CDB::Close()
         --mapFileUseCount[strFile];
 }
 
-void CloseDb(const string& strFile)
+void static CloseDb(const string& strFile)
 {
     CRITICAL_BLOCK(cs_db)
     {
@@ -358,7 +358,7 @@ bool CTxDB::WriteBestInvalidWork(CBigNum bnBestInvalidWork)
     return Write(string("bnBestInvalidWork"), bnBestInvalidWork);
 }
 
-CBlockIndex* InsertBlockIndex(uint256 hash)
+CBlockIndex static * InsertBlockIndex(uint256 hash)
 {
     if (hash == 0)
         return NULL;
@@ -583,8 +583,19 @@ bool LoadAddresses()
 // CWalletDB
 //
 
-static set<int64> setKeyPool;
-static CCriticalSection cs_setKeyPool;
+bool CWalletDB::WriteName(const string& strAddress, const string& strName)
+{
+    nWalletDBUpdated++;
+    return Write(make_pair(string("name"), strAddress), strName);
+}
+
+bool CWalletDB::EraseName(const string& strAddress)
+{
+    // This should only be used for sending addresses, never for receiving addresses,
+    // receiving addresses must always have an address book entry if they're not change return.
+    nWalletDBUpdated++;
+    return Erase(make_pair(string("name"), strAddress));
+}
 
 bool CWalletDB::ReadAccount(const string& strAccount, CAccount& account)
 {
@@ -659,9 +670,9 @@ void CWalletDB::ListAccountCreditDebit(const string& strAccount, list<CAccountin
 }
 
 
-bool CWalletDB::LoadWallet()
+bool CWalletDB::LoadWallet(CWallet* pwallet)
 {
-    vchDefaultKey.clear();
+    pwallet->vchDefaultKey.clear();
     int nFileVersion = 0;
     vector<uint256> vWalletUpgrade;
 
@@ -673,8 +684,8 @@ bool CWalletDB::LoadWallet()
 #endif
 
     //// todo: shouldn't we catch exceptions and try to recover and continue?
-    CRITICAL_BLOCK(cs_mapWallet)
-    CRITICAL_BLOCK(cs_mapKeys)
+    CRITICAL_BLOCK(pwallet->cs_mapWallet)
+    CRITICAL_BLOCK(pwallet->cs_KeyStore)
     {
         // Get cursor
         Dbc* pcursor = GetCursor();
@@ -701,14 +712,15 @@ bool CWalletDB::LoadWallet()
             {
                 string strAddress;
                 ssKey >> strAddress;
-                ssValue >> mapAddressBook[strAddress];
+                ssValue >> pwallet->mapAddressBook[strAddress];
             }
             else if (strType == "tx")
             {
                 uint256 hash;
                 ssKey >> hash;
-                CWalletTx& wtx = mapWallet[hash];
+                CWalletTx& wtx = pwallet->mapWallet[hash];
                 ssValue >> wtx;
+                wtx.pwallet = pwallet;
 
                 if (wtx.GetHash() != hash)
                     printf("Error in wallet.dat, hash mismatch\n");
@@ -753,24 +765,52 @@ bool CWalletDB::LoadWallet()
             {
                 vector<unsigned char> vchPubKey;
                 ssKey >> vchPubKey;
-                CWalletKey wkey;
+                CKey key;
                 if (strType == "key")
-                    ssValue >> wkey.vchPrivKey;
+                {
+                    CPrivKey pkey;
+                    ssValue >> pkey;
+                    key.SetPrivKey(pkey);
+                }
                 else
+                {
+                    CWalletKey wkey;
                     ssValue >> wkey;
-
-                mapKeys[vchPubKey] = wkey.vchPrivKey;
-                mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
+                    key.SetPrivKey(wkey.vchPrivKey);
+                }
+                if (!pwallet->LoadKey(key))
+                    return false;
+            }
+            else if (strType == "mkey")
+            {
+                unsigned int nID;
+                ssKey >> nID;
+                CMasterKey kMasterKey;
+                ssValue >> kMasterKey;
+                if(pwallet->mapMasterKeys.count(nID) != 0)
+                    return false;
+                pwallet->mapMasterKeys[nID] = kMasterKey;
+                if (pwallet->nMasterKeyMaxID < nID)
+                    pwallet->nMasterKeyMaxID = nID;
+            }
+            else if (strType == "ckey")
+            {
+                vector<unsigned char> vchPubKey;
+                ssKey >> vchPubKey;
+                vector<unsigned char> vchPrivKey;
+                ssValue >> vchPrivKey;
+                if (!pwallet->LoadCryptedKey(vchPubKey, vchPrivKey))
+                    return false;
             }
             else if (strType == "defaultkey")
             {
-                ssValue >> vchDefaultKey;
+                ssValue >> pwallet->vchDefaultKey;
             }
             else if (strType == "pool")
             {
                 int64 nIndex;
                 ssKey >> nIndex;
-                setKeyPool.insert(nIndex);
+                pwallet->setKeyPool.insert(nIndex);
             }
             else if (strType == "version")
             {
@@ -802,7 +842,7 @@ bool CWalletDB::LoadWallet()
     }
 
     BOOST_FOREACH(uint256 hash, vWalletUpgrade)
-        WriteTx(hash, mapWallet[hash]);
+        WriteTx(hash, pwallet->mapWallet[hash]);
 
     printf("nFileVersion = %d\n", nFileVersion);
     printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
@@ -830,37 +870,9 @@ bool CWalletDB::LoadWallet()
     return true;
 }
 
-bool LoadWallet(bool& fFirstRunRet)
-{
-    fFirstRunRet = false;
-    if (!CWalletDB("cr+").LoadWallet())
-        return false;
-    fFirstRunRet = vchDefaultKey.empty();
-
-    if (mapKeys.count(vchDefaultKey))
-    {
-        // Set keyUser
-        keyUser.SetPubKey(vchDefaultKey);
-        keyUser.SetPrivKey(mapKeys[vchDefaultKey]);
-    }
-    else
-    {
-        // Create new keyUser and set as default key
-        RandAddSeedPerfmon();
-        keyUser.MakeNewKey();
-        if (!AddKey(keyUser))
-            return false;
-        if (!SetAddressBookName(PubKeyToAddress(keyUser.GetPubKey()), ""))
-            return false;
-        CWalletDB().WriteDefaultKey(keyUser.GetPubKey());
-    }
-
-    CreateThread(ThreadFlushWalletDB, NULL);
-    return true;
-}
-
 void ThreadFlushWalletDB(void* parg)
 {
+    const string& strFile = ((const string*)parg)[0];
     static bool fOneThread;
     if (fOneThread)
         return;
@@ -896,7 +908,6 @@ void ThreadFlushWalletDB(void* parg)
 
                 if (nRefCount == 0 && !fShutdown)
                 {
-                    string strFile = "wallet.dat";
                     map<string, int>::iterator mi = mapFileUseCount.find(strFile);
                     if (mi != mapFileUseCount.end())
                     {
@@ -919,26 +930,27 @@ void ThreadFlushWalletDB(void* parg)
     }
 }
 
-void BackupWallet(const string& strDest)
+bool BackupWallet(const CWallet& wallet, const string& strDest)
 {
+    if (!wallet.fFileBacked)
+        return false;
     while (!fShutdown)
     {
         CRITICAL_BLOCK(cs_db)
         {
-            const string strFile = "wallet.dat";
-            if (!mapFileUseCount.count(strFile) || mapFileUseCount[strFile] == 0)
+            if (!mapFileUseCount.count(wallet.strWalletFile) || mapFileUseCount[wallet.strWalletFile] == 0)
             {
                 // Flush log data to the dat file
-                CloseDb(strFile);
+                CloseDb(wallet.strWalletFile);
                 dbenv.txn_checkpoint(0, 0, 0);
-                dbenv.lsn_reset(strFile.c_str(), 0);
-                mapFileUseCount.erase(strFile);
+                dbenv.lsn_reset(wallet.strWalletFile.c_str(), 0);
+                mapFileUseCount.erase(wallet.strWalletFile);
 
                 // Copy wallet.dat
-                filesystem::path pathSrc(GetDataDir() + "/" + strFile);
+                filesystem::path pathSrc(GetDataDir() + "/" + wallet.strWalletFile);
                 filesystem::path pathDest(strDest);
                 if (filesystem::is_directory(pathDest))
-                    pathDest = pathDest / strFile;
+                    pathDest = pathDest / wallet.strWalletFile;
 #if BOOST_VERSION >= 104000
                 filesystem::copy_file(pathSrc, pathDest, filesystem::copy_option::overwrite_if_exists);
 #else
@@ -946,83 +958,10 @@ void BackupWallet(const string& strDest)
 #endif
                 printf("copied wallet.dat to %s\n", pathDest.string().c_str());
 
-                return;
+                return true;
             }
         }
         Sleep(100);
     }
-}
-
-
-void CWalletDB::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
-{
-    nIndex = -1;
-    keypool.vchPubKey.clear();
-    CRITICAL_BLOCK(cs_main)
-    CRITICAL_BLOCK(cs_mapWallet)
-    CRITICAL_BLOCK(cs_setKeyPool)
-    {
-        // Top up key pool
-        int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
-        while (setKeyPool.size() < nTargetSize+1)
-        {
-            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");
-            setKeyPool.insert(nEnd);
-            printf("keypool added key %"PRI64d", size=%d\n", nEnd, setKeyPool.size());
-        }
-
-        // Get the oldest key
-        assert(!setKeyPool.empty());
-        nIndex = *(setKeyPool.begin());
-        setKeyPool.erase(setKeyPool.begin());
-        if (!Read(make_pair(string("pool"), nIndex), keypool))
-            throw runtime_error("ReserveKeyFromKeyPool() : read failed");
-        if (!mapKeys.count(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)
-{
-    // Remove from key pool
-    CRITICAL_BLOCK(cs_main)
-    CRITICAL_BLOCK(cs_mapWallet)
-    {
-        Erase(make_pair(string("pool"), nIndex));
-    }
-    printf("keypool keep %"PRI64d"\n", nIndex);
-}
-
-void CWalletDB::ReturnKey(int64 nIndex)
-{
-    // Return to key pool
-    CRITICAL_BLOCK(cs_setKeyPool)
-        setKeyPool.insert(nIndex);
-    printf("keypool return %"PRI64d"\n", nIndex);
-}
-
-vector<unsigned char> GetKeyFromKeyPool()
-{
-    CWalletDB walletdb;
-    int64 nIndex = 0;
-    CKeyPool keypool;
-    walletdb.ReserveKeyFromKeyPool(nIndex, keypool);
-    walletdb.KeepKey(nIndex);
-    return keypool.vchPubKey;
-}
-
-int64 GetOldestKeyPoolTime()
-{
-    CWalletDB walletdb;
-    int64 nIndex = 0;
-    CKeyPool keypool;
-    walletdb.ReserveKeyFromKeyPool(nIndex, keypool);
-    walletdb.ReturnKey(nIndex);
-    return keypool.nTime;
+    return false;
 }