diff options
Diffstat (limited to 'src/wallet.cpp')
| -rw-r--r-- | src/wallet.cpp | 298 |
1 files changed, 237 insertions, 61 deletions
diff --git a/src/wallet.cpp b/src/wallet.cpp index db957cbd0..211909859 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2013 The Bitcoin developers +// Copyright (c) 2009-2014 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -9,13 +9,14 @@ #include "coincontrol.h" #include "net.h" -#include <inttypes.h> - #include <boost/algorithm/string/replace.hpp> #include <openssl/rand.h> using namespace std; +// Settings +int64_t nTransactionFee = 0; +bool bSpendZeroConfChange = true; ////////////////////////////////////////////////////////////////////////////// // @@ -33,6 +34,7 @@ struct CompareValueOnly CPubKey CWallet::GenerateNewKey() { + AssertLockHeld(cs_wallet); // mapKeyMetadata bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets RandAddSeedPerfmon(); @@ -58,6 +60,7 @@ CPubKey CWallet::GenerateNewKey() bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) { + AssertLockHeld(cs_wallet); // mapKeyMetadata if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) return false; if (!fFileBacked) @@ -93,6 +96,7 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta) { + AssertLockHeld(cs_wallet); // mapKeyMetadata if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey)) nTimeFirstKey = meta.nCreateTime; @@ -186,20 +190,9 @@ void CWallet::SetBestChain(const CBlockLocator& loc) walletdb.WriteBestBlock(loc); } -// This class implements an addrIncoming entry that causes pre-0.4 -// clients to crash on startup if reading a private-key-encrypted wallet. -class CCorruptAddress -{ -public: - IMPLEMENT_SERIALIZE - ( - if (nType & SER_DISK) - READWRITE(nVersion); - ) -}; - bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit) { + AssertLockHeld(cs_wallet); // nWalletVersion if (nWalletVersion >= nVersion) return true; @@ -215,13 +208,6 @@ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, 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) @@ -233,6 +219,7 @@ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool CWallet::SetMaxVersion(int nVersion) { + AssertLockHeld(cs_wallet); // nWalletVersion, nWalletMaxVersion // cannot downgrade below current version if (nWalletVersion > nVersion) return false; @@ -242,6 +229,82 @@ bool CWallet::SetMaxVersion(int nVersion) return true; } +set<uint256> CWallet::GetConflicts(const uint256& txid) const +{ + set<uint256> result; + AssertLockHeld(cs_wallet); + + std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(txid); + if (it == mapWallet.end()) + return result; + const CWalletTx& wtx = it->second; + + std::pair<TxConflicts::const_iterator, TxConflicts::const_iterator> range; + + BOOST_FOREACH(const CTxIn& txin, wtx.vin) + { + range = mapTxConflicts.equal_range(txin.prevout); + for (TxConflicts::const_iterator it = range.first; it != range.second; ++it) + result.insert(it->second); + } + return result; +} + +void CWallet::SyncMetaData(pair<TxConflicts::iterator, TxConflicts::iterator> range) +{ + // We want all the wallet transactions in range to have the same metadata as + // the oldest (smallest nOrderPos). + // So: find smallest nOrderPos: + + int nMinOrderPos = std::numeric_limits<int>::max(); + const CWalletTx* copyFrom = NULL; + for (TxConflicts::iterator it = range.first; it != range.second; ++it) + { + const uint256& hash = it->second; + int n = mapWallet[hash].nOrderPos; + if (n < nMinOrderPos) + { + nMinOrderPos = n; + copyFrom = &mapWallet[hash]; + } + } + // Now copy data from copyFrom to rest: + for (TxConflicts::iterator it = range.first; it != range.second; ++it) + { + const uint256& hash = it->second; + CWalletTx* copyTo = &mapWallet[hash]; + if (copyFrom == copyTo) continue; + copyTo->mapValue = copyFrom->mapValue; + copyTo->vOrderForm = copyFrom->vOrderForm; + // fTimeReceivedIsTxTime not copied on purpose + // nTimeReceived not copied on purpose + copyTo->nTimeSmart = copyFrom->nTimeSmart; + copyTo->fFromMe = copyFrom->fFromMe; + copyTo->strFromAccount = copyFrom->strFromAccount; + // vfSpent not copied on purpose + // nOrderPos not copied on purpose + // cached members not copied on purpose + } +} + +void CWallet::AddToConflicts(const uint256& wtxhash) +{ + assert(mapWallet.count(wtxhash)); + CWalletTx& thisTx = mapWallet[wtxhash]; + if (thisTx.IsCoinBase()) + return; + + BOOST_FOREACH(const CTxIn& txin, thisTx.vin) + { + mapTxConflicts.insert(make_pair(txin.prevout, wtxhash)); + + pair<TxConflicts::iterator, TxConflicts::iterator> range; + range = mapTxConflicts.equal_range(txin.prevout); + if (range.first != range.second) + SyncMetaData(range); + } +} + bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) { if (IsCrypted()) @@ -325,6 +388,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) { + AssertLockHeld(cs_wallet); // nOrderPosNext int64_t nRet = nOrderPosNext++; if (pwalletdb) { pwalletdb->WriteOrderPosNext(nOrderPosNext); @@ -336,6 +400,7 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount) { + AssertLockHeld(cs_wallet); // mapWallet CWalletDB walletdb(strWalletFile); // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap. @@ -372,10 +437,10 @@ void CWallet::WalletUpdateSpent(const CTransaction &tx) { CWalletTx& wtx = (*mi).second; if (txin.prevout.n >= wtx.vout.size()) - LogPrintf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString().c_str()); + LogPrintf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString()); else if (!wtx.IsSpent(txin.prevout.n) && IsMine(wtx.vout[txin.prevout.n])) { - LogPrintf("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()), wtx.GetHash().ToString()); wtx.MarkSpent(txin.prevout.n); wtx.WriteToDisk(); NotifyTransactionChanged(this, txin.prevout.hash, CT_UPDATED); @@ -394,9 +459,16 @@ void CWallet::MarkDirty() } } -bool CWallet::AddToWallet(const CWalletTx& wtxIn) +bool CWallet::AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet) { uint256 hash = wtxIn.GetHash(); + + if (fFromLoadWallet) + { + mapWallet[hash] = wtxIn; + AddToConflicts(hash); + } + else { LOCK(cs_wallet); // Inserts only if not already there, returns tx inserted or tx found @@ -451,9 +523,10 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) } else LogPrintf("AddToWallet() : found %s in block %s not in index\n", - wtxIn.GetHash().ToString().c_str(), - wtxIn.hashBlock.ToString().c_str()); + wtxIn.GetHash().ToString(), + wtxIn.hashBlock.ToString()); } + AddToConflicts(hash); } bool fUpdated = false; @@ -480,7 +553,7 @@ bool CWallet::AddToWallet(const CWalletTx& wtxIn) } //// debug print - LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString().c_str(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); + LogPrintf("AddToWallet %s %s%s\n", wtxIn.GetHash().ToString(), (fInsertedNew ? "new" : ""), (fUpdated ? "update" : "")); // Write to disk if (fInsertedNew || fUpdated) @@ -655,7 +728,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived, int64_t nDebit = GetDebit(); if (nDebit > 0) // debit>0 means we signed/sent this transaction { - int64_t nValueOut = GetValueOut(*this); + int64_t nValueOut = GetValueOut(); nFee = nDebit - nValueOut; } @@ -681,7 +754,7 @@ void CWalletTx::GetAmounts(list<pair<CTxDestination, int64_t> >& listReceived, if (!ExtractDestination(txout.scriptPubKey, address)) { LogPrintf("CWalletTx::GetAmounts: Unknown transaction type found, txid %s\n", - this->GetHash().ToString().c_str()); + this->GetHash().ToString()); address = CNoDestination(); } @@ -765,6 +838,10 @@ void CWalletTx::AddSupportingTransactions() { tx = *mapWalletPrev[hash]; } + else + { + continue; + } int nDepth = tx.SetMerkleBranch(); vtxPrev.push_back(tx); @@ -870,7 +947,7 @@ void CWallet::ReacceptWalletTransactions() } if (fUpdated) { - LogPrintf("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()), wtx.GetHash().ToString()); wtx.MarkDirty(); wtx.WriteToDisk(); } @@ -895,7 +972,10 @@ void CWalletTx::RelayWalletTransaction() { BOOST_FOREACH(const CMerkleTx& tx, vtxPrev) { - if (!tx.IsCoinBase()) + // Important: versions of bitcoin before 0.8.6 had a bug that inserted + // empty transactions into the vtxPrev, which will cause the node to be + // banned when retransmitted, hence the check for !tx.vin.empty() + if (!tx.IsCoinBase() && !tx.vin.empty()) if (tx.GetDepthInMainChain() == 0) RelayTransaction((CTransaction)tx, tx.GetHash()); } @@ -903,12 +983,24 @@ void CWalletTx::RelayWalletTransaction() { if (GetDepthInMainChain() == 0) { uint256 hash = GetHash(); - LogPrintf("Relaying wtx %s\n", hash.ToString().c_str()); + LogPrintf("Relaying wtx %s\n", hash.ToString()); RelayTransaction((CTransaction)*this, hash); } } } +set<uint256> CWalletTx::GetConflicts() const +{ + set<uint256> result; + if (pwallet != NULL) + { + uint256 myHash = GetHash(); + result = pwallet->GetConflicts(myHash); + result.erase(myHash); + } + return result; +} + void CWallet::ResendWalletTransactions() { // Do this infrequently and randomly to avoid giving away @@ -966,7 +1058,7 @@ int64_t CWallet::GetBalance() const for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; - if (pcoin->IsConfirmed()) + if (pcoin->IsTrusted()) nTotal += pcoin->GetAvailableCredit(); } } @@ -982,7 +1074,7 @@ int64_t CWallet::GetUnconfirmedBalance() const for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it) { const CWalletTx* pcoin = &(*it).second; - if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed()) + if (!IsFinalTx(*pcoin) || (!pcoin->IsTrusted() && pcoin->GetDepthInMainChain() == 0)) nTotal += pcoin->GetAvailableCredit(); } } @@ -1017,17 +1109,21 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const if (!IsFinalTx(*pcoin)) continue; - if (fOnlyConfirmed && !pcoin->IsConfirmed()) + if (fOnlyConfirmed && !pcoin->IsTrusted()) continue; if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) continue; + int nDepth = pcoin->GetDepthInMainChain(); + if (nDepth < 0) + continue; + for (unsigned int i = 0; i < pcoin->vout.size(); i++) { if (!(pcoin->IsSpent(i)) && IsMine(pcoin->vout[i]) && !IsLockedCoin((*it).first, i) && pcoin->vout[i].nValue > 0 && (!coinControl || !coinControl->HasSelected() || coinControl->IsSelected((*it).first, i))) - vCoins.push_back(COutput(pcoin, i, pcoin->GetDepthInMainChain())); + vCoins.push_back(COutput(pcoin, i, nDepth)); } } } @@ -1170,8 +1266,8 @@ bool CWallet::SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfT LogPrint("selectcoins", "SelectCoins() best subset: "); for (unsigned int i = 0; i < vValue.size(); i++) if (vfBest[i]) - LogPrint("selectcoins", "%s ", FormatMoney(vValue[i].first).c_str()); - LogPrint("selectcoins", "total %s\n", FormatMoney(nBest).c_str()); + LogPrint("selectcoins", "%s ", FormatMoney(vValue[i].first)); + LogPrint("selectcoins", "total %s\n", FormatMoney(nBest)); } return true; @@ -1195,7 +1291,7 @@ bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsign return (SelectCoinsMinConf(nTargetValue, 1, 6, vCoins, setCoinsRet, nValueRet) || SelectCoinsMinConf(nTargetValue, 1, 1, vCoins, setCoinsRet, nValueRet) || - SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet)); + (bSpendZeroConfChange && SelectCoinsMinConf(nTargetValue, 0, 1, vCoins, setCoinsRet, nValueRet))); } @@ -1298,7 +1394,9 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, // Reserve a new key pair from key pool CPubKey vchPubKey; - assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked + bool ret; + ret = reservekey.GetReservedKey(vchPubKey); + assert(ret); // should never fail, as we just unlocked scriptChange.SetDestination(vchPubKey.GetID()); } @@ -1342,15 +1440,7 @@ bool CWallet::CreateTransaction(const vector<pair<CScript, int64_t> >& vecSend, strFailReason = _("Transaction too large"); return false; } - 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; + dPriority = wtxNew.ComputePriority(dPriority, nBytes); // Check that enough fee is included int64_t nPayFee = nTransactionFee * (1 + (int64_t)nBytes / 1000); @@ -1386,7 +1476,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) { { LOCK2(cs_main, cs_wallet); - LogPrintf("CommitTransaction:\n%s", wtxNew.ToString().c_str()); + LogPrintf("CommitTransaction:\n%s", wtxNew.ToString()); { // 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 @@ -1433,7 +1523,7 @@ bool CWallet::CommitTransaction(CWalletTx& wtxNew, CReserveKey& reservekey) -string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, bool fAskFee) +string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew) { CReserveKey reservekey(this); int64_t nFeeRequired; @@ -1441,21 +1531,18 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe if (IsLocked()) { string strError = _("Error: Wallet locked, unable to create transaction!"); - LogPrintf("SendMoney() : %s", strError.c_str()); + LogPrintf("SendMoney() : %s", strError); return strError; } string strError; if (!CreateTransaction(scriptPubKey, nValue, wtxNew, reservekey, nFeeRequired, strError)) { 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()); - LogPrintf("SendMoney() : %s\n", strError.c_str()); + 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)); + LogPrintf("SendMoney() : %s\n", strError); return strError; } - if (fAskFee && !uiInterface.ThreadSafeAskFee(nFeeRequired)) - return "ABORTED"; - if (!CommitTransaction(wtxNew, reservekey)) return _("Error: The transaction was rejected! This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."); @@ -1464,7 +1551,7 @@ string CWallet::SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNe -string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nValue, CWalletTx& wtxNew, bool fAskFee) +string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nValue, CWalletTx& wtxNew) { // Check amount if (nValue <= 0) @@ -1476,7 +1563,7 @@ string CWallet::SendMoneyToDestination(const CTxDestination& address, int64_t nV CScript scriptPubKey; scriptPubKey.SetDestination(address); - return SendMoney(scriptPubKey, nValue, wtxNew, fAskFee); + return SendMoney(scriptPubKey, nValue, wtxNew); } @@ -1492,6 +1579,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (CDB::Rewrite(strWalletFile, "\x04pool")) { + LOCK(cs_wallet); setKeyPool.clear(); // Note: can't top-up keypool here, because wallet is locked. // User will be prompted to unlock wallet the next operation @@ -1507,8 +1595,33 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) } +DBErrors CWallet::ZapWalletTx() +{ + if (!fFileBacked) + return DB_LOAD_OK; + DBErrors nZapWalletTxRet = CWalletDB(strWalletFile,"cr+").ZapWalletTx(this); + if (nZapWalletTxRet == DB_NEED_REWRITE) + { + if (CDB::Rewrite(strWalletFile, "\x04pool")) + { + LOCK(cs_wallet); + setKeyPool.clear(); + // Note: can't top-up keypool here, because wallet is locked. + // User will be prompted to unlock wallet the next operation + // the requires a new key. + } + } + + if (nZapWalletTxRet != DB_LOAD_OK) + return nZapWalletTxRet; + + return DB_LOAD_OK; +} + + bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose) { + AssertLockHeld(cs_wallet); // mapAddressBook std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address); mapAddressBook[address].name = strName; if (!strPurpose.empty()) /* update purpose only if requested */ @@ -1525,6 +1638,19 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const string& strNam bool CWallet::DelAddressBook(const CTxDestination& address) { + + AssertLockHeld(cs_wallet); // mapAddressBook + + if(fFileBacked) + { + // Delete destdata tuples associated with address + std::string strAddress = CBitcoinAddress(address).ToString(); + BOOST_FOREACH(const PAIRTYPE(string, string) &item, mapAddressBook[address].destdata) + { + CWalletDB(strWalletFile).EraseDestData(strAddress, item.first); + } + } + mapAddressBook.erase(address); NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), "", CT_DELETED); if (!fFileBacked) @@ -1706,7 +1832,7 @@ std::map<CTxDestination, int64_t> CWallet::GetAddressBalances() { CWalletTx *pcoin = &walletEntry.second; - if (!IsFinalTx(*pcoin) || !pcoin->IsConfirmed()) + if (!IsFinalTx(*pcoin) || !pcoin->IsTrusted()) continue; if (pcoin->IsCoinBase() && pcoin->GetBlocksToMaturity() > 0) @@ -1738,6 +1864,7 @@ std::map<CTxDestination, int64_t> CWallet::GetAddressBalances() set< set<CTxDestination> > CWallet::GetAddressGroupings() { + AssertLockHeld(cs_wallet); // mapWallet set< set<CTxDestination> > groupings; set<CTxDestination> grouping; @@ -1830,6 +1957,7 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings() set<CTxDestination> CWallet::GetAccountAddresses(string strAccount) const { + AssertLockHeld(cs_wallet); // mapWallet set<CTxDestination> result; BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook) { @@ -1911,21 +2039,25 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx) void CWallet::LockCoin(COutPoint& output) { + AssertLockHeld(cs_wallet); // setLockedCoins setLockedCoins.insert(output); } void CWallet::UnlockCoin(COutPoint& output) { + AssertLockHeld(cs_wallet); // setLockedCoins setLockedCoins.erase(output); } void CWallet::UnlockAllCoins() { + AssertLockHeld(cs_wallet); // setLockedCoins setLockedCoins.clear(); } bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const { + AssertLockHeld(cs_wallet); // setLockedCoins COutPoint outpt(hash, n); return (setLockedCoins.count(outpt) > 0); @@ -1933,6 +2065,7 @@ bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) { + AssertLockHeld(cs_wallet); // setLockedCoins for (std::set<COutPoint>::iterator it = setLockedCoins.begin(); it != setLockedCoins.end(); it++) { COutPoint outpt = (*it); @@ -1941,6 +2074,7 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) } void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const { + AssertLockHeld(cs_wallet); // mapKeyMetadata mapKeyBirth.clear(); // get birth times for keys with metadata @@ -1990,3 +2124,45 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const { 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 } + +bool CWallet::AddDestData(const CTxDestination &dest, const std::string &key, const std::string &value) +{ + if (boost::get<CNoDestination>(&dest)) + return false; + + mapAddressBook[dest].destdata.insert(std::make_pair(key, value)); + if (!fFileBacked) + return true; + return CWalletDB(strWalletFile).WriteDestData(CBitcoinAddress(dest).ToString(), key, value); +} + +bool CWallet::EraseDestData(const CTxDestination &dest, const std::string &key) +{ + if (!mapAddressBook[dest].destdata.erase(key)) + return false; + if (!fFileBacked) + return true; + return CWalletDB(strWalletFile).EraseDestData(CBitcoinAddress(dest).ToString(), key); +} + +bool CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value) +{ + mapAddressBook[dest].destdata.insert(std::make_pair(key, value)); + return true; +} + +bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const +{ + std::map<CTxDestination, CAddressBookData>::const_iterator i = mapAddressBook.find(dest); + if(i != mapAddressBook.end()) + { + CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key); + if(j != i->second.destdata.end()) + { + if(value) + *value = j->second; + return true; + } + } + return false; +} |