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#[derive(Clone, Deserialize, Serialize)]
20pub struct BitcoinHeader {
21 pub hash: Hash256Digest,
23 pub raw: RawHeader,
25 pub height: u32,
27 pub prevhash: Hash256Digest,
29 pub merkle_root: Hash256Digest,
31}
32
33impl BitcoinHeader {
34 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 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 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 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 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#[derive(PartialEq, Eq, Clone, Serialize, Deserialize)]
127pub struct SPVProof {
128 #[serde(with = "vec_ser")]
130 pub version: RawBytes,
131 #[serde(with = "vec_ser")]
133 pub vin: RawBytes,
134 #[serde(with = "vec_ser")]
136 pub vout: RawBytes,
137 #[serde(with = "vec_ser")]
139 pub locktime: RawBytes,
140 pub tx_id: Hash256Digest,
142 pub index: u32,
144 pub confirming_header: BitcoinHeader,
146 #[serde(with = "vec_ser")]
148 pub intermediate_nodes: RawBytes,
149}
150
151impl SPVProof {
152 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 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 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(); 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"); 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}