bitcoin_spv/
std_types.rs

1extern crate serde_json;
2extern crate std;
3
4use std::{fmt, string::ToString, vec::Vec};
5
6use serde::{Deserialize, Serialize};
7
8use crate::{btcspv, types::*, utils, validatespv};
9
10impl_hex_serde!(RawHeader, 80);
11impl_hex_serde!(Hash256Digest, 32);
12impl_hex_serde!(Hash160Digest, 20);
13
14#[doc(hidden)]
15pub type RawBytes = Vec<u8>;
16
17/// BitcoinHeader is a parsed Bitcoin header with height information appended.
18/// Values are LE
19#[derive(Clone, Deserialize, Serialize)]
20pub struct BitcoinHeader {
21    /// The double-sha2 digest encoded BE.
22    pub hash: Hash256Digest,
23    /// The 80-byte raw header.
24    pub raw: RawHeader,
25    /// The height of the header
26    pub height: u32,
27    /// The double-sha2 digest of the parent encoded BE.
28    pub prevhash: Hash256Digest,
29    /// The double-sha2 merkle tree root of the block transactions encoded BE.
30    pub merkle_root: Hash256Digest,
31}
32
33impl BitcoinHeader {
34    /// Checks validity of an entire Bitcoin header
35    ///
36    /// # Arguments
37    ///
38    /// * `self` - The Bitcoin header
39    ///
40    /// # Errors
41    ///
42    /// * Errors if any of the Bitcoin header elements are invalid.
43    pub fn validate(&self) -> Result<(), SPVError> {
44        if self.hash != self.raw.digest() {
45            return Err(SPVError::WrongDigest);
46        }
47        if self.merkle_root != self.raw.tx_root() {
48            return Err(SPVError::WrongMerkleRoot);
49        }
50        if self.prevhash != self.raw.parent() {
51            return Err(SPVError::WrongPrevHash);
52        }
53        Ok(())
54    }
55}
56
57impl PartialEq for BitcoinHeader {
58    /// Compares two Bitcoin headers
59    ///
60    /// # Arguments
61    ///
62    /// * `self` - The Bitcoin header
63    /// * ` other` - The second Bitcoin header
64    fn eq(&self, other: &Self) -> bool {
65        self.raw == other.raw
66            && self.hash == other.hash
67            && self.height == other.height
68            && self.prevhash == other.prevhash
69            && self.merkle_root == other.merkle_root
70    }
71}
72
73impl Eq for BitcoinHeader {}
74
75#[cfg_attr(tarpaulin, skip)]
76impl fmt::Debug for BitcoinHeader {
77    /// Formats the bitcoin header for readability
78    ///
79    /// # Arguments
80    ///
81    /// * `self` - The Bitcoin header
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        write!(
84            f,
85            "Header (height {:?}:\t{:?})",
86            self.height,
87            self.raw
88        )
89    }
90}
91
92#[cfg_attr(tarpaulin, skip)]
93impl fmt::Debug for RawHeader {
94    /// Formats the bitcoin header for readability
95    ///
96    /// # Arguments
97    ///
98    /// * `self` - The Bitcoin header
99    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100        write!(
101            f,
102            "Header: {}",
103            utils::serialize_hex(self.as_ref())
104        )
105    }
106}
107
108#[cfg_attr(tarpaulin, skip)]
109impl fmt::Display for BitcoinHeader {
110    /// Formats the bitcoin header for readability
111    ///
112    /// # Arguments
113    ///
114    /// * `self` - The Bitcoin header
115    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116        write!(
117            f,
118            "Header (height {:?}:\t{})",
119            self.height,
120            utils::serialize_hex(self.raw.as_ref())
121        )
122    }
123}
124
125/// SPVProof is an SPV inclusion proof for a confirmed transaction.
126#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
127pub struct SPVProof {
128    /// The 4-byte LE-encoded version number. Currently always 1 or 2.
129    #[serde(with = "vec_ser")]
130    pub version: RawBytes,
131    /// The transaction input vector, length-prefixed.
132    #[serde(with = "vec_ser")]
133    pub vin: RawBytes,
134    /// The transaction output vector, length-prefixed.
135    #[serde(with = "vec_ser")]
136    pub vout: RawBytes,
137    /// The 4-byte LE-encoded locktime number.
138    #[serde(with = "vec_ser")]
139    pub locktime: RawBytes,
140    /// The tx id
141    pub tx_id: Hash256Digest,
142    /// The transaction index
143    pub index: u32,
144    /// The confirming Bitcoin header
145    pub confirming_header: BitcoinHeader,
146    /// The intermediate nodes (digests between leaf and root)
147    #[serde(with = "vec_ser")]
148    pub intermediate_nodes: RawBytes,
149}
150
151impl SPVProof {
152    /// Checks validity of an entire SPV Proof
153    ///
154    /// # Arguments
155    ///
156    /// * `self` - The SPV Proof
157    ///
158    /// # Errors
159    ///
160    /// * Errors if any of the SPV Proof elements are invalid.
161    pub fn validate(&self) -> Result<(), SPVError> {
162        if !btcspv::validate_vin(&self.vin) {
163            return Err(SPVError::InvalidVin);
164        }
165
166        if !btcspv::validate_vout(&self.vout) {
167            return Err(SPVError::InvalidVout);
168        }
169
170        let mut ver = [0u8; 4];
171        ver.copy_from_slice(&self.version);
172        let mut lock = [0u8; 4];
173        lock.copy_from_slice(&self.locktime);
174
175        let tx_id = validatespv::calculate_txid(
176            &ver,
177            &Vin::new(&self.vin)?,
178            &Vout::new(&self.vout)?,
179            &lock,
180        );
181        if tx_id != self.tx_id {
182            return Err(SPVError::WrongTxID);
183        }
184
185        self.confirming_header.validate()?;
186
187        if !validatespv::prove(
188            tx_id,
189            self.confirming_header.merkle_root,
190            &MerkleArray::new(&self.intermediate_nodes)?,
191            self.index as u64,
192        ) {
193            return Err(SPVError::BadMerkleProof);
194        }
195        Ok(())
196    }
197}
198
199#[cfg_attr(tarpaulin, skip)]
200impl fmt::Debug for SPVProof {
201    /// Formats the SPV Proof for readability
202    ///
203    /// # Arguments
204    ///
205    /// * `self` - The SPV Proof
206    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
207        write!(
208            f,
209            "\nSPVProof (\n\ttx_id:\t{}\n\tindex:\t{}\n\th:\t",
210            utils::serialize_hex(self.tx_id.as_ref()),
211            self.index
212        )?;
213        self.confirming_header.fmt(f)?;
214        write!(
215            f,
216            "\n\tproof:\t{})\n",
217            utils::serialize_hex(self.intermediate_nodes.as_ref())
218        )
219    }
220}
221
222#[cfg_attr(tarpaulin, skip)]
223impl fmt::Display for SPVProof {
224    /// Formats the SPVProof for readability
225    ///
226    /// # Arguments
227    ///
228    /// * `self` - The SPV Proof
229    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230        write!(
231            f,
232            "\nSPVProof (\n\ttx_id:\t{}\n\tindex:\t{}\n\th:\t",
233            utils::serialize_hex(self.tx_id.as_ref()),
234            self.index
235        )?;
236        self.confirming_header.fmt(f)?;
237        write!(
238            f,
239            "\n\tproof:\t{})\n",
240            utils::serialize_hex(self.intermediate_nodes.as_ref())
241        )
242    }
243}
244mod vec_ser {
245    use super::*;
246    use serde::{Deserialize, Deserializer, Serializer};
247
248    use crate::utils;
249
250    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
251    where
252        D: Deserializer<'de>,
253    {
254        let s: &str = Deserialize::deserialize(deserializer)?;
255        utils::deserialize_hex(s).map_err(|e| serde::de::Error::custom(e.to_string()))
256    }
257
258    pub fn serialize<S>(d: &[u8], serializer: S) -> Result<S::Ok, S::Error>
259    where
260        S: Serializer,
261    {
262        let s: &str = &utils::serialize_hex(&d[..]);
263        serializer.serialize_str(s)
264    }
265}
266
267
268#[cfg(test)]
269#[cfg_attr(tarpaulin, skip)]
270mod tests {
271    use serde_json;
272
273    use std::{
274        fs::File,
275        io::Read,
276        panic,
277        string::{String, ToString},
278    };
279
280    use super::*;
281    use crate::test_utils;
282
283    #[derive(Debug, Deserialize)]
284    struct InvalidHeadersCases {
285        header: BitcoinHeader,
286        e: String,
287    }
288
289    #[derive(Debug, Deserialize)]
290    struct InvalidProofsCases {
291        proof: SPVProof,
292        e: String,
293    }
294
295    #[allow(non_snake_case)]
296    #[derive(Debug, Deserialize)]
297    struct TestCases {
298        valid: Vec<String>,
299        badHeaders: Vec<InvalidHeadersCases>,
300        badSPVProofs: Vec<InvalidProofsCases>,
301        errBadHexBytes: String,
302        errBadHexHash256: String,
303        errBadLenHash256: String,
304        errBadHexRawHeader: String,
305        errBadLenRawHeader: String,
306    }
307
308    fn setup() -> TestCases {
309        let mut file = File::open("../testProofs.json").unwrap();
310        let mut data = String::new();
311        file.read_to_string(&mut data).unwrap();
312
313        let cases: TestCases = serde_json::from_str(&data).unwrap();
314        cases
315    }
316
317    fn run_test<T>(test: T) -> ()
318    where
319        T: FnOnce(&TestCases) -> () + panic::UnwindSafe,
320    {
321        let cases = setup();
322
323        let result = panic::catch_unwind(|| test(&cases));
324
325        assert!(result.is_ok())
326    }
327
328    #[test]
329    fn it_can_deser_and_reser_proofs() {
330        run_test(|cases| {
331            let valid_proofs = &cases.valid;
332            for case in valid_proofs {
333                let proof: SPVProof = serde_json::from_str(&case).unwrap();
334                let re_stringed = serde_json::to_string(&proof).unwrap();
335                let re_proofed: SPVProof = serde_json::from_str(&re_stringed).unwrap();
336                assert_eq!(re_proofed, proof);
337            }
338        })
339    }
340
341    #[test]
342    fn it_errors_on_bad_hex_bytes() {
343        run_test(|cases| {
344            let invalid_proof = &cases.errBadHexBytes;
345            let proof: serde_json::Result<SPVProof> = serde_json::from_str(invalid_proof);
346            let expected = "Invalid character \'Q\' at position";
347            match proof {
348                Ok(_) => assert!(false, "Expected error"),
349                Err(v) => assert!(v.to_string().contains(expected)),
350            }
351        })
352    }
353
354    #[test]
355    fn it_errors_on_bad_hash256_bytes() {
356        run_test(|cases| {
357            let invalid_proof = &cases.errBadHexHash256;
358            let proof: serde_json::Result<SPVProof> = serde_json::from_str(invalid_proof);
359            let expected = "Invalid character \'R\' at position";
360            match proof {
361                Ok(_) => assert!(false, "Expected error"),
362                Err(v) => assert!(v.to_string().contains(expected)),
363            }
364        })
365    }
366
367    #[test]
368    fn it_errors_on_bad_hash256_len() {
369        run_test(|cases| {
370            let invalid_proof = &cases.errBadLenHash256;
371            let proof: serde_json::Result<SPVProof> = serde_json::from_str(invalid_proof);
372            let expected = "Expected 32 bytes, got 31 bytes";
373            match proof {
374                Ok(_) => assert!(false, "Expected error"),
375                Err(v) => assert!(v.to_string().contains(expected)),
376            }
377        })
378    }
379
380    #[test]
381    fn it_errors_on_bad_header_bytes() {
382        run_test(|cases| {
383            let invalid_proof = &cases.errBadHexRawHeader;
384            let proof: serde_json::Result<SPVProof> = serde_json::from_str(invalid_proof);
385            let expected = "Invalid character \'S\' at position";
386            match proof {
387                Ok(_) => assert!(false, "Expected error"),
388                Err(v) => assert!(v.to_string().contains(expected)),
389            }
390        })
391    }
392
393    #[test]
394    fn it_errors_on_bad_header_len() {
395        run_test(|cases| {
396            let invalid_proof = &cases.errBadLenRawHeader;
397            let proof: serde_json::Result<SPVProof> = serde_json::from_str(invalid_proof);
398            let expected = "Expected 80 bytes, got 79 bytes";
399            match proof {
400                Ok(_) => assert!(false, "Expected error"),
401                Err(v) => assert!(v.to_string().contains(expected)),
402            }
403        })
404    }
405
406    #[test]
407    fn it_validates_bitcoin_header_objects() {
408        run_test(|cases| {
409            let valid: SPVProof = serde_json::from_str(&cases.valid[0]).unwrap();
410            let header = valid.confirming_header;
411            let result = header.validate();
412            result.unwrap(); // panics if there's an error
413
414            let invalid = &cases.badHeaders;
415            for i in invalid {
416                let res = i.header.validate();
417                let expected = test_utils::match_string_to_err(&i.e);
418                match res {
419                    Ok(_) => assert!(false, "Expected an error"),
420                    Err(e) => assert_eq!(e, expected),
421                }
422            }
423        })
424    }
425
426    #[test]
427    fn it_validates_spv_proof_objects() {
428        run_test(|cases| {
429            let valid: SPVProof = serde_json::from_str(&cases.valid[0]).unwrap();
430            let result = valid.validate();
431            result.expect("Invalid case expected to be valid"); // panics if there's an error
432
433            let invalid = &cases.badSPVProofs;
434            for i in invalid {
435                let res = i.proof.validate();
436                let expected = test_utils::match_string_to_err(&i.e);
437                match res {
438                    Ok(_) => assert!(false, "Expected an error"),
439                    Err(e) => assert_eq!(e, expected),
440                }
441            }
442        })
443    }
444}