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 {}",
54 i
55 )));
56 }
57 }
58 Err(e) => {
59 return Err(UtxoCommitmentError::VerificationFailed(format!(
60 "PoW check failed at height {}: {}",
61 i, e
62 )));
63 }
64 }
65
66 if i > 0 {
68 let prev_header = &headers[i - 1];
69 let expected_prev_hash = compute_block_hash(prev_header);
71
72 if header.prev_block_hash != expected_prev_hash {
73 return Err(UtxoCommitmentError::VerificationFailed(format!(
74 "Chain linkage broken at height {}: expected prev_hash {:?}, got {:?}",
75 i, expected_prev_hash, header.prev_block_hash
76 )));
77 }
78 }
79 }
80
81 Ok(true)
82}
83
84pub fn verify_commitment_block_hash(
89 commitment: &UtxoCommitment,
90 header: &BlockHeader,
91) -> UtxoCommitmentResult<bool> {
92 let computed_hash = compute_block_hash(header);
93
94 if commitment.block_hash != computed_hash {
95 return Err(UtxoCommitmentError::VerificationFailed(format!(
96 "Block hash mismatch: commitment has {:?}, header has {:?}",
97 commitment.block_hash, computed_hash
98 )));
99 }
100
101 Ok(true)
102}
103
104fn compute_block_hash(header: &BlockHeader) -> Hash {
109 use sha2::{Digest, Sha256};
110
111 let mut bytes = [0u8; 80];
112 bytes[0..4].copy_from_slice(&(header.version as u32).to_le_bytes());
113 bytes[4..36].copy_from_slice(&header.prev_block_hash);
114 bytes[36..68].copy_from_slice(&header.merkle_root);
115 bytes[68..72].copy_from_slice(&(header.timestamp as u32).to_le_bytes());
116 bytes[72..76].copy_from_slice(&(header.bits as u32).to_le_bytes());
117 bytes[76..80].copy_from_slice(&(header.nonce as u32).to_le_bytes());
118
119 let first_hash = Sha256::digest(bytes);
120 let second_hash = Sha256::digest(first_hash);
121
122 let mut hash = [0u8; 32];
123 hash.copy_from_slice(&second_hash);
124 hash
125}
126
127pub fn verify_forward_consistency(
133 initial_commitment: &UtxoCommitment,
134 new_commitment: &UtxoCommitment,
135 expected_height_increase: Natural,
136) -> UtxoCommitmentResult<bool> {
137 if new_commitment.block_height != initial_commitment.block_height + expected_height_increase {
139 return Err(UtxoCommitmentError::VerificationFailed(format!(
140 "Height mismatch: initial {}, new {}, expected increase {}",
141 initial_commitment.block_height, new_commitment.block_height, expected_height_increase
142 )));
143 }
144
145 if new_commitment.total_supply < initial_commitment.total_supply {
147 return Err(UtxoCommitmentError::VerificationFailed(format!(
148 "Supply decreased: initial {}, new {}",
149 initial_commitment.total_supply, new_commitment.total_supply
150 )));
151 }
152
153 let expected_new_supply = total_supply(new_commitment.block_height) as u64;
156 if new_commitment.total_supply != expected_new_supply {
157 return Err(UtxoCommitmentError::VerificationFailed(format!(
158 "New supply mismatch: commitment has {}, expected {}",
159 new_commitment.total_supply, expected_new_supply
160 )));
161 }
162
163 Ok(true)
164}
165
166