cashweb_bitcoin/transaction/
input.rs

1//! This module contains the [`Input`] struct which represents a Bitcoin transaction input.
2//! It enjoys [`Encodable`] and [`Decodable`].
3
4use bytes::{Buf, BufMut};
5use thiserror::Error;
6
7use super::{
8    outpoint::{DecodeError as OutpointDecodeError, Outpoint},
9    script::Script,
10};
11use crate::{
12    var_int::{DecodeError as VarIntDecodeError, VarInt},
13    Decodable, Encodable,
14};
15
16/// Error associated with [`Input`] deserialization.
17#[derive(Clone, Debug, PartialEq, Eq, Error)]
18pub enum DecodeError {
19    /// Failed to decode [`Outpoint`].
20    #[error("outpoint: {0}")]
21    Outpoint(OutpointDecodeError),
22    /// Failed to decode script length [`VarInt`].
23    #[error("script length: {0}")]
24    ScriptLen(VarIntDecodeError),
25    /// Exhausted buffer when decoding `script` field.
26    #[error("script too short")]
27    ScriptTooShort,
28    /// Exhausted buffer when decoding `sequence` field.
29    #[error("sequence number too short")]
30    SequenceTooShort,
31}
32
33/// Represents an input.
34#[derive(Clone, Debug, Default, PartialEq, Eq)]
35#[allow(missing_docs)]
36pub struct Input {
37    pub outpoint: Outpoint,
38    pub script: Script,
39    pub sequence: u32,
40}
41
42impl Encodable for Input {
43    #[inline]
44    fn encoded_len(&self) -> usize {
45        self.outpoint.encoded_len()
46            + self.script.len_varint().encoded_len()
47            + self.script.encoded_len()
48            + 4
49    }
50
51    #[inline]
52    fn encode_raw<B: BufMut>(&self, buf: &mut B) {
53        self.outpoint.encode_raw(buf);
54        self.script.len_varint().encode_raw(buf);
55        self.script.encode_raw(buf);
56        buf.put_u32_le(self.sequence);
57    }
58}
59
60impl Decodable for Input {
61    type Error = DecodeError;
62
63    #[inline]
64    fn decode<B: Buf>(mut buf: &mut B) -> Result<Self, Self::Error> {
65        // Parse outpoint
66        let outpoint = Outpoint::decode(&mut buf).map_err(Self::Error::Outpoint)?;
67
68        // Parse script
69        let script_len: u64 = VarInt::decode(&mut buf)
70            .map_err(Self::Error::ScriptLen)?
71            .into();
72        let script_len = script_len as usize;
73        if buf.remaining() < script_len {
74            return Err(Self::Error::ScriptTooShort);
75        }
76        let mut raw_script = vec![0; script_len];
77        buf.copy_to_slice(&mut raw_script);
78        let script = raw_script.into();
79
80        // Parse sequence number
81        if buf.remaining() < 4 {
82            return Err(Self::Error::SequenceTooShort);
83        }
84        let sequence = buf.get_u32_le();
85
86        Ok(Input {
87            outpoint,
88            script,
89            sequence,
90        })
91    }
92}