casper_types/cl_value/
jsonrepr.rs

1use alloc::{string::String, vec::Vec};
2
3use serde::Serialize;
4use serde_json::{json, Value};
5
6use crate::{
7    bytesrepr::{self, FromBytes, OPTION_NONE_TAG, OPTION_SOME_TAG, RESULT_ERR_TAG, RESULT_OK_TAG},
8    cl_type::CL_TYPE_RECURSION_DEPTH,
9    CLType, CLValue, Key, PublicKey, URef, U128, U256, U512,
10};
11
12/// Returns a best-effort attempt to convert the `CLValue` into a meaningful JSON value.
13pub fn cl_value_to_json(cl_value: &CLValue) -> Option<Value> {
14    depth_limited_to_json(0, cl_value.cl_type(), cl_value.inner_bytes()).and_then(
15        |(json_value, remainder)| {
16            if remainder.is_empty() {
17                Some(json_value)
18            } else {
19                None
20            }
21        },
22    )
23}
24
25fn depth_limited_to_json<'a>(
26    depth: u8,
27    cl_type: &CLType,
28    bytes: &'a [u8],
29) -> Option<(Value, &'a [u8])> {
30    if depth >= CL_TYPE_RECURSION_DEPTH {
31        return None;
32    }
33    let depth = depth + 1;
34
35    match cl_type {
36        CLType::Bool => simple_type_to_json::<bool>(bytes),
37        CLType::I32 => simple_type_to_json::<i32>(bytes),
38        CLType::I64 => simple_type_to_json::<i64>(bytes),
39        CLType::U8 => simple_type_to_json::<u8>(bytes),
40        CLType::U32 => simple_type_to_json::<u32>(bytes),
41        CLType::U64 => simple_type_to_json::<u64>(bytes),
42        CLType::U128 => simple_type_to_json::<U128>(bytes),
43        CLType::U256 => simple_type_to_json::<U256>(bytes),
44        CLType::U512 => simple_type_to_json::<U512>(bytes),
45        CLType::Unit => simple_type_to_json::<()>(bytes),
46        CLType::String => simple_type_to_json::<String>(bytes),
47        CLType::Key => simple_type_to_json::<Key>(bytes),
48        CLType::URef => simple_type_to_json::<URef>(bytes),
49        CLType::PublicKey => simple_type_to_json::<PublicKey>(bytes),
50        CLType::Option(inner_cl_type) => {
51            let (variant, remainder) = u8::from_bytes(bytes).ok()?;
52            match variant {
53                OPTION_NONE_TAG => Some((Value::Null, remainder)),
54                OPTION_SOME_TAG => Some(depth_limited_to_json(depth, inner_cl_type, remainder)?),
55                _ => None,
56            }
57        }
58        CLType::List(inner_cl_type) => {
59            let (count, mut stream) = u32::from_bytes(bytes).ok()?;
60            let mut result: Vec<Value> = Vec::new();
61            for _ in 0..count {
62                let (value, remainder) = depth_limited_to_json(depth, inner_cl_type, stream)?;
63                result.push(value);
64                stream = remainder;
65            }
66            Some((json!(result), stream))
67        }
68        CLType::ByteArray(length) => {
69            let (bytes, remainder) = bytesrepr::safe_split_at(bytes, *length as usize).ok()?;
70            let hex_encoded_bytes = base16::encode_lower(&bytes);
71            Some((json![hex_encoded_bytes], remainder))
72        }
73        CLType::Result { ok, err } => {
74            let (variant, remainder) = u8::from_bytes(bytes).ok()?;
75            match variant {
76                RESULT_ERR_TAG => {
77                    let (value, remainder) = depth_limited_to_json(depth, err, remainder)?;
78                    Some((json!({ "Err": value }), remainder))
79                }
80                RESULT_OK_TAG => {
81                    let (value, remainder) = depth_limited_to_json(depth, ok, remainder)?;
82                    Some((json!({ "Ok": value }), remainder))
83                }
84                _ => None,
85            }
86        }
87        CLType::Map { key, value } => {
88            let (num_keys, mut stream) = u32::from_bytes(bytes).ok()?;
89            let mut result: Vec<Value> = Vec::new();
90            for _ in 0..num_keys {
91                let (k, remainder) = depth_limited_to_json(depth, key, stream)?;
92                let (v, remainder) = depth_limited_to_json(depth, value, remainder)?;
93                result.push(json!({"key": k, "value": v}));
94                stream = remainder;
95            }
96            Some((json!(result), stream))
97        }
98        CLType::Tuple1(arr) => {
99            let (t1, remainder) = depth_limited_to_json(depth, &arr[0], bytes)?;
100            Some((json!([t1]), remainder))
101        }
102        CLType::Tuple2(arr) => {
103            let (t1, remainder) = depth_limited_to_json(depth, &arr[0], bytes)?;
104            let (t2, remainder) = depth_limited_to_json(depth, &arr[1], remainder)?;
105            Some((json!([t1, t2]), remainder))
106        }
107        CLType::Tuple3(arr) => {
108            let (t1, remainder) = depth_limited_to_json(depth, &arr[0], bytes)?;
109            let (t2, remainder) = depth_limited_to_json(depth, &arr[1], remainder)?;
110            let (t3, remainder) = depth_limited_to_json(depth, &arr[2], remainder)?;
111            Some((json!([t1, t2, t3]), remainder))
112        }
113        CLType::Any => None,
114    }
115}
116
117fn simple_type_to_json<T: FromBytes + Serialize>(bytes: &[u8]) -> Option<(Value, &[u8])> {
118    let (value, remainder) = T::from_bytes(bytes).ok()?;
119    Some((json!(value), remainder))
120}
121
122#[cfg(test)]
123mod tests {
124    use super::*;
125    use crate::{bytesrepr::ToBytes, AsymmetricType, CLTyped, SecretKey};
126    use alloc::collections::BTreeMap;
127
128    fn test_value<T: ToBytes + Serialize + Clone + CLTyped>(value: T) {
129        let cl_value = CLValue::from_t(value.clone()).unwrap();
130        let cl_value_as_json: Value = cl_value_to_json(&cl_value).unwrap();
131        let expected = json!(value);
132        assert_eq!(cl_value_as_json, expected);
133    }
134
135    #[test]
136    fn list_of_ints_to_json_value() {
137        test_value::<Vec<i32>>(vec![]);
138        test_value(vec![10u32, 12u32]);
139    }
140
141    #[test]
142    fn list_of_bools_to_json_value() {
143        test_value(vec![true, false]);
144    }
145
146    #[test]
147    fn list_of_string_to_json_value() {
148        test_value(vec!["rust", "python"]);
149    }
150
151    #[test]
152    fn list_of_public_keys_to_json_value() {
153        let a = PublicKey::from(
154            &SecretKey::secp256k1_from_bytes([3; SecretKey::SECP256K1_LENGTH]).unwrap(),
155        );
156        let b = PublicKey::from(
157            &SecretKey::ed25519_from_bytes([3; SecretKey::ED25519_LENGTH]).unwrap(),
158        );
159        let a_hex = a.to_hex();
160        let b_hex = b.to_hex();
161        let cl_value = CLValue::from_t(vec![a, b]).unwrap();
162        let cl_value_as_json: Value = cl_value_to_json(&cl_value).unwrap();
163        let expected = json!([a_hex, b_hex]);
164        assert_eq!(cl_value_as_json, expected);
165    }
166
167    #[test]
168    fn list_of_list_of_public_keys_to_json_value() {
169        let a = PublicKey::from(
170            &SecretKey::secp256k1_from_bytes([3; SecretKey::SECP256K1_LENGTH]).unwrap(),
171        );
172        let b = PublicKey::from(
173            &SecretKey::ed25519_from_bytes([3; PublicKey::ED25519_LENGTH]).unwrap(),
174        );
175        let c = PublicKey::from(
176            &SecretKey::ed25519_from_bytes([6; PublicKey::ED25519_LENGTH]).unwrap(),
177        );
178        let a_hex = a.to_hex();
179        let b_hex = b.to_hex();
180        let c_hex = c.to_hex();
181        let cl_value = CLValue::from_t(vec![vec![a, b], vec![c]]).unwrap();
182        let cl_value_as_json: Value = cl_value_to_json(&cl_value).unwrap();
183        let expected = json!([[a_hex, b_hex], [c_hex]]);
184        assert_eq!(cl_value_as_json, expected);
185    }
186
187    #[test]
188    fn map_of_string_to_list_of_ints_to_json_value() {
189        let key1 = String::from("first");
190        let key2 = String::from("second");
191        let value1 = vec![];
192        let value2 = vec![1, 2, 3];
193        let mut map: BTreeMap<String, Vec<i32>> = BTreeMap::new();
194        map.insert(key1.clone(), value1.clone());
195        map.insert(key2.clone(), value2.clone());
196        let cl_value = CLValue::from_t(map).unwrap();
197        let cl_value_as_json: Value = cl_value_to_json(&cl_value).unwrap();
198        let expected = json!([
199            { "key": key1, "value": value1 },
200            { "key": key2, "value": value2 }
201        ]);
202        assert_eq!(cl_value_as_json, expected);
203    }
204
205    #[test]
206    fn option_some_of_lists_to_json_value() {
207        test_value(Some(vec![1, 2, 3]));
208    }
209
210    #[test]
211    fn option_none_to_json_value() {
212        test_value(Option::<i32>::None);
213    }
214
215    #[test]
216    fn bytes_to_json_value() {
217        let bytes = [1_u8, 2];
218        let cl_value = CLValue::from_t(bytes).unwrap();
219        let cl_value_as_json = cl_value_to_json(&cl_value).unwrap();
220        let expected = json!(base16::encode_lower(&bytes));
221        assert_eq!(cl_value_as_json, expected);
222    }
223
224    #[test]
225    fn result_ok_to_json_value() {
226        test_value(Result::<Vec<i32>, String>::Ok(vec![1, 2, 3]));
227    }
228
229    #[test]
230    fn result_error_to_json_value() {
231        test_value(Result::<Vec<i32>, String>::Err(String::from("Upsss")));
232    }
233
234    #[test]
235    fn tuples_to_json_value() {
236        let v1 = String::from("Hello");
237        let v2 = vec![1, 2, 3];
238        let v3 = 1u8;
239
240        test_value((v1.clone(),));
241        test_value((v1.clone(), v2.clone()));
242        test_value((v1, v2, v3));
243    }
244
245    #[test]
246    fn json_encoding_nested_tuple_1_value_should_not_stack_overflow() {
247        // Returns a CLType corresponding to (((...(cl_type,),...),),) nested in tuples to
248        // `depth_limit`.
249        fn wrap_in_tuple1(cl_type: CLType, current_depth: usize, depth_limit: usize) -> CLType {
250            if current_depth == depth_limit {
251                return cl_type;
252            }
253            wrap_in_tuple1(
254                CLType::Tuple1([Box::new(cl_type)]),
255                current_depth + 1,
256                depth_limit,
257            )
258        }
259
260        for depth_limit in &[1, CL_TYPE_RECURSION_DEPTH as usize] {
261            let cl_type = wrap_in_tuple1(CLType::Unit, 1, *depth_limit);
262            let cl_value = CLValue::from_components(cl_type, vec![]);
263            assert!(cl_value_to_json(&cl_value).is_some());
264        }
265
266        for depth_limit in &[CL_TYPE_RECURSION_DEPTH as usize + 1, 1000] {
267            let cl_type = wrap_in_tuple1(CLType::Unit, 1, *depth_limit);
268            let cl_value = CLValue::from_components(cl_type, vec![]);
269            assert!(cl_value_to_json(&cl_value).is_none());
270        }
271    }
272}