use blvm_consensus::serialization::block::deserialize_block_with_witnesses;
use blvm_consensus::serialization::transaction::{deserialize_transaction, serialize_transaction};
use blvm_consensus::block::calculate_tx_id;
#[test]
fn test_deserialize_transaction_returns_correct_offset() {
use blvm_consensus::types::*;
let tx = Transaction {
version: 1,
inputs: blvm_consensus::tx_inputs![TransactionInput {
prevout: OutPoint { hash: [0u8; 32], index: 0 },
sequence: 0xffffffff,
script_sig: vec![0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04], }],
outputs: blvm_consensus::tx_outputs![TransactionOutput {
value: 50_0000_0000, script_pubkey: vec![0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6, 0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, 0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f, 0xac], }],
lock_time: 0,
};
let serialized = serialize_transaction(&tx);
let original_len = serialized.len();
let (deserialized, bytes_consumed) =
blvm_consensus::serialization::deserialize_transaction_with_offset(&serialized).unwrap();
assert_eq!(bytes_consumed, original_len,
"Bytes consumed ({}) must match serialized length ({})",
bytes_consumed, original_len);
assert_eq!(deserialized.version, tx.version);
assert_eq!(deserialized.inputs.len(), tx.inputs.len());
assert_eq!(deserialized.outputs.len(), tx.outputs.len());
let original_txid = calculate_tx_id(&tx);
let deserialized_txid = calculate_tx_id(&deserialized);
assert_eq!(original_txid, deserialized_txid, "TxID must match after round-trip");
}
#[test]
fn test_block_deserialization_tracks_offset_correctly() {
use blvm_consensus::types::*;
let tx1 = Transaction {
version: 1,
inputs: blvm_consensus::tx_inputs![TransactionInput {
prevout: OutPoint { hash: [0u8; 32], index: 0 },
sequence: 0xffffffff,
script_sig: vec![0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04], }],
outputs: blvm_consensus::tx_outputs![TransactionOutput {
value: 50_0000_0000,
script_pubkey: vec![0x41; 65], }],
lock_time: 0,
};
let tx2 = Transaction {
version: 1,
inputs: blvm_consensus::tx_inputs![TransactionInput {
prevout: OutPoint { hash: [1u8; 32], index: 0 },
sequence: 0xffffffff,
script_sig: vec![0x07, 0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0xff], }],
outputs: blvm_consensus::tx_outputs![TransactionOutput {
value: 25_0000_0000,
script_pubkey: vec![0x41; 33], }],
lock_time: 0,
};
let tx1_bytes = serialize_transaction(&tx1);
let tx2_bytes = serialize_transaction(&tx2);
use blvm_consensus::serialization::varint::encode_varint;
let mut block_data = Vec::new();
block_data.extend_from_slice(&[0u8; 80]);
block_data.extend_from_slice(&encode_varint(2));
block_data.extend_from_slice(&tx1_bytes);
block_data.extend_from_slice(&tx2_bytes);
let (block, _witnesses) = deserialize_block_with_witnesses(&block_data).unwrap();
assert_eq!(block.transactions.len(), 2, "Block must have 2 transactions");
let tx1_txid = calculate_tx_id(&tx1);
let block_tx1_txid = calculate_tx_id(&block.transactions[0]);
assert_eq!(tx1_txid, block_tx1_txid, "First transaction txid must match");
let tx2_txid = calculate_tx_id(&tx2);
let block_tx2_txid = calculate_tx_id(&block.transactions[1]);
assert_eq!(tx2_txid, block_tx2_txid, "Second transaction txid must match");
assert_ne!(block_tx1_txid, block_tx2_txid, "Transactions must have different txids");
}
#[test]
fn test_sequential_block_processing_maintains_correct_txids() {
use blvm_consensus::types::*;
let transactions: Vec<Transaction> = (0..3)
.map(|i| Transaction {
version: 1,
inputs: blvm_consensus::tx_inputs![TransactionInput {
prevout: OutPoint { hash: [i as u8; 32], index: 0 },
sequence: 0xffffffff,
script_sig: vec![0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04 + i],
}],
outputs: blvm_consensus::tx_outputs![TransactionOutput {
value: (50 - i as i64) * 1000_0000,
script_pubkey: vec![0x41; 65],
}],
lock_time: 0,
})
.collect();
let tx_bytes: Vec<Vec<u8>> = transactions.iter()
.map(|tx| serialize_transaction(tx))
.collect();
let mut blocks = Vec::new();
for tx_bytes in &tx_bytes {
use blvm_consensus::serialization::varint::encode_varint;
let mut block_data = Vec::new();
block_data.extend_from_slice(&[0u8; 80]); block_data.extend_from_slice(&encode_varint(1)); block_data.extend_from_slice(tx_bytes);
blocks.push(block_data);
}
let mut deserialized_txids = Vec::new();
for block_data in &blocks {
let (block, _) = deserialize_block_with_witnesses(block_data).unwrap();
let txid = calculate_tx_id(&block.transactions[0]);
deserialized_txids.push(txid);
}
for i in 0..deserialized_txids.len() {
for j in (i+1)..deserialized_txids.len() {
assert_ne!(deserialized_txids[i], deserialized_txids[j],
"Transaction {} and {} must have different txids", i, j);
}
}
for (i, (original_tx, deserialized_txid)) in transactions.iter().zip(deserialized_txids.iter()).enumerate() {
let original_txid = calculate_tx_id(original_tx);
assert_eq!(original_txid, *deserialized_txid,
"Block {} transaction txid must match original", i);
}
}