bsv/transaction/
transaction_input.rs1use std::io::{Read, Write};
4
5use crate::script::unlocking_script::UnlockingScript;
6use crate::transaction::error::TransactionError;
7use crate::transaction::transaction::Transaction;
8use crate::transaction::{read_u32_le, read_varint, write_u32_le, write_varint};
9
10#[derive(Debug, Clone)]
12pub struct TransactionInput {
13 pub source_transaction: Option<Box<Transaction>>,
15 pub source_txid: Option<String>,
17 pub source_output_index: u32,
19 pub unlocking_script: Option<UnlockingScript>,
21 pub sequence: u32,
23}
24
25impl Default for TransactionInput {
26 fn default() -> Self {
27 Self {
28 source_transaction: None,
29 source_txid: None,
30 source_output_index: 0,
31 unlocking_script: None,
32 sequence: 0xFFFFFFFF,
33 }
34 }
35}
36
37impl TransactionInput {
38 pub fn from_binary(reader: &mut impl Read) -> Result<Self, TransactionError> {
43 let mut txid_bytes = [0u8; 32];
45 reader.read_exact(&mut txid_bytes)?;
46
47 txid_bytes.reverse();
49 let source_txid = bytes_to_hex(&txid_bytes);
50
51 let source_output_index = read_u32_le(reader)?;
53
54 let script_len = read_varint(reader)? as usize;
56 let unlocking_script = if script_len > 0 {
57 let mut script_bytes = vec![0u8; script_len];
58 reader.read_exact(&mut script_bytes)?;
59 Some(UnlockingScript::from_binary(&script_bytes))
60 } else {
61 Some(UnlockingScript::from_binary(&[]))
63 };
64
65 let sequence = read_u32_le(reader)?;
67
68 Ok(TransactionInput {
69 source_transaction: None,
70 source_txid: Some(source_txid),
71 source_output_index,
72 unlocking_script,
73 sequence,
74 })
75 }
76
77 pub fn to_binary(&self, writer: &mut impl Write) -> Result<(), TransactionError> {
79 if let Some(ref txid) = self.source_txid {
81 let mut txid_bytes = hex_to_bytes(txid)
82 .map_err(|e| TransactionError::InvalidFormat(format!("invalid txid hex: {}", e)))?;
83 txid_bytes.reverse();
84 writer.write_all(&txid_bytes)?;
85 } else if let Some(ref source_tx) = self.source_transaction {
86 let hash = source_tx.hash()?;
88 writer.write_all(&hash)?;
89 } else {
90 writer.write_all(&[0u8; 32])?;
92 }
93
94 write_u32_le(writer, self.source_output_index)?;
96
97 if let Some(ref script) = self.unlocking_script {
99 let script_bin = script.to_binary();
100 write_varint(writer, script_bin.len() as u64)?;
101 writer.write_all(&script_bin)?;
102 } else {
103 write_varint(writer, 0)?;
104 }
105
106 write_u32_le(writer, self.sequence)?;
108
109 Ok(())
110 }
111}
112
113fn bytes_to_hex(bytes: &[u8]) -> String {
115 let mut s = String::with_capacity(bytes.len() * 2);
116 for b in bytes {
117 s.push_str(&format!("{:02x}", b));
118 }
119 s
120}
121
122fn hex_to_bytes(hex: &str) -> Result<Vec<u8>, String> {
124 if !hex.len().is_multiple_of(2) {
125 return Err("odd length hex string".to_string());
126 }
127 let mut bytes = Vec::with_capacity(hex.len() / 2);
128 for i in (0..hex.len()).step_by(2) {
129 let byte = u8::from_str_radix(&hex[i..i + 2], 16)
130 .map_err(|e| format!("invalid hex at position {}: {}", i, e))?;
131 bytes.push(byte);
132 }
133 Ok(bytes)
134}