dg_xch_core 2.1.4

Core library containing type/error definitions, CLVM tools, Consensus and Pool definitions
Documentation
use crate::blockchain::coin::Coin;
use crate::blockchain::condition_opcode::ConditionOpcode;
use crate::blockchain::condition_with_args::{ConditionWithArgs, Message};
use crate::blockchain::sized_bytes::{Bytes32, Bytes48};
use crate::clvm::condition_utils::{
    agg_sig_additional_data_for_opcode, conditions_for_solution, created_outputs_for_conditions,
};
use crate::clvm::program::SerializedProgram;
use crate::consensus::constants::ConsensusConstants;
use crate::formatting::u64_to_bytes;
use crate::traits::SizedBytes;
use crate::utils::hash_256;
use num_bigint::BigInt;
use std::io::Error;

pub fn additions_for_solution(
    coin_name: Bytes32,
    puzzle_reveal: &SerializedProgram,
    solution: &SerializedProgram,
    max_cost: u64,
) -> Result<Vec<Coin>, Error> {
    let (map, _cost) = conditions_for_solution(puzzle_reveal, solution, max_cost)?;
    created_outputs_for_conditions(&map, coin_name)
}

#[must_use]
pub fn fee_for_solution(
    puzzle_reveal: &SerializedProgram,
    solution: &SerializedProgram,
    max_cost: u64,
) -> BigInt {
    match conditions_for_solution(puzzle_reveal, solution, max_cost) {
        Ok((conditions, _cost)) => {
            let mut total: BigInt = 0.into();
            for condition in conditions {
                match condition {
                    ConditionWithArgs::ReserveFee(fee) => {
                        total += fee;
                    }
                    _ => continue,
                }
            }
            total
        }
        Err(_error) => 0.into(),
    }
}

pub fn pkm_pairs_for_conditions(
    conditions: &[ConditionWithArgs],
    coin: Coin,
    additional_data: &[u8],
) -> Result<Vec<(ConditionOpcode, Bytes48, Message)>, Error> {
    let mut ret = vec![];
    let additional_data = Bytes32::parse(additional_data)?;
    for condition in conditions {
        let agg_sig_additional_data =
            agg_sig_additional_data_for_opcode(additional_data, condition.op_code());
        match condition {
            ConditionWithArgs::AggSigParent(key, message) => {
                let mut msg = message.data().to_vec();
                msg.extend_from_slice(coin.parent_coin_info.as_ref());
                msg.extend_from_slice(agg_sig_additional_data.as_ref());
                ret.push((condition.op_code(), *key, Message::new(msg)?));
            }
            ConditionWithArgs::AggSigPuzzle(key, message) => {
                let mut msg = message.data().to_vec();
                msg.extend_from_slice(coin.puzzle_hash.as_ref());
                msg.extend_from_slice(agg_sig_additional_data.as_ref());
                ret.push((condition.op_code(), *key, Message::new(msg)?));
            }
            ConditionWithArgs::AggSigAmount(key, message) => {
                let mut msg = message.data().to_vec();
                msg.extend_from_slice(&u64_to_bytes(coin.amount));
                msg.extend_from_slice(agg_sig_additional_data.as_ref());
                ret.push((condition.op_code(), *key, Message::new(msg)?));
            }
            ConditionWithArgs::AggSigPuzzleAmount(key, message) => {
                let mut msg = message.data().to_vec();
                msg.extend_from_slice(coin.puzzle_hash.as_ref());
                msg.extend_from_slice(&u64_to_bytes(coin.amount));
                msg.extend_from_slice(agg_sig_additional_data.as_ref());
                ret.push((condition.op_code(), *key, Message::new(msg)?));
            }
            ConditionWithArgs::AggSigParentAmount(key, message) => {
                let mut msg = message.data().to_vec();
                msg.extend_from_slice(coin.parent_coin_info.as_ref());
                msg.extend_from_slice(&u64_to_bytes(coin.amount));
                msg.extend_from_slice(agg_sig_additional_data.as_ref());
                ret.push((condition.op_code(), *key, Message::new(msg)?));
            }
            ConditionWithArgs::AggSigParentPuzzle(key, message) => {
                let mut msg = message.data().to_vec();
                msg.extend_from_slice(coin.parent_coin_info.as_ref());
                msg.extend_from_slice(coin.puzzle_hash.as_ref());
                msg.extend_from_slice(agg_sig_additional_data.as_ref());
                ret.push((condition.op_code(), *key, Message::new(msg)?));
            }
            ConditionWithArgs::AggSigMe(key, message) => {
                let mut msg = message.data().to_vec();
                msg.extend_from_slice(coin.name().as_ref());
                msg.extend_from_slice(agg_sig_additional_data.as_ref());
                ret.push((condition.op_code(), *key, Message::new(msg)?));
            }
            ConditionWithArgs::AggSigUnsafe(key, message) => {
                ret.push((condition.op_code(), *key, *message));
            }
            _ => continue,
        };
    }
    Ok(ret)
}

pub fn verify_agg_sig_unsafe_message(
    message: &Message,
    consensus_constants: &ConsensusConstants,
) -> Result<(), Error> {
    let mut buffer = consensus_constants.agg_sig_me_additional_data.clone();
    let mut forbidden_message_suffix;
    for code in [
        ConditionOpcode::AggSigParent,
        ConditionOpcode::AggSigPuzzle,
        ConditionOpcode::AggSigAmount,
        ConditionOpcode::AggSigPuzzleAmount,
        ConditionOpcode::AggSigParentAmount,
        ConditionOpcode::AggSigParentPuzzle,
    ] {
        buffer.push(code as u8);
        forbidden_message_suffix = Bytes32::from(hash_256(&buffer));
        if message.data().ends_with(forbidden_message_suffix.as_ref()) {
            return Err(Error::other("Invalid Condition"));
        }
        buffer.pop();
    }
    Ok(())
}