waves_rust/model/
script.rs

1use crate::error::{Error, Result};
2use crate::model::Base64String;
3use crate::util::JsonDeserializer;
4use serde_json::Value;
5use std::collections::HashMap;
6
7#[derive(Eq, PartialEq, Clone, Debug)]
8pub struct ScriptInfo {
9    script: Base64String,
10    complexity: u32,
11    verifier_complexity: u32,
12    callable_complexities: HashMap<String, u32>,
13    extra_fee: u64,
14    script_text: String,
15}
16
17impl ScriptInfo {
18    pub fn new(
19        script: Base64String,
20        complexity: u32,
21        verifier_complexity: u32,
22        callable_complexities: HashMap<String, u32>,
23        extra_fee: u64,
24        script_text: String,
25    ) -> ScriptInfo {
26        ScriptInfo {
27            script,
28            complexity,
29            verifier_complexity,
30            callable_complexities,
31            extra_fee,
32            script_text,
33        }
34    }
35
36    pub fn script(&self) -> Base64String {
37        self.script.clone()
38    }
39
40    pub fn complexity(&self) -> u32 {
41        self.complexity
42    }
43
44    pub fn verifier_complexity(&self) -> u32 {
45        self.verifier_complexity
46    }
47
48    pub fn callable_complexities(&self) -> HashMap<String, u32> {
49        self.callable_complexities.clone()
50    }
51
52    pub fn extra_fee(&self) -> u64 {
53        self.extra_fee
54    }
55
56    pub fn script_text(&self) -> String {
57        self.script_text.clone()
58    }
59}
60
61impl TryFrom<&Value> for ScriptInfo {
62    type Error = Error;
63
64    fn try_from(value: &Value) -> Result<Self> {
65        let script = Base64String::from_string(
66            &JsonDeserializer::safe_to_string_from_field(value, "script")
67                .unwrap_or_else(|_| "".to_owned()),
68        )?;
69        let complexity = JsonDeserializer::safe_to_int_from_field(value, "complexity")? as u32;
70        let verifier_complexity =
71            JsonDeserializer::safe_to_int_from_field(value, "verifierComplexity")? as u32;
72        let callable_complexities: HashMap<String, u32> =
73            JsonDeserializer::safe_to_map_from_field(value, "callableComplexities")?
74                .into_iter()
75                .map(|entry| {
76                    Ok((
77                        entry.0.to_owned(),
78                        JsonDeserializer::safe_to_int(&entry.1)? as u32,
79                    ))
80                })
81                .collect::<Result<HashMap<String, u32>>>()?;
82        let extra_fee = JsonDeserializer::safe_to_int_from_field(value, "extraFee")? as u64;
83        let script_text = JsonDeserializer::safe_to_string_from_field(value, "scriptText")
84            .unwrap_or_else(|_| "".to_owned());
85        Ok(ScriptInfo::new(
86            script,
87            complexity,
88            verifier_complexity,
89            callable_complexities,
90            extra_fee,
91            script_text,
92        ))
93    }
94}
95
96#[derive(Eq, PartialEq, Clone, Debug)]
97pub struct ScriptMeta {
98    meta_version: u32,
99    callable_functions: HashMap<String, Vec<ArgMeta>>,
100}
101
102impl ScriptMeta {
103    pub fn new(meta_version: u32, callable_functions: HashMap<String, Vec<ArgMeta>>) -> ScriptMeta {
104        ScriptMeta {
105            meta_version,
106            callable_functions,
107        }
108    }
109
110    pub fn meta_version(&self) -> u32 {
111        self.meta_version
112    }
113
114    pub fn callable_functions(&self) -> HashMap<String, Vec<ArgMeta>> {
115        self.callable_functions.clone()
116    }
117}
118
119impl TryFrom<&Value> for ScriptMeta {
120    type Error = Error;
121
122    fn try_from(value: &Value) -> Result<Self> {
123        let meta_version: u32 =
124            JsonDeserializer::safe_to_string_from_field(&value["meta"], "version")?
125                .parse()
126                .unwrap_or(0);
127        if meta_version == 0 {
128            return Ok(ScriptMeta::new(meta_version, HashMap::new()));
129        }
130        let callable_func_types =
131            JsonDeserializer::safe_to_map_from_field(&value["meta"], "callableFuncTypes")?;
132
133        let callable_functions: HashMap<String, Vec<ArgMeta>> = callable_func_types
134            .into_iter()
135            .map(|entry| {
136                let arg_meta = JsonDeserializer::safe_to_array(&entry.1)?
137                    .iter()
138                    .map(|arg| arg.try_into())
139                    .collect::<Result<Vec<ArgMeta>>>()?;
140                Ok((entry.0, arg_meta))
141            })
142            .collect::<Result<HashMap<String, Vec<ArgMeta>>>>()?;
143        Ok(ScriptMeta::new(meta_version, callable_functions))
144    }
145}
146
147#[derive(Eq, PartialEq, Clone, Debug)]
148pub struct ArgMeta {
149    arg_name: String,
150    arg_type: String,
151}
152
153impl TryFrom<&Value> for ArgMeta {
154    type Error = Error;
155
156    fn try_from(value: &Value) -> Result<Self> {
157        let arg_name = JsonDeserializer::safe_to_string_from_field(value, "name")?;
158        let arg_type = JsonDeserializer::safe_to_string_from_field(value, "type")?;
159        Ok(ArgMeta::new(arg_name, arg_type))
160    }
161}
162
163impl ArgMeta {
164    pub fn new(arg_name: String, arg_type: String) -> ArgMeta {
165        ArgMeta { arg_name, arg_type }
166    }
167
168    pub fn arg_name(&self) -> String {
169        self.arg_name.clone()
170    }
171
172    pub fn arg_type(&self) -> String {
173        self.arg_type.clone()
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use crate::error::Result;
180    use crate::model::{ByteString, ScriptInfo, ScriptMeta};
181
182    use serde_json::Value;
183    use std::borrow::Borrow;
184    use std::fs;
185
186    #[test]
187    fn test_json_to_script_info() -> Result<()> {
188        let data = fs::read_to_string("./tests/resources/addresses/script_info_rs.json")
189            .expect("Unable to read file");
190        let json: Value = serde_json::from_str(&data).expect("failed to generate json from str");
191
192        let script_info: ScriptInfo = json.borrow().try_into()?;
193
194        assert_eq!(
195            script_info.script().encoded_with_prefix(),
196            "base64:AAIFAAAAAAAAAA=="
197        );
198        assert_eq!(script_info.complexity(), 14);
199        assert_eq!(script_info.verifier_complexity(), 0);
200        assert_eq!(script_info.callable_complexities()["storeData"], 14);
201        assert_eq!(script_info.extra_fee(), 0);
202        assert_eq!(
203            script_info.script_text(),
204            "DApp(DAppMeta(2,Vector(CallableFuncSignature))"
205        );
206        Ok(())
207    }
208
209    #[test]
210    fn test_json_to_script_meta() -> Result<()> {
211        let data = fs::read_to_string("./tests/resources/addresses/script_meta_rs.json")
212            .expect("Unable to read file");
213        let json: Value = serde_json::from_str(&data).expect("failed to generate json from str");
214
215        let script_meta: ScriptMeta = json.borrow().try_into()?;
216
217        assert_eq!(script_meta.meta_version(), 2);
218        let function_args_meta = &script_meta.callable_functions()["storeData"];
219
220        assert_eq!(function_args_meta[0].arg_type, "Boolean");
221        assert_eq!(function_args_meta[0].arg_name, "bool");
222
223        assert_eq!(function_args_meta[1].arg_type, "String");
224        assert_eq!(function_args_meta[1].arg_name, "string");
225
226        assert_eq!(function_args_meta[2].arg_type, "Int");
227        assert_eq!(function_args_meta[2].arg_name, "integer");
228
229        assert_eq!(function_args_meta[3].arg_type, "ByteVector");
230        assert_eq!(function_args_meta[3].arg_name, "binary");
231
232        assert_eq!(function_args_meta[4].arg_type, "List[Int]");
233        assert_eq!(function_args_meta[4].arg_name, "list");
234
235        Ok(())
236    }
237}