chia_protocol/
bytes.rs

1use chia_sha2::Sha256;
2use chia_traits::{chia_error, read_bytes, Streamable};
3use clvm_traits::{ClvmDecoder, ClvmEncoder, FromClvm, FromClvmError, ToClvm, ToClvmError};
4use clvm_utils::TreeHash;
5use clvmr::Atom;
6use std::array::TryFromSliceError;
7use std::fmt;
8use std::io::Cursor;
9use std::ops::Deref;
10
11#[cfg(feature = "py-bindings")]
12use chia_traits::{ChiaToPython, FromJsonDict, ToJsonDict};
13#[cfg(feature = "py-bindings")]
14use hex::FromHex;
15#[cfg(feature = "py-bindings")]
16use pyo3::exceptions::PyValueError;
17#[cfg(feature = "py-bindings")]
18use pyo3::prelude::*;
19#[cfg(feature = "py-bindings")]
20use pyo3::types::PyBytes;
21
22#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
23#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
24pub struct Bytes(Vec<u8>);
25
26impl Bytes {
27    pub fn new(bytes: Vec<u8>) -> Self {
28        Self(bytes)
29    }
30
31    pub fn len(&self) -> usize {
32        self.0.len()
33    }
34
35    pub fn is_empty(&self) -> bool {
36        self.0.is_empty()
37    }
38
39    pub fn as_slice(&self) -> &[u8] {
40        self.0.as_slice()
41    }
42
43    pub fn to_vec(&self) -> Vec<u8> {
44        self.0.clone()
45    }
46
47    pub fn into_inner(self) -> Vec<u8> {
48        self.0
49    }
50}
51
52impl fmt::Debug for Bytes {
53    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
54        formatter.write_str(&hex::encode(self))
55    }
56}
57
58impl fmt::Display for Bytes {
59    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
60        formatter.write_str(&hex::encode(self))
61    }
62}
63
64#[cfg(feature = "serde")]
65impl serde::Serialize for Bytes {
66    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
67    where
68        S: serde::Serializer,
69    {
70        chia_serde::ser_bytes(self, serializer, false)
71    }
72}
73
74#[cfg(feature = "serde")]
75impl<'de> serde::Deserialize<'de> for Bytes {
76    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
77    where
78        D: serde::Deserializer<'de>,
79    {
80        chia_serde::de_bytes(deserializer)
81    }
82}
83
84impl Streamable for Bytes {
85    fn update_digest(&self, digest: &mut Sha256) {
86        (self.0.len() as u32).update_digest(digest);
87        digest.update(&self.0);
88    }
89
90    fn stream(&self, out: &mut Vec<u8>) -> chia_error::Result<()> {
91        if self.0.len() > u32::MAX as usize {
92            Err(chia_error::Error::SequenceTooLarge)
93        } else {
94            (self.0.len() as u32).stream(out)?;
95            out.extend_from_slice(&self.0);
96            Ok(())
97        }
98    }
99
100    fn parse<const TRUSTED: bool>(input: &mut Cursor<&[u8]>) -> chia_error::Result<Self> {
101        let len = u32::parse::<TRUSTED>(input)?;
102        Ok(Bytes(read_bytes(input, len as usize)?.to_vec()))
103    }
104}
105
106#[cfg(feature = "py-bindings")]
107impl ToJsonDict for Bytes {
108    fn to_json_dict(&self, py: Python<'_>) -> PyResult<PyObject> {
109        let prefix = if self.0.is_empty() { "" } else { "0x" };
110        Ok(format!("{prefix}{self}")
111            .into_pyobject(py)?
112            .into_any()
113            .unbind())
114    }
115}
116
117#[cfg(feature = "py-bindings")]
118impl FromJsonDict for Bytes {
119    fn from_json_dict(o: &Bound<'_, PyAny>) -> PyResult<Self> {
120        let s: String = o.extract()?;
121        if s.is_empty() {
122            return Ok(Bytes::default());
123        }
124        if !s.starts_with("0x") {
125            return Err(PyValueError::new_err(
126                "bytes object is expected to start with 0x",
127            ));
128        }
129        let s = &s[2..];
130        let buf = match Vec::from_hex(s) {
131            Err(_) => {
132                return Err(PyValueError::new_err("invalid hex"));
133            }
134            Ok(v) => v,
135        };
136        Ok(buf.into())
137    }
138}
139
140impl<N, E: ClvmEncoder<Node = N>> ToClvm<E> for Bytes {
141    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
142        encoder.encode_atom(Atom::Borrowed(self.0.as_slice()))
143    }
144}
145
146impl<N, D: ClvmDecoder<Node = N>> FromClvm<D> for Bytes {
147    fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
148        let bytes = decoder.decode_atom(&node)?;
149        Ok(Self(bytes.as_ref().to_vec()))
150    }
151}
152
153impl From<&[u8]> for Bytes {
154    fn from(value: &[u8]) -> Self {
155        Self(value.to_vec())
156    }
157}
158
159impl<const N: usize> From<BytesImpl<N>> for Bytes {
160    fn from(value: BytesImpl<N>) -> Self {
161        Self(value.0.to_vec())
162    }
163}
164
165impl From<Vec<u8>> for Bytes {
166    fn from(value: Vec<u8>) -> Self {
167        Self(value)
168    }
169}
170
171impl From<Bytes> for Vec<u8> {
172    fn from(value: Bytes) -> Self {
173        value.0
174    }
175}
176
177impl AsRef<[u8]> for Bytes {
178    fn as_ref(&self) -> &[u8] {
179        &self.0
180    }
181}
182
183impl Deref for Bytes {
184    type Target = [u8];
185
186    fn deref(&self) -> &[u8] {
187        &self.0
188    }
189}
190
191#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
192#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
193pub struct BytesImpl<const N: usize>([u8; N]);
194
195impl<const N: usize> BytesImpl<N> {
196    pub const fn new(bytes: [u8; N]) -> Self {
197        Self(bytes)
198    }
199
200    pub const fn len(&self) -> usize {
201        N
202    }
203
204    pub const fn is_empty(&self) -> bool {
205        N == 0
206    }
207
208    pub fn as_slice(&self) -> &[u8] {
209        &self.0
210    }
211
212    pub fn to_bytes(self) -> [u8; N] {
213        self.0
214    }
215
216    pub fn to_vec(&self) -> Vec<u8> {
217        self.0.to_vec()
218    }
219}
220
221impl<const N: usize> Default for BytesImpl<N> {
222    fn default() -> Self {
223        Self([0; N])
224    }
225}
226
227impl<const N: usize> fmt::Debug for BytesImpl<N> {
228    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
229        formatter.write_str(&hex::encode(self))
230    }
231}
232
233impl<const N: usize> fmt::Display for BytesImpl<N> {
234    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
235        formatter.write_str(&hex::encode(self))
236    }
237}
238
239#[cfg(feature = "serde")]
240impl<const N: usize> serde::Serialize for BytesImpl<N> {
241    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
242    where
243        S: serde::Serializer,
244    {
245        chia_serde::ser_bytes(self, serializer, true)
246    }
247}
248
249#[cfg(feature = "serde")]
250impl<'de, const N: usize> serde::Deserialize<'de> for BytesImpl<N> {
251    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
252    where
253        D: serde::Deserializer<'de>,
254    {
255        chia_serde::de_bytes(deserializer)
256    }
257}
258
259impl<const N: usize> Streamable for BytesImpl<N> {
260    fn update_digest(&self, digest: &mut Sha256) {
261        digest.update(self.0);
262    }
263    fn stream(&self, out: &mut Vec<u8>) -> chia_error::Result<()> {
264        out.extend_from_slice(&self.0);
265        Ok(())
266    }
267
268    fn parse<const TRUSTED: bool>(input: &mut Cursor<&[u8]>) -> chia_error::Result<Self> {
269        Ok(BytesImpl(read_bytes(input, N)?.try_into().unwrap()))
270    }
271}
272
273#[cfg(feature = "py-bindings")]
274impl<const N: usize> ToJsonDict for BytesImpl<N> {
275    fn to_json_dict(&self, py: Python<'_>) -> PyResult<PyObject> {
276        Ok(format!("0x{self}").into_pyobject(py)?.into_any().unbind())
277    }
278}
279
280#[cfg(feature = "py-bindings")]
281impl<const N: usize> FromJsonDict for BytesImpl<N> {
282    fn from_json_dict(o: &Bound<'_, PyAny>) -> PyResult<Self> {
283        let s: String = o.extract()?;
284        if !s.starts_with("0x") {
285            return Err(PyValueError::new_err(
286                "bytes object is expected to start with 0x",
287            ));
288        }
289        let s = &s[2..];
290        let buf = match Vec::from_hex(s) {
291            Err(_) => {
292                return Err(PyValueError::new_err("invalid hex"));
293            }
294            Ok(v) => v,
295        };
296        if buf.len() != N {
297            return Err(PyValueError::new_err(format!(
298                "invalid length {} expected {}",
299                buf.len(),
300                N
301            )));
302        }
303        Ok(buf.try_into().unwrap())
304    }
305}
306
307impl<N, E: ClvmEncoder<Node = N>, const LEN: usize> ToClvm<E> for BytesImpl<LEN> {
308    fn to_clvm(&self, encoder: &mut E) -> Result<N, ToClvmError> {
309        encoder.encode_atom(Atom::Borrowed(self.0.as_slice()))
310    }
311}
312
313impl<N, D: ClvmDecoder<Node = N>, const LEN: usize> FromClvm<D> for BytesImpl<LEN> {
314    fn from_clvm(decoder: &D, node: N) -> Result<Self, FromClvmError> {
315        let bytes = decoder.decode_atom(&node)?;
316        if bytes.as_ref().len() != LEN {
317            return Err(FromClvmError::WrongAtomLength {
318                expected: LEN,
319                found: bytes.as_ref().len(),
320            });
321        }
322        Ok(Self::try_from(bytes.as_ref()).unwrap())
323    }
324}
325
326impl<const N: usize> TryFrom<&[u8]> for BytesImpl<N> {
327    type Error = TryFromSliceError;
328
329    fn try_from(value: &[u8]) -> Result<Self, TryFromSliceError> {
330        Ok(Self(value.try_into()?))
331    }
332}
333
334impl<const N: usize> TryFrom<Vec<u8>> for BytesImpl<N> {
335    type Error = TryFromSliceError;
336
337    fn try_from(value: Vec<u8>) -> Result<Self, TryFromSliceError> {
338        value.as_slice().try_into()
339    }
340}
341
342impl<const N: usize> TryFrom<&Vec<u8>> for BytesImpl<N> {
343    type Error = TryFromSliceError;
344
345    fn try_from(value: &Vec<u8>) -> Result<Self, TryFromSliceError> {
346        value.as_slice().try_into()
347    }
348}
349
350impl<const N: usize> TryFrom<Bytes> for BytesImpl<N> {
351    type Error = TryFromSliceError;
352
353    fn try_from(value: Bytes) -> Result<Self, TryFromSliceError> {
354        value.0.as_slice().try_into()
355    }
356}
357
358impl<const N: usize> TryFrom<&Bytes> for BytesImpl<N> {
359    type Error = TryFromSliceError;
360
361    fn try_from(value: &Bytes) -> Result<Self, TryFromSliceError> {
362        value.0.as_slice().try_into()
363    }
364}
365
366impl<const N: usize> From<BytesImpl<N>> for Vec<u8> {
367    fn from(value: BytesImpl<N>) -> Self {
368        value.to_vec()
369    }
370}
371
372impl<const N: usize> From<[u8; N]> for BytesImpl<N> {
373    fn from(value: [u8; N]) -> Self {
374        Self(value)
375    }
376}
377
378impl<const N: usize> From<&[u8; N]> for BytesImpl<N> {
379    fn from(value: &[u8; N]) -> Self {
380        Self(*value)
381    }
382}
383
384impl<const N: usize> From<BytesImpl<N>> for [u8; N] {
385    fn from(value: BytesImpl<N>) -> Self {
386        value.0
387    }
388}
389
390impl<'a, const N: usize> From<&'a BytesImpl<N>> for &'a [u8; N] {
391    fn from(value: &'a BytesImpl<N>) -> &'a [u8; N] {
392        &value.0
393    }
394}
395
396impl<const N: usize> From<&BytesImpl<N>> for [u8; N] {
397    fn from(value: &BytesImpl<N>) -> [u8; N] {
398        value.0
399    }
400}
401
402impl<'a, const N: usize> From<&'a BytesImpl<N>> for &'a [u8] {
403    fn from(value: &'a BytesImpl<N>) -> &'a [u8] {
404        &value.0
405    }
406}
407
408impl<const N: usize> AsRef<[u8]> for BytesImpl<N> {
409    fn as_ref(&self) -> &[u8] {
410        &self.0
411    }
412}
413
414impl<const N: usize> Deref for BytesImpl<N> {
415    type Target = [u8];
416
417    fn deref(&self) -> &[u8] {
418        &self.0
419    }
420}
421
422pub type Bytes32 = BytesImpl<32>;
423pub type Bytes48 = BytesImpl<48>;
424pub type Bytes96 = BytesImpl<96>;
425pub type Bytes100 = BytesImpl<100>;
426
427impl From<Bytes32> for TreeHash {
428    fn from(value: Bytes32) -> Self {
429        Self::new(value.0)
430    }
431}
432
433impl From<TreeHash> for Bytes32 {
434    fn from(value: TreeHash) -> Self {
435        Self(value.to_bytes())
436    }
437}
438
439#[cfg(feature = "py-bindings")]
440impl<'py, const N: usize> IntoPyObject<'py> for BytesImpl<N> {
441    type Target = PyAny;
442    type Output = Bound<'py, Self::Target>;
443    type Error = PyErr;
444
445    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
446        ChiaToPython::to_python(&self, py)
447    }
448}
449
450#[cfg(feature = "py-bindings")]
451impl<const N: usize> ChiaToPython for BytesImpl<N> {
452    fn to_python<'a>(&self, py: Python<'a>) -> PyResult<Bound<'a, PyAny>> {
453        if N == 32 {
454            let bytes_module = PyModule::import(py, "chia_rs.sized_bytes")?;
455            let ty = bytes_module.getattr("bytes32")?;
456            ty.call1((self.0.into_pyobject(py)?,))
457        } else if N == 48 {
458            let bytes_module = PyModule::import(py, "chia_rs.sized_bytes")?;
459            let ty = bytes_module.getattr("bytes48")?;
460            ty.call1((self.0.into_pyobject(py)?,))
461        } else {
462            Ok(PyBytes::new(py, &self.0).into_any())
463        }
464    }
465}
466
467#[cfg(feature = "py-bindings")]
468impl<'py, const N: usize> FromPyObject<'py> for BytesImpl<N> {
469    fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult<Self> {
470        let b = obj.downcast::<PyBytes>()?;
471        let slice: &[u8] = b.as_bytes();
472        let buf: [u8; N] = slice.try_into()?;
473        Ok(BytesImpl::<N>(buf))
474    }
475}
476
477#[cfg(feature = "py-bindings")]
478impl<'py> IntoPyObject<'py> for Bytes {
479    type Target = PyAny;
480    type Output = Bound<'py, Self::Target>;
481    type Error = std::convert::Infallible;
482
483    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
484        Ok(PyBytes::new(py, &self.0).into_any())
485    }
486}
487
488#[cfg(feature = "py-bindings")]
489impl ChiaToPython for Bytes {
490    fn to_python<'a>(&self, py: Python<'a>) -> PyResult<Bound<'a, PyAny>> {
491        Ok(PyBytes::new(py, &self.0).into_any())
492    }
493}
494
495#[cfg(feature = "py-bindings")]
496impl<'py> FromPyObject<'py> for Bytes {
497    fn extract_bound(obj: &Bound<'py, PyAny>) -> PyResult<Self> {
498        let b = obj.downcast::<PyBytes>()?;
499        Ok(Bytes(b.as_bytes().to_vec()))
500    }
501}
502
503#[cfg(test)]
504#[allow(clippy::needless_pass_by_value)]
505mod tests {
506    use super::*;
507
508    use clvmr::{
509        serde::{node_from_bytes, node_to_bytes},
510        Allocator,
511    };
512    use rstest::rstest;
513
514    #[rstest]
515    // Bytess32
516    #[case(
517        "0000000000000000000000000000000000000000000000000000000000000000",
518        "0000000000000000000000000000000000000000000000000000000000000000",
519        true
520    )]
521    #[case(
522        "0000000000000000000000000000000000000000000000000000000000000000",
523        "0000000000000000000000000000000000000000000000000000000000000100",
524        false
525    )]
526    #[case(
527        "fff0000000000000000000000000000000000000000000000000000000000100",
528        "fff0000000000000000000000000000000000000000000000000000000000100",
529        true
530    )]
531    // Bytes
532    #[case("000000", "000000", true)]
533    #[case("123456", "125456", false)]
534    #[case("000001", "00000001", false)]
535    #[case("00000001", "000001", false)]
536    #[case("ffff01", "ffff01", true)]
537    #[case("", "", true)]
538    fn test_bytes_comparisons(#[case] lhs: &str, #[case] rhs: &str, #[case] expect_equal: bool) {
539        let lhs_vec: Vec<u8> = hex::decode(lhs).expect("hex::decode");
540        let rhs_vec: Vec<u8> = hex::decode(rhs).expect("hex::decode");
541
542        if lhs_vec.len() == 32 && rhs_vec.len() == 32 {
543            let lhs = Bytes32::try_from(&lhs_vec).unwrap();
544            let rhs = Bytes32::try_from(&rhs_vec).unwrap();
545
546            assert_eq!(lhs.len(), 32);
547            assert_eq!(rhs.len(), 32);
548
549            assert_eq!(lhs.is_empty(), lhs_vec.is_empty());
550            assert_eq!(rhs.is_empty(), rhs_vec.is_empty());
551
552            if expect_equal {
553                assert_eq!(lhs, rhs);
554                assert_eq!(rhs, lhs);
555            } else {
556                assert!(lhs != rhs);
557                assert!(rhs != lhs);
558            }
559        } else {
560            let lhs = Bytes::from(lhs_vec.clone());
561            let rhs = Bytes::from(rhs_vec.clone());
562
563            assert_eq!(lhs.len(), lhs_vec.len());
564            assert_eq!(rhs.len(), rhs_vec.len());
565
566            assert_eq!(lhs.is_empty(), lhs_vec.is_empty());
567            assert_eq!(rhs.is_empty(), rhs_vec.is_empty());
568
569            if expect_equal {
570                assert_eq!(lhs, rhs);
571                assert_eq!(rhs, lhs);
572            } else {
573                assert!(lhs != rhs);
574                assert!(rhs != lhs);
575            }
576        }
577    }
578
579    fn from_bytes<T: Streamable + fmt::Debug + PartialEq>(buf: &[u8], expected: T) {
580        let mut input = Cursor::<&[u8]>::new(buf);
581        assert_eq!(T::parse::<false>(&mut input).unwrap(), expected);
582    }
583
584    fn from_bytes_fail<T: Streamable + fmt::Debug + PartialEq>(
585        buf: &[u8],
586        expected: chia_error::Error,
587    ) {
588        let mut input = Cursor::<&[u8]>::new(buf);
589        assert_eq!(T::parse::<false>(&mut input).unwrap_err(), expected);
590    }
591
592    fn stream<T: Streamable>(v: &T) -> Vec<u8> {
593        let mut buf = Vec::<u8>::new();
594        v.stream(&mut buf).unwrap();
595        let mut ctx1 = Sha256::new();
596        let mut ctx2 = Sha256::new();
597        v.update_digest(&mut ctx1);
598        ctx2.update(&buf);
599        assert_eq!(&ctx1.finalize(), &ctx2.finalize());
600        buf
601    }
602
603    #[test]
604    fn test_stream_bytes32() {
605        let buf = [
606            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
607            25, 26, 27, 28, 29, 30, 31, 32,
608        ];
609        let out = stream(&Bytes32::from(buf));
610        assert_eq!(buf.as_slice(), &out);
611    }
612
613    #[test]
614    fn test_stream_bytes() {
615        let val: Bytes = vec![
616            1_u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
617            24, 25, 26, 27, 28, 29, 30, 31, 32,
618        ]
619        .into();
620        println!("{val:?}");
621        let buf = stream(&val);
622        println!("buf: {buf:?}");
623        from_bytes(&buf, val);
624    }
625
626    #[test]
627    fn test_parse_bytes_empty() {
628        let buf: &[u8] = &[0, 0, 0, 0];
629        from_bytes::<Bytes>(buf, [].to_vec().into());
630    }
631
632    #[test]
633    fn test_parse_bytes() {
634        let buf: &[u8] = &[0, 0, 0, 3, 1, 2, 3];
635        from_bytes::<Bytes>(buf, [1_u8, 2, 3].to_vec().into());
636    }
637
638    #[test]
639    fn test_parse_truncated_len() {
640        let buf: &[u8] = &[0, 0, 1];
641        from_bytes_fail::<Bytes>(buf, chia_error::Error::EndOfBuffer);
642    }
643
644    #[test]
645    fn test_parse_truncated() {
646        let buf: &[u8] = &[0, 0, 0, 4, 1, 2, 3];
647        from_bytes_fail::<Bytes>(buf, chia_error::Error::EndOfBuffer);
648    }
649
650    #[test]
651    fn test_parse_bytes32() {
652        let buf = [
653            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
654            25, 26, 27, 28, 29, 30, 31, 32,
655        ];
656        from_bytes::<Bytes32>(&buf, Bytes32::from(buf));
657        from_bytes_fail::<Bytes32>(&buf[0..30], chia_error::Error::EndOfBuffer);
658    }
659
660    #[test]
661    fn test_parse_bytes48() {
662        let buf = [
663            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
664            25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
665            47, 48,
666        ];
667        from_bytes::<Bytes48>(&buf, Bytes48::from(buf));
668        from_bytes_fail::<Bytes48>(&buf[0..47], chia_error::Error::EndOfBuffer);
669    }
670
671    #[test]
672    fn bytes_roundtrip() {
673        let a = &mut Allocator::new();
674        let expected = "84facef00d";
675        let expected_bytes = hex::decode(expected).unwrap();
676
677        let ptr = node_from_bytes(a, &expected_bytes).unwrap();
678        let bytes = Bytes::from_clvm(a, ptr).unwrap();
679
680        let round_trip = bytes.to_clvm(a).unwrap();
681        assert_eq!(expected, hex::encode(node_to_bytes(a, round_trip).unwrap()));
682    }
683
684    #[test]
685    fn bytes32_roundtrip() {
686        let a = &mut Allocator::new();
687        let expected = "a0eff07522495060c066f66f32acc2a77e3a3e737aca8baea4d1a64ea4cdc13da9";
688        let expected_bytes = hex::decode(expected).unwrap();
689
690        let ptr = node_from_bytes(a, &expected_bytes).unwrap();
691        let bytes32 = Bytes32::from_clvm(a, ptr).unwrap();
692
693        let round_trip = bytes32.to_clvm(a).unwrap();
694        assert_eq!(expected, hex::encode(node_to_bytes(a, round_trip).unwrap()));
695    }
696
697    #[test]
698    fn bytes32_failure() {
699        let a = &mut Allocator::new();
700        let bytes =
701            hex::decode("f07522495060c066f66f32acc2a77e3a3e737aca8baea4d1a64ea4cdc13da9").unwrap();
702        let ptr = a.new_atom(&bytes).unwrap();
703        assert!(Bytes32::from_clvm(a, ptr).is_err());
704
705        let ptr = a.new_pair(a.one(), a.one()).unwrap();
706        assert_eq!(
707            Bytes32::from_clvm(a, ptr).unwrap_err(),
708            FromClvmError::ExpectedAtom
709        );
710    }
711}