cashweb_bitcoin/transaction/
output.rs

1//! This module contains the [`Output`] struct which represents a Bitcoin transaction output.
2//! It enjoys [`Encodable`] and [`Decodable`].
3
4use bytes::{Buf, BufMut};
5use thiserror::Error;
6
7use super::script::Script;
8use crate::{
9    var_int::{DecodeError as VarIntDecodeError, VarInt},
10    Decodable, Encodable,
11};
12
13/// Error associated with [`Output`] deserialization.
14#[derive(Clone, Debug, PartialEq, Eq, Error)]
15pub enum DecodeError {
16    /// Value is too short.
17    #[error("value too short")]
18    ValueTooShort,
19    /// Unable to decode the script length variable-length integer.
20    #[error("script length: {0}")]
21    ScriptLen(VarIntDecodeError),
22    /// Script is too short.
23    #[error("script too short")]
24    ScriptTooShort,
25}
26
27/// Represents an output.
28#[derive(Clone, Debug, Default, PartialEq, Eq)]
29#[allow(missing_docs)]
30pub struct Output {
31    pub value: u64,
32    pub script: Script,
33}
34
35impl Encodable for Output {
36    #[inline]
37    fn encoded_len(&self) -> usize {
38        8 + self.script.len_varint().encoded_len() + self.script.encoded_len()
39    }
40
41    #[inline]
42    fn encode_raw<B: BufMut>(&self, buf: &mut B) {
43        buf.put_u64_le(self.value);
44        self.script.len_varint().encode_raw(buf);
45        self.script.encode_raw(buf);
46    }
47}
48
49impl Decodable for Output {
50    type Error = DecodeError;
51
52    #[inline]
53    fn decode<B: Buf>(buf: &mut B) -> Result<Self, Self::Error> {
54        // Get value
55        if buf.remaining() < 8 {
56            return Err(Self::Error::ValueTooShort);
57        }
58        let value = buf.get_u64_le();
59
60        // Get script
61        let script_len: u64 = VarInt::decode(buf).map_err(Self::Error::ScriptLen)?.into();
62        let script_len = script_len as usize;
63        if buf.remaining() < script_len {
64            return Err(Self::Error::ScriptTooShort);
65        }
66        let mut raw_script = vec![0; script_len];
67        buf.copy_to_slice(&mut raw_script);
68        let script = raw_script.into();
69        Ok(Output { value, script })
70    }
71}