Auto merge of #1892 - str4d:1749-disable-js-verification-before-checkpoints, r=str4d

Skip JoinSplit verification before the last checkpoint

Part of #1749
This commit is contained in:
zkbot 2016-12-13 10:36:48 +00:00
commit 5c47d620f4
6 changed files with 66 additions and 33 deletions

View File

@ -3,6 +3,7 @@
#include "consensus/validation.h" #include "consensus/validation.h"
#include "main.h" #include "main.h"
#include "zcash/Proof.hpp"
class MockCValidationState : public CValidationState { class MockCValidationState : public CValidationState {
public: public:
@ -22,12 +23,14 @@ public:
}; };
TEST(CheckBlock, VersionTooLow) { TEST(CheckBlock, VersionTooLow) {
auto verifier = libzcash::ProofVerifier::Strict();
CBlock block; CBlock block;
block.nVersion = 1; block.nVersion = 1;
MockCValidationState state; MockCValidationState state;
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "version-too-low", false)).Times(1); EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "version-too-low", false)).Times(1);
EXPECT_FALSE(CheckBlock(block, state, false, false)); EXPECT_FALSE(CheckBlock(block, state, verifier, false, false));
} }
TEST(ContextualCheckBlock, BadCoinbaseHeight) { TEST(ContextualCheckBlock, BadCoinbaseHeight) {

View File

@ -833,7 +833,8 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in
return nSigOps; return nSigOps;
} }
bool CheckTransaction(const CTransaction& tx, CValidationState &state) bool CheckTransaction(const CTransaction& tx, CValidationState &state,
libzcash::ProofVerifier& verifier)
{ {
// Don't count coinbase transactions because mining skews the count // Don't count coinbase transactions because mining skews the count
if (!tx.IsCoinBase()) { if (!tx.IsCoinBase()) {
@ -844,7 +845,6 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state)
return false; return false;
} else { } else {
// Ensure that zk-SNARKs verify // Ensure that zk-SNARKs verify
auto verifier = libzcash::ProofVerifier::Strict();
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) {
if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) { if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) {
return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"), return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"),
@ -1056,7 +1056,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa
if (pfMissingInputs) if (pfMissingInputs)
*pfMissingInputs = false; *pfMissingInputs = false;
if (!CheckTransaction(tx, state)) auto verifier = libzcash::ProofVerifier::Strict();
if (!CheckTransaction(tx, state, verifier))
return error("AcceptToMemoryPool: CheckTransaction failed"); return error("AcceptToMemoryPool: CheckTransaction failed");
// Coinbase is only valid in a block, not as a loose transaction // Coinbase is only valid in a block, not as a loose transaction
@ -2041,8 +2042,13 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
{ {
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
// Check it again in case a previous version let a bad block in
if (!CheckBlock(block, state, !fJustCheck, !fJustCheck)) bool fExpensiveChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()));
auto verifier = libzcash::ProofVerifier::Strict();
auto disabledVerifier = libzcash::ProofVerifier::Disabled();
// Check it again to verify JoinSplit proofs, and in case a previous version let a bad block in
if (!CheckBlock(block, state, fExpensiveChecks ? verifier : disabledVerifier, !fJustCheck, !fJustCheck))
return false; return false;
// verify that the view's current state corresponds to the previous block // verify that the view's current state corresponds to the previous block
@ -2061,8 +2067,6 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return true; return true;
} }
bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints()));
// Do not allow blocks that contain transactions which 'overwrite' older transactions, // Do not allow blocks that contain transactions which 'overwrite' older transactions,
// unless those are already completely spent. // unless those are already completely spent.
BOOST_FOREACH(const CTransaction& tx, block.vtx) { BOOST_FOREACH(const CTransaction& tx, block.vtx) {
@ -2088,7 +2092,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
CBlockUndo blockundo; CBlockUndo blockundo;
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); CCheckQueueControl<CScriptCheck> control(fExpensiveChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL);
int64_t nTimeStart = GetTimeMicros(); int64_t nTimeStart = GetTimeMicros();
CAmount nFees = 0; CAmount nFees = 0;
@ -2149,7 +2153,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
nFees += view.GetValueIn(tx)-tx.GetValueOut(); nFees += view.GetValueIn(tx)-tx.GetValueOut();
std::vector<CScriptCheck> vChecks; std::vector<CScriptCheck> vChecks;
if (!ContextualCheckInputs(tx, state, view, fScriptChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL)) if (!ContextualCheckInputs(tx, state, view, fExpensiveChecks, flags, false, chainparams.GetConsensus(), nScriptCheckThreads ? &vChecks : NULL))
return false; return false;
control.Add(vChecks); control.Add(vChecks);
} }
@ -2976,7 +2980,9 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f
return true; return true;
} }
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bool fCheckMerkleRoot) bool CheckBlock(const CBlock& block, CValidationState& state,
libzcash::ProofVerifier& verifier,
bool fCheckPOW, bool fCheckMerkleRoot)
{ {
// These are checks that are independent of context. // These are checks that are independent of context.
@ -3021,7 +3027,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
// Check transactions // Check transactions
BOOST_FOREACH(const CTransaction& tx, block.vtx) BOOST_FOREACH(const CTransaction& tx, block.vtx)
if (!CheckTransaction(tx, state)) if (!CheckTransaction(tx, state, verifier))
return error("CheckBlock(): CheckTransaction failed"); return error("CheckBlock(): CheckTransaction failed");
unsigned int nSigOps = 0; unsigned int nSigOps = 0;
@ -3209,7 +3215,9 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
if (fTooFarAhead) return true; // Block height is too high if (fTooFarAhead) return true; // Block height is too high
} }
if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) { // See method docstring for why this is always disabled
auto verifier = libzcash::ProofVerifier::Disabled();
if ((!CheckBlock(block, state, verifier)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
if (state.IsInvalid() && !state.CorruptionPossible()) { if (state.IsInvalid() && !state.CorruptionPossible()) {
pindex->nStatus |= BLOCK_FAILED_VALID; pindex->nStatus |= BLOCK_FAILED_VALID;
setDirtyBlockIndex.insert(pindex); setDirtyBlockIndex.insert(pindex);
@ -3258,7 +3266,8 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp) bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp)
{ {
// Preliminary checks // Preliminary checks
bool checked = CheckBlock(*pblock, state); auto verifier = libzcash::ProofVerifier::Disabled();
bool checked = CheckBlock(*pblock, state, verifier);
{ {
LOCK(cs_main); LOCK(cs_main);
@ -3294,11 +3303,13 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex
CBlockIndex indexDummy(block); CBlockIndex indexDummy(block);
indexDummy.pprev = pindexPrev; indexDummy.pprev = pindexPrev;
indexDummy.nHeight = pindexPrev->nHeight + 1; indexDummy.nHeight = pindexPrev->nHeight + 1;
// JoinSplit proofs are verified in ConnectBlock
auto verifier = libzcash::ProofVerifier::Disabled();
// NOTE: CheckBlockHeader is called by CheckBlock // NOTE: CheckBlockHeader is called by CheckBlock
if (!ContextualCheckBlockHeader(block, state, pindexPrev)) if (!ContextualCheckBlockHeader(block, state, pindexPrev))
return false; return false;
if (!CheckBlock(block, state, fCheckPOW, fCheckMerkleRoot)) if (!CheckBlock(block, state, verifier, fCheckPOW, fCheckMerkleRoot))
return false; return false;
if (!ContextualCheckBlock(block, state, pindexPrev)) if (!ContextualCheckBlock(block, state, pindexPrev))
return false; return false;
@ -3619,6 +3630,8 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
CBlockIndex* pindexFailure = NULL; CBlockIndex* pindexFailure = NULL;
int nGoodTransactions = 0; int nGoodTransactions = 0;
CValidationState state; CValidationState state;
// No need to verify JoinSplits twice
auto verifier = libzcash::ProofVerifier::Disabled();
for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
{ {
boost::this_thread::interruption_point(); boost::this_thread::interruption_point();
@ -3630,7 +3643,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
if (!ReadBlockFromDisk(block, pindex)) if (!ReadBlockFromDisk(block, pindex))
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 1: verify block validity // check level 1: verify block validity
if (nCheckLevel >= 1 && !CheckBlock(block, state)) if (nCheckLevel >= 1 && !CheckBlock(block, state, verifier))
return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); return error("VerifyDB(): *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
// check level 2: verify undo validity // check level 2: verify undo validity
if (nCheckLevel >= 2 && pindex) { if (nCheckLevel >= 2 && pindex) {

View File

@ -339,7 +339,7 @@ bool NonContextualCheckInputs(const CTransaction& tx, CValidationState &state, c
void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight); void UpdateCoins(const CTransaction& tx, CValidationState &state, CCoinsViewCache &inputs, int nHeight);
/** Context-independent validity checks */ /** Context-independent validity checks */
bool CheckTransaction(const CTransaction& tx, CValidationState& state); bool CheckTransaction(const CTransaction& tx, CValidationState& state, libzcash::ProofVerifier& verifier);
bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state); bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidationState &state);
/** Check for standard transaction types /** Check for standard transaction types
@ -416,7 +416,9 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
/** Context-independent validity checks */ /** Context-independent validity checks */
bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true);
bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = true, bool fCheckMerkleRoot = true); bool CheckBlock(const CBlock& block, CValidationState& state,
libzcash::ProofVerifier& verifier,
bool fCheckPOW = true, bool fCheckMerkleRoot = true);
/** Context-dependent validity checks */ /** Context-dependent validity checks */
bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev); bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev);
@ -425,7 +427,13 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */ /** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true); bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */ /**
* Store block on disk.
* JoinSplit proofs are never verified, because:
* - AcceptBlock doesn't perform script checks either.
* - The only caller of AcceptBlock verifies JoinSplit proofs elsewhere.
* If dbp is non-NULL, the file is known to already reside on disk
*/
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp); bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp);
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL); bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);

View File

@ -7,6 +7,7 @@
#include "main.h" #include "main.h"
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"
#include "utiltime.h" #include "utiltime.h"
#include "zcash/Proof.hpp"
#include <cstdio> #include <cstdio>
@ -56,7 +57,8 @@ BOOST_AUTO_TEST_CASE(May15)
// After May 15'th, big blocks are OK: // After May 15'th, big blocks are OK:
forkingBlock.nTime = tMay15; // Invalidates PoW forkingBlock.nTime = tMay15; // Invalidates PoW
BOOST_CHECK(CheckBlock(forkingBlock, state, false, false)); auto verifier = libzcash::ProofVerifier::Strict();
BOOST_CHECK(CheckBlock(forkingBlock, state, verifier, false, false));
} }
SetMockTime(0); SetMockTime(0);

View File

@ -29,6 +29,7 @@
#include "zcash/Note.hpp" #include "zcash/Note.hpp"
#include "zcash/Address.hpp" #include "zcash/Address.hpp"
#include "zcash/Proof.hpp"
using namespace std; using namespace std;
using namespace json_spirit; using namespace json_spirit;
@ -97,6 +98,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE" // verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid))); Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
auto verifier = libzcash::ProofVerifier::Strict();
ScriptError err; ScriptError err;
BOOST_FOREACH(Value& tv, tests) BOOST_FOREACH(Value& tv, tests)
{ {
@ -141,7 +143,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
stream >> tx; stream >> tx;
CValidationState state; CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state), strTest); BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier), strTest);
BOOST_CHECK(state.IsValid()); BOOST_CHECK(state.IsValid());
for (unsigned int i = 0; i < tx.vin.size(); i++) for (unsigned int i = 0; i < tx.vin.size(); i++)
@ -173,6 +175,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE" // verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid))); Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
auto verifier = libzcash::ProofVerifier::Strict();
ScriptError err; ScriptError err;
BOOST_FOREACH(Value& tv, tests) BOOST_FOREACH(Value& tv, tests)
{ {
@ -217,7 +220,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
stream >> tx; stream >> tx;
CValidationState state; CValidationState state;
fValid = CheckTransaction(tx, state) && state.IsValid(); fValid = CheckTransaction(tx, state, verifier) && state.IsValid();
for (unsigned int i = 0; i < tx.vin.size() && fValid; i++) for (unsigned int i = 0; i < tx.vin.size() && fValid; i++)
{ {
@ -246,11 +249,12 @@ BOOST_AUTO_TEST_CASE(basic_transaction_tests)
CMutableTransaction tx; CMutableTransaction tx;
stream >> tx; stream >> tx;
CValidationState state; CValidationState state;
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state) && state.IsValid(), "Simple deserialized transaction should be valid."); auto verifier = libzcash::ProofVerifier::Strict();
BOOST_CHECK_MESSAGE(CheckTransaction(tx, state, verifier) && state.IsValid(), "Simple deserialized transaction should be valid.");
// Check that duplicate txins fail // Check that duplicate txins fail
tx.vin.push_back(tx.vin[0]); tx.vin.push_back(tx.vin[0]);
BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state) || !state.IsValid(), "Transaction with duplicate txins should be invalid."); BOOST_CHECK_MESSAGE(!CheckTransaction(tx, state, verifier) || !state.IsValid(), "Transaction with duplicate txins should be invalid.");
} }
// //
@ -373,6 +377,7 @@ BOOST_AUTO_TEST_CASE(test_basic_joinsplit_verification)
BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity) BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
{ {
auto verifier = libzcash::ProofVerifier::Strict();
CMutableTransaction tx; CMutableTransaction tx;
tx.nVersion = 2; tx.nVersion = 2;
{ {
@ -424,23 +429,23 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
JSDescription *jsdesc = &newTx.vjoinsplit[0]; JSDescription *jsdesc = &newTx.vjoinsplit[0];
jsdesc->vpub_old = -1; jsdesc->vpub_old = -1;
BOOST_CHECK(!CheckTransaction(newTx, state)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-negative"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-negative");
jsdesc->vpub_old = MAX_MONEY + 1; jsdesc->vpub_old = MAX_MONEY + 1;
BOOST_CHECK(!CheckTransaction(newTx, state)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-toolarge"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_old-toolarge");
jsdesc->vpub_old = 0; jsdesc->vpub_old = 0;
jsdesc->vpub_new = -1; jsdesc->vpub_new = -1;
BOOST_CHECK(!CheckTransaction(newTx, state)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-negative"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-negative");
jsdesc->vpub_new = MAX_MONEY + 1; jsdesc->vpub_new = MAX_MONEY + 1;
BOOST_CHECK(!CheckTransaction(newTx, state)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-toolarge"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-vpub_new-toolarge");
jsdesc->vpub_new = (MAX_MONEY / 2) + 10; jsdesc->vpub_new = (MAX_MONEY / 2) + 10;
@ -450,7 +455,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
JSDescription *jsdesc2 = &newTx.vjoinsplit[1]; JSDescription *jsdesc2 = &newTx.vjoinsplit[1];
jsdesc2->vpub_new = (MAX_MONEY / 2) + 10; jsdesc2->vpub_new = (MAX_MONEY / 2) + 10;
BOOST_CHECK(!CheckTransaction(newTx, state)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-txns-txintotal-toolarge"); BOOST_CHECK(state.GetRejectReason() == "bad-txns-txintotal-toolarge");
} }
{ {
@ -464,7 +469,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
jsdesc->nullifiers[0] = GetRandHash(); jsdesc->nullifiers[0] = GetRandHash();
jsdesc->nullifiers[1] = jsdesc->nullifiers[0]; jsdesc->nullifiers[1] = jsdesc->nullifiers[0];
BOOST_CHECK(!CheckTransaction(newTx, state)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate"); BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
jsdesc->nullifiers[1] = GetRandHash(); jsdesc->nullifiers[1] = GetRandHash();
@ -475,7 +480,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
jsdesc2->nullifiers[0] = GetRandHash(); jsdesc2->nullifiers[0] = GetRandHash();
jsdesc2->nullifiers[1] = jsdesc->nullifiers[0]; jsdesc2->nullifiers[1] = jsdesc->nullifiers[0];
BOOST_CHECK(!CheckTransaction(newTx, state)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate"); BOOST_CHECK(state.GetRejectReason() == "bad-joinsplits-nullifiers-duplicate");
} }
{ {
@ -494,7 +499,7 @@ BOOST_AUTO_TEST_CASE(test_simple_joinsplit_invalidity)
CTransaction finalNewTx(newTx); CTransaction finalNewTx(newTx);
BOOST_CHECK(finalNewTx.IsCoinBase()); BOOST_CHECK(finalNewTx.IsCoinBase());
} }
BOOST_CHECK(!CheckTransaction(newTx, state)); BOOST_CHECK(!CheckTransaction(newTx, state, verifier));
BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-joinsplits"); BOOST_CHECK(state.GetRejectReason() == "bad-cb-has-joinsplits");
} }
} }

View File

@ -14,6 +14,7 @@
#include "util.h" #include "util.h"
#include "utiltime.h" #include "utiltime.h"
#include "wallet/wallet.h" #include "wallet/wallet.h"
#include "zcash/Proof.hpp"
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -411,7 +412,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
CWalletTx wtx; CWalletTx wtx;
ssValue >> wtx; ssValue >> wtx;
CValidationState state; CValidationState state;
if (!(CheckTransaction(wtx, state) && (wtx.GetHash() == hash) && state.IsValid())) auto verifier = libzcash::ProofVerifier::Strict();
if (!(CheckTransaction(wtx, state, verifier) && (wtx.GetHash() == hash) && state.IsValid()))
return false; return false;
// Undo serialize changes in 31600 // Undo serialize changes in 31600