bool InitializeAccumulators(const int nHeight, int& nHeightCheckpoint, AccumulatorMap& mapAccumulators)
{
    if (nHeight < Params().Zerocoin_StartHeight())
        return error("%s: height is below zerocoin activated", __func__);

    //On a specific block, a recalculation of the accumulators will be forced
    if (nHeight == Params().Zerocoin_Block_RecalculateAccumulators() && Params().NetworkID() != CBaseChainParams::REGTEST) {
        mapAccumulators.Reset();
        if (!mapAccumulators.Load(chainActive[Params().Zerocoin_Block_LastGoodCheckpoint()]->nAccumulatorCheckpoint))
            return error("%s: failed to reset to previous checkpoint when recalculating accumulators", __func__);

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

        nHeightCheckpoint = Params().Zerocoin_Block_LastGoodCheckpoint();
        return true;
    }

    if (nHeight >= Params().Zerocoin_Block_V2_Start()) {
        //after v2_start, accumulators need to use v2 params
        mapAccumulators.Reset(Params().Zerocoin_Params(false));

        // 20 after v2 start is when the new checkpoints will be in the block, so don't need to load hard checkpoints
        if (nHeight <= Params().Zerocoin_Block_V2_Start() + 20 && Params().NetworkID() != CBaseChainParams::REGTEST) {
            //Load hard coded checkpointed value
            AccumulatorCheckpoints::Checkpoint checkpoint = AccumulatorCheckpoints::GetClosestCheckpoint(nHeight,
                                                                                                         nHeightCheckpoint);
            if (nHeightCheckpoint < 0)
                return error("%s: failed to load hard-checkpoint for block %s", __func__, nHeight);

            mapAccumulators.Load(checkpoint);
            return true;
        }
    }

    //Use the previous block's checkpoint to initialize the accumulator's state
    uint256 nCheckpointPrev = chainActive[nHeight - 1]->nAccumulatorCheckpoint;
    if (nCheckpointPrev == 0)
        mapAccumulators.Reset();
    else if (!mapAccumulators.Load(nCheckpointPrev))
        return error("%s: failed to reset to previous checkpoint", __func__);

    nHeightCheckpoint = nHeight;
    return true;
}
Exemple #2
0
//Get checkpoint value for a specific block height
bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint)
{
    if (nHeight < Params().Zerocoin_StartHeight()) {
        nCheckpoint = 0;
        return true;
    }

    //the checkpoint is updated every ten blocks, return current active checkpoint if not update block
    if (nHeight % 10 != 0) {
        nCheckpoint = chainActive[nHeight - 1]->nAccumulatorCheckpoint;
        return true;
    }

    //set the accumulators to last checkpoint value
    AccumulatorMap mapAccumulators;
    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();
        } else {
            LogPrintf("%s: failed to reset to previous checkpoint\n", __func__);
            return false;
        }
    }

    //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()) {
            return false;
        }

        //make sure this block is eligible for accumulation
        if (pindex->nHeight < Params().Zerocoin_StartHeight()) {
            pindex = chainActive[pindex->nHeight + 1];
            continue;
        }

        //grab mints from this block
        CBlock block;
        if(!ReadBlockFromDisk(block, pindex)) {
            LogPrint("zero","%s: failed to read block from disk\n", __func__);
            return false;
        }

        std::list<PublicCoin> listPubcoins;
        if (!BlockToPubcoinList(block, listPubcoins, fFilterInvalid)) {
            LogPrint("zero","%s: failed to get zerocoin mintlist from block %n\n", __func__, pindex->nHeight);
            return false;
        }

        nTotalMintsFound += listPubcoins.size();
        LogPrint("zero", "%s found %d mints\n", __func__, listPubcoins.size());

        //add the pubcoins to accumulator
        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;
            }
        }
        pindex = chainActive.Next(pindex);
    }

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

    // make sure that these values are databased because reorgs may have deleted the checksums from DB
    DatabaseChecksums(mapAccumulators);

    LogPrint("zero", "%s checkpoint=%s\n", __func__, nCheckpoint.GetHex());
    return true;
}
bool GenerateAccumulatorWitness(CoinWitnessData* coinWitness, AccumulatorMap& mapAccumulators, CBlockIndex* pindexCheckpoint)
{
    try {
        // Lock
        LogPrint("zero", "%s: generating\n", __func__);
        if (!LockMethod()) return false;
        LogPrint("zero", "%s: after lock\n", __func__);

        int64_t nTimeStart = GetTimeMicros();

        //If there is a Acc End height filled in, then this has already been partially accumulated.
        if (!coinWitness->nHeightAccEnd) {
            LogPrintf("RESET ACC\n");
            coinWitness->pAccumulator = std::unique_ptr<Accumulator>(new Accumulator(Params().Zerocoin_Params(false), coinWitness->denom));
            coinWitness->pWitness = std::unique_ptr<AccumulatorWitness>(new AccumulatorWitness(Params().Zerocoin_Params(false), *coinWitness->pAccumulator, *coinWitness->coin));
        }

        // Mint added height
        coinWitness->SetHeightMintAdded(SearchMintHeightOf(coinWitness->coin->getValue()));

        // Set the initial state of the witness accumulator for this coin.
        CBigNum bnAccValue = 0;
        if (!coinWitness->nHeightAccEnd && GetAccumulatorValue(coinWitness->nHeightCheckpoint, coinWitness->coin->getDenomination(), bnAccValue)) {
            libzerocoin::Accumulator witnessAccumulator(Params().Zerocoin_Params(false), coinWitness->denom, bnAccValue);
            coinWitness->pAccumulator->setValue(witnessAccumulator.getValue());
        }

        //add the pubcoins from the blockchain up to the next checksum starting from the block
        int nChainHeight = chainActive.Height();
        int nHeightMax = nChainHeight % 10;
        nHeightMax = nChainHeight - nHeightMax - 20; // at least two checkpoints deep

        // Determine the height to stop at
        int nHeightStop;
        if (pindexCheckpoint) {
            nHeightStop = pindexCheckpoint->nHeight - 10;
            nHeightStop -= nHeightStop % 10;
            LogPrint("zero", "%s: using checkpoint height %d\n", __func__, pindexCheckpoint->nHeight);
        } else {
            nHeightStop = nHeightMax;
        }

        if (nHeightStop > coinWitness->nHeightAccEnd)
            AccumulateRange(coinWitness, nHeightStop - 1);

        mapAccumulators.Load(chainActive[nHeightStop + 10]->nAccumulatorCheckpoint);
        coinWitness->pWitness->resetValue(*coinWitness->pAccumulator, *coinWitness->coin);
        if(!coinWitness->pWitness->VerifyWitness(mapAccumulators.GetAccumulator(coinWitness->denom), *coinWitness->coin))
            return error("%s: failed to verify witness", __func__);

        // A certain amount of accumulated coins are required
        if (coinWitness->nMintsAdded < Params().Zerocoin_RequiredAccumulation())
            return error("%s : Less than %d mints added, unable to create spend. %s", __func__, Params().Zerocoin_RequiredAccumulation(), coinWitness->ToString());

        // calculate how many mints of this denomination existed in the accumulator we initialized
        coinWitness->nMintsAdded += ComputeAccumulatedCoins(coinWitness->nHeightAccStart, coinWitness->denom);
        LogPrint("zero", "%s : %d mints added to witness\n", __func__, coinWitness->nMintsAdded);

        int64_t nTime1 = GetTimeMicros();
        LogPrint("bench", "        - Witness generated in %.2fms\n", 0.001 * (nTime1 - nTimeStart));

        return true;

        // TODO: I know that could merge all of this exception but maybe it's not really good.. think if we should have a different treatment for each one
    } catch (searchMintHeightException e) {
        return error("%s: searchMintHeightException: %s", __func__, e.message);
    } catch (ChecksumInDbNotFoundException e) {
        return error("%s: ChecksumInDbNotFoundException: %s", __func__, e.message);
    } catch (GetPubcoinException e) {
        return error("%s: GetPubcoinException: %s", __func__, e.message);
    }
}