Skip to main content

bitcoin_primitives/
lib.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Rust Bitcoin - primitive types
4//!
5//! Primitive data types that are used throughout the [`rust-bitcoin`] ecosystem.
6//!
7//! If you are using `rust-bitcoin` then you do not need to access this crate directly. Everything
8//! here is re-exported in `rust-bitcoin` at the same path.
9//!
10//! This crate can be used in a no-std environment but a lot of the functionality requires an
11//! allocator i.e., requires the `alloc` feature to be enabled.
12//!
13//! [`rust-bitcoin`]: <https://github.com/rust-bitcoin/rust-bitcoin>
14
15#![no_std]
16// Coding conventions.
17#![warn(missing_docs)]
18#![warn(deprecated_in_future)]
19#![doc(test(attr(warn(unused))))]
20// Package-specific lint overrides.
21
22#[cfg(feature = "alloc")]
23extern crate alloc;
24
25#[cfg(feature = "std")]
26extern crate std;
27
28#[cfg(feature = "serde")]
29#[macro_use]
30extern crate serde;
31
32#[cfg(feature = "hex")]
33pub extern crate hex_stable as hex;
34
35#[doc(hidden)]
36pub mod _export {
37    /// A re-export of `core::*`.
38    pub mod _core {
39        pub use core::*;
40    }
41}
42
43mod hash_types;
44#[cfg(feature = "alloc")]
45mod opcodes;
46
47pub mod block;
48pub mod merkle_tree;
49#[cfg(feature = "alloc")]
50pub mod script;
51pub mod transaction;
52#[cfg(feature = "alloc")]
53pub mod witness;
54
55#[doc(inline)]
56pub use units::{
57    amount::{self, Amount, SignedAmount},
58    block::{BlockHeight, BlockHeightInterval, BlockMtp, BlockMtpInterval},
59    fee_rate::{self, FeeRate},
60    locktime::{self, absolute, relative},
61    parse_int,
62    pow::{self, CompactTarget},
63    result::{self, NumOpResult},
64    sequence::{self, Sequence},
65    time::{self, BlockTime},
66    weight::{self, Weight},
67};
68
69#[deprecated(since = "1.0.0-rc.0", note = "use `BlockHeightInterval` instead")]
70#[doc(hidden)]
71pub type BlockInterval = BlockHeightInterval;
72
73#[doc(inline)]
74#[cfg(feature = "alloc")]
75pub use self::{
76    block::{
77        Block, Checked as BlockChecked, Unchecked as BlockUnchecked, Validation as BlockValidation,
78    },
79    script::{
80        RedeemScript, RedeemScriptBuf, ScriptPubKey, ScriptPubKeyBuf, ScriptSig, ScriptSigBuf,
81        TapScript, TapScriptBuf, WitnessScript, WitnessScriptBuf,
82    },
83    transaction::{Transaction, TxIn, TxOut},
84    witness::Witness,
85};
86#[doc(inline)]
87pub use self::{
88    block::{BlockHash, Header as BlockHeader, Version as BlockVersion, WitnessCommitment},
89    merkle_tree::{TxMerkleNode, WitnessMerkleNode},
90    transaction::{Ntxid, OutPoint, Txid, Version as TransactionVersion, Wtxid},
91};
92
93#[rustfmt::skip]
94#[allow(unused_imports)]
95mod prelude {
96    #[cfg(feature = "alloc")]
97    pub use alloc::collections::{BTreeMap, BTreeSet, btree_map, BinaryHeap};
98
99    #[cfg(feature = "alloc")]
100    pub use alloc::{string::{String, ToString}, vec::Vec, boxed::Box, borrow::{Borrow, BorrowMut, Cow, ToOwned}, slice, rc};
101
102    #[cfg(all(feature = "alloc", target_has_atomic = "ptr"))]
103    pub use alloc::sync;
104}
105
106#[cfg(feature = "alloc")]
107use encoding::Encoder;
108#[cfg(feature = "alloc")]
109use internals::array_vec::ArrayVec;
110
111// Encode a compact size to a slice without allocating
112#[cfg(feature = "alloc")]
113pub(crate) fn compact_size_encode(value: usize) -> ArrayVec<u8, 9> {
114    let encoder = encoding::CompactSizeEncoder::new(value);
115    ArrayVec::from_slice(encoder.current_chunk())
116}
117
118#[cfg(all(feature = "hex", feature = "alloc"))]
119use core::{convert, fmt};
120
121#[cfg(all(feature = "hex", feature = "alloc"))]
122use encoding::{Decodable, Decoder};
123#[cfg(all(feature = "hex", feature = "alloc"))]
124use internals::write_err;
125
126/// An error type for errors that can occur during parsing of a `Decodable` type from hex.
127#[cfg(all(feature = "hex", feature = "alloc"))]
128enum ParsePrimitiveError<T: Decodable> {
129    /// Tried to decode an odd length string
130    OddLengthString(hex::error::OddLengthStringError),
131    /// Encountered an invalid hex character
132    InvalidChar(hex::error::InvalidCharError),
133    /// A decode error from `consensus_encoding`
134    Decode(<T::Decoder as Decoder>::Error),
135}
136
137#[cfg(all(feature = "hex", feature = "alloc"))]
138impl<T: Decodable> fmt::Debug for ParsePrimitiveError<T> {
139    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
140        match self {
141            Self::OddLengthString(ref e) => write_err!(f, "odd length string"; e),
142            Self::InvalidChar(ref e) => write_err!(f, "invalid character"; e),
143            // Decoder error types don't have Debug, so we only provide this generic error
144            Self::Decode(_) =>
145                write!(f, "failure decoding hex string into {}", core::any::type_name::<T>()),
146        }
147    }
148}
149
150#[cfg(all(feature = "hex", feature = "alloc"))]
151impl<T: Decodable> fmt::Display for ParsePrimitiveError<T> {
152    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(&self, f) }
153}
154
155#[cfg(all(feature = "hex", feature = "alloc"))]
156impl<T: Decodable> From<hex::DecodeVariableLengthBytesError> for ParsePrimitiveError<T> {
157    fn from(dec_err: hex::DecodeVariableLengthBytesError) -> Self {
158        use hex::DecodeVariableLengthBytesError as D;
159
160        match dec_err {
161            D::InvalidChar(err) => Self::InvalidChar(err),
162            D::OddLengthString(err) => Self::OddLengthString(err),
163        }
164    }
165}
166
167#[cfg(all(feature = "hex", feature = "alloc"))]
168impl<T: Decodable> From<convert::Infallible> for ParsePrimitiveError<T> {
169    fn from(never: convert::Infallible) -> Self { match never {} }
170}
171
172#[cfg(all(feature = "hex", feature = "alloc", feature = "std"))]
173impl<T: Decodable> std::error::Error for ParsePrimitiveError<T> {
174    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
175        match self {
176            Self::OddLengthString(ref e) => Some(e),
177            Self::InvalidChar(ref e) => Some(e),
178            Self::Decode(_) => None,
179        }
180    }
181}
182
183#[cfg(all(feature = "hex", feature = "alloc"))]
184pub(crate) mod hex_codec {
185    use encoding::{Encodable, EncodableByteIter};
186    use hex_unstable::{BytesToHexIter, Case};
187
188    use super::{fmt, Decodable, ParsePrimitiveError};
189
190    /// Writes an Encodable object to the given formatter in the requested case.
191    #[inline]
192    fn hex_write_with_case<T: Encodable + Decodable>(
193        obj: &HexPrimitive<T>,
194        f: &mut fmt::Formatter,
195        case: Case,
196    ) -> fmt::Result {
197        let iter = BytesToHexIter::new(encoding::EncodableByteIter::new(obj.0), case);
198        let collection = iter.collect::<alloc::string::String>();
199        f.pad(&collection)
200    }
201
202    /// Hex encoding wrapper type for Encodable + Decodable types.
203    ///
204    /// Provides default implementations for `Display`, `Debug`, `LowerHex`, and `UpperHex`.
205    /// Also provides [`Self::from_str`] for parsing a string to a `T`.
206    /// This can be used to implement hex display traits for any encodable types.
207    pub(crate) struct HexPrimitive<'a, T: Encodable + Decodable>(pub &'a T);
208
209    impl<'a, T: Encodable + Decodable> IntoIterator for &HexPrimitive<'a, T> {
210        type Item = u8;
211        type IntoIter = EncodableByteIter<'a, T>;
212
213        fn into_iter(self) -> Self::IntoIter { EncodableByteIter::new(self.0) }
214    }
215
216    impl<T: Encodable + Decodable> HexPrimitive<'_, T> {
217        /// Parses a given string into an instance of the type `T`.
218        ///
219        /// Since `FromStr` would return an instance of Self and thus a &T, this function
220        /// is implemented directly on the struct to return the owned instance of T.
221        /// Other `FromStr` implementations can directly return the result of
222        /// [`HexPrimitive::from_str`].
223        ///
224        /// # Errors
225        ///
226        /// [`ParsePrimitiveError::OddLengthString`] if the input string is an odd length.
227        /// [`ParsePrimitiveError::Decode`] if an error occurs during decoding of the object.
228        pub(crate) fn from_str(s: &str) -> Result<T, ParsePrimitiveError<T>> {
229            let bytes = hex::decode_to_vec(s).map_err(ParsePrimitiveError::from)?;
230
231            encoding::decode_from_slice(&bytes).map_err(ParsePrimitiveError::Decode)
232        }
233    }
234
235    impl<T: Encodable + Decodable> fmt::Display for HexPrimitive<'_, T> {
236        #[inline]
237        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
238    }
239
240    impl<T: Encodable + Decodable> fmt::Debug for HexPrimitive<'_, T> {
241        #[inline]
242        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
243    }
244
245    impl<T: Encodable + Decodable> fmt::LowerHex for HexPrimitive<'_, T> {
246        #[inline]
247        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
248            hex_write_with_case(self, f, Case::Lower)
249        }
250    }
251
252    impl<T: Encodable + Decodable> fmt::UpperHex for HexPrimitive<'_, T> {
253        #[inline]
254        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
255            hex_write_with_case(self, f, Case::Upper)
256        }
257    }
258}
259
260#[cfg(test)]
261mod tests {
262    #[cfg(feature = "alloc")]
263    use alloc::{format, string::ToString};
264
265    #[cfg(feature = "alloc")]
266    use super::*;
267
268    #[test]
269    #[cfg(all(feature = "alloc", feature = "hex"))]
270    fn parse_primitive_error_display() {
271        let odd: ParsePrimitiveError<block::Header> =
272            hex_codec::HexPrimitive::from_str("0").unwrap_err();
273        let invalid: ParsePrimitiveError<block::Header> =
274            hex_codec::HexPrimitive::from_str("zz").unwrap_err();
275        let decode: ParsePrimitiveError<block::Header> =
276            hex_codec::HexPrimitive::from_str("00").unwrap_err();
277
278        assert!(!odd.to_string().is_empty());
279        assert!(!invalid.to_string().is_empty());
280        assert!(!decode.to_string().is_empty());
281    }
282
283    #[test]
284    #[cfg(all(feature = "hex", feature = "std"))]
285    fn parse_primitive_error_source() {
286        use std::error::Error as _;
287
288        let odd: ParsePrimitiveError<block::Header> =
289            hex_codec::HexPrimitive::from_str("0").unwrap_err();
290        let invalid: ParsePrimitiveError<block::Header> =
291            hex_codec::HexPrimitive::from_str("zz").unwrap_err();
292        let decode: ParsePrimitiveError<block::Header> =
293            hex_codec::HexPrimitive::from_str("00").unwrap_err();
294
295        assert!(odd.source().is_some());
296        assert!(invalid.source().is_some());
297        assert!(decode.source().is_none());
298    }
299
300    #[test]
301    #[cfg(all(feature = "alloc", feature = "hex"))]
302    fn hex_primitive_iter_and_debug() {
303        let header: block::Header =
304            encoding::decode_from_slice(&[0u8; block::Header::SIZE]).expect("valid header");
305        let hex = hex_codec::HexPrimitive(&header);
306
307        assert_eq!((&hex).into_iter().next(), Some(0u8));
308        assert!(!format!("{hex:?}").is_empty());
309    }
310}