use bsv_primitives::util::{BsvReader, BsvWriter, VarInt};
use bsv_script::Script;
use crate::output::TransactionOutput;
use crate::TransactionError;
pub const DEFAULT_SEQUENCE_NUMBER: u32 = 0xFFFF_FFFF;
#[derive(Clone, Debug)]
pub struct TransactionInput {
pub source_txid: [u8; 32],
pub source_tx_out_index: u32,
pub sequence_number: u32,
pub unlocking_script: Option<Script>,
pub source_transaction: Option<Box<crate::transaction::Transaction>>,
source_output: Option<TransactionOutput>,
}
impl TransactionInput {
pub fn new() -> Self {
TransactionInput {
source_txid: [0u8; 32],
source_tx_out_index: 0,
sequence_number: DEFAULT_SEQUENCE_NUMBER,
unlocking_script: None,
source_transaction: None,
source_output: None,
}
}
pub fn read_from(reader: &mut BsvReader) -> Result<Self, TransactionError> {
let txid_bytes = reader.read_bytes(32).map_err(|e| {
TransactionError::SerializationError(format!("reading source txid: {}", e))
})?;
let mut source_txid = [0u8; 32];
source_txid.copy_from_slice(txid_bytes);
let source_tx_out_index = reader.read_u32_le().map_err(|e| {
TransactionError::SerializationError(format!("reading output index: {}", e))
})?;
let script_len = reader.read_varint().map_err(|e| {
TransactionError::SerializationError(format!("reading script length: {}", e))
})?;
let script_bytes = reader
.read_bytes(script_len.value() as usize)
.map_err(|e| {
TransactionError::SerializationError(format!("reading unlocking script: {}", e))
})?;
let sequence_number = reader.read_u32_le().map_err(|e| {
TransactionError::SerializationError(format!("reading sequence number: {}", e))
})?;
let unlocking_script = if script_bytes.is_empty() {
None
} else {
Some(Script::from_bytes(script_bytes))
};
Ok(TransactionInput {
source_txid,
source_tx_out_index,
sequence_number,
unlocking_script,
source_transaction: None,
source_output: None,
})
}
pub fn write_to(&self, writer: &mut BsvWriter) {
writer.write_bytes(&self.source_txid);
writer.write_u32_le(self.source_tx_out_index);
match &self.unlocking_script {
Some(script) => {
let script_bytes = script.to_bytes();
writer.write_varint(VarInt::from(script_bytes.len()));
writer.write_bytes(script_bytes);
}
None => {
writer.write_varint(VarInt::from(0u64));
}
}
writer.write_u32_le(self.sequence_number);
}
pub fn to_bytes_cleared(&self, clear: bool) -> Vec<u8> {
let mut writer = BsvWriter::new();
writer.write_bytes(&self.source_txid);
writer.write_u32_le(self.source_tx_out_index);
if clear {
writer.write_varint(VarInt::from(0u64));
} else if let Some(script) = self.unlocking_script.as_ref() {
let script_bytes = script.to_bytes();
writer.write_varint(VarInt::from(script_bytes.len()));
writer.write_bytes(script_bytes);
} else {
writer.write_varint(VarInt::from(0u64));
}
writer.write_u32_le(self.sequence_number);
writer.into_bytes()
}
pub fn set_source_output(&mut self, output: Option<TransactionOutput>) {
self.source_output = output;
}
pub fn source_tx_output(&self) -> Option<&TransactionOutput> {
if let Some(ref output) = self.source_output {
return Some(output);
}
if let Some(ref source_tx) = self.source_transaction {
source_tx.outputs.get(self.source_tx_out_index as usize)
} else {
None
}
}
pub fn source_tx_satoshis(&self) -> Option<u64> {
self.source_tx_output().map(|o| o.satoshis)
}
pub fn source_tx_script(&self) -> Option<&Script> {
self.source_tx_output().map(|o| &o.locking_script)
}
}
impl Default for TransactionInput {
fn default() -> Self {
Self::new()
}
}