dg_xch_core 2.1.1

Core library containing type/error definitions, CLVM tools, Consensus and Pool definitions
Documentation
use crate::clvm::sexp::SExp;
use crate::formatting::{i32_from_slice, number_from_slice};
use num_bigint::BigInt;
use std::io::{Error, ErrorKind};

pub const NO_NEG_DIV: u32 = 0x0001;
pub const NO_UNKNOWN_OPS: u32 = 0x0002;
pub const COND_CANON_INTS: u32 = 0x0001_0000;
pub const NO_UNKNOWN_CONDS: u32 = 0x20000;
pub const COND_ARGS_NIL: u32 = 0x40000;
pub const STRICT_ARGS_COUNT: u32 = 0x80000;
pub const MEMPOOL_MODE: u32 =
    NO_NEG_DIV | COND_CANON_INTS | NO_UNKNOWN_CONDS | NO_UNKNOWN_OPS | COND_ARGS_NIL;
pub const INFINITE_COST: u64 = 0x7FFF_FFFF_FFFF_FFFF;

pub fn check_cost(cost: u64, max_cost: u64) -> Result<(), Error> {
    if cost > max_cost {
        Err(Error::new(
            ErrorKind::InvalidData,
            format!("cost {cost} exceeded {max_cost}"),
        ))
    } else {
        Ok(())
    }
}

pub fn check_arg_count(args: &SExp, expected: usize, name: &str) -> Result<(), Error> {
    if args.arg_count(expected) == expected {
        Ok(())
    } else {
        Err(Error::new(
            ErrorKind::InvalidData,
            format!(
                "{name} takes exactly {expected} argument{}",
                if expected == 1 { "" } else { "s" }
            ),
        ))
    }
}

pub fn int_atom<'a>(args: &'a SExp, op_name: &str) -> Result<&'a [u8], Error> {
    args.atom().map(|b| b.data.as_slice()).map_err(|_| {
        Error::new(
            ErrorKind::InvalidInput,
            format!("{op_name} requires int args: Got {args}"),
        )
    })
}

pub fn atom<'a>(args: &'a SExp, op_name: &str) -> Result<&'a [u8], Error> {
    args.atom()
        .map(|b| b.data.as_slice())
        .map_err(|_| Error::new(ErrorKind::InvalidInput, format!("{op_name} on list")))
}

pub fn two_ints(args: &SExp, op_name: &str) -> Result<(BigInt, usize, BigInt, usize), Error> {
    check_arg_count(args, 2, op_name)?;
    let a0 = args.first()?;
    let a1 = args.rest()?.first()?;
    let n0 = int_atom(a0, op_name)?;
    let n1 = int_atom(a1, op_name)?;
    Ok((
        number_from_slice(n0),
        n0.len(),
        number_from_slice(n1),
        n1.len(),
    ))
}

pub fn i32_atom(args: &SExp, op_name: &str) -> Result<i32, Error> {
    let Ok(buf) = args.atom() else {
        return Err(Error::new(
            ErrorKind::InvalidData,
            format!("{op_name} requires int32 args"),
        ));
    };
    match i32_from_slice(&buf.data) {
        Some(v) => Ok(v),
        _ => Err(Error::new(
            ErrorKind::InvalidData,
            format!("{op_name} requires int32 args (with no leading zeros)"),
        )),
    }
}