use std::io::{Read, Write};
use crate::script::unlocking_script::UnlockingScript;
use crate::transaction::error::TransactionError;
use crate::transaction::transaction::Transaction;
use crate::transaction::{read_u32_le, read_varint, write_u32_le, write_varint};
#[derive(Debug, Clone)]
pub struct TransactionInput {
pub source_transaction: Option<Box<Transaction>>,
pub source_txid: Option<String>,
pub source_output_index: u32,
pub unlocking_script: Option<UnlockingScript>,
pub sequence: u32,
}
impl Default for TransactionInput {
fn default() -> Self {
Self {
source_transaction: None,
source_txid: None,
source_output_index: 0,
unlocking_script: None,
sequence: 0xFFFFFFFF,
}
}
}
impl TransactionInput {
pub fn from_binary(reader: &mut impl Read) -> Result<Self, TransactionError> {
let mut txid_bytes = [0u8; 32];
reader.read_exact(&mut txid_bytes)?;
txid_bytes.reverse();
let source_txid = bytes_to_hex(&txid_bytes);
let source_output_index = read_u32_le(reader)?;
let script_len = read_varint(reader)? as usize;
let unlocking_script = if script_len > 0 {
let mut script_bytes = vec![0u8; script_len];
reader.read_exact(&mut script_bytes)?;
Some(UnlockingScript::from_binary(&script_bytes))
} else {
Some(UnlockingScript::from_binary(&[]))
};
let sequence = read_u32_le(reader)?;
Ok(TransactionInput {
source_transaction: None,
source_txid: Some(source_txid),
source_output_index,
unlocking_script,
sequence,
})
}
pub fn to_binary(&self, writer: &mut impl Write) -> Result<(), TransactionError> {
if let Some(ref txid) = self.source_txid {
let mut txid_bytes = hex_to_bytes(txid)
.map_err(|e| TransactionError::InvalidFormat(format!("invalid txid hex: {}", e)))?;
txid_bytes.reverse();
writer.write_all(&txid_bytes)?;
} else if let Some(ref source_tx) = self.source_transaction {
let hash = source_tx.hash()?;
writer.write_all(&hash)?;
} else {
writer.write_all(&[0u8; 32])?;
}
write_u32_le(writer, self.source_output_index)?;
if let Some(ref script) = self.unlocking_script {
let script_bin = script.to_binary();
write_varint(writer, script_bin.len() as u64)?;
writer.write_all(&script_bin)?;
} else {
write_varint(writer, 0)?;
}
write_u32_le(writer, self.sequence)?;
Ok(())
}
}
fn bytes_to_hex(bytes: &[u8]) -> String {
let mut s = String::with_capacity(bytes.len() * 2);
for b in bytes {
s.push_str(&format!("{:02x}", b));
}
s
}
fn hex_to_bytes(hex: &str) -> Result<Vec<u8>, String> {
if !hex.len().is_multiple_of(2) {
return Err("odd length hex string".to_string());
}
let mut bytes = Vec::with_capacity(hex.len() / 2);
for i in (0..hex.len()).step_by(2) {
let byte = u8::from_str_radix(&hex[i..i + 2], 16)
.map_err(|e| format!("invalid hex at position {}: {}", i, e))?;
bytes.push(byte);
}
Ok(bytes)
}