bitcoin_cash/
tx.rs

1use crate::{
2    encode_bitcoin_code, encoding_utils, error::Result, ByteArray, Hashed, Script, Sha256d,
3    SigHashFlags, ToPreimages, TxPreimage,
4};
5use serde_derive::{Deserialize, Serialize};
6
7pub const DEFAULT_SEQUENCE: u32 = 0xffff_ffff;
8pub const MAX_SIGNATURE_SIZE: usize = 73; // explained https://bitcoin.stackexchange.com/a/77192
9
10#[derive(Deserialize, Serialize, PartialEq, Debug, Clone, Default)]
11pub struct TxOutpoint {
12    pub tx_hash: Sha256d,
13    pub vout: u32,
14}
15
16#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
17pub struct TxInput {
18    pub prev_out: TxOutpoint,
19    pub script: Script,
20    pub sequence: u32,
21
22    #[serde(skip)]
23    pub lock_script: Option<Script>,
24
25    #[serde(skip)]
26    pub value: Option<u64>,
27
28    #[serde(skip)]
29    pub is_p2sh: Option<bool>,
30}
31
32#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
33pub struct TxOutput {
34    pub value: u64,
35    pub script: Script,
36}
37
38#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
39pub struct UnhashedTx {
40    pub version: i32,
41    pub inputs: Vec<TxInput>,
42    pub outputs: Vec<TxOutput>,
43    pub lock_time: u32,
44}
45
46#[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
47pub struct Tx {
48    #[serde(skip)]
49    unhashed_tx: UnhashedTx,
50
51    #[serde(skip)]
52    hash: Sha256d,
53
54    raw: ByteArray,
55}
56
57impl TxInput {
58    pub fn serialize(&self) -> Result<ByteArray> {
59        let vout = ByteArray::new("vout", encode_bitcoin_code(&self.prev_out.vout)?);
60        let sequence = ByteArray::new("sequence", encode_bitcoin_code(&self.sequence)?);
61        let script = self.script.serialize()?.named("script");
62        let mut script_len_ser = Vec::new();
63        encoding_utils::write_var_int(&mut script_len_ser, script.len() as u64)?;
64        let script_len = ByteArray::new("script_len", script_len_ser);
65        Ok(self
66            .prev_out
67            .tx_hash
68            .clone()
69            .concat(vout)
70            .concat(script_len)
71            .concat(script)
72            .concat(sequence))
73    }
74}
75
76impl TxOutput {
77    pub fn serialize(&self) -> Result<ByteArray> {
78        let value = ByteArray::new("value", encode_bitcoin_code(&self.value)?);
79        let script = self.script.serialize()?.named("script");
80        let mut script_len_ser = Vec::new();
81        encoding_utils::write_var_int(&mut script_len_ser, script.len() as u64)?;
82        let script_len = ByteArray::new("script_len", script_len_ser);
83        Ok(value.concat(script_len).concat(script))
84    }
85}
86
87impl UnhashedTx {
88    pub fn preimages(&self, sig_hash_flags: &[SigHashFlags]) -> Vec<Vec<TxPreimage>> {
89        TxPreimage::build_preimages(&SigTxPreimage {
90            tx: self,
91            sig_hash_flags,
92        })
93    }
94
95    pub fn serialize(&self) -> Result<ByteArray> {
96        let version = ByteArray::new("version", encode_bitcoin_code(&self.version)?);
97        let lock_time = ByteArray::new("lock_time", encode_bitcoin_code(&self.version)?);
98
99        let mut inputs_len_ser = Vec::new();
100        encoding_utils::write_var_int(&mut inputs_len_ser, self.inputs.len() as u64)?;
101        let inputs_len = ByteArray::new("inputs_len", inputs_len_ser);
102
103        let mut outputs_len_ser = Vec::new();
104        encoding_utils::write_var_int(&mut outputs_len_ser, self.outputs.len() as u64)?;
105        let outputs_len = ByteArray::new("outputs_len", outputs_len_ser);
106
107        let mut byte_array = version.concat(inputs_len);
108        for input in self.inputs.iter() {
109            byte_array = byte_array.concat(input.serialize()?);
110        }
111
112        byte_array = byte_array.concat(outputs_len);
113        for output in self.outputs.iter() {
114            byte_array = byte_array.concat(output.serialize()?);
115        }
116
117        Ok(byte_array.concat(lock_time))
118    }
119
120    pub fn hashed(self) -> Tx {
121        let raw = self.serialize().expect("Couldn't encode UnhashedTx");
122        let hash = Sha256d::digest(raw.clone());
123        Tx {
124            unhashed_tx: self,
125            raw,
126            hash,
127        }
128    }
129}
130
131impl Tx {
132    pub fn hash(&self) -> &Sha256d {
133        &self.hash
134    }
135
136    pub fn raw(&self) -> &ByteArray {
137        &self.raw
138    }
139
140    pub fn version(&self) -> i32 {
141        self.unhashed_tx.version
142    }
143
144    pub fn inputs(&self) -> &[TxInput] {
145        &self.unhashed_tx.inputs
146    }
147
148    pub fn outputs(&self) -> &[TxOutput] {
149        &self.unhashed_tx.outputs
150    }
151
152    pub fn lock_time(&self) -> u32 {
153        self.unhashed_tx.lock_time
154    }
155
156    pub fn preimages(&self, sig_hash_flags: &[SigHashFlags]) -> Vec<Vec<TxPreimage>> {
157        self.unhashed_tx.preimages(sig_hash_flags)
158    }
159}
160
161impl Default for UnhashedTx {
162    fn default() -> Self {
163        UnhashedTx {
164            version: 1,
165            inputs: vec![],
166            outputs: vec![],
167            lock_time: 0,
168        }
169    }
170}
171
172struct SigTxPreimage<'b> {
173    tx: &'b UnhashedTx,
174    sig_hash_flags: &'b [SigHashFlags],
175}
176
177impl ToPreimages for SigTxPreimage<'_> {
178    fn version(&self) -> i32 {
179        self.tx.version
180    }
181    fn num_inputs(&self) -> usize {
182        self.tx.inputs.len()
183    }
184    fn input_outpoint_at(&self, input_idx: usize) -> &TxOutpoint {
185        &self.tx.inputs[input_idx].prev_out
186    }
187    fn input_sequence_at(&self, input_idx: usize) -> u32 {
188        self.tx.inputs[input_idx].sequence
189    }
190    fn input_sig_hash_flags_at(&self, _input_idx: usize) -> &[SigHashFlags] {
191        &self.sig_hash_flags
192    }
193    fn input_value_at(&self, input_idx: usize) -> u64 {
194        self.tx.inputs[input_idx]
195            .value
196            .expect("No known value for input")
197    }
198    fn input_lock_script_at(&self, input_idx: usize) -> Script {
199        self.tx.inputs[input_idx]
200            .lock_script
201            .clone()
202            .expect("No known lock_script for input")
203    }
204    fn num_outputs(&self) -> usize {
205        self.tx.outputs.len()
206    }
207    fn output_at(&self, output_idx: usize) -> &TxOutput {
208        &self.tx.outputs[output_idx]
209    }
210    fn lock_time(&self) -> u32 {
211        self.tx.lock_time
212    }
213}