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
12pub 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 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}