#![cfg(feature = "utxo-commitments")]
mod tests {
use blvm_consensus::types::{OutPoint, UTXO};
use blvm_protocol::utxo_commitments::*;
#[test]
fn test_utxo_merkle_tree_new() {
let tree = UtxoMerkleTree::new().unwrap();
assert_eq!(tree.total_supply(), 0);
assert_eq!(tree.utxo_count(), 0);
}
#[test]
fn test_insert_utxo() {
let mut tree = UtxoMerkleTree::new().unwrap();
let outpoint = OutPoint {
hash: [1; 32],
index: 0,
};
let utxo = UTXO {
value: 1000,
script_pubkey: vec![0x51].into(), height: 0,
is_coinbase: false,
};
let root = tree.insert(outpoint.clone(), utxo.clone()).unwrap();
assert_eq!(tree.utxo_count(), 1);
assert_eq!(tree.total_supply(), 1000);
assert_eq!(tree.root(), root);
}
#[test]
fn test_remove_utxo() {
let mut tree = UtxoMerkleTree::new().unwrap();
let outpoint = OutPoint {
hash: [1; 32],
index: 0,
};
let utxo = UTXO {
value: 1000,
script_pubkey: vec![].into(),
height: 0,
is_coinbase: false,
};
tree.insert(outpoint.clone(), utxo.clone()).unwrap();
assert_eq!(tree.utxo_count(), 1);
tree.remove(&outpoint, &utxo).unwrap();
assert_eq!(tree.utxo_count(), 0);
assert_eq!(tree.total_supply(), 0);
}
#[test]
fn test_generate_commitment() {
let mut tree = UtxoMerkleTree::new().unwrap();
let outpoint = OutPoint {
hash: [1; 32],
index: 0,
};
let utxo = UTXO {
value: 1000,
script_pubkey: vec![].into(),
height: 0,
};
tree.insert(outpoint, utxo).unwrap();
let block_hash = [2; 32];
let commitment = tree.generate_commitment(block_hash, 0);
assert_eq!(commitment.block_height, 0);
assert_eq!(commitment.block_hash, block_hash);
assert_eq!(commitment.total_supply, 1000);
assert_eq!(commitment.utxo_count, 1);
assert_eq!(commitment.merkle_root, tree.root());
}
#[test]
fn test_verify_commitment_supply() {
let mut tree = UtxoMerkleTree::new().unwrap();
let outpoint = OutPoint {
hash: [1; 32],
index: 0,
};
let utxo = UTXO {
value: 5000000000, script_pubkey: vec![].into(),
height: 0,
is_coinbase: false,
};
tree.insert(outpoint, utxo).unwrap();
let block_hash = [2; 32];
let commitment = tree.generate_commitment(block_hash, 0);
let result = tree.verify_commitment_supply(&commitment);
assert!(result.is_ok());
}
#[test]
fn test_verify_supply_function() {
let commitment = UtxoCommitment::new(
[0; 32], 5000000000, 1, 0, [0; 32],
);
let result = verify_supply(&commitment);
assert!(result.is_ok());
assert!(result.unwrap());
}
#[test]
fn test_commitment_serialization() {
let commitment = UtxoCommitment::new([1; 32], 1000, 5, 100, [2; 32]);
let bytes = commitment.to_bytes();
assert_eq!(bytes.len(), 84);
let deserialized = UtxoCommitment::from_bytes(&bytes).unwrap();
assert_eq!(deserialized.merkle_root, commitment.merkle_root);
assert_eq!(deserialized.total_supply, commitment.total_supply);
assert_eq!(deserialized.utxo_count, commitment.utxo_count);
assert_eq!(deserialized.block_height, commitment.block_height);
assert_eq!(deserialized.block_hash, commitment.block_hash);
}
#[test]
fn test_generate_proof() {
let mut tree = UtxoMerkleTree::new().unwrap();
let outpoint = OutPoint {
hash: [1; 32],
index: 0,
};
let utxo = UTXO {
value: 1000,
script_pubkey: vec![].into(),
height: 0,
};
tree.insert(outpoint.clone(), utxo).unwrap();
let proof = tree.generate_proof(&outpoint).unwrap();
assert!(true); }
#[test]
fn test_commitment_verify_supply_method() {
let commitment = UtxoCommitment::new([0; 32], 5000000000, 1, 0, [0; 32]);
assert!(commitment.verify_supply(5000000000));
assert!(!commitment.verify_supply(1000));
}
#[test]
fn test_commitment_verify_count() {
let commitment = UtxoCommitment::new([0; 32], 1000, 5, 0, [0; 32]);
assert!(commitment.verify_count(5));
assert!(!commitment.verify_count(10));
}
#[test]
fn test_verifyconsensuscommitment_orange_paper_genesis() {
use blvm_consensus::constants::{
GENESIS_BLOCK_HASH, GENESIS_BLOCK_MERKLE_ROOT, GENESIS_BLOCK_NONCE,
GENESIS_BLOCK_TIMESTAMP,
};
use blvm_consensus::types::BlockHeader;
use blvm_protocol::utxo_commitments::verification::{
verify_commitment_block_hash, verify_header_chain, verify_supply,
};
let genesis_header = BlockHeader {
version: 1,
prev_block_hash: [0; 32],
merkle_root: GENESIS_BLOCK_MERKLE_ROOT,
timestamp: GENESIS_BLOCK_TIMESTAMP as u64,
bits: 0x1d00ffff,
nonce: GENESIS_BLOCK_NONCE,
};
let valid_commitment = UtxoCommitment::new(
[0; 32], 5000000000, 1,
0, GENESIS_BLOCK_HASH,
);
let result = (verify_supply(&valid_commitment).is_ok()
&& verify_header_chain(&[genesis_header.clone()]).is_ok()
&& verify_commitment_block_hash(&valid_commitment, &genesis_header).is_ok())
as i64;
assert_eq!(result, 1, "Valid genesis commitment should return 1");
}
#[test]
fn test_verifyconsensuscommitment_orange_paper_invalid_cases() {
use blvm_consensus::types::BlockHeader;
use blvm_protocol::utxo_commitments::verification::{
verify_commitment_block_hash, verify_header_chain, verify_supply,
};
let header = BlockHeader {
version: 1,
prev_block_hash: [0; 32],
merkle_root: [0; 32],
timestamp: 1231006505,
bits: 0x1d00ffff,
nonce: 0,
};
let commitment = UtxoCommitment::new([0; 32], 5000000000, 1, 0, [0; 32]);
assert!(verify_header_chain(&[]).is_err());
let bad_supply = UtxoCommitment::new([0; 32], 999, 1, 0, [0; 32]);
assert!(verify_supply(&bad_supply).is_err());
let height_oob = UtxoCommitment::new([0; 32], 5000000000, 1, 5, [0; 32]);
assert!(verify_supply(&height_oob).is_ok()); assert!(verify_commitment_block_hash(&height_oob, &header).is_err()); }
#[test]
fn test_verify_utxo_proof_valid() {
let mut tree = UtxoMerkleTree::new().unwrap();
let outpoint = OutPoint {
hash: [1; 32],
index: 0,
};
let utxo = UTXO {
value: 1000,
script_pubkey: vec![0x51], height: 0,
is_coinbase: false,
};
tree.insert(outpoint.clone(), utxo.clone()).unwrap();
let block_hash = [2; 32];
let commitment = tree.generate_commitment(block_hash, 0);
let proof = tree.generate_proof(&outpoint).unwrap();
let is_valid = UtxoMerkleTree::verify_utxo_proof(
&commitment,
&outpoint,
&utxo,
proof, )
.unwrap();
assert!(is_valid, "Valid proof should verify successfully");
}
#[test]
fn test_verify_utxo_proof_wrong_utxo() {
let mut tree = UtxoMerkleTree::new().unwrap();
let outpoint = OutPoint {
hash: [1; 32],
index: 0,
};
let utxo_a = UTXO {
value: 1000,
script_pubkey: vec![0x51].into(), height: 0,
is_coinbase: false,
};
let utxo_b = UTXO {
value: 2000, script_pubkey: vec![0x52].into(), height: 0,
is_coinbase: false,
};
tree.insert(outpoint.clone(), utxo_a.clone()).unwrap();
let block_hash = [2; 32];
let commitment = tree.generate_commitment(block_hash, 0);
let proof = tree.generate_proof(&outpoint).unwrap();
let is_valid = UtxoMerkleTree::verify_utxo_proof(
&commitment,
&outpoint,
&utxo_b, proof,
)
.unwrap();
assert!(!is_valid, "Proof with wrong UTXO should fail verification");
}
#[test]
fn test_verify_utxo_proof_wrong_root() {
let mut tree_a = UtxoMerkleTree::new().unwrap();
let mut tree_b = UtxoMerkleTree::new().unwrap();
let outpoint = OutPoint {
hash: [1; 32],
index: 0,
};
let utxo = UTXO {
value: 1000,
script_pubkey: vec![0x51].into(),
height: 0,
is_coinbase: false,
};
tree_a.insert(outpoint.clone(), utxo.clone()).unwrap();
let commitment_a = tree_a.generate_commitment([2; 32], 0);
let utxo_b = UTXO {
value: 2000, script_pubkey: vec![0x52].into(),
height: 0,
is_coinbase: false,
};
tree_b.insert(outpoint.clone(), utxo_b).unwrap();
let commitment_b = tree_b.generate_commitment([3; 32], 0);
let proof = tree_a.generate_proof(&outpoint).unwrap();
let is_valid = UtxoMerkleTree::verify_utxo_proof(
&commitment_b, &outpoint,
&utxo,
proof,
)
.unwrap();
assert!(!is_valid, "Proof with wrong root should fail verification");
}
#[test]
fn test_verify_utxo_proof_coinbase_utxo() {
let mut tree = UtxoMerkleTree::new().unwrap();
let outpoint = OutPoint {
hash: [1; 32],
index: 0,
};
let utxo = UTXO {
value: 5000000000, script_pubkey: vec![0x51].into(),
height: 0,
is_coinbase: true, };
tree.insert(outpoint.clone(), utxo.clone()).unwrap();
let commitment = tree.generate_commitment([2; 32], 0);
let proof = tree.generate_proof(&outpoint).unwrap();
let is_valid =
UtxoMerkleTree::verify_utxo_proof(&commitment, &outpoint, &utxo, proof).unwrap();
assert!(is_valid, "Coinbase UTXO proof should verify successfully");
}
#[test]
fn test_verify_utxo_proof_multiple_utxos() {
let mut tree = UtxoMerkleTree::new().unwrap();
let outpoint1 = OutPoint {
hash: [1; 32],
index: 0,
};
let outpoint2 = OutPoint {
hash: [2; 32],
index: 0,
};
let utxo1 = UTXO {
value: 1000,
script_pubkey: vec![0x51].into(),
height: 0,
is_coinbase: false,
};
let utxo2 = UTXO {
value: 2000,
script_pubkey: vec![0x52].into(),
height: 0,
is_coinbase: false,
};
tree.insert(outpoint1.clone(), utxo1.clone()).unwrap();
tree.insert(outpoint2.clone(), utxo2.clone()).unwrap();
let commitment = tree.generate_commitment([3; 32], 0);
let proof1 = tree.generate_proof(&outpoint1).unwrap();
let is_valid1 =
UtxoMerkleTree::verify_utxo_proof(&commitment, &outpoint1, &utxo1, proof1).unwrap();
assert!(is_valid1, "First UTXO proof should verify");
let proof2 = tree.generate_proof(&outpoint2).unwrap();
let is_valid2 =
UtxoMerkleTree::verify_utxo_proof(&commitment, &outpoint2, &utxo2, proof2).unwrap();
assert!(is_valid2, "Second UTXO proof should verify");
}
}