Browse Source

Merge pull request #3401

012ca1c LoadWallet: acquire cs_wallet mutex before clearing setKeyPool (Wladimir J. van der Laan)
9569168 Document cs_wallet lock and add AssertLockHeld (Wladimir J. van der Laan)
19a5676 Use mutex pointer instead of name for AssertLockHeld (Wladimir J. van der Laan)
0.10
Wladimir J. van der Laan 11 years ago
parent
commit
7aedb91476
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 2
      src/main.cpp
  2. 6
      src/sync.cpp
  3. 5
      src/sync.h
  4. 18
      src/wallet.cpp
  5. 13
      src/wallet.h

2
src/main.cpp

@ -2235,7 +2235,7 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
{ {
AssertLockHeld("cs_main"); AssertLockHeld(cs_main);
// Check for duplicate // Check for duplicate
uint256 hash = pblock->GetHash(); uint256 hash = pblock->GetHash();

6
src/sync.cpp

@ -136,11 +136,11 @@ std::string LocksHeld()
return result; return result;
} }
void AssertLockHeld(std::string strName) void AssertLockHeldInternal(const char *pszName, const char* pszFile, int nLine, void *cs)
{ {
BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack) BOOST_FOREACH(const PAIRTYPE(void*, CLockLocation)&i, *lockstack)
if (i.second.MutexName() == strName) return; if (i.first == cs) return;
LogPrintf("Lock %s not held; locks held:\n%s", strName.c_str(), LocksHeld().c_str()); LogPrintf("Lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
assert(0); assert(0);
} }

5
src/sync.h

@ -88,12 +88,13 @@ typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false); void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
void LeaveCritical(); void LeaveCritical();
std::string LocksHeld(); std::string LocksHeld();
void AssertLockHeld(std::string strName); void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void *cs);
#else #else
void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {} void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
void static inline LeaveCritical() {} void static inline LeaveCritical() {}
void static inline AssertLockHeld(std::string) {} void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void *cs) {}
#endif #endif
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
#ifdef DEBUG_LOCKCONTENTION #ifdef DEBUG_LOCKCONTENTION
void PrintLockContention(const char* pszName, const char* pszFile, int nLine); void PrintLockContention(const char* pszName, const char* pszFile, int nLine);

18
src/wallet.cpp

@ -35,6 +35,7 @@ struct CompareValueOnly
CPubKey CWallet::GenerateNewKey() CPubKey CWallet::GenerateNewKey()
{ {
AssertLockHeld(cs_wallet); // mapKeyMetadata
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
RandAddSeedPerfmon(); RandAddSeedPerfmon();
@ -60,6 +61,7 @@ CPubKey CWallet::GenerateNewKey()
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
{ {
AssertLockHeld(cs_wallet); // mapKeyMetadata
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
return false; return false;
if (!fFileBacked) if (!fFileBacked)
@ -95,6 +97,7 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta) bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
{ {
AssertLockHeld(cs_wallet); // mapKeyMetadata
if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey)) if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
nTimeFirstKey = meta.nCreateTime; nTimeFirstKey = meta.nCreateTime;
@ -202,6 +205,7 @@ public:
bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit) bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
{ {
AssertLockHeld(cs_wallet); // nWalletVersion
if (nWalletVersion >= nVersion) if (nWalletVersion >= nVersion)
return true; return true;
@ -235,6 +239,7 @@ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn,
bool CWallet::SetMaxVersion(int nVersion) bool CWallet::SetMaxVersion(int nVersion)
{ {
AssertLockHeld(cs_wallet); // nWalletVersion, nWalletMaxVersion
// cannot downgrade below current version // cannot downgrade below current version
if (nWalletVersion > nVersion) if (nWalletVersion > nVersion)
return false; return false;
@ -327,6 +332,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb) int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
{ {
AssertLockHeld(cs_wallet); // nOrderPosNext
int64_t nRet = nOrderPosNext++; int64_t nRet = nOrderPosNext++;
if (pwalletdb) { if (pwalletdb) {
pwalletdb->WriteOrderPosNext(nOrderPosNext); pwalletdb->WriteOrderPosNext(nOrderPosNext);
@ -338,6 +344,7 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount) CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount)
{ {
AssertLockHeld(cs_wallet); // mapWallet
CWalletDB walletdb(strWalletFile); CWalletDB walletdb(strWalletFile);
// First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap. // First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap.
@ -1492,6 +1499,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
{ {
if (CDB::Rewrite(strWalletFile, "\x04pool")) if (CDB::Rewrite(strWalletFile, "\x04pool"))
{ {
LOCK(cs_wallet);
setKeyPool.clear(); setKeyPool.clear();
// Note: can't top-up keypool here, because wallet is locked. // Note: can't top-up keypool here, because wallet is locked.
// User will be prompted to unlock wallet the next operation // User will be prompted to unlock wallet the next operation
@ -1509,6 +1517,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose) 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); std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address);
mapAddressBook[address].name = strName; mapAddressBook[address].name = strName;
if (!strPurpose.empty()) /* update purpose only if requested */ if (!strPurpose.empty()) /* update purpose only if requested */
@ -1525,6 +1534,7 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const string& strNam
bool CWallet::DelAddressBook(const CTxDestination& address) bool CWallet::DelAddressBook(const CTxDestination& address)
{ {
AssertLockHeld(cs_wallet); // mapAddressBook
mapAddressBook.erase(address); mapAddressBook.erase(address);
NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), "", CT_DELETED); NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), "", CT_DELETED);
if (!fFileBacked) if (!fFileBacked)
@ -1738,6 +1748,7 @@ std::map<CTxDestination, int64_t> CWallet::GetAddressBalances()
set< set<CTxDestination> > CWallet::GetAddressGroupings() set< set<CTxDestination> > CWallet::GetAddressGroupings()
{ {
AssertLockHeld(cs_wallet); // mapWallet
set< set<CTxDestination> > groupings; set< set<CTxDestination> > groupings;
set<CTxDestination> grouping; set<CTxDestination> grouping;
@ -1830,6 +1841,7 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
set<CTxDestination> CWallet::GetAccountAddresses(string strAccount) const set<CTxDestination> CWallet::GetAccountAddresses(string strAccount) const
{ {
AssertLockHeld(cs_wallet); // mapWallet
set<CTxDestination> result; set<CTxDestination> result;
BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook) BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook)
{ {
@ -1911,21 +1923,25 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx)
void CWallet::LockCoin(COutPoint& output) void CWallet::LockCoin(COutPoint& output)
{ {
AssertLockHeld(cs_wallet); // setLockedCoins
setLockedCoins.insert(output); setLockedCoins.insert(output);
} }
void CWallet::UnlockCoin(COutPoint& output) void CWallet::UnlockCoin(COutPoint& output)
{ {
AssertLockHeld(cs_wallet); // setLockedCoins
setLockedCoins.erase(output); setLockedCoins.erase(output);
} }
void CWallet::UnlockAllCoins() void CWallet::UnlockAllCoins()
{ {
AssertLockHeld(cs_wallet); // setLockedCoins
setLockedCoins.clear(); setLockedCoins.clear();
} }
bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
{ {
AssertLockHeld(cs_wallet); // setLockedCoins
COutPoint outpt(hash, n); COutPoint outpt(hash, n);
return (setLockedCoins.count(outpt) > 0); return (setLockedCoins.count(outpt) > 0);
@ -1933,6 +1949,7 @@ bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts) void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
{ {
AssertLockHeld(cs_wallet); // setLockedCoins
for (std::set<COutPoint>::iterator it = setLockedCoins.begin(); for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
it != setLockedCoins.end(); it++) { it != setLockedCoins.end(); it++) {
COutPoint outpt = (*it); COutPoint outpt = (*it);
@ -1941,6 +1958,7 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
} }
void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const { void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
AssertLockHeld(cs_wallet); // mapKeyMetadata
mapKeyBirth.clear(); mapKeyBirth.clear();
// get birth times for keys with metadata // get birth times for keys with metadata

13
src/wallet.h

@ -105,6 +105,11 @@ private:
int64_t nLastResend; int64_t nLastResend;
public: public:
/// Main wallet lock.
/// This lock protects all the fields added by CWallet
/// except for:
/// fFileBacked (immutable after instantiation)
/// strWalletFile (immutable after instantiation)
mutable CCriticalSection cs_wallet; mutable CCriticalSection cs_wallet;
bool fFileBacked; bool fFileBacked;
@ -154,10 +159,11 @@ public:
int64_t nTimeFirstKey; int64_t nTimeFirstKey;
// check whether we are allowed to upgrade (or already support) to the named feature // check whether we are allowed to upgrade (or already support) to the named feature
bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; } bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL) const; void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL) const;
bool SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const; bool SelectCoinsMinConf(int64_t nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet) const;
bool IsLockedCoin(uint256 hash, unsigned int n) const; bool IsLockedCoin(uint256 hash, unsigned int n) const;
void LockCoin(COutPoint& output); void LockCoin(COutPoint& output);
void UnlockCoin(COutPoint& output); void UnlockCoin(COutPoint& output);
@ -174,7 +180,7 @@ public:
// Load metadata (used by LoadWallet) // Load metadata (used by LoadWallet)
bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata); bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata);
bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; } bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
// Adds an encrypted key to the store, and saves it to disk. // Adds an encrypted key to the store, and saves it to disk.
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
@ -323,6 +329,7 @@ public:
unsigned int GetKeyPoolSize() unsigned int GetKeyPoolSize()
{ {
AssertLockHeld(cs_wallet); // setKeyPool
return setKeyPool.size(); return setKeyPool.size();
} }
@ -335,7 +342,7 @@ public:
bool SetMaxVersion(int nVersion); bool SetMaxVersion(int nVersion);
// get the current wallet format (the oldest client version guaranteed to understand this wallet) // get the current wallet format (the oldest client version guaranteed to understand this wallet)
int GetVersion() { return nWalletVersion; } int GetVersion() { AssertLockHeld(cs_wallet); return nWalletVersion; }
/** Address book entry changed. /** Address book entry changed.
* @note called with lock cs_wallet held. * @note called with lock cs_wallet held.

Loading…
Cancel
Save