chia-sdk-types 0.27.1

Standard Chia types for things such as puzzle info and conditions.
Documentation
use std::{collections::HashMap, fs, io, path::Path, rc::Rc};

use clvm_tools_rs::{
    classic::clvm_tools::clvmc::compile_clvm_text,
    compiler::{compiler::DefaultCompilerOpts, comptypes::CompilerOpts},
};
use clvm_utils::{tree_hash, TreeHash};
use clvmr::{serde::node_to_bytes, Allocator};
use thiserror::Error;

#[derive(Debug, Error)]
pub enum LoadClvmError {
    #[error("IO error: {0}")]
    Io(#[from] io::Error),

    #[error("Invalid file name")]
    InvalidFileName,

    #[error("Compiler error: {0}")]
    Compiler(String),
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Compilation {
    pub reveal: Vec<u8>,
    pub hash: TreeHash,
}

pub fn load_clvm<P: AsRef<Path>>(
    path: P,
    include_paths: &[String],
) -> Result<Compilation, LoadClvmError> {
    let path = path.as_ref();

    let mut allocator = Allocator::new();

    let opts = Rc::new(DefaultCompilerOpts::new(
        path.file_name()
            .ok_or(LoadClvmError::InvalidFileName)?
            .to_str()
            .ok_or(LoadClvmError::InvalidFileName)?,
    ))
    .set_search_paths(include_paths);

    let text = fs::read_to_string(path)?;

    let ptr = compile_clvm_text(
        &mut allocator,
        opts,
        &mut HashMap::new(),
        &text,
        path.to_str().ok_or(LoadClvmError::InvalidFileName)?,
        false,
    )
    .map_err(|error| LoadClvmError::Compiler(format!("{error:?}")))?;

    let hash = tree_hash(&allocator, ptr);
    let reveal = node_to_bytes(&allocator, ptr)?;

    Ok(Compilation { reveal, hash })
}

#[cfg(test)]
mod tests {
    use std::borrow::Cow;

    use clvm_traits::{FromClvm, ToClvm};
    use clvm_utils::CurriedProgram;
    use clvmr::{serde::node_from_bytes, NodePtr};
    use once_cell::sync::Lazy;

    use crate::{run_puzzle, Mod};

    use super::*;

    #[test]
    fn test_load_clvm() -> anyhow::Result<()> {
        #[derive(Debug, Clone, PartialEq, Eq, Hash, ToClvm, FromClvm)]
        #[clvm(curry)]
        struct TestArgs {
            a: u64,
            b: u64,
        }

        static TEST_MOD: Lazy<Compilation> = Lazy::new(|| {
            load_clvm(
                "load_clvm_test.clsp",
                &[".".to_string(), "include".to_string()],
            )
            .unwrap()
        });

        impl Mod for TestArgs {
            fn mod_reveal() -> Cow<'static, [u8]> {
                Cow::Owned(TEST_MOD.reveal.clone())
            }

            fn mod_hash() -> TreeHash {
                TEST_MOD.hash
            }
        }

        let args = TestArgs { a: 10, b: 20 };

        let mut allocator = Allocator::new();

        let mod_ptr = node_from_bytes(&mut allocator, TestArgs::mod_reveal().as_ref())?;

        let ptr = CurriedProgram {
            program: mod_ptr,
            args,
        }
        .to_clvm(&mut allocator)?;

        let output = run_puzzle(&mut allocator, ptr, NodePtr::NIL)?;

        assert_eq!(hex::encode(node_to_bytes(&allocator, output)?), "8200e6");

        Ok(())
    }
}