use crate::storage::blockstore::BlockStore;
use crate::storage::Storage;
use crate::utils::current_timestamp;
use anyhow::Result;
use blvm_protocol::serialization::deserialize_block_with_witnesses;
use blvm_protocol::validation::ProtocolValidationContext;
use blvm_protocol::{
segwit::Witness, BitcoinProtocolEngine, Block, BlockHeader, UtxoSet, ValidationResult,
};
use std::sync::Arc;
pub fn parse_block_from_wire(data: &[u8]) -> Result<(Block, Vec<Vec<Witness>>)> {
let (block, witnesses) = deserialize_block_with_witnesses(data)
.map_err(|e| anyhow::anyhow!("Failed to parse block from wire format: {}", e))?;
let include_witness = true;
if !blvm_protocol::serialization::block::validate_block_serialized_size(
&block,
&witnesses,
include_witness,
data.len(),
) {
anyhow::bail!("Block size mismatch: serialized block does not match wire size");
}
Ok((block, witnesses))
}
pub fn store_block_with_context(
blockstore: &BlockStore,
block: &Block,
witnesses: &[Vec<Witness>], height: u64,
) -> Result<()> {
blockstore.store_block_with_witness(block, witnesses, height)?;
let block_hash = blockstore.get_block_hash(block);
blockstore.store_height(height, &block_hash)?;
Ok(())
}
pub fn store_block_with_context_and_index(
blockstore: &BlockStore,
storage: Option<&Arc<Storage>>,
block: &Block,
witnesses: &[Vec<Witness>], height: u64,
) -> Result<()> {
store_block_with_context(blockstore, block, witnesses, height)?;
if let Some(storage) = storage {
let block_hash = blockstore.get_block_hash(block);
if let Err(e) = storage.index_block(block, &block_hash, height) {
tracing::warn!("Failed to index block transactions: {}", e);
}
}
Ok(())
}
pub fn prepare_block_validation_context(
blockstore: &BlockStore,
block: &Block,
_current_height: u64,
) -> Result<(Vec<Vec<Witness>>, Option<Vec<BlockHeader>>)> {
let block_hash = blockstore.get_block_hash(block);
let witnesses = blockstore.get_witness(&block_hash)?.unwrap_or_else(|| {
block
.transactions
.iter()
.map(|tx| tx.inputs.iter().map(|_| Vec::new()).collect())
.collect()
});
let recent_headers = blockstore
.get_recent_headers(11)
.ok()
.filter(|headers| !headers.is_empty());
Ok((witnesses, recent_headers))
}
pub fn validate_block_with_context(
blockstore: &BlockStore,
protocol: &BitcoinProtocolEngine,
block: &Block,
witnesses: &[Vec<Witness>], utxo_set: &mut UtxoSet,
height: u64,
) -> Result<ValidationResult> {
let recent_headers = blockstore
.get_recent_headers(11)
.ok()
.filter(|headers| !headers.is_empty());
let median_time_past = recent_headers
.as_ref()
.map(|headers| blvm_protocol::bip113::get_median_time_past(headers))
.unwrap_or(0);
let network_time = current_timestamp();
let mut context = ProtocolValidationContext::new(protocol.get_protocol_version(), height)?;
context
.context_data
.insert("median_time_past".to_string(), median_time_past.to_string());
context
.context_data
.insert("network_time".to_string(), network_time.to_string());
let owned_utxo = std::mem::take(utxo_set);
let (result, new_utxo_set) = protocol.validate_and_connect_block(
block,
witnesses,
&owned_utxo,
height,
recent_headers.as_deref(),
&context,
)?;
*utxo_set = new_utxo_set;
Ok(result)
}