pub fn validate_transaction(transaction: &Transaction) -> Result<ValidTransaction, &'static str> {
        // Check basic requirements
        ensure!(!transaction.inputs.is_empty(), "no inputs");
        ensure!(!transaction.outputs.is_empty(), "no outputs");

        {
            let input_set: BTreeMap<_, ()> =transaction.inputs.iter().map(|input| (input, ())).collect();
            ensure!(input_set.len() == transaction.inputs.len(), "each input must only be used once");
        }
        {
            let output_set: BTreeMap<_, ()> = transaction.outputs.iter().map(|output| (output, ())).collect();
            ensure!(output_set.len() == transaction.outputs.len(), "each output must be defined only once");
        }

        let mut total_input: Value = 0;
        let mut total_output: Value = 0;
        let mut output_index: u64 = 0;
        let simple_transaction = Self::get_simple_transaction(transaction);

        // Variables sent to transaction pool
        let mut missing_utxos = Vec::new();
        let mut new_utxos = Vec::new();
        let mut reward = 0;

        // Check that inputs are valid
        for input in transaction.inputs.iter() {
            if let Some(input_utxo) = <UtxoStore>::get(&input.outpoint) {
                ensure!(sp_io::crypto::sr25519_verify(
                    &Signature::from_raw(*input.sigscript.as_fixed_bytes()),
                    &simple_transaction,
                    &Public::from_h256(input_utxo.pubkey)
                ), "signature must be valid" );
                total_input = total_input.checked_add(input_utxo.value).ok_or("input value overflow")?;
            } else {
                missing_utxos.push(input.outpoint.clone().as_fixed_bytes().to_vec()); // TODO is clone needed here?
            }
        }

        // Check that outputs are valid
        for output in transaction.outputs.iter() {
            ensure!(output.value > 0, "output value must be nonzero");
            let hash = BlakeTwo256::hash_of(&(&transaction.encode(), output_index));
            output_index = output_index.checked_add(1).ok_or("output index overflow")?;
            ensure!(!<UtxoStore>::exists(hash), "output already exists");
            total_output = total_output.checked_add(output.value).ok_or("output value overflow")?;
            new_utxos.push(hash.as_fixed_bytes().to_vec());
        }
        
        // If no race condition, check the math
        if missing_utxos.is_empty() {
            ensure!( total_input >= total_output, "output value must not exceed input value");
            reward = total_input.checked_sub(total_output).ok_or("reward underflow")?;
        }

        // Returns transaction details
        Ok(ValidTransaction {
            requires: missing_utxos,
            provides: new_utxos,
            priority: reward as u64,
            longevity: TransactionLongevity::max_value(),
            propagate: true,
        })
    }
/// Check transaction for validity, errors, & race conditions
/// Called by both transaction pool and runtime execution
/// 
/// Ensures that:
/// - inputs and outputs are not empty
/// - all inputs match to existing, unspent and unlocked outputs
/// - each input is used exactly once
/// - each output is defined exactly once and has nonzero value
/// - total output value must not exceed total input value
/// - new outputs do not collide with existing ones
/// - sum of input and output values does not overflow
/// - provided signatures are valid
/// - transaction outputs cannot be modified by malicious nodes
Check transaction for validity, errors, & race conditions
Called by both transaction pool and runtime execution

Ensures that:
inputs and outputs are not empty
all inputs match to existing, unspent and unlocked outputs
each input is used exactly once
each output is defined exactly once and has nonzero value
total output value must not exceed total input value
new outputs do not collide with existing ones
sum of input and output values does not overflow
provided signatures are valid
transaction outputs cannot be modified by malicious nodes
Check transaction for validity errors & race conditions Called by both transaction pool and runtime execution Ensures that : inputs and outputs are not empty all inputs match to existing unspent and unlocked outputs each input is used exactly once each output is defined exactly once and has nonzero value total output value must not exceed total input value new outputs do not collide with existing ones sum of input and output values does not overflow provided signatures are valid transaction outputs cannot be modified by malicious nodes
pub fn validate_transaction(transaction: &Transaction) -> Result<ValidTransaction, &'static str> {
        // Check basic requirements
        ensure!(!transaction.inputs.is_empty(), "no inputs");
        ensure!(!transaction.outputs.is_empty(), "no outputs");
        {
            let input_set: BTreeMap<_, ()> =transaction.inputs.iter().map(|input| (input, ())).collect();
            ensure!(input_set.len() == transaction.inputs.len(), "each input must only be used once");
        }
        {
            let output_set: BTreeMap<_, ()> = transaction.outputs.iter().map(|output| (output, ())).collect();
            ensure!(output_set.len() == transaction.outputs.len(), "each output must be defined only once");
        }
        let mut total_input: Value = 0;
        let mut total_output: Value = 0;
        let mut output_index: u64 = 0;
        let simple_transaction = Self::get_simple_transaction(transaction);
        // Variables sent to transaction pool
        let mut missing_utxos = Vec::new();
        let mut new_utxos = Vec::new();
        let mut reward = 0;
        // Check that inputs are valid
        for input in transaction.inputs.iter() {
            if let Some(input_utxo) = <UtxoStore>::get(&input.outpoint) {
                ensure!(sp_io::crypto::sr25519_verify(
                    &Signature::from_raw(*input.sigscript.as_fixed_bytes()),
                    &simple_transaction,
                    &Public::from_h256(input_utxo.pubkey)
                ), "signature must be valid" );
                total_input = total_input.checked_add(input_utxo.value).ok_or("input value overflow")?;
            } else {
                missing_utxos.push(input.outpoint.clone().as_fixed_bytes().to_vec()); // TODO is clone needed here?
            }
        }
        // Check that outputs are valid
        for output in transaction.outputs.iter() {
            ensure!(output.value > 0, "output value must be nonzero");
            let hash = BlakeTwo256::hash_of(&(&transaction.encode(), output_index));
            output_index = output_index.checked_add(1).ok_or("output index overflow")?;
            ensure!(!<UtxoStore>::exists(hash), "output already exists");
            total_output = total_output.checked_add(output.value).ok_or("output value overflow")?;
            new_utxos.push(hash.as_fixed_bytes().to_vec());
        }
        // If no race condition, check the math
        if missing_utxos.is_empty() {
            ensure!( total_input >= total_output, "output value must not exceed input value");
            reward = total_input.checked_sub(total_output).ok_or("reward underflow")?;
        }
        // Returns transaction details
        Ok(ValidTransaction {
            requires: missing_utxos,
            provides: new_utxos,
            priority: reward as u64,
            longevity: TransactionLongevity::max_value(),
            propagate: true,
        })
    }
pub fn validate_transaction ( transaction : & Transaction ) -> Result < ValidTransaction , & ' static str > { // Check basic requirements ensure ! ( transaction inputs is_empty ( ) " " ) ; ensure ! ( transaction outputs is_empty ( ) " " ) ; { let input_set : BTreeMap < _ , ( ) > = transaction . inputs . iter ( ) . map ( | input | ( input , ( ) ) ) . collect ( ) ; ensure ! ( input_set len ( ) transaction inputs len ( ) " " ) ; } { let output_set : BTreeMap < _ , ( ) > = transaction . outputs . iter ( ) . map ( | output | ( output , ( ) ) ) . collect ( ) ; ensure ! ( output_set len ( ) transaction outputs len ( ) " " ) ; } let mut total_input : Value = 0 ; let mut total_output : Value = 0 ; let mut output_index : u64 = 0 ; let simple_transaction = Self :: get_simple_transaction ( transaction ) ; // Variables sent to transaction pool let mut missing_utxos = Vec :: new ( ) ; let mut new_utxos = Vec :: new ( ) ; let mut reward = 0 ; // Check that inputs are valid for input in transaction . inputs . iter ( ) { if let Some ( input_utxo ) = < UtxoStore > :: get ( & input . outpoint ) { ensure ! ( sp_io crypto sr25519_verify ( Signature from_raw ( input sigscript as_fixed_bytes ( ) ) simple_transaction Public from_h256 ( input_utxo pubkey ) ) " " ) ; total_input = total_input . checked_add ( input_utxo . value ) . ok_or ( " " ) ? ; } else { missing_utxos . push ( input . outpoint . clone ( ) . as_fixed_bytes ( ) . to_vec ( ) ) ; // TODO is clone needed here? } } // Check that outputs are valid for output in transaction . outputs . iter ( ) { ensure ! ( output value 0 " " ) ; let hash = BlakeTwo256 :: hash_of ( & ( & transaction . encode ( ) , output_index ) ) ; output_index = output_index . checked_add ( 1 ) . ok_or ( " " ) ? ; ensure ! ( UtxoStore exists ( hash ) " " ) ; total_output = total_output . checked_add ( output . value ) . ok_or ( " " ) ? ; new_utxos . push ( hash . as_fixed_bytes ( ) . to_vec ( ) ) ; } // If no race condition, check the math if missing_utxos . is_empty ( ) { ensure ! ( total_input total_output " " ) ; reward = total_input . checked_sub ( total_output ) . ok_or ( " " ) ? ; } // Returns transaction details Ok ( ValidTransaction { requires : missing_utxos , provides : new_utxos , priority : reward as u64 , longevity : TransactionLongevity :: max_value ( ) , propagate : true , } ) }
Check transaction for validity, errors, & race conditions
Called by both transaction pool and runtime execution
Check transaction for validity errors & race conditions Called by both transaction pool and runtime execution
transaction
&Transaction
transaction
&Transaction