diff options
author | dergoegge <n.goeggi@gmail.com> | 2024-02-22 11:27:49 +0000 |
---|---|---|
committer | dergoegge <n.goeggi@gmail.com> | 2024-02-27 14:19:14 +0000 |
commit | e7669e1343aec4298fd30d539847963e6fa5619c (patch) | |
tree | 91748c744d452c1f4abc61b1bc10e510f0d97995 | |
parent | 95bddb930aa72edd40fdff52cf447202995b0dce (diff) |
[refactor] Cleanup merkle root checks
-rw-r--r-- | src/validation.cpp | 55 |
1 files changed, 41 insertions, 14 deletions
diff --git a/src/validation.cpp b/src/validation.cpp index 98383cd133..e02ce2ad1d 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -3642,35 +3642,59 @@ static bool CheckBlockHeader(const CBlockHeader& block, BlockValidationState& st static bool CheckMerkleRoot(const CBlock& block, BlockValidationState& state) { bool mutated; - uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated); - if (block.hashMerkleRoot != hashMerkleRoot2) - return state.Invalid(BlockValidationResult::BLOCK_MUTATED, "bad-txnmrklroot", "hashMerkleRoot mismatch"); + uint256 merkle_root = BlockMerkleRoot(block, &mutated); + if (block.hashMerkleRoot != merkle_root) { + return state.Invalid( + /*result=*/BlockValidationResult::BLOCK_MUTATED, + /*reject_reason=*/"bad-txnmrklroot", + /*debug_message=*/"hashMerkleRoot mismatch"); + } // Check for merkle tree malleability (CVE-2012-2459): repeating sequences // of transactions in a block without affecting the merkle root of a block, // while still invalidating it. - if (mutated) - return state.Invalid(BlockValidationResult::BLOCK_MUTATED, "bad-txns-duplicate", "duplicate transaction"); + if (mutated) { + return state.Invalid( + /*result=*/BlockValidationResult::BLOCK_MUTATED, + /*reject_reason=*/"bad-txns-duplicate", + /*debug_message=*/"duplicate transaction"); + } return true; } +/** CheckWitnessMalleation performs checks for block malleation with regard to + * its witnesses. + * + * Note: If the witness commitment is expected (i.e. `expect_witness_commitment + * = true`), then the block is required to have at least one transaction and the + * first transaction needs to have at least one input. */ static bool CheckWitnessMalleation(const CBlock& block, bool expect_witness_commitment, BlockValidationState& state) { if (expect_witness_commitment) { int commitpos = GetWitnessCommitmentIndex(block); if (commitpos != NO_WITNESS_COMMITMENT) { - bool malleated = false; - uint256 hashWitness = BlockWitnessMerkleRoot(block, &malleated); + assert(!block.vtx.empty() && !block.vtx[0]->vin.empty()); + const auto& witness_stack{block.vtx[0]->vin[0].scriptWitness.stack}; + + if (witness_stack.size() != 1 || witness_stack[0].size() != 32) { + return state.Invalid( + /*result=*/BlockValidationResult::BLOCK_MUTATED, + /*reject_reason=*/"bad-witness-nonce-size", + /*debug_message=*/strprintf("%s : invalid witness reserved value size", __func__)); + } + // The malleation check is ignored; as the transaction tree itself // already does not permit it, it is impossible to trigger in the // witness tree. - if (block.vtx[0]->vin[0].scriptWitness.stack.size() != 1 || block.vtx[0]->vin[0].scriptWitness.stack[0].size() != 32) { - return state.Invalid(BlockValidationResult::BLOCK_MUTATED, "bad-witness-nonce-size", strprintf("%s : invalid witness reserved value size", __func__)); - } - CHash256().Write(hashWitness).Write(block.vtx[0]->vin[0].scriptWitness.stack[0]).Finalize(hashWitness); - if (memcmp(hashWitness.begin(), &block.vtx[0]->vout[commitpos].scriptPubKey[6], 32)) { - return state.Invalid(BlockValidationResult::BLOCK_MUTATED, "bad-witness-merkle-match", strprintf("%s : witness merkle commitment mismatch", __func__)); + uint256 hash_witness = BlockWitnessMerkleRoot(block, /*mutated=*/nullptr); + + CHash256().Write(hash_witness).Write(witness_stack[0]).Finalize(hash_witness); + if (memcmp(hash_witness.begin(), &block.vtx[0]->vout[commitpos].scriptPubKey[6], 32)) { + return state.Invalid( + /*result=*/BlockValidationResult::BLOCK_MUTATED, + /*reject_reason=*/"bad-witness-merkle-match", + /*debug_message=*/strprintf("%s : witness merkle commitment mismatch", __func__)); } return true; @@ -3680,7 +3704,10 @@ static bool CheckWitnessMalleation(const CBlock& block, bool expect_witness_comm // No witness data is allowed in blocks that don't commit to witness data, as this would otherwise leave room for spam for (const auto& tx : block.vtx) { if (tx->HasWitness()) { - return state.Invalid(BlockValidationResult::BLOCK_MUTATED, "unexpected-witness", strprintf("%s : unexpected witness data found", __func__)); + return state.Invalid( + /*result=*/BlockValidationResult::BLOCK_MUTATED, + /*reject_reason=*/"unexpected-witness", + /*debug_message=*/strprintf("%s : unexpected witness data found", __func__)); } } |