Skip to content

Commit 7aedb91

Browse files
committed
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)
2 parents ab086e0 + 012ca1c commit 7aedb91

File tree

5 files changed

+35
-9
lines changed

5 files changed

+35
-9
lines changed

src/main.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2235,7 +2235,7 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
22352235

22362236
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
22372237
{
2238-
AssertLockHeld("cs_main");
2238+
AssertLockHeld(cs_main);
22392239

22402240
// Check for duplicate
22412241
uint256 hash = pblock->GetHash();

src/sync.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,11 @@ std::string LocksHeld()
136136
return result;
137137
}
138138

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

src/sync.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,13 @@ typedef AnnotatedMixin<boost::mutex> CWaitableCriticalSection;
8888
void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false);
8989
void LeaveCritical();
9090
std::string LocksHeld();
91-
void AssertLockHeld(std::string strName);
91+
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void *cs);
9292
#else
9393
void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
9494
void static inline LeaveCritical() {}
95-
void static inline AssertLockHeld(std::string) {}
95+
void static inline AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void *cs) {}
9696
#endif
97+
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
9798

9899
#ifdef DEBUG_LOCKCONTENTION
99100
void PrintLockContention(const char* pszName, const char* pszFile, int nLine);

src/wallet.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct CompareValueOnly
3535

3636
CPubKey CWallet::GenerateNewKey()
3737
{
38+
AssertLockHeld(cs_wallet); // mapKeyMetadata
3839
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets
3940

4041
RandAddSeedPerfmon();
@@ -60,6 +61,7 @@ CPubKey CWallet::GenerateNewKey()
6061

6162
bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey)
6263
{
64+
AssertLockHeld(cs_wallet); // mapKeyMetadata
6365
if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey))
6466
return false;
6567
if (!fFileBacked)
@@ -95,6 +97,7 @@ bool CWallet::AddCryptedKey(const CPubKey &vchPubKey,
9597

9698
bool CWallet::LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &meta)
9799
{
100+
AssertLockHeld(cs_wallet); // mapKeyMetadata
98101
if (meta.nCreateTime && (!nTimeFirstKey || meta.nCreateTime < nTimeFirstKey))
99102
nTimeFirstKey = meta.nCreateTime;
100103

@@ -202,6 +205,7 @@ class CCorruptAddress
202205

203206
bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
204207
{
208+
AssertLockHeld(cs_wallet); // nWalletVersion
205209
if (nWalletVersion >= nVersion)
206210
return true;
207211

@@ -235,6 +239,7 @@ bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn,
235239

236240
bool CWallet::SetMaxVersion(int nVersion)
237241
{
242+
AssertLockHeld(cs_wallet); // nWalletVersion, nWalletMaxVersion
238243
// cannot downgrade below current version
239244
if (nWalletVersion > nVersion)
240245
return false;
@@ -327,6 +332,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase)
327332

328333
int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
329334
{
335+
AssertLockHeld(cs_wallet); // nOrderPosNext
330336
int64_t nRet = nOrderPosNext++;
331337
if (pwalletdb) {
332338
pwalletdb->WriteOrderPosNext(nOrderPosNext);
@@ -338,6 +344,7 @@ int64_t CWallet::IncOrderPosNext(CWalletDB *pwalletdb)
338344

339345
CWallet::TxItems CWallet::OrderedTxItems(std::list<CAccountingEntry>& acentries, std::string strAccount)
340346
{
347+
AssertLockHeld(cs_wallet); // mapWallet
341348
CWalletDB walletdb(strWalletFile);
342349

343350
// First: get all CWalletTx and CAccountingEntry into a sorted-by-order multimap.
@@ -1492,6 +1499,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
14921499
{
14931500
if (CDB::Rewrite(strWalletFile, "\x04pool"))
14941501
{
1502+
LOCK(cs_wallet);
14951503
setKeyPool.clear();
14961504
// Note: can't top-up keypool here, because wallet is locked.
14971505
// User will be prompted to unlock wallet the next operation
@@ -1509,6 +1517,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
15091517

15101518
bool CWallet::SetAddressBook(const CTxDestination& address, const string& strName, const string& strPurpose)
15111519
{
1520+
AssertLockHeld(cs_wallet); // mapAddressBook
15121521
std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address);
15131522
mapAddressBook[address].name = strName;
15141523
if (!strPurpose.empty()) /* update purpose only if requested */
@@ -1525,6 +1534,7 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const string& strNam
15251534

15261535
bool CWallet::DelAddressBook(const CTxDestination& address)
15271536
{
1537+
AssertLockHeld(cs_wallet); // mapAddressBook
15281538
mapAddressBook.erase(address);
15291539
NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), "", CT_DELETED);
15301540
if (!fFileBacked)
@@ -1738,6 +1748,7 @@ std::map<CTxDestination, int64_t> CWallet::GetAddressBalances()
17381748

17391749
set< set<CTxDestination> > CWallet::GetAddressGroupings()
17401750
{
1751+
AssertLockHeld(cs_wallet); // mapWallet
17411752
set< set<CTxDestination> > groupings;
17421753
set<CTxDestination> grouping;
17431754

@@ -1830,6 +1841,7 @@ set< set<CTxDestination> > CWallet::GetAddressGroupings()
18301841

18311842
set<CTxDestination> CWallet::GetAccountAddresses(string strAccount) const
18321843
{
1844+
AssertLockHeld(cs_wallet); // mapWallet
18331845
set<CTxDestination> result;
18341846
BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, mapAddressBook)
18351847
{
@@ -1911,28 +1923,33 @@ void CWallet::UpdatedTransaction(const uint256 &hashTx)
19111923

19121924
void CWallet::LockCoin(COutPoint& output)
19131925
{
1926+
AssertLockHeld(cs_wallet); // setLockedCoins
19141927
setLockedCoins.insert(output);
19151928
}
19161929

19171930
void CWallet::UnlockCoin(COutPoint& output)
19181931
{
1932+
AssertLockHeld(cs_wallet); // setLockedCoins
19191933
setLockedCoins.erase(output);
19201934
}
19211935

19221936
void CWallet::UnlockAllCoins()
19231937
{
1938+
AssertLockHeld(cs_wallet); // setLockedCoins
19241939
setLockedCoins.clear();
19251940
}
19261941

19271942
bool CWallet::IsLockedCoin(uint256 hash, unsigned int n) const
19281943
{
1944+
AssertLockHeld(cs_wallet); // setLockedCoins
19291945
COutPoint outpt(hash, n);
19301946

19311947
return (setLockedCoins.count(outpt) > 0);
19321948
}
19331949

19341950
void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
19351951
{
1952+
AssertLockHeld(cs_wallet); // setLockedCoins
19361953
for (std::set<COutPoint>::iterator it = setLockedCoins.begin();
19371954
it != setLockedCoins.end(); it++) {
19381955
COutPoint outpt = (*it);
@@ -1941,6 +1958,7 @@ void CWallet::ListLockedCoins(std::vector<COutPoint>& vOutpts)
19411958
}
19421959

19431960
void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t> &mapKeyBirth) const {
1961+
AssertLockHeld(cs_wallet); // mapKeyMetadata
19441962
mapKeyBirth.clear();
19451963

19461964
// get birth times for keys with metadata

src/wallet.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ class CWallet : public CCryptoKeyStore, public CWalletInterface
105105
int64_t nLastResend;
106106

107107
public:
108+
/// Main wallet lock.
109+
/// This lock protects all the fields added by CWallet
110+
/// except for:
111+
/// fFileBacked (immutable after instantiation)
112+
/// strWalletFile (immutable after instantiation)
108113
mutable CCriticalSection cs_wallet;
109114

110115
bool fFileBacked;
@@ -154,10 +159,11 @@ class CWallet : public CCryptoKeyStore, public CWalletInterface
154159
int64_t nTimeFirstKey;
155160

156161
// check whether we are allowed to upgrade (or already support) to the named feature
157-
bool CanSupportFeature(enum WalletFeature wf) { return nWalletMaxVersion >= wf; }
162+
bool CanSupportFeature(enum WalletFeature wf) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; }
158163

159164
void AvailableCoins(std::vector<COutput>& vCoins, bool fOnlyConfirmed=true, const CCoinControl *coinControl = NULL) const;
160165
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;
166+
161167
bool IsLockedCoin(uint256 hash, unsigned int n) const;
162168
void LockCoin(COutPoint& output);
163169
void UnlockCoin(COutPoint& output);
@@ -174,7 +180,7 @@ class CWallet : public CCryptoKeyStore, public CWalletInterface
174180
// Load metadata (used by LoadWallet)
175181
bool LoadKeyMetadata(const CPubKey &pubkey, const CKeyMetadata &metadata);
176182

177-
bool LoadMinVersion(int nVersion) { nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
183+
bool LoadMinVersion(int nVersion) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
178184

179185
// Adds an encrypted key to the store, and saves it to disk.
180186
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
@@ -323,6 +329,7 @@ class CWallet : public CCryptoKeyStore, public CWalletInterface
323329

324330
unsigned int GetKeyPoolSize()
325331
{
332+
AssertLockHeld(cs_wallet); // setKeyPool
326333
return setKeyPool.size();
327334
}
328335

@@ -335,7 +342,7 @@ class CWallet : public CCryptoKeyStore, public CWalletInterface
335342
bool SetMaxVersion(int nVersion);
336343

337344
// get the current wallet format (the oldest client version guaranteed to understand this wallet)
338-
int GetVersion() { return nWalletVersion; }
345+
int GetVersion() { AssertLockHeld(cs_wallet); return nWalletVersion; }
339346

340347
/** Address book entry changed.
341348
* @note called with lock cs_wallet held.

0 commit comments

Comments
 (0)