diff options
Diffstat (limited to 'src/wallet.cpp')
| -rw-r--r-- | src/wallet.cpp | 304 |
1 files changed, 202 insertions, 102 deletions
diff --git a/src/wallet.cpp b/src/wallet.cpp index 27aab08ec..a7a2992bb 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2012 The Bitcoin developers +// Copyright (c) 2009-2013 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -40,6 +40,13 @@ CPubKey CWallet::GenerateNewKey() SetMinVersion(FEATURE_COMPRPUBKEY); 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 pubkey; @@ -52,12 +59,15 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) if (!fFileBacked) return true; if (!IsCrypted()) { - return CWalletDB(strWalletFile).WriteKey(pubkey, secret.GetPrivKey()); + 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; @@ -66,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); @@ -136,7 +159,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, if (pMasterKey.second.nDeriveIterations < 25000) pMasterKey.second.nDeriveIterations = 25000; - printf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations); + LogPrintf("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; @@ -244,7 +267,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) if (kMasterKey.nDeriveIterations < 25000) kMasterKey.nDeriveIterations = 25000; - printf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations); + LogPrintf("Encrypting Wallet with an nDeriveIterations of %i\n", kMasterKey.nDeriveIterations); if (!crypter.SetKeyFromPassphrase(strWalletPassphrase, kMasterKey.vchSalt, kMasterKey.nDeriveIterations, kMasterKey.nDerivationMethod)) return false; @@ -345,10 +368,10 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx) { CWalletTx& wtx = (*mi).second; if (txin.prevout.n >= wtx.vout.size()) - printf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString().c_str()); + LogPrintf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString().c_str()); else 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()); + LogPrintf("WalletUpdateSpent found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); wtx.MarkSpent(txin.prevout.n); wtx.WriteToDisk(); NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED); @@ -423,9 +446,9 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) wtx.nTimeSmart = std::max(latestEntry, std::min(blocktime, latestNow)); } else - printf("AddToWallet() : found %s in block %s not in index\n", - wtxIn.GetHash().ToString().c_str(), - wtxIn.hashBlock.ToString().c_str()); + LogPrintf("AddToWallet() : found %s in block %s not in index\n", + wtxIn.GetHash().ToString().c_str(), + wtxIn.hashBlock.ToString().c_str()); } } @@ -453,31 +476,13 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) } //// debug print - printf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); + LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); // Write to disk 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) - { - 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); @@ -642,29 +647,42 @@ 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; } // Sent/received. BOOST_FOREACH(const CTxOut& txout, vout) { + bool fIsMine; + // Only need to handle txouts if AT LEAST one of these is true: + // 1) they debit from us (sent) + // 2) the output is to us (received) + if (nDebit > 0) + { + // Don't report 'change' txouts + if (pwallet->IsChange(txout)) + continue; + fIsMine = pwallet->IsMine(txout); + } + else if (!(fIsMine = pwallet->IsMine(txout))) + continue; + + // In either case, we need to get the destination address CTxDestination address; - vector<unsigned char> vchPubKey; if (!ExtractDestination(txout.scriptPubKey, address)) { - printf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", - this->GetHash().ToString().c_str()); + LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", + this->GetHash().ToString().c_str()); + address = CNoDestination(); } - // Don't report 'change' txouts - if (nDebit > 0 && pwallet->IsChange(txout)) - continue; - + // If we are debited by the transaction, add the output as a "sent" entry if (nDebit > 0) listSent.push_back(make_pair(address, txout.nValue)); - if (pwallet->IsMine(txout)) + // If we are receiving the output, add it as a "received" entry + if (fIsMine) listReceived.push_back(make_pair(address, txout.nValue)); } @@ -693,8 +711,8 @@ void CWalletTx::GetAccountAmounts(const string& strAccount, int64& nReceived, { if (pwallet->mapAddressBook.count(r.first)) { - map<CTxDestination, string>::const_iterator mi = pwallet->mapAddressBook.find(r.first); - if (mi != pwallet->mapAddressBook.end() && (*mi).second == strAccount) + map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(r.first); + if (mi != pwallet->mapAddressBook.end() && (*mi).second.name == strAccount) nReceived += r.second; } else if (strAccount.empty()) @@ -772,14 +790,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 = chainActive.Next(pindex); + 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->GetNextInMainChain(); + pindex = chainActive.Next(pindex); } } return ret; @@ -818,7 +843,7 @@ void CWallet::ReacceptWalletTransactions() } if (fUpdated) { - printf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); + LogPrintf("ReacceptWalletTransactions found spent coin %sbc %s\n", FormatMoney(wtx.GetCredit()).c_str(), wtx.GetHash().ToString().c_str()); wtx.MarkDirty(); wtx.WriteToDisk(); } @@ -827,13 +852,13 @@ 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) { // TODO: optimize this to scan just part of the block chain? - if (ScanForWalletTransactions(pindexGenesisBlock)) + if (ScanForWalletTransactions(chainActive.Genesis())) fRepeat = true; // Found missing transactions: re-do re-accept. } } @@ -851,7 +876,7 @@ void CWalletTx::RelayWalletTransaction() { if (GetDepthInMainChain() == 0) { uint256 hash = GetHash(); - printf("Relaying wtx %s\n", hash.ToString().c_str()); + LogPrintf("Relaying wtx %s\n", hash.ToString().c_str()); RelayTransaction((CTransaction)*this, hash); } } @@ -861,22 +886,20 @@ void CWallet::ResendWalletTransactions() { // Do this infrequently and randomly to avoid giving away // that these are our transactions. - static int64 nNextTime; - if (GetTime() < nNextTime) + if (GetTime() < nNextResend) return; - bool fFirst = (nNextTime == 0); - nNextTime = GetTime() + GetRand(30 * 60); + bool fFirst = (nNextResend == 0); + nNextResend = GetTime() + GetRand(30 * 60); if (fFirst) return; // Only do it if there's been a new block since last time - static int64 nLastTime; - if (nTimeBestReceived < nLastTime) + if (nTimeBestReceived < nLastResend) return; - nLastTime = GetTime(); + nLastResend = GetTime(); // Rebroadcast any of our txes that aren't in a block yet - printf("ResendWalletTransactions()\n"); + LogPrintf("ResendWalletTransactions()\n"); { LOCK(cs_wallet); // Sort them in chronological order @@ -932,7 +955,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(); } } @@ -964,7 +987,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()) @@ -1116,12 +1139,11 @@ bool CWallet::SelectCoinsMinConf(int64 nTargetValue, int nConfMine, int nConfThe nValueRet += vValue[i].first; } - //// debug print - printf("SelectCoins() best subset: "); + LogPrint("selectcoins", "SelectCoins() best subset: "); for (unsigned int i = 0; i < vValue.size(); i++) if (vfBest[i]) - printf("%s ", FormatMoney(vValue[i].first).c_str()); - printf("total %s\n", FormatMoney(nBest).c_str()); + LogPrint("selectcoins", "%s ", FormatMoney(vValue[i].first).c_str()); + LogPrint("selectcoins", "total %s\n", FormatMoney(nBest).c_str()); } return true; @@ -1165,7 +1187,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, LOCK2(cs_main, cs_wallet); { nFeeRet = nTransactionFee; - loop + while (true) { wtxNew.vin.clear(); wtxNew.vout.clear(); @@ -1177,7 +1199,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; @@ -1203,9 +1225,10 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, } int64 nChange = nValueIn - nValue - nFeeRet; - // if sub-cent change is required, the fee must be raised to at least nMinTxFee - // or until nChange becomes zero - // NOTE: this depends on the exact behaviour of GetMinFee + // The following if statement should be removed once enough miners + // have upgraded to the 0.9 GetMinFee() rules. Until then, this avoids + // creating free transactions that have change outputs less than + // CENT bitcoins. if (nFeeRet < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT) { int64 nMoveToFee = min(nChange, CTransaction::nMinTxFee - nFeeRet); @@ -1236,7 +1259,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(); @@ -1271,12 +1294,20 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64> >& vecSend, strFailReason = _("Transaction too large"); return false; } - dPriority /= nBytes; + unsigned int nTxSizeMod = nBytes; + // See miner.c's dPriority logic for the matching network-node side code. + BOOST_FOREACH(const CTxIn& txin, (*(CTransaction*)&wtxNew).vin) + { + unsigned int offset = 41U + min(110U, (unsigned int)txin.scriptSig.size()); + if (nTxSizeMod > offset) + nTxSizeMod -= offset; + } + dPriority /= nTxSizeMod; // 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); @@ -1307,7 +1338,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) { { LOCK2(cs_main, cs_wallet); - printf("CommitTransaction:\n%s", wtxNew.ToString().c_str()); + LogPrintf("CommitTransaction:\n%s", wtxNew.ToString().c_str()); { // 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 @@ -1340,10 +1371,10 @@ 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"); + LogPrintf("CommitTransaction() : Error: Transaction not valid"); return false; } wtxNew.RelayWalletTransaction(); @@ -1362,7 +1393,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, if (IsLocked()) { string strError = _("Error: Wallet locked, unable to create transaction!"); - printf("SendMoney() : %s", strError.c_str()); + LogPrintf("SendMoney() : %s", strError.c_str()); return strError; } string strError; @@ -1370,7 +1401,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew, { 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()); - printf("SendMoney() : %s\n", strError.c_str()); + LogPrintf("SendMoney() : %s\n", strError.c_str()); return strError; } @@ -1428,26 +1459,32 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) } -bool CWallet::SetAddressBookName(const CTxDestination& address, const string& strName) +bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose) { - std::map<CTxDestination, std::string>::iterator mi = mapAddressBook.find(address); - mapAddressBook[address] = strName; - NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address), (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED); + std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address); + mapAddressBook[address].name = strName; + if (!strPurpose.empty()) /* update purpose only if requested */ + mapAddressBook[address].purpose = strPurpose; + NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address), + mapAddressBook[address].purpose, + (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED); if (!fFileBacked) return false; + if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose)) + return false; return CWalletDB(strWalletFile).WriteName(CBitcoinAddress(address).ToString(), strName); } -bool CWallet::DelAddressBookName(const CTxDestination& address) +bool CWallet::DelAddressBook(const CTxDestination& address) { mapAddressBook.erase(address); - NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), CT_DELETED); + NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), "", CT_DELETED); if (!fFileBacked) return false; + CWalletDB(strWalletFile).ErasePurpose(CBitcoinAddress(address).ToString()); return CWalletDB(strWalletFile).EraseName(CBitcoinAddress(address).ToString()); } - void CWallet::PrintWallet(const CBlock& block) { { @@ -1455,10 +1492,10 @@ void CWallet::PrintWallet(const CBlock& block) if (mapWallet.count(block.vtx[0].GetHash())) { CWalletTx& wtx = mapWallet[block.vtx[0].GetHash()]; - printf(" mine: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); + LogPrintf(" mine: %d %d %"PRI64d"", wtx.GetDepthInMainChain(), wtx.GetBlocksToMaturity(), wtx.GetCredit()); } } - printf("\n"); + LogPrintf("\n"); } bool CWallet::GetTransaction(const uint256 &hashTx, CWalletTx& wtx) @@ -1517,12 +1554,12 @@ bool CWallet::NewKeyPool() walletdb.WritePool(nIndex, CKeyPool(GenerateNewKey())); setKeyPool.insert(nIndex); } - printf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys); + LogPrintf("CWallet::NewKeyPool wrote %"PRI64d" new keys\n", nKeys); } return true; } -bool CWallet::TopUpKeyPool() +bool CWallet::TopUpKeyPool(unsigned int kpSize) { { LOCK(cs_wallet); @@ -1533,7 +1570,12 @@ bool CWallet::TopUpKeyPool() CWalletDB walletdb(strWalletFile); // Top up key pool - unsigned int nTargetSize = max(GetArg("-keypool", 100), 0LL); + unsigned int nTargetSize; + if (kpSize > 0) + nTargetSize = kpSize; + else + nTargetSize = max(GetArg("-keypool", 100), 0LL); + while (setKeyPool.size() < (nTargetSize + 1)) { int64 nEnd = 1; @@ -1542,7 +1584,7 @@ bool CWallet::TopUpKeyPool() if (!walletdb.WritePool(nEnd, CKeyPool(GenerateNewKey()))) throw runtime_error("TopUpKeyPool() : writing generated key failed"); setKeyPool.insert(nEnd); - printf("keypool added key %"PRI64d", size=%"PRIszu"\n", nEnd, setKeyPool.size()); + LogPrintf("keypool added key %"PRI64d", size=%"PRIszu"\n", nEnd, setKeyPool.size()); } } return true; @@ -1571,7 +1613,7 @@ void CWallet::ReserveKeyFromKeyPool(int64& nIndex, CKeyPool& keypool) if (!HaveKey(keypool.vchPubKey.GetID())) throw runtime_error("ReserveKeyFromKeyPool() : unknown key in key pool"); assert(keypool.vchPubKey.IsValid()); - printf("keypool reserve %"PRI64d"\n", nIndex); + LogPrintf("keypool reserve %"PRI64d"\n", nIndex); } } @@ -1598,7 +1640,7 @@ void CWallet::KeepKey(int64 nIndex) CWalletDB walletdb(strWalletFile); walletdb.ErasePool(nIndex); } - printf("keypool keep %"PRI64d"\n", nIndex); + LogPrintf("keypool keep %"PRI64d"\n", nIndex); } void CWallet::ReturnKey(int64 nIndex) @@ -1608,10 +1650,10 @@ void CWallet::ReturnKey(int64 nIndex) LOCK(cs_wallet); setKeyPool.insert(nIndex); } - printf("keypool return %"PRI64d"\n", nIndex); + LogPrintf("keypool return %"PRI64d"\n", nIndex); } -bool CWallet::GetKeyFromPool(CPubKey& result, bool fAllowReuse) +bool CWallet::GetKeyFromPool(CPubKey& result) { int64 nIndex = 0; CKeyPool keypool; @@ -1620,11 +1662,6 @@ bool CWallet::GetKeyFromPool(CPubKey& result, bool fAllowReuse) ReserveKeyFromKeyPool(nIndex, keypool); if (nIndex == -1) { - if (fAllowReuse && vchDefaultKey.IsValid()) - { - result = vchDefaultKey; - return true; - } if (IsLocked()) return false; result = GenerateNewKey(); return true; @@ -1656,7 +1693,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) @@ -1778,6 +1815,19 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings() return ret; } +set<CTxDestination> CWallet::GetAccountAddresses(string strAccount) const +{ + set<CTxDestination> result; + BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook) + { + const CTxDestination& address = item.first; + const string& strName = item.second.name; + if (strName == strAccount) + result.insert(address); + } + return result; +} + bool CReserveKey::GetReservedKey(CPubKey& pubkey) { if (nIndex == -1) @@ -1788,7 +1838,7 @@ bool CReserveKey::GetReservedKey(CPubKey& pubkey) vchPubKey = keypool.vchPubKey; else { if (pwallet->vchDefaultKey.IsValid()) { - printf("CReserveKey::GetReservedKey(): Warning: Using default key instead of a new key, top up your keypool!"); + LogPrintf("CReserveKey::GetReservedKey(): Warning: Using default key instead of a new key, top up your keypool!"); vchPubKey = pwallet->vchDefaultKey; } else return false; @@ -1815,7 +1865,7 @@ void CReserveKey::ReturnKey() vchPubKey = CPubKey(); } -void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) +void CWallet::GetAllReserveKeys(set<CKeyID>& setAddress) const { setAddress.clear(); @@ -1877,3 +1927,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 = chainActive[std::max(0, chainActive.Height() - 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() && chainActive.Contains(blit->second)) { + // ... 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 +} |