diff options
Diffstat (limited to 'src/wallet.cpp')
-rw-r--r-- | src/wallet.cpp | 162 |
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 +} |