bitcoin_spv/
types.rs

1use primitive_types::U256;
2
3/// enum for bitcoin-spv errors
4#[derive(Debug, PartialEq, Eq, Clone)]
5pub enum SPVError {
6    /// Overran a checked read on a slice
7    ReadOverrun,
8    /// Attempted to parse a CompactInt without enough bytes
9    BadCompactInt,
10    /// Called `extract_op_return_data` on an output without an op_return.
11    MalformattedOpReturnOutput,
12    /// `extract_hash` identified a SH output prefix without a SH postfix.
13    MalformattedP2SHOutput,
14    /// `extract_hash` identified a PKH output prefix without a PKH postfix.
15    MalformattedP2PKHOutput,
16    /// `extract_hash` identified a Witness output with a bad length tag.
17    MalformattedWitnessOutput,
18    /// `extract_hash` could not identify the output type.
19    MalformattedOutput,
20    /// Header not exactly 80 bytes.
21    WrongLengthHeader,
22    /// Header chain changed difficulties unexpectedly
23    UnexpectedDifficultyChange,
24    /// Header does not meet its own difficulty target.
25    InsufficientWork,
26    /// Header in chain does not correctly reference parent header.
27    InvalidChain,
28    /// When validating a `BitcoinHeader`, the `hash` field is not the digest
29    /// of the raw header.
30    WrongDigest,
31    /// When validating a `BitcoinHeader`, the `merkle_root` field does not
32    /// match the root found in the raw header.
33    WrongMerkleRoot,
34    /// When validating a `BitcoinHeader`, the `prevhash` field does not
35    /// match the parent hash found in the raw header.
36    WrongPrevHash,
37    /// A `vin` (transaction input vector) is malformatted.
38    InvalidVin,
39    /// A `vout` (transaction output vector) is malformatted.
40    InvalidVout,
41    /// When validating an `SPVProof`, the `tx_id` field is not the digest
42    /// of the `version`, `vin`, `vout`, and `locktime`.
43    WrongTxID,
44    /// When validating an `SPVProof`, the `intermediate_nodes` is not a valid
45    /// merkle proof connecting the `tx_id_le` to the `confirming_header`.
46    BadMerkleProof,
47    /// TxOut's reported length does not match passed-in byte slice's length
48    OutputLengthMismatch,
49    /// Any other error
50    UnknownError,
51}
52
53/// The standard address payload types
54#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
55pub enum PayloadType<'a> {
56    /// A PKH
57    PKH(&'a [u8]),
58    /// A SH
59    SH(&'a [u8]),
60    /// A WPKH
61    WPKH(&'a [u8]),
62    /// A WSH
63    WSH(&'a [u8]),
64}
65
66impl PartialEq<[u8]> for PayloadType<'_> {
67    fn eq(&self, other: &[u8]) -> bool {
68        match self {
69            PayloadType::PKH(slice) => *slice == other,
70            PayloadType::SH(slice) => *slice == other,
71            PayloadType::WPKH(slice) => *slice == other,
72            PayloadType::WSH(slice) => *slice == other,
73        }
74    }
75}
76
77impl PartialEq<&[u8]> for PayloadType<'_> {
78    fn eq(&self, other: &&[u8]) -> bool {
79        match self {
80            PayloadType::PKH(slice) => slice == other,
81            PayloadType::SH(slice) => slice == other,
82            PayloadType::WPKH(slice) => slice == other,
83            PayloadType::WSH(slice) => slice == other,
84        }
85    }
86}
87
88/// A raw bitcoin header.
89#[derive(Copy, Clone)]
90pub struct RawHeader([u8; 80]);
91
92impl PartialEq for RawHeader {
93    fn eq(&self, other: &Self) -> bool {
94        self.0[..] == other.0[..]
95    }
96}
97
98impl Eq for RawHeader {}
99
100impl RawHeader {
101    /// Try to instantiate a new RawHeader from some bytes. Errors if the bytearray is not 80
102    /// bytes or more.
103    pub fn new<T: AsRef<[u8]>>(buf: &T) -> Result<Self, SPVError> {
104        if buf.as_ref().len() < 80 {
105            return Err(SPVError::WrongLengthHeader);
106        }
107        let mut header = Self::default();
108        header.as_mut().copy_from_slice(&buf.as_ref()[..80]);
109        Ok(header)
110    }
111
112    /// Calculate the LE header digest
113    pub fn digest(&self) -> Hash256Digest {
114        crate::btcspv::hash256(&[self.as_ref()])
115    }
116
117    /// Extract the LE tx merkle root from the header
118    pub fn tx_root(&self) -> Hash256Digest {
119        crate::btcspv::extract_merkle_root_le(*self)
120    }
121
122    /// Extract the target from the header
123    pub fn target(&self) -> U256 {
124        crate::btcspv::extract_target(*self)
125    }
126
127    /// Extract the difficulty from the header
128    pub fn difficulty(&self) -> U256 {
129        crate::btcspv::extract_difficulty(*self)
130    }
131
132    /// Extract the timestamp from the header
133    pub fn timestamp(&self) -> u32 {
134        crate::btcspv::extract_timestamp(*self)
135    }
136
137    /// Extract the LE parent digest from the header
138    pub fn parent(&self) -> Hash256Digest {
139        crate::btcspv::extract_prev_block_hash_le(*self)
140    }
141}
142
143impl Default for RawHeader {
144    fn default() -> Self {
145        Self([0u8; 80])
146    }
147}
148
149impl From<[u8; 80]> for RawHeader {
150    fn from(buf: [u8; 80]) -> Self {
151        Self(buf)
152    }
153}
154
155impl AsRef<[u8; 80]> for RawHeader {
156    fn as_ref(&self) -> &[u8; 80] {
157        &self.0
158    }
159}
160
161impl AsMut<[u8; 80]> for RawHeader {
162    fn as_mut(&mut self) -> &mut [u8; 80] {
163        &mut self.0
164    }
165}
166
167impl<I: core::slice::SliceIndex<[u8]>> core::ops::Index<I> for RawHeader {
168    type Output = I::Output;
169
170    fn index(&self, index: I) -> &Self::Output {
171        self.as_ref().index(index)
172    }
173}
174
175/// A slice of `Hash256Digest`s for use in a merkle array
176#[derive(Clone, PartialEq, Eq, Hash)]
177pub struct HeaderArray<'a>(&'a [u8]);
178
179#[cfg_attr(tarpaulin, skip)]
180impl core::fmt::Debug for HeaderArray<'_> {
181    /// Formats the RawHeader for readability
182    ///
183    /// # Arguments
184    ///
185    /// * `self` - The Bitcoin header
186    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
187        write!(
188            f,
189            "HeaderArray: {:x?}", self.0
190        )
191    }
192}
193
194impl<'a> HeaderArray<'a> {
195    /// Return a new merkle array from a slice
196    pub fn new(slice: &'a [u8]) -> Result<HeaderArray<'a>, SPVError> {
197        if slice.len() % 80 == 0 {
198            Ok(Self(slice))
199        } else {
200            Err(SPVError::WrongLengthHeader)
201        }
202    }
203}
204
205impl HeaderArray<'_> {
206    /// The length of the underlying slice
207    pub fn len(&self) -> usize {
208        self.0.len() / 80
209    }
210
211    /// Whether the underlying slice is empty
212    pub fn is_empty(&self) -> bool {
213        self.0.is_empty()
214    }
215
216    /// Index into the merkle array. This does not protect you from overruns, which may result in
217    /// panics.
218    pub fn index(&self, index: usize) -> RawHeader {
219        let mut header = RawHeader::default();
220        header
221            .as_mut()
222            .copy_from_slice(&self.0[index * 80..(index + 1) * 80]);
223        header
224    }
225
226    /// Validate the header array. Return either the accumulated difficulty, or an error
227    pub fn valid_difficulty(&self, constant_difficulty: bool) -> Result<U256, SPVError> {
228        crate::validatespv::validate_header_chain(self, constant_difficulty)
229    }
230
231    /// Return a new iterator for the header array.
232    pub fn iter(&self) -> HeaderArrayIter {
233        HeaderArrayIter::new(&self)
234    }
235}
236
237/// Iterator for a HeaderArray
238pub struct HeaderArrayIter<'a> {
239    next_index: usize,
240    headers: &'a HeaderArray<'a>,
241}
242
243impl<'a> HeaderArrayIter<'a> {
244    fn new(headers: &'a HeaderArray<'a>) -> Self {
245        Self {
246            next_index: 0,
247            headers,
248        }
249    }
250}
251
252impl<'a> Iterator for HeaderArrayIter<'a> {
253    type Item = RawHeader;
254
255    fn next(&mut self) -> Option<Self::Item> {
256        if self.next_index == self.headers.len() {
257            return None;
258        }
259        let header = self.headers.index(self.next_index);
260        self.next_index += 1;
261        Some(header)
262    }
263}
264
265/// A bitoin double-sha256 digest
266#[derive(Copy, Clone, PartialEq, Eq, Default, Hash)]
267pub struct Hash256Digest([u8; 32]);
268
269#[cfg_attr(tarpaulin, skip)]
270impl core::fmt::Debug for Hash256Digest {
271    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
272        write!(
273            f,
274            "Hash256Digest: {:x?}", self.0
275        )
276    }
277}
278
279
280impl From<[u8; 32]> for Hash256Digest {
281    fn from(buf: [u8; 32]) -> Self {
282        Self(buf)
283    }
284}
285
286impl AsRef<[u8; 32]> for Hash256Digest {
287    fn as_ref(&self) -> &[u8; 32] {
288        &self.0
289    }
290}
291
292impl AsMut<[u8; 32]> for Hash256Digest {
293    fn as_mut(&mut self) -> &mut [u8; 32] {
294        &mut self.0
295    }
296}
297
298/// A bitcoin rmd160-of-sha256 digest
299#[derive(Copy, Clone, PartialEq, Eq, Default, Hash)]
300pub struct Hash160Digest([u8; 20]);
301
302#[cfg_attr(tarpaulin, skip)]
303impl core::fmt::Debug for Hash160Digest {
304    /// Formats the Hash160Digest for readability
305    ///
306    /// # Arguments
307    ///
308    /// * `self` - The Bitcoin header
309    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
310        write!(
311            f,
312            "Hash160Digest: {:x?}", self.0
313        )
314    }
315}
316
317impl From<[u8; 20]> for Hash160Digest {
318    fn from(buf: [u8; 20]) -> Self {
319        Self(buf)
320    }
321}
322
323impl AsRef<[u8; 20]> for Hash160Digest {
324    fn as_ref(&self) -> &[u8; 20] {
325        &self.0
326    }
327}
328
329impl AsMut<[u8; 20]> for Hash160Digest {
330    fn as_mut(&mut self) -> &mut [u8; 20] {
331        &mut self.0
332    }
333}
334
335/// A slice of `Hash256Digest`s for use in a merkle array
336#[derive(Debug, Clone, PartialEq, Eq)]
337pub struct MerkleArray<'a>(&'a [u8]);
338
339impl<'a> MerkleArray<'a> {
340    /// Return a new merkle array from a slice
341    pub fn new(slice: &'a [u8]) -> Result<MerkleArray<'a>, SPVError> {
342        if slice.len() % 32 == 0 {
343            Ok(Self(slice))
344        } else {
345            Err(SPVError::BadMerkleProof)
346        }
347    }
348}
349
350impl MerkleArray<'_> {
351    /// The length of the underlying slice
352    pub fn len(&self) -> usize {
353        self.0.len() / 32
354    }
355
356    /// Whether the underlying slice is empty
357    pub fn is_empty(&self) -> bool {
358        self.0.is_empty()
359    }
360
361    /// Index into the merkle array
362    pub fn index(&self, index: usize) -> Hash256Digest {
363        let mut digest = Hash256Digest::default();
364        digest
365            .as_mut()
366            .copy_from_slice(&self.0[index * 32..(index + 1) * 32]);
367        digest
368    }
369}
370
371/// A Bitcoin-formatted `CompactInt`
372#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
373pub struct CompactInt(u64);
374
375compact_int_conv!(u8);
376compact_int_conv!(u16);
377compact_int_conv!(u32);
378compact_int_conv!(u64);
379compact_int_conv!(usize);
380
381impl AsRef<u64> for CompactInt {
382    fn as_ref(&self) -> &u64 {
383        &self.0
384    }
385}
386
387impl CompactInt {
388    /// Parse a compact int from a byte slice
389    pub fn parse<T: AsRef<[u8]> + ?Sized>(t: &T) -> Result<CompactInt, SPVError> {
390        crate::btcspv::parse_compact_int(t)
391    }
392
393    /// Return the underlying u64
394    pub fn number(&self) -> u64 {
395        self.0
396    }
397
398    /// The underlying number as a usize
399    pub fn as_usize(&self) -> usize {
400        self.0 as usize
401    }
402
403    /// Determine the length of the compact int when serialized
404    pub fn serialized_length(&self) -> usize {
405        match self.0 {
406            0..=0xfc => 1,
407            0xfd..=0xffff => 3,
408            0x10000..=0xffff_ffff => 5,
409            _ => 9,
410        }
411    }
412
413    /// Determines the length of a CompactInt in bytes.
414    /// A CompactInt of > 1 byte is prefixed with a flag indicating its length.
415    ///
416    /// # Arguments
417    ///
418    /// * `flag` - The first byte of a compact_int
419    pub fn data_length(flag: u8) -> u8 {
420        let length: u8 = match flag {
421            0xfd => 2,
422            0xfe => 4,
423            0xff => 8,
424            _ => 0,
425        };
426        length
427    }
428}
429
430impl_view_type!(
431    /// A ScriptSig
432    ScriptSig
433);
434
435impl_view_type!(
436    /// A Outpoint
437    Outpoint
438);
439
440impl Outpoint<'_> {
441    /// Extract the LE txid from the outpoint
442    pub fn txid_le(&self) -> Hash256Digest {
443        crate::btcspv::extract_input_tx_id_le(self)
444    }
445
446    /// Extract the outpoint's index in the prevout tx's vout
447    pub fn vout_index(&self) -> u32 {
448        crate::btcspv::extract_tx_index(self)
449    }
450}
451
452impl_view_type!(
453    /// A TxIn
454    TxIn
455);
456
457impl TxIn<'_> {
458    /// Extract the outpoint from the TxIn
459    pub fn outpoint(&self) -> Outpoint {
460        crate::btcspv::extract_outpoint(self)
461    }
462
463    /// Extract the sequence number from the TxIn
464    pub fn sequence(&self) -> u32 {
465        crate::btcspv::extract_sequence(self).expect("Not malformed")
466    }
467
468    /// Extract the script sig from the TxIn
469    pub fn script_sig(&self) -> ScriptSig {
470        crate::btcspv::extract_script_sig(self).expect("Not malformed")
471    }
472}
473
474impl_view_type!(
475    /// A Vin
476    Vin
477);
478
479impl<'a> Vin<'a> {
480    /// Instantiate a new `Vin` from a slice, if the slice is a valid `Vin`
481    pub fn new(slice: &'a [u8]) -> Result<Vin<'a>, SPVError> {
482        if crate::btcspv::validate_vin(slice) {
483            Ok(Self(slice))
484        } else {
485            Err(SPVError::InvalidVin)
486        }
487    }
488
489    /// Retrieve the txin at the specified index of the vin
490    pub fn index(&self, index: usize) -> Result<TxIn, SPVError> {
491        crate::btcspv::extract_input_at_index(self, index)
492    }
493}
494
495impl_view_type!(
496    /// A ScriptPubkey, with its compact int length prefix
497    ScriptPubkey
498);
499
500impl ScriptPubkey<'_> {
501    /// Extract the op return payload, if any
502    pub fn op_return(&self) -> Result<OpReturnPayload, SPVError> {
503        crate::btcspv::extract_op_return_data(self)
504    }
505
506    /// Extract the hash payload from standard scripts
507    pub fn payload(&self) -> Result<PayloadType, SPVError> {
508        crate::btcspv::extract_hash(self)
509    }
510}
511
512impl_view_type!(
513    /// A OpReturnPayload
514    OpReturnPayload
515);
516
517impl_view_type!(
518    /// A TxOut
519    TxOut
520);
521
522impl TxOut<'_> {
523    /// Extract the value of the txout, as a u64
524    pub fn value(&self) -> u64 {
525        crate::btcspv::extract_value(self)
526    }
527
528    /// Extract the script pubkey from the TxOut
529    pub fn script_pubkey(&self) -> ScriptPubkey {
530        crate::btcspv::extract_script_pubkey(self)
531    }
532}
533
534impl_view_type!(
535    /// A Vout
536    Vout
537);
538
539impl<'a> Vout<'a> {
540    /// Instantiate a new `Vout` from a slice, if the slice is a valid `Vout`
541    pub fn new(slice: &'a [u8]) -> Result<Vout<'a>, SPVError> {
542        if crate::btcspv::validate_vout(slice) {
543            Ok(Self(slice))
544        } else {
545            Err(SPVError::InvalidVout)
546        }
547    }
548
549    /// Retrieve the txout at the specified index of the vout
550    pub fn index(&self, index: usize) -> Result<TxOut, SPVError> {
551        crate::btcspv::extract_output_at_index(self, index)
552    }
553}