| 4478 | |
| 4479 | |
| 4480 | BlockValidationState TestBlockValidity( |
| 4481 | Chainstate& chainstate, |
| 4482 | const CBlock& block, |
| 4483 | const bool check_pow, |
| 4484 | const bool check_merkle_root) |
| 4485 | { |
| 4486 | // Lock must be held throughout this function for two reasons: |
| 4487 | // 1. We don't want the tip to change during several of the validation steps |
| 4488 | // 2. To prevent a CheckBlock() race condition for fChecked, see ProcessNewBlock() |
| 4489 | AssertLockHeld(chainstate.m_chainman.GetMutex()); |
| 4490 | |
| 4491 | BlockValidationState state; |
| 4492 | CBlockIndex* tip{Assert(chainstate.m_chain.Tip())}; |
| 4493 | |
| 4494 | if (block.hashPrevBlock != *Assert(tip->phashBlock)) { |
| 4495 | state.Invalid({}, "inconclusive-not-best-prevblk"); |
| 4496 | return state; |
| 4497 | } |
| 4498 | |
| 4499 | // For signets CheckBlock() verifies the challenge iff fCheckPow is set. |
| 4500 | if (!CheckBlock(block, state, chainstate.m_chainman.GetConsensus(), /*fCheckPow=*/check_pow, /*fCheckMerkleRoot=*/check_merkle_root)) { |
| 4501 | // This should never happen, but belt-and-suspenders don't approve the |
| 4502 | // block if it does. |
| 4503 | if (state.IsValid()) NONFATAL_UNREACHABLE(); |
| 4504 | return state; |
| 4505 | } |
| 4506 | |
| 4507 | /** |
| 4508 | * At this point ProcessNewBlock would call AcceptBlock(), but we |
| 4509 | * don't want to store the block or its header. Run individual checks |
| 4510 | * instead: |
| 4511 | * - skip AcceptBlockHeader() because: |
| 4512 | * - we don't want to update the block index |
| 4513 | * - we do not care about duplicates |
| 4514 | * - we already ran CheckBlockHeader() via CheckBlock() |
| 4515 | * - we already checked for prev-blk-not-found |
| 4516 | * - we know the tip is valid, so no need to check bad-prevblk |
| 4517 | * - we already ran CheckBlock() |
| 4518 | * - do run ContextualCheckBlockHeader() |
| 4519 | * - do run ContextualCheckBlock() |
| 4520 | */ |
| 4521 | |
| 4522 | if (!ContextualCheckBlockHeader(block, state, chainstate.m_chainman, tip)) { |
| 4523 | if (state.IsValid()) NONFATAL_UNREACHABLE(); |
| 4524 | return state; |
| 4525 | } |
| 4526 | |
| 4527 | if (!ContextualCheckBlock(block, state, chainstate.m_chainman, tip)) { |
| 4528 | if (state.IsValid()) NONFATAL_UNREACHABLE(); |
| 4529 | return state; |
| 4530 | } |
| 4531 | |
| 4532 | // We don't want ConnectBlock to update the actual chainstate, so create |
| 4533 | // a cache on top of it, along with a dummy block index. |
| 4534 | CBlockIndex index_dummy{block}; |
| 4535 | uint256 block_hash(block.GetHash()); |
| 4536 | index_dummy.pprev = tip; |
| 4537 | index_dummy.nHeight = tip->nHeight + 1; |
no test coverage detected