Repository: ergoplatform/sigma-rust (language: rust)

Issue:
Box Expr enum variant data
Because enum allocates memory enough to store largets variant for *each* enum variant.


Discussion / hints:

Fix patch:
diff --git a/ergo-lib/src/ast.rs b/ergo-lib/src/ast.rs
index c79fab4fa..6551458ca 100644
--- a/ergo-lib/src/ast.rs
+++ b/ergo-lib/src/ast.rs
@@ -1,6 +1,6 @@
 //! AST for ErgoTree
 
-pub(crate) mod coll_methods;
+pub(crate) mod coll_fold;
 pub(crate) mod expr;
 pub(crate) mod extract_reg_as;
 pub(crate) mod global_vars;
diff --git a/ergo-lib/src/ast/coll_fold.rs b/ergo-lib/src/ast/coll_fold.rs
new file mode 100644
index 000000000..d37c54073
--- /dev/null
+++ b/ergo-lib/src/ast/coll_fold.rs
@@ -0,0 +1,35 @@
+use crate::serialization::sigma_byte_reader::SigmaByteRead;
+use crate::serialization::sigma_byte_writer::SigmaByteWrite;
+use crate::serialization::SerializationError;
+use crate::serialization::SigmaSerializable;
+
+use super::expr::Expr;
+
+#[derive(PartialEq, Eq, Debug, Clone)]
+pub struct Fold {
+    /// Collection
+    input: Expr,
+    /// Initial value for accumulator
+    zero: Expr,
+    /// Function (lambda)
+    fold_op: Expr,
+}
+
+impl SigmaSerializable for Fold {
+    fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> Result<(), std::io::Error> {
+        self.input.sigma_serialize(w)?;
+        self.zero.sigma_serialize(w)?;
+        self.fold_op.sigma_serialize(w)
+    }
+
+    fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SerializationError> {
+        let input = Expr::sigma_parse(r)?;
+        let zero = Expr::sigma_parse(r)?;
+        let fold_op = Expr::sigma_parse(r)?;
+        Ok(Fold {
+            input,
+            zero,
+            fold_op,
+        })
+    }
+}
diff --git a/ergo-lib/src/ast/coll_methods.rs b/ergo-lib/src/ast/coll_methods.rs
deleted file mode 100644
index 8fba9390b..000000000
--- a/ergo-lib/src/ast/coll_methods.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use super::expr::Expr;
-
-#[derive(PartialEq, Eq, Debug, Clone)]
-/// Methods for Collection type instance
-pub enum CollM {
-    /// Fold method
-    Fold {
-        /// Collection
-        input: Box<Expr>,
-        /// Initial value for accumulator
-        zero: Box<Expr>,
-        /// Function (lambda)
-        fold_op: Box<Expr>,
-    },
-}
diff --git a/ergo-lib/src/ast/expr.rs b/ergo-lib/src/ast/expr.rs
index 5faa62327..f2e9338a5 100644
--- a/ergo-lib/src/ast/expr.rs
+++ b/ergo-lib/src/ast/expr.rs
@@ -3,7 +3,7 @@ use core::fmt;
 use crate::serialization::op_code::OpCode;
 use crate::types::stype::SType;
 
-use super::coll_methods::CollM;
+use super::coll_fold::Fold;
 use super::constant::Constant;
 use super::constant::ConstantPlaceholder;
 use super::extract_reg_as::ExtractRegisterAs;
@@ -21,21 +21,21 @@ use derive_more::From;
 /// Expression in ErgoTree
 pub enum Expr {
     /// Constant value
-    Const(Constant),
+    Const(Box<Constant>),
     /// Placeholder for a constant
-    ConstPlaceholder(ConstantPlaceholder),
+    ConstPlaceholder(Box<ConstantPlaceholder>),
     /// Predefined functions (global)
-    PredefFunc(PredefFunc),
-    /// Collection type methods
-    CollM(CollM),
+    PredefFunc(Box<PredefFunc>),
+    /// Collection fold op
+    Fold(Box<Fold>),
     Context,
     // Global(Global),
     /// Predefined global variables
-    GlobalVars(GlobalVars),
+    GlobalVars(Box<GlobalVars>),
     /// Method call
-    MethodCall(MethodCall),
+    MethodCall(Box<MethodCall>),
     /// Property call
-    ProperyCall(PropertyCall),
+    ProperyCall(Box<PropertyCall>),
     /// Binary operation
     BinOp(ops::BinOp, Box<Expr>, Box<Expr>),
     /// Option get method
@@ -87,7 +87,7 @@ mod tests {
         type Strategy = BoxedStrategy<Self>;
 
         fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
-            prop_oneof![any::<Constant>().prop_map(Expr::Const)].boxed()
+            prop_oneof![any::<Constant>().prop_map(Box::new).prop_map(Expr::Const)].boxed()
         }
     }
 }
diff --git a/ergo-lib/src/ast/extract_reg_as.rs b/ergo-lib/src/ast/extract_reg_as.rs
index afe9913a0..8afbac31b 100644
--- a/ergo-lib/src/ast/extract_reg_as.rs
+++ b/ergo-lib/src/ast/extract_reg_as.rs
@@ -18,7 +18,7 @@ use super::value::Value;
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct ExtractRegisterAs {
     /// Box
-    pub input: Box<Expr>,
+    pub input: Expr,
     /// Register id to extract value from
     pub register_id: RegisterId,
     /// Type
@@ -51,7 +51,7 @@ impl SigmaSerializable for ExtractRegisterAs {
     }
 
     fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SerializationError> {
-        let input = Expr::sigma_parse(r)?.into();
+        let input = Expr::sigma_parse(r)?;
         let register_id = RegisterId::sigma_parse(r)?;
         let tpe = SType::sigma_parse(r)?;
         Ok(ExtractRegisterAs {
@@ -78,7 +78,7 @@ mod tests {
     #[test]
     fn eval_box_get_reg() {
         let get_reg_expr: Expr = Box::new(ExtractRegisterAs {
-            input: Box::new(GlobalVars::SelfBox.into()),
+            input: Box::new(GlobalVars::SelfBox).into(),
             register_id: RegisterId::R0,
             tpe: SType::SOption(SType::SLong.into()),
         })
@@ -95,7 +95,7 @@ mod tests {
     #[test]
     fn ser_roundtrip() {
         let e: Expr = Box::new(ExtractRegisterAs {
-            input: Box::new(GlobalVars::SelfBox.into()),
+            input: Box::new(GlobalVars::SelfBox).into(),
             register_id: RegisterId::R0,
             tpe: SType::SOption(SType::SLong.into()),
         })
diff --git a/ergo-lib/src/ast/method_call.rs b/ergo-lib/src/ast/method_call.rs
index c31c868de..956a2863e 100644
--- a/ergo-lib/src/ast/method_call.rs
+++ b/ergo-lib/src/ast/method_call.rs
@@ -6,7 +6,7 @@ use super::expr::Expr;
 
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct MethodCall {
-    pub obj: Box<Expr>,
+    pub obj: Expr,
     pub method: SMethod,
     pub args: Vec<Expr>,
 }
diff --git a/ergo-lib/src/ast/option_get.rs b/ergo-lib/src/ast/option_get.rs
index 3066307e9..3a1cbc800 100644
--- a/ergo-lib/src/ast/option_get.rs
+++ b/ergo-lib/src/ast/option_get.rs
@@ -67,7 +67,7 @@ mod tests {
     #[test]
     fn eval_get() {
         let get_reg_expr: Expr = Box::new(ExtractRegisterAs {
-            input: Box::new(GlobalVars::SelfBox.into()),
+            input: Box::new(GlobalVars::SelfBox).into(),
             register_id: RegisterId::R0,
             tpe: SType::SOption(SType::SLong.into()),
         })
diff --git a/ergo-lib/src/ast/property_call.rs b/ergo-lib/src/ast/property_call.rs
index 9616631d7..32fa06e0c 100644
--- a/ergo-lib/src/ast/property_call.rs
+++ b/ergo-lib/src/ast/property_call.rs
@@ -6,7 +6,7 @@ use super::expr::Expr;
 
 #[derive(PartialEq, Eq, Debug, Clone)]
 pub struct PropertyCall {
-    pub obj: Box<Expr>,
+    pub obj: Expr,
     pub method: SMethod,
 }
 
diff --git a/ergo-lib/src/chain/address.rs b/ergo-lib/src/chain/address.rs
index c2216095a..dee1bbf0f 100644
--- a/ergo-lib/src/chain/address.rs
+++ b/ergo-lib/src/chain/address.rs
@@ -86,12 +86,15 @@ impl Address {
     pub fn recreate_from_ergo_tree(tree: &ErgoTree) -> Result<Address, AddressError> {
         match tree.proposition() {
             Ok(expr) => Ok(match &*expr {
-                Expr::Const(Constant {
-                    tpe: SType::SSigmaProp,
-                    v,
-                }) => ProveDlog::try_from(v.clone())
-                    .map(Address::P2PK)
-                    .unwrap_or_else(|_| Address::P2S(tree.sigma_serialize_bytes())),
+                Expr::Const(c) => match &**c {
+                    Constant {
+                        tpe: SType::SSigmaProp,
+                        v,
+                    } => ProveDlog::try_from(v.clone())
+                        .map(Address::P2PK)
+                        .unwrap_or_else(|_| Address::P2S(tree.sigma_serialize_bytes())),
+                    _ => Address::P2S(tree.sigma_serialize_bytes()),
+                },
                 _ => Address::P2S(tree.sigma_serialize_bytes()),
             }),
             Err(_) => Ok(Address::P2S(tree.sigma_serialize_bytes())),
@@ -118,12 +121,12 @@ impl Address {
     /// script encoded in the address
     pub fn script(&self) -> Result<ErgoTree, SerializationError> {
         match self {
-            Address::P2PK(prove_dlog) => Ok(ErgoTree::from(Rc::new(Expr::Const(
+            Address::P2PK(prove_dlog) => Ok(ErgoTree::from(Rc::new(Expr::Const(Box::new(
                 SigmaProp::new(SigmaBoolean::ProofOfKnowledge(
                     SigmaProofOfKnowledgeTree::ProveDlog(prove_dlog.clone()),
                 ))
                 .into(),
-            )))),
+            ))))),
             Address::P2S(bytes) => ErgoTree::sigma_parse_bytes(bytes.to_vec()),
         }
     }
diff --git a/ergo-lib/src/ergo_tree.rs b/ergo-lib/src/ergo_tree.rs
index 2a4344a4a..7686bfe6f 100644
--- a/ergo-lib/src/ergo_tree.rs
+++ b/ergo-lib/src/ergo_tree.rs
@@ -141,9 +141,12 @@ impl ErgoTree {
 impl From<Rc<Expr>> for ErgoTree {
     fn from(expr: Rc<Expr>) -> Self {
         match expr.as_ref() {
-            Expr::Const(Constant { tpe, .. }) if *tpe == SType::SSigmaProp => {
-                ErgoTree::without_segregation(expr)
-            }
+            Expr::Const(c) => match &**c {
+                Constant { tpe, .. } if *tpe == SType::SSigmaProp => {
+                    ErgoTree::without_segregation(expr)
+                }
+                _ => ErgoTree::with_segregation(expr),
+            },
             _ => ErgoTree::with_segregation(expr),
         }
     }
@@ -277,10 +280,15 @@ impl TryFrom<ErgoTree> for ProveDlog {
             .proposition()
             .map_err(|_| TryExtractFromError("cannot read root expr".to_string()))?;
         match expr {
-            Expr::Const(Constant {
-                tpe: SType::SSigmaProp,
-                v,
-            }) => ProveDlog::try_from(v.clone()),
+            Expr::Const(c) => match &**c {
+                Constant {
+                    tpe: SType::SSigmaProp,
+                    v,
+                } => ProveDlog::try_from(v.clone()),
+                _ => Err(TryExtractFromError(
+                    "expected ProveDlog in the root".to_string(),
+                )),
+            },
             _ => Err(TryExtractFromError(
                 "expected ProveDlog in the root".to_string(),
             )),
@@ -296,6 +304,7 @@ mod tests {
     use crate::chain;
     use crate::chain::Base16DecodedBytes;
     use crate::serialization::sigma_serialize_roundtrip;
+    use crate::sigma_protocol::sigma_boolean::SigmaBoolean;
     use crate::sigma_protocol::sigma_boolean::SigmaProp;
     use proptest::prelude::*;
 
@@ -306,9 +315,9 @@ mod tests {
         fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
             prop_oneof![
                 // make sure that P2PK tree is included
-                any::<ProveDlog>().prop_map(|p| ErgoTree::from(Rc::new(Expr::from(
-                    Constant::from(SigmaProp::from(p))
-                )))),
+                any::<ProveDlog>().prop_map(|p| ErgoTree::from(Rc::new(Expr::Const(Box::new(
+                    Constant::from(SigmaProp::from(SigmaBoolean::from(p)))
+                ))))),
             ]
             .boxed()
         }
@@ -354,10 +363,13 @@ mod tests {
 
     #[test]
     fn test_constant_segregation() {
-        let expr = Expr::Const(Constant {
-            tpe: SType::SBoolean,
-            v: Value::Boolean(true),
-        });
+        let expr = Expr::Const(
+            Constant {
+                tpe: SType::SBoolean,
+                v: Value::Boolean(true),
+            }
+            .into(),
+        );
         let ergo_tree = ErgoTree::with_segregation(Rc::new(expr.clone()));
         let bytes = ergo_tree.sigma_serialize_bytes();
         let parsed_expr = ErgoTree::sigma_parse_bytes(bytes)
diff --git a/ergo-lib/src/eval/expr.rs b/ergo-lib/src/eval/expr.rs
index 276fb8b29..25c273aab 100644
--- a/ergo-lib/src/eval/expr.rs
+++ b/ergo-lib/src/eval/expr.rs
@@ -12,7 +12,7 @@ impl Evaluable for Expr {
         match self {
             Expr::Const(c) => Ok(c.v.clone()),
             Expr::PredefFunc(_) => todo!(),
-            Expr::CollM(_) => todo!(),
+            Expr::Fold(_) => todo!(),
             Expr::ExtractRegisterAs(v) => v.eval(env, ectx),
             Expr::GlobalVars(v) => v.eval(env, ectx),
             Expr::MethodCall(v) => v.eval(env, ectx),
diff --git a/ergo-lib/src/eval/global_vars.rs b/ergo-lib/src/eval/global_vars.rs
index 4e01d7dec..3fd32886b 100644
--- a/ergo-lib/src/eval/global_vars.rs
+++ b/ergo-lib/src/eval/global_vars.rs
@@ -35,7 +35,7 @@ mod tests {
     fn eval_height() {
         let ctx = Rc::new(force_any_val::<Context>());
         assert_eq!(
-            eval_out::<i32>(&GlobalVars::Height.into(), ctx.clone()),
+            eval_out::<i32>(&Box::new(GlobalVars::Height).into(), ctx.clone()),
             ctx.height
         );
     }
@@ -44,7 +44,7 @@ mod tests {
     fn eval_self_box() {
         let ctx = Rc::new(force_any_val::<Context>());
         assert_eq!(
-            eval_out::<ErgoBox>(&GlobalVars::SelfBox.into(), ctx.clone()),
+            eval_out::<ErgoBox>(&Box::new(GlobalVars::SelfBox).into(), ctx.clone()),
             ctx.self_box
         );
     }
@@ -53,7 +53,7 @@ mod tests {
     fn eval_outputs() {
         let ctx = Rc::new(force_any_val::<Context>());
         assert_eq!(
-            eval_out::<Vec<ErgoBox>>(&GlobalVars::Outputs.into(), ctx.clone()),
+            eval_out::<Vec<ErgoBox>>(&Box::new(GlobalVars::Outputs).into(), ctx.clone()),
             ctx.outputs
         );
     }
diff --git a/ergo-lib/src/eval/method_call.rs b/ergo-lib/src/eval/method_call.rs
index f3d43e891..f10eb5b2c 100644
--- a/ergo-lib/src/eval/method_call.rs
+++ b/ergo-lib/src/eval/method_call.rs
@@ -8,7 +8,7 @@ use super::Evaluable;
 
 impl Evaluable for MethodCall {
     fn eval(&self, env: &Env, ectx: &mut EvalContext) -> Result<Value, EvalError> {
-        let ov = (*self.obj).eval(env, ectx)?;
+        let ov = self.obj.eval(env, ectx)?;
         let argsv: Result<Vec<Value>, EvalError> =
             self.args.iter().map(|arg| arg.eval(env, ectx)).collect();
         self.method.eval_fn()(ov, argsv?)
@@ -32,11 +32,11 @@ mod tests {
 
     #[test]
     fn eval_box_get_reg() {
-        let mc: Expr = MethodCall {
-            obj: Box::new(GlobalVars::SelfBox.into()),
+        let mc: Expr = Box::new(MethodCall {
+            obj: Box::new(GlobalVars::SelfBox).into(),
             method: sbox::GET_REG_METHOD.clone(),
-            args: vec![Constant::from(0i8).into()],
-        }
+            args: vec![Box::new(Constant::from(0i8)).into()],
+        })
         .into();
         let option_get_expr: Expr = Box::new(OptionGet { input: mc }).into();
         let ctx = Rc::new(force_any_val::<Context>());
diff --git a/ergo-lib/src/eval/property_call.rs b/ergo-lib/src/eval/property_call.rs
index 0c1e1ca9b..14ccf2490 100644
--- a/ergo-lib/src/eval/property_call.rs
+++ b/ergo-lib/src/eval/property_call.rs
@@ -8,7 +8,7 @@ use super::Evaluable;
 
 impl Evaluable for PropertyCall {
     fn eval(&self, env: &Env, ectx: &mut EvalContext) -> Result<Value, EvalError> {
-        let ov = (*self.obj).eval(env, ectx)?;
+        let ov = self.obj.eval(env, ectx)?;
         self.method.eval_fn()(ov, vec![])
     }
 }
@@ -28,14 +28,12 @@ mod tests {
 
     #[test]
     fn eval_context_data_inputs() {
-        let pc = PropertyCall {
-            obj: Box::new(Expr::Context),
+        let pc: Expr = Box::new(PropertyCall {
+            obj: Expr::Context,
             method: scontext::DATA_INPUTS_PROPERTY.clone(),
-        };
+        })
+        .into();
         let ctx = Rc::new(force_any_val::<Context>());
-        assert_eq!(
-            eval_out::<Vec<ErgoBox>>(&pc.into(), ctx.clone()),
-            ctx.data_inputs
-        );
+        assert_eq!(eval_out::<Vec<ErgoBox>>(&pc, ctx.clone()), ctx.data_inputs);
     }
 }
diff --git a/ergo-lib/src/serialization.rs b/ergo-lib/src/serialization.rs
index 3a4384093..1223015ad 100644
--- a/ergo-lib/src/serialization.rs
+++ b/ergo-lib/src/serialization.rs
@@ -4,7 +4,6 @@ mod constant;
 mod constant_placeholder;
 mod data;
 mod expr;
-mod fold;
 mod global_vars;
 mod method_call;
 mod property_call;
diff --git a/ergo-lib/src/serialization/expr.rs b/ergo-lib/src/serialization/expr.rs
index cda205243..1de5a1b14 100644
--- a/ergo-lib/src/serialization/expr.rs
+++ b/ergo-lib/src/serialization/expr.rs
@@ -1,5 +1,5 @@
-use super::{fold::FoldSerializer, op_code::OpCode, sigma_byte_writer::SigmaByteWrite};
-use crate::ast::coll_methods::CollM;
+use super::{op_code::OpCode, sigma_byte_writer::SigmaByteWrite};
+use crate::ast::coll_fold::Fold;
 use crate::ast::constant::Constant;
 use crate::ast::constant::ConstantPlaceholder;
 use crate::ast::expr::Expr;
@@ -19,7 +19,7 @@ impl SigmaSerializable for Expr {
         match self {
             Expr::Const(c) => match w.constant_store() {
                 Some(cs) => {
-                    let ph = cs.put(c.clone());
+                    let ph = cs.put(*c.clone());
                     ph.op_code().sigma_serialize(w)?;
                     ph.sigma_serialize(w)
                 }
@@ -29,9 +29,7 @@ impl SigmaSerializable for Expr {
                 let op_code = self.op_code();
                 op_code.sigma_serialize(w)?;
                 match expr {
-                    Expr::CollM(cm) => match cm {
-                        CollM::Fold { .. } => FoldSerializer::sigma_serialize(expr, w),
-                    },
+                    Expr::Fold(op) => op.sigma_serialize(w),
                     Expr::ConstPlaceholder(cp) => cp.sigma_serialize(w),
                     Expr::GlobalVars(_) => Ok(()),
                     Expr::MethodCall(mc) => mc.sigma_serialize(w),
@@ -56,28 +54,30 @@ impl SigmaSerializable for Expr {
         }?;
         if first_byte <= OpCode::LAST_CONSTANT_CODE.value() {
             let constant = Constant::sigma_parse(r)?;
-            Ok(Expr::Const(constant))
+            Ok(Expr::Const(constant.into()))
         } else {
             let op_code = OpCode::sigma_parse(r)?;
             match op_code {
-                FoldSerializer::OP_CODE => FoldSerializer::sigma_parse(r),
+                OpCode::FOLD => Ok(Box::new(Fold::sigma_parse(r)?).into()),
                 ConstantPlaceholder::OP_CODE => {
                     let cp = ConstantPlaceholder::sigma_parse(r)?;
                     if r.substitute_placeholders() {
                         // ConstantPlaceholder itself can be created only if a corresponding
                         // constant is in the constant_store, thus unwrap() is safe here
                         let c = r.constant_store().get(cp.id).unwrap();
-                        Ok(Expr::Const(c.clone()))
+                        Ok(Expr::Const(c.clone().into()))
                     } else {
-                        Ok(Expr::ConstPlaceholder(cp))
+                        Ok(Expr::ConstPlaceholder(cp.into()))
                     }
                 }
-                OpCode::HEIGHT => Ok(Expr::GlobalVars(GlobalVars::Height)),
-                OpCode::SELF_BOX => Ok(Expr::GlobalVars(GlobalVars::SelfBox)),
-                OpCode::INPUTS => Ok(Expr::GlobalVars(GlobalVars::Inputs)),
-                OpCode::OUTPUTS => Ok(Expr::GlobalVars(GlobalVars::Outputs)),
-                OpCode::PROPERTY_CALL => Ok(Expr::ProperyCall(PropertyCall::sigma_parse(r)?)),
-                OpCode::METHOD_CALL => Ok(Expr::MethodCall(MethodCall::sigma_parse(r)?)),
+                OpCode::HEIGHT => Ok(Expr::GlobalVars(GlobalVars::Height.into())),
+                OpCode::SELF_BOX => Ok(Expr::GlobalVars(GlobalVars::SelfBox.into())),
+                OpCode::INPUTS => Ok(Expr::GlobalVars(GlobalVars::Inputs.into())),
+                OpCode::OUTPUTS => Ok(Expr::GlobalVars(GlobalVars::Outputs.into())),
+                OpCode::PROPERTY_CALL => {
+                    Ok(Expr::ProperyCall(PropertyCall::sigma_parse(r)?.into()))
+                }
+                OpCode::METHOD_CALL => Ok(Expr::MethodCall(MethodCall::sigma_parse(r)?.into())),
                 OpCode::CONTEXT => Ok(Expr::Context),
                 OpCode::OPTION_GET => Ok(Box::new(OptionGet::sigma_parse(r)?).into()),
                 OpCode::EXTRACT_REGISTER_AS => {
diff --git a/ergo-lib/src/serialization/fold.rs b/ergo-lib/src/serialization/fold.rs
deleted file mode 100644
index 33af5e6b9..000000000
--- a/ergo-lib/src/serialization/fold.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use super::{op_code::OpCode, sigma_byte_writer::SigmaByteWrite};
-use crate::ast::coll_methods::CollM;
-use crate::ast::expr::Expr;
-use crate::serialization::{
-    sigma_byte_reader::SigmaByteRead, SerializationError, SigmaSerializable,
-};
-
-use std::io;
-
-pub struct FoldSerializer {}
-
-impl FoldSerializer {
-    pub const OP_CODE: OpCode = OpCode::FOLD;
-
-    pub fn sigma_serialize<W: SigmaByteWrite>(expr: &Expr, w: &mut W) -> Result<(), io::Error> {
-        match expr {
-            Expr::CollM(CollM::Fold {
-                input,
-                zero,
-                fold_op,
-            }) => {
-                input.sigma_serialize(w)?;
-                zero.sigma_serialize(w)?;
-                fold_op.sigma_serialize(w)?;
-                Ok(())
-            }
-            _ => panic!("expected Fold"),
-        }
-    }
-
-    pub fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Expr, SerializationError> {
-        let input = Expr::sigma_parse(r)?;
-        let zero = Expr::sigma_parse(r)?;
-        let fold_op = Expr::sigma_parse(r)?;
-        Ok(Expr::CollM(CollM::Fold {
-            input: Box::new(input),
-            zero: Box::new(zero),
-            fold_op: Box::new(fold_op),
-        }))
-    }
-}
diff --git a/ergo-lib/src/serialization/global_vars.rs b/ergo-lib/src/serialization/global_vars.rs
index 83498be41..0c2475fc0 100644
--- a/ergo-lib/src/serialization/global_vars.rs
+++ b/ergo-lib/src/serialization/global_vars.rs
@@ -10,7 +10,7 @@ mod tests {
 
         #[test]
         fn ser_roundtrip(v in any::<GlobalVars>()) {
-            let expr = Expr::GlobalVars(v);
+            let expr = Expr::GlobalVars(v.into());
             prop_assert_eq![sigma_serialize_roundtrip(&expr), expr];
         }
     }
diff --git a/ergo-lib/src/serialization/method_call.rs b/ergo-lib/src/serialization/method_call.rs
index f3faf31d4..a8c634d04 100644
--- a/ergo-lib/src/serialization/method_call.rs
+++ b/ergo-lib/src/serialization/method_call.rs
@@ -31,7 +31,7 @@ impl SigmaSerializable for MethodCall {
             args.push(Expr::sigma_parse(r)?);
         }
         Ok(MethodCall {
-            obj: Box::new(obj),
+            obj,
             method: SMethod::from_ids(type_id, method_id),
             args,
         })
@@ -40,20 +40,21 @@ impl SigmaSerializable for MethodCall {
 
 #[cfg(test)]
 mod tests {
-    // use crate::ast::expr::Expr;
-    // use crate::ast::method_call::MethodCall;
-    // use crate::serialization::sigma_serialize_roundtrip;
-    // use crate::types::scontext;
+    use crate::ast::constant::Constant;
+    use crate::ast::expr::Expr;
+    use crate::ast::global_vars::GlobalVars;
+    use crate::ast::method_call::MethodCall;
+    use crate::serialization::sigma_serialize_roundtrip;
+    use crate::types::sbox;
 
-    // #[test]
-    // fn ser_roundtrip_property() {
-    //     let mc = MethodCall {
-    //         tpe: scontext::DATA_INPUTS_METHOD.tpe().clone(),
-    //         obj: Box::new(Expr::Context),
-    //         method: scontext::DATA_INPUTS_METHOD.clone(),
-    //         args: vec![],
-    //     };
-    //     let expr = Expr::MethodCall(mc);
-    //     assert_eq![sigma_serialize_roundtrip(&expr), expr];
-    // }
+    #[test]
+    fn ser_roundtrip_property() {
+        let mc: Expr = Box::new(MethodCall {
+            obj: Box::new(GlobalVars::SelfBox).into(),
+            method: sbox::GET_REG_METHOD.clone(),
+            args: vec![Box::new(Constant::from(0i8)).into()],
+        })
+        .into();
+        assert_eq![sigma_serialize_roundtrip(&mc), mc];
+    }
 }
diff --git a/ergo-lib/src/serialization/property_call.rs b/ergo-lib/src/serialization/property_call.rs
index 89a126353..abbe7e9b0 100644
--- a/ergo-lib/src/serialization/property_call.rs
+++ b/ergo-lib/src/serialization/property_call.rs
@@ -24,7 +24,7 @@ impl SigmaSerializable for PropertyCall {
         let method_id = MethodId::sigma_parse(r)?;
         let obj = Expr::sigma_parse(r)?;
         Ok(PropertyCall {
-            obj: Box::new(obj),
+            obj,
             method: SMethod::from_ids(type_id, method_id),
         })
     }
@@ -40,9 +40,10 @@ mod tests {
     #[test]
     fn ser_roundtrip_property() {
         let mc = PropertyCall {
-            obj: Box::new(Expr::Context),
+            obj: Expr::Context,
             method: scontext::DATA_INPUTS_PROPERTY.clone(),
-        };
+        }
+        .into();
         let expr = Expr::ProperyCall(mc);
         assert_eq![sigma_serialize_roundtrip(&expr), expr];
     }
diff --git a/ergo-lib/src/sigma_protocol/fiat_shamir.rs b/ergo-lib/src/sigma_protocol/fiat_shamir.rs
index 54f6cb477..61498bd85 100644
--- a/ergo-lib/src/sigma_protocol/fiat_shamir.rs
+++ b/ergo-lib/src/sigma_protocol/fiat_shamir.rs
@@ -76,9 +76,9 @@ pub fn fiat_shamir_tree_to_bytes(tree: &ProofTree) -> Vec<u8> {
         _ => todo!(),
     };
 
-    let prop_tree = ErgoTree::with_segregation(Rc::new(Expr::Const(
+    let prop_tree = ErgoTree::with_segregation(Rc::new(Expr::Const(Box::new(
         SigmaProp::new(leaf.proposition()).into(),
-    )));
+    ))));
     let mut prop_bytes = prop_tree.sigma_serialize_bytes();
     // TODO: is unwrap safe here? Create new type with non-optional commitment? Decide when other scenarios
     // are implemented (leafs and trees)
diff --git a/ergo-lib/src/sigma_protocol/prover.rs b/ergo-lib/src/sigma_protocol/prover.rs
index 2b700fd76..2787cb0a4 100644
--- a/ergo-lib/src/sigma_protocol/prover.rs
+++ b/ergo-lib/src/sigma_protocol/prover.rs
@@ -311,10 +311,13 @@ mod tests {
 
     #[test]
     fn test_prove_true_prop() {
-        let bool_true_tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
-            tpe: SType::SBoolean,
-            v: Value::Boolean(true),
-        })));
+        let bool_true_tree = ErgoTree::from(Rc::new(Expr::Const(
+            Constant {
+                tpe: SType::SBoolean,
+                v: Value::Boolean(true),
+            }
+            .into(),
+        )));
         let message = vec![0u8; 100];
 
         let prover = TestProver { secrets: vec![] };
@@ -330,10 +333,13 @@ mod tests {
 
     #[test]
     fn test_prove_false_prop() {
-        let bool_false_tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
-            tpe: SType::SBoolean,
-            v: Value::Boolean(false),
-        })));
+        let bool_false_tree = ErgoTree::from(Rc::new(Expr::Const(
+            Constant {
+                tpe: SType::SBoolean,
+                v: Value::Boolean(false),
+            }
+            .into(),
+        )));
         let message = vec![0u8; 100];
 
         let prover = TestProver { secrets: vec![] };
@@ -351,10 +357,13 @@ mod tests {
     fn test_prove_pk_prop() {
         let secret = DlogProverInput::random();
         let pk = secret.public_image();
-        let tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
-            tpe: SType::SSigmaProp,
-            v: pk.into(),
-        })));
+        let tree = ErgoTree::from(Rc::new(Expr::Const(
+            Constant {
+                tpe: SType::SSigmaProp,
+                v: pk.into(),
+            }
+            .into(),
+        )));
         let message = vec![0u8; 100];
 
         let prover = TestProver {
diff --git a/ergo-lib/src/sigma_protocol/verifier.rs b/ergo-lib/src/sigma_protocol/verifier.rs
index 3f1b698dc..eef3209a8 100644
--- a/ergo-lib/src/sigma_protocol/verifier.rs
+++ b/ergo-lib/src/sigma_protocol/verifier.rs
@@ -142,7 +142,7 @@ mod tests {
             let tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
                 tpe: SType::SSigmaProp,
                 v: pk.into(),
-            })));
+            }.into())));
 
             let prover = TestProver {
                 secrets: vec![PrivateInput::DlogProverInput(secret)],
diff --git a/ergo-lib/src/types/stype_companion.rs b/ergo-lib/src/types/stype_companion.rs
index 53e6d087c..88dbb00db 100644
--- a/ergo-lib/src/types/stype_companion.rs
+++ b/ergo-lib/src/types/stype_companion.rs
@@ -6,6 +6,7 @@ use crate::serialization::sigma_byte_writer::SigmaByteWrite;
 use crate::serialization::SerializationError;
 use crate::serialization::SigmaSerializable;
 
+use super::sbox;
 use super::scontext;
 use super::smethod::MethodId;
 use super::smethod::SMethod;
@@ -44,6 +45,8 @@ impl STypeCompanion {
     pub fn type_by_id(type_id: TypeId) -> &'static STypeCompanion {
         if type_id == scontext::S_CONTEXT_TYPE_COMPANION.type_id() {
             &scontext::S_CONTEXT_TYPE_COMPANION
+        } else if type_id == sbox::S_BOX_TYPE_COMPANION.type_id() {
+            &sbox::S_BOX_TYPE_COMPANION
         } else {
             todo!("cannot find STypeCompanion for {0:?} type id", type_id)
         }
diff --git a/ergo-lib/src/wallet/signing.rs b/ergo-lib/src/wallet/signing.rs
index 7c726a342..1216b8dd5 100644
--- a/ergo-lib/src/wallet/signing.rs
+++ b/ergo-lib/src/wallet/signing.rs
@@ -139,7 +139,7 @@ mod tests {
                 let tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
                     tpe: SType::SSigmaProp,
                     v: pk.into(),
-                })));
+                }.into())));
                 ErgoBox::new(BoxValue::SAFE_USER_MIN,
                              tree,
                              vec![],
@@ -155,7 +155,7 @@ mod tests {
             let ergo_tree = ErgoTree::from(Rc::new(Expr::Const(Constant {
                     tpe: SType::SSigmaProp,
                     v: secrets.get(0).unwrap().public_image().into(),
-            })));
+            }.into())));
             let candidate = ErgoBoxCandidateBuilder::new(BoxValue::SAFE_USER_MIN, ergo_tree, 0)
                 .build().unwrap();
             let output_candidates = vec![candidate];


Test patch: