1use std::{rc::Rc, sync::Arc};
2
3use num_bigint::BigInt;
4
5use crate::{decode_number, ClvmDecoder, FromClvmError};
6
7pub trait FromClvm<D>: Sized
8where
9 D: ClvmDecoder,
10{
11 fn from_clvm(decoder: &D, node: D::Node) -> Result<Self, FromClvmError>;
12}
13
14macro_rules! clvm_primitive {
15 ($primitive:ty, $signed:expr) => {
16 impl<N, D: ClvmDecoder<Node = N>> FromClvm<D> for $primitive {
17 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
18 const LEN: usize = std::mem::size_of::<$primitive>();
19
20 let atom = decoder.decode_atom(&node)?;
21 let slice = atom.as_ref();
22
23 let Some(bytes) = decode_number(slice, $signed) else {
24 return Err(FromClvmError::WrongAtomLength {
25 expected: LEN,
26 found: slice.len(),
27 });
28 };
29
30 Ok(<$primitive>::from_be_bytes(bytes))
31 }
32 }
33 };
34}
35
36clvm_primitive!(u8, false);
37clvm_primitive!(i8, true);
38clvm_primitive!(u16, false);
39clvm_primitive!(i16, true);
40clvm_primitive!(u32, false);
41clvm_primitive!(i32, true);
42clvm_primitive!(u64, false);
43clvm_primitive!(i64, true);
44clvm_primitive!(u128, false);
45clvm_primitive!(i128, true);
46clvm_primitive!(usize, false);
47clvm_primitive!(isize, true);
48
49impl<N, D: ClvmDecoder<Node = N>> FromClvm<D> for BigInt {
50 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
51 decoder.decode_bigint(&node)
52 }
53}
54
55impl<N, D: ClvmDecoder<Node = N>> FromClvm<D> for bool {
56 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
57 let atom = decoder.decode_atom(&node)?;
58 match atom.as_ref() {
59 [] => Ok(false),
60 [1] => Ok(true),
61 _ => Err(FromClvmError::Custom(
62 "expected boolean value of either `()` or `1`".to_string(),
63 )),
64 }
65 }
66}
67
68impl<N, D: ClvmDecoder<Node = N>, T> FromClvm<D> for Box<T>
69where
70 T: FromClvm<D>,
71{
72 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
73 T::from_clvm(decoder, node).map(Box::new)
74 }
75}
76
77impl<N, D: ClvmDecoder<Node = N>, T> FromClvm<D> for Rc<T>
78where
79 T: FromClvm<D>,
80{
81 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
82 T::from_clvm(decoder, node).map(Rc::new)
83 }
84}
85
86impl<N, D: ClvmDecoder<Node = N>, T> FromClvm<D> for Arc<T>
87where
88 T: FromClvm<D>,
89{
90 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
91 T::from_clvm(decoder, node).map(Arc::new)
92 }
93}
94
95impl<N, D: ClvmDecoder<Node = N>, A, B> FromClvm<D> for (A, B)
96where
97 A: FromClvm<D>,
98 B: FromClvm<D>,
99{
100 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
101 let (first, rest) = decoder.decode_pair(&node)?;
102 let first = A::from_clvm(decoder, first)?;
103 let rest = B::from_clvm(decoder, rest)?;
104 Ok((first, rest))
105 }
106}
107
108impl<N, D: ClvmDecoder<Node = N>> FromClvm<D> for () {
109 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
110 let bytes = decoder.decode_atom(&node)?;
111 if bytes.as_ref().is_empty() {
112 Ok(())
113 } else {
114 Err(FromClvmError::WrongAtomLength {
115 expected: 0,
116 found: bytes.as_ref().len(),
117 })
118 }
119 }
120}
121
122impl<N, D: ClvmDecoder<Node = N>, T, const LEN: usize> FromClvm<D> for [T; LEN]
123where
124 T: FromClvm<D>,
125{
126 fn from_clvm(decoder: &D, mut node: N) -> Result<Self, FromClvmError> {
127 let mut items = Vec::with_capacity(LEN);
128 loop {
129 if let Ok((first, rest)) = decoder.decode_pair(&node) {
130 if items.len() >= LEN {
131 return Err(FromClvmError::ExpectedAtom);
132 }
133
134 items.push(T::from_clvm(decoder, first)?);
135 node = rest;
136 } else {
137 let bytes = decoder.decode_atom(&node)?;
138 if bytes.as_ref().is_empty() {
139 return items.try_into().or(Err(FromClvmError::ExpectedPair));
140 }
141
142 return Err(FromClvmError::WrongAtomLength {
143 expected: 0,
144 found: bytes.as_ref().len(),
145 });
146 }
147 }
148 }
149}
150
151impl<N, D: ClvmDecoder<Node = N>, T> FromClvm<D> for Vec<T>
152where
153 T: FromClvm<D>,
154{
155 fn from_clvm(decoder: &D, mut node: N) -> Result<Self, FromClvmError> {
156 let mut items = Vec::new();
157 loop {
158 if let Ok((first, rest)) = decoder.decode_pair(&node) {
159 items.push(T::from_clvm(decoder, first)?);
160 node = rest;
161 } else {
162 let bytes = decoder.decode_atom(&node)?;
163 if bytes.as_ref().is_empty() {
164 return Ok(items);
165 }
166
167 return Err(FromClvmError::WrongAtomLength {
168 expected: 0,
169 found: bytes.as_ref().len(),
170 });
171 }
172 }
173 }
174}
175
176impl<N, D: ClvmDecoder<Node = N>, T> FromClvm<D> for Option<T>
177where
178 T: FromClvm<D>,
179{
180 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
181 if let Ok(atom) = decoder.decode_atom(&node) {
182 if atom.as_ref().is_empty() {
183 return Ok(None);
184 }
185 }
186 Ok(Some(T::from_clvm(decoder, node)?))
187 }
188}
189
190impl<N, D: ClvmDecoder<Node = N>> FromClvm<D> for String {
191 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
192 let bytes = decoder.decode_atom(&node)?;
193 Ok(Self::from_utf8(bytes.as_ref().to_vec())?)
194 }
195}
196
197#[cfg(feature = "chia-bls")]
198impl<N, D: ClvmDecoder<Node = N>> FromClvm<D> for chia_bls::PublicKey {
199 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
200 let bytes = decoder.decode_atom(&node)?;
201 let error = Err(FromClvmError::WrongAtomLength {
202 expected: 48,
203 found: bytes.as_ref().len(),
204 });
205 let bytes: [u8; 48] = bytes.as_ref().try_into().or(error)?;
206 Self::from_bytes(&bytes).map_err(|error| FromClvmError::Custom(error.to_string()))
207 }
208}
209
210#[cfg(feature = "chia-bls")]
211impl<N, D: ClvmDecoder<Node = N>> FromClvm<D> for chia_bls::Signature {
212 fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
213 let bytes = decoder.decode_atom(&node)?;
214 let error = Err(FromClvmError::WrongAtomLength {
215 expected: 96,
216 found: bytes.as_ref().len(),
217 });
218 let bytes: [u8; 96] = bytes.as_ref().try_into().or(error)?;
219 Self::from_bytes(&bytes).map_err(|error| FromClvmError::Custom(error.to_string()))
220 }
221}
222
223#[cfg(feature = "chia-secp")]
224impl<D> FromClvm<D> for chia_secp::K1PublicKey
225where
226 D: ClvmDecoder,
227{
228 fn from_clvm(decoder: &D, node: D::Node) -> Result<Self, FromClvmError> {
229 let atom = decoder.decode_atom(&node)?;
230 let bytes: [u8; Self::SIZE] =
231 atom.as_ref()
232 .try_into()
233 .map_err(|_| FromClvmError::WrongAtomLength {
234 expected: Self::SIZE,
235 found: atom.len(),
236 })?;
237 Self::from_bytes(&bytes).map_err(|error| FromClvmError::Custom(error.to_string()))
238 }
239}
240
241#[cfg(feature = "chia-secp")]
242impl<D> FromClvm<D> for chia_secp::K1Signature
243where
244 D: ClvmDecoder,
245{
246 fn from_clvm(decoder: &D, node: D::Node) -> Result<Self, FromClvmError> {
247 let atom = decoder.decode_atom(&node)?;
248 let bytes: [u8; Self::SIZE] =
249 atom.as_ref()
250 .try_into()
251 .map_err(|_| FromClvmError::WrongAtomLength {
252 expected: Self::SIZE,
253 found: atom.len(),
254 })?;
255 Self::from_bytes(&bytes).map_err(|error| FromClvmError::Custom(error.to_string()))
256 }
257}
258
259#[cfg(feature = "chia-secp")]
260impl<D> FromClvm<D> for chia_secp::R1PublicKey
261where
262 D: ClvmDecoder,
263{
264 fn from_clvm(decoder: &D, node: D::Node) -> Result<Self, FromClvmError> {
265 let atom = decoder.decode_atom(&node)?;
266 let bytes: [u8; Self::SIZE] =
267 atom.as_ref()
268 .try_into()
269 .map_err(|_| FromClvmError::WrongAtomLength {
270 expected: Self::SIZE,
271 found: atom.len(),
272 })?;
273 Self::from_bytes(&bytes).map_err(|error| FromClvmError::Custom(error.to_string()))
274 }
275}
276
277#[cfg(feature = "chia-secp")]
278impl<D> FromClvm<D> for chia_secp::R1Signature
279where
280 D: ClvmDecoder,
281{
282 fn from_clvm(decoder: &D, node: D::Node) -> Result<Self, FromClvmError> {
283 let atom = decoder.decode_atom(&node)?;
284 let bytes: [u8; Self::SIZE] =
285 atom.as_ref()
286 .try_into()
287 .map_err(|_| FromClvmError::WrongAtomLength {
288 expected: Self::SIZE,
289 found: atom.len(),
290 })?;
291 Self::from_bytes(&bytes).map_err(|error| FromClvmError::Custom(error.to_string()))
292 }
293}
294
295#[cfg(test)]
296mod tests {
297 use clvmr::{serde::node_from_bytes, Allocator};
298
299 use super::*;
300
301 fn decode<T>(a: &mut Allocator, hex: &str) -> Result<T, FromClvmError>
302 where
303 T: FromClvm<Allocator>,
304 {
305 let bytes = hex::decode(hex).unwrap();
306 let actual = node_from_bytes(a, &bytes).unwrap();
307 T::from_clvm(a, actual)
308 }
309
310 #[test]
311 fn test_primitives() {
312 let a = &mut Allocator::new();
313 assert_eq!(decode(a, "80"), Ok(0u8));
314 assert_eq!(decode(a, "80"), Ok(0i8));
315 assert_eq!(decode(a, "05"), Ok(5u8));
316 assert_eq!(decode(a, "05"), Ok(5u32));
317 assert_eq!(decode(a, "05"), Ok(5i32));
318 assert_eq!(decode(a, "81e5"), Ok(-27i32));
319 assert_eq!(decode(a, "80"), Ok(-0));
320 assert_eq!(decode(a, "8180"), Ok(-128i8));
321 }
322
323 #[test]
324 fn test_bool() {
325 let a = &mut Allocator::new();
326 assert_eq!(decode(a, "80"), Ok(false));
327 assert_eq!(decode(a, "01"), Ok(true));
328 assert_eq!(
329 decode::<bool>(a, "05"),
330 Err(FromClvmError::Custom(
331 "expected boolean value of either `()` or `1`".to_string(),
332 ))
333 );
334 }
335
336 #[test]
337 fn test_smart_pointers() {
338 let a = &mut Allocator::new();
339 assert_eq!(decode(a, "80"), Ok(Box::new(0u8)));
340 assert_eq!(decode(a, "80"), Ok(Rc::new(0u8)));
341 assert_eq!(decode(a, "80"), Ok(Arc::new(0u8)));
342 }
343
344 #[test]
345 fn test_pair() {
346 let a = &mut Allocator::new();
347 assert_eq!(decode(a, "ff0502"), Ok((5, 2)));
348 assert_eq!(decode(a, "ff81b8ff8301600980"), Ok((-72, (90121, ()))));
349 assert_eq!(
350 decode(a, "ffff80ff80ff80ffff80ff80ff80808080"),
351 Ok((((), ((), ((), (((), ((), ((), ()))), ())))), ()))
352 );
353 }
354
355 #[test]
356 fn test_nil() {
357 let a = &mut Allocator::new();
358 assert_eq!(decode(a, "80"), Ok(()));
359 }
360
361 #[test]
362 fn test_array() {
363 let a = &mut Allocator::new();
364 assert_eq!(decode(a, "ff01ff02ff03ff0480"), Ok([1, 2, 3, 4]));
365 assert_eq!(decode(a, "80"), Ok([0; 0]));
366 }
367
368 #[test]
369 fn test_vec() {
370 let a = &mut Allocator::new();
371 assert_eq!(decode(a, "ff01ff02ff03ff0480"), Ok(vec![1, 2, 3, 4]));
372 assert_eq!(decode(a, "80"), Ok(Vec::<i32>::new()));
373 }
374
375 #[test]
376 fn test_option() {
377 let a = &mut Allocator::new();
378 assert_eq!(decode(a, "8568656c6c6f"), Ok(Some("hello".to_string())));
379 assert_eq!(decode(a, "80"), Ok(None::<String>));
380
381 assert_ne!(decode(a, "80"), Ok(Some(String::new())));
384 }
385
386 #[test]
387 fn test_string() {
388 let a = &mut Allocator::new();
389 assert_eq!(decode(a, "8568656c6c6f"), Ok("hello".to_string()));
390 assert_eq!(decode(a, "80"), Ok(String::new()));
391 }
392
393 #[cfg(feature = "chia-bls")]
394 #[test]
395 fn test_public_key() {
396 use chia_bls::PublicKey;
397 use hex_literal::hex;
398
399 let a = &mut Allocator::new();
400
401 let bytes = hex!(
402 "
403 b8f7dd239557ff8c49d338f89ac1a258a863fa52cd0a502e
404 3aaae4b6738ba39ac8d982215aa3fa16bc5f8cb7e44b954d
405 "
406 );
407
408 assert_eq!(
409 decode(a, "b0b8f7dd239557ff8c49d338f89ac1a258a863fa52cd0a502e3aaae4b6738ba39ac8d982215aa3fa16bc5f8cb7e44b954d"),
410 Ok(PublicKey::from_bytes(&bytes).unwrap())
411 );
412 assert_eq!(
413 decode::<PublicKey>(a, "8568656c6c6f"),
414 Err(FromClvmError::WrongAtomLength {
415 expected: 48,
416 found: 5
417 })
418 );
419 }
420
421 #[cfg(feature = "chia-bls")]
422 #[test]
423 fn test_signature() {
424 use chia_bls::Signature;
425 use hex_literal::hex;
426
427 let a = &mut Allocator::new();
428
429 let bytes = hex!(
430 "
431 a3994dc9c0ef41a903d3335f0afe42ba16c88e7881706798492da4a1653cd10c
432 69c841eeb56f44ae005e2bad27fb7ebb16ce8bbfbd708ea91dd4ff24f030497b
433 50e694a8270eccd07dbc206b8ffe0c34a9ea81291785299fae8206a1e1bbc1d1
434 "
435 );
436 assert_eq!(
437 decode(a, "c060a3994dc9c0ef41a903d3335f0afe42ba16c88e7881706798492da4a1653cd10c69c841eeb56f44ae005e2bad27fb7ebb16ce8bbfbd708ea91dd4ff24f030497b50e694a8270eccd07dbc206b8ffe0c34a9ea81291785299fae8206a1e1bbc1d1"),
438 Ok(Signature::from_bytes(&bytes).unwrap())
439 );
440 assert_eq!(
441 decode::<Signature>(a, "8568656c6c6f"),
442 Err(FromClvmError::WrongAtomLength {
443 expected: 96,
444 found: 5
445 })
446 );
447 }
448
449 #[cfg(feature = "chia-secp")]
450 #[test]
451 fn test_secp_public_key() {
452 use chia_secp::{K1PublicKey, R1PublicKey};
453 use hex_literal::hex;
454
455 let a = &mut Allocator::new();
456
457 let bytes = hex!("02827cdbbed87e45683d448be2ea15fb72ba3732247bda18474868cf5456123fb4");
458
459 assert_eq!(
460 decode(
461 a,
462 "a102827cdbbed87e45683d448be2ea15fb72ba3732247bda18474868cf5456123fb4"
463 ),
464 Ok(K1PublicKey::from_bytes(&bytes).unwrap())
465 );
466 assert_eq!(
467 decode::<K1PublicKey>(a, "8568656c6c6f"),
468 Err(FromClvmError::WrongAtomLength {
469 expected: 33,
470 found: 5
471 })
472 );
473
474 let bytes = hex!("037dc85102f5eb7867b9580fea8b242c774173e1a47db320c798242d3a7a7579e4");
475
476 assert_eq!(
477 decode(
478 a,
479 "a1037dc85102f5eb7867b9580fea8b242c774173e1a47db320c798242d3a7a7579e4"
480 ),
481 Ok(R1PublicKey::from_bytes(&bytes).unwrap())
482 );
483 assert_eq!(
484 decode::<R1PublicKey>(a, "8568656c6c6f"),
485 Err(FromClvmError::WrongAtomLength {
486 expected: 33,
487 found: 5
488 })
489 );
490 }
491
492 #[cfg(feature = "chia-secp")]
493 #[test]
494 fn test_secp_signature() {
495 use chia_secp::K1Signature;
496 use hex_literal::hex;
497
498 let a = &mut Allocator::new();
499
500 let bytes = hex!(
501 "
502 6f07897d1d28b8698af5dec5ca06907b1304b227dc9f740b8c4065cf04d5e865
503 3ae66aa17063e7120ee7f22fae54373b35230e259244b90400b65cf00d86c591
504 "
505 );
506
507 assert_eq!(
508 decode(a, "c0406f07897d1d28b8698af5dec5ca06907b1304b227dc9f740b8c4065cf04d5e8653ae66aa17063e7120ee7f22fae54373b35230e259244b90400b65cf00d86c591"),
509 Ok(K1Signature::from_bytes(&bytes).unwrap())
510 );
511 assert_eq!(
512 decode::<K1Signature>(a, "8568656c6c6f"),
513 Err(FromClvmError::WrongAtomLength {
514 expected: 64,
515 found: 5
516 })
517 );
518
519 let bytes = hex!(
520 "
521 550e83da8cf9b2d407ed093ae213869ebd7ceaea603920f87d535690e52b4053
522 7915d8fe3d5a96c87e700c56dc638c32f7a2954f2ba409367d1a132000cc2228
523 "
524 );
525
526 assert_eq!(
527 decode(a, "c040550e83da8cf9b2d407ed093ae213869ebd7ceaea603920f87d535690e52b40537915d8fe3d5a96c87e700c56dc638c32f7a2954f2ba409367d1a132000cc2228"),
528 Ok(K1Signature::from_bytes(&bytes).unwrap())
529 );
530 assert_eq!(
531 decode::<K1Signature>(a, "8568656c6c6f"),
532 Err(FromClvmError::WrongAtomLength {
533 expected: 64,
534 found: 5
535 })
536 );
537 }
538}