bitcointx 0.0.11

Bitcoin TX utility crate
Documentation
extern crate hex;
extern crate sha2;

mod sighash;
mod buffer;
pub mod op;

use sha2::{Sha256, Digest};
use buffer::{ByteBuffer};

pub fn get_var_int(value: usize) -> Vec<u8> {
    let mut data: Vec<u8> = vec![];

    if value > 0xFFFFFFFF {
        data.push(0xFF);
        data.append(&mut (value as u64).to_le_bytes().to_vec());
    }
    else if value > 0xFFFF {
        data.push(0xFE);
        data.append(&mut (value as u32).to_le_bytes().to_vec());
    }
    else if value > 0xFC {
        data.push(0xFD);
        data.append(&mut (value as u16).to_le_bytes().to_vec());
    }
    else {
        data.append(&mut (value as u8).to_le_bytes().to_vec());
    }

    return data;
}

#[derive(Clone)]
pub struct TxIn {
    prev_hash: Vec<u8>,
    prev_out: u32,
    script_sig: Vec<u8>,
    seq_no: u32,
}

impl TxIn {
    pub fn deserialize(buffer: &mut ByteBuffer) -> TxIn {
       let mut txin = TxIn{
           prev_hash: vec![],
           prev_out: 0,
           script_sig: vec![],
           seq_no: 0,
       };

        txin.prev_hash = buffer.read_bytes(32);
        txin.prev_out = buffer.read_u32();
        
        let script_len = buffer.read_var_int() as usize;
        txin.script_sig = buffer.read_bytes(script_len);
        txin.seq_no = buffer.read_u32();

        return txin;
    }

    pub fn serialize(&self) -> Vec<u8> {
        let mut data = vec![];

        data.extend(self.prev_hash.as_slice());
        data.extend(self.prev_out.to_le_bytes().to_vec());
        data.extend(get_var_int(self.script_sig.len()));
        data.extend(self.script_sig.as_slice());
        data.extend(self.seq_no.to_le_bytes().to_vec());

        return data;
    }   
}


#[derive(Clone)]
pub struct TxOut {
    value: u64,
    script_pub_key: Vec<u8>,
}

impl TxOut {
    pub fn deserialize(buffer: &mut ByteBuffer) -> TxOut {
        let mut txout = TxOut{
            value: 0,
            script_pub_key: vec![],
        };
        txout.value = buffer.read_u64();

        let script_len = buffer.read_var_int() as usize;
        txout.script_pub_key = buffer.read_bytes(script_len);

        return txout;
    }

    pub fn serialize(&self) -> Vec<u8> {
        let mut data = vec![];

        data.extend(self.value.to_le_bytes().to_vec());
        data.extend(get_var_int(self.script_pub_key.len()));
        data.extend(self.script_pub_key.as_slice());

        return data;
    }
}

#[derive(Clone)]
pub struct Tx {
    version: u32,
    inputs: Vec<TxIn>,
    outputs: Vec<TxOut>,
    lock_time: u32,
}

impl Tx {

    pub fn deserialize(data: Vec<u8>) -> Tx {
        let mut buffer = ByteBuffer::from_vec(data);
        let mut tx = Tx {
            version: 0,
            inputs: vec![],
            outputs: vec![],
            lock_time: 0,
        };

        tx.version = buffer.read_u32();
        
        let inp_count = buffer.read_var_int();
        for _ in 0..inp_count {
            tx.inputs.push(TxIn::deserialize(&mut buffer));
        }

        let out_count = buffer.read_var_int();
        for _ in 0..out_count {
            tx.outputs.push(TxOut::deserialize(&mut buffer));
        }

        tx.lock_time = buffer.read_u32();
        return tx;
    }

    pub fn serialize(&self) -> Vec<u8> {
        let mut data = vec![];

        data.extend(self.version.to_le_bytes().to_vec());

        data.extend(get_var_int(self.inputs.len()));
        for inp in &self.inputs {
            data.extend(inp.serialize());
        }
        data.extend(get_var_int(self.outputs.len()));
        for out in &self.outputs {
            data.extend(out.serialize());
        }

        data.extend(self.lock_time.to_le_bytes().to_vec());

        return data;
    }

    pub fn sighash_serialize(&self, sighash_type: u8, index: usize, pubkey: Vec<u8>) -> Result<Vec<u8>, &'static str> {
        if (sighash_type & sighash::FORKID) == 0 {
            return Err("Sighash forkID must be set, this is Bitcoin SV");
        }

        let mut tmp = self.clone();

        for inp in &mut tmp.inputs {
            inp.script_sig = vec![];
        }

        if index > tmp.inputs.len() {
            return Err("Index too large for inputs");
        }
        tmp.inputs[index].script_sig = pubkey;

        let lower_sighash_bits = sighash_type & 0x1F;
        match lower_sighash_bits {
            sighash::NONE | sighash::SINGLE => {
                // Clear all sequences numbers
                for i in 0..tmp.inputs.len() {
                    if i != index {
                        tmp.inputs[i].seq_no = 0;
                    }
                }

                // Make the appropriate update
                match lower_sighash_bits {
                    sighash::NONE => {
                        tmp.outputs = vec![];
                    }
                    sighash::SINGLE => {
                        if index > tmp.outputs.len() {
                            return Err("Index too large for outputs");
                        }
                        let out = tmp.outputs[index].clone();
                        tmp.outputs = vec![out];
                    }
                    _ => {}
                }
            }
            _ => {
                return Err("Invalid, sighash type unknown");
            }
        }

        if (sighash_type & sighash::ANYONECANPAY) != 0 {
            let inp = tmp.inputs[index].clone();
            tmp.inputs = vec![inp];
        }

        let mut result = vec![];
        result.extend(tmp.serialize());
        result.push(sighash_type);

        return Ok(result);
    }

    pub fn sighash(&self, sighash_type: u8, index: usize, pubkey: Vec<u8>) -> Result<Vec<u8>, &'static str> {
        match self.sighash_serialize(sighash_type, index, pubkey) {
            Ok(serialized) => {
                Sha256::digest(serialized.as_slice());
                return Ok(Sha256::digest(serialized.as_slice()).to_vec());
            }
            Err(err) => {
                return Err(err);
            }
        }
    }
}







#[cfg(test)]
mod tests {
    use super::*;
    use hex;

    #[test]
    fn serialization_test() {
        let tx1 = "0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000";
        let want = hex::decode(tx1).unwrap();
        let got = Tx::deserialize(want.clone())
            .serialize();


        println!("{:?}", want);
        println!("{:?}", got);
        if want.len() != got.len() {
            panic!("bad sized serialized vector got={}, want={}", got.len(), want.len());
        }
        want.iter().enumerate().zip(got.iter())
            .for_each(|((wi, w), g)| {
                if w != g {
                    println!("Looking at index {}", wi);
                    assert_eq!(w,g, "Not all bytes are equal from serialization");
                }
            });
    }
}