Skip to content

Commit 00cd668

Browse files
committed
Refactor ConnectBlock() to segregate state tracking items from the 'Just Check' section.
- Remove a `WriteBlockIndex` that was in the middle of `ConnectBlock()`. This really shouldn't be in this code at all because the index is written by adding it to a list of dirty. This is very likely what has caused PIVX to especially likely to corrupt on force close. - Remove the auto-repair db code on init. This seems to actually cause more problems than it fixes. - Do not write serials as spent until after the 'Just Check' section. Hold them in a vector until the just check section has passed. - Do not write the accumulator checkpoints until the 'Just Check' section has passed. - Refactor aspects of the zerocoin checks to be within their own functions external to `ConnectBlock()`. Functionally the same, but easier to read.
1 parent 61156de commit 00cd668

File tree

5 files changed

+165
-226
lines changed

5 files changed

+165
-226
lines changed

src/accumulators.cpp

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ bool EraseCheckpoints(int nStartHeight, int nEndHeight)
152152
}
153153

154154
//Get checkpoint value for a specific block height
155-
bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint)
155+
bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint, AccumulatorMap& mapAccumulators)
156156
{
157157
if (nHeight < Params().Zerocoin_StartHeight()) {
158158
nCheckpoint = 0;
@@ -166,7 +166,7 @@ bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint)
166166
}
167167

168168
//set the accumulators to last checkpoint value
169-
AccumulatorMap mapAccumulators;
169+
mapAccumulators.Reset();
170170
if (!mapAccumulators.Load(chainActive[nHeight - 1]->nAccumulatorCheckpoint)) {
171171
if (chainActive[nHeight - 1]->nAccumulatorCheckpoint == 0) {
172172
//Before zerocoin is fully activated so set to init state
@@ -216,14 +216,12 @@ bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint)
216216
//grab mints from this block
217217
CBlock block;
218218
if(!ReadBlockFromDisk(block, pindex)) {
219-
LogPrint("zero","%s: failed to read block from disk\n", __func__);
220-
return false;
219+
return error("%s: failed to read block from disk\n", __func__);
221220
}
222221

223222
std::list<PublicCoin> listPubcoins;
224223
if (!BlockToPubcoinList(block, listPubcoins, fFilterInvalid)) {
225-
LogPrint("zero","%s: failed to get zerocoin mintlist from block %n\n", __func__, pindex->nHeight);
226-
return false;
224+
return error("%s: failed to get zerocoin mintlist from block %d\n", __func__, pindex->nHeight);
227225
}
228226

229227
nTotalMintsFound += listPubcoins.size();
@@ -232,23 +230,18 @@ bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint)
232230
//add the pubcoins to accumulator
233231
for (const PublicCoin pubcoin : listPubcoins) {
234232
if(!mapAccumulators.Accumulate(pubcoin, true)) {
235-
LogPrintf("%s: failed to add pubcoin to accumulator at height %n\n", __func__, pindex->nHeight);
236-
return false;
233+
return error("%s: failed to add pubcoin to accumulator at height %n\n", __func__, pindex->nHeight);
237234
}
238235
}
239236
pindex = chainActive.Next(pindex);
240237
}
241238

242239
// if there were no new mints found, the accumulator checkpoint will be the same as the last checkpoint
243-
if (nTotalMintsFound == 0) {
240+
if (nTotalMintsFound == 0)
244241
nCheckpoint = chainActive[nHeight - 1]->nAccumulatorCheckpoint;
245-
}
246242
else
247243
nCheckpoint = mapAccumulators.GetCheckpoint();
248244

249-
// make sure that these values are databased because reorgs may have deleted the checksums from DB
250-
DatabaseChecksums(mapAccumulators);
251-
252245
LogPrint("zero", "%s checkpoint=%s\n", __func__, nCheckpoint.GetHex());
253246
return true;
254247
}
@@ -258,6 +251,51 @@ bool InvalidCheckpointRange(int nHeight)
258251
return nHeight > Params().Zerocoin_Block_LastGoodCheckpoint() && nHeight < Params().Zerocoin_Block_RecalculateAccumulators();
259252
}
260253

254+
bool ValidateAccumulatorCheckpoint(const CBlock& block, CBlockIndex* pindex, AccumulatorMap& mapAccumulators)
255+
{
256+
if (!fVerifyingBlocks && pindex->nHeight >= Params().Zerocoin_StartHeight() && pindex->nHeight % 10 == 0) {
257+
uint256 nCheckpointCalculated = 0;
258+
259+
// if IDB, invalid outpoints must be calculated or else acc checkpoint will be incorrect
260+
if (pindex->nHeight == Params().Zerocoin_Block_RecalculateAccumulators())
261+
PopulateInvalidOutPointMap();
262+
263+
if (!CalculateAccumulatorCheckpoint(pindex->nHeight, nCheckpointCalculated, mapAccumulators)) {
264+
//Calculate list of checkpoints that may be missing due to deletion on block 809000, and rewinding back before 809000
265+
int nStop = Params().Zerocoin_Block_RecalculateAccumulators() + 20;
266+
if (pindex->nHeight < nStop && pindex->nHeight > Params().Zerocoin_Block_LastGoodCheckpoint()) {
267+
LogPrintf("%s : Checkpoint not found for block %d, recalculating accumulators\n", __func__, pindex->nHeight);
268+
CBlockIndex* pindexCheckpoint = chainActive[Params().Zerocoin_Block_LastGoodCheckpoint()];
269+
list<uint256> listCheckpoints;
270+
while (pindexCheckpoint->nHeight <= nStop) {
271+
if (!count(listCheckpoints.begin(), listCheckpoints.end(), pindexCheckpoint->nAccumulatorCheckpoint))
272+
listCheckpoints.emplace_back(pindexCheckpoint->nAccumulatorCheckpoint);
273+
274+
pindexCheckpoint = chainActive.Next(pindexCheckpoint);
275+
if (!pindexCheckpoint)
276+
break;
277+
}
278+
279+
string strError;
280+
if (!ReindexAccumulators(listCheckpoints, strError) || !CalculateAccumulatorCheckpoint(pindex->nHeight, nCheckpointCalculated, mapAccumulators))
281+
return error("%s : failed to recalculate accumulator checkpoint", __func__);
282+
} else {
283+
return error("%s : failed to calculate accumulator checkpoint", __func__);
284+
}
285+
}
286+
287+
if (nCheckpointCalculated != block.nAccumulatorCheckpoint) {
288+
LogPrintf("%s: block=%d calculated: %s\n block: %s\n", __func__, pindex->nHeight, nCheckpointCalculated.GetHex(), block.nAccumulatorCheckpoint.GetHex());
289+
return error("%s : accumulator does not match calculated value", __func__);
290+
}
291+
} else if (!fVerifyingBlocks) {
292+
if (block.nAccumulatorCheckpoint != pindex->pprev->nAccumulatorCheckpoint)
293+
return error("%s : new accumulator checkpoint generated on a block that is not multiple of 10", __func__);
294+
}
295+
296+
return true;
297+
}
298+
261299
bool GenerateAccumulatorWitness(const PublicCoin &coin, Accumulator& accumulator, AccumulatorWitness& witness, int nSecurityLevel, int& nMintsAdded, string& strError)
262300
{
263301
uint256 txid;

src/accumulators.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,24 @@
66
#define PIVX_ACCUMULATORS_H
77

88
#include "libzerocoin/Accumulator.h"
9-
#include "libzerocoin/Denominations.h"
109
#include "libzerocoin/Coin.h"
10+
#include "libzerocoin/Denominations.h"
1111
#include "primitives/zerocoin.h"
12+
#include "accumulatormap.h"
13+
#include "chain.h"
1214
#include "uint256.h"
1315

1416
bool GenerateAccumulatorWitness(const libzerocoin::PublicCoin &coin, libzerocoin::Accumulator& accumulator, libzerocoin::AccumulatorWitness& witness, int nSecurityLevel, int& nMintsAdded, std::string& strError);
1517
bool GetAccumulatorValueFromDB(uint256 nCheckpoint, libzerocoin::CoinDenomination denom, CBigNum& bnAccValue);
1618
bool GetAccumulatorValueFromChecksum(uint32_t nChecksum, bool fMemoryOnly, CBigNum& bnAccValue);
1719
void AddAccumulatorChecksum(const uint32_t nChecksum, const CBigNum &bnValue, bool fMemoryOnly);
18-
bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint);
20+
bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint, AccumulatorMap& mapAccumulators);
21+
void DatabaseChecksums(AccumulatorMap& mapAccumulators);
1922
bool LoadAccumulatorValuesFromDB(const uint256 nCheckpoint);
2023
bool EraseAccumulatorValues(const uint256& nCheckpointErase, const uint256& nCheckpointPrevious);
2124
uint32_t ParseChecksum(uint256 nChecksum, libzerocoin::CoinDenomination denomination);
2225
uint32_t GetChecksum(const CBigNum &bnValue);
2326
bool InvalidCheckpointRange(int nHeight);
27+
bool ValidateAccumulatorCheckpoint(const CBlock& block, CBlockIndex* pindex, AccumulatorMap& mapAccumulators);
2428

2529
#endif //PIVX_ACCUMULATORS_H

0 commit comments

Comments
 (0)