bitcoin_spv/
lib.rs

1#![warn(missing_docs)]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4//! This crate is part of the `bitcoin-spv` project.
5//!
6//! This work is produced and copyrighted by Summa, and released under
7//! the terms of the LGPLv3 license.
8//!
9//! It contains a collection of Rust functions and structs for working with
10//! Bitcoin data structures. Basically, these tools help you parse, inspect,
11//! and authenticate Bitcoin transactions.
12//!
13//! *It is extremely easy to write insecure code using these libraries. We do
14//! not recommend a specific security model. Any SPV verification involves
15//! complex security assumptions. Please seek external review for your design
16//! before building with these libraries.*
17
18#[doc(hidden)]
19#[macro_use]
20pub mod macros;
21
22/// `btcspv` provides basic Bitcoin transaction and header parsing, as well as
23/// utility functions like merkle verification and difficulty adjustment
24/// calculation.
25pub mod btcspv;
26
27/// `validatespv` provides higher-levels of abstraction for evaluating
28/// SPV proofs, transactions, and headers.
29pub mod validatespv;
30
31/// `types` exposes simple types for on-chain evaluation of SPV proofs
32pub mod types;
33
34/// `std_types` exposes useful structs for headers and SPV proofs, and provides
35/// (de)serialization for these structs. It implements a standard JSON format
36/// that is compatible with all other `bitcoin-spv` implementations.
37#[cfg(feature = "std")]
38pub mod std_types;
39
40/// `utils` contains utility functions for working with bytestrings, including
41/// hex encoding and decoding.
42#[cfg(feature = "std")]
43pub mod utils;
44
45#[cfg(test)]
46#[doc(hidden)]
47#[cfg_attr(tarpaulin, skip)]
48pub mod test_utils {
49
50    extern crate hex;
51    extern crate std;
52
53    use primitive_types::U256;
54    use serde::Deserialize;
55
56    use crate::btcspv;
57    use crate::types::{RawHeader, SPVError};
58
59    use std::{
60        format,
61        fs::File,
62        io::Read,
63        panic,
64        string::String,
65        vec,      // The macro
66        vec::Vec, // The struct
67    };
68
69    /// Changes the endianness of a byte array.
70    /// Returns a new, backwards, byte array.
71    ///
72    /// # Arguments
73    ///
74    /// * `b` - The bytes to reverse
75    pub fn reverse_endianness(b: &[u8]) -> Vec<u8> {
76        b.iter().rev().copied().collect()
77    }
78
79    /// Strips the '0x' prefix off of hex string so it can be deserialized.
80    ///
81    /// # Arguments
82    ///
83    /// * `s` - The hex str
84    pub fn strip_0x_prefix(s: &str) -> &str {
85        if &s[..2] == "0x" {
86            &s[2..]
87        } else {
88            s
89        }
90    }
91
92    /// Deserializes a hex string into a u8 array.
93    ///
94    /// # Arguments
95    ///
96    /// * `s` - The hex string
97    pub fn deserialize_hex(s: &str) -> Result<Vec<u8>, hex::FromHexError> {
98        hex::decode(&strip_0x_prefix(s))
99    }
100
101    /// Serializes a u8 array into a hex string.
102    ///
103    /// # Arguments
104    ///
105    /// * `buf` - The value as a u8 array
106    pub fn serialize_hex(buf: &[u8]) -> String {
107        format!("0x{}", hex::encode(buf))
108    }
109
110    /// Deserialize a hex string into bytes.
111    /// Panics if the string is malformatted.
112    ///
113    /// # Arguments
114    ///
115    /// * `s` - The hex string
116    ///
117    /// # Panics
118    ///
119    /// When the string is not validly formatted hex.
120    pub fn force_deserialize_hex(s: &str) -> Vec<u8> {
121        deserialize_hex(s).unwrap()
122    }
123
124    #[derive(Deserialize, Debug)]
125    pub struct TestCase {
126        pub input: serde_json::Value,
127        pub output: serde_json::Value,
128        pub error_message: serde_json::Value,
129    }
130
131    pub struct TestHeader {
132        pub raw: RawHeader,
133        pub timestamp: u32,
134        pub target: U256,
135        pub difficulty: U256,
136    }
137
138    pub fn to_test_header(head: &serde_json::map::Map<String, serde_json::Value>) -> TestHeader {
139        let mut raw = RawHeader::default();
140        raw.as_mut().copy_from_slice(&force_deserialize_hex(
141            head.get("hex").unwrap().as_str().unwrap(),
142        ));
143
144        let timestamp = head.get("timestamp").unwrap().as_u64().unwrap() as u32;
145        let target = btcspv::extract_target(raw);
146        let difficulty = btcspv::calculate_difficulty(&target);
147        TestHeader {
148            raw,
149            timestamp,
150            target,
151            difficulty,
152        }
153    }
154
155    pub fn get_headers(heads: &serde_json::Value) -> Vec<TestHeader> {
156        let vals: &Vec<serde_json::Value> = heads.as_array().unwrap();
157        let mut headers = vec![];
158        for i in vals {
159            headers.push(to_test_header(&i.as_object().unwrap()));
160        }
161        headers
162    }
163
164    pub fn setup() -> serde_json::Value {
165        let mut file = File::open("../testVectors.json").unwrap();
166        let mut data = String::new();
167        file.read_to_string(&mut data).unwrap();
168
169        serde_json::from_str(&data).unwrap()
170    }
171
172    pub fn to_test_case(val: &serde_json::Value) -> TestCase {
173        let o = val.get("output");
174        let output: &serde_json::Value;
175        output = match o {
176            Some(v) => v,
177            None => &serde_json::Value::Null,
178        };
179
180        let e = val.get("rustError");
181        let error_message: &serde_json::Value;
182        error_message = match e {
183            Some(v) => v,
184            None => &serde_json::Value::Null,
185        };
186
187        TestCase {
188            input: val.get("input").unwrap().clone(),
189            output: output.clone(),
190            error_message: error_message.clone(),
191        }
192    }
193
194    pub fn get_test_cases(name: &str, fixtures: &serde_json::Value) -> Vec<TestCase> {
195        let vals: &Vec<serde_json::Value> = fixtures.get(name).unwrap().as_array().unwrap();
196        let mut cases = vec![];
197        for i in vals {
198            cases.push(to_test_case(&i));
199        }
200        cases
201    }
202
203    pub fn match_string_to_err(s: &str) -> SPVError {
204        match s {
205            "Malformatted data. Read overrun" => SPVError::ReadOverrun,
206            "Read overrun" => SPVError::ReadOverrun,
207            "Vout read overrun" => SPVError::ReadOverrun,
208            "Vin read overrun" => SPVError::ReadOverrun,
209            "Read overrun when parsing vout" => SPVError::ReadOverrun,
210            "Read overrun when parsing vin" => SPVError::ReadOverrun,
211            "Bad VarInt in scriptPubkey" => SPVError::BadCompactInt,
212            "Bad VarInt in scriptSig" => SPVError::BadCompactInt,
213            "Read overrun during VarInt parsing" => SPVError::BadCompactInt,
214            "Malformatted data. Must be an op return" => SPVError::MalformattedOpReturnOutput,
215            "Maliciously formatted p2sh output" => SPVError::MalformattedP2SHOutput,
216            "Maliciously formatted p2pkh output" => SPVError::MalformattedP2PKHOutput,
217            "Maliciously formatted witness output" => SPVError::MalformattedWitnessOutput,
218            "Nonstandard, OP_RETURN, or malformatted output" => SPVError::MalformattedOutput,
219            "Header bytes not multiple of 80" => SPVError::WrongLengthHeader,
220            "Header does not meet its own difficulty target" => SPVError::InsufficientWork,
221            "Header bytes not a valid chain" => SPVError::InvalidChain,
222            "Hash is not the correct hash of the header" => SPVError::WrongDigest,
223            "MerkleRoot is not the correct merkle root of the header" => SPVError::WrongMerkleRoot,
224            "Prevhash is not the correct parent hash of the header" => SPVError::WrongPrevHash,
225            "Vin is not valid" => SPVError::InvalidVin,
226            "Vout is not valid" => SPVError::InvalidVout,
227            "Version, Vin, Vout and Locktime did not yield correct TxID" => SPVError::WrongTxID,
228            "Merkle Proof is not valid" => SPVError::BadMerkleProof,
229            "Reported length mismatch" => SPVError::OutputLengthMismatch,
230            _ => SPVError::UnknownError,
231        }
232    }
233
234    pub fn run_test<T>(test: T)
235    where
236        T: FnOnce(&serde_json::Value) -> () + panic::UnwindSafe,
237    {
238        let fixtures = setup();
239
240        let result = panic::catch_unwind(|| test(&fixtures));
241
242        assert!(result.is_ok())
243    }
244
245    #[test]
246    fn it_strips_0x_prefixes() {
247        let cases = [
248            ("00", "00"),
249            ("0x00", "00"),
250            ("aa", "aa"),
251            ("0xaa", "aa"),
252            ("Quotidian", "Quotidian"),
253            ("0xQuotidian", "Quotidian"),
254        ];
255        for case in cases.iter() {
256            assert_eq!(strip_0x_prefix(case.0), case.1);
257        }
258    }
259}