Merge pull request #381 from TheBlueMatt/nminversion
authorJeff Garzik <jgarzik@exmulti.com>
Wed, 13 Jul 2011 02:34:30 +0000 (19:34 -0700)
committerJeff Garzik <jgarzik@exmulti.com>
Wed, 13 Jul 2011 02:34:30 +0000 (19:34 -0700)
Add minversion to wallet.

1  2 
src/db.cpp
src/db.h
src/init.cpp
src/wallet.cpp

diff --combined src/db.cpp
@@@ -670,7 -670,7 +670,7 @@@ void CWalletDB::ListAccountCreditDebit(
  }
  
  
- bool CWalletDB::LoadWallet(CWallet* pwallet)
+ int CWalletDB::LoadWallet(CWallet* pwallet)
  {
      pwallet->vchDefaultKey.clear();
      int nFileVersion = 0;
  
      //// todo: shouldn't we catch exceptions and try to recover and continue?
      CRITICAL_BLOCK(pwallet->cs_mapWallet)
 -    CRITICAL_BLOCK(pwallet->cs_mapKeys)
 +    CRITICAL_BLOCK(pwallet->cs_KeyStore)
      {
          // Get cursor
          Dbc* pcursor = GetCursor();
          if (!pcursor)
-             return false;
+             return DB_CORRUPT;
  
          loop
          {
              if (ret == DB_NOTFOUND)
                  break;
              else if (ret != 0)
-                 return false;
+                 return DB_CORRUPT;
  
              // Unserialize
              // Taking advantage of the fact that pair serialization
              {
                  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;
 -
 -                pwallet->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")
              {
                  if (strKey == "fGenerateBitcoins")  ssValue >> fGenerateBitcoins;
  #endif
                  if (strKey == "nTransactionFee")    ssValue >> nTransactionFee;
 -                if (strKey == "addrIncoming")       ssValue >> addrIncoming;
                  if (strKey == "fLimitProcessors")   ssValue >> fLimitProcessors;
                  if (strKey == "nLimitProcessors")   ssValue >> nLimitProcessors;
                  if (strKey == "fMinimizeToTray")    ssValue >> fMinimizeToTray;
                  if (strKey == "addrProxy")          ssValue >> addrProxy;
                  if (fHaveUPnP && strKey == "fUseUPnP")           ssValue >> fUseUPnP;
              }
+             else if (strType == "minversion")
+             {
+                 int nMinVersion = 0;
+                 ssValue >> nMinVersion;
+                 if (nMinVersion > VERSION)
+                     return DB_TOO_NEW;
+             }
          }
          pcursor->close();
      }
      printf("nFileVersion = %d\n", nFileVersion);
      printf("fGenerateBitcoins = %d\n", fGenerateBitcoins);
      printf("nTransactionFee = %"PRI64d"\n", nTransactionFee);
 -    printf("addrIncoming = %s\n", addrIncoming.ToString().c_str());
      printf("fMinimizeToTray = %d\n", fMinimizeToTray);
      printf("fMinimizeOnClose = %d\n", fMinimizeOnClose);
      printf("fUseProxy = %d\n", fUseProxy);
      }
  
  
-     return true;
+     return DB_LOAD_OK;
  }
  
  void ThreadFlushWalletDB(void* parg)
diff --combined src/db.h
+++ b/src/db.h
@@@ -342,6 -342,13 +342,13 @@@ public
  
  
  
+ enum DBErrors
+ {
+     DB_LOAD_OK,
+     DB_CORRUPT,
+     DB_TOO_NEW
+ };
  class CWalletDB : public CDB
  {
  public:
@@@ -391,25 -398,6 +398,25 @@@ public
          return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
      }
  
 +    bool WriteCryptedKey(const std::vector<unsigned char>& vchPubKey, const std::vector<unsigned char>& vchCryptedSecret, bool fEraseUnencryptedKey = true)
 +    {
 +        nWalletDBUpdated++;
 +        if (!Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
 +            return false;
 +        if (fEraseUnencryptedKey)
 +        {
 +            Erase(std::make_pair(std::string("key"), vchPubKey));
 +            Erase(std::make_pair(std::string("wkey"), vchPubKey));
 +        }
 +        return true;
 +    }
 +
 +    bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
 +    {
 +        nWalletDBUpdated++;
 +        return Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
 +    }
 +
      bool WriteBestBlock(const CBlockLocator& locator)
      {
          nWalletDBUpdated++;
      int64 GetAccountCreditDebit(const std::string& strAccount);
      void ListAccountCreditDebit(const std::string& strAccount, std::list<CAccountingEntry>& acentries);
  
-     bool LoadWallet(CWallet* pwallet);
+     int LoadWallet(CWallet* pwallet);
  };
  
  #endif
diff --combined src/init.cpp
@@@ -387,8 -387,16 +387,16 @@@ bool AppInit2(int argc, char* argv[]
      nStart = GetTimeMillis();
      bool fFirstRun;
      pwalletMain = new CWallet("wallet.dat");
-     if (!pwalletMain->LoadWallet(fFirstRun))
-         strErrors += _("Error loading wallet.dat      \n");
+     int nLoadWalletRet = pwalletMain->LoadWallet(fFirstRun);
+     if (nLoadWalletRet != DB_LOAD_OK)
+     {
+         if (nLoadWalletRet == DB_CORRUPT)
+             strErrors += _("Error loading wallet.dat: Wallet corrupted      \n");
+         else if (nLoadWalletRet == DB_TOO_NEW)
+             strErrors += _("Error loading wallet.dat: Wallet requires newer version of Bitcoin      \n");
+         else
+             strErrors += _("Error loading wallet.dat      \n");
+     }
      printf(" wallet      %15"PRI64d"ms\n", GetTimeMillis() - nStart);
  
      RegisterWallet(pwalletMain);
          //// debug print
          printf("mapBlockIndex.size() = %d\n",   mapBlockIndex.size());
          printf("nBestHeight = %d\n",            nBestHeight);
 -        printf("mapKeys.size() = %d\n",         pwalletMain->mapKeys.size());
          printf("setKeyPool.size() = %d\n",      pwalletMain->setKeyPool.size());
          printf("mapPubKeys.size() = %d\n",      mapPubKeys.size());
          printf("mapWallet.size() = %d\n",       pwalletMain->mapWallet.size());
diff --combined src/wallet.cpp
@@@ -5,11 -5,11 +5,11 @@@
  #include "headers.h"
  #include "db.h"
  #include "cryptopp/sha.h"
 +#include "crypter.h"
  
  using namespace std;
  
  
 -
  //////////////////////////////////////////////////////////////////////////////
  //
  // mapWallet
  
  bool CWallet::AddKey(const CKey& key)
  {
 -    this->CKeyStore::AddKey(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).WriteKey(key.GetPubKey(), key.GetPrivKey());
 +    CRITICAL_BLOCK(cs_pwalletdbEncryption)
 +    {
 +        if (pwalletdbEncryption)
 +            return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
 +        else
 +            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))
 +            {
 +                int64 nStartTime = GetTimeMillis();
 +                crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
 +                pMasterKey.second.nDeriveIterations = pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)));
 +
 +                nStartTime = GetTimeMillis();
 +                crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod);
 +                pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
 +
 +                if (pMasterKey.second.nDeriveIterations < 25000)
 +                    pMasterKey.second.nDeriveIterations = 25000;
 +
 +                printf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations);
 +
 +                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;
 +}
 +
 +
 +// This class implements an addrIncoming entry that causes pre-0.4
 +// clients to crash on startup if reading a private-key-encrypted wallet.
 +class CCorruptAddress
 +{
 +public:
 +    IMPLEMENT_SERIALIZE
 +    (
 +        if (nType & SER_DISK)
 +            READWRITE(nVersion);
 +    )
 +};
 +
 +bool CWallet::EncryptWallet(const string& strWalletPassphrase)
 +{
 +    CRITICAL_BLOCK(cs_mapPubKeys)
 +    CRITICAL_BLOCK(cs_KeyStore)
 +    CRITICAL_BLOCK(cs_vMasterKey)
 +    CRITICAL_BLOCK(cs_pwalletdbEncryption)
 +    {
 +        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;
 +        int64 nStartTime = GetTimeMillis();
 +        crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
 +        kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
 +
 +        nStartTime = GetTimeMillis();
 +        crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod);
 +        kMasterKey.nDeriveIterations = (kMasterKey.nDeriveIterations + kMasterKey.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime))) / 2;
 +
 +        if (kMasterKey.nDeriveIterations < 25000)
 +            kMasterKey.nDeriveIterations = 25000;
 +
 +        printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations);
 +
 +        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)
 +        {
 +            pwalletdbEncryption = new CWalletDB(strWalletFile);
 +            pwalletdbEncryption->TxnBegin();
 +            pwalletdbEncryption->WriteMasterKey(nMasterKeyMaxID, kMasterKey);
 +        }
 +
 +        if (!EncryptKeys(vMasterKey))
 +        {
 +            if (fFileBacked)
 +                pwalletdbEncryption->TxnAbort();
 +            exit(1); //We now probably have half of our keys encrypted in memory, and half not...die and let the user reload their unencrypted wallet.
 +        }
 +
 +        if (fFileBacked)
 +        {
 +            CCorruptAddress corruptAddress;
 +            pwalletdbEncryption->WriteSetting("addrIncoming", corruptAddress);
 +            if (!pwalletdbEncryption->TxnCommit())
 +                exit(1); //We now have keys encrypted in memory, but no on disk...die to avoid confusion and let the user reload their unencrypted wallet.
 +
 +            pwalletdbEncryption->Close();
 +            pwalletdbEncryption = NULL;
 +        }
 +
 +        Lock();
 +    }
 +    return true;
  }
  
  void CWallet::WalletUpdateSpent(const CTransaction &tx)
@@@ -268,7 -98,14 +268,7 @@@ bool CWallet::AddToWallet(const CWallet
          BOOST_FOREACH(const CTxOut& txout, wtx.vout)
          {
              if (txout.scriptPubKey == scriptDefaultKey)
 -            {
 -                if (!fFileBacked)
 -                    continue;
 -                CWalletDB walletdb(strWalletFile);
 -                vchDefaultKey = GetKeyFromKeyPool();
 -                walletdb.WriteDefaultKey(vchDefaultKey);
 -                walletdb.WriteName(PubKeyToAddress(vchDefaultKey), "");
 -            }
 +                SetDefaultKey(GetOrReuseKeyFromPool());
          }
  
          // Notify UI
@@@ -953,7 -790,7 +953,7 @@@ bool CWallet::CreateTransaction(const v
  
                      // 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;
@@@ -1073,24 -910,15 +1073,24 @@@ string CWallet::SendMoney(CScript scrip
  {
      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))
@@@ -1130,18 -958,20 +1130,19 @@@ bool CWallet::LoadWallet(bool& fFirstRu
      if (!fFileBacked)
          return false;
      fFirstRunRet = false;
-     if (!CWalletDB(strWalletFile,"cr+").LoadWallet(this))
-         return false;
+     int nLoadWalletRet = CWalletDB(strWalletFile,"cr+").LoadWallet(this);
+     if (nLoadWalletRet != DB_LOAD_OK)
+         return nLoadWalletRet;
      fFirstRunRet = vchDefaultKey.empty();
  
 -    if (!mapKeys.count(vchDefaultKey))
 +    if (!HaveKey(vchDefaultKey))
      {
 -        // Create new default key
 +        // Create new keyUser and set as default key
          RandAddSeedPerfmon();
  
 -        vchDefaultKey = GetKeyFromKeyPool();
 +        SetDefaultKey(GetOrReuseKeyFromPool());
          if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), ""))
              return false;
 -        CWalletDB(strWalletFile).WriteDefaultKey(vchDefaultKey);
      }
  
      CreateThread(ThreadFlushWalletDB, &strWalletFile);
@@@ -1193,17 -1023,6 +1194,17 @@@ bool CWallet::GetTransaction(const uint
      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 true;
  }
  
 -void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
 +bool CWallet::TopUpKeyPool()
  {
      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
              if (!setKeyPool.empty())
                  nEnd = *(--setKeyPool.end()) + 1;
              if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
 -                throw runtime_error("ReserveKeyFromKeyPool() : writing generated key failed");
 +                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 (!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);
@@@ -1290,13 -1089,11 +1291,13 @@@ void CWallet::ReturnKey(int64 nIndex
      printf("keypool return %"PRI64d"\n", nIndex);
  }
  
 -vector<unsigned char> CWallet::GetKeyFromKeyPool()
 +vector<unsigned char> CWallet::GetOrReuseKeyFromPool()
  {
      int64 nIndex = 0;
      CKeyPool keypool;
      ReserveKeyFromKeyPool(nIndex, keypool);
 +    if(nIndex == -1)
 +        return vchDefaultKey;
      KeepKey(nIndex);
      return keypool.vchPubKey;
  }
@@@ -1306,8 -1103,6 +1307,8 @@@ int64 CWallet::GetOldestKeyPoolTime(
      int64 nIndex = 0;
      CKeyPool keypool;
      ReserveKeyFromKeyPool(nIndex, keypool);
 +    if (nIndex == -1)
 +        return GetTime();
      ReturnKey(nIndex);
      return keypool.nTime;
  }
@@@ -1339,4 -1134,3 +1340,4 @@@ void CReserveKey::ReturnKey(
      nIndex = -1;
      vchPubKey.clear();
  }
 +