use crate::network::filter_service::BlockFilterService;
use crate::network::protocol::{
CfcheckptMessage, CfheadersMessage, CfilterMessage, FilterHeaderData, GetCfcheckptMessage,
GetCfheadersMessage, GetCfiltersMessage, ProtocolMessage,
};
use crate::storage::Storage;
use anyhow::{anyhow, Result};
use blvm_protocol::Hash;
use std::sync::Arc;
pub fn handle_getcfilters(
request: &GetCfiltersMessage,
filter_service: &BlockFilterService,
storage: Option<&Arc<Storage>>,
) -> Result<Vec<ProtocolMessage>> {
if request.filter_type != 0 {
return Err(anyhow!("Unsupported filter type: {}", request.filter_type));
}
let mut responses = Vec::new();
if let Some(storage) = storage {
let current_height = storage.chain().get_height()?.unwrap_or(0) as u32;
let start_height = request.start_height;
let mut stop_height = start_height;
let mut found_stop = false;
for height in start_height..=current_height.min(start_height + 2000) {
if let Ok(Some(block_hash)) = storage.blocks().get_hash_by_height(height as u64) {
if let Ok(Some(block)) = storage.blocks().get_block(&block_hash) {
use crate::storage::hashing::double_sha256;
let mut header_data = Vec::with_capacity(80);
header_data.extend_from_slice(&(block.header.version as i32).to_le_bytes()); header_data.extend_from_slice(&block.header.prev_block_hash); header_data.extend_from_slice(&block.header.merkle_root); header_data.extend_from_slice(&(block.header.timestamp as u32).to_le_bytes()); header_data.extend_from_slice(&(block.header.bits as u32).to_le_bytes()); header_data.extend_from_slice(&(block.header.nonce as u32).to_le_bytes()); let calculated_hash = double_sha256(&header_data);
if calculated_hash == request.stop_hash {
found_stop = true;
stop_height = height;
}
let filter = if let Some(cached) = filter_service.get_filter(&calculated_hash) {
cached
} else {
let mut prev_scripts = Vec::new();
for tx in &block.transactions {
for input in &tx.inputs {
if let Ok(Some(utxo)) = storage.utxos().get_utxo(&input.prevout) {
prev_scripts.push(utxo.script_pubkey.as_ref().to_vec());
}
}
}
filter_service.generate_and_cache_filter(&block, &prev_scripts, height)?
};
responses.push(ProtocolMessage::Cfilter(CfilterMessage {
filter_type: 0,
block_hash: calculated_hash,
filter_data: filter.filter_data,
num_elements: filter.num_elements,
}));
if found_stop {
break;
}
}
}
}
if !found_stop && stop_height < current_height {
}
}
Ok(responses)
}
pub fn handle_getcfheaders(
request: &GetCfheadersMessage,
filter_service: &BlockFilterService,
) -> Result<ProtocolMessage> {
if request.filter_type != 0 {
return Err(anyhow!("Unsupported filter type: {}", request.filter_type));
}
let filter_headers =
filter_service.get_filter_headers_range(request.start_height, request.stop_hash)?;
let prev_header = filter_service
.get_prev_filter_header(request.start_height)
.unwrap_or({
blvm_protocol::bip157::FilterHeader {
filter_hash: [0u8; 32],
prev_header_hash: [0u8; 32],
}
});
let prev_header_data = FilterHeaderData {
filter_hash: prev_header.filter_hash,
prev_header_hash: prev_header.prev_header_hash,
};
Ok(ProtocolMessage::Cfheaders(CfheadersMessage {
filter_type: request.filter_type,
stop_hash: request.stop_hash,
prev_header: prev_header_data,
filter_headers,
}))
}
pub fn handle_getcfcheckpt(
request: &GetCfcheckptMessage,
filter_service: &BlockFilterService,
) -> Result<ProtocolMessage> {
if request.filter_type != 0 {
return Err(anyhow!("Unsupported filter type: {}", request.filter_type));
}
let filter_header_hashes = filter_service.get_filter_checkpoints(request.stop_hash)?;
Ok(ProtocolMessage::Cfcheckpt(CfcheckptMessage {
filter_type: request.filter_type,
stop_hash: request.stop_hash,
filter_header_hashes,
}))
}
pub fn generate_cfilter_response(
block_hash: Hash,
filter_type: u8,
filter_service: &BlockFilterService,
) -> Result<ProtocolMessage> {
if filter_type != 0 {
return Err(anyhow!("Unsupported filter type: {}", filter_type));
}
let filter = filter_service
.get_filter(&block_hash)
.ok_or_else(|| anyhow!("Filter not found for block hash"))?;
Ok(ProtocolMessage::Cfilter(CfilterMessage {
filter_type,
block_hash,
filter_data: filter.filter_data,
num_elements: filter.num_elements,
}))
}