diff --git a/src/Makefile.am b/src/Makefile.am index d594050f318f..57d50944402c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,6 +77,8 @@ endif # pivx core # BITCOIN_CORE_H = \ activemasternode.h \ + accumulators.h \ + accumulatormap.h \ addrman.h \ alert.h \ allocators.h \ @@ -169,7 +171,6 @@ BITCOIN_CORE_H = \ zmq/zmqconfig.h \ zmq/zmqnotificationinterface.h \ zmq/zmqpublishnotifier.h \ - accumulators.h \ compat/sanity.h JSON_H = \ @@ -334,6 +335,8 @@ libzerocoin_libbitcoin_zerocoin_a_SOURCES = \ # common: shared between pivxd, and pivx-qt and non-server tools libbitcoin_common_a_CPPFLAGS = $(BITCOIN_INCLUDES) libbitcoin_common_a_SOURCES = \ + accumulators.cpp \ + accumulatormap.cpp \ allocators.cpp \ amount.cpp \ base58.cpp \ @@ -361,7 +364,6 @@ libbitcoin_common_a_SOURCES = \ script/script_error.cpp \ spork.cpp \ sporkdb.cpp \ - accumulators.cpp \ $(BITCOIN_CORE_H) # util: shared between all executables. diff --git a/src/accumulatormap.cpp b/src/accumulatormap.cpp new file mode 100644 index 000000000000..0f98c7eb7077 --- /dev/null +++ b/src/accumulatormap.cpp @@ -0,0 +1,88 @@ +// Copyright (c) 2017 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "accumulatormap.h" +#include "accumulators.h" +#include "main.h" +#include "txdb.h" +#include "libzerocoin/Denominations.h" + +using namespace libzerocoin; +using namespace std; + +//Construct accumulators for all denominations +AccumulatorMap::AccumulatorMap() +{ + for (auto& denom : zerocoinDenomList) { + unique_ptr uptr(new Accumulator(Params().Zerocoin_Params(), denom)); + mapAccumulators.insert(make_pair(denom, std::move(uptr))); + } +} + +//Reset each accumulator to its default state +void AccumulatorMap::Reset() +{ + mapAccumulators.clear(); + for (auto& denom : zerocoinDenomList) { + unique_ptr uptr(new Accumulator(Params().Zerocoin_Params(), denom)); + mapAccumulators.insert(make_pair(denom, std::move(uptr))); + } +} + +//Load a checkpoint containing 8 32bit checksums of accumulator values. +bool AccumulatorMap::Load(uint256 nCheckpoint) +{ + for (auto& denom : zerocoinDenomList) { + uint32_t nChecksum = ParseChecksum(nCheckpoint, denom); + + CBigNum bnValue; + if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnValue)) { + LogPrintf("%s : cannot find checksum %d", __func__, nChecksum); + return false; + } + + mapAccumulators.at(denom)->setValue(bnValue); + } + return true; +} + +//Add a zerocoin to the accumulator of its denomination. +bool AccumulatorMap::Accumulate(PublicCoin pubCoin, bool fSkipValidation) +{ + CoinDenomination denom = pubCoin.getDenomination(); + if (denom == CoinDenomination::ZQ_ERROR) + return false; + + if (fSkipValidation) + mapAccumulators.at(denom)->increment(pubCoin.getValue()); + else + mapAccumulators.at(denom)->accumulate(pubCoin); + return true; +} + +//Get the value of a specific accumulator +CBigNum AccumulatorMap::GetValue(CoinDenomination denom) +{ + if (denom == CoinDenomination::ZQ_ERROR) + return CBigNum(0); + return mapAccumulators.at(denom)->getValue(); +} + +//Calculate a 32bit checksum of each accumulator value. Concatenate checksums into uint256 +uint256 AccumulatorMap::GetCheckpoint() +{ + uint256 nCheckpoint; + + //Prevent possible overflows from future changes to the list and forgetting to update this code + assert(zerocoinDenomList.size() == 8); + for (auto& denom : zerocoinDenomList) { + CBigNum bnValue = mapAccumulators.at(denom)->getValue(); + uint32_t nCheckSum = GetChecksum(bnValue); + nCheckpoint = nCheckpoint << 32 | nCheckSum; + } + + return nCheckpoint; +} + + diff --git a/src/accumulatormap.h b/src/accumulatormap.h new file mode 100644 index 000000000000..15ee3b0450ae --- /dev/null +++ b/src/accumulatormap.h @@ -0,0 +1,23 @@ +// Copyright (c) 2017 The PIVX developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#ifndef PIVX_ACCUMULATORMAP_H +#define PIVX_ACCUMULATORMAP_H + +#include "libzerocoin/Accumulator.h" +#include "libzerocoin/Coin.h" + +//A map with an accumulator for each denomination +class AccumulatorMap +{ +private: + std::map > mapAccumulators; +public: + AccumulatorMap(); + bool Load(uint256 nCheckpoint); + bool Accumulate(libzerocoin::PublicCoin pubCoin, bool fSkipValidation = false); + CBigNum GetValue(libzerocoin::CoinDenomination denom); + uint256 GetCheckpoint(); + void Reset(); +}; +#endif //PIVX_ACCUMULATORMAP_H diff --git a/src/accumulators.cpp b/src/accumulators.cpp index 05b36ffede71..7be36d14fbe2 100644 --- a/src/accumulators.cpp +++ b/src/accumulators.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "accumulators.h" +#include "accumulatormap.h" #include "chainparams.h" #include "main.h" #include "txdb.h" @@ -11,34 +12,18 @@ using namespace libzerocoin; -void CAccumulators::Setup() -{ - //construct accumulators for all denominations - for (auto& denom : zerocoinDenomList) { - unique_ptr uptr(new Accumulator(Params().Zerocoin_Params(), denom)); - mapAccumulators.insert(make_pair(denom, std::move(uptr))); - } -} - -Accumulator CAccumulators::Get(CoinDenomination denomination) -{ - return Accumulator(Params().Zerocoin_Params(), denomination, mapAccumulators.at(denomination)->getValue()); -} +std::map mapAccumulatorValues; +std::list listAccCheckpointsNoDB; -bool CAccumulators::AddPubCoinToAccumulator(const PublicCoin& publicCoin) +uint32_t ParseChecksum(uint256 nChecksum, CoinDenomination denomination) { - CoinDenomination denomination = publicCoin.getDenomination(); - if(mapAccumulators.find(denomination) == mapAccumulators.end()) { - LogPrintf("%s: failed to find accumulator for %d\n", __func__, denomination); - return false; - } - - mapAccumulators.at(denomination)->accumulate(publicCoin); - LogPrint("zero", "%s: Accumulated %d\n", __func__, denomination); - return true; + //shift to the beginning bit of this denomination and trim any remaining bits by returning 32 bits only + int pos = distance(zerocoinDenomList.begin(), find(zerocoinDenomList.begin(), zerocoinDenomList.end(), denomination)); + nChecksum = nChecksum >> (32*((zerocoinDenomList.size() - 1) - pos)); + return nChecksum.Get32(); } -uint32_t CAccumulators::GetChecksum(const CBigNum &bnValue) +uint32_t GetChecksum(const CBigNum &bnValue) { CDataStream ss(SER_GETHASH, 0); ss << bnValue; @@ -47,51 +32,48 @@ uint32_t CAccumulators::GetChecksum(const CBigNum &bnValue) return hash.Get32(); } -uint32_t CAccumulators::GetChecksum(const Accumulator &accumulator) +bool GetAccumulatorValueFromChecksum(uint32_t nChecksum, bool fMemoryOnly, CBigNum& bnAccValue) { - return GetChecksum(accumulator.getValue()); + if (mapAccumulatorValues.count(nChecksum)) { + bnAccValue = mapAccumulatorValues.at(nChecksum); + return true; + } + + if (fMemoryOnly) + return false; + + if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnAccValue)) { + bnAccValue = 0; + } + + return true; } -void CAccumulators::DatabaseChecksums(const uint256& nCheckpoint) +bool GetAccumulatorValueFromDB(uint256 nCheckpoint, CoinDenomination denom, CBigNum& bnAccValue) { - uint256 nCheckpointCalculated = 0; - for (auto& denom : zerocoinDenomList) { - CBigNum bnValue = mapAccumulators.at(denom)->getValue(); - uint32_t nCheckSum = GetChecksum(bnValue); - AddAccumulatorChecksum(nCheckSum, bnValue); - nCheckpointCalculated = nCheckpointCalculated << 32 | nCheckSum; - } + uint32_t nChecksum = ParseChecksum(nCheckpoint, denom); + return GetAccumulatorValueFromChecksum(nChecksum, false, bnAccValue); } -void CAccumulators::AddAccumulatorChecksum(const uint32_t nChecksum, const CBigNum &bnValue, bool fMemoryOnly) +void AddAccumulatorChecksum(const uint32_t nChecksum, const CBigNum &bnValue, bool fMemoryOnly) { if(!fMemoryOnly) zerocoinDB->WriteAccumulatorValue(nChecksum, bnValue); mapAccumulatorValues.insert(make_pair(nChecksum, bnValue)); - - LogPrint("zero", "%s checksum %d val %s\n", __func__, nChecksum, bnValue.GetHex()); - LogPrint("zero", "%s map val %s\n", __func__, mapAccumulatorValues[nChecksum].GetHex()); } -bool CAccumulators::LoadAccumulatorValuesFromDB(const uint256 nCheckpoint) +void DatabaseChecksums(AccumulatorMap& mapAccumulators) { - for (auto& denomination : zerocoinDenomList) { - uint32_t nChecksum = ParseChecksum(nCheckpoint, denomination); - - //if read is not successful then we are not in a state to verify zerocoin transactions - CBigNum bnValue; - if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnValue)) { - LogPrint("zero","%s : Missing databased value for checksum %d\n", __func__, nChecksum); - if (!count(listAccCheckpointsNoDB.begin(), listAccCheckpointsNoDB.end(), nCheckpoint)) - listAccCheckpointsNoDB.push_back(nCheckpoint); - return false; - } - mapAccumulatorValues.insert(make_pair(nChecksum, bnValue)); + uint256 nCheckpoint = 0; + for (auto& denom : zerocoinDenomList) { + CBigNum bnValue = mapAccumulators.GetValue(denom); + uint32_t nCheckSum = GetChecksum(bnValue); + AddAccumulatorChecksum(nCheckSum, bnValue, false); + nCheckpoint = nCheckpoint << 32 | nCheckSum; } - return true; } -bool CAccumulators::EraseAccumulatorValues(const uint256& nCheckpointErase, const uint256& nCheckpointPrevious) +bool EraseAccumulatorValues(const uint256& nCheckpointErase, const uint256& nCheckpointPrevious) { for (auto& denomination : zerocoinDenomList) { uint32_t nChecksumErase = ParseChecksum(nCheckpointErase, denomination); @@ -110,82 +92,28 @@ bool CAccumulators::EraseAccumulatorValues(const uint256& nCheckpointErase, cons return true; } -bool CAccumulators::EraseCoinMint(const CBigNum& bnPubCoin) -{ - return zerocoinDB->EraseCoinMint(bnPubCoin); -} - -bool CAccumulators::EraseCoinSpend(const CBigNum& bnSerial) -{ - mapSerials.erase(bnSerial); - return zerocoinDB->EraseCoinSpend(bnSerial); -} - -uint32_t ParseChecksum(uint256 nChecksum, CoinDenomination denomination) +bool LoadAccumulatorValuesFromDB(const uint256 nCheckpoint) { - //shift to the beginning bit of this denomination and trim any remaining bits by returning 32 bits only - int pos = distance(zerocoinDenomList.begin(), find(zerocoinDenomList.begin(), zerocoinDenomList.end(), denomination)); - nChecksum = nChecksum >> (32*((zerocoinDenomList.size() - 1) - pos)); - return nChecksum.Get32(); -} - -CBigNum CAccumulators::GetAccumulatorValueFromCheckpoint(const uint256& nCheckpoint, CoinDenomination denomination) -{ - uint32_t nDenominationChecksum = ParseChecksum(nCheckpoint, denomination); - LogPrint("zero", "%s checkpoint:%d\n", __func__, nCheckpoint.GetHex()); - LogPrint("zero", "%s checksum:%d\n", __func__, nDenominationChecksum); - - return GetAccumulatorValueFromChecksum(nDenominationChecksum); -} - -CBigNum CAccumulators::GetAccumulatorValueFromChecksum(const uint32_t& nChecksum) -{ - if(!mapAccumulatorValues.count(nChecksum)) - return CBigNum(0); - - return mapAccumulatorValues[nChecksum]; -} + for (auto& denomination : zerocoinDenomList) { + uint32_t nChecksum = ParseChecksum(nCheckpoint, denomination); -//set all of the accumulators held by mapAccumulators to a certain checkpoint -bool CAccumulators::ResetToCheckpoint(const uint256& nCheckpoint) -{ - for (auto& denom : zerocoinDenomList) { - CBigNum bnValue = GetAccumulatorValueFromCheckpoint(nCheckpoint, denom); - if (bnValue == 0) { - //if the value is zero, then this is an unused accumulator and must be reinitialized - unique_ptr uptr(new Accumulator(Params().Zerocoin_Params(), denom)); - mapAccumulators.at(denom) = std::move(uptr); - continue; + //if read is not successful then we are not in a state to verify zerocoin transactions + CBigNum bnValue; + if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnValue)) { + LogPrint("zero","%s : Missing databased value for checksum %d\n", __func__, nChecksum); + if (!count(listAccCheckpointsNoDB.begin(), listAccCheckpointsNoDB.end(), nCheckpoint)) + listAccCheckpointsNoDB.push_back(nCheckpoint); + return false; } - - mapAccumulators.at(denom)->setValue(bnValue); + mapAccumulatorValues.insert(make_pair(nChecksum, bnValue)); } - return true; } -//Get checkpoint value from the current state of our accumulator map -uint256 CAccumulators::GetCheckpoint() -{ - uint256 nCheckpoint; - for (auto& denom : zerocoinDenomList) { - CBigNum bnValue = mapAccumulators.at(denom)->getValue(); - uint32_t nCheckSum = GetChecksum(bnValue); - AddAccumulatorChecksum(nCheckSum, bnValue); - nCheckpoint = nCheckpoint << 32 | nCheckSum; - - LogPrint("zero", "%s: Acc value:%s\n", __func__, bnValue.GetHex()); - LogPrint("zero", "%s: checksum value:%d\n", __func__, nCheckSum); - LogPrint("zero", "%s: checkpoint %s\n", __func__, nCheckpoint.GetHex()); - } - - return nCheckpoint; -} - //Get checkpoint value for a specific block height -bool CAccumulators::GetCheckpoint(int nHeight, uint256& nCheckpoint) +bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint) { - if (nHeight <= chainActive.Height() && chainActive[nHeight]->GetBlockHeader().nVersion < Params().Zerocoin_HeaderVersion()) { + if (nHeight < Params().Zerocoin_StartHeight()) { nCheckpoint = 0; return true; } @@ -197,9 +125,15 @@ bool CAccumulators::GetCheckpoint(int nHeight, uint256& nCheckpoint) } //set the accumulators to last checkpoint value - if(!ResetToCheckpoint(chainActive[nHeight - 1]->nAccumulatorCheckpoint)) { - LogPrint("zero","%s: failed to reset to previous checkpoint\n", __func__); - return false; + 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; + } } //Accumulate all coins over the last ten blocks that havent been accumulated (height - 20 through height - 11) @@ -212,7 +146,7 @@ bool CAccumulators::GetCheckpoint(int nHeight, uint256& nCheckpoint) } //make sure this block is eligible for accumulation - if (pindex->GetBlockHeader().nVersion < Params().Zerocoin_HeaderVersion()) { + if (pindex->nHeight < Params().Zerocoin_StartHeight()) { pindex = chainActive[pindex->nHeight + 1]; continue; } @@ -234,29 +168,29 @@ bool CAccumulators::GetCheckpoint(int nHeight, uint256& nCheckpoint) //add the pubcoins to accumulator for(const PublicCoin pubcoin : listPubcoins) { - if(!AddPubCoinToAccumulator(pubcoin)) { - LogPrint("zero","%s: failed to add pubcoin to accumulator at height %n\n", __func__, pindex->nHeight); + if(!mapAccumulators.Accumulate(pubcoin, true)) { + LogPrintf("%s: failed to add pubcoin to accumulator at height %n\n", __func__, pindex->nHeight); return false; } } - pindex = chainActive[pindex->nHeight + 1]; + 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; - - // make sure that these values are databased because reorgs may have deleted the checksums from DB - DatabaseChecksums(nCheckpoint); } else - nCheckpoint = GetCheckpoint(); + 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 CAccumulators::IntializeWitnessAndAccumulator(const PublicCoin &coin, Accumulator& accumulator, AccumulatorWitness& witness, int nSecurityLevel, int& nMintsAdded, string& strError) +bool GenerateAccumulatorWitness(const PublicCoin &coin, Accumulator& accumulator, AccumulatorWitness& witness, int nSecurityLevel, int& nMintsAdded, string& strError) { uint256 txid; if (!zerocoinDB->ReadCoinMint(coin.getValue(), txid)) { @@ -272,7 +206,7 @@ bool CAccumulators::IntializeWitnessAndAccumulator(const PublicCoin &coin, Accum } int nHeightMintAdded= mapBlockIndex[hashBlock]->nHeight; - uint256 nChecksumBeforeMint = 0, nChecksumContainingMint = 0; + uint256 nCheckpointBeforeMint = 0, nCheckpointContainingMint = 0; CBlockIndex* pindex = chainActive[nHeightMintAdded]; int nChanges = 0; @@ -286,11 +220,11 @@ bool CAccumulators::IntializeWitnessAndAccumulator(const PublicCoin &coin, Accum //check if the next checksum was generated if (pindex->nHeight % 10 == 0) { - nChecksumContainingMint = pindex->nAccumulatorCheckpoint; + nCheckpointContainingMint = pindex->nAccumulatorCheckpoint; nChanges++; if (nChanges == 1) - nChecksumBeforeMint = pindex->nAccumulatorCheckpoint; + nCheckpointBeforeMint = pindex->nAccumulatorCheckpoint; else if (nChanges == 2) break; } @@ -301,10 +235,12 @@ bool CAccumulators::IntializeWitnessAndAccumulator(const PublicCoin &coin, Accum int nAccStartHeight = nHeightMintAdded - (nHeightMintAdded % 10); //Get the accumulator that is right before the cluster of blocks containing our mint was added to the accumulator - CBigNum bnAccValue = GetAccumulatorValueFromCheckpoint(nChecksumBeforeMint, coin.getDenomination()); - if (bnAccValue != 0) { - accumulator.setValue(bnAccValue); - witness.resetValue(accumulator, coin); + CBigNum bnAccValue = 0; + if (GetAccumulatorValueFromDB(nCheckpointBeforeMint, coin.getDenomination(), bnAccValue)) { + if (bnAccValue > 0) { + accumulator.setValue(bnAccValue); + witness.resetValue(accumulator, coin); + } } //security level: this is an important prevention of tracing the coins via timing. Security level represents how many checkpoints @@ -333,7 +269,12 @@ bool CAccumulators::IntializeWitnessAndAccumulator(const PublicCoin &coin, Accum //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)) { - CBigNum bnAccValue = GetAccumulatorValueFromCheckpoint(chainActive[pindex->nHeight + 10]->nAccumulatorCheckpoint, coin.getDenomination()); + uint32_t nChecksum = ParseChecksum(chainActive[pindex->nHeight + 10]->nAccumulatorCheckpoint, coin.getDenomination()); + CBigNum bnAccValue = 0; + if (!zerocoinDB->ReadAccumulatorValue(nChecksum, bnAccValue)) { + LogPrintf("%s : failed to find checksum in database for accumulator\n", __func__); + return false; + } accumulator.setValue(bnAccValue); break; } @@ -343,13 +284,13 @@ bool CAccumulators::IntializeWitnessAndAccumulator(const PublicCoin &coin, Accum //grab mints from this block CBlock block; if(!ReadBlockFromDisk(block, pindex)) { - LogPrint("zero","%s: failed to read block from disk while adding pubcoins to witness\n", __func__); + LogPrintf("%s: failed to read block from disk while adding pubcoins to witness\n", __func__); return false; } std::vector vValues; if(!BlockToMintValueVector(block, coin.getDenomination(), vValues)) { - LogPrint("zero","%s: failed to get zerocoin mintlist from block %n\n", __func__, pindex->nHeight); + LogPrintf("%s: failed to get zerocoin mintlist from block %n\n", __func__, pindex->nHeight); return false; } @@ -366,8 +307,8 @@ bool CAccumulators::IntializeWitnessAndAccumulator(const PublicCoin &coin, Accum pindex = chainActive[pindex->nHeight + 1]; } - if (nMintsAdded < 3) { - strError = _("Less than 3 mints added, unable to create spend"); + if (nMintsAdded < Params().Zerocoin_RequiredAccumulation()) { + strError = _(strprintf("Less than %d mints added, unable to create spend", Params().Zerocoin_RequiredAccumulation()).c_str()); LogPrintf("%s : %s\n", __func__, strError); return false; } @@ -379,7 +320,7 @@ bool CAccumulators::IntializeWitnessAndAccumulator(const PublicCoin &coin, Accum nMintsAdded += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), coin.getDenomination()); pindex = chainActive[pindex->nHeight + 1]; } - + LogPrint("zero","%s : %d mints added to witness\n", __func__, nMintsAdded); return true; -} +} \ No newline at end of file diff --git a/src/accumulators.h b/src/accumulators.h index 4e10568f4b2d..3c7c00aa5869 100644 --- a/src/accumulators.h +++ b/src/accumulators.h @@ -11,50 +11,14 @@ #include "primitives/zerocoin.h" #include "uint256.h" -class CAccumulators -{ -public: - static CAccumulators& getInstance() - { - static CAccumulators instance; - return instance; - } -private: - std::map > mapAccumulators; - std::map mapSerials; - std::map mapAccumulatorValues; - std::list listAccCheckpointsNoDB; - - CAccumulators() { Setup(); } - void Setup(); - -public: - CAccumulators(CAccumulators const&) = delete; - void operator=(CAccumulators const&) = delete; - - libzerocoin::Accumulator Get(libzerocoin::CoinDenomination denomination); - bool AddPubCoinToAccumulator(const libzerocoin::PublicCoin& publicCoin); - bool IntializeWitnessAndAccumulator(const libzerocoin::PublicCoin &coin, libzerocoin::Accumulator& accumulator, libzerocoin::AccumulatorWitness& witness, int nSecurityLevel, int& nMintsAdded, std::string& strError); - bool EraseCoinSpend(const CBigNum& bnSerial); - bool EraseCoinMint(const CBigNum& bnPubCoin); - - //checksum/checkpoint - void DatabaseChecksums(const uint256& nCheckpoint); - void AddAccumulatorChecksum(const uint32_t nChecksum, const CBigNum &bnValue, bool fMemoryOnly = false); - bool LoadAccumulatorValuesFromDB(const uint256 nCheckpoint); - bool EraseAccumulatorValues(const uint256& nCheckpointErase, const uint256& nCheckpointPrevious); - uint32_t GetChecksum(const CBigNum &bnValue); - uint32_t GetChecksum(const libzerocoin::Accumulator &accumulator); - uint256 GetCheckpoint(); - bool GetCheckpoint(int nHeight, uint256& nCheckpoint); - CBigNum GetAccumulatorValueFromChecksum(const uint32_t& nChecksum); - CBigNum GetAccumulatorValueFromCheckpoint(const uint256& nCheckpoint, libzerocoin::CoinDenomination denomination); - bool ResetToCheckpoint(const uint256& nCheckpoint); - std::list GetAccCheckpointsNoDB() { return listAccCheckpointsNoDB; }; - void ClearAccCheckpointsNoDB() { listAccCheckpointsNoDB.clear(); } -}; - +bool GenerateAccumulatorWitness(const libzerocoin::PublicCoin &coin, libzerocoin::Accumulator& accumulator, libzerocoin::AccumulatorWitness& witness, int nSecurityLevel, int& nMintsAdded, std::string& strError); +bool GetAccumulatorValueFromDB(uint256 nCheckpoint, libzerocoin::CoinDenomination denom, CBigNum& bnAccValue); +bool GetAccumulatorValueFromChecksum(uint32_t nChecksum, bool fMemoryOnly, CBigNum& bnAccValue); +void AddAccumulatorChecksum(const uint32_t nChecksum, const CBigNum &bnValue, bool fMemoryOnly); +bool CalculateAccumulatorCheckpoint(int nHeight, uint256& nCheckpoint); +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); #endif //PIVX_ACCUMULATORS_H diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 26341d74e88e..df63c989e6dc 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -205,6 +205,7 @@ class CMainParams : public CChainParams nMaxZerocoinSpendsPerTransaction = 7; // Assume about 20kb each nMinZerocoinMintFee = 1 * CENT; //high fee required for zerocoin mints nMintRequiredConfirmations = 20; //the maximum amount of confirmations until accumulated in 19 + nRequiredAccumulation = 2; nDefaultSecurityLevel = 100; //full security level for accumulators nZerocoinHeaderVersion = 4; //Block headers must be this version once zerocoin is active nBudget_Fee_Confirmations = 6; // Number of confirmations for the finalization fee @@ -244,6 +245,7 @@ class CTestNetParams : public CMainParams nMasternodeCountDrift = 4; nModifierUpdateBlock = 51197; //approx Mon, 17 Apr 2017 04:00:00 GMT nMaxMoneyOut = 43199500 * COIN; + nZerocoinStartHeight = 201576; //! Modify the testnet genesis block so the timestamp is valid for a later start. genesis.nTime = 1454124731; diff --git a/src/chainparams.h b/src/chainparams.h index f8e16e07f23e..8d411b899593 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -105,6 +105,7 @@ class CChainParams int Zerocoin_MaxSpendsPerTransaction() const { return nMaxZerocoinSpendsPerTransaction; } CAmount Zerocoin_MintFee() const { return nMinZerocoinMintFee; } int Zerocoin_MintRequiredConfirmations() const { return nMintRequiredConfirmations; } + int Zerocoin_RequiredAccumulation() const { return nRequiredAccumulation; } int Zerocoin_DefaultSpendSecurity() const { return nDefaultSecurityLevel; } int Zerocoin_HeaderVersion() const { return nZerocoinHeaderVersion; } @@ -160,6 +161,7 @@ class CChainParams int nMaxZerocoinSpendsPerTransaction; CAmount nMinZerocoinMintFee; int nMintRequiredConfirmations; + int nRequiredAccumulation; int nDefaultSecurityLevel; int nZerocoinHeaderVersion; int64_t nBudget_Fee_Confirmations; diff --git a/src/init.cpp b/src/init.cpp index bc0a786d39ed..1048b003a5ce 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -11,6 +11,7 @@ #include "init.h" +#include "accumulators.h" #include "activemasternode.h" #include "addrman.h" #include "amount.h" @@ -70,6 +71,7 @@ int nWalletBackups = 10; #endif volatile bool fFeeEstimatesInitialized = false; volatile bool fRestartRequested = false; // true: restart false: shutdown +extern std::list listAccCheckpointsNoDB; #if ENABLE_ZMQ static CZMQNotificationInterface* pzmqNotificationInterface = NULL; @@ -330,6 +332,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-pid=", strprintf(_("Specify pid file (default: %s)"), "pivxd.pid")); #endif strUsage += HelpMessageOpt("-reindex", _("Rebuild block chain index from current blk000??.dat files") + " " + _("on startup")); + strUsage += HelpMessageOpt("-reindexaccumulators", _("Reindex the accumulator database") + " " + _("on startup")); strUsage += HelpMessageOpt("-resync", _("Delete blockchain folders and resync from scratch") + " " + _("on startup")); #if !defined(WIN32) strUsage += HelpMessageOpt("-sysperms", _("Create new files with system default permissions, instead of umask 077 (only effective with disabled wallet functionality)")); @@ -1451,7 +1454,16 @@ bool AppInit2(boost::thread_group& threadGroup) pblocktree->WriteFlag("msindexfix", true); } - list listAccCheckpointsNoDB = CAccumulators::getInstance().GetAccCheckpointsNoDB(); + // Force recalculation of accumulators. + if (GetBoolArg("-reindexaccumulators", false)) { + CBlockIndex* pindex = chainActive[Params().Zerocoin_StartHeight()]; + while (pindex->nHeight < chainActive.Height()) { + if (!count(listAccCheckpointsNoDB.begin(), listAccCheckpointsNoDB.end(), pindex->nAccumulatorCheckpoint)) + listAccCheckpointsNoDB.emplace_back(pindex->nAccumulatorCheckpoint); + pindex = chainActive.Next(pindex); + } + } + // PIVX: recalculate Accumulator Checkpoints that failed to database properly if (!listAccCheckpointsNoDB.empty() && chainActive.Tip()->GetBlockHeader().nVersion >= Params().Zerocoin_HeaderVersion()) { uiInterface.InitMessage(_("Calculating missing accumulators...")); @@ -1482,11 +1494,13 @@ bool AppInit2(boost::thread_group& threadGroup) uiInterface.ShowProgress(_("Calculating missing accumulators..."), (int)(dPercent * 100)); if(find(listAccCheckpointsNoDB.begin(), listAccCheckpointsNoDB.end(), pindex->nAccumulatorCheckpoint) != listAccCheckpointsNoDB.end()) { uint256 nCheckpointCalculated = 0; - CAccumulators::getInstance().GetCheckpoint(pindex->nHeight, nCheckpointCalculated); + if (!CalculateAccumulatorCheckpoint(pindex->nHeight, nCheckpointCalculated)) { + // GetCheckpoint could have terminated due to a shutdown request. Check this here. + if (ShutdownRequested()) + break; + return InitError(_("Failed to calculate accumulator checkpoint")); + } - // GetCheckpoint could have terminated due to a shutdown request. Check this here. - if (ShutdownRequested()) - break; //check that the calculated checkpoint is what is in the index. if(nCheckpointCalculated != pindex->nAccumulatorCheckpoint) { LogPrintf("%s : height=%d calculated_checkpoint=%s actual=%s\n", __func__, pindex->nHeight, nCheckpointCalculated.GetHex(), pindex->nAccumulatorCheckpoint.GetHex()); @@ -1505,7 +1519,6 @@ bool AppInit2(boost::thread_group& threadGroup) break; } } - CAccumulators::getInstance().ClearAccCheckpointsNoDB(); uiInterface.InitMessage(_("Verifying blocks...")); diff --git a/src/main.cpp b/src/main.cpp index 5007a74a0556..ff8d90c6d27c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1173,10 +1173,8 @@ bool TxOutToPublicCoin(const CTxOut txout, PublicCoin& pubCoin, CValidationState return state.DoS(100, error("TxOutToPublicCoin : txout.nValue is not correct")); PublicCoin checkPubCoin(Params().Zerocoin_Params(), publicZerocoin, denomination); - if (!checkPubCoin.validate()) - return state.DoS(100, error("TxOutToPublicCoin : PubCoin does not validate")); - pubCoin = checkPubCoin; + return true; } @@ -1280,6 +1278,9 @@ bool CheckZerocoinMint(const uint256& txHash, const CTxOut& txout, CValidationSt if(!TxOutToPublicCoin(txout, pubCoin, state)) return state.DoS(100, error("CheckZerocoinMint(): TxOutToPublicCoin() failed")); + if (!pubCoin.validate()) + return state.DoS(100, error("CheckZerocoinMint() : PubCoin does not validate")); + if(!fCheckOnly && !RecordMintToDB(pubCoin, txHash)) return state.DoS(100, error("CheckZerocoinMint(): RecordMintToDB() failed")); @@ -1360,9 +1361,8 @@ bool CheckZerocoinSpend(const CTransaction tx, bool fVerifySignature, CValidatio // Skip signature verification during initial block download if (fVerifySignature) { //see if we have record of the accumulator used in the spend tx - CBigNum bnAccumulatorValue = CAccumulators::getInstance().GetAccumulatorValueFromChecksum( - newSpend.getAccumulatorChecksum()); - if(bnAccumulatorValue == 0) + CBigNum bnAccumulatorValue = 0; + if(!zerocoinDB->ReadAccumulatorValue(newSpend.getAccumulatorChecksum(), bnAccumulatorValue)) return state.DoS(100, error("Zerocoinspend could not find accumulator associated with checksum")); Accumulator accumulator(Params().Zerocoin_Params(), newSpend.getDenomination(), bnAccumulatorValue); @@ -2707,7 +2707,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex for (const CTxIn txin : tx.vin) { if (txin.scriptSig.IsZerocoinSpend()) { CoinSpend spend = TxInToZerocoinSpend(txin); - if (!CAccumulators::getInstance().EraseCoinSpend(spend.getCoinSerialNumber())) + if (!zerocoinDB->EraseCoinSpend(spend.getCoinSerialNumber())) return error("failed to erase spent zerocoin in block"); } } @@ -2722,7 +2722,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex if (!TxOutToPublicCoin(txout, pubCoin, state)) return error("DisconnectBlock(): TxOutToPublicCoin() failed"); - if(!CAccumulators::getInstance().EraseCoinMint(pubCoin.getValue())) + if(!zerocoinDB->EraseCoinMint(pubCoin.getValue())) return error("DisconnectBlock(): Failed to erase coin mint"); } } @@ -2789,7 +2789,7 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex //if block is an accumulator checkpoint block, remove checkpoint and checksums from db uint256 nCheckpoint = pindex->nAccumulatorCheckpoint; if(nCheckpoint != pindex->pprev->nAccumulatorCheckpoint) { - if(!CAccumulators::getInstance().EraseAccumulatorValues(nCheckpoint, pindex->pprev->nAccumulatorCheckpoint)) + if(!EraseAccumulatorValues(nCheckpoint, pindex->pprev->nAccumulatorCheckpoint)) return error("DisconnectBlock(): failed to erase checkpoint"); } } @@ -3068,7 +3068,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin // zerocoin accumulator: if a new accumulator checkpoint was generated, check that it is the correct value if (!fVerifyingBlocks && block.nVersion >= Params().Zerocoin_HeaderVersion() && pindex->nHeight % 10 == 0) { uint256 nCheckpointCalculated = 0; - if (!CAccumulators::getInstance().GetCheckpoint(pindex->nHeight, nCheckpointCalculated)) + if (!CalculateAccumulatorCheckpoint(pindex->nHeight, nCheckpointCalculated)) return state.DoS(100, error("ConnectBlock() : failed to calculate accumulator checkpoint")); if (nCheckpointCalculated != block.nAccumulatorCheckpoint) { diff --git a/src/miner.cpp b/src/miner.cpp index dd749d1cec7f..2e5a673d3ec8 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -405,7 +405,7 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, pblock->nBits = GetNextWorkRequired(pindexPrev, pblock); pblock->nNonce = 0; uint256 nCheckpoint = 0; - if(fZerocoinActive && !CAccumulators::getInstance().GetCheckpoint(nHeight, nCheckpoint)){ + if(fZerocoinActive && !CalculateAccumulatorCheckpoint(nHeight, nCheckpoint)){ LogPrintf("%s: failed to get accumulator checkpoint\n", __func__); } pblock->nAccumulatorCheckpoint = nCheckpoint; diff --git a/src/qt/forms/privacydialog.ui b/src/qt/forms/privacydialog.ui index d3d03da5bd57..47dc32136c51 100644 --- a/src/qt/forms/privacydialog.ui +++ b/src/qt/forms/privacydialog.ui @@ -581,7 +581,7 @@ Available (mature and spendable) zPIV for spending -zPIV are mature when they have more than 20 confirmations AND more than 3 mints of the same denomination after them were minted +zPIV are mature when they have more than 20 confirmations AND more than 2 mints of the same denomination after them were minted 0 zPIV @@ -1048,7 +1048,7 @@ zPIV are mature when they have more than 20 confirmations AND more than 3 mints Unconfirmed: less than 20 confirmations -Immature: confirmed, but less than 3 mints of the same denomination after it was minted +Immature: confirmed, but less than 2 mints of the same denomination after it was minted 0 x @@ -1101,7 +1101,7 @@ Immature: confirmed, but less than 3 mints of the same denomination after it was Unconfirmed: less than 20 confirmations -Immature: confirmed, but less than 3 mints of the same denomination after it was minted +Immature: confirmed, but less than 2 mints of the same denomination after it was minted 0 x @@ -1154,7 +1154,7 @@ Immature: confirmed, but less than 3 mints of the same denomination after it was Unconfirmed: less than 20 confirmations -Immature: confirmed, but less than 3 mints of the same denomination after it was minted +Immature: confirmed, but less than 2 mints of the same denomination after it was minted 0 x @@ -1207,7 +1207,7 @@ Immature: confirmed, but less than 3 mints of the same denomination after it was Unconfirmed: less than 20 confirmations -Immature: confirmed, but less than 3 mints of the same denomination after it was minted +Immature: confirmed, but less than 2 mints of the same denomination after it was minted 0 x @@ -1260,7 +1260,7 @@ Immature: confirmed, but less than 3 mints of the same denomination after it was Unconfirmed: less than 20 confirmations -Immature: confirmed, but less than 3 mints of the same denomination after it was minted +Immature: confirmed, but less than 2 mints of the same denomination after it was minted 0 x @@ -1313,7 +1313,7 @@ Immature: confirmed, but less than 3 mints of the same denomination after it was Unconfirmed: less than 20 confirmations -Immature: confirmed, but less than 3 mints of the same denomination after it was minted +Immature: confirmed, but less than 2 mints of the same denomination after it was minted 0 x @@ -1366,7 +1366,7 @@ Immature: confirmed, but less than 3 mints of the same denomination after it was Unconfirmed: less than 20 confirmations -Immature: confirmed, but less than 3 mints of the same denomination after it was minted +Immature: confirmed, but less than 2 mints of the same denomination after it was minted 0 x @@ -1419,7 +1419,7 @@ Immature: confirmed, but less than 3 mints of the same denomination after it was Unconfirmed: less than 20 confirmations -Immature: confirmed, but less than 3 mints of the same denomination after it was minted +Immature: confirmed, but less than 2 mints of the same denomination after it was minted 0 x diff --git a/src/qt/privacydialog.cpp b/src/qt/privacydialog.cpp index 436877bcf049..37adb7a723b1 100644 --- a/src/qt/privacydialog.cpp +++ b/src/qt/privacydialog.cpp @@ -555,21 +555,21 @@ void PrivacyDialog::setBalance(const CAmount& balance, const CAmount& unconfirme // All denominations mapDenomBalances.at(mint.GetDenomination())++; - if (!mint.GetHeight() || mint.GetHeight() > chainActive.Height() - Params().Zerocoin_MintRequiredConfirmations()) { + if (!mint.GetHeight() || chainActive.Height() - mint.GetHeight() <= Params().Zerocoin_MintRequiredConfirmations()) { // All unconfirmed denominations mapUnconfirmed.at(mint.GetDenomination())++; } else { // After a denomination is confirmed it might still be immature because < 3 of the same denomination were minted after it - CBlockIndex *pindex = chainActive[mint.GetHeight()]; + CBlockIndex *pindex = chainActive[mint.GetHeight() + 1]; int nMintsAdded = 0; - while(pindex->nHeight < chainActive.Height() - 30) { // 30 just to make sure that its at least 2 checkpoints from the top block + while (pindex->nHeight < chainActive.Height() - 30) { // 30 just to make sure that its at least 2 checkpoints from the top block nMintsAdded += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), mint.GetDenomination()); - if(nMintsAdded >= 3) + if (nMintsAdded >= Params().Zerocoin_RequiredAccumulation()) break; pindex = chainActive[pindex->nHeight + 1]; } - if(nMintsAdded < 3){ + if (nMintsAdded < Params().Zerocoin_RequiredAccumulation()){ // Immature denominations mapImmature.at(mint.GetDenomination())++; } diff --git a/src/qt/zpivcontroldialog.cpp b/src/qt/zpivcontroldialog.cpp index 51cd8aa7df02..4bebcf1c9079 100644 --- a/src/qt/zpivcontroldialog.cpp +++ b/src/qt/zpivcontroldialog.cpp @@ -95,14 +95,14 @@ void ZPivControlDialog::updateList() CBlockIndex *pindex = chainActive[mint.GetHeight() + 1]; while(pindex->nHeight < chainActive.Height() - 30) { // 30 just to make sure that its at least 2 checkpoints from the top block nMintsAdded += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), mint.GetDenomination()); - if(nMintsAdded >= 3) + if(nMintsAdded >= Params().Zerocoin_RequiredAccumulation()) break; pindex = chainActive[pindex->nHeight + 1]; } } // disable selecting this mint if it is not spendable - also display a reason why - bool fSpendable = nMintsAdded >= 3 && nConfirmations >= Params().Zerocoin_MintRequiredConfirmations(); + bool fSpendable = nMintsAdded >= Params().Zerocoin_RequiredAccumulation() && nConfirmations >= Params().Zerocoin_MintRequiredConfirmations(); if(!fSpendable) { itemMint->setDisabled(true); itemMint->setCheckState(COLUMN_CHECKBOX, Qt::Unchecked); @@ -117,7 +117,7 @@ void ZPivControlDialog::updateList() if(nConfirmations < Params().Zerocoin_MintRequiredConfirmations()) strReason = strprintf("Needs %d more confirmations", Params().Zerocoin_MintRequiredConfirmations() - nConfirmations); else - strReason = strprintf("Needs %d more mints added to network", 3 - nMintsAdded); + strReason = strprintf("Needs %d more mints added to network", Params().Zerocoin_RequiredAccumulation() - nMintsAdded); itemMint->setText(COLUMN_ISSPENDABLE, QString::fromStdString(strReason)); } else { diff --git a/src/test/zerocoin_implementation_tests.cpp b/src/test/zerocoin_implementation_tests.cpp index 6764d49e3cc3..46e7f3d7f284 100644 --- a/src/test/zerocoin_implementation_tests.cpp +++ b/src/test/zerocoin_implementation_tests.cpp @@ -134,8 +134,8 @@ bool CheckZerocoinSpendNoDB(const CTransaction tx, string& strError) // } //see if we have record of the accumulator used in the spend tx - CBigNum bnAccumulatorValue = CAccumulators::getInstance().GetAccumulatorValueFromChecksum(newSpend.getAccumulatorChecksum()); - if(bnAccumulatorValue == 0) { + CBigNum bnAccumulatorValue = 0; + if (!GetAccumulatorValueFromChecksum(newSpend.getAccumulatorChecksum(), true, bnAccumulatorValue)) { strError = "Zerocoinspend could not find accumulator associated with checksum"; return false; } @@ -213,8 +213,8 @@ BOOST_AUTO_TEST_CASE(checkzerocoinspend_test) privateCoin.setSerialNumber(zerocoinMint.GetSerialNumber()); //Get the checksum of the accumulator we use for the spend and also add it to our checksum map - uint32_t nChecksum = CAccumulators::getInstance().GetChecksum(accumulator); - CAccumulators::getInstance().AddAccumulatorChecksum(nChecksum, accumulator.getValue(), true); + uint32_t nChecksum = GetChecksum(accumulator.getValue()); + AddAccumulatorChecksum(nChecksum, accumulator.getValue(), true); CoinSpend coinSpend(Params().Zerocoin_Params(), privateCoin, accumulator, nChecksum, witness, 0); CBigNum serial = coinSpend.getCoinSerialNumber(); diff --git a/src/txdb.cpp b/src/txdb.cpp index 9e06f833ed8a..61f5be178df1 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -271,7 +271,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts() //populate accumulator checksum map in memory if(pindexNew->nAccumulatorCheckpoint != 0 && pindexNew->nAccumulatorCheckpoint != nPreviousCheckpoint) { - CAccumulators::getInstance().LoadAccumulatorValuesFromDB(pindexNew->nAccumulatorCheckpoint); + LoadAccumulatorValuesFromDB(pindexNew->nAccumulatorCheckpoint); nPreviousCheckpoint = pindexNew->nAccumulatorCheckpoint; } diff --git a/src/wallet.cpp b/src/wallet.cpp index 570fb5657310..5764cc62a005 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -4035,8 +4035,9 @@ bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, con libzerocoin::AccumulatorWitness witness(Params().Zerocoin_Params(), accumulator, pubCoinSelected); string strFailReason = ""; int nMintsAdded = 0; - if (!CAccumulators::getInstance().IntializeWitnessAndAccumulator(pubCoinSelected, accumulator, witness, nSecurityLevel, nMintsAdded, strFailReason)) { + if (!GenerateAccumulatorWitness(pubCoinSelected, accumulator, witness, nSecurityLevel, nMintsAdded, strFailReason)) { receipt.SetStatus("Try to spend with a higher security level to include more coins", ZPIV_FAILED_ACCUMULATOR_INITIALIZATION); + LogPrintf("%s : %s \n", __func__, receipt.GetStatusMessage()); return false; } @@ -4045,7 +4046,7 @@ bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, con privateCoin.setPublicCoin(pubCoinSelected); privateCoin.setRandomness(zerocoinSelected.GetRandomness()); privateCoin.setSerialNumber(zerocoinSelected.GetSerialNumber()); - uint32_t nChecksum = CAccumulators::getInstance().GetChecksum(accumulator); + uint32_t nChecksum = GetChecksum(accumulator.getValue()); try { libzerocoin::CoinSpend spend(Params().Zerocoin_Params(), privateCoin, accumulator, nChecksum, witness, hashTxOut); @@ -4099,7 +4100,7 @@ bool CWallet::MintToTxIn(CZerocoinMint zerocoinSelected, int nSecurityLevel, con } } - uint32_t nAccumulatorChecksum = CAccumulators::getInstance().GetChecksum(accumulator); + uint32_t nAccumulatorChecksum = GetChecksum(accumulator.getValue()); CZerocoinSpend zcSpend(spend.getCoinSerialNumber(), 0, zerocoinSelected.GetValue(), zerocoinSelected.GetDenomination(), nAccumulatorChecksum); zcSpend.SetMintCount(nMintsAdded); receipt.AddSpend(zcSpend); diff --git a/src/walletdb.cpp b/src/walletdb.cpp index 8b297ef12df3..d42f14726004 100644 --- a/src/walletdb.cpp +++ b/src/walletdb.cpp @@ -1166,12 +1166,12 @@ std::list CWalletDB::ListMintedCoins(bool fUnusedOnly, bool fMatu int nMintsAdded = 0; while(pindex->nHeight < chainActive.Height() - 30) { // 30 just to make sure that its at least 2 checkpoints from the top block nMintsAdded += count(pindex->vMintDenominationsInBlock.begin(), pindex->vMintDenominationsInBlock.end(), mint.GetDenomination()); - if(nMintsAdded >= 3) + if(nMintsAdded >= Params().Zerocoin_RequiredAccumulation()) break; pindex = chainActive[pindex->nHeight + 1]; } - if(nMintsAdded < 3) + if(nMintsAdded < Params().Zerocoin_RequiredAccumulation()) continue; } }