From b81b4340bffb18ce56c68a4c8461cbe154a950a9 Mon Sep 17 00:00:00 2001
From: "Constantin P." <papizh.konstantin@demlabs.net>
Date: Tue, 4 Jun 2024 14:25:38 +0000
Subject: [PATCH] Decrees are now bound to net

---
 modules/net/dap_chain_net.c                   |  18 +++
 modules/net/dap_chain_net_anchor.c            |  23 ++--
 modules/net/dap_chain_net_decree.c            | 123 ++++++++----------
 modules/net/dap_chain_node_cli_cmd_tx.c       |  13 +-
 modules/net/include/dap_chain_net.h           |  11 +-
 modules/net/include/dap_chain_net_decree.h    |   6 +-
 .../dap_chain_net_srv_stake_pos_delegate.c    |   3 +-
 modules/type/blocks/dap_chain_cs_blocks.c     |  18 +--
 8 files changed, 108 insertions(+), 107 deletions(-)

diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index addabe4fa0..f5e39df6e4 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -184,6 +184,8 @@ typedef struct dap_chain_net_pvt{
 
     // Block sign rewards history
     struct block_reward *rewards;
+    dap_chain_net_decree_t *decree;
+    decree_table_t *decrees;
 } dap_chain_net_pvt_t;
 
 typedef struct dap_chain_net_item{
@@ -3347,3 +3349,19 @@ void dap_chain_net_announce_addrs(dap_chain_net_t *a_net)
                l_net_pvt->node_info->ext_port, a_net->pub.name);
     }
 }
+
+dap_chain_net_decree_t *dap_chain_net_get_net_decree(dap_chain_net_t *a_net) {
+    return a_net ? PVT(a_net)->decree : NULL;
+}
+
+void dap_chain_net_set_net_decree(dap_chain_net_t *a_net, dap_chain_net_decree_t *a_decree) {
+    if (!a_net) {
+        log_it(L_ERROR, "Net is not initialized");
+        return;
+    }
+    PVT(a_net)->decree = a_decree;
+}
+
+decree_table_t **dap_chain_net_get_decrees(dap_chain_net_t *a_net) {
+    return a_net ? &(PVT(a_net)->decrees) : NULL;
+}
\ No newline at end of file
diff --git a/modules/net/dap_chain_net_anchor.c b/modules/net/dap_chain_net_anchor.c
index e5825d6537..5c1d5a6ca2 100644
--- a/modules/net/dap_chain_net_anchor.c
+++ b/modules/net/dap_chain_net_anchor.c
@@ -80,7 +80,8 @@ static int s_anchor_verify(dap_chain_net_t *a_net, dap_chain_datum_anchor_t *a_a
     size_t l_signs_size_original = a_anchor->header.signs_size;
     a_anchor->header.signs_size = 0;
     for (size_t i = 0; i < l_num_of_unique_signs; i++) {
-        for (dap_list_t *it = a_net->pub.decree->pkeys; it; it = it->next) {
+        dap_chain_net_decree_t *l_net_decree = dap_chain_net_get_net_decree(a_net);
+        for (dap_list_t *it = l_net_decree->pkeys; it; it = it->next) {
             if (dap_pkey_compare_with_sign(it->data, l_unique_signs[i])) {
                 // TODO make signs verification in s_concate_all_signs_in_array to correctly header.signs_size calculation
                 size_t l_verify_data_size = a_anchor->header.data_size + sizeof(dap_chain_datum_anchor_t);
@@ -114,7 +115,7 @@ static int s_anchor_verify(dap_chain_net_t *a_net, dap_chain_datum_anchor_t *a_a
         return 0;
 
     bool l_is_applied = false;
-    l_decree = dap_chain_net_decree_get_by_hash(&l_decree_hash, &l_is_applied);
+    l_decree = dap_chain_net_decree_get_by_hash(a_net, &l_decree_hash, &l_is_applied);
     if (!l_decree) {
         log_it(L_WARNING, "Can't get decree by hash %s", dap_hash_fast_to_str_static(&l_decree_hash));
         return DAP_CHAIN_CS_VERIFY_CODE_NO_DECREE;
@@ -144,8 +145,8 @@ int dap_chain_net_anchor_load(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *
     }
 
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
-
-    if (!l_net->pub.decree)
+    dap_chain_net_decree_t *l_net_decree = dap_chain_net_get_net_decree(l_net);
+    if (!l_net_decree)
     {
         log_it(L_WARNING, "Decree is not inited!");
         return -108;
@@ -176,13 +177,13 @@ dap_chain_datum_anchor_t * s_find_previous_anchor(dap_chain_datum_anchor_t * a_a
         log_it(L_ERROR,"Params are NULL");
         return NULL;
     }
-
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
     dap_chain_datum_anchor_t * l_ret_anchor = NULL;
 
     dap_hash_fast_t l_old_decrere_hash = {};
     if (dap_chain_datum_anchor_get_hash_from_data(a_anchor, &l_old_decrere_hash) != 0)
         return NULL;
-    dap_chain_datum_decree_t *l_old_decree = dap_chain_net_decree_get_by_hash(&l_old_decrere_hash, NULL);
+    dap_chain_datum_decree_t *l_old_decree = dap_chain_net_decree_get_by_hash(l_net, &l_old_decrere_hash, NULL);
     uint16_t l_old_decree_type = l_old_decree->header.type;
     uint16_t l_old_decree_subtype = l_old_decree->header.sub_type;
 
@@ -207,7 +208,7 @@ dap_chain_datum_anchor_t * s_find_previous_anchor(dap_chain_datum_anchor_t * a_a
                 continue;
             
             bool l_is_applied = false;
-            dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(&l_hash, &l_is_applied);
+            dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(l_net, &l_hash, &l_is_applied);
             if (!l_decree)
                 continue;
 
@@ -226,13 +227,13 @@ dap_chain_datum_anchor_t * s_find_previous_anchor(dap_chain_datum_anchor_t * a_a
 
                 if(dap_chain_addr_compare(&l_addr_old, &l_addr_new)){
                     l_ret_anchor = l_curr_anchor;
-                    dap_chain_net_decree_reset_applied(a_chain, &l_hash);
+                    dap_chain_net_decree_reset_applied(l_net, &l_hash);
                 break;
                 }
             } else if (l_decree->header.type == l_old_decree_type && l_decree->header.sub_type == l_old_decree_subtype){
                 // check addr if l_decree type is stake approve
                 l_ret_anchor = l_curr_anchor;
-                dap_chain_net_decree_reset_applied(a_chain, &l_hash);
+                dap_chain_net_decree_reset_applied(l_net, &l_hash);
                 break;
             }
         }
@@ -259,7 +260,7 @@ int dap_chain_net_anchor_unload(dap_chain_datum_anchor_t * a_anchor, dap_chain_t
 
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
 
-    if (!l_net->pub.decree)
+    if (!dap_chain_net_get_net_decree(l_net))
     {
         log_it(L_WARNING,"Decree is not inited!");
         return -108;
@@ -275,7 +276,7 @@ int dap_chain_net_anchor_unload(dap_chain_datum_anchor_t * a_anchor, dap_chain_t
     if (dap_chain_datum_anchor_get_hash_from_data(a_anchor, &l_hash) != 0)
         return -110;
             
-    dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(&l_hash, NULL);
+    dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(l_net, &l_hash, NULL);
     if (!l_decree)
         return -111;
 
diff --git a/modules/net/dap_chain_net_decree.c b/modules/net/dap_chain_net_decree.c
index e30a3d28af..64c715e298 100644
--- a/modules/net/dap_chain_net_decree.c
+++ b/modules/net/dap_chain_net_decree.c
@@ -38,14 +38,14 @@
 
 #define LOG_TAG "chain_net_decree"
 
+
 // private types definition
-static struct decree_hh {
+typedef struct decree_table {
     dap_hash_fast_t key;
-    bool is_applied;
-    bool wait_for_apply;
+    bool wait_for_apply, is_applied;
     dap_chain_datum_decree_t *decree;
     UT_hash_handle hh;
-} *s_decree_hh = NULL;
+} decree_table_t;
 
 // Private variable
 
@@ -91,23 +91,21 @@ int dap_chain_net_decree_init(dap_chain_net_t *a_net)
     l_decree->min_num_of_owners = l_count_verify;
     l_decree->num_of_owners = l_auth_certs_count;
     l_decree->pkeys = l_net_keys;
-
-    a_net->pub.decree = l_decree;
-
+    dap_chain_net_set_net_decree(a_net, l_decree);
     return 0;
 }
 
 int dap_chain_net_decree_deinit(dap_chain_net_t *a_net)
 {
-    dap_chain_net_decree_t *l_decree = a_net->pub.decree;
+    dap_chain_net_decree_t *l_decree = dap_chain_net_get_net_decree(a_net);
     dap_list_free_full(l_decree->pkeys, NULL);
     DAP_DELETE(l_decree);
-    struct decree_hh *l_decree_hh, *l_tmp;
-    HASH_ITER(hh, s_decree_hh, l_decree_hh, l_tmp) {
-        HASH_DEL(s_decree_hh, l_decree_hh);
-        if ( !dap_chain_find_by_id(l_decree_hh->decree->header.common_decree_params.net_id, l_decree_hh->decree->header.common_decree_params.chain_id)->is_mapped )
-            DAP_DELETE(l_decree_hh->decree);
-        DAP_DELETE(l_decree_hh);
+    decree_table_t **l_decrees = dap_chain_net_get_decrees(a_net), *l_cur_decree, *l_tmp;
+    HASH_ITER(hh, *l_decrees, l_cur_decree, l_tmp) {
+        HASH_DEL(*l_decrees, l_cur_decree);
+        if ( !dap_chain_find_by_id(l_cur_decree->decree->header.common_decree_params.net_id, l_cur_decree->decree->header.common_decree_params.chain_id)->is_mapped )
+            DAP_DELETE(l_cur_decree->decree);
+        DAP_DELETE(l_cur_decree);
     }
     return 0;
 }
@@ -133,9 +131,9 @@ static int s_decree_verify(dap_chain_net_t *a_net, dap_chain_datum_decree_t *a_d
         return -122;
     }
 
-    struct decree_hh *l_decree_hh = NULL;
-    HASH_FIND(hh, s_decree_hh, a_decree_hash, sizeof(dap_hash_fast_t), l_decree_hh);
-    if (l_decree_hh && l_decree_hh->decree) {
+    decree_table_t **l_decrees = dap_chain_net_get_decrees(a_net), *l_sought_decree;
+    HASH_FIND(hh, *l_decrees, a_decree_hash, sizeof(dap_hash_fast_t), l_sought_decree);
+    if (l_sought_decree && l_sought_decree->decree) {
         log_it(L_WARNING, "Decree with hash %s is already present", dap_hash_fast_to_str_static(a_decree_hash));
         return -123;
     }
@@ -153,13 +151,13 @@ static int s_decree_verify(dap_chain_net_t *a_net, dap_chain_datum_decree_t *a_d
     // Find unique pkeys in pkeys set from previous step and check that number of signs > min
     size_t l_num_of_unique_signs = 0;
     dap_sign_t **l_unique_signs = dap_sign_get_unique_signs(l_signs_block, l_signs_size, &l_num_of_unique_signs);
-
-    if (!a_net->pub.decree) {
+    dap_chain_net_decree_t *l_decree = dap_chain_net_get_net_decree(a_net);
+    if (!l_decree) {
         log_it(L_ERROR, "Decree module hasn't been initialized yet");
         return -404;
     }
 
-    uint16_t l_min_signs = a_net->pub.decree->min_num_of_owners;
+    uint16_t l_min_signs = l_decree->min_num_of_owners;
     if (l_num_of_unique_signs < l_min_signs) {
         log_it(L_WARNING, "Not enough unique signatures, get %zu from %hu", l_num_of_unique_signs, l_min_signs);
         return -106;
@@ -238,54 +236,54 @@ int dap_chain_net_decree_apply(dap_hash_fast_t *a_decree_hash, dap_chain_datum_d
     }
 
     l_net = dap_chain_net_by_id(a_chain->net_id);
-
-    if (!l_net || !l_net->pub.decree)
+    
+    if (!l_net || !dap_chain_net_get_net_decree(l_net))
     {
         log_it(L_WARNING,"Decree is not inited!");
         return -108;
     }
 
-    struct decree_hh *l_decree_hh = NULL;
-    HASH_FIND(hh, s_decree_hh, a_decree_hash, sizeof(dap_hash_fast_t), l_decree_hh);
+    decree_table_t **l_decrees = dap_chain_net_get_decrees(l_net), *l_new_decree;
+    HASH_FIND(hh, *l_decrees, a_decree_hash, sizeof(dap_hash_fast_t), l_new_decree);
 
-    if (!l_decree_hh) {
-        l_decree_hh = DAP_NEW_Z(struct decree_hh);
-        if (!l_decree_hh) {
+    if (!l_new_decree) {
+        l_new_decree = DAP_NEW_Z(decree_table_t);
+        if (!l_new_decree) {
             log_it(L_CRITICAL, "Memory allocation error");
             return -1;
         }
-        l_decree_hh->key = *a_decree_hash;
-        HASH_ADD(hh, s_decree_hh, key, sizeof(dap_hash_fast_t), l_decree_hh);
+        l_new_decree->key = *a_decree_hash;
+        HASH_ADD(hh, *l_decrees, key, sizeof(dap_hash_fast_t), l_new_decree);
     }
 
     if (!a_decree) {    // Processing anchor for decree
-        if (!l_decree_hh->decree) {
+        if (!l_new_decree->decree) {
             log_it(L_WARNING, "Decree with hash %s is not found", dap_hash_fast_to_str_static(a_decree_hash));
-            l_decree_hh->wait_for_apply = true;
+            l_new_decree->wait_for_apply = true;
             return -110;
         }
-        if (l_decree_hh->is_applied) {
+        if (l_new_decree->is_applied) {
             log_it(L_WARNING, "Decree already applied");
             return -111;
         }
     } else {            // Process decree itself
-        if (l_decree_hh->decree) {
+        if (l_new_decree->decree) {
             log_it(L_WARNING, "Decree with hash %s is already present", dap_hash_fast_to_str_static(a_decree_hash));
             return -123;
         }
-        l_decree_hh->decree = a_chain->is_mapped ? a_decree : DAP_DUP_SIZE(a_decree, dap_chain_datum_decree_get_size(a_decree));
-        if (a_decree->header.common_decree_params.chain_id.uint64 != a_chain->id.uint64 && !l_decree_hh->wait_for_apply)
+        l_new_decree->decree = a_chain->is_mapped ? a_decree : DAP_DUP_SIZE(a_decree, dap_chain_datum_decree_get_size(a_decree));
+        if (a_decree->header.common_decree_params.chain_id.uint64 != a_chain->id.uint64 && !l_new_decree->wait_for_apply)
             // Apply it with corresponding anchor
             return ret_val;
     }
 
     // Process decree
-    switch(l_decree_hh->decree->header.type) {
+    switch(l_new_decree->decree->header.type) {
     case DAP_CHAIN_DATUM_DECREE_TYPE_COMMON:
-        ret_val = s_common_decree_handler(l_decree_hh->decree, l_net, true, false);
+        ret_val = s_common_decree_handler(l_new_decree->decree, l_net, true, false);
         break;
     case DAP_CHAIN_DATUM_DECREE_TYPE_SERVICE:
-        ret_val = s_service_decree_handler(l_decree_hh->decree, l_net, true);
+        ret_val = s_service_decree_handler(l_new_decree->decree, l_net, true);
         break;
     default:
         log_it(L_WARNING,"Decree type is undefined!");
@@ -293,8 +291,8 @@ int dap_chain_net_decree_apply(dap_hash_fast_t *a_decree_hash, dap_chain_datum_d
     }
 
     if (!ret_val) {
-        l_decree_hh->is_applied = true;
-        l_decree_hh->wait_for_apply = false;
+        l_new_decree->is_applied = true;
+        l_new_decree->wait_for_apply = false;
     } else
         log_it(L_ERROR,"Decree applying failed!");
 
@@ -311,7 +309,7 @@ int dap_chain_net_decree_load(dap_chain_datum_decree_t * a_decree, dap_chain_t *
 
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
 
-    if (!l_net->pub.decree) {
+    if ( !dap_chain_net_get_net_decree(l_net) ) {
         log_it(L_WARNING, "Decree is not inited!");
         return -108;
     }
@@ -326,37 +324,31 @@ int dap_chain_net_decree_load(dap_chain_datum_decree_t * a_decree, dap_chain_t *
     return dap_chain_net_decree_apply(a_decree_hash, a_decree, a_chain);
 }
 
-int dap_chain_net_decree_reset_applied(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_decree_hash)
+int dap_chain_net_decree_reset_applied(dap_chain_net_t *a_net, dap_chain_hash_fast_t *a_decree_hash)
 {
-    if (!a_chain || !a_decree_hash)
+    if (!a_net || !a_decree_hash)
         return -1;
-    struct decree_hh* l_decree_hh = NULL;
-    HASH_FIND(hh, s_decree_hh, a_decree_hash, sizeof(dap_hash_fast_t), l_decree_hh);
-    if (!l_decree_hh)
+    decree_table_t **l_decrees = dap_chain_net_get_decrees(a_net), *l_sought_decree;
+    HASH_FIND(hh, *l_decrees, a_decree_hash, sizeof(dap_hash_fast_t), l_sought_decree);
+    if (!l_sought_decree)
         return -2;
-
-    l_decree_hh->is_applied = false;
-
+    l_sought_decree->is_applied = false;
     return 0;
 }
 
-dap_chain_datum_decree_t *dap_chain_net_decree_get_by_hash(dap_hash_fast_t *a_hash, bool *is_applied)
+dap_chain_datum_decree_t *dap_chain_net_decree_get_by_hash(dap_chain_net_t *a_net, dap_hash_fast_t *a_hash, bool *is_applied)
 {
-    struct decree_hh* l_decree_hh = NULL;
-    HASH_FIND(hh, s_decree_hh, a_hash, sizeof(dap_hash_fast_t), l_decree_hh);
-    if (!l_decree_hh || !l_decree_hh->decree)
-        return NULL;
-
-    if (is_applied)
-        *is_applied = l_decree_hh->is_applied;
-
-    return l_decree_hh->decree;
+    decree_table_t **l_decrees = dap_chain_net_get_decrees(a_net), *l_sought_decree;
+    HASH_FIND(hh, *l_decrees, a_hash, sizeof(dap_hash_fast_t), l_sought_decree);
+    return ( !l_sought_decree || !l_sought_decree->decree )
+        ? NULL
+        : ({ if (is_applied) { *is_applied = l_sought_decree->is_applied; } l_sought_decree->decree; });
 }
 
 // Private functions
 static bool s_verify_pkey (dap_sign_t *a_sign, dap_chain_net_t *a_net)
 {
-    for (dap_list_t *it = a_net->pub.decree->pkeys; it; it = it->next)
+    for (dap_list_t *it = dap_chain_net_get_net_decree(a_net)->pkeys; it; it = it->next)
         if (dap_pkey_compare_with_sign(it->data, a_sign))
             return true;
     return false;
@@ -401,14 +393,13 @@ static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain
                 log_it(L_WARNING,"Can't get ownners from decree.");
                 return -104;
             }
-
             if (!a_apply)
                 break;
+            dap_chain_net_decree_t *l_net_decree = dap_chain_net_get_net_decree(a_net);
+            l_net_decree->num_of_owners = l_owners_num;
+            dap_list_free_full(l_net_decree->pkeys, NULL);
 
-            a_net->pub.decree->num_of_owners = l_owners_num;
-            dap_list_free_full(a_net->pub.decree->pkeys, NULL);
-
-            a_net->pub.decree->pkeys = l_owners_list;
+            l_net_decree->pkeys = l_owners_list;
             break;
         case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_OWNERS_MIN:
             if (dap_chain_datum_decree_get_min_owners(a_decree, &l_value)) {
@@ -421,7 +412,7 @@ static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain
             }
             if (!a_apply)
                 break;
-            a_net->pub.decree->min_num_of_owners = dap_uint256_to_uint64(l_value);
+            dap_chain_net_get_net_decree(a_net)->min_num_of_owners = dap_uint256_to_uint64(l_value);
             break;
         case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_APPROVE:
             if (dap_chain_datum_decree_get_hash(a_decree, &l_hash)){
diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c
index 1924ec2c25..ffbc035b5d 100644
--- a/modules/net/dap_chain_node_cli_cmd_tx.c
+++ b/modules/net/dap_chain_node_cli_cmd_tx.c
@@ -1646,7 +1646,7 @@ int cmd_decree(int a_argc, char **a_argv, void **a_str_reply)
                 dap_cert_parse_str_list(l_param_value_str, &l_new_certs, &l_new_certs_count);
 
                 dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
-                uint16_t l_min_signs = l_net->pub.decree->min_num_of_owners;
+                uint16_t l_min_signs = dap_chain_net_get_net_decree(l_net)->min_num_of_owners;
                 if (l_new_certs_count < l_min_signs) {
                     log_it(L_WARNING,"Number of new certificates is less than minimum owner number.");
                     return -106;
@@ -1680,7 +1680,7 @@ int cmd_decree(int a_argc, char **a_argv, void **a_str_reply)
                     return -112;
                 }
                 dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
-                uint256_t l_owners = GET_256_FROM_64(l_net->pub.decree->num_of_owners);
+                uint256_t l_owners = GET_256_FROM_64(dap_chain_net_get_net_decree(l_net)->num_of_owners);
                 if (compare256(l_new_num_of_owners, l_owners) > 0) {
                     log_it(L_WARNING, "The minimum number of owners is greater than the total number of owners.");
                     dap_list_free_full(l_tsd_list, NULL);
@@ -1976,14 +1976,15 @@ int cmd_decree(int a_argc, char **a_argv, void **a_str_reply)
             return -111;
         }
         bool l_applied = false;
-        dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(&l_datum_hash, &l_applied);
+        dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(l_net, &l_datum_hash, &l_applied);
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified decree is %s in decrees hash-table",
                                           l_decree ? (l_applied ? "applied" : "not applied") : "not found");
     } break;
     case CMD_INFO: {
         dap_string_t *l_str_owner_pkey = dap_string_new("");
+        dap_chain_net_decree_t *l_net_decree = dap_chain_net_get_net_decree(l_net);
         int i = 1;
-        for (dap_list_t *l_current_pkey = l_net->pub.decree->pkeys; l_current_pkey; l_current_pkey = l_current_pkey->next){
+        for (dap_list_t *l_current_pkey = l_net_decree->pkeys; l_current_pkey; l_current_pkey = l_current_pkey->next){
             dap_pkey_t *l_pkey = (dap_pkey_t*)(l_current_pkey->data);
             dap_hash_fast_t l_pkey_hash = {0};
             dap_pkey_get_hash(l_pkey, &l_pkey_hash);
@@ -1998,8 +1999,8 @@ int cmd_decree(int a_argc, char **a_argv, void **a_str_reply)
                                                        "%s"
                                                        "\t=====================================================================\n"
                                                        "\tMin owners for apply decree: %d\n",
-                                          l_net->pub.decree->num_of_owners, l_str_owner_pkey->str,
-                                          l_net->pub.decree->min_num_of_owners);
+                                          l_net_decree->num_of_owners, l_str_owner_pkey->str,
+                                          l_net_decree->min_num_of_owners);
         dap_string_free(l_str_owner_pkey, true);
     } break;
     default:
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index 1727b4982c..6e9f139a52 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -43,7 +43,7 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 typedef struct dap_chain_node_client dap_chain_node_client_t;
 typedef struct dap_ledger dap_ledger_t;
 typedef struct dap_chain_net_decree dap_chain_net_decree_t;
-
+typedef struct decree_table decree_table_t;
 typedef enum dap_chain_net_state {
     NET_STATE_OFFLINE = 0,
     NET_STATE_LINKS_PREPARE,
@@ -67,11 +67,9 @@ typedef struct dap_chain_net{
         dap_chain_t *chains; // double-linked list of chains
         const char *native_ticker;
         dap_ledger_t *ledger;
-        dap_chain_net_decree_t *decree;
         // Net fee
         uint256_t fee_value;
         dap_chain_addr_t fee_addr;
-        
         dap_list_t *bridged_networks;   // List of bridged network ID's allowed to cross-network TX
         dap_config_t *config;
     } pub;
@@ -171,9 +169,7 @@ DAP_STATIC_INLINE char *dap_chain_net_get_gdb_group_mempool_new(dap_chain_t *a_c
 DAP_STATIC_INLINE char *dap_chain_net_get_gdb_group_nochain_new(dap_chain_t *a_chain)
 {
     dap_chain_net_t *l_net = a_chain ? dap_chain_net_by_id(a_chain->net_id) : NULL;
-    return l_net
-            ? dap_strdup_printf("%s.chain-%s.data", l_net->pub.name, a_chain->name)
-            : NULL;
+    return l_net ? dap_strdup_printf("%s.chain-%s.data", l_net->pub.name, a_chain->name) : NULL;
 }
 
 dap_chain_t *dap_chain_net_get_chain_by_chain_type(dap_chain_net_t *a_net, dap_chain_type_t a_datum_type);
@@ -235,3 +231,6 @@ enum dap_chain_net_json_rpc_error_list{
     DAP_CHAIN_NET_JSON_RPC_NO_POA_CERTS_FOUND_POA_CERTS,
     DAP_CHAIN_NET_JSON_RPC_UNKNOWN_SUBCOMMANDS
 };
+dap_chain_net_decree_t *dap_chain_net_get_net_decree(dap_chain_net_t *a_net);
+void dap_chain_net_set_net_decree(dap_chain_net_t *a_net, dap_chain_net_decree_t *a_decree);
+decree_table_t **dap_chain_net_get_decrees(dap_chain_net_t *a_net);
\ No newline at end of file
diff --git a/modules/net/include/dap_chain_net_decree.h b/modules/net/include/dap_chain_net_decree.h
index 95b035c565..270db17d76 100644
--- a/modules/net/include/dap_chain_net_decree.h
+++ b/modules/net/include/dap_chain_net_decree.h
@@ -39,7 +39,5 @@ void dap_chain_net_decree_purge(dap_chain_net_t *a_net);
 int dap_chain_net_decree_apply(dap_hash_fast_t *a_decree_hash, dap_chain_datum_decree_t * a_decree, dap_chain_t *a_chain);
 int dap_chain_net_decree_verify(dap_chain_net_t *a_net, dap_chain_datum_decree_t *a_decree, size_t a_data_size, dap_chain_hash_fast_t *a_decree_hash);
 int dap_chain_net_decree_load(dap_chain_datum_decree_t * a_decree, dap_chain_t *a_chain, dap_chain_hash_fast_t *a_decree_hash);
-int dap_chain_net_decree_reset_applied(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_decree_hash);
-
-
-dap_chain_datum_decree_t *dap_chain_net_decree_get_by_hash(dap_hash_fast_t *a_hash, bool *is_applied);
+dap_chain_datum_decree_t *dap_chain_net_decree_get_by_hash(dap_chain_net_t *a_net, dap_hash_fast_t *a_hash, bool *is_applied);
+int dap_chain_net_decree_reset_applied(dap_chain_net_t *a_net, dap_chain_hash_fast_t *a_decree_hash);
diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
index 6531e9f550..9cc44aeaad 100644
--- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
+++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
@@ -307,7 +307,8 @@ static bool s_srv_stake_is_poa_cert(dap_chain_net_t *a_net, dap_enc_key_t *a_key
 {
     bool l_is_poa_cert = false;
     dap_pkey_t *l_pkey = dap_pkey_from_enc_key(a_key);
-    for (dap_list_t *it = a_net->pub.decree->pkeys; it; it = it->next)
+    dap_list_t *l_pkeys = dap_chain_net_get_net_decree(a_net)->pkeys;
+    for (dap_list_t *it = l_pkeys; it; it = it->next)
         if (dap_pkey_compare(l_pkey, (dap_pkey_t *)it->data)) {
             l_is_poa_cert = true;
             break;
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 931f8f326b..7738c1efde 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -70,7 +70,7 @@ typedef struct dap_chain_cs_blocks_pvt
     dap_chain_hash_fast_t genesis_block_hash;
     dap_chain_hash_fast_t static_genesis_block_hash;
 
-    uint64_t blocks_count;
+    _Atomic uint64_t blocks_count;
 
     time_t time_between_blocks_minimum; // Minimal time between blocks
     bool is_celled;
@@ -563,8 +563,7 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void **a_str_reply)
     const char* l_subcmd_str_args[l_subcmd_str_count];
 	for(size_t i=0;i<l_subcmd_str_count;i++)
         l_subcmd_str_args[i]=NULL;
-    const char* l_subcmd_str_arg;
-    const char* l_subcmd_str = NULL;
+    const char* l_subcmd_str_arg = NULL, *l_subcmd_str = NULL;
 
     int arg_index = 1;
 
@@ -1620,19 +1619,17 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
         if ( !dap_chain_net_get_load_mode( dap_chain_net_by_id(a_chain->net_id)) ) {
             if ( (ret = dap_chain_atom_save(l_cell, a_atom, a_atom_size, &l_block_hash)) < 0 ) {
                 log_it(L_ERROR, "Can't save atom to file, code %d", ret);
-                pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
                 return ATOM_REJECT;
             } else if (a_chain->is_mapped) {
                 l_block = (dap_chain_block_t*)( l_cell->map_pos += sizeof(uint64_t) );  // Switching to mapped area
                 l_cell->map_pos += a_atom_size;
             }
-            ret = ATOM_PASS;
+            ret = ATOM_ACCEPT;
         }
 #endif
         l_block_cache = dap_chain_block_cache_new(&l_block_hash, l_block, a_atom_size, PVT(l_blocks)->blocks_count + 1, !a_chain->is_mapped);
         if (!l_block_cache) {
             log_it(L_DEBUG, "%s", "... corrupted block");
-            pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
             return ATOM_REJECT;
         }
         debug_if(s_debug_more, L_DEBUG, "... new block %s", l_block_cache->block_hash_str);
@@ -1677,11 +1674,11 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
         } else {
             HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_block_cache->block_hash), l_block_cache);
             ++PVT(l_blocks)->blocks_count;
-            pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
             debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", a_atom);
             s_add_atom_datums(l_blocks, l_block_cache);
             dap_chain_atom_notify(l_cell, &l_block_cache->block_hash, (byte_t*)l_block, a_atom_size);
             dap_chain_atom_add_from_threshold(a_chain);
+            pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
             return ret;
         }
         pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
@@ -1705,19 +1702,17 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
         if ( !dap_chain_net_get_load_mode( dap_chain_net_by_id(a_chain->net_id)) ) {
             if ( (ret = dap_chain_atom_save(l_cell, a_atom, a_atom_size, &l_block_hash)) < 0 ) {
                 log_it(L_ERROR, "Can't save atom to file, code %d", ret);
-                pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
                 return ATOM_REJECT;
             } else if (a_chain->is_mapped) {
                 l_block = (dap_chain_block_t*)( l_cell->map_pos += sizeof(uint64_t) );  // Switching to mapped area
                 l_cell->map_pos += a_atom_size;
             }
-            ret = ATOM_PASS;
+            ret = ATOM_FORK;
         }
 #endif
         l_block_cache = dap_chain_block_cache_new(&l_block_hash, l_block, a_atom_size, PVT(l_blocks)->blocks_count + 1, !a_chain->is_mapped);
         if (!l_block_cache) {
             log_it(L_DEBUG, "%s", "... corrupted block");
-            pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
             return ATOM_REJECT;
         }
         debug_if(s_debug_more, L_DEBUG, "... new block %s", l_block_cache->block_hash_str);
@@ -1749,7 +1744,6 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
         debug_if(s_debug_more, L_DEBUG, "Unknown verification ret code %d", ret);
         break;
     }
-    pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
     return ret;
 }
 
@@ -2210,9 +2204,7 @@ static uint64_t s_callback_count_atom(dap_chain_t *a_chain)
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
     assert(l_blocks && l_blocks->chain == a_chain);
     uint64_t l_ret = 0;
-    pthread_rwlock_rdlock(&PVT(l_blocks)->rwlock);
     l_ret = PVT(l_blocks)->blocks_count;
-    pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
     return l_ret;
 }
 
-- 
GitLab