diff --git a/src/wallet.cpp b/src/wallet.cpp index 1087db63..dcedf86f 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1846,7 +1846,7 @@ void CReserveKey::ReturnKey() vchPubKey = CPubKey(); } -void CWallet::GetAllReserveKeys(set& setAddress) +void CWallet::GetAllReserveKeys(set& setAddress) const { setAddress.clear(); @@ -1908,3 +1908,53 @@ void CWallet::ListLockedCoins(std::vector& vOutpts) } } +void CWallet::GetKeyBirthTimes(std::map &mapKeyBirth) const { + mapKeyBirth.clear(); + + // get birth times for keys with metadata + for (std::map::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 mapKeyFirstBlock; + std::set 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 vAffected; + for (std::map::const_iterator it = mapWallet.begin(); it != mapWallet.end(); it++) { + // iterate over all wallet transactions... + const CWalletTx &wtx = (*it).second; + std::map::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::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::const_iterator it = mapKeyFirstBlock.begin(); it != mapKeyFirstBlock.end(); it++) + mapKeyBirth[it->first] = it->second->nTime - 7200; // block times can be 2h off +} diff --git a/src/wallet.h b/src/wallet.h index 48bd5119..36b3608f 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -159,6 +159,8 @@ public: bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase); + void GetKeyBirthTimes(std::map &mapKeyBirth) const; + /** Increment the next transaction order id @return next transaction order id */ @@ -200,7 +202,7 @@ public: void ReturnKey(int64 nIndex); bool GetKeyFromPool(CPubKey &key, bool fAllowReuse=true); int64 GetOldestKeyPoolTime(); - void GetAllReserveKeys(std::set& setAddress); + void GetAllReserveKeys(std::set& setAddress) const; std::set< std::set > GetAddressGroupings(); std::map GetAddressBalances(); diff --git a/src/walletdb.cpp b/src/walletdb.cpp index bf23357f..702e219a 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -365,7 +365,16 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, { int64 nIndex; ssKey >> nIndex; + CKeyPool keypool; + ssValue >> keypool; pwallet->setKeyPool.insert(nIndex); + + // If no metadata exists yet, create a default with the pool key's + // creation time. Note that this may be overwritten by actually + // stored metadata for that key later, which is fine. + CKeyID keyid = keypool.vchPubKey.GetID(); + if (pwallet->mapKeyMetadata.count(keyid) == 0) + pwallet->mapKeyMetadata[keyid] = CKeyMetadata(keypool.nTime); } else if (strType == "version") {