clvm_traits/
to_clvm.rs

1use std::{rc::Rc, sync::Arc};
2
3use clvmr::Atom;
4use num_bigint::BigInt;
5
6use crate::{encode_number, ClvmEncoder, ToClvmError};
7
8pub trait ToClvm<E>
9where
10    E: ClvmEncoder,
11{
12    fn to_clvm(&self, encoder: &mut E) -> Result<E::Node, ToClvmError>;
13}
14
15macro_rules! clvm_primitive {
16    ($primitive:ty) => {
17        impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for $primitive {
18            fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
19                let bytes = self.to_be_bytes();
20                #[allow(unused_comparisons)]
21                encoder.encode_atom(Atom::Borrowed(&encode_number(&bytes, *self < 0)))
22            }
23        }
24    };
25}
26
27clvm_primitive!(u8);
28clvm_primitive!(i8);
29clvm_primitive!(u16);
30clvm_primitive!(i16);
31clvm_primitive!(u32);
32clvm_primitive!(i32);
33clvm_primitive!(u64);
34clvm_primitive!(i64);
35clvm_primitive!(u128);
36clvm_primitive!(i128);
37clvm_primitive!(usize);
38clvm_primitive!(isize);
39
40impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for BigInt {
41    fn to_clvm(&self, encoder: &mut E) -> Result<<E as ClvmEncoder>::Node, ToClvmError> {
42        encoder.encode_bigint(self.clone())
43    }
44}
45
46impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for bool {
47    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
48        i32::from(*self).to_clvm(encoder)
49    }
50}
51
52impl<N, E: ClvmEncoder<Node = N>, T> ToClvm<E> for &T
53where
54    T: ToClvm<E>,
55{
56    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
57        T::to_clvm(*self, encoder)
58    }
59}
60
61impl<N, E: ClvmEncoder<Node = N>, T> ToClvm<E> for Box<T>
62where
63    T: ToClvm<E>,
64{
65    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
66        T::to_clvm(self, encoder)
67    }
68}
69
70impl<N, E: ClvmEncoder<Node = N>, T> ToClvm<E> for Rc<T>
71where
72    T: ToClvm<E>,
73{
74    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
75        T::to_clvm(self, encoder)
76    }
77}
78
79impl<N, E: ClvmEncoder<Node = N>, T> ToClvm<E> for Arc<T>
80where
81    T: ToClvm<E>,
82{
83    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
84        T::to_clvm(self, encoder)
85    }
86}
87
88impl<N, E: ClvmEncoder<Node = N>, A, B> ToClvm<E> for (A, B)
89where
90    A: ToClvm<E>,
91    B: ToClvm<E>,
92{
93    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
94        let first = self.0.to_clvm(encoder)?;
95        let rest = self.1.to_clvm(encoder)?;
96        encoder.encode_pair(first, rest)
97    }
98}
99
100impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for () {
101    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
102        encoder.encode_atom(Atom::Borrowed(&[]))
103    }
104}
105
106impl<N, E: ClvmEncoder<Node = N>, T> ToClvm<E> for &[T]
107where
108    T: ToClvm<E>,
109{
110    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
111        let mut result = encoder.encode_atom(Atom::Borrowed(&[]))?;
112        for item in self.iter().rev() {
113            let value = item.to_clvm(encoder)?;
114            result = encoder.encode_pair(value, result)?;
115        }
116        Ok(result)
117    }
118}
119
120impl<N, E: ClvmEncoder<Node = N>, T, const LEN: usize> ToClvm<E> for [T; LEN]
121where
122    T: ToClvm<E>,
123{
124    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
125        self.as_slice().to_clvm(encoder)
126    }
127}
128
129impl<N, E: ClvmEncoder<Node = N>, T> ToClvm<E> for Vec<T>
130where
131    T: ToClvm<E>,
132{
133    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
134        self.as_slice().to_clvm(encoder)
135    }
136}
137
138impl<N, E: ClvmEncoder<Node = N>, T> ToClvm<E> for Option<T>
139where
140    T: ToClvm<E>,
141{
142    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
143        match self {
144            Some(value) => value.to_clvm(encoder),
145            None => encoder.encode_atom(Atom::Borrowed(&[])),
146        }
147    }
148}
149
150impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for &str {
151    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
152        encoder.encode_atom(Atom::Borrowed(self.as_bytes()))
153    }
154}
155
156impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for String {
157    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
158        self.as_str().to_clvm(encoder)
159    }
160}
161
162#[cfg(feature = "chia-bls")]
163impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for chia_bls::PublicKey {
164    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
165        encoder.encode_atom(Atom::Borrowed(&self.to_bytes()))
166    }
167}
168
169#[cfg(feature = "chia-bls")]
170impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for chia_bls::Signature {
171    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
172        encoder.encode_atom(Atom::Borrowed(&self.to_bytes()))
173    }
174}
175
176#[cfg(feature = "chia-secp")]
177impl<E> ToClvm<E> for chia_secp::K1PublicKey
178where
179    E: ClvmEncoder,
180{
181    fn to_clvm(&self, encoder: &mut E) -> Result<E::Node, ToClvmError> {
182        encoder.encode_atom(Atom::Borrowed(&self.to_bytes()))
183    }
184}
185
186#[cfg(feature = "chia-secp")]
187impl<E> ToClvm<E> for chia_secp::K1Signature
188where
189    E: ClvmEncoder,
190{
191    fn to_clvm(&self, encoder: &mut E) -> Result<E::Node, ToClvmError> {
192        encoder.encode_atom(Atom::Borrowed(&self.to_bytes()))
193    }
194}
195
196#[cfg(feature = "chia-secp")]
197impl<E> ToClvm<E> for chia_secp::R1PublicKey
198where
199    E: ClvmEncoder,
200{
201    fn to_clvm(&self, encoder: &mut E) -> Result<E::Node, ToClvmError> {
202        encoder.encode_atom(Atom::Borrowed(&self.to_bytes()))
203    }
204}
205
206#[cfg(feature = "chia-secp")]
207impl<E> ToClvm<E> for chia_secp::R1Signature
208where
209    E: ClvmEncoder,
210{
211    fn to_clvm(&self, encoder: &mut E) -> Result<E::Node, ToClvmError> {
212        encoder.encode_atom(Atom::Borrowed(&self.to_bytes()))
213    }
214}
215
216#[cfg(test)]
217mod tests {
218    use clvmr::{serde::node_to_bytes, Allocator};
219    use hex::ToHex;
220
221    use super::*;
222
223    fn encode<T>(a: &mut Allocator, value: T) -> Result<String, ToClvmError>
224    where
225        T: ToClvm<Allocator>,
226    {
227        let actual = value.to_clvm(a)?;
228        let actual_bytes = node_to_bytes(a, actual).unwrap();
229        Ok(actual_bytes.encode_hex())
230    }
231
232    #[test]
233    fn test_nodeptr() {
234        let a = &mut Allocator::new();
235        let ptr = a.one();
236        assert_eq!(ptr.to_clvm(a).unwrap(), ptr);
237    }
238
239    #[test]
240    fn test_primitives() {
241        let a = &mut Allocator::new();
242        assert_eq!(encode(a, 0u8), Ok("80".to_owned()));
243        assert_eq!(encode(a, 0i8), Ok("80".to_owned()));
244        assert_eq!(encode(a, 5u8), Ok("05".to_owned()));
245        assert_eq!(encode(a, 5u32), Ok("05".to_owned()));
246        assert_eq!(encode(a, 5i32), Ok("05".to_owned()));
247        assert_eq!(encode(a, -27i32), Ok("81e5".to_owned()));
248        assert_eq!(encode(a, -0), Ok("80".to_owned()));
249        assert_eq!(encode(a, -128i8), Ok("8180".to_owned()));
250    }
251
252    #[test]
253    fn test_bool() {
254        let a = &mut Allocator::new();
255        assert_eq!(encode(a, true), Ok("01".to_owned()));
256        assert_eq!(encode(a, false), Ok("80".to_owned()));
257    }
258
259    #[test]
260    fn test_reference() {
261        let a = &mut Allocator::new();
262        assert_eq!(encode(a, [1, 2, 3]), encode(a, [1, 2, 3]));
263        assert_eq!(encode(a, Some(42)), encode(a, Some(42)));
264        assert_eq!(encode(a, Some(&42)), encode(a, Some(42)));
265        assert_eq!(encode(a, Some(&42)), encode(a, Some(42)));
266    }
267
268    #[test]
269    fn test_smart_pointers() {
270        let a = &mut Allocator::new();
271        assert_eq!(encode(a, Box::new(42)), encode(a, 42));
272        assert_eq!(encode(a, Rc::new(42)), encode(a, 42));
273        assert_eq!(encode(a, Arc::new(42)), encode(a, 42));
274    }
275
276    #[test]
277    fn test_pair() {
278        let a = &mut Allocator::new();
279        assert_eq!(encode(a, (5, 2)), Ok("ff0502".to_owned()));
280        assert_eq!(
281            encode(a, (-72, (90121, ()))),
282            Ok("ff81b8ff8301600980".to_owned())
283        );
284        assert_eq!(
285            encode(a, (((), ((), ((), (((), ((), ((), ()))), ())))), ())),
286            Ok("ffff80ff80ff80ffff80ff80ff80808080".to_owned())
287        );
288    }
289
290    #[test]
291    fn test_nil() {
292        let a = &mut Allocator::new();
293        assert_eq!(encode(a, ()), Ok("80".to_owned()));
294    }
295
296    #[test]
297    fn test_slice() {
298        let a = &mut Allocator::new();
299        assert_eq!(
300            encode(a, [1, 2, 3, 4].as_slice()),
301            Ok("ff01ff02ff03ff0480".to_owned())
302        );
303        assert_eq!(encode(a, [0; 0].as_slice()), Ok("80".to_owned()));
304    }
305
306    #[test]
307    fn test_array() {
308        let a = &mut Allocator::new();
309        assert_eq!(encode(a, [1, 2, 3, 4]), Ok("ff01ff02ff03ff0480".to_owned()));
310        assert_eq!(encode(a, [0; 0]), Ok("80".to_owned()));
311    }
312
313    #[test]
314    fn test_vec() {
315        let a = &mut Allocator::new();
316        assert_eq!(
317            encode(a, vec![1, 2, 3, 4]),
318            Ok("ff01ff02ff03ff0480".to_owned())
319        );
320        assert_eq!(encode(a, vec![0; 0]), Ok("80".to_owned()));
321    }
322
323    #[test]
324    fn test_option() {
325        let a = &mut Allocator::new();
326        assert_eq!(encode(a, Some("hello")), Ok("8568656c6c6f".to_owned()));
327        assert_eq!(encode(a, None::<&str>), Ok("80".to_owned()));
328        assert_eq!(encode(a, Some("")), Ok("80".to_owned()));
329    }
330
331    #[test]
332    fn test_str() {
333        let a = &mut Allocator::new();
334        assert_eq!(encode(a, "hello"), Ok("8568656c6c6f".to_owned()));
335        assert_eq!(encode(a, ""), Ok("80".to_owned()));
336    }
337
338    #[test]
339    fn test_string() {
340        let a = &mut Allocator::new();
341        assert_eq!(
342            encode(a, "hello".to_string()),
343            Ok("8568656c6c6f".to_owned())
344        );
345        assert_eq!(encode(a, String::new()), Ok("80".to_owned()));
346    }
347
348    #[cfg(feature = "chia-bls")]
349    #[test]
350    fn test_public_key() {
351        use chia_bls::PublicKey;
352        use hex_literal::hex;
353
354        let a = &mut Allocator::new();
355
356        let bytes = hex!(
357            "
358            b8f7dd239557ff8c49d338f89ac1a258a863fa52cd0a502e
359            3aaae4b6738ba39ac8d982215aa3fa16bc5f8cb7e44b954d
360            "
361        );
362        assert_eq!(
363            encode(a, PublicKey::from_bytes(&bytes).unwrap()),
364            Ok("b0b8f7dd239557ff8c49d338f89ac1a258a863fa52cd0a502e3aaae4b6738ba39ac8d982215aa3fa16bc5f8cb7e44b954d".to_string())
365        );
366    }
367
368    #[cfg(feature = "chia-bls")]
369    #[test]
370    fn test_signature() {
371        use chia_bls::Signature;
372        use hex_literal::hex;
373
374        let a = &mut Allocator::new();
375
376        let bytes = hex!(
377            "
378            a3994dc9c0ef41a903d3335f0afe42ba16c88e7881706798492da4a1653cd10c
379            69c841eeb56f44ae005e2bad27fb7ebb16ce8bbfbd708ea91dd4ff24f030497b
380            50e694a8270eccd07dbc206b8ffe0c34a9ea81291785299fae8206a1e1bbc1d1
381            "
382        );
383        assert_eq!(
384            encode(a, Signature::from_bytes(&bytes).unwrap()),
385            Ok("c060a3994dc9c0ef41a903d3335f0afe42ba16c88e7881706798492da4a1653cd10c69c841eeb56f44ae005e2bad27fb7ebb16ce8bbfbd708ea91dd4ff24f030497b50e694a8270eccd07dbc206b8ffe0c34a9ea81291785299fae8206a1e1bbc1d1".to_string())
386        );
387    }
388
389    #[cfg(feature = "chia-secp")]
390    #[test]
391    fn test_secp_public_key() {
392        use chia_secp::{K1PublicKey, R1PublicKey};
393        use hex_literal::hex;
394
395        let a = &mut Allocator::new();
396
397        let k1_pk = K1PublicKey::from_bytes(&hex!(
398            "02827cdbbed87e45683d448be2ea15fb72ba3732247bda18474868cf5456123fb4"
399        ))
400        .unwrap();
401        assert_eq!(
402            encode(a, k1_pk),
403            Ok("a102827cdbbed87e45683d448be2ea15fb72ba3732247bda18474868cf5456123fb4".to_string())
404        );
405
406        let r1_pk = R1PublicKey::from_bytes(&hex!(
407            "037dc85102f5eb7867b9580fea8b242c774173e1a47db320c798242d3a7a7579e4"
408        ))
409        .unwrap();
410        assert_eq!(
411            encode(a, r1_pk),
412            Ok("a1037dc85102f5eb7867b9580fea8b242c774173e1a47db320c798242d3a7a7579e4".to_string())
413        );
414    }
415
416    #[cfg(feature = "chia-secp")]
417    #[test]
418    fn test_secp_signature() {
419        use chia_secp::{K1Signature, R1Signature};
420        use hex_literal::hex;
421
422        let a = &mut Allocator::new();
423
424        let k1_sig = K1Signature::from_bytes(&hex!(
425            "6f07897d1d28b8698af5dec5ca06907b1304b227dc9f740b8c4065cf04d5e8653ae66aa17063e7120ee7f22fae54373b35230e259244b90400b65cf00d86c591"
426        ))
427        .unwrap();
428        assert_eq!(
429            encode(a, k1_sig),
430            Ok("c0406f07897d1d28b8698af5dec5ca06907b1304b227dc9f740b8c4065cf04d5e8653ae66aa17063e7120ee7f22fae54373b35230e259244b90400b65cf00d86c591".to_string())
431        );
432
433        let r1_sig = R1Signature::from_bytes(&hex!(
434            "550e83da8cf9b2d407ed093ae213869ebd7ceaea603920f87d535690e52b40537915d8fe3d5a96c87e700c56dc638c32f7a2954f2ba409367d1a132000cc2228"
435        ))
436        .unwrap();
437        assert_eq!(
438            encode(a, r1_sig),
439            Ok("c040550e83da8cf9b2d407ed093ae213869ebd7ceaea603920f87d535690e52b40537915d8fe3d5a96c87e700c56dc638c32f7a2954f2ba409367d1a132000cc2228".to_string())
440        );
441    }
442}