1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
2use linked_hash_map::LinkedHashMap;
3use messages::message::Payload;
4use messages::{OutPoint, TxIn, TxOut, COINBASE_OUTPOINT_HASH, COINBASE_OUTPOINT_INDEX};
5use script::{op_codes, Script, TransactionChecker};
6use std::fmt;
7use std::io;
8use std::io::{Read, Write};
9use transaction::sighash::SigHashCache;
10use util::{sha256d, var_int, Error, Hash256, Result, Serializable};
11
12pub const MAX_SATOSHIS: i64 = 21_000_000 * 100_000_000;
14
15#[derive(Default, PartialEq, Eq, Hash, Clone)]
17pub struct Tx {
18 pub version: u32,
20 pub inputs: Vec<TxIn>,
22 pub outputs: Vec<TxOut>,
24 pub lock_time: u32,
26}
27
28impl Tx {
29 pub fn hash(&self) -> Hash256 {
31 let mut b = Vec::with_capacity(self.size());
32 self.write(&mut b).unwrap();
33 sha256d(&b)
34 }
35
36 pub fn validate(
38 &self,
39 require_sighash_forkid: bool,
40 utxos: &LinkedHashMap<OutPoint, TxOut>,
41 ) -> Result<()> {
42 if self.inputs.len() == 0 {
44 return Err(Error::BadData("inputs empty".to_string()));
45 }
46 if self.outputs.len() == 0 {
47 return Err(Error::BadData("outputs empty".to_string()));
48 }
49
50 let mut total_out = 0;
52 for tx_out in self.outputs.iter() {
53 if tx_out.amount.0 < 0 {
54 return Err(Error::BadData("tx_out amount negative".to_string()));
55 }
56 total_out += tx_out.amount.0;
57 }
58 if total_out > MAX_SATOSHIS {
59 return Err(Error::BadData("Total out exceeds max satoshis".to_string()));
60 }
61
62 for tx_in in self.inputs.iter() {
64 if tx_in.prev_output.hash == COINBASE_OUTPOINT_HASH
65 && tx_in.prev_output.index == COINBASE_OUTPOINT_INDEX
66 {
67 return Err(Error::BadData("Unexpected coinbase".to_string()));
68 }
69 }
70
71 if self.lock_time > 2_147_483_647 {
73 return Err(Error::BadData("Lock time too large".to_string()));
74 }
75
76 let mut total_in = 0;
78 for tx_in in self.inputs.iter() {
79 let utxo = utxos.get(&tx_in.prev_output);
80 if let Some(tx_out) = utxo {
81 if tx_out.amount.0 < 0 {
82 return Err(Error::BadData("tx_out amount negative".to_string()));
83 }
84 total_in += tx_out.amount.0;
85 } else {
86 return Err(Error::BadData("utxo not found".to_string()));
87 }
88 }
89 if total_in > MAX_SATOSHIS {
90 return Err(Error::BadData("Total in exceeds max satoshis".to_string()));
91 }
92
93 if total_in < total_out {
95 return Err(Error::BadData("Output total exceeds input".to_string()));
96 }
97
98 let mut sighash_cache = SigHashCache::new();
100 for input in 0..self.inputs.len() {
101 let tx_in = &self.inputs[input];
102 let tx_out = utxos.get(&tx_in.prev_output).unwrap();
103
104 let mut script = Script::new();
105 script.append_slice(&tx_in.sig_script.0);
106 script.append(op_codes::OP_CODESEPARATOR);
107 script.append_slice(&tx_out.pk_script.0);
108
109 let mut tx_checker = TransactionChecker {
110 tx: self,
111 sig_hash_cache: &mut sighash_cache,
112 input: input,
113 amount: tx_out.amount,
114 require_sighash_forkid,
115 };
116
117 script.eval(&mut tx_checker)?;
118 }
119
120 Ok(())
121 }
122
123 pub fn coinbase(&self) -> bool {
125 return self.inputs.len() == 1
126 && self.inputs[0].prev_output.hash == COINBASE_OUTPOINT_HASH
127 && self.inputs[0].prev_output.index == COINBASE_OUTPOINT_INDEX;
128 }
129}
130
131impl Serializable<Tx> for Tx {
132 fn read(reader: &mut dyn Read) -> Result<Tx> {
133 let version = reader.read_i32::<LittleEndian>()?;
134 let version = version as u32;
135 let n_inputs = var_int::read(reader)?;
136 let mut inputs = Vec::with_capacity(n_inputs as usize);
137 for _i in 0..n_inputs {
138 inputs.push(TxIn::read(reader)?);
139 }
140 let n_outputs = var_int::read(reader)?;
141 let mut outputs = Vec::with_capacity(n_outputs as usize);
142 for _i in 0..n_outputs {
143 outputs.push(TxOut::read(reader)?);
144 }
145 let lock_time = reader.read_u32::<LittleEndian>()?;
146 Ok(Tx {
147 version,
148 inputs,
149 outputs,
150 lock_time,
151 })
152 }
153
154 fn write(&self, writer: &mut dyn Write) -> io::Result<()> {
155 writer.write_u32::<LittleEndian>(self.version)?;
156 var_int::write(self.inputs.len() as u64, writer)?;
157 for tx_in in self.inputs.iter() {
158 tx_in.write(writer)?;
159 }
160 var_int::write(self.outputs.len() as u64, writer)?;
161 for tx_out in self.outputs.iter() {
162 tx_out.write(writer)?;
163 }
164 writer.write_u32::<LittleEndian>(self.lock_time)?;
165 Ok(())
166 }
167}
168
169impl Payload<Tx> for Tx {
170 fn size(&self) -> usize {
171 let mut size = 8;
172 size += var_int::size(self.inputs.len() as u64);
173 for tx_in in self.inputs.iter() {
174 size += tx_in.size();
175 }
176 size += var_int::size(self.outputs.len() as u64);
177 for tx_out in self.outputs.iter() {
178 size += tx_out.size();
179 }
180 size
181 }
182}
183
184impl fmt::Debug for Tx {
185 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186 let inputs_str = format!("[<{} inputs>]", self.inputs.len());
187 let outputs_str = format!("[<{} outputs>]", self.outputs.len());
188
189 f.debug_struct("Tx")
190 .field("version", &self.version)
191 .field(
192 "inputs",
193 if self.inputs.len() <= 3 {
194 &self.inputs
195 } else {
196 &inputs_str
197 },
198 ).field(
199 "outputs",
200 if self.outputs.len() <= 3 {
201 &self.outputs
202 } else {
203 &outputs_str
204 },
205 ).field("lock_time", &self.lock_time)
206 .finish()
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213 use messages::OutPoint;
214 use std::io::Cursor;
215 use util::{Amount, Hash256};
216
217 #[test]
218 fn write_read() {
219 let mut v = Vec::new();
220 let t = Tx {
221 version: 1,
222 inputs: vec![
223 TxIn {
224 prev_output: OutPoint {
225 hash: Hash256([9; 32]),
226 index: 9,
227 },
228 sig_script: Script(vec![1, 3, 5, 7, 9]),
229 sequence: 100,
230 },
231 TxIn {
232 prev_output: OutPoint {
233 hash: Hash256([0; 32]),
234 index: 8,
235 },
236 sig_script: Script(vec![3; 333]),
237 sequence: 22,
238 },
239 ],
240 outputs: vec![
241 TxOut {
242 amount: Amount(99),
243 pk_script: Script(vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 100, 99, 98, 97, 96]),
244 },
245 TxOut {
246 amount: Amount(199),
247 pk_script: Script(vec![56, 78, 90, 90, 78, 56]),
248 },
249 ],
250 lock_time: 1000,
251 };
252 t.write(&mut v).unwrap();
253 assert!(v.len() == t.size());
254 assert!(Tx::read(&mut Cursor::new(&v)).unwrap() == t);
255 }
256
257 #[test]
258 fn hash() {
259 let tx = Tx {
261 version: 1,
262 inputs: vec![TxIn {
263 prev_output: OutPoint {
264 hash: Hash256([0; 32]),
265 index: 4294967295,
266 },
267 sig_script: Script(vec![4, 255, 255, 0, 29, 1, 11]),
268 sequence: 4294967295,
269 }],
270 outputs: vec![TxOut {
271 amount: Amount(5000000000),
272 pk_script: Script(vec![
273 65, 4, 114, 17, 168, 36, 245, 91, 80, 82, 40, 228, 195, 213, 25, 76, 31, 207,
274 170, 21, 164, 86, 171, 223, 55, 249, 185, 217, 122, 64, 64, 175, 192, 115, 222,
275 230, 200, 144, 100, 152, 79, 3, 56, 82, 55, 217, 33, 103, 193, 62, 35, 100, 70,
276 180, 23, 171, 121, 160, 252, 174, 65, 42, 227, 49, 107, 119, 172,
277 ]),
278 }],
279 lock_time: 0,
280 };
281 let h = "9b0fc92260312ce44e74ef369f5c66bbb85848f2eddd5a7a1cde251e54ccfdd5";
282 assert!(tx.hash() == Hash256::decode(h).unwrap());
283 assert!(tx.coinbase());
284 }
285
286 #[test]
287 fn validate() {
288 let utxo = (
289 OutPoint {
290 hash: Hash256([5; 32]),
291 index: 3,
292 },
293 TxOut {
294 amount: Amount(100),
295 pk_script: Script(vec![]),
296 },
297 );
298 let mut utxos = LinkedHashMap::new();
299 utxos.insert(utxo.0.clone(), utxo.1.clone());
300
301 let tx = Tx {
302 version: 2,
303 inputs: vec![TxIn {
304 prev_output: utxo.0.clone(),
305 sig_script: Script(vec![op_codes::OP_1]),
306 sequence: 0,
307 }],
308 outputs: vec![
309 TxOut {
310 amount: Amount(10),
311 pk_script: Script(vec![]),
312 },
313 TxOut {
314 amount: Amount(20),
315 pk_script: Script(vec![]),
316 },
317 ],
318 lock_time: 0,
319 };
320 assert!(tx.validate(false, &utxos).is_ok());
321
322 let mut tx_test = tx.clone();
323 tx_test.inputs = vec![];
324 assert!(tx_test.validate(false, &utxos).is_err());
325
326 let mut tx_test = tx.clone();
327 tx_test.outputs = vec![];
328 assert!(tx_test.validate(false, &utxos).is_err());
329
330 let mut tx_test = tx.clone();
331 tx_test.outputs[0].amount = Amount(-1);
332 assert!(tx_test.validate(false, &utxos).is_err());
333
334 let mut tx_test = tx.clone();
335 tx_test.outputs[0].amount = Amount(0);
336 tx_test.outputs[0].amount = Amount(0);
337 assert!(tx_test.validate(false, &utxos).is_ok());
338
339 let mut tx_test = tx.clone();
340 tx_test.outputs[0].amount = Amount(MAX_SATOSHIS);
341 tx_test.outputs[1].amount = Amount(MAX_SATOSHIS);
342 assert!(tx_test.validate(false, &utxos).is_err());
343
344 let mut tx_test = tx.clone();
345 tx_test.outputs[1].amount = Amount(MAX_SATOSHIS + 1);
346 assert!(tx_test.validate(false, &utxos).is_err());
347
348 let mut tx_test = tx.clone();
349 tx_test.inputs[0].prev_output.hash = COINBASE_OUTPOINT_HASH;
350 tx_test.inputs[0].prev_output.index = COINBASE_OUTPOINT_INDEX;
351 assert!(tx_test.validate(false, &utxos).is_err());
352
353 let mut tx_test = tx.clone();
354 tx_test.lock_time = 4294967295;
355 assert!(tx_test.validate(false, &utxos).is_err());
356
357 let mut tx_test = tx.clone();
358 tx_test.inputs[0].prev_output.hash = Hash256([8; 32]);
359 assert!(tx_test.validate(false, &utxos).is_err());
360
361 let mut utxos_clone = utxos.clone();
362 let prev_output = &tx.inputs[0].prev_output;
363 utxos_clone.get_mut(prev_output).unwrap().amount = Amount(-1);
364 assert!(tx.validate(false, &utxos_clone).is_err());
365
366 let mut utxos_clone = utxos.clone();
367 let prev_output = &tx.inputs[0].prev_output;
368 utxos_clone.get_mut(prev_output).unwrap().amount = Amount(MAX_SATOSHIS + 1);
369 assert!(tx.validate(false, &utxos_clone).is_err());
370
371 let mut tx_test = tx.clone();
372 tx_test.outputs[0].amount = Amount(100);
373 assert!(tx_test.validate(false, &utxos).is_err());
374
375 let mut utxos_clone = utxos.clone();
376 let prev_output = &tx.inputs[0].prev_output;
377 utxos_clone.get_mut(prev_output).unwrap().pk_script = Script(vec![op_codes::OP_0]);
378 assert!(tx.validate(false, &utxos_clone).is_err());
379 }
380}