diff --git a/src/miner.cpp b/src/miner.cpp --- a/src/miner.cpp +++ b/src/miner.cpp @@ -214,7 +214,10 @@ GetSigOpCountWithoutP2SH(*pblock->vtx[0]); CValidationState state; - if (!TestBlockValidity(*config, state, *pblock, pindexPrev, false, false)) { + BlockValidationOptions validationOptions = + BlockValidationOptions(false, false); + if (!TestBlockValidity(*config, state, *pblock, pindexPrev, + validationOptions)) { throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, FormatStateMessage(state))); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -516,7 +516,10 @@ return "inconclusive-not-best-prevblk"; } CValidationState state; - TestBlockValidity(config, state, block, pindexPrev, false, true); + BlockValidationOptions validationOptions = + BlockValidationOptions(false, true); + TestBlockValidity(config, state, block, pindexPrev, + validationOptions); return BIP22ValidationResult(config, state); } diff --git a/src/test/blockcheck_tests.cpp b/src/test/blockcheck_tests.cpp --- a/src/test/blockcheck_tests.cpp +++ b/src/test/blockcheck_tests.cpp @@ -17,7 +17,9 @@ static void RunCheckOnBlockImpl(const GlobalConfig &config, const CBlock &block, CValidationState &state, bool expected) { block.fChecked = false; - bool fValid = CheckBlock(config, block, state, false, false); + BlockValidationOptions validationOptions = + BlockValidationOptions(false, false); + bool fValid = CheckBlock(config, block, state, validationOptions); BOOST_CHECK_EQUAL(fValid, expected); BOOST_CHECK_EQUAL(fValid, state.IsValid()); diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -271,6 +271,21 @@ */ static const uint64_t MIN_DISK_SPACE_FOR_BLOCK_FILES = 550 * 1024 * 1024; +class BlockValidationOptions { +private: + bool checkPoW : 1; + bool checkMerkleRoot : 1; + +public: + // Do full validation by default + BlockValidationOptions() : checkPoW(true), checkMerkleRoot(true) {} + BlockValidationOptions(bool checkPoWIn, bool checkMerkleRootIn) + : checkPoW(checkPoWIn), checkMerkleRoot(checkMerkleRootIn) {} + + bool shouldValidatePoW() const { return checkPoW; } + bool shouldValidateMerkleRoot() const { return checkMerkleRoot; } +}; + /** * Process an incoming block. This only returns after the best known valid * block is made active. Note that it does not, however, guarantee that the @@ -579,9 +594,9 @@ * Returns true if the provided block is valid (has valid header, * transactions are valid, block is a valid size, etc.) */ -bool CheckBlock(const Config &Config, const CBlock &block, - CValidationState &state, bool fCheckPOW = true, - bool fCheckMerkleRoot = true); +bool CheckBlock( + const Config &Config, const CBlock &block, CValidationState &state, + BlockValidationOptions validationOptions = BlockValidationOptions()); /** * Context dependent validity checks for non coinbase transactions. This @@ -608,9 +623,10 @@ * 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(const Config &config, CValidationState &state, - const CBlock &block, CBlockIndex *pindexPrev, - bool fCheckPOW = true, bool fCheckMerkleRoot = true); +bool TestBlockValidity( + const Config &config, CValidationState &state, const CBlock &block, + CBlockIndex *pindexPrev, + BlockValidationOptions validationOptions = BlockValidationOptions()); /** * When there are blocks in the active chain with missing data, rewind the diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1965,7 +1965,9 @@ int64_t nTimeStart = GetTimeMicros(); // Check it again in case a previous version let a bad block in - if (!CheckBlock(config, block, state, !fJustCheck, !fJustCheck)) { + BlockValidationOptions validationOptions = + BlockValidationOptions(!fJustCheck, !fJustCheck); + if (!CheckBlock(config, block, state, validationOptions)) { return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); } @@ -3378,10 +3380,20 @@ return true; } -static bool CheckBlockHeader(const Config &config, const CBlockHeader &block, - CValidationState &state, bool fCheckPOW = true) { +/** + * Return true if the provided block header is valid. + * Only verify PoW if blockValidationOptions is configured to do so. + * This allows validation of headers on which the PoW hasn't been done. + * For example: to validate template handed to mining software. + * Do not call this for any check that depends on the context. + * For context-dependant calls, see ContextualCheckBlockHeader. + */ +static bool CheckBlockHeader( + const Config &config, const CBlockHeader &block, CValidationState &state, + BlockValidationOptions validationOptions = BlockValidationOptions()) { // Check proof of work matches claimed amount - if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits, config)) { + if (validationOptions.shouldValidatePoW() && + !CheckProofOfWork(block.GetHash(), block.nBits, config)) { return state.DoS(50, false, REJECT_INVALID, "high-hash", false, "proof of work failed"); } @@ -3390,8 +3402,8 @@ } bool CheckBlock(const Config &config, const CBlock &block, - CValidationState &state, bool fCheckPOW, - bool fCheckMerkleRoot) { + CValidationState &state, + BlockValidationOptions validationOptions) { // These are checks that are independent of context. if (block.fChecked) { return true; @@ -3399,12 +3411,12 @@ // Check that the header is valid (particularly PoW). This is mostly // redundant with the call in AcceptBlockHeader. - if (!CheckBlockHeader(config, block, state, fCheckPOW)) { + if (!CheckBlockHeader(config, block, state, validationOptions)) { return false; } // Check the merkle root. - if (fCheckMerkleRoot) { + if (validationOptions.shouldValidateMerkleRoot()) { bool mutated; uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated); if (block.hashMerkleRoot != hashMerkleRoot2) { @@ -3494,7 +3506,8 @@ } } - if (fCheckPOW && fCheckMerkleRoot) { + if (validationOptions.shouldValidatePoW() && + validationOptions.shouldValidateMerkleRoot()) { block.fChecked = true; } @@ -3949,7 +3962,7 @@ bool TestBlockValidity(const Config &config, CValidationState &state, const CBlock &block, CBlockIndex *pindexPrev, - bool fCheckPOW, bool fCheckMerkleRoot) { + BlockValidationOptions validationOptions) { AssertLockHeld(cs_main); const CChainParams &chainparams = config.GetChainParams(); @@ -3972,7 +3985,7 @@ return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, FormatStateMessage(state)); } - if (!CheckBlock(config, block, state, fCheckPOW, fCheckMerkleRoot)) { + if (!CheckBlock(config, block, state, validationOptions)) { return error("%s: Consensus::CheckBlock: %s", __func__, FormatStateMessage(state)); }