diff --git a/src/main.cpp b/src/main.cpp index 5e87e6300250e..583d28c98df62 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2937,8 +2937,8 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin unsigned int nSigOps = 0; CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); std::vector > vPos; - std::vector > vSpends; - vector > vMints; + std::vector > vSpends; + std::vector > vMints; vPos.reserve(block.vtx.size()); CBlockUndo blockundo; blockundo.vtxundo.reserve(block.vtx.size() - 1); @@ -3135,10 +3135,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin //Record zPIV serials set setAddedTx; for (pair pSpend : vSpends) { - //record spend to database - if (!zerocoinDB->WriteCoinSpend(pSpend.first.getCoinSerialNumber(), pSpend.second)) - return state.Abort(("Failed to record coin serial to database")); - // Send signal to wallet if this is ours if (pwalletMain) { if (pwalletMain->IsMyZerocoinSpend(pSpend.first.getCoinSerialNumber())) { @@ -3163,11 +3159,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin } } - //Record mints to db - for (pair pMint : vMints) { - if (!zerocoinDB->WriteCoinMint(pMint.first, pMint.second)) - return state.Abort(("Failed to record new mint to database")); - } + // Flush spend/mint info to disk + if (!zerocoinDB->WriteCoinSpendBatch(vSpends)) return state.Abort(("Failed to record coin serials to database")); + if (!zerocoinDB->WriteCoinMintBatch(vMints)) return state.Abort(("Failed to record new mints to database")); //Record accumulator checksums DatabaseChecksums(mapAccumulators); diff --git a/src/txdb.cpp b/src/txdb.cpp index 125ac29bd8c2b..b6212feab4937 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -294,10 +294,19 @@ CZerocoinDB::CZerocoinDB(size_t nCacheSize, bool fMemory, bool fWipe) : CLevelDB { } -bool CZerocoinDB::WriteCoinMint(const PublicCoin& pubCoin, const uint256& hashTx) +bool CZerocoinDB::WriteCoinMintBatch(const std::vector >& mintInfo) { - uint256 hash = GetPubCoinHash(pubCoin.getValue()); - return Write(make_pair('m', hash), hashTx, true); + CLevelDBBatch batch; + size_t count = 0; + for (std::vector >::const_iterator it=mintInfo.begin(); it != mintInfo.end(); it++) { + PublicCoin pubCoin = it->first; + uint256 hash = GetPubCoinHash(pubCoin.getValue()); + batch.Write(make_pair('m', hash), it->second); + ++count; + } + + LogPrint("zero", "Writing %u coin mints to db.\n", (unsigned int)count); + return WriteBatch(batch, true); } bool CZerocoinDB::ReadCoinMint(const CBigNum& bnPubcoin, uint256& hashTx) @@ -316,13 +325,21 @@ bool CZerocoinDB::EraseCoinMint(const CBigNum& bnPubcoin) return Erase(make_pair('m', hash)); } -bool CZerocoinDB::WriteCoinSpend(const CBigNum& bnSerial, const uint256& txHash) +bool CZerocoinDB::WriteCoinSpendBatch(const std::vector >& spendInfo) { - CDataStream ss(SER_GETHASH, 0); - ss << bnSerial; - uint256 hash = Hash(ss.begin(), ss.end()); + CLevelDBBatch batch; + size_t count = 0; + for (std::vector >::const_iterator it=spendInfo.begin(); it != spendInfo.end(); it++) { + CBigNum bnSerial = it->first.getCoinSerialNumber(); + CDataStream ss(SER_GETHASH, 0); + ss << bnSerial; + uint256 hash = Hash(ss.begin(), ss.end()); + batch.Write(make_pair('s', hash), it->second); + ++count; + } - return Write(make_pair('s', hash), txHash, true); + LogPrint("zero", "Writing %u coin spends to db.\n", (unsigned int)count); + return WriteBatch(batch, true); } bool CZerocoinDB::ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash) diff --git a/src/txdb.h b/src/txdb.h index f47d69915fde2..7728e29a63cbc 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -69,6 +69,7 @@ class CBlockTreeDB : public CLevelDBWrapper bool LoadBlockIndexGuts(); }; +/** Zerocoin database (zerocoin/) */ class CZerocoinDB : public CLevelDBWrapper { public: @@ -79,10 +80,12 @@ class CZerocoinDB : public CLevelDBWrapper void operator=(const CZerocoinDB&); public: - bool WriteCoinMint(const libzerocoin::PublicCoin& pubCoin, const uint256& txHash); + /** Write zPIV mints to the zerocoinDB in a batch */ + bool WriteCoinMintBatch(const std::vector >& mintInfo); bool ReadCoinMint(const CBigNum& bnPubcoin, uint256& txHash); bool ReadCoinMint(const uint256& hashPubcoin, uint256& hashTx); - bool WriteCoinSpend(const CBigNum& bnSerial, const uint256& txHash); + /** Write zPIV spends to the zerocoinDB in a batch */ + bool WriteCoinSpendBatch(const std::vector >& spendInfo); bool ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash); bool ReadCoinSpend(const uint256& hashSerial, uint256 &txHash); bool EraseCoinMint(const CBigNum& bnPubcoin); diff --git a/src/zpivchain.cpp b/src/zpivchain.cpp index 480d96ce4d83e..8912735716852 100644 --- a/src/zpivchain.cpp +++ b/src/zpivchain.cpp @@ -262,6 +262,8 @@ std::string ReindexZerocoinDB() uiInterface.ShowProgress(_("Reindexing zerocoin database..."), 0); CBlockIndex* pindex = chainActive[Params().Zerocoin_StartHeight()]; + std::vector > vSpendInfo; + std::vector > vMintInfo; while (pindex) { uiInterface.ShowProgress(_("Reindexing zerocoin database..."), std::max(1, std::min(99, (int)((double)(pindex->nHeight - Params().Zerocoin_StartHeight()) / (double)(chainActive.Height() - Params().Zerocoin_StartHeight()) * 100)))); @@ -287,7 +289,7 @@ std::string ReindexZerocoinDB() continue; libzerocoin::CoinSpend spend = TxInToZerocoinSpend(in); - zerocoinDB->WriteCoinSpend(spend.getCoinSerialNumber(), txid); + vSpendInfo.push_back(make_pair(spend, txid)); } } @@ -300,16 +302,31 @@ std::string ReindexZerocoinDB() CValidationState state; libzerocoin::PublicCoin coin(Params().Zerocoin_Params(pindex->nHeight < Params().Zerocoin_Block_V2_Start())); TxOutToPublicCoin(out, coin, state); - zerocoinDB->WriteCoinMint(coin, txid); + vMintInfo.push_back(make_pair(coin, txid)); } } } } } + + // Flush the zerocoinDB to disk every 100 blocks + if (pindex->nHeight % 100 == 0) { + if ((!vSpendInfo.empty() && !zerocoinDB->WriteCoinSpendBatch(vSpendInfo)) || (!vMintInfo.empty() && !zerocoinDB->WriteCoinMintBatch(vMintInfo))) + return _("Error writing zerocoinDB to disk"); + vSpendInfo.clear(); + vMintInfo.clear(); + } + pindex = chainActive.Next(pindex); } uiInterface.ShowProgress("", 100); + // Final flush to disk in case any remaining information exists + if ((!vSpendInfo.empty() && !zerocoinDB->WriteCoinSpendBatch(vSpendInfo)) || (!vMintInfo.empty() && !zerocoinDB->WriteCoinMintBatch(vMintInfo))) + return _("Error writing zerocoinDB to disk"); + + uiInterface.ShowProgress("", 100); + return ""; }