bitcoin_cash/
tx_preimage.rs1use crate::{
2 encode_bitcoin_code, BitcoinByteArray, BitcoinDataType, ByteArray, DataType, Hashed, Op,
3 Script, Sha256d, ToPreimages, TxOutpoint,
4};
5use bitflags::bitflags;
6use serde_derive::{Deserialize, Serialize};
7
8bitflags! {
9 #[derive(Deserialize, Serialize, Default)]
10 pub struct SigHashFlags: u32 {
11 const ALL = 0x01;
12 const NONE = 0x02;
13 const SINGLE = 0x03;
14 const FORKID = 0x40;
15 const ANYONECANPAY = 0x80;
16 const MASK = 0x1f;
17 const DEFAULT = Self::ALL.bits | Self::FORKID.bits;
18 }
19}
20
21#[derive(Clone, Debug, Default)]
22pub struct TxPreimage {
23 pub version: i32,
24 pub hash_prevouts: Sha256d,
25 pub hash_sequence: Sha256d,
26 pub outpoint: TxOutpoint,
27 pub script_code: ByteArray,
28 pub value: u64,
29 pub sequence: u32,
30 pub hash_outputs: Sha256d,
31 pub lock_time: u32,
32 pub sig_hash_type: u32,
33}
34
35impl SigHashFlags {
36 pub fn from_u8(flags: u8) -> Self {
37 let mut sig_hash_flags = Self::DEFAULT;
38 sig_hash_flags.bits = flags as u32;
39 sig_hash_flags
40 }
41}
42
43impl TxPreimage {
44 pub fn build_preimages(tx: &impl ToPreimages) -> Vec<Vec<TxPreimage>> {
45 let hash_all_prevouts = {
46 let mut outpoints_serialized = ByteArray::from_slice_unnamed(&[]);
47 for input_idx in 0..tx.num_inputs() {
48 outpoints_serialized = outpoints_serialized.concat(ByteArray::new(
49 format!("outpoint_{}", input_idx),
50 encode_bitcoin_code(tx.input_outpoint_at(input_idx))
51 .expect("Cannot encode outpoint"),
52 ));
53 }
54 Sha256d::digest(outpoints_serialized.named("prevouts")).named("hashPrevouts")
55 };
56 let hash_all_sequences = {
57 let mut sequences_serialized = ByteArray::from_slice_unnamed(&[]);
58 for input_idx in 0..tx.num_inputs() {
59 sequences_serialized = sequences_serialized.concat(ByteArray::new(
60 format!("sequence_{}", input_idx),
61 encode_bitcoin_code(&tx.input_sequence_at(input_idx))
62 .expect("Cannot encode sequence"),
63 ));
64 }
65 Sha256d::digest(sequences_serialized.named("sequences")).named("hashSequence")
66 };
67
68 let hash_all_outputs = {
69 let mut outputs_serialized = ByteArray::from_slice_unnamed(&[]);
70 for output_idx in 0..tx.num_outputs() {
71 let byte_array = tx
72 .output_at(output_idx)
73 .serialize()
74 .expect("Cannot encode output")
75 .named(format!("output_{}", output_idx));
76 outputs_serialized = outputs_serialized.concat(byte_array);
77 }
78 Sha256d::digest(outputs_serialized.named("outputs")).named("hashOutputs")
79 };
80 let mut inputs_preimages = Vec::with_capacity(tx.num_inputs());
81 for input_idx in 0..tx.num_inputs() {
82 let sig_hash_flags = tx.input_sig_hash_flags_at(input_idx);
83 let mut preimages = Vec::with_capacity(sig_hash_flags.len());
84 for &sig_hash_flags in sig_hash_flags {
85 let hash_prevouts = if !sig_hash_flags.contains(SigHashFlags::ANYONECANPAY) {
86 hash_all_prevouts.clone()
87 } else {
88 Sha256d::new([0; 32]).named("hashPrevouts")
89 };
90 let masked_flags = sig_hash_flags & SigHashFlags::MASK;
91 let hash_sequence = if !sig_hash_flags.contains(SigHashFlags::ANYONECANPAY)
92 && masked_flags != SigHashFlags::SINGLE
93 && masked_flags != SigHashFlags::NONE
94 {
95 hash_all_sequences.clone()
96 } else {
97 Sha256d::new([0; 32]).named("hashSequence")
98 };
99 let hash_outputs =
100 if masked_flags != SigHashFlags::SINGLE && masked_flags != SigHashFlags::NONE {
101 hash_all_outputs.clone()
102 } else if masked_flags == SigHashFlags::SINGLE && input_idx < tx.num_outputs() {
103 Sha256d::digest(
104 tx.output_at(input_idx)
105 .serialize()
106 .expect("Cannot encode output"),
107 )
108 } else {
109 Sha256d::new([0; 32]).named("hashOutputs")
110 };
111 preimages.push(TxPreimage {
112 version: tx.version(),
113 hash_prevouts,
114 hash_sequence,
115 outpoint: tx.input_outpoint_at(input_idx).clone(),
116 script_code: encode_bitcoin_code(
117 &tx.input_lock_script_at(input_idx).to_script_code_first(),
118 )
119 .unwrap()
120 .into(),
121 value: tx.input_value_at(input_idx),
122 sequence: tx.input_sequence_at(input_idx),
123 hash_outputs,
124 lock_time: tx.lock_time(),
125 sig_hash_type: sig_hash_flags.bits(),
126 });
127 }
128 inputs_preimages.push(preimages);
129 }
130 inputs_preimages
131 }
132
133 pub fn size_with_script(script_code: &Script) -> usize {
134 struct TxPreimageWithoutScript {
135 _version: i32,
136 _hash_prevouts: Sha256d,
137 _hash_sequence: Sha256d,
138 _outpoint: TxOutpoint,
139 _value: u64,
140 _sequence: u32,
141 _hash_outputs: Sha256d,
142 _lock_time: u32,
143 _sighash_flags: u32,
144 }
145 #[derive(Serialize)]
146 struct TxPreimageOnlyScript<'a> {
147 script_code: &'a Script,
148 }
149 let script_size = encode_bitcoin_code(&TxPreimageOnlyScript { script_code })
150 .expect("Couldn't encode script")
151 .len();
152 let rest_size = std::mem::size_of::<TxPreimageWithoutScript>();
153 script_size + rest_size
154 }
155
156 pub fn empty_with_script(script_code: &Script) -> TxPreimage {
157 TxPreimage {
158 version: 0,
159 hash_prevouts: Sha256d::new([0; 32]).named("hashPrevouts"),
160 hash_sequence: Sha256d::new([0; 32]).named("hashSequence"),
161 outpoint: TxOutpoint {
162 tx_hash: Sha256d::new([0; 32]),
163 vout: 0,
164 },
165 script_code: script_code.serialize().expect("Cannot encode script_code"),
166 value: 0,
167 sequence: 0,
168 hash_outputs: Sha256d::new([0; 32]).named("hashOutputs"),
169 lock_time: 0,
170 sig_hash_type: SigHashFlags::ALL.bits(),
171 }
172 }
173
174 pub fn to_byte_array(&self) -> ByteArray {
175 ByteArray::new("nVersion", self.version.to_le_bytes().to_vec())
176 .concat(self.hash_prevouts.as_byte_array().clone())
177 .concat(self.hash_sequence.as_byte_array().clone())
178 .concat(ByteArray::new(
179 "scriptCode",
180 encode_bitcoin_code(&self.outpoint).unwrap(),
181 ))
182 .concat(self.script_code.clone())
183 .concat(ByteArray::new("value", self.value.to_le_bytes().to_vec()))
184 .concat(ByteArray::new(
185 "nSequence",
186 self.sequence.to_le_bytes().to_vec(),
187 ))
188 .concat(self.hash_outputs.as_byte_array().clone())
189 .concat(ByteArray::new(
190 "nLocktime",
191 self.lock_time.to_le_bytes().to_vec(),
192 ))
193 .concat(ByteArray::new(
194 "sighash",
195 self.sig_hash_type.to_le_bytes().to_vec(),
196 ))
197 }
198}
199
200impl BitcoinDataType for TxPreimage {
201 type Type = BitcoinByteArray;
202 fn to_data(&self) -> Self::Type {
203 BitcoinByteArray(self.to_byte_array())
204 }
205 fn to_pushop(&self) -> Op {
206 self.to_byte_array().into()
207 }
208 fn to_data_type(&self) -> DataType {
209 DataType::ByteArray(None)
210 }
211}