diff BUGFIX handle merging opaque diff nodes
diff --git a/src/diff.c b/src/diff.c
index 0625bc9..d05d319 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -1569,33 +1569,41 @@
 /**
  * @brief Update operations in a diff node when the new operation is CREATE.
  *
- * @param[in] diff_match Node from the diff.
+ * @param[in,out] diff_match Node from the diff, may be replaced.
+ * @param[in,out] diff Diff root node, may be updated.
  * @param[in] cur_op Current operation of @p diff_match.
  * @param[in] src_diff Current source diff node.
  * @param[in] options Diff merge options.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyd_diff_merge_create(struct lyd_node *diff_match, enum lyd_diff_op cur_op, const struct lyd_node *src_diff, uint16_t options)
+lyd_diff_merge_create(struct lyd_node **diff_match, struct lyd_node **diff, enum lyd_diff_op cur_op,
+        const struct lyd_node *src_diff, uint16_t options)
 {
-    struct lyd_node *child;
+    struct lyd_node *child, *src_dup, *to_free = NULL;
     const struct lysc_node_leaf *sleaf = NULL;
     uint32_t trg_flags;
     const char *meta_name, *orig_meta_name;
     struct lyd_meta *meta, *orig_meta;
-    const struct ly_ctx *ctx = LYD_CTX(diff_match);
+    const struct ly_ctx *ctx = LYD_CTX(*diff_match);
+    LY_ERR r;
+
+    /* create operation is valid only for data nodes */
+    LY_CHECK_ERR_RET(!src_diff->schema, LOGINT(ctx), LY_EINT);
 
     switch (cur_op) {
     case LYD_DIFF_OP_DELETE:
         /* remember current flags */
-        trg_flags = diff_match->flags;
+        trg_flags = (*diff_match)->flags;
 
-        if (lysc_is_userordered(diff_match->schema)) {
+        if (lysc_is_userordered(src_diff->schema)) {
+            assert((*diff_match)->schema);
+
             /* get anchor metadata */
-            if (lysc_is_dup_inst_list(diff_match->schema)) {
+            if (lysc_is_dup_inst_list((*diff_match)->schema)) {
                 meta_name = "yang:position";
                 orig_meta_name = "yang:orig-position";
-            } else if (diff_match->schema->nodetype == LYS_LIST) {
+            } else if ((*diff_match)->schema->nodetype == LYS_LIST) {
                 meta_name = "yang:key";
                 orig_meta_name = "yang:orig-key";
             } else {
@@ -1604,71 +1612,86 @@
             }
             meta = lyd_find_meta(src_diff->meta, NULL, meta_name);
             LY_CHECK_ERR_RET(!meta, LOGERR_META(ctx, meta_name, src_diff), LY_EINVAL);
-            orig_meta = lyd_find_meta(diff_match->meta, NULL, orig_meta_name);
-            LY_CHECK_ERR_RET(!orig_meta, LOGERR_META(ctx, orig_meta_name, diff_match), LY_EINVAL);
+            orig_meta = lyd_find_meta((*diff_match)->meta, NULL, orig_meta_name);
+            LY_CHECK_ERR_RET(!orig_meta, LOGERR_META(ctx, orig_meta_name, *diff_match), LY_EINVAL);
 
             /* the (incorrect) assumption made here is that there are no previous diff nodes that would affect
              * the anchors stored in the metadata */
             if (strcmp(lyd_get_meta_value(meta), lyd_get_meta_value(orig_meta))) {
                 /* deleted + created at another position -> operation REPLACE */
-                LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_REPLACE));
+                LY_CHECK_RET(lyd_diff_change_op(*diff_match, LYD_DIFF_OP_REPLACE));
 
                 /* add anchor metadata */
-                LY_CHECK_RET(lyd_dup_meta_single(meta, diff_match, NULL));
+                LY_CHECK_RET(lyd_dup_meta_single(meta, *diff_match, NULL));
             } else {
                 /* deleted + created at the same position -> operation NONE */
-                LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_NONE));
+                LY_CHECK_RET(lyd_diff_change_op(*diff_match, LYD_DIFF_OP_NONE));
 
                 /* delete anchor metadata */
                 lyd_free_meta_single(orig_meta);
             }
-        } else if (diff_match->schema->nodetype == LYS_LEAF) {
+        } else if (src_diff->schema->nodetype == LYS_LEAF) {
             if (options & LYD_DIFF_MERGE_DEFAULTS) {
                 /* we are dealing with a leaf and are handling default values specially (as explicit nodes) */
-                sleaf = (struct lysc_node_leaf *)diff_match->schema;
+                sleaf = (struct lysc_node_leaf *)src_diff->schema;
             }
 
             if (sleaf && sleaf->dflt && !sleaf->dflt->realtype->plugin->compare(sleaf->dflt,
                     &((struct lyd_node_term *)src_diff)->value)) {
                 /* we deleted it, so a default value was in-use, and it matches the created value -> operation NONE */
-                LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_NONE));
-            } else if (!lyd_compare_single(diff_match, src_diff, 0)) {
+                LY_CHECK_RET(lyd_diff_change_op(*diff_match, LYD_DIFF_OP_NONE));
+            } else if (!lyd_compare_single(*diff_match, src_diff, 0)) {
                 /* deleted + created -> operation NONE */
-                LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_NONE));
-            } else {
+                LY_CHECK_RET(lyd_diff_change_op(*diff_match, LYD_DIFF_OP_NONE));
+            } else if ((*diff_match)->schema) {
                 /* we deleted it, but it was created with a different value -> operation REPLACE */
-                LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_REPLACE));
+                LY_CHECK_RET(lyd_diff_change_op(*diff_match, LYD_DIFF_OP_REPLACE));
 
                 /* current value is the previous one (meta) */
-                LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), diff_match, NULL, "yang:orig-value",
-                        lyd_get_value(diff_match), 0, NULL));
+                LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), *diff_match, NULL, "yang:orig-value",
+                        lyd_get_value(*diff_match), 0, NULL));
 
                 /* update the value itself */
-                LY_CHECK_RET(lyd_change_term(diff_match, lyd_get_value(src_diff)));
+                LY_CHECK_RET(lyd_change_term(*diff_match, lyd_get_value(src_diff)));
+            } else {
+                /* also operation REPLACE but we need to change an opaque node into a data node */
+                LY_CHECK_RET(lyd_dup_single(src_diff, (*diff_match)->parent, LYD_DUP_NO_META | LYD_DUP_WITH_FLAGS, &src_dup));
+                if (!(*diff_match)->parent) {
+                    /* will always be inserted before diff_match, which is opaque */
+                    LY_CHECK_RET(lyd_insert_sibling(*diff_match, src_dup, diff));
+                }
+                to_free = *diff_match;
+                *diff_match = src_dup;
+
+                r = lyd_new_meta(ctx, src_dup, NULL, "yang:orig-value", lyd_get_value(to_free), 0, NULL);
+                lyd_free_tree(to_free);
+                LY_CHECK_RET(r);
+                LY_CHECK_RET(lyd_new_meta(ctx, src_dup, NULL, "yang:operation", lyd_diff_op2str(LYD_DIFF_OP_REPLACE), 0, NULL));
             }
         } else {
             /* deleted + created -> operation NONE */
-            LY_CHECK_RET(lyd_diff_change_op(diff_match, LYD_DIFF_OP_NONE));
+            LY_CHECK_RET(lyd_diff_change_op(*diff_match, LYD_DIFF_OP_NONE));
         }
 
-        if (diff_match->schema->nodetype & LYD_NODE_TERM) {
+        assert((*diff_match)->schema);
+        if ((*diff_match)->schema->nodetype & LYD_NODE_TERM) {
             /* add orig-dflt metadata */
-            LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), diff_match, NULL, "yang:orig-default",
+            LY_CHECK_RET(lyd_new_meta(LYD_CTX(src_diff), *diff_match, NULL, "yang:orig-default",
                     trg_flags & LYD_DEFAULT ? "true" : "false", 0, NULL));
 
             /* update dflt flag itself */
-            diff_match->flags &= ~LYD_DEFAULT;
-            diff_match->flags |= src_diff->flags & LYD_DEFAULT;
+            (*diff_match)->flags &= ~LYD_DEFAULT;
+            (*diff_match)->flags |= src_diff->flags & LYD_DEFAULT;
         }
 
         /* but the operation of its children should remain DELETE */
-        LY_LIST_FOR(lyd_child_no_keys(diff_match), child) {
+        LY_LIST_FOR(lyd_child_no_keys(*diff_match), child) {
             LY_CHECK_RET(lyd_diff_change_op(child, LYD_DIFF_OP_DELETE));
         }
         break;
     default:
         /* create and replace operations are not valid */
-        LOGERR_MERGEOP(LYD_CTX(src_diff), diff_match, cur_op, LYD_DIFF_OP_CREATE);
+        LOGERR_MERGEOP(LYD_CTX(src_diff), *diff_match, cur_op, LYD_DIFF_OP_CREATE);
         return LY_EINVAL;
     }
 
@@ -1895,7 +1918,7 @@
                 goto add_diff;
             }
 
-            ret = lyd_diff_merge_create(diff_node, cur_op, src_diff, options);
+            ret = lyd_diff_merge_create(&diff_node, diff, cur_op, src_diff, options);
             break;
         case LYD_DIFF_OP_DELETE:
             ret = lyd_diff_merge_delete(diff_node, cur_op, src_diff);