txoproof.rs
1 use std::borrow::Cow; 2 use std::hash::Hash; 3 use std::io::Cursor; 4 5 use bitcoin::block::Header as BlockHeader; 6 use bitcoin::merkle_tree::PartialMerkleTree; 7 use bitcoin::{BlockHash, Txid}; 8 use hex::{FromHex, ToHex}; 9 use serde::de::Error; 10 use serde::{Deserialize, Deserializer, Serialize, Serializer}; 11 12 use crate::encoding::{Decodable, DecodeError, Encodable}; 13 use crate::module::registry::ModuleDecoderRegistry; 14 15 #[derive(Clone, Debug)] 16 pub struct TxOutProof { 17 pub block_header: BlockHeader, 18 pub merkle_proof: PartialMerkleTree, 19 } 20 21 impl TxOutProof { 22 pub fn block(&self) -> BlockHash { 23 self.block_header.block_hash() 24 } 25 26 pub fn contains_tx(&self, tx_id: Txid) -> bool { 27 let mut transactions = Vec::new(); 28 let mut indices = Vec::new(); 29 let root = self 30 .merkle_proof 31 .extract_matches(&mut transactions, &mut indices) 32 .expect("Checked at construction time"); 33 34 debug_assert_eq!(root, self.block_header.merkle_root); 35 36 transactions.contains(&tx_id) 37 } 38 } 39 40 impl Decodable for TxOutProof { 41 fn consensus_decode<D: std::io::Read>( 42 d: &mut D, 43 modules: &ModuleDecoderRegistry, 44 ) -> Result<Self, DecodeError> { 45 let block_header = BlockHeader::consensus_decode(d, modules)?; 46 let merkle_proof = PartialMerkleTree::consensus_decode(d, modules)?; 47 48 let mut transactions = Vec::new(); 49 let mut indices = Vec::new(); 50 let root = merkle_proof 51 .extract_matches(&mut transactions, &mut indices) 52 .map_err(|_| DecodeError::from_str("Invalid partial merkle tree"))?; 53 54 if block_header.merkle_root != root { 55 Err(DecodeError::from_str( 56 "Partial merkle tree does not belong to block header", 57 )) 58 } else { 59 Ok(TxOutProof { 60 block_header, 61 merkle_proof, 62 }) 63 } 64 } 65 } 66 67 impl Encodable for TxOutProof { 68 fn consensus_encode<W: std::io::Write>(&self, writer: &mut W) -> Result<usize, std::io::Error> { 69 let mut written = 0; 70 71 written += self.block_header.consensus_encode(writer)?; 72 written += self.merkle_proof.consensus_encode(writer)?; 73 74 Ok(written) 75 } 76 } 77 78 impl Serialize for TxOutProof { 79 fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> 80 where 81 S: Serializer, 82 { 83 let mut bytes = Vec::new(); 84 self.consensus_encode(&mut bytes).unwrap(); 85 86 if serializer.is_human_readable() { 87 serializer.serialize_str(&bytes.encode_hex::<String>()) 88 } else { 89 serializer.serialize_bytes(&bytes) 90 } 91 } 92 } 93 94 impl<'de> Deserialize<'de> for TxOutProof { 95 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> 96 where 97 D: Deserializer<'de>, 98 { 99 let empty_module_registry = ModuleDecoderRegistry::default(); 100 if deserializer.is_human_readable() { 101 let hex_str: Cow<str> = Deserialize::deserialize(deserializer)?; 102 let bytes = Vec::from_hex(hex_str.as_ref()).map_err(D::Error::custom)?; 103 Ok( 104 TxOutProof::consensus_decode(&mut Cursor::new(bytes), &empty_module_registry) 105 .map_err(D::Error::custom)?, 106 ) 107 } else { 108 let bytes: &[u8] = Deserialize::deserialize(deserializer)?; 109 Ok( 110 TxOutProof::consensus_decode(&mut Cursor::new(bytes), &empty_module_registry) 111 .map_err(D::Error::custom)?, 112 ) 113 } 114 } 115 } 116 117 // TODO: upstream 118 impl Hash for TxOutProof { 119 fn hash<H: std::hash::Hasher>(&self, state: &mut H) { 120 let mut bytes = Vec::new(); 121 self.consensus_encode(&mut bytes).unwrap(); 122 state.write(&bytes); 123 } 124 } 125 126 impl PartialEq for TxOutProof { 127 fn eq(&self, other: &TxOutProof) -> bool { 128 self.block_header == other.block_header && self.merkle_proof == other.merkle_proof 129 } 130 } 131 132 impl Eq for TxOutProof {}