Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 94 additions & 17 deletions src/accumulators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ void DatabaseChecksums(AccumulatorMap& mapAccumulators)
}
}

bool EraseChecksum(uint32_t nChecksum)
{
//erase from both memory and database
mapAccumulatorValues.erase(nChecksum);
return zerocoinDB->EraseAccumulatorValue(nChecksum);
}

bool EraseAccumulatorValues(const uint256& nCheckpointErase, const uint256& nCheckpointPrevious)
{
for (auto& denomination : zerocoinDenomList) {
Expand All @@ -83,9 +90,7 @@ bool EraseAccumulatorValues(const uint256& nCheckpointErase, const uint256& nChe
if(nChecksumErase == nChecksumPrevious)
continue;

//erase from both memory and database
mapAccumulatorValues.erase(nChecksumErase);
if(!zerocoinDB->EraseAccumulatorValue(nChecksumErase))
if (!EraseChecksum(nChecksumErase))
return false;
}

Expand All @@ -110,6 +115,42 @@ bool LoadAccumulatorValuesFromDB(const uint256 nCheckpoint)
return true;
}

//Erase accumulator checkpoints for a certain block range
bool EraseCheckpoints(int nStartHeight, int nEndHeight)
{
if (chainActive.Height() < nStartHeight)
return false;

nEndHeight = min(chainActive.Height(), nEndHeight);

CBlockIndex* pindex = chainActive[nStartHeight];
uint256 nCheckpointPrev = pindex->pprev->nAccumulatorCheckpoint;

//Keep a list of checkpoints from the previous block so that we don't delete them
list<uint32_t> listCheckpointsPrev;
for (auto denom : zerocoinDenomList)
listCheckpointsPrev.emplace_back(ParseChecksum(nCheckpointPrev, denom));

while (true) {
uint256 nCheckpointDelete = pindex->nAccumulatorCheckpoint;

for (auto denom : zerocoinDenomList) {
uint32_t nChecksumDelete = ParseChecksum(nCheckpointDelete, denom);
if (count(listCheckpointsPrev.begin(), listCheckpointsPrev.end(), nCheckpointDelete))
continue;
EraseChecksum(nChecksumDelete);
}
LogPrintf("%s : erasing checksums for block %d\n", __func__, pindex->nHeight);

if (pindex->nHeight + 1 <= nEndHeight)
pindex = chainActive.Next(pindex);
else
break;
}

return true;
}

//Get checkpoint value for a specific block height
bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint)
{
Expand All @@ -126,7 +167,7 @@ bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint)

//set the accumulators to last checkpoint value
AccumulatorMap mapAccumulators;
if(!mapAccumulators.Load(chainActive[nHeight - 1]->nAccumulatorCheckpoint)) {
if (!mapAccumulators.Load(chainActive[nHeight - 1]->nAccumulatorCheckpoint)) {
if (chainActive[nHeight - 1]->nAccumulatorCheckpoint == 0) {
//Before zerocoin is fully activated so set to init state
mapAccumulators.Reset();
Expand All @@ -136,9 +177,30 @@ bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint)
}
}

//Whether this should filter out invalid/fraudulent outpoints
bool fFilterInvalid = nHeight >= Params().Zerocoin_Block_RecalculateAccumulators();

//Accumulate all coins over the last ten blocks that havent been accumulated (height - 20 through height - 11)
int nTotalMintsFound = 0;
CBlockIndex *pindex = chainActive[nHeight - 20];

//On a specific block, a recalculation of the accumulators will be forced
if (nHeight == Params().Zerocoin_Block_RecalculateAccumulators()) {
pindex = chainActive[Params().Zerocoin_Block_LastGoodCheckpoint() - 10];
mapAccumulators.Reset();
if (!mapAccumulators.Load(chainActive[Params().Zerocoin_Block_LastGoodCheckpoint()]->nAccumulatorCheckpoint)) {
LogPrintf("%s: failed to reset to previous checkpoint when recalculating accumulators\n", __func__);
return false;
}
LogPrintf("*** %s recalculating checkpoint\n", __func__);

// Erase the checkpoints from the period of time that bad mints were being made
if (!EraseCheckpoints(Params().Zerocoin_Block_LastGoodCheckpoint() + 1, nHeight)) {
LogPrintf("%s : failed to erase Checkpoints while recalculating checkpoints\n", __func__);
return false;
}
}

while (pindex->nHeight < nHeight - 10) {
// checking whether we should stop this process due to a shutdown request
if (ShutdownRequested()) {
Expand All @@ -157,8 +219,9 @@ bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint)
LogPrint("zero","%s: failed to read block from disk\n", __func__);
return false;
}

std::list<PublicCoin> listPubcoins;
if(!BlockToPubcoinList(block, listPubcoins)) {
if (!BlockToPubcoinList(block, listPubcoins, fFilterInvalid)) {
LogPrint("zero","%s: failed to get zerocoin mintlist from block %n\n", __func__, pindex->nHeight);
return false;
}
Expand All @@ -167,7 +230,7 @@ bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint)
LogPrint("zero", "%s found %d mints\n", __func__, listPubcoins.size());

//add the pubcoins to accumulator
for(const PublicCoin pubcoin : listPubcoins) {
for (const PublicCoin pubcoin : listPubcoins) {
if(!mapAccumulators.Accumulate(pubcoin, true)) {
LogPrintf("%s: failed to add pubcoin to accumulator at height %n\n", __func__, pindex->nHeight);
return false;
Expand All @@ -190,6 +253,11 @@ bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint)
return true;
}

bool InvalidCheckpointRange(int nHeight)
{
return nHeight > Params().Zerocoin_Block_LastGoodCheckpoint() && nHeight < Params().Zerocoin_Block_RecalculateAccumulators();
}

bool GenerateAccumulatorWitness(const PublicCoin &coin, Accumulator& accumulator, AccumulatorWitness& witness, int nSecurityLevel, int& nMintsAdded, string& strError)
{
uint256 txid;
Expand All @@ -206,7 +274,7 @@ bool GenerateAccumulatorWitness(const PublicCoin &coin, Accumulator& accumulator
}

int nHeightMintAdded= mapBlockIndex[hashBlock]->nHeight;
uint256 nCheckpointBeforeMint = 0, nCheckpointContainingMint = 0;
uint256 nCheckpointBeforeMint = 0;
CBlockIndex* pindex = chainActive[nHeightMintAdded];
int nChanges = 0;

Expand All @@ -220,20 +288,26 @@ bool GenerateAccumulatorWitness(const PublicCoin &coin, Accumulator& accumulator

//check if the next checksum was generated
if (pindex->nHeight % 10 == 0) {
nCheckpointContainingMint = pindex->nAccumulatorCheckpoint;
nChanges++;

if (nChanges == 1)
nCheckpointBeforeMint = pindex->nAccumulatorCheckpoint;
else if (nChanges == 2)
break;
}
pindex = chainActive[pindex->nHeight + 1];
pindex = chainActive.Next(pindex);
}

//the height to start accumulating coins to add to witness
int nAccStartHeight = nHeightMintAdded - (nHeightMintAdded % 10);

//If the checkpoint is from the recalculated checkpoint period, then adjust it
int nHeight_LastGoodCheckpoint = Params().Zerocoin_Block_LastGoodCheckpoint();
int nHeight_Recalculate = Params().Zerocoin_Block_RecalculateAccumulators();
if (pindex->nHeight < nHeight_Recalculate - 10 && pindex->nHeight > nHeight_LastGoodCheckpoint) {
//The checkpoint before the mint will be the last good checkpoint
nCheckpointBeforeMint = chainActive[nHeight_LastGoodCheckpoint]->nAccumulatorCheckpoint;
nAccStartHeight = nHeight_LastGoodCheckpoint - 10;
}

//Get the accumulator that is right before the cluster of blocks containing our mint was added to the accumulator
CBigNum bnAccValue = 0;
if (GetAccumulatorValueFromDB(nCheckpointBeforeMint, coin.getDenomination(), bnAccValue)) {
Expand Down Expand Up @@ -268,7 +342,7 @@ bool GenerateAccumulatorWitness(const PublicCoin &coin, Accumulator& accumulator

//if a new checkpoint was generated on this block, and we have added the specified amount of checkpointed accumulators,
//then initialize the accumulator at this point and break
if (pindex->nHeight == nHeightStop || (nSecurityLevel != 100 && nCheckpointsAdded >= nSecurityLevel)) {
if (!InvalidCheckpointRange(pindex->nHeight) && (pindex->nHeight == nHeightStop || (nSecurityLevel != 100 && nCheckpointsAdded >= nSecurityLevel))) {
uint32_t nChecksum = ParseChecksum(chainActive[pindex->nHeight + 10]->nAccumulatorCheckpoint, coin.getDenomination());
CBigNum bnAccValue = 0;
if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnAccValue)) {
Expand All @@ -288,18 +362,21 @@ bool GenerateAccumulatorWitness(const PublicCoin &coin, Accumulator& accumulator
return false;
}

std::vector<CBigNum> vValues;
if(!BlockToMintValueVector(block, coin.getDenomination(), vValues)) {
list<PublicCoin> listPubcoins;
if(!BlockToPubcoinList(block, listPubcoins, true)) {
LogPrintf("%s: failed to get zerocoin mintlist from block %n\n", __func__, pindex->nHeight);
return false;
}

//add the mints to the witness
for (const CBigNum bnValue : vValues) {
if(pindex->nHeight == nHeightMintAdded && bnValue == coin.getValue())
for (const PublicCoin pubcoin : listPubcoins) {
if (pubcoin.getDenomination() != coin.getDenomination())
continue;

if (pindex->nHeight == nHeightMintAdded && pubcoin.getValue() == coin.getValue())
continue;

witness.addRawValue(bnValue);
witness.addRawValue(pubcoin.getValue());
++nMintsAdded;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/accumulators.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ bool LoadAccumulatorValuesFromDB(const uint256 nCheckpoint);
bool EraseAccumulatorValues(const uint256& nCheckpointErase, const uint256& nCheckpointPrevious);
uint32_t ParseChecksum(uint256 nChecksum, libzerocoin::CoinDenomination denomination);
uint32_t GetChecksum(const CBigNum &bnValue);
bool InvalidCheckpointRange(int nHeight);

#endif //PIVX_ACCUMULATORS_H
12 changes: 9 additions & 3 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,13 @@ static Checkpoints::MapCheckpoints mapCheckpoints =
(863795, uint256("2ad866818c4866e0d555181daccc628056216c0db431f88a825e84ed4f469067"))
(863805, uint256("a755bd9a22b63c70d3db474f4b2b61a1f86c835b290a081bb3ec1ba2103eb4cb"))
(867733, uint256("03b26296bf693de5782c76843d2fb649cb66d4b05550c6a79c047ff7e1c3ae15"))
(879650, uint256("227e1d2b738b6cd83c46d1d64617934ec899d77cee34336a56e61b71acd10bb2"));
(879650, uint256("227e1d2b738b6cd83c46d1d64617934ec899d77cee34336a56e61b71acd10bb2"))
(895400, uint256("7796a0274a608fac12d400198174e50beda992c1d522e52e5b95b884bc1beac6"))//block that serial# range is enforced
(895991, uint256("d53013ed7ea5c325b9696c95e07667d6858f8ff7ee13fecfa90827bf3c9ae316"));//network split here
static const Checkpoints::CCheckpointData data = {
&mapCheckpoints,
1509225216, // * UNIX timestamp of last checkpoint block
1770098, // * total number of transactions between genesis and last checkpoint
1510187238, // * UNIX timestamp of last checkpoint block
1816040, // * total number of transactions between genesis and last checkpoint
// (the tx=... number in the SetBestChain debug.log lines)
2000 // * estimated number of transactions per day after checkpoint
};
Expand Down Expand Up @@ -132,6 +134,10 @@ class CMainParams : public CChainParams
nLastPOWBlock = 259200;
nModifierUpdateBlock = 615800;
nZerocoinStartHeight = 863787;
nBlockEnforceSerialRange = 895400; //Enforce serial range starting this block
nBlockRecalculateAccumulators = 908000; //Trigger a recalculation of accumulators
nBlockFirstFraudulent = 891737; //First block that bad serials emerged
nBlockLastGoodCheckpoint = 891730; //Last valid accumulator checkpoint

/**
* Build the genesis block. Note that the output of the genesis coinbase cannot
Expand Down
8 changes: 8 additions & 0 deletions src/chainparams.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ class CChainParams
int ModifierUpgradeBlock() const { return nModifierUpdateBlock; }
int LAST_POW_BLOCK() const { return nLastPOWBlock; }
int Zerocoin_StartHeight() const { return nZerocoinStartHeight; }
int Zerocoin_Block_EnforceSerialRange() const { return nBlockEnforceSerialRange; }
int Zerocoin_Block_RecalculateAccumulators() const { return nBlockRecalculateAccumulators; }
int Zerocoin_Block_FirstFraudulent() const { return nBlockFirstFraudulent; }
int Zerocoin_Block_LastGoodCheckpoint() const { return nBlockLastGoodCheckpoint; }

protected:
CChainParams() {}
Expand Down Expand Up @@ -162,6 +166,10 @@ class CChainParams
int nZerocoinHeaderVersion;
int64_t nBudget_Fee_Confirmations;
int nZerocoinStartHeight;
int nBlockEnforceSerialRange;
int nBlockRecalculateAccumulators;
int nBlockFirstFraudulent;
int nBlockLastGoodCheckpoint;
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/coins.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ class CCoins
//! check whether a particular output is still available
bool IsAvailable(unsigned int nPos) const
{
return (nPos < vout.size() && !vout[nPos].IsNull());
return (nPos < vout.size() && !vout[nPos].IsNull() && !vout[nPos].scriptPubKey.IsZerocoinMint());
}

//! check whether the entire CCoins is spent
Expand Down
Loading