Skip to content

Commit

Permalink
Merge pull request zcash#3401
Browse files Browse the repository at this point in the history
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)
  • Loading branch information
laanwj committed Jan 6, 2014
2 parents ab086e0 + 012ca1c commit 7aedb91
Show file tree
Hide file tree
Showing 5 changed files with 35 additions and 9 deletions.
2 changes: 1 addition & 1 deletion src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2235,7 +2235,7 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)

bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
{
AssertLockHeld("cs_main");
AssertLockHeld(cs_main);

// Check for duplicate
uint256 hash = pblock->GetHash();
Expand Down
6 changes: 3 additions & 3 deletions src/sync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,11 @@ std::string LocksHeld()
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)
if (i.second.MutexName() == strName) return;
LogPrintf("Lock %s not held; locks held:\n%s", strName.c_str(), LocksHeld().c_str());
if (i.first == cs) return;
LogPrintf("Lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld().c_str());
assert(0);
}

Expand Down
5 changes: 3 additions & 2 deletions src/sync.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 LeaveCritical();
std::string LocksHeld();
void AssertLockHeld(std::string strName);
void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void *cs);
#else
void static inline EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry = false) {}
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
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)

#ifdef DEBUG_LOCKCONTENTION
void PrintLockContention(const char* pszName, const char* pszFile, int nLine);
Expand Down
18 changes: 18 additions & 0 deletions src/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,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();
Expand All @@ -60,6 +61,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)
Expand Down Expand Up @@ -95,6 +97,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;

Expand Down Expand Up @@ -202,6 +205,7 @@ class CCorruptAddress

bool CWallet::SetMinVersion(enum WalletFeature nVersion, CWalletDB* pwalletdbIn, bool fExplicit)
{
AssertLockHeld(cs_wallet); // nWalletVersion
if (nWalletVersion >= nVersion)
return true;

Expand Down Expand Up @@ -235,6 +239,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;
Expand Down Expand Up @@ -327,6 +332,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);
Expand All @@ -338,6 +344,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.
Expand Down Expand Up @@ -1492,6 +1499,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
Expand All @@ -1509,6 +1517,7 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)

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 */
Expand All @@ -1525,6 +1534,7 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const string& strNam

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

set< set<CTxDestination> > CWallet::GetAddressGroupings()
{
AssertLockHeld(cs_wallet); // mapWallet
set< set<CTxDestination> > groupings;
set<CTxDestination> grouping;

Expand Down Expand Up @@ -1830,6 +1841,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)
{
Expand Down Expand Up @@ -1911,28 +1923,33 @@ 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);
}

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);
Expand All @@ -1941,6 +1958,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
Expand Down
13 changes: 10 additions & 3 deletions src/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ class CWallet : public CCryptoKeyStore, public CWalletInterface
int64_t nLastResend;

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;

bool fFileBacked;
Expand Down Expand Up @@ -154,10 +159,11 @@ class CWallet : public CCryptoKeyStore, public CWalletInterface
int64_t nTimeFirstKey;

// 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;
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;
void LockCoin(COutPoint& output);
void UnlockCoin(COutPoint& output);
Expand All @@ -174,7 +180,7 @@ class CWallet : public CCryptoKeyStore, public CWalletInterface
// Load metadata (used by LoadWallet)
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.
bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);
Expand Down Expand Up @@ -323,6 +329,7 @@ class CWallet : public CCryptoKeyStore, public CWalletInterface

unsigned int GetKeyPoolSize()
{
AssertLockHeld(cs_wallet); // setKeyPool
return setKeyPool.size();
}

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

// 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.
* @note called with lock cs_wallet held.
Expand Down

0 comments on commit 7aedb91

Please sign in to comment.