bitcoin_consensus_encoding/decode/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Consensus Decoding Traits
4
5pub mod decoders;
6
7/// A Bitcoin object which can be consensus-decoded using a push decoder.
8///
9/// To decode something, create a [`Self::Decoder`] and push byte slices
10/// into it with [`Decoder::push_bytes`], then call [`Decoder::end`] to get the result.
11pub trait Decodable {
12    /// Associated decoder for the type.
13    type Decoder: Decoder<Output = Self>;
14    /// Constructs a "default decoder" for the type.
15    fn decoder() -> Self::Decoder;
16}
17
18/// A push decoder for a consensus-decodable object.
19pub trait Decoder: Sized {
20    /// The type that this decoder produces when decoding is complete.
21    type Output;
22    /// The error type that this decoder can produce.
23    type Error;
24
25    /// Push bytes into the decoder, consuming as much as possible.
26    ///
27    /// The slice reference will be advanced to point to the unconsumed portion.
28    /// Returns `Ok(true)` if more bytes are needed to complete decoding,
29    /// `Ok(false)` if the decoder is ready to finalize with [`Self::end`],
30    /// or `Err(error)` if parsing failed.
31    ///
32    /// # Errors
33    ///
34    /// Returns an error if the provided bytes are invalid or malformed according
35    /// to the decoder's validation rules. Insufficient data (needing more
36    /// bytes) is *not* an error for this method, the decoder will simply consume
37    /// what it can and return `true` to indicate more data is needed.
38    ///
39    /// # Panics
40    ///
41    /// May panic if called after a previous call to [`Self::push_bytes`] errored.
42    #[must_use = "must check result to avoid panics on subsequent calls"]
43    fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error>;
44
45    /// Complete the decoding process and return the final result.
46    ///
47    /// This consumes the decoder and should be called when no more input
48    /// data is available.
49    ///
50    /// # Errors
51    ///
52    /// Returns an error if the decoder has not received sufficient data to
53    /// complete decoding, or if the accumulated data is invalid when considered
54    /// as a complete object.
55    ///
56    /// # Panics
57    ///
58    /// May panic if called after a previous call to [`Self::push_bytes`] errored.
59    #[must_use = "must check result to avoid panics on subsequent calls"]
60    fn end(self) -> Result<Self::Output, Self::Error>;
61
62    /// Returns the maximum number of bytes this decoder can consume without over-reading.
63    ///
64    /// Returns 0 if the decoder is complete and ready to finalize with [`Self::end`].
65    /// This is used by [`decode_from_read_unbuffered`] to optimize read sizes,
66    /// avoiding both inefficient under-reads and unnecessary over-reads.
67    fn read_limit(&self) -> usize;
68}
69
70/// Decodes an object from a byte slice.
71///
72/// # Errors
73///
74/// Returns an error if the decoder encounters an error while
75/// parsing the data, including insufficient data.
76pub fn decode_from_slice<T>(bytes: &[u8]) -> Result<T, <T::Decoder as Decoder>::Error>
77where
78    T: Decodable,
79{
80    let mut decoder = T::decoder();
81    let mut remaining = bytes;
82
83    while !remaining.is_empty() {
84        if !decoder.push_bytes(&mut remaining)? {
85            break;
86        }
87    }
88
89    decoder.end()
90}
91
92/// Decodes an object from a buffered reader.
93///
94/// # Performance
95///
96/// For unbuffered readers (like [`std::fs::File`] or [`std::net::TcpStream`]),
97/// consider wrapping your reader with [`std::io::BufReader`] in order to use
98/// this function. This avoids frequent small reads, which can significantly
99/// impact performance.
100///
101/// # Errors
102///
103/// Returns [`ReadError::Decode`] if the decoder encounters an error while parsing
104/// the data, or [`ReadError::Io`] if an I/O error occurs while reading.
105#[cfg(feature = "std")]
106pub fn decode_from_read<T, R>(mut reader: R) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
107where
108    T: Decodable,
109    R: std::io::BufRead,
110{
111    let mut decoder = T::decoder();
112
113    loop {
114        let mut buffer = match reader.fill_buf() {
115            Ok(buffer) => buffer,
116            // Auto retry read for non-fatal error.
117            Err(error) if error.kind() == std::io::ErrorKind::Interrupted => continue,
118            Err(error) => return Err(ReadError::Io(error)),
119        };
120
121        if buffer.is_empty() {
122            // EOF, but still try to finalize the decoder.
123            return decoder.end().map_err(ReadError::Decode);
124        }
125
126        let original_len = buffer.len();
127        let need_more = decoder.push_bytes(&mut buffer).map_err(ReadError::Decode)?;
128        let consumed = original_len - buffer.len();
129        reader.consume(consumed);
130
131        if !need_more {
132            return decoder.end().map_err(ReadError::Decode);
133        }
134    }
135}
136
137/// Decodes an object from an unbuffered reader using a fixed-size buffer.
138///
139/// For most use cases, prefer [`decode_from_read`] with a [`std::io::BufReader`].
140/// This function is only needed when you have an unbuffered reader which you
141/// cannot wrap. It will probably have worse performance.
142///
143/// # Buffer
144///
145/// Uses a fixed 4KB (4096 bytes) stack-allocated buffer that is reused across
146/// read operations. This size is a good balance between memory usage and
147/// system call efficiency for most use cases.
148///
149/// For different buffer sizes, use [`decode_from_read_unbuffered_with`].
150///
151/// # Errors
152///
153/// Returns [`ReadError::Decode`] if the decoder encounters an error while parsing
154/// the data, or [`ReadError::Io`] if an I/O error occurs while reading.
155#[cfg(feature = "std")]
156pub fn decode_from_read_unbuffered<T, R>(
157    reader: R,
158) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
159where
160    T: Decodable,
161    R: std::io::Read,
162{
163    decode_from_read_unbuffered_with::<T, R, 4096>(reader)
164}
165
166/// Decodes an object from an unbuffered reader using a custom-sized buffer.
167///
168/// For most use cases, prefer [`decode_from_read`] with a [`std::io::BufReader`].
169/// This function is only needed when you have an unbuffered reader which you
170/// cannot wrap. It will probably have worse performance.
171///
172/// # Buffer
173///
174/// The `BUFFER_SIZE` parameter controls the intermediate buffer size used for
175/// reading. The buffer is allocated on the stack (not heap) and reused across
176/// read operations. Larger buffers reduce the number of system calls, but use
177/// more memory.
178///
179/// # Errors
180///
181/// Returns [`ReadError::Decode`] if the decoder encounters an error while parsing
182/// the data, or [`ReadError::Io`] if an I/O error occurs while reading.
183#[cfg(feature = "std")]
184pub fn decode_from_read_unbuffered_with<T, R, const BUFFER_SIZE: usize>(
185    mut reader: R,
186) -> Result<T, ReadError<<T::Decoder as Decoder>::Error>>
187where
188    T: Decodable,
189    R: std::io::Read,
190{
191    let mut decoder = T::decoder();
192    let mut buffer = [0u8; BUFFER_SIZE];
193
194    while decoder.read_limit() > 0 {
195        // Only read what we need, up to buffer size.
196        let clamped_buffer = &mut buffer[..decoder.read_limit().min(BUFFER_SIZE)];
197        match reader.read(clamped_buffer) {
198            Ok(0) => {
199                // EOF, but still try to finalize the decoder.
200                return decoder.end().map_err(ReadError::Decode);
201            }
202            Ok(bytes_read) => {
203                if !decoder
204                    .push_bytes(&mut &clamped_buffer[..bytes_read])
205                    .map_err(ReadError::Decode)?
206                {
207                    return decoder.end().map_err(ReadError::Decode);
208                }
209            }
210            Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {
211                // Auto retry read for non-fatal error.
212            }
213            Err(e) => return Err(ReadError::Io(e)),
214        }
215    }
216
217    decoder.end().map_err(ReadError::Decode)
218}
219
220/// An error that can occur when reading and decoding from a buffered reader.
221#[cfg(feature = "std")]
222#[derive(Debug)]
223pub enum ReadError<D> {
224    /// An I/O error occurred while reading from the reader.
225    Io(std::io::Error),
226    /// The decoder encountered an error while parsing the data.
227    Decode(D),
228}
229
230#[cfg(feature = "std")]
231impl<D: core::fmt::Display> core::fmt::Display for ReadError<D> {
232    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
233        match self {
234            Self::Io(e) => write!(f, "I/O error: {}", e),
235            Self::Decode(e) => write!(f, "decode error: {}", e),
236        }
237    }
238}
239
240#[cfg(feature = "std")]
241impl<D> std::error::Error for ReadError<D>
242where
243    D: core::fmt::Debug + core::fmt::Display + std::error::Error + 'static,
244{
245    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
246        match self {
247            Self::Io(e) => Some(e),
248            Self::Decode(e) => Some(e),
249        }
250    }
251}
252
253#[cfg(feature = "std")]
254impl<D> From<std::io::Error> for ReadError<D> {
255    fn from(e: std::io::Error) -> Self { Self::Io(e) }
256}
257
258#[cfg(test)]
259mod tests {
260    #[cfg(feature = "std")]
261    use alloc::vec::Vec;
262    #[cfg(feature = "std")]
263    use std::io::{Cursor, Read};
264
265    use super::*;
266    use crate::decode::decoders::{ArrayDecoder, UnexpectedEofError};
267
268    #[derive(Debug, PartialEq)]
269    struct TestArray([u8; 4]);
270
271    impl Decodable for TestArray {
272        type Decoder = TestArrayDecoder;
273        fn decoder() -> Self::Decoder { TestArrayDecoder { inner: ArrayDecoder::new() } }
274    }
275
276    struct TestArrayDecoder {
277        inner: ArrayDecoder<4>,
278    }
279
280    impl Decoder for TestArrayDecoder {
281        type Output = TestArray;
282        type Error = UnexpectedEofError;
283
284        fn push_bytes(&mut self, bytes: &mut &[u8]) -> Result<bool, Self::Error> {
285            self.inner.push_bytes(bytes)
286        }
287
288        fn end(self) -> Result<Self::Output, Self::Error> { self.inner.end().map(TestArray) }
289
290        fn read_limit(&self) -> usize { self.inner.read_limit() }
291    }
292
293    #[test]
294    fn decode_from_slice_success() {
295        let data = [1, 2, 3, 4];
296        let result: Result<TestArray, _> = decode_from_slice(&data);
297        assert!(result.is_ok());
298        let decoded = result.unwrap();
299        assert_eq!(decoded.0, [1, 2, 3, 4]);
300    }
301
302    #[test]
303    fn decode_from_slice_unexpected_eof() {
304        let data = [1, 2, 3];
305        let result: Result<TestArray, _> = decode_from_slice(&data);
306        assert!(result.is_err());
307    }
308
309    #[test]
310    fn decode_from_slice_extra_data() {
311        let data = [1, 2, 3, 4, 5];
312        let result: Result<TestArray, _> = decode_from_slice(&data);
313        assert!(result.is_ok());
314        let decoded = result.unwrap();
315        assert_eq!(decoded.0, [1, 2, 3, 4]);
316    }
317
318    #[cfg(feature = "std")]
319    #[test]
320    fn decode_from_read_extra_data() {
321        let data = [1, 2, 3, 4, 5, 6];
322        let mut cursor = Cursor::new(&data);
323        let result: Result<TestArray, _> = decode_from_read(&mut cursor);
324        assert!(result.is_ok());
325        let decoded = result.unwrap();
326        assert_eq!(decoded.0, [1, 2, 3, 4]);
327    }
328
329    #[cfg(feature = "std")]
330    #[test]
331    fn decode_from_read_success() {
332        let data = [1, 2, 3, 4];
333        let cursor = Cursor::new(&data);
334        let result: Result<TestArray, _> = decode_from_read(cursor);
335        assert!(result.is_ok());
336        let decoded = result.unwrap();
337        assert_eq!(decoded.0, [1, 2, 3, 4]);
338    }
339
340    #[cfg(feature = "std")]
341    #[test]
342    fn decode_from_read_unexpected_eof() {
343        let data = [1, 2, 3];
344        let cursor = Cursor::new(&data);
345        let result: Result<TestArray, _> = decode_from_read(cursor);
346        assert!(matches!(result, Err(ReadError::Decode(_))));
347    }
348
349    #[cfg(feature = "std")]
350    #[test]
351    fn decode_from_read_trait_object() {
352        let data = [1, 2, 3, 4];
353        let mut cursor = Cursor::new(&data);
354        // Test that we can pass a trait object (&mut dyn BufRead implements BufRead).
355        let reader: &mut dyn std::io::BufRead = &mut cursor;
356        let result: Result<TestArray, _> = decode_from_read(reader);
357        assert!(result.is_ok());
358        let decoded = result.unwrap();
359        assert_eq!(decoded.0, [1, 2, 3, 4]);
360    }
361
362    #[cfg(feature = "std")]
363    #[test]
364    fn decode_from_read_by_reference() {
365        let data = [1, 2, 3, 4];
366        let mut cursor = Cursor::new(&data);
367        // Test that we can pass by reference (&mut T implements BufRead when T: BufRead).
368        let result: Result<TestArray, _> = decode_from_read(&mut cursor);
369        assert!(result.is_ok());
370        let decoded = result.unwrap();
371        assert_eq!(decoded.0, [1, 2, 3, 4]);
372
373        let mut buf = Vec::new();
374        let _ = cursor.read_to_end(&mut buf);
375    }
376
377    #[cfg(feature = "std")]
378    #[test]
379    fn decode_from_read_unbuffered_success() {
380        let data = [1, 2, 3, 4];
381        let cursor = Cursor::new(&data);
382        let result: Result<TestArray, _> = decode_from_read_unbuffered(cursor);
383        assert!(result.is_ok());
384        let decoded = result.unwrap();
385        assert_eq!(decoded.0, [1, 2, 3, 4]);
386    }
387
388    #[cfg(feature = "std")]
389    #[test]
390    fn decode_from_read_unbuffered_unexpected_eof() {
391        let data = [1, 2, 3];
392        let cursor = Cursor::new(&data);
393        let result: Result<TestArray, _> = decode_from_read_unbuffered(cursor);
394        assert!(matches!(result, Err(ReadError::Decode(_))));
395    }
396
397    #[cfg(feature = "std")]
398    #[test]
399    fn decode_from_read_unbuffered_empty() {
400        let data = [];
401        let cursor = Cursor::new(&data);
402        let result: Result<TestArray, _> = decode_from_read_unbuffered(cursor);
403        assert!(matches!(result, Err(ReadError::Decode(_))));
404    }
405
406    #[cfg(feature = "std")]
407    #[test]
408    fn decode_from_read_unbuffered_extra_data() {
409        let data = [1, 2, 3, 4, 5, 6];
410        let cursor = Cursor::new(&data);
411        let result: Result<TestArray, _> = decode_from_read_unbuffered(cursor);
412        assert!(result.is_ok());
413        let decoded = result.unwrap();
414        assert_eq!(decoded.0, [1, 2, 3, 4]);
415    }
416}