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 #[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 #[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}