Skip to content

Commit 8aa93b9

Browse files
luke-jrrandom-zebra
authored andcommitted
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
1 parent db5e692 commit 8aa93b9

File tree

2 files changed

+57
-69
lines changed

2 files changed

+57
-69
lines changed

src/wallet/walletdb.cpp

Lines changed: 36 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -69,48 +69,39 @@ static std::atomic<unsigned int> nWalletDBUpdateCounter;
6969

7070
bool CWalletDB::WriteName(const std::string& strAddress, const std::string& strName)
7171
{
72-
nWalletDBUpdateCounter++;
73-
return batch.Write(std::make_pair(std::string(DBKeys::NAME), strAddress), strName);
72+
return WriteIC(std::make_pair(std::string(DBKeys::NAME), strAddress), strName);
7473
}
7574

7675
bool CWalletDB::EraseName(const std::string& strAddress)
7776
{
7877
// This should only be used for sending addresses, never for receiving addresses,
7978
// receiving addresses must always have an address book entry if they're not change return.
80-
nWalletDBUpdateCounter++;
81-
return batch.Erase(std::make_pair(std::string(DBKeys::NAME), strAddress));
79+
return EraseIC(std::make_pair(std::string(DBKeys::NAME), strAddress));
8280
}
8381

8482
bool CWalletDB::WritePurpose(const std::string& strAddress, const std::string& strPurpose)
8583
{
86-
nWalletDBUpdateCounter++;
87-
return batch.Write(std::make_pair(std::string(DBKeys::PURPOSE), strAddress), strPurpose);
84+
return WriteIC(std::make_pair(std::string(DBKeys::PURPOSE), strAddress), strPurpose);
8885
}
8986

9087
bool CWalletDB::ErasePurpose(const std::string& strPurpose)
9188
{
92-
nWalletDBUpdateCounter++;
93-
return batch.Erase(std::make_pair(std::string(DBKeys::PURPOSE), strPurpose));
89+
return EraseIC(std::make_pair(std::string(DBKeys::PURPOSE), strPurpose));
9490
}
9591

9692
bool CWalletDB::WriteTx(const CWalletTx& wtx)
9793
{
98-
nWalletDBUpdateCounter++;
99-
return batch.Write(std::make_pair(std::string(DBKeys::TX), wtx.GetHash()), wtx);
94+
return WriteIC(std::make_pair(std::string(DBKeys::TX), wtx.GetHash()), wtx);
10095
}
10196

10297
bool CWalletDB::EraseTx(uint256 hash)
10398
{
104-
nWalletDBUpdateCounter++;
105-
return batch.Erase(std::make_pair(std::string(DBKeys::TX), hash));
99+
return EraseIC(std::make_pair(std::string(DBKeys::TX), hash));
106100
}
107101

108102
bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta)
109103
{
110-
nWalletDBUpdateCounter++;
111-
112-
if (!batch.Write(std::make_pair(std::string(DBKeys::KEYMETA), vchPubKey),
113-
keyMeta, false))
104+
if (!WriteIC(std::make_pair(std::string(DBKeys::KEYMETA), vchPubKey), keyMeta, false))
114105
return false;
115106

116107
// hash pubkey/privkey to accelerate wallet load
@@ -119,47 +110,42 @@ bool CWalletDB::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, c
119110
vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
120111
vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
121112

122-
return batch.Write(std::make_pair(std::string(DBKeys::KEY), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
113+
return WriteIC(std::make_pair(std::string(DBKeys::KEY), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
123114
}
124115

125116
bool CWalletDB::WriteCryptedKey(const CPubKey& vchPubKey,
126117
const std::vector<unsigned char>& vchCryptedSecret,
127118
const CKeyMetadata& keyMeta)
128119
{
129120
const bool fEraseUnencryptedKey = true;
130-
nWalletDBUpdateCounter++;
131121

132-
if (!batch.Write(std::make_pair(std::string(DBKeys::KEYMETA), vchPubKey),
133-
keyMeta))
122+
if (!WriteIC(std::make_pair(std::string(DBKeys::KEYMETA), vchPubKey), keyMeta))
134123
return false;
135124

136-
if (!batch.Write(std::make_pair(std::string(DBKeys::CRYPTED_KEY), vchPubKey), vchCryptedSecret, false))
125+
if (!WriteIC(std::make_pair(std::string(DBKeys::CRYPTED_KEY), vchPubKey), vchCryptedSecret, false))
137126
return false;
138127
if (fEraseUnencryptedKey) {
139-
batch.Erase(std::make_pair(std::string(DBKeys::KEY), vchPubKey));
128+
EraseIC(std::make_pair(std::string(DBKeys::KEY), vchPubKey));
140129
}
130+
141131
return true;
142132
}
143133

144134
bool CWalletDB::WriteSaplingZKey(const libzcash::SaplingIncomingViewingKey &ivk,
145135
const libzcash::SaplingExtendedSpendingKey &key,
146136
const CKeyMetadata &keyMeta)
147137
{
148-
nWalletDBUpdateCounter++;
149-
150-
if (!batch.Write(std::make_pair(std::string(DBKeys::SAP_KEYMETA), ivk), keyMeta))
138+
if (!WriteIC(std::make_pair(std::string(DBKeys::SAP_KEYMETA), ivk), keyMeta))
151139
return false;
152140

153-
return batch.Write(std::make_pair(std::string(DBKeys::SAP_KEY), ivk), key, false);
141+
return WriteIC(std::make_pair(std::string(DBKeys::SAP_KEY), ivk), key, false);
154142
}
155143

156144
bool CWalletDB::WriteSaplingPaymentAddress(
157145
const libzcash::SaplingPaymentAddress &addr,
158146
const libzcash::SaplingIncomingViewingKey &ivk)
159147
{
160-
nWalletDBUpdateCounter++;
161-
162-
return batch.Write(std::make_pair(std::string(DBKeys::SAP_ADDR), addr), ivk, false);
148+
return WriteIC(std::make_pair(std::string(DBKeys::SAP_ADDR), addr), ivk, false);
163149
}
164150

165151
bool CWalletDB::WriteCryptedSaplingZKey(
@@ -168,25 +154,23 @@ bool CWalletDB::WriteCryptedSaplingZKey(
168154
const CKeyMetadata &keyMeta)
169155
{
170156
const bool fEraseUnencryptedKey = true;
171-
nWalletDBUpdateCounter++;
172157
auto ivk = extfvk.fvk.in_viewing_key();
173158

174-
if (!batch.Write(std::make_pair(std::string(DBKeys::SAP_KEYMETA), ivk), keyMeta))
159+
if (!WriteIC(std::make_pair(std::string(DBKeys::SAP_KEYMETA), ivk), keyMeta))
175160
return false;
176161

177-
if (!batch.Write(std::make_pair(std::string(DBKeys::SAP_KEY_CRIPTED), ivk), std::make_pair(extfvk, vchCryptedSecret), false))
162+
if (!WriteIC(std::make_pair(std::string(DBKeys::SAP_KEY_CRIPTED), ivk), std::make_pair(extfvk, vchCryptedSecret), false))
178163
return false;
179164

180165
if (fEraseUnencryptedKey) {
181-
batch.Erase(std::make_pair(std::string(DBKeys::SAP_KEY), ivk));
166+
EraseIC(std::make_pair(std::string(DBKeys::SAP_KEY), ivk));
182167
}
183168
return true;
184169
}
185170

186171
bool CWalletDB::WriteSaplingCommonOVK(const uint256& ovk)
187172
{
188-
nWalletDBUpdateCounter++;
189-
return batch.Write(std::string(DBKeys::SAP_COMMON_OVK), ovk);
173+
return WriteIC(std::string(DBKeys::SAP_COMMON_OVK), ovk);
190174
}
191175

192176
bool CWalletDB::ReadSaplingCommonOVK(uint256& ovkRet)
@@ -196,40 +180,33 @@ bool CWalletDB::ReadSaplingCommonOVK(uint256& ovkRet)
196180

197181
bool CWalletDB::WriteWitnessCacheSize(int64_t nWitnessCacheSize)
198182
{
199-
nWalletDBUpdateCounter++;
200-
return batch.Write(std::string(DBKeys::SAP_WITNESS_CACHE_SIZE), nWitnessCacheSize);
183+
return WriteIC(std::string(DBKeys::SAP_WITNESS_CACHE_SIZE), nWitnessCacheSize);
201184
}
202185

203186
bool CWalletDB::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey)
204187
{
205-
nWalletDBUpdateCounter++;
206-
return batch.Write(std::make_pair(std::string(DBKeys::MASTER_KEY), nID), kMasterKey, true);
188+
return WriteIC(std::make_pair(std::string(DBKeys::MASTER_KEY), nID), kMasterKey, true);
207189
}
208190

209191
bool CWalletDB::WriteCScript(const uint160& hash, const CScript& redeemScript)
210192
{
211-
nWalletDBUpdateCounter++;
212-
return batch.Write(std::make_pair(std::string(DBKeys::CSCRIPT), hash), redeemScript, false);
193+
return WriteIC(std::make_pair(std::string(DBKeys::CSCRIPT), hash), redeemScript, false);
213194
}
214195

215196
bool CWalletDB::WriteWatchOnly(const CScript& dest)
216197
{
217-
nWalletDBUpdateCounter++;
218-
return batch.Write(std::make_pair(std::string(DBKeys::WATCHS), dest), '1');
198+
return WriteIC(std::make_pair(std::string(DBKeys::WATCHS), dest), '1');
219199
}
220200

221201
bool CWalletDB::EraseWatchOnly(const CScript& dest)
222202
{
223-
224-
nWalletDBUpdateCounter++;
225-
return batch.Erase(std::make_pair(std::string(DBKeys::WATCHS), dest));
203+
return EraseIC(std::make_pair(std::string(DBKeys::WATCHS), dest));
226204
}
227205

228206
bool CWalletDB::WriteBestBlock(const CBlockLocator& locator)
229207
{
230-
nWalletDBUpdateCounter++;
231-
batch.Write(std::string(DBKeys::BESTBLOCK), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
232-
return batch.Write(std::string(DBKeys::BESTBLOCK_NOMERKLE), locator);
208+
WriteIC(std::string(DBKeys::BESTBLOCK), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan
209+
return WriteIC(std::string(DBKeys::BESTBLOCK_NOMERKLE), locator);
233210
}
234211

235212
bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
@@ -240,35 +217,30 @@ bool CWalletDB::ReadBestBlock(CBlockLocator& locator)
240217

241218
bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
242219
{
243-
nWalletDBUpdateCounter++;
244-
return batch.Write(std::string(DBKeys::ORDERPOSNEXT), nOrderPosNext);
220+
return WriteIC(std::string(DBKeys::ORDERPOSNEXT), nOrderPosNext);
245221
}
246222

247223
bool CWalletDB::WriteStakeSplitThreshold(const CAmount& nStakeSplitThreshold)
248224
{
249-
nWalletDBUpdateCounter++;
250-
return batch.Write(std::string(DBKeys::STAKE_SPLIT_THRESHOLD), nStakeSplitThreshold);
225+
return WriteIC(std::string(DBKeys::STAKE_SPLIT_THRESHOLD), nStakeSplitThreshold);
251226
}
252227

253228
bool CWalletDB::WriteUseCustomFee(bool fUse)
254229
{
255-
nWalletDBUpdateCounter++;
256-
return batch.Write(std::string(DBKeys::USE_CUSTOM_FEE), fUse);
230+
return WriteIC(std::string(DBKeys::USE_CUSTOM_FEE), fUse);
257231
}
258232

259233
bool CWalletDB::WriteCustomFeeValue(const CAmount& nFee)
260234
{
261-
nWalletDBUpdateCounter++;
262-
return batch.Write(std::string(DBKeys::CUSTOM_FEE_VALUE), nFee);
235+
return WriteIC(std::string(DBKeys::CUSTOM_FEE_VALUE), nFee);
263236
}
264237

265238
bool CWalletDB::WriteAutoCombineSettings(bool fEnable, CAmount nCombineThreshold)
266239
{
267-
nWalletDBUpdateCounter++;
268240
std::pair<bool, CAmount> pSettings;
269241
pSettings.first = fEnable;
270242
pSettings.second = nCombineThreshold;
271-
return batch.Write(std::string(DBKeys::AUTOCOMBINE), pSettings, true);
243+
return WriteIC(std::string(DBKeys::AUTOCOMBINE), pSettings, true);
272244
}
273245

274246
bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
@@ -278,14 +250,12 @@ bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
278250

279251
bool CWalletDB::WritePool(int64_t nPool, const CKeyPool& keypool)
280252
{
281-
nWalletDBUpdateCounter++;
282-
return batch.Write(std::make_pair(std::string(DBKeys::POOL), nPool), keypool);
253+
return WriteIC(std::make_pair(std::string(DBKeys::POOL), nPool), keypool);
283254
}
284255

285256
bool CWalletDB::ErasePool(int64_t nPool)
286257
{
287-
nWalletDBUpdateCounter++;
288-
return batch.Erase(std::make_pair(std::string(DBKeys::POOL), nPool));
258+
return EraseIC(std::make_pair(std::string(DBKeys::POOL), nPool));
289259
}
290260

291261
bool CWalletDB::WriteMinVersion(int nVersion)
@@ -295,10 +265,9 @@ bool CWalletDB::WriteMinVersion(int nVersion)
295265

296266
bool CWalletDB::WriteHDChain(const CHDChain& chain)
297267
{
298-
nWalletDBUpdateCounter++;
299268
std::string key = chain.chainType == HDChain::ChainCounterType::Sapling ?
300269
DBKeys::SAP_HDCHAIN : DBKeys::HDCHAIN;
301-
return batch.Write(key, chain);
270+
return WriteIC(key, chain);
302271
}
303272

304273
DBErrors CWalletDB::ReorderTransactions(CWallet* pwallet)
@@ -1140,14 +1109,12 @@ bool CWalletDB::VerifyDatabaseFile(const std::string& walletFile, const fs::path
11401109

11411110
bool CWalletDB::WriteDestData(const std::string& address, const std::string& key, const std::string& value)
11421111
{
1143-
nWalletDBUpdateCounter++;
1144-
return batch.Write(std::make_pair(std::string(DBKeys::DESTDATA), std::make_pair(address, key)), value);
1112+
return WriteIC(std::make_pair(std::string(DBKeys::DESTDATA), std::make_pair(address, key)), value);
11451113
}
11461114

11471115
bool CWalletDB::EraseDestData(const std::string& address, const std::string& key)
11481116
{
1149-
nWalletDBUpdateCounter++;
1150-
return batch.Erase(std::make_pair(std::string(DBKeys::DESTDATA), std::make_pair(address, key)));
1117+
return EraseIC(std::make_pair(std::string(DBKeys::DESTDATA), std::make_pair(address, key)));
11511118
}
11521119

11531120
void CWalletDB::IncrementUpdateCounter()

src/wallet/walletdb.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,27 @@ class CKeyMetadata
114114
*/
115115
class CWalletDB
116116
{
117+
private:
118+
template <typename K, typename T>
119+
bool WriteIC(const K& key, const T& value, bool fOverwrite = true)
120+
{
121+
if (!batch.Write(key, value, fOverwrite)) {
122+
return false;
123+
}
124+
IncrementUpdateCounter();
125+
return true;
126+
}
127+
128+
template <typename K>
129+
bool EraseIC(const K& key)
130+
{
131+
if (!batch.Erase(key)) {
132+
return false;
133+
}
134+
IncrementUpdateCounter();
135+
return true;
136+
}
137+
117138
public:
118139
CWalletDB(CWalletDBWrapper& dbw, const char* pszMode = "r+", bool _fFlushOnClose = true) :
119140
batch(dbw, pszMode, _fFlushOnClose)

0 commit comments

Comments
 (0)