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