Skip to main content

chik_sdk_types/
load_klvm.rs

1use std::{collections::HashMap, fs, io, path::Path, rc::Rc};
2
3use klvm_tools_rs::{
4    classic::klvm_tools::klvmc::compile_klvm_text,
5    compiler::{compiler::DefaultCompilerOpts, comptypes::CompilerOpts},
6};
7use klvm_utils::{tree_hash, TreeHash};
8use klvmr::{serde::node_to_bytes, Allocator};
9use thiserror::Error;
10
11#[derive(Debug, Error)]
12pub enum LoadKlvmError {
13    #[error("IO error: {0}")]
14    Io(#[from] io::Error),
15
16    #[error("Invalid file name")]
17    InvalidFileName,
18
19    #[error("Compiler error: {0}")]
20    Compiler(String),
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24pub struct Compilation {
25    pub reveal: Vec<u8>,
26    pub hash: TreeHash,
27}
28
29pub fn load_klvm<P: AsRef<Path>>(
30    path: P,
31    include_paths: &[String],
32) -> Result<Compilation, LoadKlvmError> {
33    let path = path.as_ref();
34
35    let mut allocator = Allocator::new();
36
37    let opts = Rc::new(DefaultCompilerOpts::new(
38        path.file_name()
39            .ok_or(LoadKlvmError::InvalidFileName)?
40            .to_str()
41            .ok_or(LoadKlvmError::InvalidFileName)?,
42    ))
43    .set_search_paths(include_paths);
44
45    let text = fs::read_to_string(path)?;
46
47    let ptr = compile_klvm_text(
48        &mut allocator,
49        opts,
50        &mut HashMap::new(),
51        &text,
52        path.to_str().ok_or(LoadKlvmError::InvalidFileName)?,
53        false,
54    )
55    .map_err(|error| LoadKlvmError::Compiler(format!("{error:?}")))?;
56
57    let hash = tree_hash(&allocator, ptr);
58    let reveal = node_to_bytes(&allocator, ptr)?;
59
60    Ok(Compilation { reveal, hash })
61}
62
63#[cfg(test)]
64mod tests {
65    use std::borrow::Cow;
66
67    use klvm_traits::{FromKlvm, ToKlvm};
68    use klvm_utils::CurriedProgram;
69    use klvmr::{serde::node_from_bytes, NodePtr};
70    use once_cell::sync::Lazy;
71
72    use crate::{run_puzzle, Mod};
73
74    use super::*;
75
76    #[test]
77    fn test_load_klvm() -> anyhow::Result<()> {
78        #[derive(Debug, Clone, PartialEq, Eq, Hash, ToKlvm, FromKlvm)]
79        #[klvm(curry)]
80        struct TestArgs {
81            a: u64,
82            b: u64,
83        }
84
85        static TEST_MOD: Lazy<Compilation> = Lazy::new(|| {
86            load_klvm(
87                "load_klvm_test.clsp",
88                &[".".to_string(), "include".to_string()],
89            )
90            .unwrap()
91        });
92
93        impl Mod for TestArgs {
94            fn mod_reveal() -> Cow<'static, [u8]> {
95                Cow::Owned(TEST_MOD.reveal.clone())
96            }
97
98            fn mod_hash() -> TreeHash {
99                TEST_MOD.hash
100            }
101        }
102
103        let args = TestArgs { a: 10, b: 20 };
104
105        let mut allocator = Allocator::new();
106
107        let mod_ptr = node_from_bytes(&mut allocator, TestArgs::mod_reveal().as_ref())?;
108
109        let ptr = CurriedProgram {
110            program: mod_ptr,
111            args,
112        }
113        .to_klvm(&mut allocator)?;
114
115        let output = run_puzzle(&mut allocator, ptr, NodePtr::NIL)?;
116
117        assert_eq!(hex::encode(node_to_bytes(&allocator, output)?), "8200e6");
118
119        Ok(())
120    }
121}