1use super::varint::{decode_varint, encode_varint};
7use crate::error::{ConsensusError, Result};
8use crate::types::*;
9use std::borrow::Cow;
10
11#[cfg(feature = "production")]
12use smallvec::SmallVec;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
16pub enum TransactionParseError {
17 InsufficientBytes,
18 InvalidVersion,
19 InvalidInputCount,
20 InvalidOutputCount,
21 InvalidScriptLength,
22 InvalidLockTime,
23 SuperfluousWitness,
25}
26
27impl std::fmt::Display for TransactionParseError {
28 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29 match self {
30 TransactionParseError::InsufficientBytes => {
31 write!(f, "Insufficient bytes to parse transaction")
32 }
33 TransactionParseError::InvalidVersion => write!(f, "Invalid transaction version"),
34 TransactionParseError::InvalidInputCount => write!(f, "Invalid input count"),
35 TransactionParseError::InvalidOutputCount => write!(f, "Invalid output count"),
36 TransactionParseError::InvalidScriptLength => write!(f, "Invalid script length"),
37 TransactionParseError::InvalidLockTime => write!(f, "Invalid lock time"),
38 TransactionParseError::SuperfluousWitness => {
39 write!(f, "Witness flag set but every witness stack is empty")
40 }
41 }
42 }
43}
44
45impl std::error::Error for TransactionParseError {}
46
47#[inline]
48fn checked_slice_end(offset: usize, len: u64) -> Result<usize> {
49 let len = usize::try_from(len).map_err(|_| {
50 ConsensusError::Serialization(Cow::Owned(
51 TransactionParseError::InvalidScriptLength.to_string(),
52 ))
53 })?;
54 offset.checked_add(len).ok_or_else(|| {
55 ConsensusError::Serialization(Cow::Owned(
56 TransactionParseError::InsufficientBytes.to_string(),
57 ))
58 })
59}
60
61fn read_tx_input_count_after_version(
72 data: &[u8],
73 mut offset: usize,
74) -> Result<(bool, u64, usize, bool)> {
75 let (mut input_count, varint_len) = decode_varint(&data[offset..])?;
76 offset += varint_len;
77
78 if input_count > 1_000_000 {
79 return Err(ConsensusError::Serialization(Cow::Owned(
80 TransactionParseError::InvalidInputCount.to_string(),
81 )));
82 }
83
84 let mut is_segwit = false;
85 let mut implicit_empty_outputs = false;
87
88 if input_count == 0 {
89 if offset >= data.len() {
90 return Err(ConsensusError::Serialization(Cow::Owned(
91 TransactionParseError::InsufficientBytes.to_string(),
92 )));
93 }
94 let flag = data[offset];
95 offset += 1;
96
97 if flag == 0 {
98 implicit_empty_outputs = true;
99 return Ok((false, 0, offset, implicit_empty_outputs));
100 }
101
102 if flag != 1 {
103 return Err(ConsensusError::Serialization(Cow::Owned(format!(
104 "Unsupported segwit transaction flag: {flag}"
105 ))));
106 }
107
108 is_segwit = true;
109
110 let (ic2, vl2) = decode_varint(&data[offset..])?;
111 offset += vl2;
112 if ic2 > 1_000_000 {
113 return Err(ConsensusError::Serialization(Cow::Owned(
114 TransactionParseError::InvalidInputCount.to_string(),
115 )));
116 }
117 input_count = ic2;
118 }
119
120 Ok((is_segwit, input_count, offset, implicit_empty_outputs))
121}
122
123#[inline(always)]
125pub fn serialize_transaction(tx: &Transaction) -> Vec<u8> {
126 let mut result = Vec::new();
127 serialize_transaction_append(&mut result, tx);
128 result
129}
130
131#[inline(always)]
139fn serialize_transaction_append(result: &mut Vec<u8>, tx: &Transaction) {
140 result.extend_from_slice(&(tx.version as u32).to_le_bytes());
141
142 if tx.inputs.is_empty() && !tx.outputs.is_empty() {
143 result.extend_from_slice(&encode_varint(0));
144 result.push(0x01);
145 result.extend_from_slice(&encode_varint(tx.inputs.len() as u64));
146 } else {
147 result.extend_from_slice(&encode_varint(tx.inputs.len() as u64));
148 }
149
150 for input in &tx.inputs {
151 result.extend_from_slice(&input.prevout.hash);
152 result.extend_from_slice(&input.prevout.index.to_le_bytes());
153 result.extend_from_slice(&encode_varint(input.script_sig.len() as u64));
154 result.extend_from_slice(&input.script_sig);
155 result.extend_from_slice(&(input.sequence as u32).to_le_bytes());
156 }
157
158 result.extend_from_slice(&encode_varint(tx.outputs.len() as u64));
159
160 for output in &tx.outputs {
161 result.extend_from_slice(&(output.value as u64).to_le_bytes());
162 result.extend_from_slice(&encode_varint(output.script_pubkey.len() as u64));
163 result.extend_from_slice(&output.script_pubkey);
164 }
165
166 result.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
167}
168
169#[inline(always)]
171pub fn serialize_transaction_into(dst: &mut Vec<u8>, tx: &Transaction) -> usize {
172 dst.clear();
173 serialize_transaction_append(dst, tx);
174 dst.len()
175}
176
177pub fn serialize_transaction_with_witness(
181 tx: &Transaction,
182 witnesses: &[Witness],
183) -> Result<Vec<u8>> {
184 if witnesses.len() != tx.inputs.len() {
185 return Err(ConsensusError::TransactionValidation(
186 format!(
187 "witness count {} must match input count {}",
188 witnesses.len(),
189 tx.inputs.len()
190 )
191 .into(),
192 ));
193 }
194 if !tx.inputs.is_empty() && witnesses.iter().all(|stack| stack.is_empty()) {
198 return Ok(serialize_transaction(tx));
199 }
200 let mut result = Vec::new();
201 result.extend_from_slice(&(tx.version as u32).to_le_bytes());
202 result.push(0x00);
203 result.push(0x01);
204 result.extend_from_slice(&encode_varint(tx.inputs.len() as u64));
205 for input in &tx.inputs {
206 result.extend_from_slice(&input.prevout.hash);
207 result.extend_from_slice(&input.prevout.index.to_le_bytes());
208 result.extend_from_slice(&encode_varint(input.script_sig.len() as u64));
209 result.extend_from_slice(&input.script_sig);
210 result.extend_from_slice(&(input.sequence as u32).to_le_bytes());
211 }
212 result.extend_from_slice(&encode_varint(tx.outputs.len() as u64));
213 for output in &tx.outputs {
214 result.extend_from_slice(&(output.value as u64).to_le_bytes());
215 result.extend_from_slice(&encode_varint(output.script_pubkey.len() as u64));
216 result.extend_from_slice(&output.script_pubkey);
217 }
218 for witness in witnesses {
219 result.extend_from_slice(&encode_varint(witness.len() as u64));
220 for element in witness {
221 result.extend_from_slice(&encode_varint(element.len() as u64));
222 result.extend_from_slice(element);
223 }
224 }
225 result.extend_from_slice(&(tx.lock_time as u32).to_le_bytes());
226 Ok(result)
227}
228
229pub fn deserialize_transaction(data: &[u8]) -> Result<Transaction> {
234 deserialize_transaction_with_witness(data).map(|(tx, _, _)| tx)
235}
236
237#[cfg(feature = "production")]
243type TxInputVec = SmallVec<[TransactionInput; 2]>;
244#[cfg(not(feature = "production"))]
245type TxInputVec = Vec<TransactionInput>;
246
247#[cfg(feature = "production")]
248type TxOutputVec = SmallVec<[TransactionOutput; 2]>;
249#[cfg(not(feature = "production"))]
250type TxOutputVec = Vec<TransactionOutput>;
251
252#[inline]
254fn parse_inputs(data: &[u8], offset: &mut usize, count: u64) -> Result<TxInputVec> {
255 let mut inputs = TxInputVec::new();
256
257 for _ in 0..count {
258 if data.len() < *offset + 36 {
259 return Err(ConsensusError::Serialization(Cow::Owned(
260 TransactionParseError::InsufficientBytes.to_string(),
261 )));
262 }
263 let mut hash = [0u8; 32];
264 hash.copy_from_slice(&data[*offset..*offset + 32]);
265 *offset += 32;
266
267 let index = u32::from_le_bytes([
268 data[*offset],
269 data[*offset + 1],
270 data[*offset + 2],
271 data[*offset + 3],
272 ]);
273 *offset += 4;
274
275 let (script_len, varint_len) = decode_varint(&data[*offset..])?;
276 *offset += varint_len;
277
278 let script_sig_end = checked_slice_end(*offset, script_len)?;
279 if data.len() < script_sig_end {
280 return Err(ConsensusError::Serialization(Cow::Owned(
281 TransactionParseError::InsufficientBytes.to_string(),
282 )));
283 }
284 let script_sig = data[*offset..script_sig_end].to_vec();
285 *offset = script_sig_end;
286
287 if data.len() < *offset + 4 {
288 return Err(ConsensusError::Serialization(Cow::Owned(
289 TransactionParseError::InsufficientBytes.to_string(),
290 )));
291 }
292 let sequence = u32::from_le_bytes([
293 data[*offset],
294 data[*offset + 1],
295 data[*offset + 2],
296 data[*offset + 3],
297 ]) as u64;
298 *offset += 4;
299
300 inputs.push(TransactionInput {
301 prevout: OutPoint { hash, index },
302 script_sig,
303 sequence,
304 });
305 }
306
307 Ok(inputs)
308}
309
310#[inline]
313fn parse_outputs(
314 data: &[u8],
315 offset: &mut usize,
316 implicit_empty_outputs: bool,
317) -> Result<TxOutputVec> {
318 let output_count = if implicit_empty_outputs {
319 0
320 } else {
321 let (output_count, varint_len) = decode_varint(&data[*offset..])?;
322 *offset += varint_len;
323
324 if output_count > 1_000_000 {
325 return Err(ConsensusError::Serialization(Cow::Owned(
326 TransactionParseError::InvalidOutputCount.to_string(),
327 )));
328 }
329 output_count
330 };
331
332 let mut outputs = TxOutputVec::new();
333
334 for _ in 0..output_count {
335 if data.len() < *offset + 8 {
336 return Err(ConsensusError::Serialization(Cow::Owned(
337 TransactionParseError::InsufficientBytes.to_string(),
338 )));
339 }
340 let value = i64::from_le_bytes([
341 data[*offset],
342 data[*offset + 1],
343 data[*offset + 2],
344 data[*offset + 3],
345 data[*offset + 4],
346 data[*offset + 5],
347 data[*offset + 6],
348 data[*offset + 7],
349 ]);
350 *offset += 8;
351
352 let (script_len, varint_len) = decode_varint(&data[*offset..])?;
353 *offset += varint_len;
354
355 let script_pubkey_end = checked_slice_end(*offset, script_len)?;
356 if data.len() < script_pubkey_end {
357 return Err(ConsensusError::Serialization(Cow::Owned(
358 TransactionParseError::InsufficientBytes.to_string(),
359 )));
360 }
361 let script_pubkey = data[*offset..script_pubkey_end].to_vec();
362 *offset = script_pubkey_end;
363
364 outputs.push(TransactionOutput {
365 value,
366 script_pubkey,
367 });
368 }
369
370 Ok(outputs)
371}
372
373pub fn deserialize_transaction_with_offset(data: &[u8]) -> Result<(Transaction, usize)> {
377 let (tx, _witnesses, bytes_consumed) = deserialize_transaction_with_witness(data)?;
378 Ok((tx, bytes_consumed))
379}
380
381pub fn deserialize_transaction_with_witness(
383 data: &[u8],
384) -> Result<(Transaction, Vec<Witness>, usize)> {
385 let mut offset = 0;
386
387 if data.len() < offset + 4 {
388 return Err(ConsensusError::Serialization(Cow::Owned(
389 TransactionParseError::InsufficientBytes.to_string(),
390 )));
391 }
392 let version = u32::from_le_bytes([
395 data[offset],
396 data[offset + 1],
397 data[offset + 2],
398 data[offset + 3],
399 ]) as u64;
400 offset += 4;
401
402 let (is_segwit, input_count, mut offset, implicit_empty_outputs) =
403 read_tx_input_count_after_version(data, offset)?;
404
405 let inputs = parse_inputs(data, &mut offset, input_count)?;
406 let outputs = parse_outputs(data, &mut offset, implicit_empty_outputs)?;
407
408 let mut all_witnesses: Vec<Witness> = Vec::new();
409 if is_segwit {
410 for _ in 0..input_count {
411 let (stack_count, varint_len) = decode_varint(&data[offset..])?;
412 offset += varint_len;
413
414 let mut witness_stack: Witness = Vec::new();
415 for _ in 0..stack_count {
416 let (item_len, varint_len) = decode_varint(&data[offset..])?;
417 offset += varint_len;
418
419 let item_end = checked_slice_end(offset, item_len)?;
420 if data.len() < item_end {
421 return Err(ConsensusError::Serialization(Cow::Owned(
422 TransactionParseError::InsufficientBytes.to_string(),
423 )));
424 }
425 witness_stack.push(data[offset..item_end].to_vec());
426 offset = item_end;
427 }
428 all_witnesses.push(witness_stack);
429 }
430 if input_count > 0 && all_witnesses.iter().all(|stack| stack.is_empty()) {
434 return Err(ConsensusError::Serialization(Cow::Owned(
435 TransactionParseError::SuperfluousWitness.to_string(),
436 )));
437 }
438 } else {
439 for _ in 0..input_count {
440 all_witnesses.push(Vec::new());
441 }
442 }
443
444 if data.len() < offset + 4 {
445 return Err(ConsensusError::Serialization(Cow::Owned(
446 TransactionParseError::InsufficientBytes.to_string(),
447 )));
448 }
449 let lock_time = u32::from_le_bytes([
450 data[offset],
451 data[offset + 1],
452 data[offset + 2],
453 data[offset + 3],
454 ]) as u64;
455 offset += 4;
456
457 let tx = Transaction {
458 version,
459 inputs,
460 outputs,
461 lock_time,
462 };
463
464 Ok((tx, all_witnesses, offset))
465}
466
467#[cfg(test)]
468mod tests {
469 use super::*;
470
471 #[test]
472 fn test_serialize_deserialize_round_trip() {
473 let tx = Transaction {
474 version: 1,
475 inputs: crate::tx_inputs![TransactionInput {
476 prevout: OutPoint {
477 hash: [1; 32],
478 index: 0
479 },
480 script_sig: vec![0x51],
481 sequence: 0xffffffff,
482 }],
483 outputs: crate::tx_outputs![TransactionOutput {
484 value: 5000000000,
485 script_pubkey: vec![0x51],
486 }],
487 lock_time: 0,
488 };
489
490 let serialized = serialize_transaction(&tx);
491 let deserialized = deserialize_transaction(&serialized).unwrap();
492
493 assert_eq!(deserialized.version, tx.version);
494 assert_eq!(deserialized.inputs.len(), tx.inputs.len());
495 assert_eq!(deserialized.outputs.len(), tx.outputs.len());
496 assert_eq!(deserialized.lock_time, tx.lock_time);
497 }
498
499 #[test]
501 fn empty_tx_round_trip_matches_double_zero_preamble() {
502 let tx = Transaction {
503 version: 1,
504 inputs: crate::tx_inputs![],
505 outputs: crate::tx_outputs![],
506 lock_time: 0,
507 };
508 let bytes = serialize_transaction(&tx);
509 let back = deserialize_transaction(&bytes).unwrap();
510 assert_eq!(back.version, tx.version);
511 assert!(back.inputs.is_empty());
512 assert!(back.outputs.is_empty());
513 assert_eq!(back.lock_time, tx.lock_time);
514 assert_eq!(&bytes[4..6], &[0u8, 0u8]);
516 }
517
518 #[test]
519 fn zero_inputs_one_output_round_trips_extended_framing() {
520 let tx = Transaction {
521 version: 2,
522 inputs: crate::tx_inputs![],
523 outputs: crate::tx_outputs![TransactionOutput {
524 value: 1000,
525 script_pubkey: vec![0x51],
526 }],
527 lock_time: 0x11223344,
528 };
529 let bytes = serialize_transaction(&tx);
530 let back = deserialize_transaction(&bytes).unwrap();
531 assert_eq!(back.version, tx.version);
532 assert!(back.inputs.is_empty());
533 assert_eq!(back.outputs.len(), 1);
534 assert_eq!(back.outputs[0].value, 1000);
535 assert_eq!(back.lock_time, tx.lock_time);
536 assert_eq!(&bytes[4..8], &[0u8, 1, 0, 1]);
538 }
539
540 #[test]
541 fn high_bit_version_stays_in_the_low_32_bits() {
542 let tx = Transaction {
543 version: 0xffff_ffff,
544 inputs: crate::tx_inputs![],
545 outputs: crate::tx_outputs![],
546 lock_time: 0,
547 };
548 let bytes = serialize_transaction(&tx);
549 assert_eq!(&bytes[0..4], &[0xff, 0xff, 0xff, 0xff]);
550 let back = deserialize_transaction(&bytes).unwrap();
551 assert_eq!(back.version, 0xffff_ffff);
552 assert!(back.version >= 2);
553
554 let witness_bytes = serialize_transaction_with_witness(&tx, &[]).unwrap();
555 assert_eq!(&witness_bytes[0..4], &[0xff, 0xff, 0xff, 0xff]);
556 let (witness_back, stacks, _) =
557 deserialize_transaction_with_witness(&witness_bytes).unwrap();
558 assert_eq!(witness_back.version, 0xffff_ffff);
559 assert!(stacks.is_empty());
560 }
561
562 #[test]
563 fn witness_flag_with_only_empty_stacks_does_not_decode() {
564 let bytes = hex_bytes(
566 "0100000000010100000000000000000000000000000000000000000000000000\
567 00000000000000ffffffff00ffffffff010000000000000000000000000000",
568 );
569 let err = deserialize_transaction_with_witness(&bytes).unwrap_err();
570 let msg = err.to_string();
571 assert!(
572 msg.contains("every witness stack is empty"),
573 "unexpected error: {msg}"
574 );
575 }
576
577 #[test]
578 fn witness_stack_of_one_empty_item_still_decodes() {
579 let tx = Transaction {
580 version: 1,
581 inputs: crate::tx_inputs![TransactionInput {
582 prevout: OutPoint {
583 hash: [0; 32],
584 index: 0xffffffff,
585 },
586 script_sig: vec![],
587 sequence: 0xffffffff,
588 }],
589 outputs: crate::tx_outputs![TransactionOutput {
590 value: 0,
591 script_pubkey: vec![],
592 }],
593 lock_time: 0,
594 };
595 let bytes = serialize_transaction_with_witness(&tx, &[vec![vec![]]]).unwrap();
596 let (back, stacks, consumed) = deserialize_transaction_with_witness(&bytes).unwrap();
597 assert_eq!(consumed, bytes.len());
598 assert_eq!(back.inputs.len(), 1);
599 assert_eq!(stacks.len(), 1);
600 assert_eq!(stacks[0].len(), 1);
601 assert!(stacks[0][0].is_empty());
602 }
603
604 #[test]
605 fn empty_stacks_serialize_without_the_witness_flag() {
606 let tx = Transaction {
607 version: 1,
608 inputs: crate::tx_inputs![TransactionInput {
609 prevout: OutPoint {
610 hash: [2; 32],
611 index: 1,
612 },
613 script_sig: vec![0x51],
614 sequence: 0xfffffffe,
615 }],
616 outputs: crate::tx_outputs![TransactionOutput {
617 value: 50,
618 script_pubkey: vec![0x51],
619 }],
620 lock_time: 0,
621 };
622 let with_empty = serialize_transaction_with_witness(&tx, &[Vec::new()]).unwrap();
623 let legacy = serialize_transaction(&tx);
624 assert_eq!(with_empty, legacy);
625 let (back, stacks, _) = deserialize_transaction_with_witness(&with_empty).unwrap();
626 assert_eq!(back.inputs.len(), 1);
627 assert!(stacks[0].is_empty());
628 }
629
630 #[test]
631 fn witness_count_mismatch_is_an_error() {
632 let tx = Transaction {
633 version: 1,
634 inputs: crate::tx_inputs![TransactionInput {
635 prevout: OutPoint {
636 hash: [3; 32],
637 index: 0,
638 },
639 script_sig: vec![],
640 sequence: 0xffffffff,
641 }],
642 outputs: crate::tx_outputs![TransactionOutput {
643 value: 1,
644 script_pubkey: vec![],
645 }],
646 lock_time: 0,
647 };
648 assert!(serialize_transaction_with_witness(&tx, &[]).is_err());
649 assert!(serialize_transaction_with_witness(&tx, &[vec![vec![1]], vec![vec![2]]]).is_err());
650 assert!(serialize_transaction_with_witness(&tx, &[vec![vec![1]]]).is_ok());
651 }
652
653 fn hex_bytes(s: &str) -> Vec<u8> {
654 (0..s.len())
655 .step_by(2)
656 .map(|i| u8::from_str_radix(&s[i..i + 2], 16).unwrap())
657 .collect()
658 }
659}