diff --git a/src/main.cpp b/src/main.cpp index 2781c6f3fb4..fda71a365dd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1593,7 +1593,7 @@ static int64_t nTimeIndex = 0; static int64_t nTimeCallbacks = 0; static int64_t nTimeTotal = 0; -bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck) { AssertLockHeld(cs_main); // Check it again in case a previous version let a bad block in @@ -2573,6 +2573,30 @@ bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDis return true; } +bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex * const pindexPrev, bool fCheckPOW, bool fCheckMerkleRoot) +{ + AssertLockHeld(cs_main); + assert(pindexPrev == chainActive.Tip()); + + CCoinsViewCache viewNew(pcoinsTip); + CBlockIndex indexDummy(block); + indexDummy.pprev = pindexPrev; + indexDummy.nHeight = pindexPrev->nHeight + 1; + + // NOTE: CheckBlockHeader is called by CheckBlock + if (!ContextualCheckBlockHeader(block, state, pindexPrev)) + return false; + if (!CheckBlock(block, state, fCheckPOW, fCheckMerkleRoot)) + return false; + if (!ContextualCheckBlock(block, state, pindexPrev)) + return false; + if (!ConnectBlock(block, state, &indexDummy, viewNew, true)) + return false; + assert(state.IsValid()); + + return true; +} + diff --git a/src/main.h b/src/main.h index 6e684be8c0e..b49f0a06ebb 100644 --- a/src/main.h +++ b/src/main.h @@ -457,7 +457,7 @@ bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex); bool DisconnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool* pfClean = NULL); // Apply the effects of this block (with given index) on the UTXO set represented by coins -bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); +bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& coins, bool fJustCheck = false); // Context-independent validity checks bool CheckBlockHeader(const CBlockHeader& block, CValidationState& state, bool fCheckPOW = true); @@ -467,6 +467,9 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW = t bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex *pindexPrev); bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIndex *pindexPrev); +// 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); + // Store block on disk // if dbp is provided, the file is known to already reside on disk bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, CDiskBlockPos* dbp = NULL); diff --git a/src/miner.cpp b/src/miner.cpp index d7ecd5e40e3..200498d109a 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -321,22 +321,9 @@ CBlockTemplate* CreateNewBlock(const CScript& scriptPubKeyIn) pblock->nNonce = 0; pblocktemplate->vTxSigOps[0] = GetLegacySigOpCount(pblock->vtx[0]); - CBlockIndex indexDummy(*pblock); - indexDummy.pprev = pindexPrev; - indexDummy.nHeight = pindexPrev->nHeight + 1; - CCoinsViewCache viewNew(pcoinsTip); CValidationState state; - // NOTE: CheckBlockHeader is called by CheckBlock - if (!ContextualCheckBlockHeader(*pblock, state, pindexPrev)) - throw std::runtime_error("CreateNewBlock() : ContextualCheckBlockHeader failed"); - if (!CheckBlock(*pblock, state, false, false)) - throw std::runtime_error("CreateNewBlock() : CheckBlock failed"); - if (!ContextualCheckBlock(*pblock, state, pindexPrev)) - throw std::runtime_error("CreateNewBlock() : ContextualCheckBlock failed"); - if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true)) - throw std::runtime_error("CreateNewBlock() : ConnectBlock failed"); - if (!state.IsValid()) - throw std::runtime_error("CreateNewBlock() : State is not valid"); + if (!TestBlockValidity(state, *pblock, pindexPrev, false, false)) + throw std::runtime_error("CreateNewBlock() : TestBlockValidity failed"); } return pblocktemplate.release();