What changed, and why it matters
This commit only adds a new automated test to the project. It does not change any production code. The test demonstrates that two equivalent Bitcoin blocks—one with a cached witness root and one without—compare as equal. It is a regression test for a bug fixed in an earlier patch, not a security fix itself.
No action required; treat as routine test coverage. Review the prior patch referenced in the commit message if assessing the original bug's security relevance.
Security signals we found
Test-only change, no runtime code modified
References a prior bug fix in commit message
Demonstrates equality semantics ignore cached witness root
Evidence from the diff
The diff adds a unit test checked_block_eq_ignores_cached_witness_root in primitives/src/block.rs. The test builds a block with two transactions, derives a validated block (which has a cached witness root) and an assumed block (which does not), then asserts header, transaction, encoding, and equality equivalence. No library logic is modified; this is purely test coverage.
Changed components
primitives/src/block.rs (tests module only)Inspect captured patch +46 / −0
diff --git a/primitives/src/block.rs b/primitives/src/block.rs
index 06bbd4bb..03b3f385 100644
--- a/primitives/src/block.rs
+++ b/primitives/src/block.rs
@@ -1756,6 +1756,52 @@ mod tests {
);
}
+ #[test]
+ #[cfg(feature = "alloc")]
+ #[cfg(feature = "hex")]
+ fn checked_block_eq_ignores_cached_witness_root() {
+ let mut txin = crate::TxIn::EMPTY_COINBASE;
+ txin.witness.push([11u8; 32]);
+
+ let script_pubkey_bytes = hex::decode_to_array::<38>(
+ "6a24aa21a9ed3cde9e0b9f4ad8f9d0fd66d6b9326cd68597c04fa22ab64b8e455f08d2e31ceb",
+ )
+ .unwrap();
+ let tx1 = Transaction {
+ version: crate::transaction::Version::ONE,
+ lock_time: crate::absolute::LockTime::ZERO,
+ inputs: vec![txin],
+ outputs: vec![crate::TxOut {
+ amount: units::Amount::MIN,
+ script_pubkey: crate::script::ScriptBuf::from_bytes(script_pubkey_bytes.to_vec()),
+ }],
+ };
+ let tx2 = Transaction {
+ version: crate::transaction::Version::ONE,
+ lock_time: crate::absolute::LockTime::ZERO,
+ inputs: vec![crate::TxIn::EMPTY_COINBASE],
+ outputs: vec![crate::TxOut {
+ amount: units::Amount::MIN,
+ script_pubkey: crate::script::ScriptBuf::new(),
+ }],
+ };
+
+ let transactions = vec![tx1, tx2];
+ let mut header = dummy_header();
+ header.merkle_root = compute_merkle_root(&transactions).unwrap();
+ let block = Block::new_unchecked(header, transactions);
+
+ let validated = block.clone().validate().unwrap();
+ assert!(validated.cached_witness_root().is_some());
+ let assumed = block.assume_checked(None);
+ assert!(assumed.cached_witness_root().is_none());
+
+ assert_eq!(validated.header(), assumed.header());
+ assert_eq!(validated.transactions(), assumed.transactions());
+ assert_eq!(encoding::encode_to_vec(&validated), encoding::encode_to_vec(&assumed));
+ assert_eq!(validated, assumed);
+ }
+
#[test]
#[cfg(feature = "alloc")]
#[cfg(feature = "hex")]
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.