blvm_protocol/utxo_commitments/
verification.rs1#[cfg(feature = "utxo-commitments")]
9use crate::utxo_commitments::data_structures::{
10 UtxoCommitment, UtxoCommitmentError, UtxoCommitmentResult,
11};
12#[cfg(feature = "utxo-commitments")]
13use blvm_consensus::economic::total_supply;
14#[cfg(feature = "utxo-commitments")]
15use blvm_consensus::pow::check_proof_of_work;
16#[cfg(feature = "utxo-commitments")]
17use blvm_consensus::types::{BlockHeader, Hash, Natural};
18#[cfg(feature = "utxo-commitments")]
19pub fn verify_supply(commitment: &UtxoCommitment) -> UtxoCommitmentResult<bool> {
24 let expected_supply = total_supply(commitment.block_height) as u64;
25
26 if commitment.total_supply != expected_supply {
27 return Err(UtxoCommitmentError::VerificationFailed(format!(
28 "Supply mismatch at height {}: commitment has {} satoshis, expected {} satoshis",
29 commitment.block_height, commitment.total_supply, expected_supply
30 )));
31 }
32
33 Ok(true)
34}
35
36pub fn verify_header_chain(headers: &[BlockHeader]) -> UtxoCommitmentResult<bool> {
41 if headers.is_empty() {
42 return Err(UtxoCommitmentError::VerificationFailed(
43 "Empty header chain".to_string(),
44 ));
45 }
46
47 for (i, header) in headers.iter().enumerate() {
49 match check_proof_of_work(header) {
50 Ok(is_valid) => {
51 if !is_valid {
52 return Err(UtxoCommitmentError::VerificationFailed(format!(
53 "Invalid proof of work at height {i}"
54 )));
55 }
56 }
57 Err(e) => {
58 return Err(UtxoCommitmentError::VerificationFailed(format!(
59 "PoW check failed at height {i}: {e}"
60 )));
61 }
62 }
63
64 if i > 0 {
66 let prev_header = &headers[i - 1];
67 let expected_prev_hash = compute_block_hash(prev_header);
69
70 if header.prev_block_hash != expected_prev_hash {
71 return Err(UtxoCommitmentError::VerificationFailed(format!(
72 "Chain linkage broken at height {}: expected prev_hash {:?}, got {:?}",
73 i, expected_prev_hash, header.prev_block_hash
74 )));
75 }
76 }
77 }
78
79 Ok(true)
80}
81
82pub fn verify_commitment_block_hash(
87 commitment: &UtxoCommitment,
88 header: &BlockHeader,
89) -> UtxoCommitmentResult<bool> {
90 let computed_hash = compute_block_hash(header);
91
92 if commitment.block_hash != computed_hash {
93 return Err(UtxoCommitmentError::VerificationFailed(format!(
94 "Block hash mismatch: commitment has {:?}, header has {:?}",
95 commitment.block_hash, computed_hash
96 )));
97 }
98
99 Ok(true)
100}
101
102fn compute_block_hash(header: &BlockHeader) -> Hash {
107 use sha2::{Digest, Sha256};
108
109 let mut bytes = [0u8; 80];
110 bytes[0..4].copy_from_slice(&(header.version as u32).to_le_bytes());
111 bytes[4..36].copy_from_slice(&header.prev_block_hash);
112 bytes[36..68].copy_from_slice(&header.merkle_root);
113 bytes[68..72].copy_from_slice(&(header.timestamp as u32).to_le_bytes());
114 bytes[72..76].copy_from_slice(&(header.bits as u32).to_le_bytes());
115 bytes[76..80].copy_from_slice(&(header.nonce as u32).to_le_bytes());
116
117 let first_hash = Sha256::digest(bytes);
118 let second_hash = Sha256::digest(first_hash);
119
120 let mut hash = [0u8; 32];
121 hash.copy_from_slice(&second_hash);
122 hash
123}
124
125pub fn verify_forward_consistency(
131 initial_commitment: &UtxoCommitment,
132 new_commitment: &UtxoCommitment,
133 expected_height_increase: Natural,
134) -> UtxoCommitmentResult<bool> {
135 if new_commitment.block_height != initial_commitment.block_height + expected_height_increase {
137 return Err(UtxoCommitmentError::VerificationFailed(format!(
138 "Height mismatch: initial {}, new {}, expected increase {}",
139 initial_commitment.block_height, new_commitment.block_height, expected_height_increase
140 )));
141 }
142
143 if new_commitment.total_supply < initial_commitment.total_supply {
145 return Err(UtxoCommitmentError::VerificationFailed(format!(
146 "Supply decreased: initial {}, new {}",
147 initial_commitment.total_supply, new_commitment.total_supply
148 )));
149 }
150
151 let expected_new_supply = total_supply(new_commitment.block_height) as u64;
154 if new_commitment.total_supply != expected_new_supply {
155 return Err(UtxoCommitmentError::VerificationFailed(format!(
156 "New supply mismatch: commitment has {}, expected {}",
157 new_commitment.total_supply, expected_new_supply
158 )));
159 }
160
161 Ok(true)
162}
163
164