use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BitcoinSealRef {
pub txid: [u8; 32],
pub vout: u32,
pub nonce: Option<u64>,
}
impl BitcoinSealRef {
pub fn new(txid: [u8; 32], vout: u32, nonce: Option<u64>) -> Self {
Self { txid, vout, nonce }
}
pub fn to_vec(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(32 + 4 + 8);
out.extend_from_slice(&self.txid);
out.extend_from_slice(&self.vout.to_le_bytes());
if let Some(nonce) = self.nonce {
out.extend_from_slice(&nonce.to_le_bytes());
} else {
out.extend_from_slice(&[0u8; 8]);
}
out
}
pub fn txid_hex(&self) -> String {
hex::encode(self.txid)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BitcoinAnchorRef {
pub txid: [u8; 32],
pub output_index: u32,
pub block_height: u64,
}
impl BitcoinAnchorRef {
pub fn new(txid: [u8; 32], output_index: u32, block_height: u64) -> Self {
Self {
txid,
output_index,
block_height,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct BitcoinInclusionProof {
pub merkle_branch: Vec<[u8; 32]>,
pub block_hash: [u8; 32],
pub tx_index: u32,
pub block_height: u64,
}
impl BitcoinInclusionProof {
pub fn new(
merkle_branch: Vec<[u8; 32]>,
block_hash: [u8; 32],
tx_index: u32,
block_height: u64,
) -> Self {
Self {
merkle_branch,
block_hash,
tx_index,
block_height,
}
}
pub fn is_confirmed(&self, current_height: u64, required_depth: u32) -> bool {
self.block_height + required_depth as u64 <= current_height
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct BitcoinFinalityProof {
pub confirmations: u64,
pub meets_required_depth: bool,
pub required_depth: u32,
}
impl BitcoinFinalityProof {
pub fn new(confirmations: u64, required_depth: u32) -> Self {
Self {
confirmations,
meets_required_depth: confirmations >= required_depth as u64,
required_depth,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_seal_ref_creation() {
let seal = BitcoinSealRef::new([1u8; 32], 0, Some(42));
assert_eq!(seal.vout, 0);
assert_eq!(seal.nonce, Some(42));
}
#[test]
fn test_anchor_ref_creation() {
let anchor = BitcoinAnchorRef::new([2u8; 32], 1, 100);
assert_eq!(anchor.output_index, 1);
assert_eq!(anchor.block_height, 100);
}
#[test]
fn test_inclusion_proof_confirmed() {
let proof = BitcoinInclusionProof::new(vec![], [3u8; 32], 0, 100);
assert!(proof.is_confirmed(106, 6));
assert!(!proof.is_confirmed(105, 6));
}
#[test]
fn test_finality_proof() {
let proof = BitcoinFinalityProof::new(6, 6);
assert!(proof.meets_required_depth);
let proof = BitcoinFinalityProof::new(5, 6);
assert!(!proof.meets_required_depth);
}
}