buffett-core 0.1.1

Core library for Bitconch:buffett
use bincode::serialize;
use buffett_crypto::hash::{Hash, Hasher};
use buffett_crypto::signature::{Keypair, KeypairUtil, Signature};
use buffett_interface::pubkey::Pubkey;
use std::mem::size_of;

pub const SIGNED_DATA_OFFSET: usize = size_of::<Signature>();
pub const SIG_OFFSET: usize = 0;
pub const PUB_KEY_OFFSET: usize = size_of::<Signature>() + size_of::<u64>();


#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Transaction {
    
    pub signature: Signature,

    pub keys: Vec<Pubkey>,

    pub program_id: Pubkey,

    pub last_id: Hash,

    pub fee: i64,

    pub userdata: Vec<u8>,
}

impl Transaction {
    pub fn new(
        from_keypair: &Keypair,
        transaction_keys: &[Pubkey],
        program_id: Pubkey,
        userdata: Vec<u8>,
        last_id: Hash,
        fee: i64,
    ) -> Self {
        let from = from_keypair.pubkey();
        let mut keys = vec![from];
        keys.extend_from_slice(transaction_keys);
        let mut tx = Transaction {
            signature: Signature::default(),
            keys,
            program_id,
            last_id,
            fee,
            userdata,
        };
        tx.sign(from_keypair);
        tx
    }

    pub fn get_sign_data(&self) -> Vec<u8> {
        let mut data = serialize(&(&self.keys)).expect("serialize keys");

        let program_id = serialize(&(&self.program_id)).expect("serialize program_id");
        data.extend_from_slice(&program_id);

        let last_id_data = serialize(&(&self.last_id)).expect("serialize last_id");
        data.extend_from_slice(&last_id_data);

        let fee_data = serialize(&(&self.fee)).expect("serialize last_id");
        data.extend_from_slice(&fee_data);

        let userdata = serialize(&(&self.userdata)).expect("serialize userdata");
        data.extend_from_slice(&userdata);
        data
    }

    pub fn sign(&mut self, keypair: &Keypair) {
        let sign_data = self.get_sign_data();
        self.signature = Signature::new(keypair.sign(&sign_data).as_ref());
    }

    pub fn verify_signature(&self) -> bool {
        warn!("transaction signature verification called");
        self.signature
            .verify(&self.from().as_ref(), &self.get_sign_data())
    }

    pub fn from(&self) -> &Pubkey {
        &self.keys[0]
    }

    pub fn hash(transactions: &[Transaction]) -> Hash {
        let mut hasher = Hasher::default();
        transactions
            .iter()
            .for_each(|tx| hasher.hash(&tx.signature.as_ref()));
        hasher.result()
    }
}