Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move zerocoin validation to its own legacy file. #1733

Merged
merged 4 commits into from
Jul 11, 2020
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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ set(SERVER_SOURCES
./src/httpserver.cpp
./src/init.cpp
./src/dbwrapper.cpp
./src/legacy/validation_zerocoin_legacy.cpp
./src/main.cpp
./src/merkleblock.cpp
./src/miner.cpp
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ BITCOIN_CORE_H = \
dbwrapper.h \
limitedmap.h \
logging.h \
legacy/validation_zerocoin_legacy.h \
main.h \
memusage.h \
masternode.h \
Expand Down Expand Up @@ -239,6 +240,7 @@ libbitcoin_server_a_SOURCES = \
httpserver.cpp \
init.cpp \
dbwrapper.cpp \
legacy/validation_zerocoin_legacy.cpp \
main.cpp \
merkleblock.cpp \
miner.cpp \
Expand Down
130 changes: 130 additions & 0 deletions src/legacy/validation_zerocoin_legacy.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
// Copyright (c) 2020 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php.
#include "legacy/validation_zerocoin_legacy.h"

#include "consensus/zerocoin_verify.h"
#include "libzerocoin/CoinSpend.h"
#include "wallet/wallet.h"
#include "zpivchain.h"

bool AcceptToMemoryPoolZerocoin(const CTransaction& tx, CAmount& nValueIn, int chainHeight, CValidationState& state, const Consensus::Params& consensus)
{
nValueIn = tx.GetZerocoinSpent();

//Check that txid is not already in the chain
int nHeightTx = 0;
if (IsTransactionInChain(tx.GetHash(), nHeightTx))
return state.Invalid(error("%s : zPIV spend tx %s already in block %d", __func__, tx.GetHash().GetHex(), nHeightTx),
REJECT_DUPLICATE, "bad-txns-inputs-spent");

//Check for double spending of serial #'s
for (const CTxIn& txIn : tx.vin) {
// Only allow for public zc spends inputs
if (!txIn.IsZerocoinPublicSpend())
return state.Invalid(false, REJECT_INVALID, "bad-zc-spend-notpublic");

libzerocoin::ZerocoinParams* params = consensus.Zerocoin_Params(false);
PublicCoinSpend publicSpend(params);
if (!ZPIVModule::ParseZerocoinPublicSpend(txIn, tx, state, publicSpend)){
return false;
}
if (!ContextualCheckZerocoinSpend(tx, &publicSpend, chainHeight, UINT256_ZERO))
return state.Invalid(false, REJECT_INVALID, "bad-zc-spend-contextcheck");

// Check that the version matches the one enforced with SPORK_18
if (!CheckPublicCoinSpendVersion(publicSpend.getVersion())) {
return state.Invalid(false, REJECT_INVALID, "bad-zc-spend-version");
}
}

return true;
}

bool DisconnectZerocoinTx(const CTransaction& tx, CAmount& nValueIn, CZerocoinDB* zerocoinDB)
{
/** UNDO ZEROCOIN DATABASING
* note we only undo zerocoin databasing in the following statement, value to and from PIVX
* addresses should still be handled by the typical bitcoin based undo code
* */
if (tx.ContainsZerocoins()) {
libzerocoin::ZerocoinParams *params = Params().GetConsensus().Zerocoin_Params(false);
if (tx.HasZerocoinSpendInputs()) {
//erase all zerocoinspends in this transaction
for (const CTxIn &txin : tx.vin) {
bool isPublicSpend = txin.IsZerocoinPublicSpend();
if (txin.scriptSig.IsZerocoinSpend() || isPublicSpend) {
CBigNum serial;
if (isPublicSpend) {
PublicCoinSpend publicSpend(params);
CValidationState state;
if (!ZPIVModule::ParseZerocoinPublicSpend(txin, tx, state, publicSpend)) {
return error("Failed to parse public spend");
}
serial = publicSpend.getCoinSerialNumber();
nValueIn += publicSpend.getDenomination() * COIN;
} else {
libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txin);
serial = spend.getCoinSerialNumber();
nValueIn += spend.getDenomination() * COIN;
}

if (!zerocoinDB->EraseCoinSpend(serial))
return error("failed to erase spent zerocoin in block");

//if this was our spend, then mark it unspent now
if (pwalletMain) {
if (pwalletMain->IsMyZerocoinSpend(serial)) {
if (!pwalletMain->SetMintUnspent(serial))
LogPrintf("%s: failed to automatically reset mint", __func__);
}
}
}

}
}

if (tx.HasZerocoinMintOutputs()) {
//erase all zerocoinmints in this transaction
for (const CTxOut &txout : tx.vout) {
if (txout.scriptPubKey.empty() || !txout.IsZerocoinMint())
continue;

libzerocoin::PublicCoin pubCoin(params);
CValidationState state;
if (!TxOutToPublicCoin(txout, pubCoin, state))
return error("DisconnectBlock(): TxOutToPublicCoin() failed");

if (!zerocoinDB->EraseCoinMint(pubCoin.getValue()))
return error("DisconnectBlock(): Failed to erase coin mint");
}
}
}
return true;
}

// Legacy Zerocoin DB: used for performance during IBD
// (between Zerocoin_Block_V2_Start and Zerocoin_Block_Last_Checkpoint)
void DataBaseAccChecksum(CBlockIndex* pindex, bool fWrite)
{
const Consensus::Params& consensus = Params().GetConsensus();
if (!pindex ||
!consensus.NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_ZC_V2) ||
pindex->nHeight > consensus.height_last_ZC_AccumCheckpoint ||
pindex->nAccumulatorCheckpoint == pindex->pprev->nAccumulatorCheckpoint)
return;

uint256 accCurr = pindex->nAccumulatorCheckpoint;
uint256 accPrev = pindex->pprev->nAccumulatorCheckpoint;
// add/remove changed checksums to/from DB
for (int i = (int)libzerocoin::zerocoinDenomList.size()-1; i >= 0; i--) {
const uint32_t& nChecksum = accCurr.Get32();
if (nChecksum != accPrev.Get32()) {
fWrite ?
zerocoinDB->WriteAccChecksum(nChecksum, libzerocoin::zerocoinDenomList[i], pindex->nHeight) :
zerocoinDB->EraseAccChecksum(nChecksum, libzerocoin::zerocoinDenomList[i]);
}
accCurr >>= 32;
accPrev >>= 32;
}
}
16 changes: 16 additions & 0 deletions src/legacy/validation_zerocoin_legacy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) 2020 The PIVX developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or https://www.opensource.org/licenses/mit-license.php.

#ifndef VALIDATION_ZEROCOIN_LEGACY_H
#define VALIDATION_ZEROCOIN_LEGACY_H

#include "amount.h"
#include "primitives/transaction.h"
#include "txdb.h" // for the zerocoinDB implementation.

bool AcceptToMemoryPoolZerocoin(const CTransaction& tx, CAmount& nValueIn, int chainHeight, CValidationState& state, const Consensus::Params& consensus);
bool DisconnectZerocoinTx(const CTransaction& tx, CAmount& nValueIn, CZerocoinDB* zerocoinDB);
void DataBaseAccChecksum(CBlockIndex* pindex, bool fWrite);

#endif //VALIDATION_ZEROCOIN_LEGACY_H
114 changes: 5 additions & 109 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "zpivchain.h"

#include "invalid.h"
#include "legacy/validation_zerocoin_legacy.h"
#include "libzerocoin/Denominations.h"
#include "masternode-sync.h"
#include "zpiv/zerocoin.h"
Expand Down Expand Up @@ -906,33 +907,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState& state, const CTransa

CAmount nValueIn = 0;
if (hasZcSpendInputs) {
nValueIn = tx.GetZerocoinSpent();

//Check that txid is not already in the chain
int nHeightTx = 0;
if (IsTransactionInChain(tx.GetHash(), nHeightTx))
return state.Invalid(error("%s : zPIV spend tx %s already in block %d", __func__, tx.GetHash().GetHex(), nHeightTx),
REJECT_DUPLICATE, "bad-txns-inputs-spent");

//Check for double spending of serial #'s
for (const CTxIn& txIn : tx.vin) {
// Only allow for public zc spends inputs
if (!txIn.IsZerocoinPublicSpend())
return state.Invalid(false, REJECT_INVALID, "bad-zc-spend-notpublic");

libzerocoin::ZerocoinParams* params = consensus.Zerocoin_Params(false);
PublicCoinSpend publicSpend(params);
if (!ZPIVModule::ParseZerocoinPublicSpend(txIn, tx, state, publicSpend)){
return false;
}
if (!ContextualCheckZerocoinSpend(tx, &publicSpend, chainHeight, UINT256_ZERO))
return state.Invalid(false, REJECT_INVALID, "bad-zc-spend-contextcheck");

// Check that the version matches the one enforced with SPORK_18
if (!CheckPublicCoinSpendVersion(publicSpend.getVersion())) {
return state.Invalid(false, REJECT_INVALID, "bad-zc-spend-version");
}

if (!AcceptToMemoryPoolZerocoin(tx, nValueIn, chainHeight, state, consensus)) {
return false;
}
} else {
LOCK(pool.cs);
Expand Down Expand Up @@ -1935,32 +1911,6 @@ static bool AbortNode(CValidationState& state, const std::string& strMessage, co
return state.Error(strMessage);
}

// Legacy Zerocoin DB: used for performance during IBD
// (between Zerocoin_Block_V2_Start and Zerocoin_Block_Last_Checkpoint)
void DataBaseAccChecksum(CBlockIndex* pindex, bool fWrite)
{
const Consensus::Params& consensus = Params().GetConsensus();
if (!pindex ||
!consensus.NetworkUpgradeActive(pindex->nHeight, Consensus::UPGRADE_ZC_V2) ||
pindex->nHeight > consensus.height_last_ZC_AccumCheckpoint ||
pindex->nAccumulatorCheckpoint == pindex->pprev->nAccumulatorCheckpoint)
return;

uint256 accCurr = pindex->nAccumulatorCheckpoint;
uint256 accPrev = pindex->pprev->nAccumulatorCheckpoint;
// add/remove changed checksums to/from DB
for (int i = (int)libzerocoin::zerocoinDenomList.size()-1; i >= 0; i--) {
const uint32_t& nChecksum = accCurr.Get32();
if (nChecksum != accPrev.Get32()) {
fWrite ?
zerocoinDB->WriteAccChecksum(nChecksum, libzerocoin::zerocoinDenomList[i], pindex->nHeight) :
zerocoinDB->EraseAccChecksum(nChecksum, libzerocoin::zerocoinDenomList[i]);
}
accCurr >>= 32;
accPrev >>= 32;
}
}

bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool* pfClean)
{
AssertLockHeld(cs_main);
Expand Down Expand Up @@ -1994,64 +1944,10 @@ bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex
for (int i = block.vtx.size() - 1; i >= 0; i--) {
const CTransaction& tx = block.vtx[i];

/** UNDO ZEROCOIN DATABASING
* note we only undo zerocoin databasing in the following statement, value to and from PIVX
* addresses should still be handled by the typical bitcoin based undo code
* */
if (tx.ContainsZerocoins()) {
libzerocoin::ZerocoinParams *params = Params().GetConsensus().Zerocoin_Params(false);
if (tx.HasZerocoinSpendInputs()) {
//erase all zerocoinspends in this transaction
for (const CTxIn &txin : tx.vin) {
bool isPublicSpend = txin.IsZerocoinPublicSpend();
if (txin.scriptSig.IsZerocoinSpend() || isPublicSpend) {
CBigNum serial;
if (isPublicSpend) {
PublicCoinSpend publicSpend(params);
CValidationState state;
if (!ZPIVModule::ParseZerocoinPublicSpend(txin, tx, state, publicSpend)) {
return error("Failed to parse public spend");
}
serial = publicSpend.getCoinSerialNumber();
nValueIn += publicSpend.getDenomination() * COIN;
} else {
libzerocoin::CoinSpend spend = TxInToZerocoinSpend(txin);
serial = spend.getCoinSerialNumber();
nValueIn += spend.getDenomination() * COIN;
}

if (!zerocoinDB->EraseCoinSpend(serial))
return error("failed to erase spent zerocoin in block");

//if this was our spend, then mark it unspent now
if (pwalletMain) {
if (pwalletMain->IsMyZerocoinSpend(serial)) {
if (!pwalletMain->SetMintUnspent(serial))
LogPrintf("%s: failed to automatically reset mint", __func__);
}
}
}

}
}

if (tx.HasZerocoinMintOutputs()) {
//erase all zerocoinmints in this transaction
for (const CTxOut &txout : tx.vout) {
if (txout.scriptPubKey.empty() || !txout.IsZerocoinMint())
continue;

libzerocoin::PublicCoin pubCoin(params);
if (!TxOutToPublicCoin(txout, pubCoin, state))
return error("DisconnectBlock(): TxOutToPublicCoin() failed");
if (!DisconnectZerocoinTx(tx, nValueIn, zerocoinDB))
return false;

if (!zerocoinDB->EraseCoinMint(pubCoin.getValue()))
return error("DisconnectBlock(): Failed to erase coin mint");
}
}
}
nValueOut += tx.GetValueOut();

uint256 hash = tx.GetHash();


Expand Down