#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)
// 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();
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
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;
{
// 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
if (IsCoinBase())
{
if (GetBlocksToMaturity() > 0)
- nGeneratedImmature = CTransaction::GetCredit();
+ nGeneratedImmature = pwallet->GetCredit(*this);
else
nGeneratedMature = GetCredit();
return;
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
{
}
// 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));
}
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())
{
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;
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))
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;
return ret;
}
-void ReacceptWalletTransactions()
+void CWallet::ReacceptWalletTransactions()
{
CTxDB txdb("r");
bool fRepeat = true;
{
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;
RelayWalletTransaction(txdb);
}
-void ResendWalletTransactions()
+void CWallet::ResendWalletTransactions()
{
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
//
-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();
}
-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;
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;
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)
{
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) ||
-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)
if (vecSend.empty() || nValue < 0)
return false;
+ wtxNew.pwallet = this;
+
CRITICAL_BLOCK(cs_main)
{
// txdb must be opened before the mapWallet lock
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();
// 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;
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
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));
}
// 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)
{
// 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();
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
// 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))
// 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)
-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)
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)
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());
void CReserveKey::KeepKey()
{
if (nIndex != -1)
- CWalletDB().KeepKey(nIndex);
+ pwallet->KeepKey(nIndex);
nIndex = -1;
vchPubKey.clear();
}
void CReserveKey::ReturnKey()
{
if (nIndex != -1)
- CWalletDB::ReturnKey(nIndex);
+ pwallet->ReturnKey(nIndex);
nIndex = -1;
vchPubKey.clear();
}
+