X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=src%2Fwallet.cpp;h=c3d793d379f21019ed684b3d1f6f775f49492dfb;hb=4e87d341f75f13bbd7d108c31c03886fbc4df56f;hp=7a65b2a5729a3fedd83504107e2ba7c240125f32;hpb=aa0c5e87e8000791009fac1cb394a36a94016d9f;p=novacoin.git diff --git a/src/wallet.cpp b/src/wallet.cpp index 7a65b2a..c3d793d 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -5,11 +5,11 @@ #include "headers.h" #include "db.h" #include "cryptopp/sha.h" +#include "crypter.h" using namespace std; - ////////////////////////////////////////////////////////////////////////////// // // mapWallet @@ -17,10 +17,120 @@ using namespace std; 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 &vchPubKey, const vector &vchCryptedSecret) +{ + if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) + return false; if (!fFileBacked) return true; - return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey()); + 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) @@ -98,14 +208,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) 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 @@ -790,7 +893,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, CW // Reserve a new key pair from key pool vector 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; @@ -910,15 +1013,24 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, { 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)) @@ -962,27 +1074,38 @@ bool CWallet::LoadWallet(bool& fFirstRunRet) 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(); - vchDefaultKey = GetKeyFromKeyPool(); + SetDefaultKey(GetOrReuseKeyFromPool()); if (!SetAddressBookName(PubKeyToAddress(vchDefaultKey), "")) return false; - CWalletDB(strWalletFile).WriteDefaultKey(keyUser.GetPubKey()); } CreateThread(ThreadFlushWalletDB, &strWalletFile); return true; } + +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) @@ -1006,8 +1129,19 @@ bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx) wtx = (*mi).second; return true; } - return false; } + return false; +} + +bool CWallet::SetDefaultKey(const std::vector &vchPubKey) +{ + if (fFileBacked) + { + if (!CWalletDB(strWalletFile).WriteDefaultKey(vchPubKey)) + return false; + } + vchDefaultKey = vchPubKey; + return true; } bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut) @@ -1018,14 +1152,16 @@ bool GetWalletFile(CWallet* pwallet, string &strWalletFileOut) return true; } -void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) +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 @@ -1036,18 +1172,36 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) 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); @@ -1076,11 +1230,13 @@ void CWallet::ReturnKey(int64 nIndex) printf("keypool return %"PRI64d"\n", nIndex); } -vector CWallet::GetKeyFromKeyPool() +vector CWallet::GetOrReuseKeyFromPool() { int64 nIndex = 0; CKeyPool keypool; ReserveKeyFromKeyPool(nIndex, keypool); + if(nIndex == -1) + return vchDefaultKey; KeepKey(nIndex); return keypool.vchPubKey; } @@ -1090,6 +1246,8 @@ int64 CWallet::GetOldestKeyPoolTime() int64 nIndex = 0; CKeyPool keypool; ReserveKeyFromKeyPool(nIndex, keypool); + if (nIndex == -1) + return GetTime(); ReturnKey(nIndex); return keypool.nTime; } @@ -1121,3 +1279,4 @@ void CReserveKey::ReturnKey() nIndex = -1; vchPubKey.clear(); } +