aboutsummaryrefslogtreecommitdiff
path: root/src/wallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet.cpp')
-rw-r--r--src/wallet.cpp162
1 files changed, 121 insertions, 41 deletions
diff --git a/src/wallet.cpp b/src/wallet.cpp
index c70ea20e88..488787f967 100644
--- a/src/wallet.cpp
+++ b/src/wallet.cpp
@@ -32,30 +32,42 @@ CPubKey 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);
+ CKey secret;
+ secret.MakeNewKey(fCompressed);
// Compressed public keys were introduced in version 0.6.0
if (fCompressed)
SetMinVersion(FEATURE_COMPRPUBKEY);
- if (!AddKey(key))
+ CPubKey pubkey = secret.GetPubKey();
+
+ // Create new metadata
+ int64 nCreationTime = GetTime();
+ mapKeyMetadata[pubkey.GetID()] = CKeyMetadata(nCreationTime);
+ if (!nTimeFirstKey || nCreationTime < nTimeFirstKey)
+ nTimeFirstKey = nCreationTime;
+
+ if (!AddKeyPubKey(secret, pubkey))
throw std::runtime_error("CWallet::GenerateNewKey() : AddKey failed");
- return key.GetPubKey();
+ return pubkey;
}
-bool CWallet::AddKey(const CKey& key)
+bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
{
- if (!CCryptoKeyStore::AddKey(key))
+ if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
return false;
if (!fFileBacked)
return true;
- if (!IsCrypted())
- return CWalletDB(strWalletFile).WriteKey(key.GetPubKey(), key.GetPrivKey());
+ if (!IsCrypted()) {
+ return CWalletDB(strWalletFile).WriteKey(pubkey,
+ secret.GetPrivKey(),
+ mapKeyMetadata[pubkey.GetID()]);
+ }
return true;
}
-bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector<unsigned char> &vchCryptedSecret)
+bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
+ const vector<unsigned char> &vchCryptedSecret)
{
if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret))
return false;
@@ -64,13 +76,26 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const vector<unsigned char
{
LOCK(cs_wallet);
if (pwalletdbEncryption)
- return pwalletdbEncryption->WriteCryptedKey(vchPubKey, vchCryptedSecret);
+ return pwalletdbEncryption->WriteCryptedKey(vchPubKey,
+ vchCryptedSecret,
+ mapKeyMetadata[vchPubKey.GetID()]);
else
- return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey, vchCryptedSecret);
+ return CWalletDB(strWalletFile).WriteCryptedKey(vchPubKey,
+ vchCryptedSecret,
+ mapKeyMetadata[vchPubKey.GetID()]);
}
return false;
}
+bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
+{
+ if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
+ nTimeFirstKey = meta.nCreateTime;
+
+ mapKeyMetadata[pubkey.GetID()] = meta;
+ return true;
+}
+
bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret)
{
return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret);
@@ -87,9 +112,6 @@ bool CWallet::AddCScript(const CScript& redeemScript)
bool CWallet::Unlock(const SecureString& strWalletPassphrase)
{
- if (!IsLocked())
- return false;
-
CCrypter crypter;
CKeyingMaterial vMasterKey;
@@ -100,7 +122,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase)
if(!crypter.SetKeyFromPassphrase(strWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod))
return false;
if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, vMasterKey))
- return false;
+ continue; // try another master key
if (CCryptoKeyStore::Unlock(vMasterKey))
return true;
}
@@ -460,25 +482,26 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn)
if (fInsertedNew || fUpdated)
if (!wtx.WriteToDisk())
return false;
-#ifndef QT_GUI
- // If default receiving address gets used, replace it with a new one
- if (vchDefaultKey.IsValid()) {
- CScript scriptDefaultKey;
- scriptDefaultKey.SetDestination(vchDefaultKey.GetID());
- BOOST_FOREACH(const CTxOut& txout, wtx.vout)
- {
- if (txout.scriptPubKey == scriptDefaultKey)
+
+ if (!fHaveGUI) {
+ // If default receiving address gets used, replace it with a new one
+ if (vchDefaultKey.IsValid()) {
+ CScript scriptDefaultKey;
+ scriptDefaultKey.SetDestination(vchDefaultKey.GetID());
+ BOOST_FOREACH(const CTxOut& txout, wtx.vout)
{
- CPubKey newDefaultKey;
- if (GetKeyFromPool(newDefaultKey, false))
+ if (txout.scriptPubKey == scriptDefaultKey)
{
- SetDefaultKey(newDefaultKey);
- SetAddressBookName(vchDefaultKey.GetID(), "");
+ CPubKey newDefaultKey;
+ if (GetKeyFromPool(newDefaultKey, false))
+ {
+ SetDefaultKey(newDefaultKey);
+ SetAddressBookName(vchDefaultKey.GetID(), "");
+ }
}
}
}
}
-#endif
// since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
WalletUpdateSpent(wtx);
@@ -643,7 +666,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64> >& listReceived,
int64 nDebit = GetDebit();
if (nDebit > 0) // debit>0 means we signed/sent this transaction
{
- int64 nValueOut = GetValueOut();
+ int64 nValueOut = GetValueOut(*this);
nFee = nDebit - nValueOut;
}
@@ -773,14 +796,21 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
LOCK(cs_wallet);
while (pindex)
{
+ // no need to read and scan block, if block was created before
+ // our wallet birthday (as adjusted for block time variability)
+ if (nTimeFirstKey && (pindex->nTime < (nTimeFirstKey - 7200))) {
+ pindex = pindex->GetNextInMainChain();
+ continue;
+ }
+
CBlock block;
- block.ReadFromDisk(pindex);
+ ReadBlockFromDisk(block, pindex);
BOOST_FOREACH(CTransaction& tx, block.vtx)
{
if (AddToWalletIfInvolvingMe(tx.GetHash(), tx, &block, fUpdate))
ret++;
}
- pindex = pindex->pnext;
+ pindex = pindex->GetNextInMainChain();
}
}
return ret;
@@ -828,7 +858,7 @@ void CWallet::ReacceptWalletTransactions()
{
// Re-accept any txes of ours that aren't already in a block
if (!wtx.IsCoinBase())
- wtx.AcceptWalletTransaction(false);
+ wtx.AcceptWalletTransaction();
}
}
if (fMissing)
@@ -933,7 +963,7 @@ int64 CWallet::GetUnconfirmedBalance() const
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
{
const CWalletTx* pcoin = &(*it).second;
- if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed())
nTotal += pcoin->GetAvailableCredit();
}
}
@@ -965,7 +995,7 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed) const
{
const CWalletTx* pcoin = &(*it).second;
- if (!pcoin->IsFinal())
+ if (!IsFinalTx(*pcoin))
continue;
if (fOnlyConfirmed && !pcoin->IsConfirmed())
@@ -1178,7 +1208,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend,
BOOST_FOREACH (const PAIRTYPE(CScript, int64)& s, vecSend)
{
CTxOut txout(s.second, s.first);
- if (txout.IsDust())
+ if (txout.IsDust(CTransaction::nMinRelayTxFee))
{
strFailReason = _("Transaction amount too small");
return false;
@@ -1237,7 +1267,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend,
// Never create dust outputs; if we would, just
// add the dust to the fee.
- if (newTxOut.IsDust())
+ if (newTxOut.IsDust(CTransaction::nMinRelayTxFee))
{
nFeeRet += nChange;
reservekey.ReturnKey();
@@ -1276,8 +1306,8 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend,
// Check that enough fee is included
int64 nPayFee = nTransactionFee * (1 + (int64)nBytes / 1000);
- bool fAllowFree = CTransaction::AllowFree(dPriority);
- int64 nMinFee = wtxNew.GetMinFee(1, fAllowFree, GMF_SEND);
+ bool fAllowFree = AllowFree(dPriority);
+ int64 nMinFee = GetMinFee(wtxNew, fAllowFree, GMF_SEND);
if (nFeeRet < max(nPayFee, nMinFee))
{
nFeeRet = max(nPayFee, nMinFee);
@@ -1341,7 +1371,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey)
mapRequestCount[wtxNew.GetHash()] = 0;
// Broadcast
- if (!wtxNew.AcceptToMemoryPool(true, false))
+ if (!wtxNew.AcceptToMemoryPool(false))
{
// This must not fail. The transaction has already been signed and recorded.
printf("CommitTransaction() : Error: Transaction not valid");
@@ -1657,7 +1687,7 @@ std::map<CTxDestination, int64> CWallet::GetAddressBalances()
{
CWalletTx *pcoin = &walletEntry.second;
- if (!pcoin->IsFinal() || !pcoin->IsConfirmed())
+ if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed())
continue;
if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0)
@@ -1816,7 +1846,7 @@ void CReserveKey::ReturnKey()
vchPubKey = CPubKey();
}
-void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress)
+void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const
{
setAddress.clear();
@@ -1878,3 +1908,53 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
}
}
+void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64> &mapKeyBirth) const {
+ mapKeyBirth.clear();
+
+ // get birth times for keys with metadata
+ for (std::map<CKeyID, CKeyMetadata>::const_iterator it = mapKeyMetadata.begin(); it != mapKeyMetadata.end(); it++)
+ if (it->second.nCreateTime)
+ mapKeyBirth[it->first] = it->second.nCreateTime;
+
+ // map in which we'll infer heights of other keys
+ CBlockIndex *pindexMax = FindBlockByHeight(std::max(0, nBestHeight - 144)); // the tip can be reorganised; use a 144-block safety margin
+ std::map<CKeyID, CBlockIndex*> mapKeyFirstBlock;
+ std::set<CKeyID> setKeys;
+ GetKeys(setKeys);
+ BOOST_FOREACH(const CKeyID &keyid, setKeys) {
+ if (mapKeyBirth.count(keyid) == 0)
+ mapKeyFirstBlock[keyid] = pindexMax;
+ }
+ setKeys.clear();
+
+ // if there are no such keys, we're done
+ if (mapKeyFirstBlock.empty())
+ return;
+
+ // find first block that affects those keys, if there are any left
+ std::vector<CKeyID> vAffected;
+ for (std::map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) {
+ // iterate over all wallet transactions...
+ const CWalletTx &wtx = (*it).second;
+ std::map<uint256, CBlockIndex*>::const_iterator blit = mapBlockIndex.find(wtx.hashBlock);
+ if (blit != mapBlockIndex.end() && blit->second->IsInMainChain()) {
+ // ... which are already in a block
+ int nHeight = blit->second->nHeight;
+ BOOST_FOREACH(const CTxOut &txout, wtx.vout) {
+ // iterate over all their outputs
+ ::ExtractAffectedKeys(*this, txout.scriptPubKey, vAffected);
+ BOOST_FOREACH(const CKeyID &keyid, vAffected) {
+ // ... and all their affected keys
+ std::map<CKeyID, CBlockIndex*>::iterator rit = mapKeyFirstBlock.find(keyid);
+ if (rit != mapKeyFirstBlock.end() && nHeight < rit->second->nHeight)
+ rit->second = blit->second;
+ }
+ vAffected.clear();
+ }
+ }
+ }
+
+ // Extract block timestamps for those keys
+ for (std::map<CKeyID, CBlockIndex*>::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++)
+ mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off
+}