use blvm_node::network::protocol::{FilterPreferences, GetFilteredBlockMessage, GetUTXOSetMessage};
use blvm_node::network::protocol_extensions::{handle_get_filtered_block, handle_get_utxo_set};
use blvm_node::storage::database::DatabaseBackend;
use blvm_node::storage::hashing::double_sha256;
use blvm_node::storage::Storage;
use blvm_node::{Block, BlockHeader, Transaction};
use std::sync::Arc;
fn block_hash(block: &Block) -> [u8; 32] {
let mut header_data = [0u8; 80];
header_data[0..4].copy_from_slice(&(block.header.version as i32).to_le_bytes());
header_data[4..36].copy_from_slice(&block.header.prev_block_hash);
header_data[36..68].copy_from_slice(&block.header.merkle_root);
header_data[68..72].copy_from_slice(&(block.header.timestamp as u32).to_le_bytes());
header_data[72..76].copy_from_slice(&(block.header.bits as u32).to_le_bytes());
header_data[76..80].copy_from_slice(&(block.header.nonce as u32).to_le_bytes());
double_sha256(&header_data)
}
fn create_test_storage() -> Arc<Storage> {
let temp_dir = std::env::temp_dir().join(format!(
"blvm_pe_test_{}_{}",
std::process::id(),
std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&temp_dir).unwrap();
#[cfg(feature = "redb")]
{
let storage = Storage::with_backend(&temp_dir, DatabaseBackend::Redb).unwrap();
return Arc::new(storage);
}
#[cfg(not(feature = "redb"))]
{
let storage = Storage::new(&temp_dir).unwrap();
Arc::new(storage)
}
}
#[tokio::test]
async fn test_handle_get_utxo_set_no_storage() {
let message = GetUTXOSetMessage {
height: 0,
block_hash: [0; 32],
};
let result = handle_get_utxo_set(message, None).await;
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Storage not available"));
}
#[tokio::test]
async fn test_handle_get_utxo_set_with_storage() {
let storage = create_test_storage();
let message = GetUTXOSetMessage {
height: 0,
block_hash: [0; 32],
};
let result = handle_get_utxo_set(message, Some(storage)).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.commitment.block_height, 0);
}
#[tokio::test]
async fn test_handle_get_utxo_set_specific_height() {
let storage = create_test_storage();
let message = GetUTXOSetMessage {
height: 100,
block_hash: [0x42; 32],
};
let result = handle_get_utxo_set(message, Some(storage)).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.commitment.block_height, 100);
}
#[tokio::test]
async fn test_handle_get_filtered_block_no_storage() {
let message = GetFilteredBlockMessage {
request_id: 12345,
block_hash: [0x42; 32],
filter_preferences: FilterPreferences {
filter_ordinals: false,
filter_dust: false,
filter_brc20: false,
min_output_value: 0,
},
include_bip158_filter: false,
};
let result = handle_get_filtered_block(message, None, None).await;
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Storage not available"));
}
#[tokio::test]
async fn test_handle_get_filtered_block_block_not_found() {
let storage = create_test_storage();
let message = GetFilteredBlockMessage {
request_id: 12345,
block_hash: [0xFF; 32], filter_preferences: FilterPreferences {
filter_ordinals: false,
filter_dust: false,
filter_brc20: false,
min_output_value: 0,
},
include_bip158_filter: false,
};
let result = handle_get_filtered_block(message, Some(storage), None).await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_handle_get_filtered_block_with_preferences() {
let storage = create_test_storage();
let block = Block {
header: BlockHeader {
version: 1,
prev_block_hash: [0; 32],
merkle_root: [0; 32],
timestamp: 1231006505,
bits: 0x1d00ffff,
nonce: 0,
},
transactions: vec![Transaction {
version: 1,
inputs: vec![].into(),
outputs: vec![].into(),
lock_time: 0,
}]
.into_boxed_slice(),
};
let block_hash_val = block_hash(&block);
storage.blocks().store_block(&block).unwrap();
let message = GetFilteredBlockMessage {
request_id: 12345,
block_hash: block_hash_val,
filter_preferences: FilterPreferences {
filter_ordinals: true,
filter_dust: true,
filter_brc20: true,
min_output_value: 1000,
},
include_bip158_filter: false,
};
let result = handle_get_filtered_block(message, Some(storage), None).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.request_id, 12345);
}
#[tokio::test]
async fn test_handle_get_filtered_block_with_bip158() {
let storage = create_test_storage();
let block = Block {
header: BlockHeader {
version: 1,
prev_block_hash: [0; 32],
merkle_root: [0; 32],
timestamp: 1231006505,
bits: 0x1d00ffff,
nonce: 0,
},
transactions: vec![Transaction {
version: 1,
inputs: vec![].into(),
outputs: vec![].into(),
lock_time: 0,
}]
.into_boxed_slice(),
};
let block_hash_val = block_hash(&block);
storage.blocks().store_block(&block).unwrap();
let message = GetFilteredBlockMessage {
request_id: 12345,
block_hash: block_hash_val,
filter_preferences: FilterPreferences {
filter_ordinals: false,
filter_dust: false,
filter_brc20: false,
min_output_value: 0,
},
include_bip158_filter: true,
};
let result = handle_get_filtered_block(message, Some(storage), None).await;
assert!(result.is_ok());
let response = result.unwrap();
assert_eq!(response.request_id, 12345);
}