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

[Cleanup] The zerocoin garbage collector is in town once more. #2425

Merged
Merged
Changes from 1 commit
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
Prev Previous commit
Validation cleanup: Inside ConnectBlock, move coinSpend parse and val…
…idation to zerocoin_verify file.
furszy committed Jul 1, 2021
commit 017ee3e8a49abd238d12a0491ea142dd8464f397
43 changes: 43 additions & 0 deletions src/consensus/zerocoin_verify.cpp
Original file line number Diff line number Diff line change
@@ -250,3 +250,46 @@ bool ContextualCheckZerocoinSpendNoSerialCheck(const CTransaction& tx, const lib
return true;
}

Optional<CoinSpendValues> 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>(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>(CoinSpendValues(spend.getCoinSerialNumber(), spend.getDenomination() * COIN));
}
}
return nullopt;
}
11 changes: 11 additions & 0 deletions src/consensus/zerocoin_verify.h
Original file line number Diff line number Diff line change
@@ -19,4 +19,15 @@ bool ContextualCheckZerocoinTx(const CTransactionRef& tx, CValidationState& stat
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<CoinSpendValues> ParseAndValidateZerocoinSpend(const Consensus::Params& consensus,
const CTransaction& tx, int chainHeight,
CValidationState& state);

#endif //PIVX_CONSENSUS_ZEROCOIN_VERIFY_H
6 changes: 3 additions & 3 deletions src/txdb.cpp
Original file line number Diff line number Diff line change
@@ -356,12 +356,12 @@ CZerocoinDB::CZerocoinDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapp
{
}

bool CZerocoinDB::WriteCoinSpendBatch(const std::vector<std::pair<libzerocoin::CoinSpend, uint256> >& spendInfo)
bool CZerocoinDB::WriteCoinSpendBatch(const std::vector<std::pair<CBigNum, uint256> >& spendInfo)
{
CDBBatch batch;
size_t count = 0;
for (std::vector<std::pair<libzerocoin::CoinSpend, uint256> >::const_iterator it=spendInfo.begin(); it != spendInfo.end(); it++) {
CBigNum bnSerial = it->first.getCoinSerialNumber();
for (std::vector<std::pair<CBigNum, uint256> >::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());
6 changes: 4 additions & 2 deletions src/txdb.h
Original file line number Diff line number Diff line change
@@ -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<std::pair<libzerocoin::CoinSpend, uint256> >& spendInfo);
/** Write zPIV spends to the zerocoinDB in a batch
* Pair of: CBigNum -> coinSerialNumber and uint256 -> txHash.
*/
bool WriteCoinSpendBatch(const std::vector<std::pair<CBigNum, uint256> >& spendInfo);
bool ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash);
bool EraseCoinSpend(const CBigNum& bnSerial);

38 changes: 6 additions & 32 deletions src/validation.cpp
Original file line number Diff line number Diff line change
@@ -1547,7 +1547,7 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
unsigned int nSigOps = 0;
CDiskTxPos pos(pindex->GetBlockPos(), GetSizeOfCompactSize(block.vtx.size()));
std::vector<std::pair<uint256, CDiskTxPos> > vPos;
std::vector<std::pair<libzerocoin::CoinSpend, uint256> > vSpends;
std::vector<std::pair<CBigNum, uint256> > vSpends;
vPos.reserve(block.vtx.size());
CBlockUndo blockundo;
blockundo.vtxundo.reserve(block.vtx.size() - 1);
@@ -1587,38 +1587,12 @@ static bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockInd
}

if (tx.HasZerocoinSpendInputs()) {
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))
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))
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");