use blvm_node::node::block_processor::{
parse_block_from_wire, prepare_block_validation_context, store_block_with_context,
validate_block_with_context,
};
use blvm_node::storage::Storage;
use blvm_node::{Block, BlockHeader, Hash};
use blvm_protocol::{segwit::Witness, BitcoinProtocolEngine, ProtocolVersion, UtxoSet};
use std::sync::Arc;
use tempfile::TempDir;
fn create_test_block(height: u64) -> Block {
let mut prev_hash = [0u8; 32];
prev_hash[0] = (height % 256) as u8;
Block {
header: BlockHeader {
version: 1,
prev_block_hash: prev_hash,
merkle_root: [0u8; 32],
timestamp: 1231006505 + height,
bits: 0x1d00ffff,
nonce: 0,
},
transactions: vec![].into_boxed_slice(),
}
}
fn create_test_storage() -> (TempDir, Arc<Storage>) {
let temp_dir = TempDir::new().unwrap();
let storage = Arc::new(Storage::new(temp_dir.path()).unwrap());
(temp_dir, storage)
}
#[tokio::test]
async fn test_concurrent_block_processing() {
let (_temp_dir, storage) = create_test_storage();
let protocol = Arc::new(BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap());
let blockstore = storage.blocks();
let blocks: Vec<_> = (0..10).map(|i| create_test_block(i)).collect();
let mut handles = vec![];
for (i, block) in blocks.iter().enumerate() {
let blockstore_clone = Arc::clone(&blockstore);
let protocol_clone = Arc::clone(&protocol);
let block_clone = block.clone();
let height = i as u64;
handles.push(tokio::spawn(async move {
let mut utxo_set = UtxoSet::default();
let witnesses = vec![];
store_block_with_context(&*blockstore_clone, &block_clone, &witnesses, height).ok()?;
validate_block_with_context(
&*blockstore_clone,
&protocol_clone,
&block_clone,
&witnesses,
&mut utxo_set,
height,
)
.ok()
}));
}
let results: Vec<_> = futures::future::join_all(handles).await;
assert_eq!(results.len(), 10);
for result in results {
let _ = result;
}
}
#[tokio::test]
async fn test_block_processing_with_invalid_sequence() {
let (_temp_dir, storage) = create_test_storage();
let protocol = Arc::new(BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap());
let blockstore = storage.blocks();
let block1 = create_test_block(1);
let block0 = create_test_block(0);
let mut utxo_set = UtxoSet::default();
let witnesses = vec![];
let result1 = store_block_with_context(&*blockstore, &block1, &witnesses, 1);
let result2 = store_block_with_context(&*blockstore, &block0, &witnesses, 0);
let _ = result1;
let _ = result2;
let validation_result = validate_block_with_context(
&*blockstore,
&protocol,
&block1,
&witnesses,
&mut utxo_set,
1,
);
let _ = validation_result;
}
#[tokio::test]
async fn test_block_processing_reorganization_scenario() {
let (_temp_dir, storage) = create_test_storage();
let protocol = Arc::new(BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap());
let blockstore = storage.blocks();
let block0 = create_test_block(0);
let mut block1 = create_test_block(1);
block1.header.prev_block_hash = blockstore.get_block_hash(&block0);
let mut block2 = create_test_block(2);
block2.header.prev_block_hash = blockstore.get_block_hash(&block1);
let mut block1_alt = create_test_block(1);
block1_alt.header.prev_block_hash = blockstore.get_block_hash(&block0);
block1_alt.header.nonce = 1; let mut block2_alt = create_test_block(2);
block2_alt.header.prev_block_hash = blockstore.get_block_hash(&block1_alt);
let mut utxo_set = UtxoSet::default();
let witnesses = vec![];
store_block_with_context(&*blockstore, &block0, &witnesses, 0).unwrap();
store_block_with_context(&*blockstore, &block1, &witnesses, 1).unwrap();
store_block_with_context(&*blockstore, &block2, &witnesses, 2).unwrap();
store_block_with_context(&*blockstore, &block1_alt, &witnesses, 1).unwrap();
store_block_with_context(&*blockstore, &block2_alt, &witnesses, 2).unwrap();
assert!(true);
}
#[tokio::test]
async fn test_block_processing_large_block() {
let (_temp_dir, storage) = create_test_storage();
let protocol = Arc::new(BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap());
let blockstore = storage.blocks();
let mut block = create_test_block(0);
let mut utxo_set = UtxoSet::default();
let witnesses = vec![];
let store_result = store_block_with_context(&*blockstore, &block, &witnesses, 0);
assert!(store_result.is_ok());
let validation_result = validate_block_with_context(
&*blockstore,
&protocol,
&block,
&witnesses,
&mut utxo_set,
0,
);
let _ = validation_result;
}
#[tokio::test]
async fn test_block_processing_rapid_blocks() {
let (_temp_dir, storage) = create_test_storage();
let blockstore = storage.blocks();
let mut handles = vec![];
for i in 0..50 {
let blockstore_clone = Arc::clone(&blockstore);
let block = create_test_block(i);
let witnesses = vec![];
handles.push(tokio::spawn(async move {
store_block_with_context(&*blockstore_clone, &block, &witnesses, i).ok()
}));
}
let results: Vec<_> = futures::future::join_all(handles).await;
assert_eq!(results.len(), 50);
}