Skip to content

Commit cd672cd

Browse files
committed
[Main] Write to the zerocoinDB in batches
instead of using a separate write operation for each and every bit of data that needs to be flushed to disk, utilize leveldb's batch writing capability.
1 parent 6b525f0 commit cd672cd

File tree

4 files changed

+54
-23
lines changed

4 files changed

+54
-23
lines changed

src/main.cpp

+5-11
Original file line numberDiff line numberDiff line change
@@ -2933,8 +2933,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
29332933
unsigned int nSigOps = 0;
29342934
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
29352935
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
2936-
std::vector<pair<CoinSpend, uint256> > vSpends;
2937-
vector<pair<PublicCoin, uint256> > vMints;
2936+
std::vector<std::pair<CoinSpend, uint256> > vSpends;
2937+
std::vector<std::pair<PublicCoin, uint256> > vMints;
29382938
vPos.reserve(block.vtx.size());
29392939
CBlockUndo blockundo;
29402940
blockundo.vtxundo.reserve(block.vtx.size() - 1);
@@ -3131,10 +3131,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
31313131
//Record zPIV serials
31323132
set<uint256> setAddedTx;
31333133
for (pair<CoinSpend, uint256> pSpend : vSpends) {
3134-
//record spend to database
3135-
if (!zerocoinDB->WriteCoinSpend(pSpend.first.getCoinSerialNumber(), pSpend.second))
3136-
return state.Abort(("Failed to record coin serial to database"));
3137-
31383134
// Send signal to wallet if this is ours
31393135
if (pwalletMain) {
31403136
if (pwalletMain->IsMyZerocoinSpend(pSpend.first.getCoinSerialNumber())) {
@@ -3159,11 +3155,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
31593155
}
31603156
}
31613157

3162-
//Record mints to db
3163-
for (pair<PublicCoin, uint256> pMint : vMints) {
3164-
if (!zerocoinDB->WriteCoinMint(pMint.first, pMint.second))
3165-
return state.Abort(("Failed to record new mint to database"));
3166-
}
3158+
// Flush spend/mint info to disk
3159+
if (!zerocoinDB->WriteCoinSpendBatch(vSpends)) return state.Abort(("Failed to record coin serials to database"));
3160+
if (!zerocoinDB->WriteCoinMintBatch(vMints)) return state.Abort(("Failed to record new mints to database"));
31673161

31683162
//Record accumulator checksums
31693163
DatabaseChecksums(mapAccumulators);

src/txdb.cpp

+25-8
Original file line numberDiff line numberDiff line change
@@ -294,10 +294,19 @@ CZerocoinDB::CZerocoinDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB
294294
{
295295
}
296296

297-
bool CZerocoinDB::WriteCoinMint(const PublicCoin& pubCoin, const uint256& hashTx)
297+
bool CZerocoinDB::WriteCoinMintBatch(const std::vector<std::pair<libzerocoin::PublicCoin, uint256> >& mintInfo)
298298
{
299-
uint256 hash = GetPubCoinHash(pubCoin.getValue());
300-
return Write(make_pair('m', hash), hashTx, true);
299+
CLevelDBBatch batch;
300+
size_t count = 0;
301+
for (std::vector<std::pair<libzerocoin::PublicCoin, uint256> >::const_iterator it=mintInfo.begin(); it != mintInfo.end(); it++) {
302+
PublicCoin pubCoin = it->first;
303+
uint256 hash = GetPubCoinHash(pubCoin.getValue());
304+
batch.Write(make_pair('m', hash), it->second);
305+
++count;
306+
}
307+
308+
LogPrint("zero", "Writing %u coin mints to db.\n", (unsigned int)count);
309+
return WriteBatch(batch, true);
301310
}
302311

303312
bool CZerocoinDB::ReadCoinMint(const CBigNum& bnPubcoin, uint256& hashTx)
@@ -316,13 +325,21 @@ bool CZerocoinDB::EraseCoinMint(const CBigNum& bnPubcoin)
316325
return Erase(make_pair('m', hash));
317326
}
318327

319-
bool CZerocoinDB::WriteCoinSpend(const CBigNum& bnSerial, const uint256& txHash)
328+
bool CZerocoinDB::WriteCoinSpendBatch(const std::vector<std::pair<libzerocoin::CoinSpend, uint256> >& spendInfo)
320329
{
321-
CDataStream ss(SER_GETHASH, 0);
322-
ss << bnSerial;
323-
uint256 hash = Hash(ss.begin(), ss.end());
330+
CLevelDBBatch batch;
331+
size_t count = 0;
332+
for (std::vector<std::pair<libzerocoin::CoinSpend, uint256> >::const_iterator it=spendInfo.begin(); it != spendInfo.end(); it++) {
333+
CBigNum bnSerial = it->first.getCoinSerialNumber();
334+
CDataStream ss(SER_GETHASH, 0);
335+
ss << bnSerial;
336+
uint256 hash = Hash(ss.begin(), ss.end());
337+
batch.Write(make_pair('s', hash), it->second);
338+
++count;
339+
}
324340

325-
return Write(make_pair('s', hash), txHash, true);
341+
LogPrint("zero", "Writing %u coin spends to db.\n", (unsigned int)count);
342+
return WriteBatch(batch, true);
326343
}
327344

328345
bool CZerocoinDB::ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash)

src/txdb.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class CBlockTreeDB : public CLevelDBWrapper
6969
bool LoadBlockIndexGuts();
7070
};
7171

72+
/** Zerocoin database (zerocoin/) */
7273
class CZerocoinDB : public CLevelDBWrapper
7374
{
7475
public:
@@ -79,10 +80,12 @@ class CZerocoinDB : public CLevelDBWrapper
7980
void operator=(const CZerocoinDB&);
8081

8182
public:
82-
bool WriteCoinMint(const libzerocoin::PublicCoin& pubCoin, const uint256& txHash);
83+
/** Write zPIV mints to the zerocoinDB in a batch */
84+
bool WriteCoinMintBatch(const std::vector<std::pair<libzerocoin::PublicCoin, uint256> >& mintInfo);
8385
bool ReadCoinMint(const CBigNum& bnPubcoin, uint256& txHash);
8486
bool ReadCoinMint(const uint256& hashPubcoin, uint256& hashTx);
85-
bool WriteCoinSpend(const CBigNum& bnSerial, const uint256& txHash);
87+
/** Write zPIV spends to the zerocoinDB in a batch */
88+
bool WriteCoinSpendBatch(const std::vector<std::pair<libzerocoin::CoinSpend, uint256> >& spendInfo);
8689
bool ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash);
8790
bool ReadCoinSpend(const uint256& hashSerial, uint256 &txHash);
8891
bool EraseCoinMint(const CBigNum& bnPubcoin);

src/zpivchain.cpp

+19-2
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ std::string ReindexZerocoinDB()
260260
}
261261

262262
CBlockIndex* pindex = chainActive[Params().Zerocoin_StartHeight()];
263+
std::vector<std::pair<libzerocoin::CoinSpend, uint256> > vSpendInfo;
264+
std::vector<std::pair<libzerocoin::PublicCoin, uint256> > vMintInfo;
263265
while (pindex) {
264266
if (pindex->nHeight % 1000 == 0)
265267
LogPrintf("Reindexing zerocoin : block %d...\n", pindex->nHeight);
@@ -283,7 +285,7 @@ std::string ReindexZerocoinDB()
283285
continue;
284286

285287
libzerocoin::CoinSpend spend = TxInToZerocoinSpend(in);
286-
zerocoinDB->WriteCoinSpend(spend.getCoinSerialNumber(), txid);
288+
vSpendInfo.push_back(make_pair(spend, txid));
287289
}
288290
}
289291

@@ -296,15 +298,30 @@ std::string ReindexZerocoinDB()
296298
CValidationState state;
297299
libzerocoin::PublicCoin coin(Params().Zerocoin_Params(pindex->nHeight < Params().Zerocoin_Block_V2_Start()));
298300
TxOutToPublicCoin(out, coin, state);
299-
zerocoinDB->WriteCoinMint(coin, txid);
301+
vMintInfo.push_back(make_pair(coin, txid));
300302
}
301303
}
302304
}
303305
}
304306
}
307+
308+
// Flush the zerocoinDB to disk every 100 blocks
309+
if (pindex->nHeight % 100 == 0) {
310+
if ((!vSpendInfo.empty() && !zerocoinDB->WriteCoinSpendBatch(vSpendInfo)) || (!vMintInfo.empty() && !zerocoinDB->WriteCoinMintBatch(vMintInfo)))
311+
return _("Error writing zerocoinDB to disk");
312+
vSpendInfo.clear();
313+
vMintInfo.clear();
314+
}
315+
305316
pindex = chainActive.Next(pindex);
306317
}
307318

319+
// Final flush to disk in case any remaining information exists
320+
if ((!vSpendInfo.empty() && !zerocoinDB->WriteCoinSpendBatch(vSpendInfo)) || (!vMintInfo.empty() && !zerocoinDB->WriteCoinMintBatch(vMintInfo)))
321+
return _("Error writing zerocoinDB to disk");
322+
323+
uiInterface.ShowProgress("", 100);
324+
308325
return "";
309326
}
310327

0 commit comments

Comments
 (0)