blvm_protocol/utxo_commitments/
network_integration.rs1#[cfg(feature = "utxo-commitments")]
7use crate::spam_filter::{SpamFilter, SpamSummary};
8#[cfg(feature = "utxo-commitments")]
9use crate::utxo_commitments::data_structures::{
10 UtxoCommitment, UtxoCommitmentError, UtxoCommitmentResult,
11};
12#[cfg(feature = "utxo-commitments")]
13use blvm_consensus::types::{BlockHeader, Hash as HashType, Natural, Transaction};
14#[cfg(feature = "utxo-commitments")]
15#[derive(Debug, Clone)]
17pub struct FilteredBlock {
18 pub header: BlockHeader,
19 pub commitment: UtxoCommitment,
20 pub transactions: Vec<Transaction>,
21 pub transaction_indices: Vec<u32>,
22 pub spam_summary: SpamSummary,
23}
24
25pub trait UtxoCommitmentsNetworkClient: Send + Sync {
33 fn request_utxo_set(
38 &self,
39 peer_id: &str,
40 height: Natural,
41 block_hash: HashType,
42 ) -> std::pin::Pin<
43 Box<dyn std::future::Future<Output = UtxoCommitmentResult<UtxoCommitment>> + Send + '_>,
44 >;
45
46 fn request_filtered_block(
48 &self,
49 peer_id: &str,
50 block_hash: HashType,
51 ) -> std::pin::Pin<
52 Box<dyn std::future::Future<Output = UtxoCommitmentResult<FilteredBlock>> + Send + '_>,
53 >;
54
55 fn request_full_block(
60 &self,
61 peer_id: &str,
62 block_hash: HashType,
63 ) -> std::pin::Pin<
64 Box<dyn std::future::Future<Output = UtxoCommitmentResult<FullBlock>> + Send + '_>,
65 >;
66
67 fn get_peer_ids(&self) -> Vec<String>;
69}
70
71#[derive(Debug, Clone)]
76pub struct FullBlock {
77 pub block: blvm_consensus::types::Block,
78 pub witnesses: Vec<Vec<blvm_consensus::segwit::Witness>>,
79}
80
81pub async fn request_utxo_sets_from_peers_fn<F, Fut>(
85 request_fn: F,
86 peers: &[String],
87 height: Natural,
88 block_hash: HashType,
89) -> Vec<(String, UtxoCommitmentResult<UtxoCommitment>)>
90where
91 F: Fn(&str, Natural, HashType) -> Fut,
92 Fut: std::future::Future<Output = UtxoCommitmentResult<UtxoCommitment>>,
93{
94 let mut results = Vec::new();
95
96 for peer_id in peers {
97 let result = request_fn(peer_id, height, block_hash).await;
98 results.push((peer_id.clone(), result));
99 }
100
101 results
102}
103
104pub fn process_and_verify_filtered_block(
106 filtered_block: &FilteredBlock,
107 expected_height: Natural,
108 _spam_filter: &SpamFilter,
109) -> UtxoCommitmentResult<bool> {
110 if filtered_block.commitment.block_height != expected_height {
115 return Err(UtxoCommitmentError::VerificationFailed(format!(
116 "Commitment height mismatch: expected {}, got {}",
117 expected_height, filtered_block.commitment.block_height
118 )));
119 }
120
121 let computed_hash = compute_block_hash(&filtered_block.header);
126 if filtered_block.commitment.block_hash != computed_hash {
127 return Err(UtxoCommitmentError::VerificationFailed(format!(
128 "Block hash mismatch: expected {:?}, got {:?}",
129 computed_hash, filtered_block.commitment.block_hash
130 )));
131 }
132
133 Ok(true)
134}
135
136fn compute_block_hash(header: &BlockHeader) -> HashType {
138 use sha2::{Digest, Sha256};
139
140 let mut bytes = Vec::with_capacity(80);
141 bytes.extend_from_slice(&header.version.to_le_bytes());
142 bytes.extend_from_slice(&header.prev_block_hash);
143 bytes.extend_from_slice(&header.merkle_root);
144 bytes.extend_from_slice(&header.timestamp.to_le_bytes());
145 bytes.extend_from_slice(&header.bits.to_le_bytes());
146 bytes.extend_from_slice(&header.nonce.to_le_bytes());
147
148 let first_hash = Sha256::digest(&bytes);
149 let second_hash = Sha256::digest(&first_hash);
150
151 let mut hash = [0u8; 32];
152 hash.copy_from_slice(&second_hash);
153 hash
154}