|
|
@ -833,7 +833,8 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, const CCoinsViewCache& in |
|
|
|
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
|
|
|
|
if (!tx.IsCoinBase()) { |
|
|
@ -844,7 +845,6 @@ bool CheckTransaction(const CTransaction& tx, CValidationState &state) |
|
|
|
return false; |
|
|
|
} else { |
|
|
|
// Ensure that zk-SNARKs verify
|
|
|
|
auto verifier = libzcash::ProofVerifier::Strict(); |
|
|
|
BOOST_FOREACH(const JSDescription &joinsplit, tx.vjoinsplit) { |
|
|
|
if (!joinsplit.Verify(*pzcashParams, verifier, tx.joinSplitPubKey)) { |
|
|
|
return state.DoS(100, error("CheckTransaction(): joinsplit does not verify"), |
|
|
@ -1056,7 +1056,8 @@ bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransa |
|
|
|
if (pfMissingInputs) |
|
|
|
*pfMissingInputs = false; |
|
|
|
|
|
|
|
if (!CheckTransaction(tx, state)) |
|
|
|
auto verifier = libzcash::ProofVerifier::Strict(); |
|
|
|
if (!CheckTransaction(tx, state, verifier)) |
|
|
|
return error("AcceptToMemoryPool: CheckTransaction failed"); |
|
|
|
|
|
|
|
// 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(); |
|
|
|
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; |
|
|
|
|
|
|
|
// 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; |
|
|
|
} |
|
|
|
|
|
|
|
bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints())); |
|
|
|
|
|
|
|
// Do not allow blocks that contain transactions which 'overwrite' older transactions,
|
|
|
|
// unless those are already completely spent.
|
|
|
|
BOOST_FOREACH(const CTransaction& tx, block.vtx) { |
|
|
@ -2088,7 +2092,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin |
|
|
|
|
|
|
|
CBlockUndo blockundo; |
|
|
|
|
|
|
|
CCheckQueueControl<CScriptCheck> control(fScriptChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); |
|
|
|
CCheckQueueControl<CScriptCheck> control(fExpensiveChecks && nScriptCheckThreads ? &scriptcheckqueue : NULL); |
|
|
|
|
|
|
|
int64_t nTimeStart = GetTimeMicros(); |
|
|
|
CAmount nFees = 0; |
|
|
@ -2149,7 +2153,7 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin |
|
|
|
nFees += view.GetValueIn(tx)-tx.GetValueOut(); |
|
|
|
|
|
|
|
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; |
|
|
|
control.Add(vChecks); |
|
|
|
} |
|
|
@ -2976,7 +2980,9 @@ bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool f |
|
|
|
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.
|
|
|
|
|
|
|
@ -3021,7 +3027,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo |
|
|
|
|
|
|
|
// Check transactions
|
|
|
|
BOOST_FOREACH(const CTransaction& tx, block.vtx) |
|
|
|
if (!CheckTransaction(tx, state)) |
|
|
|
if (!CheckTransaction(tx, state, verifier)) |
|
|
|
return error("CheckBlock(): CheckTransaction failed"); |
|
|
|
|
|
|
|
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 ((!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()) { |
|
|
|
pindex->nStatus |= BLOCK_FAILED_VALID; |
|
|
|
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) |
|
|
|
{ |
|
|
|
// Preliminary checks
|
|
|
|
bool checked = CheckBlock(*pblock, state); |
|
|
|
auto verifier = libzcash::ProofVerifier::Disabled(); |
|
|
|
bool checked = CheckBlock(*pblock, state, verifier); |
|
|
|
|
|
|
|
{ |
|
|
|
LOCK(cs_main); |
|
|
@ -3294,11 +3303,13 @@ bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex |
|
|
|
CBlockIndex indexDummy(block); |
|
|
|
indexDummy.pprev = pindexPrev; |
|
|
|
indexDummy.nHeight = pindexPrev->nHeight + 1; |
|
|
|
// JoinSplit proofs are verified in ConnectBlock
|
|
|
|
auto verifier = libzcash::ProofVerifier::Disabled(); |
|
|
|
|
|
|
|
// NOTE: CheckBlockHeader is called by CheckBlock
|
|
|
|
if (!ContextualCheckBlockHeader(block, state, pindexPrev)) |
|
|
|
return false; |
|
|
|
if (!CheckBlock(block, state, fCheckPOW, fCheckMerkleRoot)) |
|
|
|
if (!CheckBlock(block, state, verifier, fCheckPOW, fCheckMerkleRoot)) |
|
|
|
return false; |
|
|
|
if (!ContextualCheckBlock(block, state, pindexPrev)) |
|
|
|
return false; |
|
|
@ -3619,6 +3630,8 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth |
|
|
|
CBlockIndex* pindexFailure = NULL; |
|
|
|
int nGoodTransactions = 0; |
|
|
|
CValidationState state; |
|
|
|
// No need to verify JoinSplits twice
|
|
|
|
auto verifier = libzcash::ProofVerifier::Disabled(); |
|
|
|
for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) |
|
|
|
{ |
|
|
|
boost::this_thread::interruption_point(); |
|
|
@ -3630,7 +3643,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth |
|
|
|
if (!ReadBlockFromDisk(block, pindex)) |
|
|
|
return error("VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString()); |
|
|
|
// 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()); |
|
|
|
// check level 2: verify undo validity
|
|
|
|
if (nCheckLevel >= 2 && pindex) { |
|
|
|