diff --git a/CMakeLists.txt b/CMakeLists.txt index cff73d1a9638f..46c3e6baf63b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -257,10 +257,8 @@ set(WALLET_SOURCES ./src/wallet/db.cpp ./src/addressbook.cpp ./src/crypter.cpp - ./src/zpiv/mintpool.cpp ./src/wallet/hdchain.cpp ./src/wallet/rpcdump.cpp - ./src/zpiv/zerocoin.cpp ./src/wallet/fees.cpp ./src/wallet/init.cpp ./src/wallet/scriptpubkeyman.cpp @@ -367,7 +365,6 @@ set(COMMON_SOURCES ./src/consensus/zerocoin_verify.cpp ./src/primitives/block.cpp ./src/primitives/transaction.cpp - ./src/zpiv/zerocoin.cpp ./src/core_read.cpp ./src/core_write.cpp ./src/hash.cpp diff --git a/src/Makefile.am b/src/Makefile.am index a747e373eaa0b..8205383911b64 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -306,8 +306,6 @@ BITCOIN_CORE_H = \ wallet/walletdb.h \ warnings.h \ zpivchain.h \ - zpiv/mintpool.h \ - zpiv/zerocoin.h \ zpiv/zpos.h \ zmq/zmqabstractnotifier.h \ zmq/zmqconfig.h \ @@ -409,8 +407,6 @@ libbitcoin_wallet_a_SOURCES = \ destination_io.cpp \ wallet/wallet.cpp \ wallet/walletdb.cpp \ - zpiv/zerocoin.cpp \ - zpiv/mintpool.cpp \ stakeinput.cpp \ zpiv/zpos.cpp \ $(BITCOIN_CORE_H) \ @@ -501,7 +497,6 @@ libbitcoin_common_a_SOURCES = \ key_io.cpp \ primitives/block.cpp \ primitives/transaction.cpp \ - zpiv/zerocoin.cpp \ core_read.cpp \ core_write.cpp \ hash.cpp \ diff --git a/src/consensus/zerocoin_verify.cpp b/src/consensus/zerocoin_verify.cpp index 75610a1750244..a3f9a406fd1f0 100644 --- a/src/consensus/zerocoin_verify.cpp +++ b/src/consensus/zerocoin_verify.cpp @@ -194,9 +194,9 @@ bool ContextualCheckZerocoinTx(const CTransactionRef& tx, CValidationState& stat return true; } -bool ContextualCheckZerocoinSpend(const CTransaction& tx, const libzerocoin::CoinSpend* spend, int nHeight, const uint256& hashBlock) +bool ContextualCheckZerocoinSpend(const CTransaction& tx, const libzerocoin::CoinSpend* spend, int nHeight) { - if(!ContextualCheckZerocoinSpendNoSerialCheck(tx, spend, nHeight, hashBlock)){ + if(!ContextualCheckZerocoinSpendNoSerialCheck(tx, spend, nHeight)){ return false; } @@ -209,7 +209,7 @@ bool ContextualCheckZerocoinSpend(const CTransaction& tx, const libzerocoin::Coi return true; } -bool ContextualCheckZerocoinSpendNoSerialCheck(const CTransaction& tx, const libzerocoin::CoinSpend* spend, int nHeight, const uint256& hashBlock) +bool ContextualCheckZerocoinSpendNoSerialCheck(const CTransaction& tx, const libzerocoin::CoinSpend* spend, int nHeight) { const Consensus::Params& consensus = Params().GetConsensus(); //Check to see if the zPIV is properly signed @@ -250,3 +250,46 @@ bool ContextualCheckZerocoinSpendNoSerialCheck(const CTransaction& tx, const lib return true; } +Optional ParseAndValidateZerocoinSpend(const Consensus::Params& consensus, + const CTransaction& tx, int chainHeight, + CValidationState& state) +{ + for (const CTxIn& txIn : tx.vin) { + bool isPublicSpend = txIn.IsZerocoinPublicSpend(); + bool isPrivZerocoinSpend = txIn.IsZerocoinSpend(); + if (!isPrivZerocoinSpend && !isPublicSpend) + continue; + + // Check enforcement + if (!CheckPublicCoinSpendEnforced(chainHeight, isPublicSpend)){ + return nullopt; + } + + if (isPublicSpend) { + libzerocoin::ZerocoinParams* params = consensus.Zerocoin_Params(false); + PublicCoinSpend publicSpend(params); + if (!ZPIVModule::ParseZerocoinPublicSpend(txIn, tx, state, publicSpend) || + !CheckPublicCoinSpendVersion(publicSpend.getCoinVersion())){ + return nullopt; + } + //queue for db write after the 'justcheck' section has concluded + if (!ContextualCheckZerocoinSpend(tx, &publicSpend, chainHeight)) { + state.DoS(100, error("%s: failed to add block %s with invalid public zc spend", __func__, + tx.GetHash().GetHex()), REJECT_INVALID); + return nullopt; + } + // return value + return Optional(CoinSpendValues(publicSpend.getCoinSerialNumber(), publicSpend.getDenomination() * COIN)); + } else { + libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txIn); + //queue for db write after the 'justcheck' section has concluded + if (!ContextualCheckZerocoinSpend(tx, &spend, chainHeight)) { + state.DoS(100, error("%s: failed to add block %s with invalid zerocoinspend", __func__, + tx.GetHash().GetHex()), REJECT_INVALID); + return nullopt; + } + return Optional(CoinSpendValues(spend.getCoinSerialNumber(), spend.getDenomination() * COIN)); + } + } + return nullopt; +} diff --git a/src/consensus/zerocoin_verify.h b/src/consensus/zerocoin_verify.h index 18906785be429..37e8ebbf0fda8 100644 --- a/src/consensus/zerocoin_verify.h +++ b/src/consensus/zerocoin_verify.h @@ -16,7 +16,18 @@ bool CheckPublicCoinSpendEnforced(int blockHeight, bool isPublicSpend); int CurrentPublicCoinSpendVersion(); bool CheckPublicCoinSpendVersion(int version); bool ContextualCheckZerocoinTx(const CTransactionRef& tx, CValidationState& state, const Consensus::Params& consensus, int nHeight); -bool ContextualCheckZerocoinSpend(const CTransaction& tx, const libzerocoin::CoinSpend* spend, int nHeight, const uint256& hashBlock); -bool ContextualCheckZerocoinSpendNoSerialCheck(const CTransaction& tx, const libzerocoin::CoinSpend* spend, int nHeight, const uint256& hashBlock); +bool ContextualCheckZerocoinSpend(const CTransaction& tx, const libzerocoin::CoinSpend* spend, int nHeight); +bool ContextualCheckZerocoinSpendNoSerialCheck(const CTransaction& tx, const libzerocoin::CoinSpend* spend, int nHeight); + +struct CoinSpendValues { +public: + explicit CoinSpendValues(const CBigNum& s, CAmount v) : serial(s), value(v) {} + CBigNum serial; + CAmount value; +}; +// Returns nullopt if coin spend is invalid. Invalidity/DoS causes are treated inside the function. +Optional ParseAndValidateZerocoinSpend(const Consensus::Params& consensus, + const CTransaction& tx, int chainHeight, + CValidationState& state); #endif //PIVX_CONSENSUS_ZEROCOIN_VERIFY_H diff --git a/src/txdb.cpp b/src/txdb.cpp index 2035c1c75081b..66c49ec1c5752 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -10,7 +10,6 @@ #include "pow.h" #include "uint256.h" #include "util/system.h" -#include "zpiv/zerocoin.h" #include "util/vector.h" #include @@ -357,12 +356,12 @@ CZerocoinDB::CZerocoinDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapp { } -bool CZerocoinDB::WriteCoinSpendBatch(const std::vector >& spendInfo) +bool CZerocoinDB::WriteCoinSpendBatch(const std::vector >& spendInfo) { CDBBatch batch; size_t count = 0; - for (std::vector >::const_iterator it=spendInfo.begin(); it != spendInfo.end(); it++) { - CBigNum bnSerial = it->first.getCoinSerialNumber(); + for (std::vector >::const_iterator it=spendInfo.begin(); it != spendInfo.end(); it++) { + CBigNum bnSerial = it->first; CDataStream ss(SER_GETHASH, 0); ss << bnSerial; uint256 hash = Hash(ss.begin(), ss.end()); diff --git a/src/txdb.h b/src/txdb.h index 533d0301c4eb8..f11020d6f0dcb 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -163,8 +163,10 @@ class CZerocoinDB : public CDBWrapper void operator=(const CZerocoinDB&); public: - /** Write zPIV spends to the zerocoinDB in a batch */ - bool WriteCoinSpendBatch(const std::vector >& spendInfo); + /** Write zPIV spends to the zerocoinDB in a batch + * Pair of: CBigNum -> coinSerialNumber and uint256 -> txHash. + */ + bool WriteCoinSpendBatch(const std::vector >& spendInfo); bool ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash); bool EraseCoinSpend(const CBigNum& bnSerial); diff --git a/src/validation.cpp b/src/validation.cpp index 4aefc393a2c8e..f6ff1de4c93c9 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -50,7 +50,6 @@ #include "validationinterface.h" #include "warnings.h" #include "zpivchain.h" -#include "zpiv/zerocoin.h" #include "zpiv/zpivmodule.h" #include @@ -1548,14 +1547,13 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd unsigned int nSigOps = 0; CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size())); std::vector > vPos; - std::vector > vSpends; + std::vector > vSpends; vPos.reserve(block.vtx.size()); CBlockUndo blockundo; blockundo.vtxundo.reserve(block.vtx.size() - 1); CAmount nValueOut = 0; CAmount nValueIn = 0; unsigned int nMaxBlockSigOps = MAX_BLOCK_SIGOPS_CURRENT; - std::vector vSpendsInBlock; uint256 hashBlock = block.GetHash(); // Sapling @@ -1589,43 +1587,12 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd } if (tx.HasZerocoinSpendInputs()) { - const uint256& txid = tx.GetHash(); - vSpendsInBlock.emplace_back(txid); - - //Check for double spending of serial #'s - std::set setSerials; - for (const CTxIn& txIn : tx.vin) { - bool isPublicSpend = txIn.IsZerocoinPublicSpend(); - bool isPrivZerocoinSpend = txIn.IsZerocoinSpend(); - if (!isPrivZerocoinSpend && !isPublicSpend) - continue; - - // Check enforcement - if (!CheckPublicCoinSpendEnforced(pindex->nHeight, isPublicSpend)){ - return false; - } - - if (isPublicSpend) { - libzerocoin::ZerocoinParams* params = consensus.Zerocoin_Params(false); - PublicCoinSpend publicSpend(params); - if (!ZPIVModule::ParseZerocoinPublicSpend(txIn, tx, state, publicSpend)){ - return false; - } - nValueIn += publicSpend.getDenomination() * COIN; - //queue for db write after the 'justcheck' section has concluded - vSpends.emplace_back(publicSpend, tx.GetHash()); - if (!ContextualCheckZerocoinSpend(tx, &publicSpend, pindex->nHeight, hashBlock)) - return state.DoS(100, error("%s: failed to add block %s with invalid public zc spend", __func__, tx.GetHash().GetHex()), REJECT_INVALID); - } else { - libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txIn); - nValueIn += spend.getDenomination() * COIN; - //queue for db write after the 'justcheck' section has concluded - vSpends.emplace_back(spend, tx.GetHash()); - if (!ContextualCheckZerocoinSpend(tx, &spend, pindex->nHeight, hashBlock)) - return state.DoS(100, error("%s: failed to add block %s with invalid zerocoinspend", __func__, tx.GetHash().GetHex()), REJECT_INVALID); - } + auto opCoinSpendValues = ParseAndValidateZerocoinSpend(consensus, tx, pindex->nHeight, state); + if (!opCoinSpendValues) { + return false; // Invalidity/DoS is handled by ParseAndValidateZerocoinSpend. } - + nValueIn += opCoinSpendValues->value; + vSpends.emplace_back(opCoinSpendValues->serial, tx.GetHash()); } else if (!tx.IsCoinBase()) { if (!view.HaveInputs(tx)) { return state.DoS(100, false, REJECT_INVALID, "bad-txns-inputs-missingorspent"); @@ -3310,7 +3277,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockInde return state.DoS(100, error("%s: serial double spent on main chain", __func__)); } - if (!ContextualCheckZerocoinSpendNoSerialCheck(stakeTxIn, &spend, pindex->nHeight, UINT256_ZERO)) + if (!ContextualCheckZerocoinSpendNoSerialCheck(stakeTxIn, &spend, pindex->nHeight)) return state.DoS(100,error("%s: forked chain ContextualCheckZerocoinSpend failed for tx %s", __func__, stakeTxIn.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-zpiv"); @@ -3334,7 +3301,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, CBlockInde if(!isBlockFromFork) for (const CTxIn& zPivInput : zPIVInputs) { libzerocoin::CoinSpend spend = TxInToZerocoinSpend(zPivInput); - if (!ContextualCheckZerocoinSpend(stakeTxIn, &spend, pindex->nHeight, UINT256_ZERO)) + if (!ContextualCheckZerocoinSpend(stakeTxIn, &spend, pindex->nHeight)) return state.DoS(100,error("%s: main chain ContextualCheckZerocoinSpend failed for tx %s", __func__, stakeTxIn.GetHash().GetHex()), REJECT_INVALID, "bad-txns-invalid-zpiv"); } diff --git a/src/zpiv/mintpool.cpp b/src/zpiv/mintpool.cpp deleted file mode 100644 index 16c8f39b60518..0000000000000 --- a/src/zpiv/mintpool.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2017-2019 The PIVX developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "mintpool.h" -#include "util/system.h" - - -CMintPool::CMintPool() -{ - this->nCountLastGenerated = 0; - this->nCountLastRemoved = 0; -} - -CMintPool::CMintPool(uint32_t nCount) -{ - this->nCountLastRemoved = nCount; - this->nCountLastGenerated = nCount; -} - -void CMintPool::Add(const CBigNum& bnValue, const uint32_t& nCount) -{ - uint256 hash = GetPubCoinHash(bnValue); - Add(std::make_pair(hash, nCount)); - LogPrintf("%s : add %s to mint pool, nCountLastGenerated=%d\n", __func__, bnValue.GetHex().substr(0, 6), nCountLastGenerated); -} - -void CMintPool::Add(const std::pair& pMint, bool fVerbose) -{ - insert(pMint); - if (pMint.second > nCountLastGenerated) - nCountLastGenerated = pMint.second; - - if (fVerbose) - LogPrintf("%s : add %s count %d to mint pool\n", __func__, pMint.first.GetHex().substr(0, 6), pMint.second); -} - -bool CMintPool::Has(const CBigNum& bnValue) -{ - return static_cast(count(GetPubCoinHash(bnValue))); -} - -std::pair CMintPool::Get(const CBigNum& bnValue) -{ - auto it = find(GetPubCoinHash(bnValue)); - return *it; -} - -bool SortSmallest(const std::pair& a, const std::pair& b) -{ - return a.second < b.second; -} - -std::list > CMintPool::List() -{ - std::list > listMints; - for (auto pMint : *(this)) { - listMints.emplace_back(pMint); - } - - listMints.sort(SortSmallest); - - return listMints; -} - -void CMintPool::Reset() -{ - clear(); - nCountLastGenerated = 0; - nCountLastRemoved = 0; -} - -bool CMintPool::Front(std::pair& pMint) -{ - if (empty()) - return false; - pMint = *begin(); - return true; -} - -bool CMintPool::Next(std::pair& pMint) -{ - auto it = find(pMint.first); - if (it == end() || ++it == end()) - return false; - - pMint = *it; - return true; -} - -void CMintPool::Remove(const CBigNum& bnValue) -{ - Remove(GetPubCoinHash(bnValue)); - LogPrintf("%s : remove %s from mint pool\n", __func__, bnValue.GetHex().substr(0, 6)); -} - -void CMintPool::Remove(const uint256& hashPubcoin) -{ - auto it = find(hashPubcoin); - if (it == end()) - return; - - nCountLastRemoved = it->second; - erase(it); -} - - - diff --git a/src/zpiv/mintpool.h b/src/zpiv/mintpool.h deleted file mode 100644 index 8c2a137c2245d..0000000000000 --- a/src/zpiv/mintpool.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2017-2018 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_MINTPOOL_H -#define PIVX_MINTPOOL_H - -#include -#include - -#include "zpiv/zerocoin.h" -#include "libzerocoin/bignum.h" -#include "uint256.h" - -/** - * The MintPool only contains mint values that have not been added to the blockchain yet. - * When a mint is generated by the wallet, or found while syncing, the mint will be removed - * from the MintPool. - * - * The MintPool provides a convenient way to check whether mints in the blockchain belong to a - * wallet's deterministic seed. - */ -class CMintPool : public std::map //pubcoin hash, count -{ -private: - uint32_t nCountLastGenerated; - uint32_t nCountLastRemoved; - -public: - CMintPool(); - explicit CMintPool(uint32_t nCount); - void Add(const CBigNum& bnValue, const uint32_t& nCount); - void Add(const std::pair& pMint, bool fVerbose = false); - bool Has(const CBigNum& bnValue); - void Remove(const CBigNum& bnValue); - void Remove(const uint256& hashPubcoin); - std::pair Get(const CBigNum& bnValue); - std::list > List(); - void Reset(); - - bool Front(std::pair& pMint); - bool Next(std::pair& pMint); - - //The count of the next mint to generate will have be a mint that is already in the pool - //therefore need to return the next value that has not been removed from the pool yet - uint32_t CountOfLastRemoved() { return nCountLastRemoved; } - - //The next pool count returns the next count that will be added to the pool - uint32_t CountOfLastGenerated() { return nCountLastGenerated; } -}; - - -#endif //PIVX_MINTPOOL_H diff --git a/src/zpiv/zerocoin.cpp b/src/zpiv/zerocoin.cpp deleted file mode 100644 index 4f0fc81b0d0fa..0000000000000 --- a/src/zpiv/zerocoin.cpp +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright (c) 2017-2018 The PIVX developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include "zerocoin.h" -#include "streams.h" -#include "hash.h" - -uint256 GetPubCoinHash(const CBigNum& bnValue) -{ - CDataStream ss(SER_GETHASH, 0); - ss << bnValue; - return Hash(ss.begin(), ss.end()); -} diff --git a/src/zpiv/zerocoin.h b/src/zpiv/zerocoin.h deleted file mode 100644 index db748478f8a02..0000000000000 --- a/src/zpiv/zerocoin.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) 2017-2020 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_ZEROCOIN_H -#define PIVX_ZEROCOIN_H - -#include "uint256.h" -#include "libzerocoin/bignum.h" - -uint256 GetPubCoinHash(const CBigNum& bnValue); - -#endif //PIVX_ZEROCOIN_H diff --git a/src/zpiv/zpivmodule.h b/src/zpiv/zpivmodule.h index 94025e33af62b..2131f48018f7a 100644 --- a/src/zpiv/zpivmodule.h +++ b/src/zpiv/zpivmodule.h @@ -17,7 +17,6 @@ #include "uint256.h" #include #include -#include "zpiv/zerocoin.h" #include "chainparams.h" static int const PUBSPEND_SCHNORR = 4;