1use crate::mir::constant::Constant;
3use crate::mir::constant::TryExtractFromError;
4use crate::mir::expr::Expr;
5use crate::serialization::SigmaSerializationError;
6use crate::serialization::SigmaSerializeResult;
7use crate::serialization::{
8 sigma_byte_reader::{SigmaByteRead, SigmaByteReader},
9 sigma_byte_writer::{SigmaByteWrite, SigmaByteWriter},
10 SigmaParsingError, SigmaSerializable,
11};
12use crate::sigma_protocol::sigma_boolean::ProveDlog;
13use crate::types::stype::SType;
14use io::Cursor;
15use sigma_ser::vlq_encode::ReadSigmaVlqExt;
16use sigma_ser::vlq_encode::WriteSigmaVlqExt;
17
18use crate::serialization::constant_store::ConstantStore;
19use derive_more::From;
20use std::convert::TryFrom;
21use std::io;
22use std::io::Read;
23use thiserror::Error;
24
25mod tree_header;
26pub use tree_header::*;
27
28#[derive(PartialEq, Eq, Debug, Clone)]
30pub struct ParsedErgoTree {
31 header: ErgoTreeHeader,
32 constants: Vec<Constant>,
33 root: Expr,
34}
35
36impl ParsedErgoTree {
37 fn with_constant(self, index: usize, constant: Constant) -> Result<Self, SetConstantError> {
40 let mut new_constants = self.constants.clone();
41 if let Some(old_constant) = self.constants.get(index) {
42 if constant.tpe == old_constant.tpe {
43 let _ = std::mem::replace(&mut new_constants[index], constant);
44 Ok(Self {
45 constants: new_constants,
46 ..self
47 })
48 } else {
49 Err(SetConstantError::TypeMismatch(format!(
50 "with_constant: expected constant type to be {:?}, got {:?}",
51 old_constant.tpe, constant.tpe
52 )))
53 }
54 } else {
55 Err(SetConstantError::OutOfBounds(format!(
56 "with_constant: index({0}) out of bounds (lengh = {1})",
57 index,
58 self.constants.len()
59 )))
60 }
61 }
62
63 fn template_bytes(&self) -> Result<Vec<u8>, ErgoTreeError> {
64 Ok(self.root.sigma_serialize_bytes()?)
65 }
66}
67
68#[derive(Error, PartialEq, Eq, Debug, Clone)]
70pub enum SetConstantError {
71 #[error("Index is out of bounds: {0}")]
73 OutOfBounds(String),
74 #[error("Existing constant type differs from the provided new constant type: {0}")]
76 TypeMismatch(String),
77}
78
79#[derive(Error, PartialEq, Eq, Debug, Clone, From)]
81pub enum ErgoTreeRootParsingError {
82 #[error("SigmaParsingError: {0:?}")]
84 SigmaParsingError(SigmaParsingError),
85 #[error("Non-consumed bytes after root expr is parsed")]
87 NonConsumedBytes,
88}
89
90#[derive(Error, PartialEq, Eq, Debug, Clone, From)]
92pub enum ErgoTreeError {
93 #[error("ErgoTree header error: {0:?}")]
95 HeaderError(ErgoTreeHeaderError),
96 #[error("ErgoTree constants error: {0:?}")]
98 ConstantsError(ErgoTreeConstantError),
99 #[error("ErgoTree root expr parsing (deserialization) error: {0:?}")]
101 RootParsingError(ErgoTreeRootParsingError),
102 #[error("ErgoTree serialization error: {0}")]
104 RootSerializationError(SigmaSerializationError),
105 #[error("Sigma parsing error: {0:?}")]
107 SigmaParsingError(SigmaParsingError),
108 #[error("IO error: {0:?}")]
110 IoError(String),
111}
112
113#[derive(PartialEq, Eq, Debug, Clone, From)]
115pub enum ErgoTree {
116 Unparsed {
118 tree_bytes: Vec<u8>,
120 error: ErgoTreeError,
122 },
123 Parsed(ParsedErgoTree),
125}
126
127impl ErgoTree {
128 fn parsed_tree(&self) -> Result<&ParsedErgoTree, ErgoTreeError> {
129 match self {
130 ErgoTree::Unparsed {
131 tree_bytes: _,
132 error,
133 } => Err(error.clone()),
134 ErgoTree::Parsed(parsed) => Ok(parsed),
135 }
136 }
137
138 fn sigma_parse_sized<R: SigmaByteRead>(
139 r: &mut R,
140 header: ErgoTreeHeader,
141 ) -> Result<ParsedErgoTree, ErgoTreeError> {
142 let constants = if header.is_constant_segregation() {
143 ErgoTree::sigma_parse_constants(r)?
144 } else {
145 vec![]
146 };
147 r.set_constant_store(ConstantStore::new(constants.clone()));
148 let root = Expr::sigma_parse(r)?;
149 Ok(ParsedErgoTree {
150 header,
151 constants,
152 root,
153 })
154 }
155
156 fn sigma_parse_constants<R: SigmaByteRead>(
157 r: &mut R,
158 ) -> Result<Vec<Constant>, SigmaParsingError> {
159 let constants_len = r.get_u32()?;
160 if constants_len as usize > ErgoTree::MAX_CONSTANTS_COUNT {
161 return Err(SigmaParsingError::ValueOutOfBounds(
162 "too many constants".to_string(),
163 ));
164 }
165 let mut constants = Vec::with_capacity(constants_len as usize);
167 for _ in 0..constants_len {
168 let c = Constant::sigma_parse(r)?;
169 constants.push(c);
171 }
172 Ok(constants)
173 }
174
175 pub fn new(header: ErgoTreeHeader, expr: &Expr) -> Result<Self, ErgoTreeError> {
177 Ok(if header.is_constant_segregation() {
178 let mut data = Vec::new();
179 let cs = ConstantStore::empty();
180 let ww = &mut data;
181 let mut w = SigmaByteWriter::new(ww, Some(cs));
182 expr.sigma_serialize(&mut w)?;
183 #[allow(clippy::unwrap_used)]
184 let constants = w.constant_store_mut_ref().unwrap().get_all();
186 let cursor = Cursor::new(&mut data[..]);
187 let new_cs = ConstantStore::new(constants.clone());
188 let mut sr = SigmaByteReader::new(cursor, new_cs);
189 let parsed_expr = Expr::sigma_parse(&mut sr)?;
190 ErgoTree::Parsed(ParsedErgoTree {
191 header,
192 constants,
193 root: parsed_expr,
194 })
195 } else {
196 ErgoTree::Parsed(ParsedErgoTree {
197 header,
198 constants: Vec::new(),
199 root: expr.clone(),
200 })
201 })
202 }
203
204 pub const MAX_CONSTANTS_COUNT: usize = 4096;
206
207 pub fn proposition(&self) -> Result<Expr, ErgoTreeError> {
209 let tree = self.parsed_tree()?.clone();
210 let root = tree.root;
214 if tree.header.is_constant_segregation() {
215 let mut data = Vec::new();
216 let constants = {
217 let cs = ConstantStore::new(tree.constants.clone());
218 let mut w = SigmaByteWriter::new(&mut data, Some(cs));
219 root.sigma_serialize(&mut w)?;
220 #[allow(clippy::unwrap_used)] w.constant_store.unwrap()
222 };
223 let cursor = Cursor::new(&mut data[..]);
224 let mut sr = SigmaByteReader::new_with_substitute_placeholders(cursor, constants);
225 let parsed_expr = Expr::sigma_parse(&mut sr)?;
226 Ok(parsed_expr)
227 } else {
228 Ok(root)
229 }
230 }
231
232 pub fn debug_tree(&self) -> String {
234 let tree = format!("{:#?}", self);
235 tree
236 }
237
238 pub fn pretty_print(&self) -> Result<(Expr, String), String> {
240 let tree = self.parsed_tree().map_err(|e| e.to_string())?;
241 tree.root.pretty_print().map_err(|e| e.to_string())
242 }
243
244 pub fn to_base16_bytes(&self) -> Result<String, SigmaSerializationError> {
246 let bytes = self.sigma_serialize_bytes()?;
247 Ok(base16::encode_lower(&bytes))
248 }
249
250 pub fn constants_len(&self) -> Result<usize, ErgoTreeError> {
253 self.parsed_tree().map(|tree| tree.constants.len())
254 }
255
256 pub fn get_constant(&self, index: usize) -> Result<Option<Constant>, ErgoTreeError> {
260 self.parsed_tree()
261 .map(|tree| tree.constants.get(index).cloned())
262 }
263
264 pub fn get_constants(&self) -> Result<Vec<Constant>, ErgoTreeError> {
267 self.parsed_tree().map(|tree| tree.constants.clone())
268 }
269
270 pub fn with_constant(self, index: usize, constant: Constant) -> Result<Self, ErgoTreeError> {
274 let parsed_tree = self.parsed_tree()?.clone();
275 Ok(Self::Parsed(
276 parsed_tree
277 .with_constant(index, constant)
278 .map_err(ErgoTreeConstantError::from)?,
279 ))
280 }
281
282 pub fn template_bytes(&self) -> Result<Vec<u8>, ErgoTreeError> {
285 self.clone().parsed_tree()?.template_bytes()
286 }
287}
288
289#[derive(Error, PartialEq, Eq, Debug, Clone, From)]
291pub enum ErgoTreeConstantError {
292 #[error("Fail to parse a constant when deserializing an ErgoTree: {0}")]
294 ParsingError(SigmaParsingError),
295 #[error("Fail to set a new constant value: {0}")]
297 SetConstantError(SetConstantError),
298}
299
300impl TryFrom<Expr> for ErgoTree {
301 type Error = ErgoTreeError;
302
303 fn try_from(expr: Expr) -> Result<Self, Self::Error> {
304 match &expr {
305 Expr::Const(c) => match c {
306 Constant { tpe, .. } if *tpe == SType::SSigmaProp => {
307 ErgoTree::new(ErgoTreeHeader::v0(false), &expr)
308 }
309 _ => ErgoTree::new(ErgoTreeHeader::v0(true), &expr),
310 },
311 _ => ErgoTree::new(ErgoTreeHeader::v0(true), &expr),
312 }
313 }
314}
315
316impl SigmaSerializable for ErgoTree {
317 fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> SigmaSerializeResult {
318 match self {
319 ErgoTree::Unparsed {
320 tree_bytes,
321 error: _,
322 } => w.write_all(&tree_bytes[..])?,
323 ErgoTree::Parsed(parsed_tree) => {
324 let bytes = {
325 let mut data = Vec::new();
326 let mut inner_w = SigmaByteWriter::new(&mut data, None);
327 if parsed_tree.header.is_constant_segregation() {
328 inner_w.put_usize_as_u32_unwrapped(parsed_tree.constants.len())?;
329 parsed_tree
330 .constants
331 .iter()
332 .try_for_each(|c| c.sigma_serialize(&mut inner_w))?;
333 };
334 parsed_tree.root.sigma_serialize(&mut inner_w)?;
335 data
336 };
337
338 parsed_tree.header.sigma_serialize(w)?;
339 if parsed_tree.header.has_size() {
340 w.put_usize_as_u32_unwrapped(bytes.len())?;
341 }
342 w.write_all(&bytes)?;
343 }
344 };
345 Ok(())
346 }
347
348 fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SigmaParsingError> {
349 let header = ErgoTreeHeader::sigma_parse(r)?;
350 if header.has_size() {
351 let tree_size_bytes = r.get_u32()?;
352 let mut buf = vec![0u8; tree_size_bytes as usize];
353 r.read_exact(buf.as_mut_slice())?;
354 let buf_copy = buf.clone();
355 let mut inner_r =
356 SigmaByteReader::new(Cursor::new(&mut buf[..]), ConstantStore::empty());
357 match ErgoTree::sigma_parse_sized(&mut inner_r, header.clone()) {
358 Ok(parsed_tree) => Ok(parsed_tree.into()),
359 Err(error) => {
360 let mut bytes = vec![header.serialized()];
361 #[allow(clippy::unwrap_used)]
362 bytes.put_u32(tree_size_bytes).unwrap();
363 bytes.extend_from_slice(&buf_copy);
364 Ok(ErgoTree::Unparsed {
365 tree_bytes: bytes,
366 error,
367 })
368 }
369 }
370 } else {
371 let constants = if header.is_constant_segregation() {
372 ErgoTree::sigma_parse_constants(r)?
373 } else {
374 vec![]
375 };
376 r.set_constant_store(ConstantStore::new(constants.clone()));
377 let root = Expr::sigma_parse(r)?;
378 Ok(ErgoTree::Parsed(ParsedErgoTree {
379 header,
380 constants,
381 root,
382 }))
383 }
384 }
385
386 fn sigma_parse_bytes(bytes: &[u8]) -> Result<Self, SigmaParsingError> {
387 let wrap_in_ergotree = |r: Result<ParsedErgoTree, ErgoTreeError>| -> Self {
388 match r {
389 Ok(parsed_tree) => ErgoTree::Parsed(parsed_tree),
390 Err(error) => ErgoTree::Unparsed {
391 tree_bytes: bytes.to_vec(),
392 error,
393 },
394 }
395 };
396 let mut r = SigmaByteReader::new(Cursor::new(bytes), ConstantStore::empty());
397 let tree: Result<ErgoTree, SigmaParsingError> = match ErgoTreeHeader::sigma_parse(&mut r) {
398 Ok(header) => {
399 if header.has_size() {
400 let tree_size_bytes = r.get_u32()?;
401 let mut buf = vec![0u8; tree_size_bytes as usize];
402 r.read_exact(buf.as_mut_slice())?;
403 let mut inner_r =
404 SigmaByteReader::new(Cursor::new(&mut buf[..]), ConstantStore::empty());
405 Ok(wrap_in_ergotree(ErgoTree::sigma_parse_sized(
406 &mut inner_r,
407 header,
408 )))
409 } else {
410 Ok(wrap_in_ergotree(ErgoTree::sigma_parse_sized(
411 &mut r, header,
412 )))
413 }
414 }
415 Err(e) => Ok(ErgoTree::Unparsed {
416 tree_bytes: bytes.to_vec(),
417 error: e.into(),
418 }),
419 };
420 let mut buffer = Vec::new();
421 if let Ok(0) = r.read_to_end(&mut buffer) {
422 tree
423 } else {
424 Ok(ErgoTree::Unparsed {
425 tree_bytes: bytes.to_vec(),
426 error: ErgoTreeRootParsingError::NonConsumedBytes.into(),
427 })
428 }
429 }
430}
431
432impl TryFrom<ErgoTree> for ProveDlog {
433 type Error = TryExtractFromError;
434
435 fn try_from(tree: ErgoTree) -> Result<Self, Self::Error> {
436 let expr = tree
437 .proposition()
438 .map_err(|_| TryExtractFromError("cannot read root expr".to_string()))?;
439 match expr {
440 Expr::Const(Constant {
441 tpe: SType::SSigmaProp,
442 v,
443 }) => ProveDlog::try_from(v),
444 _ => Err(TryExtractFromError(
445 "expected ProveDlog in the root".to_string(),
446 )),
447 }
448 }
449}
450
451impl From<std::io::Error> for ErgoTreeError {
452 fn from(e: std::io::Error) -> Self {
453 ErgoTreeError::IoError(e.to_string())
454 }
455}
456
457#[cfg(feature = "arbitrary")]
458#[allow(clippy::unwrap_used)]
459pub(crate) mod arbitrary {
460
461 use crate::mir::expr::arbitrary::ArbExprParams;
462
463 use super::*;
464 use proptest::prelude::*;
465
466 impl Arbitrary for ErgoTree {
467 type Parameters = ();
468 type Strategy = BoxedStrategy<Self>;
469
470 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
471 prop_oneof![
473 any::<ProveDlog>().prop_map(|p| ErgoTree::new(
474 ErgoTreeHeader::v0(false),
475 &Expr::Const(p.into())
476 )
477 .unwrap()),
478 any::<ProveDlog>().prop_map(|p| ErgoTree::new(
479 ErgoTreeHeader::v1(false),
480 &Expr::Const(p.into())
481 )
482 .unwrap()),
483 any_with::<Expr>(ArbExprParams {
485 tpe: SType::SSigmaProp,
486 depth: 1
487 })
488 .prop_map(|e| ErgoTree::new(ErgoTreeHeader::v1(true), &e).unwrap()),
489 any_with::<Expr>(ArbExprParams {
490 tpe: SType::SSigmaProp,
491 depth: 1
492 })
493 .prop_map(|e| ErgoTree::new(ErgoTreeHeader::v0(true), &e).unwrap()),
494 ]
495 .boxed()
496 }
497 }
498}
499
500#[cfg(test)]
501#[cfg(feature = "arbitrary")]
502#[allow(clippy::unwrap_used)]
503#[allow(clippy::panic)]
504#[allow(clippy::expect_used)]
505mod tests {
506 use super::*;
507 use crate::chain::address::AddressEncoder;
508 use crate::chain::address::NetworkPrefix;
509 use crate::mir::constant::Literal;
510 use proptest::prelude::*;
511
512 proptest! {
513 #[test]
514 fn ser_roundtrip(v in any::<ErgoTree>()) {
515 let mut data = Vec::new();
517 let mut w = SigmaByteWriter::new(&mut data, None);
518 v.sigma_serialize(&mut w).expect("serialization failed");
519 let cursor = Cursor::new(&mut data[..]);
521 let mut sr = SigmaByteReader::new(cursor, ConstantStore::empty());
522 let res = ErgoTree::sigma_parse(&mut sr).expect("parse failed");
523 prop_assert_eq![&res, &v];
525 let res = ErgoTree::sigma_parse_bytes(&data).expect("parse failed");
527 prop_assert_eq!(&res.template_bytes().unwrap(), &v.template_bytes().unwrap());
528 prop_assert_eq![res, v];
529 }
530 }
531
532 #[test]
533 fn deserialization_non_parseable_tree_v0() {
534 let bytes = [
536 ErgoTreeHeader::v0(true).serialized(),
537 1, 0, 99,
540 99,
541 ];
542 let tree = ErgoTree::sigma_parse_bytes(&bytes).unwrap();
543 assert!(tree.parsed_tree().is_err(), "parsing constants should fail");
544 assert_eq!(
545 tree.sigma_serialize_bytes().unwrap(),
546 bytes,
547 "serialization should return original bytes"
548 );
549 assert!(
550 tree.template_bytes().is_err(),
551 "template bytes should not be parsed"
552 );
553 }
554
555 #[test]
556 fn deserialization_non_parseable_tree_v1() {
557 let bytes = [
559 ErgoTreeHeader::v1(true).serialized(),
560 4, 1, 0, 99,
564 99,
565 ];
566 let tree = ErgoTree::sigma_parse_bytes(&bytes).unwrap();
567 assert!(tree.parsed_tree().is_err(), "parsing constants should fail");
568 assert_eq!(
569 tree.sigma_serialize_bytes().unwrap(),
570 bytes,
571 "serialization should return original bytes"
572 );
573 assert!(
574 tree.template_bytes().is_err(),
575 "template bytes should not be parsed"
576 );
577 }
578
579 #[test]
580 fn deserialization_non_parseable_root_v0() {
581 let bytes = [ErgoTreeHeader::v0(false).serialized(), 0, 1];
583 let tree = ErgoTree::sigma_parse_bytes(&bytes).unwrap();
584 assert!(tree.parsed_tree().is_err(), "parsing root should fail");
585 assert_eq!(
586 tree.sigma_serialize_bytes().unwrap(),
587 bytes,
588 "serialization should return original bytes"
589 );
590 assert!(
591 tree.template_bytes().is_err(),
592 "template bytes should not be parsed"
593 );
594 }
595
596 #[test]
597 fn deserialization_non_parseable_root_v1() {
598 let bytes = [
600 ErgoTreeHeader::v1(false).serialized(),
601 2, 0,
603 1,
604 ];
605 let tree = ErgoTree::sigma_parse_bytes(&bytes).unwrap();
606 assert!(tree.parsed_tree().is_err(), "parsing root should fail");
607 assert_eq!(
608 tree.sigma_serialize_bytes().unwrap(),
609 bytes,
610 "serialization should return original bytes"
611 );
612 assert!(
613 tree.template_bytes().is_err(),
614 "template bytes should not be parsed"
615 );
616 let mut reader = SigmaByteReader::new(Cursor::new(&bytes), ConstantStore::empty());
618 let tree = ErgoTree::sigma_parse(&mut reader).unwrap();
619 assert!(tree.parsed_tree().is_err(), "parsing root should fail");
620 assert_eq!(
621 tree.sigma_serialize_bytes().unwrap(),
622 bytes,
623 "serialization should return original bytes"
624 );
625 assert!(
626 tree.template_bytes().is_err(),
627 "template bytes should not be parsed"
628 );
629 }
630
631 #[test]
632 fn test_constant_segregation_header_flag_support() {
633 let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
634 let address = encoder
635 .parse_address_from_str("9hzP24a2q8KLPVCUk7gdMDXYc7vinmGuxmLp5KU7k9UwptgYBYV")
636 .unwrap();
637 let bytes = address.script().unwrap().sigma_serialize_bytes().unwrap();
638 assert_eq!(&bytes[..2], vec![0u8, 8u8].as_slice());
639 }
640
641 #[test]
642 fn test_constant_segregation() {
643 let expr = Expr::Const(Constant {
644 tpe: SType::SBoolean,
645 v: Literal::Boolean(true),
646 });
647 let ergo_tree = ErgoTree::new(ErgoTreeHeader::v0(false), &expr).unwrap();
648 let bytes = ergo_tree.sigma_serialize_bytes().unwrap();
649 let parsed_expr = ErgoTree::sigma_parse_bytes(&bytes)
650 .unwrap()
651 .proposition()
652 .unwrap();
653 assert_eq!(parsed_expr, expr)
654 }
655
656 #[test]
657 fn test_constant_len() {
658 let expr = Expr::Const(Constant {
659 tpe: SType::SBoolean,
660 v: Literal::Boolean(false),
661 });
662 let ergo_tree = ErgoTree::new(ErgoTreeHeader::v0(true), &expr).unwrap();
663 assert_eq!(ergo_tree.constants_len().unwrap(), 1);
664 }
665
666 #[test]
667 fn test_get_constant() {
668 let expr = Expr::Const(Constant {
669 tpe: SType::SBoolean,
670 v: Literal::Boolean(false),
671 });
672 let ergo_tree = ErgoTree::new(ErgoTreeHeader::v0(true), &expr).unwrap();
673 assert_eq!(ergo_tree.constants_len().unwrap(), 1);
674 assert_eq!(ergo_tree.get_constant(0).unwrap().unwrap(), false.into());
675 }
676
677 #[test]
678 fn test_set_constant() {
679 let expr = Expr::Const(Constant {
680 tpe: SType::SBoolean,
681 v: Literal::Boolean(false),
682 });
683 let ergo_tree = ErgoTree::new(ErgoTreeHeader::v0(true), &expr).unwrap();
684 let new_ergo_tree = ergo_tree.with_constant(0, true.into()).unwrap();
685 assert_eq!(new_ergo_tree.get_constant(0).unwrap().unwrap(), true.into());
686 }
687
688 #[test]
689 fn dex_t2tpool_parse() {
690 let base16_str = "19a3030f0400040204020404040404060406058080a0f6f4acdbe01b058080a0f6f4acdbe01b050004d00f0400040005000500d81ad601b2a5730000d602e4c6a70405d603db63087201d604db6308a7d605b27203730100d606b27204730200d607b27203730300d608b27204730400d609b27203730500d60ab27204730600d60b9973078c720602d60c999973088c720502720bd60d8c720802d60e998c720702720dd60f91720e7309d6108c720a02d6117e721006d6127e720e06d613998c7209027210d6147e720d06d615730ad6167e721306d6177e720c06d6187e720b06d6199c72127218d61a9c72167218d1edededededed93c27201c2a793e4c672010405720292c17201c1a793b27203730b00b27204730c00938c7205018c720601ed938c7207018c720801938c7209018c720a019593720c730d95720f929c9c721172127e7202069c7ef07213069a9c72147e7215067e9c720e720206929c9c721472167e7202069c7ef0720e069a9c72117e7215067e9c721372020695ed720f917213730e907217a19d721972149d721a7211ed9272199c7217721492721a9c72177211";
691 let tree_bytes = base16::decode(base16_str.as_bytes()).unwrap();
692 let tree = ErgoTree::sigma_parse_bytes(&tree_bytes).unwrap();
693 let header = tree.parsed_tree().unwrap().header.clone();
695 assert!(header.has_size());
696 assert!(header.is_constant_segregation());
697 assert_eq!(header.version(), &ErgoTreeVersion::V1);
698 let new_tree = tree
699 .with_constant(7, 1i64.into())
700 .unwrap()
701 .with_constant(8, 2i64.into())
702 .unwrap();
703 assert_eq!(new_tree.get_constant(7).unwrap().unwrap(), 1i64.into());
704 assert_eq!(new_tree.get_constant(8).unwrap().unwrap(), 2i64.into());
705 assert!(new_tree.sigma_serialize_bytes().unwrap().len() > 1);
706 }
707
708 #[test]
709 fn parse_invalid_677() {
710 let base16_str = "cd07021a8e6f59fd4a";
712 let tree_bytes = base16::decode(base16_str.as_bytes()).unwrap();
713 let tree = ErgoTree::sigma_parse_bytes(&tree_bytes).unwrap();
714 assert_eq!(tree.sigma_serialize_bytes().unwrap(), tree_bytes);
716 assert_eq!(
717 tree,
718 ErgoTree::Unparsed {
719 tree_bytes,
720 error: ErgoTreeRootParsingError::NonConsumedBytes.into()
721 }
722 );
723 }
724
725 #[test]
726 fn parse_invalid_tree_extra_bytes() {
727 let valid_ergo_tree_hex =
728 "0008cd02a706374307f3038cb2f16e7ae9d3e29ca03ea5333681ca06a9bd87baab1164bc";
729 let invalid_ergo_tree_with_extra_bytes = format!("{}aaaa", valid_ergo_tree_hex);
731 let bytes = base16::decode(invalid_ergo_tree_with_extra_bytes.as_bytes()).unwrap();
732 let tree = ErgoTree::sigma_parse_bytes(&bytes).unwrap();
733 assert_eq!(tree.sigma_serialize_bytes().unwrap(), bytes);
735 assert_eq!(
736 tree,
737 ErgoTree::Unparsed {
738 tree_bytes: bytes,
739 error: ErgoTreeRootParsingError::NonConsumedBytes.into()
740 }
741 );
742 }
743
744 #[test]
745 fn parse_p2pk_672() {
746 let valid_p2pk = "0e2103e02fa2bbd85e9298aa37fe2634602a0fba746234fe2a67f04d14deda55fac491";
748 let bytes = base16::decode(valid_p2pk).unwrap();
749 let tree = ErgoTree::sigma_parse_bytes(&bytes).unwrap();
750 assert_eq!(tree.sigma_serialize_bytes().unwrap(), bytes);
752 assert_eq!(
753 tree,
754 ErgoTree::Unparsed {
755 tree_bytes: bytes,
756 error: ErgoTreeRootParsingError::NonConsumedBytes.into()
757 }
758 );
759 }
760
761 #[test]
762 fn parse_invalid_tree_707() {
763 let ergo_tree_hex =
765 "100208cd03553448c194fdd843c87d080f5e8ed983f5bb2807b13b45a9683bba8c7bfb5ae808cd0354c06b1af711e51986d787ff1df2883fcaf8d34865fea720f549e382063a08ebd1eb0273007301";
766 let bytes = base16::decode(ergo_tree_hex.as_bytes()).unwrap();
767 let tree = ErgoTree::sigma_parse_bytes(&bytes).unwrap();
768 assert!(tree.parsed_tree().is_err(), "the tree is BoolToSigmaProp(SigmaOr(pk1, pk2)) is invalid (BoolToSigmaProp expects bool");
770 }
771
772 #[test]
774 fn test_contract_template() {
775 let ergo_tree_hex =
776 "10010e20007a24c677a4dc0fdbeaa1c6db1052fc1839b7675851358aaf96823b2245408bd80ed60183200202de02ae02cf025b026402ba02d602f50257020b02ad020a0261020c024e02480249025702cf0247028202300284020002bc02900240024c021d0214021002dad602d9010263e4c672020464d603d901033c0c630eb58c720301d9010563aedb63087205d901074d0e938c7207018c720302d604b2da7203018602db6501fe7300040000d605e3010ed606d9010632b4e4720604020442d607d9010763b2db63087207040000d608da720701a7d609b2da7203018602a58c720801040000d60ad9010a63b2db6308720a040200d60bd9010b0ed801d60ddc640bda72020172040283020e7201720be472059683020193b1dad9010e3c0c630eb58c720e01d901106393cbc272108c720e02018602a4da720601b2720d0402000402dad9010e0e9683030193cbc27209720e93da72070172097208938cda720a017209018cda720a01a70101da720601b2720d040000d60ce4e30002d60ddc0c1aa402a70400d60ed9010e05958f720e0580020402958f720e058080020404958f720e05808080020406958f720e0580808080020408958f720e05808080808002040a958f720e0580808080808002040c958f720e058080808080808002040e958f720e0580808080808080800204100412d197830801dad9010f029593720f0200da720b0183200202030292020802bc024e02ef029a020302e802d7028b0286026302a3020102bb025f02ad02dc02a7028b02e1029d027f02e5023502b302c6024c02be02fe0242010001720cdad9010f029593720f0202da720b01832002028b02c7028f021c026a02ae02c9021e0262028e021502cf0266028c021602cc021e029b02d802e402b902b702e1026d0263021802b502f5022302a502e902bd010001720cdad9010f029593720f0201da720b01832002028802300261022c02520235025f026f0228020d0212029702f1029f026702b0027802c902da02a702d702b0024b0245029c029102cc02640249025702c20280010001720cdad9010f029593720f0203da720b01832002024f02d802b002d602d9028202420272026f025702b302df02a6028602120267029202b802e50205026e021d025102b602e9020d0268028002cf022d02cd02c5010001720cdad9010f029593720f0204da720b018320020289022e026f024702a1020d025c029002b8027a02d402860233025502ce02ad020002c302e202980232021702ee021502530232025302cd029a0260022502c2010001720cdad9010f029593720f0205da720b01832002023a02110295025c0247021902e5028802bc02e602a70261021d022702bd021f02df02db02570238025c02ae02e2026602d80204020c0289024f021c022e021d010001720cdad9010f029593720f0206da720b0183200202090282020f02cb0288027102fb0245020c023e020602b702cb025e022702b002450250028702a302660262021a029d02de0275028202a002190211021e023e010001720cdad9010f029593720f0207dad901113c0e639592720db1a50100d809d613b2a5720d00d614c17213d615c1a7d616c27213d617c4a7d618c2a7d6198cc7a701d61ac47213d61b8cc772130196830401927214997215058092f40193cb7216da720601b2dc640bda7202018c7211020283010e8c721101e5720583000204000093b472179a9ada720e017215b17218da720e017e721905b17217b4721a9a9ada720e017214b17216da720e017e721b05b1721a978302019299721b72190480c33d947218721601860272017204010001720c";
777 let bytes = base16::decode(ergo_tree_hex.as_bytes()).unwrap();
778 let tree = ErgoTree::sigma_parse_bytes(&bytes).unwrap();
779 tree.proposition().unwrap();
780 }
781}