Bugfix: wallet: Increment "update counter" only after actually making the applicable db changes to avoid potential races

Also does all "update counter" access via IncrementUpdateCounter
This commit is contained in:
Luke Dashjr 2017-03-09 20:29:01 +00:00
parent 9fec4da0be
commit f28eb8020e
2 changed files with 50 additions and 49 deletions

View file

@ -32,47 +32,39 @@ static std::atomic<unsigned int> nWalletDBUpdateCounter;
bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName) bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName)
{ {
nWalletDBUpdateCounter++; return WriteIC(std::make_pair(std::string("name"), strAddress), strName);
return batch.Write(std::make_pair(std::string("name"), strAddress), strName);
} }
bool CWalletDB::EraseName(const std::string& strAddress) bool CWalletDB::EraseName(const std::string& strAddress)
{ {
// This should only be used for sending addresses, never for receiving addresses, // This should only be used for sending addresses, never for receiving addresses,
// receiving addresses must always have an address book entry if they're not change return. // receiving addresses must always have an address book entry if they're not change return.
nWalletDBUpdateCounter++; return EraseIC(std::make_pair(std::string("name"), strAddress));
return batch.Erase(std::make_pair(std::string("name"), strAddress));
} }
bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose) bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
{ {
nWalletDBUpdateCounter++; return WriteIC(std::make_pair(std::string("purpose"), strAddress), strPurpose);
return batch.Write(std::make_pair(std::string("purpose"), strAddress), strPurpose);
} }
bool CWalletDB::ErasePurpose(const std::string& strPurpose) bool CWalletDB::ErasePurpose(const std::string& strPurpose)
{ {
nWalletDBUpdateCounter++; return EraseIC(std::make_pair(std::string("purpose"), strPurpose));
return batch.Erase(std::make_pair(std::string("purpose"), strPurpose));
} }
bool CWalletDB::WriteTx(const CWalletTx& wtx) bool CWalletDB::WriteTx(const CWalletTx& wtx)
{ {
nWalletDBUpdateCounter++; return WriteIC(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
return batch.Write(std::make_pair(std::string("tx"), wtx.GetHash()), wtx);
} }
bool CWalletDB::EraseTx(uint256 hash) bool CWalletDB::EraseTx(uint256 hash)
{ {
nWalletDBUpdateCounter++; return EraseIC(std::make_pair(std::string("tx"), hash));
return batch.Erase(std::make_pair(std::string("tx"), hash));
} }
bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta) bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
{ {
nWalletDBUpdateCounter++; if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey),
if (!batch.Write(std::make_pair(std::string("keymeta"), vchPubKey),
keyMeta, false)) keyMeta, false))
return false; return false;
@ -82,7 +74,7 @@ bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, c
vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end()); vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end()); vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
return batch.Write(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false); return WriteIC(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
} }
bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey, bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
@ -90,55 +82,50 @@ bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
const CKeyMetadata &keyMeta) const CKeyMetadata &keyMeta)
{ {
const bool fEraseUnencryptedKey = true; const bool fEraseUnencryptedKey = true;
nWalletDBUpdateCounter++;
if (!batch.Write(std::make_pair(std::string("keymeta"), vchPubKey), if (!WriteIC(std::make_pair(std::string("keymeta"), vchPubKey),
keyMeta)) keyMeta))
return false; return false;
if (!batch.Write(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) if (!WriteIC(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false))
return false; return false;
if (fEraseUnencryptedKey) if (fEraseUnencryptedKey)
{ {
batch.Erase(std::make_pair(std::string("key"), vchPubKey)); EraseIC(std::make_pair(std::string("key"), vchPubKey));
batch.Erase(std::make_pair(std::string("wkey"), vchPubKey)); EraseIC(std::make_pair(std::string("wkey"), vchPubKey));
} }
return true; return true;
} }
bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
{ {
nWalletDBUpdateCounter++; return WriteIC(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
return batch.Write(std::make_pair(std::string("mkey"), nID), kMasterKey, true);
} }
bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript) bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
{ {
nWalletDBUpdateCounter++; return WriteIC(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
return batch.Write(std::make_pair(std::string("cscript"), hash), *(const CScriptBase*)(&redeemScript), false);
} }
bool CWalletDB::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta) bool CWalletDB::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta)
{ {
nWalletDBUpdateCounter++; if (!WriteIC(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)), keyMeta))
if (!batch.Write(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest)), keyMeta))
return false; return false;
return batch.Write(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1'); return WriteIC(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)), '1');
} }
bool CWalletDB::EraseWatchOnly(const CScript &dest) bool CWalletDB::EraseWatchOnly(const CScript &dest)
{ {
nWalletDBUpdateCounter++; if (!EraseIC(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest))))
if (!batch.Erase(std::make_pair(std::string("watchmeta"), *(const CScriptBase*)(&dest))))
return false; return false;
return batch.Erase(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest))); return EraseIC(std::make_pair(std::string("watchs"), *(const CScriptBase*)(&dest)));
} }
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator) bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
{ {
nWalletDBUpdateCounter++; WriteIC(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
batch.Write(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan return WriteIC(std::string("bestblock_nomerkle"), locator);
return batch.Write(std::string("bestblock_nomerkle"), locator);
} }
bool CWalletDB::ReadBestBlock(CBlockLocator& locator) bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
@ -149,14 +136,12 @@ bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext) bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
{ {
nWalletDBUpdateCounter++; return WriteIC(std::string("orderposnext"), nOrderPosNext);
return batch.Write(std::string("orderposnext"), nOrderPosNext);
} }
bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey) bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
{ {
nWalletDBUpdateCounter++; return WriteIC(std::string("defaultkey"), vchPubKey);
return batch.Write(std::string("defaultkey"), vchPubKey);
} }
bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool) bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
@ -166,19 +151,17 @@ bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool) bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
{ {
nWalletDBUpdateCounter++; return WriteIC(std::make_pair(std::string("pool"), nPool), keypool);
return batch.Write(std::make_pair(std::string("pool"), nPool), keypool);
} }
bool CWalletDB::ErasePool(int64_t nPool) bool CWalletDB::ErasePool(int64_t nPool)
{ {
nWalletDBUpdateCounter++; return EraseIC(std::make_pair(std::string("pool"), nPool));
return batch.Erase(std::make_pair(std::string("pool"), nPool));
} }
bool CWalletDB::WriteMinVersion(int nVersion) bool CWalletDB::WriteMinVersion(int nVersion)
{ {
return batch.Write(std::string("minversion"), nVersion); return WriteIC(std::string("minversion"), nVersion);
} }
bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account) bool CWalletDB::ReadAccount(const std::string& strAccount, CAccount& account)
@ -854,21 +837,18 @@ bool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path
bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value) bool CWalletDB::WriteDestData(const std::string &address, const std::string &key, const std::string &value)
{ {
nWalletDBUpdateCounter++; return WriteIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
return batch.Write(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value);
} }
bool CWalletDB::EraseDestData(const std::string &address, const std::string &key) bool CWalletDB::EraseDestData(const std::string &address, const std::string &key)
{ {
nWalletDBUpdateCounter++; return EraseIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
return batch.Erase(std::make_pair(std::string("destdata"), std::make_pair(address, key)));
} }
bool CWalletDB::WriteHDChain(const CHDChain& chain) bool CWalletDB::WriteHDChain(const CHDChain& chain)
{ {
nWalletDBUpdateCounter++; return WriteIC(std::string("hdchain"), chain);
return batch.Write(std::string("hdchain"), chain);
} }
void CWalletDB::IncrementUpdateCounter() void CWalletDB::IncrementUpdateCounter()

View file

@ -140,6 +140,27 @@ public:
*/ */
class CWalletDB class CWalletDB
{ {
private:
template <typename K, typename T>
bool WriteIC(const K& key, const T& value, bool fOverwrite = true)
{
if (!batch.Write(key, value, fOverwrite)) {
return false;
}
IncrementUpdateCounter();
return true;
}
template <typename K>
bool EraseIC(const K& key)
{
if (!batch.Erase(key)) {
return false;
}
IncrementUpdateCounter();
return true;
}
public: public:
CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool _fFlushOnClose = true) : CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool _fFlushOnClose = true) :
batch(dbw, pszMode, _fFlushOnClose) batch(dbw, pszMode, _fFlushOnClose)