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

Issue:
[100 SigmaUSD] `LastBlockUtxoRootHash` IR node
Evaluation should return the AvlTree built from `Context::headers[0].stateRoot` (see https://github.com/ergoplatform/ergo/blob/246ac2918028462a07dff19ea1ca35e4e15bb5e0/ergo-wallet/src/main/scala/org/ergoplatform/wallet/interpreter/ErgoInterpreter.scala#L97-L101 )

Reference Scala implementation - https://github.com/ScorexFoundation/sigmastate-interpreter/blob/c863a9b1a82589e47b15f76f3affdb30a475e740/sigmastate/src/main/scala/org/ergoplatform/ErgoLikeContext.scala#L284-L296



Discussion / hints:
Working on this.

Fix patch:
diff --git a/ergotree-interpreter/src/eval.rs b/ergotree-interpreter/src/eval.rs
index 28d591afe..e7bb66918 100644
--- a/ergotree-interpreter/src/eval.rs
+++ b/ergotree-interpreter/src/eval.rs
@@ -224,6 +224,9 @@ fn smethod_eval_fn(method: &SMethod) -> Result<EvalFn, EvalError> {
             scontext::SELF_BOX_INDEX_PROPERTY_METHOD_ID => self::scontext::SELF_BOX_INDEX_EVAL_FN,
             scontext::HEADERS_PROPERTY_METHOD_ID => self::scontext::HEADERS_EVAL_FN,
             scontext::PRE_HEADER_PROPERTY_METHOD_ID => self::scontext::PRE_HEADER_EVAL_FN,
+            scontext::LAST_BLOCK_UTXO_ROOT_HASH_PROPERTY_METHOD_ID => {
+                self::scontext::LAST_BLOCK_UTXO_ROOT_HASH_EVAL_FN
+            }
             method_id => {
                 return Err(EvalError::NotFound(format!(
                     "Eval fn: unknown method id in SContext: {:?}",
diff --git a/ergotree-interpreter/src/eval/scontext.rs b/ergotree-interpreter/src/eval/scontext.rs
index ccfaf5609..689cab5e4 100644
--- a/ergotree-interpreter/src/eval/scontext.rs
+++ b/ergotree-interpreter/src/eval/scontext.rs
@@ -1,3 +1,5 @@
+use ergotree_ir::mir::avl_tree_data::AvlTreeData;
+use ergotree_ir::mir::avl_tree_data::AvlTreeFlags;
 use ergotree_ir::mir::value::CollKind;
 use ergotree_ir::mir::value::Value;
 use ergotree_ir::types::stype::SType;
@@ -70,6 +72,23 @@ pub(crate) static PRE_HEADER_EVAL_FN: EvalFn = |_env, ctx, obj, _args| {
     Ok(Box::from(ctx.ctx.pre_header.clone()).into())
 };
 
+pub(crate) static LAST_BLOCK_UTXO_ROOT_HASH_EVAL_FN: EvalFn = |_env, ctx, obj, _args| {
+    if obj != Value::Context {
+        return Err(EvalError::UnexpectedValue(format!(
+            "Context.LastBlockUtxoRootHash: expected object of Value::Context, got {:?}",
+            obj
+        )));
+    }
+    let digest = ctx.ctx.headers[0].state_root.clone();
+    let tree_flags = AvlTreeFlags::new(true, true, true);
+    Ok(Value::AvlTree(Box::from(AvlTreeData {
+        digest,
+        tree_flags,
+        key_length: 32,
+        value_length_opt: None,
+    })))
+};
+
 #[cfg(test)]
 #[cfg(feature = "arbitrary")]
 #[allow(clippy::unwrap_used, clippy::expect_used)]
@@ -79,6 +98,7 @@ mod tests {
     use ergotree_ir::chain::ergo_box::ErgoBox;
     use ergotree_ir::chain::header::Header;
     use ergotree_ir::chain::preheader::PreHeader;
+    use ergotree_ir::mir::avl_tree_data::{AvlTreeData, AvlTreeFlags};
     use ergotree_ir::mir::expr::Expr;
     use ergotree_ir::mir::property_call::PropertyCall;
     use ergotree_ir::types::scontext;
@@ -124,4 +144,24 @@ mod tests {
         let ctx = Rc::new(force_any_val::<Context>());
         assert_eq!(eval_out::<PreHeader>(&expr, ctx.clone()), ctx.pre_header);
     }
+
+    #[test]
+    fn eval_last_block_utxo_root_hash() {
+        let expr: Expr = PropertyCall::new(
+            Expr::Context,
+            scontext::LAST_BLOCK_UTXO_ROOT_HASH_PROPERTY.clone(),
+        )
+        .unwrap()
+        .into();
+        let ctx = Rc::new(force_any_val::<Context>());
+        let digest = ctx.headers[0].state_root.clone();
+        let tree_flags = AvlTreeFlags::new(true, true, true);
+        let avl_tree_data = AvlTreeData {
+            digest,
+            tree_flags,
+            key_length: 32,
+            value_length_opt: None,
+        };
+        assert_eq!(eval_out::<AvlTreeData>(&expr, ctx), avl_tree_data);
+    }
 }
diff --git a/ergotree-ir/README.md b/ergotree-ir/README.md
index 690e793d3..3a539a2f8 100644
--- a/ergotree-ir/README.md
+++ b/ergotree-ir/README.md
@@ -25,11 +25,6 @@ Descriptions for the operations can be found in [ErgoTree Specification](https:/
 
 - isProven
 
-#### Context
-
-- LastBlockUtxoRootHash
-
-
 ## Implemented operations (IR nodes): 
 
 ### General
@@ -146,6 +141,7 @@ Descriptions for the operations can be found in [ErgoTree Specification](https:/
 - selfBoxIndex
 - headers
 - preHeader
+- LastBlockUtxoRootHash
 
 #### AvlTree 
 
diff --git a/ergotree-ir/src/types/scontext.rs b/ergotree-ir/src/types/scontext.rs
index 1f398dcf2..432a01388 100644
--- a/ergotree-ir/src/types/scontext.rs
+++ b/ergotree-ir/src/types/scontext.rs
@@ -135,7 +135,7 @@ lazy_static! {
     );
 }
 lazy_static! {
-    static ref LAST_BLOCK_UTXO_ROOT_HASH_PROPERTY: SMethod = SMethod::new(
+    pub static ref LAST_BLOCK_UTXO_ROOT_HASH_PROPERTY: SMethod = SMethod::new(
         STypeCompanion::Context,
         LAST_BLOCK_UTXO_ROOT_HASH_PROPERTY_METHOD_DESC.clone()
     );


Test patch: