// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2011 The Bitcoin developers
+// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
-#include <stdint.h>
-
#include "headers.h"
#include "db.h"
#include "crypter.h"
// mapWallet
//
+std::vector<unsigned char> CWallet::GenerateNewKey()
+{
+ bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
+
+ RandAddSeedPerfmon();
+ CKey key;
+ key.MakeNewKey(fCompressed);
+
+ // Compressed public keys were introduced in version 0.6.0
+ if (fCompressed)
+ SetMinVersion(FEATURE_COMPRPUBKEY);
+
+ if (!AddKey(key))
+ throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
+ return key.GetPubKey();
+}
+
bool CWallet::AddKey(const CKey& key)
{
if (!CCryptoKeyStore::AddKey(key))
return false;
}
-bool CWallet::AddCScript(const uint160 &hash, const CScript& redeemScript)
+bool CWallet::AddCScript(const CScript& redeemScript)
{
- if (!CCryptoKeyStore::AddCScript(hash, redeemScript))
+ if (!CCryptoKeyStore::AddCScript(redeemScript))
return false;
if (!fFileBacked)
return true;
- return CWalletDB(strWalletFile).WriteCScript(hash, redeemScript);
+ return CWalletDB(strWalletFile).WriteCScript(Hash160(redeemScript), redeemScript);
}
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
return false;
if (CCryptoKeyStore::Unlock(vMasterKey))
{
- int64_t nStartTime = GetTimeMillis();
+ 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)));
)
};
+bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
+{
+ if (nWalletVersion >= nVersion)
+ return true;
+
+ // when doing an explicit upgrade, if we pass the max version permitted, upgrade all the way
+ if (fExplicit && nVersion > nWalletMaxVersion)
+ nVersion = FEATURE_LATEST;
+
+ nWalletVersion = nVersion;
+
+ if (nVersion > nWalletMaxVersion)
+ nWalletMaxVersion = nVersion;
+
+ if (fFileBacked)
+ {
+ CWalletDB* pwalletdb = pwalletdbIn ? pwalletdbIn : new CWalletDB(strWalletFile);
+ if (nWalletVersion >= 40000)
+ {
+ // Versions prior to 0.4.0 did not support the "minversion" record.
+ // Use a CCorruptAddress to make them crash instead.
+ CCorruptAddress corruptAddress;
+ pwalletdb->WriteSetting("addrIncoming", corruptAddress);
+ }
+ if (nWalletVersion > 40000)
+ pwalletdb->WriteMinVersion(nWalletVersion);
+ if (!pwalletdbIn)
+ delete pwalletdb;
+ }
+
+ return true;
+}
+
+bool CWallet::SetMaxVersion(int nVersion)
+{
+ // cannot downgrade below current version
+ if (nWalletVersion > nVersion)
+ return false;
+
+ nWalletMaxVersion = nVersion;
+
+ return true;
+}
+
bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
{
if (IsCrypted())
RAND_bytes(&kMasterKey.vchSalt[0], WALLET_CRYPTO_SALT_SIZE);
CCrypter crypter;
- int64_t nStartTime = GetTimeMillis();
+ int64 nStartTime = GetTimeMillis();
crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, 25000, kMasterKey.nDerivationMethod);
kMasterKey.nDeriveIterations = 2500000 / ((double)(GetTimeMillis() - nStartTime));
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.
}
+ // Encryption was introduced in version 0.4.0
+ SetMinVersion(FEATURE_WALLETCRYPT, pwalletdbEncryption, true);
+
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();
+ delete pwalletdbEncryption;
pwalletdbEncryption = NULL;
}
return false;
}
-int64_t CWallet::GetDebit(const CTxIn &txin) const
+int64 CWallet::GetDebit(const CTxIn &txin) const
{
CRITICAL_BLOCK(cs_wallet)
{
// a better way of identifying which outputs are 'the send' and which are
// 'the change' will need to be implemented (maybe extend CWalletTx to remember
// which output, if any, was change).
- if (ExtractAddress(txout.scriptPubKey, this, address))
+ if (ExtractAddress(txout.scriptPubKey, address) && HaveKey(address))
CRITICAL_BLOCK(cs_wallet)
if (!mapAddressBook.count(address))
return true;
return false;
}
-int64_t CWalletTx::GetTxTime() const
+int64 CWalletTx::GetTxTime() const
{
return nTimeReceived;
}
return nRequests;
}
-void CWalletTx::GetAmounts(int64_t& nGeneratedImmature, int64_t& nGeneratedMature, list<pair<CBitcoinAddress, int64_t> >& listReceived,
- list<pair<CBitcoinAddress, int64_t> >& listSent, int64_t& nFee, string& strSentAccount) const
+void CWalletTx::GetAmounts(int64& nGeneratedImmature, int64& nGeneratedMature, list<pair<CBitcoinAddress, int64> >& listReceived,
+ list<pair<CBitcoinAddress, int64> >& listSent, int64& nFee, string& strSentAccount) const
{
nGeneratedImmature = nGeneratedMature = nFee = 0;
listReceived.clear();
}
// Compute fee:
- int64_t nDebit = GetDebit();
+ int64 nDebit = GetDebit();
if (nDebit > 0) // debit>0 means we signed/sent this transaction
{
- int64_t nValueOut = GetValueOut();
+ int64 nValueOut = GetValueOut();
nFee = nDebit - nValueOut;
}
{
CBitcoinAddress address;
vector<unsigned char> vchPubKey;
- if (!ExtractAddress(txout.scriptPubKey, NULL, address))
+ if (!ExtractAddress(txout.scriptPubKey, address))
{
printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n",
this->GetHash().ToString().c_str());
}
-void CWalletTx::GetAccountAmounts(const string& strAccount, int64_t& nGenerated, int64_t& nReceived,
- int64_t& nSent, int64_t& nFee) const
+void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nGenerated, int64& nReceived,
+ int64& nSent, int64& nFee) const
{
nGenerated = nReceived = nSent = nFee = 0;
- int64_t allGeneratedImmature, allGeneratedMature, allFee;
+ int64 allGeneratedImmature, allGeneratedMature, allFee;
allGeneratedImmature = allGeneratedMature = allFee = 0;
string strSentAccount;
- list<pair<CBitcoinAddress, int64_t> > listReceived;
- list<pair<CBitcoinAddress, int64_t> > listSent;
+ list<pair<CBitcoinAddress, int64> > listReceived;
+ list<pair<CBitcoinAddress, int64> > listSent;
GetAmounts(allGeneratedImmature, allGeneratedMature, listReceived, listSent, allFee, strSentAccount);
if (strAccount == "")
nGenerated = allGeneratedMature;
if (strAccount == strSentAccount)
{
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& s, listSent)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& s, listSent)
nSent += s.second;
nFee = allFee;
}
CRITICAL_BLOCK(pwallet->cs_wallet)
{
- BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64_t)& r, listReceived)
+ BOOST_FOREACH(const PAIRTYPE(CBitcoinAddress,int64)& r, listReceived)
{
if (pwallet->mapAddressBook.count(r.first))
{
{
// Do this infrequently and randomly to avoid giving away
// that these are our transactions.
- static int64_t nNextTime;
+ static int64 nNextTime;
if (GetTime() < nNextTime)
return;
bool fFirst = (nNextTime == 0);
return;
// Only do it if there's been a new block since last time
- static int64_t nLastTime;
+ static int64 nLastTime;
if (nTimeBestReceived < nLastTime)
return;
nLastTime = GetTime();
CWalletTx& wtx = item.second;
// Don't rebroadcast until it's had plenty of time that
// it should have gotten in already by now.
- if (nTimeBestReceived - (int64_t)wtx.nTimeReceived > 5 * 60)
+ if (nTimeBestReceived - (int64)wtx.nTimeReceived > 5 * 60)
mapSorted.insert(make_pair(wtx.nTimeReceived, &wtx));
}
BOOST_FOREACH(PAIRTYPE(const unsigned int, CWalletTx*)& item, mapSorted)
//
-int64_t CWallet::GetBalance() const
+int64 CWallet::GetBalance() const
{
- int64_t nTotal = 0;
+ int64 nTotal = 0;
CRITICAL_BLOCK(cs_wallet)
{
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
return nTotal;
}
-int64_t CWallet::GetUnconfirmedBalance() const
+int64 CWallet::GetUnconfirmedBalance() const
{
- int64_t nTotal = 0;
+ int64 nTotal = 0;
CRITICAL_BLOCK(cs_wallet)
{
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
return nTotal;
}
-bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfTheirs, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const
+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_t, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
- coinLowestLarger.first = std::numeric_limits<int64_t>::max();
+ pair<int64, pair<const CWalletTx*,unsigned int> > coinLowestLarger;
+ coinLowestLarger.first = std::numeric_limits<int64>::max();
coinLowestLarger.second.first = NULL;
- vector<pair<int64_t, pair<const CWalletTx*,unsigned int> > > vValue;
- int64_t nTotalLower = 0;
+ vector<pair<int64, pair<const CWalletTx*,unsigned int> > > vValue;
+ int64 nTotalLower = 0;
CRITICAL_BLOCK(cs_wallet)
{
if (pcoin->IsSpent(i) || !IsMine(pcoin->vout[i]))
continue;
- int64_t n = pcoin->vout[i].nValue;
+ int64 n = pcoin->vout[i].nValue;
if (n <= 0)
continue;
- pair<int64_t,pair<const 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)
{
sort(vValue.rbegin(), vValue.rend());
vector<char> vfIncluded;
vector<char> vfBest(vValue.size(), true);
- int64_t nBest = nTotalLower;
+ int64 nBest = nTotalLower;
for (int nRep = 0; nRep < 1000 && nBest != nTargetValue; nRep++)
{
vfIncluded.assign(vValue.size(), false);
- int64_t nTotal = 0;
+ int64 nTotal = 0;
bool fReachedTarget = false;
for (int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
{
return true;
}
-bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const
+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 CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet)
+bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
{
- int64_t nValue = 0;
- BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend)
+ int64 nValue = 0;
+ BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
{
if (nValue < 0)
return false;
wtxNew.vout.clear();
wtxNew.fFromMe = true;
- int64_t nTotalValue = nValue + nFeeRet;
+ int64 nTotalValue = nValue + nFeeRet;
double dPriority = 0;
// vouts to the payees
- BOOST_FOREACH (const PAIRTYPE(CScript, int64_t)& s, vecSend)
+ BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
wtxNew.vout.push_back(CTxOut(s.second, s.first));
// Choose coins to use
set<pair<const CWalletTx*,unsigned int> > setCoins;
- int64_t nValueIn = 0;
+ int64 nValueIn = 0;
if (!SelectCoins(nTotalValue, setCoins, nValueIn))
return false;
BOOST_FOREACH(PAIRTYPE(const CWalletTx*, unsigned int) pcoin, setCoins)
{
- int64_t nCredit = pcoin.first->vout[pcoin.second].nValue;
+ int64 nCredit = pcoin.first->vout[pcoin.second].nValue;
dPriority += (double)nCredit * pcoin.first->GetDepthInMainChain();
}
- int64_t nChange = nValueIn - nValue - nFeeRet;
+ int64 nChange = nValueIn - nValue - nFeeRet;
// if sub-cent change is required, the fee must be raised to at least MIN_TX_FEE
// or until nChange becomes zero
// NOTE: this depends on the exact behaviour of GetMinFee
if (nFeeRet < MIN_TX_FEE && nChange > 0 && nChange < CENT)
{
- int64_t nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
+ int64 nMoveToFee = min(nChange, MIN_TX_FEE - nFeeRet);
nChange -= nMoveToFee;
nFeeRet += nMoveToFee;
}
dPriority /= nBytes;
// Check that enough fee is included
- int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000);
+ int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
bool fAllowFree = CTransaction::AllowFree(dPriority);
- int64_t nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND);
+ int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND);
if (nFeeRet < max(nPayFee, nMinFee))
{
nFeeRet = max(nPayFee, nMinFee);
return true;
}
-bool CWallet::CreateTransaction(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64_t& nFeeRet)
+bool CWallet::CreateTransaction(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, CReserveKey& reservekey, int64& nFeeRet)
{
- vector< pair<CScript, int64_t> > vecSend;
+ vector< pair<CScript, int64> > vecSend;
vecSend.push_back(make_pair(scriptPubKey, nValue));
return CreateTransaction(vecSend, wtxNew, reservekey, nFeeRet);
}
-string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, bool fAskFee)
+string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
{
CReserveKey reservekey(this);
- int64_t nFeeRequired;
+ int64 nFeeRequired;
if (IsLocked())
{
-string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64_t nValue, CWalletTx& wtxNew, bool fAskFee)
+string CWallet::SendMoneyToBitcoinAddress(const CBitcoinAddress& address, int64 nValue, CWalletTx& wtxNew, bool fAskFee)
{
// Check amount
if (nValue <= 0)
return nLoadWalletRet;
fFirstRunRet = vchDefaultKey.empty();
- if (!HaveKey(Hash160(vchDefaultKey)))
- {
- // Create new keyUser and set as default key
- RandAddSeedPerfmon();
-
- std::vector<unsigned char> newDefaultKey;
- if (!GetKeyFromPool(newDefaultKey, false))
- return DB_LOAD_FAIL;
- SetDefaultKey(newDefaultKey);
- if (!SetAddressBookName(CBitcoinAddress(vchDefaultKey), ""))
- return DB_LOAD_FAIL;
- }
-
CreateThread(ThreadFlushWalletDB, &strWalletFile);
return DB_LOAD_OK;
}
CRITICAL_BLOCK(cs_wallet)
{
CWalletDB walletdb(strWalletFile);
- BOOST_FOREACH(int64_t nIndex, setKeyPool)
+ BOOST_FOREACH(int64 nIndex, setKeyPool)
walletdb.ErasePool(nIndex);
setKeyPool.clear();
if (IsLocked())
return false;
- int64_t nKeys = max(GetArg("-keypool", 100), (int64_t)0);
+ int64 nKeys = max(GetArg("-keypool", 100), (int64)0);
for (int i = 0; i < nKeys; i++)
{
- int64_t nIndex = i+1;
+ int64 nIndex = i+1;
walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey()));
setKeyPool.insert(nIndex);
}
CWalletDB walletdb(strWalletFile);
// Top up key pool
- int64_t nTargetSize = max(GetArg("-keypool", 100), (int64_t)0);
+ int64 nTargetSize = max(GetArg("-keypool", 100), (int64)0);
while (setKeyPool.size() < nTargetSize+1)
{
- int64_t nEnd = 1;
+ int64 nEnd = 1;
if (!setKeyPool.empty())
nEnd = *(--setKeyPool.end()) + 1;
if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey())))
return true;
}
-void CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool)
+void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool)
{
nIndex = -1;
keypool.vchPubKey.clear();
}
}
-int64_t CWallet::AddReserveKey(const CKeyPool& keypool)
+int64 CWallet::AddReserveKey(const CKeyPool& keypool)
{
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_wallet)
{
CWalletDB walletdb(strWalletFile);
- int64_t nIndex = 1 + *(--setKeyPool.end());
+ int64 nIndex = 1 + *(--setKeyPool.end());
if (!walletdb.WritePool(nIndex, keypool))
throw runtime_error("AddReserveKey() : writing added key failed");
setKeyPool.insert(nIndex);
return -1;
}
-void CWallet::KeepKey(int64_t nIndex)
+void CWallet::KeepKey(int64 nIndex)
{
// Remove from key pool
if (fFileBacked)
printf("keypool keep %"PRI64d"\n", nIndex);
}
-void CWallet::ReturnKey(int64_t nIndex)
+void CWallet::ReturnKey(int64 nIndex)
{
// Return to key pool
CRITICAL_BLOCK(cs_wallet)
bool CWallet::GetKeyFromPool(vector<unsigned char>& result, bool fAllowReuse)
{
- int64_t nIndex = 0;
+ int64 nIndex = 0;
CKeyPool keypool;
CRITICAL_BLOCK(cs_wallet)
{
return true;
}
-int64_t CWallet::GetOldestKeyPoolTime()
+int64 CWallet::GetOldestKeyPoolTime()
{
- int64_t nIndex = 0;
+ int64 nIndex = 0;
CKeyPool keypool;
ReserveKeyFromKeyPool(nIndex, keypool);
if (nIndex == -1)
CRITICAL_BLOCK(cs_main)
CRITICAL_BLOCK(cs_wallet)
- BOOST_FOREACH(const int64_t& id, setKeyPool)
+ BOOST_FOREACH(const int64& id, setKeyPool)
{
CKeyPool keypool;
if (!walletdb.ReadPool(id, keypool))