clvm_traits/
from_clvm.rs

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        // Empty strings get decoded as None instead, since both values are represented by nil bytes.
382        // This could be considered either intended behavior or not, depending on the way it's used.
383        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}