diff --git a/dap-sdk b/dap-sdk
index 737ab3c9660c0e7133786ef256abfbd4bfec87fb..648afd3a17e1f0705740641d007e396a72f24cc0 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 737ab3c9660c0e7133786ef256abfbd4bfec87fb
+Subproject commit 648afd3a17e1f0705740641d007e396a72f24cc0
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 20b2e15e7d3e447ace60cd902ea44626aa7be6f4..d85b8c0bc1abe52a8c4d62c12e4242289c01a729 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -144,6 +144,12 @@ void dap_chain_set_cs_type(dap_chain_t *a_chain, const char *a_cs_type)
     DAP_CHAIN_PVT(a_chain)->cs_type = dap_strdup(a_cs_type);
 }
 
+int dap_chain_purge(dap_chain_t *a_chain)
+{
+    int ret = dap_chain_cs_class_purge(a_chain);
+    return ret + dap_chain_cs_purge(a_chain);
+}
+
 /**
  * @brief
  * delete dap chain object
@@ -523,13 +529,15 @@ int dap_chain_load_all(dap_chain_t *a_chain)
     const char l_suffix[] = ".dchaincell", *l_filename;
     struct dirent *l_dir_entry = NULL;
     dap_time_t l_ts_start = dap_time_now();
-    while (( l_dir_entry = readdir(l_dir) ) && !l_err ) {
+    while (( l_dir_entry = readdir(l_dir) ) ) {
         l_filename = l_dir_entry->d_name;
         size_t l_namelen = strlen(l_filename);
-        if ( l_namelen >= sizeof(l_suffix) && !strncmp(l_filename + l_namelen - sizeof(l_suffix) - 1, l_suffix, sizeof(l_suffix) - 1) ) {
+        if ( l_namelen >= sizeof(l_suffix) && !strncmp(l_filename + l_namelen - (sizeof(l_suffix) - 1), l_suffix, sizeof(l_suffix) - 1) ) {
             dap_timerfd_t* l_load_notify_timer = dap_timerfd_start(5000, (dap_timerfd_callback_t)s_load_notify_callback, a_chain);
             l_err = dap_chain_cell_open(a_chain, l_filename, 'a');
             dap_timerfd_delete(l_load_notify_timer->worker, l_load_notify_timer->esocket_uuid);
+            if (l_err)
+                break;
             s_load_notify_callback(a_chain);
         }
     }
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index 46236b6d1b623468f827c883bc7285deb309a230..cf8255d1363ae6bff11e55c40052d3c2e5d3f63d 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -263,8 +263,8 @@ void dap_chain_cell_close_all(dap_chain_t *a_chain) {
 DAP_STATIC_INLINE int s_cell_load_from_file(dap_chain_cell_t *a_cell)
 {
     off_t l_pos, l_full_size = !fseeko(a_cell->file_storage, 0, SEEK_END) ? ftello(a_cell->file_storage) : -1;
-    dap_return_val_if_fail_err(l_full_size < 0, 1, "Can't get chain size, error %d: \"%s\"", errno, dap_strerror(errno));
-    dap_return_val_if_fail_err(l_full_size < (off_t)sizeof(dap_chain_cell_file_header_t), 2, "Chain cell \"%s\" is corrupt, create new file", a_cell->file_storage_path);
+    dap_return_val_if_fail_err(l_full_size > 0, 1, "Can't get chain size, error %d: \"%s\"", errno, dap_strerror(errno));
+    dap_return_val_if_fail_err(l_full_size >= (off_t)sizeof(dap_chain_cell_file_header_t), 2, "Chain cell \"%s\" is corrupt, create new file", a_cell->file_storage_path);
 
     /* Load header */
     {
@@ -274,7 +274,7 @@ DAP_STATIC_INLINE int s_cell_load_from_file(dap_chain_cell_t *a_cell)
             l_hdr = (dap_chain_cell_file_header_t*)a_cell->mapping->volume->base;
         } else {
             fseeko(a_cell->file_storage, 0, SEEK_SET);
-            dap_return_val_if_fail_err( fread(l_hdr, 1, sizeof(*l_hdr), a_cell->file_storage) != sizeof(*l_hdr), -4,
+            dap_return_val_if_fail_err( fread(l_hdr, 1, sizeof(*l_hdr), a_cell->file_storage) == sizeof(*l_hdr), -4,
                                         "Can't read chain header \"%s\"", a_cell->file_storage_path );
         }
         dap_return_val_if_fail_err( l_hdr->cell_id.uint64 == a_cell->id.uint64, 5,
@@ -536,7 +536,7 @@ int dap_chain_cell_file_append(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_
                                             a_cell_id.uint64, a_chain->net_name, a_chain->name);
     //pthread_rwlock_wrlock(&l_cell->storage_rwlock);
     int l_err = s_cell_file_atom_add(l_cell, a_atom, a_atom_size, a_atom_map);
-    if (l_err)
+    if (!l_err)
         log_it(L_DEBUG, "Saved atom of size %zu bytes to chain \"%s : %s\", cell 0x%016"DAP_UINT64_FORMAT_X"",
                         a_atom_size, a_chain->net_name, a_chain->name, a_cell_id.uint64);
     else
diff --git a/modules/chain/dap_chain_common.c b/modules/chain/dap_chain_common.c
index e6ff3354a04fbdbe054957b63737651670986224..3830f97d8d8c43e0841650612cfb0d626fe307d7 100644
--- a/modules/chain/dap_chain_common.c
+++ b/modules/chain/dap_chain_common.c
@@ -34,6 +34,7 @@
 
 const dap_chain_srv_uid_t c_dap_chain_srv_uid_null = {0};
 const dap_chain_cell_id_t c_dap_chain_cell_id_null = {0};
+const dap_chain_cell_id_t c_dap_chain_cell_id_hardfork = { .uint64 = INT64_MIN }; // 0x800...
 const dap_chain_addr_t c_dap_chain_addr_blank = {0};
 
 /**
diff --git a/modules/chain/dap_chain_srv.c b/modules/chain/dap_chain_srv.c
index 8c469254761edc98849c80fa669cc7673f304e1e..7d9d9ce1b34538c1521713ab9ea55b161f8abe61 100644
--- a/modules/chain/dap_chain_srv.c
+++ b/modules/chain/dap_chain_srv.c
@@ -259,10 +259,17 @@ void *dap_chain_srv_get_internal(dap_chain_net_id_t a_net_id, dap_chain_srv_uid_
  * @param a_srv_uid
  * @return ponter to list
  */
-DAP_INLINE dap_list_t *dap_chain_srv_get_internal_all(dap_chain_srv_uid_t a_srv_uid)
+dap_list_t *dap_chain_srv_get_internal_all(dap_chain_srv_uid_t a_srv_uid)
 {
+    dap_list_t *ret = NULL;
     struct service_list *l_service_item = s_service_find(a_srv_uid);
-    return l_service_item ? l_service_item->networks : NULL;
+    if (l_service_item) {
+        for (dap_list_t *it = l_service_item->networks; it; it = it->next) {
+            struct network_service *l_service = it->data;
+            ret = dap_list_append(ret, l_service->service);
+        }
+    }
+    return ret;
 }
 
 /**
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index b2912ac1b197fe150784ad61e22f9aa2530b1a8e..62882bda5aea1ed3def3920ea274167b44069aa4 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -308,7 +308,7 @@ bool dap_chain_has_file_store(dap_chain_t *a_chain);
 dap_chain_t *dap_chain_find_by_id(dap_chain_net_id_t a_chain_net_id,dap_chain_id_t a_chain_id);
 dap_chain_t *dap_chain_load_from_cfg(const char *a_chain_net_name, dap_chain_net_id_t a_chain_net_id, dap_config_t *a_cfg);
 void dap_chain_info_dump_log(dap_chain_t *a_chain);
-
+int dap_chain_purge(dap_chain_t *a_chain);
 void dap_chain_delete(dap_chain_t *a_chain);
 void dap_chain_add_callback_notify(dap_chain_t *a_chain, dap_chain_callback_notify_t a_callback, dap_proc_thread_t *a_thread, void *a_arg);
 void dap_chain_add_callback_datum_index_notify(dap_chain_t *a_chain, dap_chain_callback_datum_notify_t a_callback, dap_proc_thread_t *a_thread, void *a_callback_arg);
diff --git a/modules/chain/include/dap_chain_common.h b/modules/chain/include/dap_chain_common.h
index 74706f6d1bb9a316153b07f65212dd6ed98c9300..1e758ae7c6274802cc826e989f0028ccabc7cd78 100644
--- a/modules/chain/include/dap_chain_common.h
+++ b/modules/chain/include/dap_chain_common.h
@@ -144,6 +144,7 @@ typedef union {
 
 extern const dap_chain_srv_uid_t c_dap_chain_srv_uid_null;
 extern const dap_chain_cell_id_t c_dap_chain_cell_id_null;
+extern const dap_chain_cell_id_t c_dap_chain_cell_id_hardfork;
 extern const dap_chain_addr_t c_dap_chain_addr_blank;
 
 enum dap_chain_srv_unit_enum {
diff --git a/modules/chain/include/dap_chain_policy.h b/modules/chain/include/dap_chain_policy.h
index 0335a8e94f433b5e4c2c59ee99a816b3b473a28b..e526e4267117fa315599c1431ca9214d22a06a16 100644
--- a/modules/chain/include/dap_chain_policy.h
+++ b/modules/chain/include/dap_chain_policy.h
@@ -33,6 +33,9 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 #define DAP_CHAIN_POLICY_FLAG_ACTIVATE_BY_BLOCK_NUM     (1 << 1)
 #define DAP_CHAIN_POLICY_FLAG_ACTIVATE_BY_CONFIG        (1 << 2)
 
+#define DAP_CHAIN_POLICY_PUBLIC_KEY_HASH_SIGN_VALIDATORS    0x1
+#define DAP_CHAIN_POLICY_OUT_EXT_USE_ENSURE                 0x2
+
 typedef struct dap_chain_policy {
     uint16_t version;
     struct {
@@ -67,4 +70,4 @@ bool dap_chain_policy_activated(uint32_t a_policy_num, uint64_t a_net_id);
 DAP_STATIC_INLINE size_t dap_chain_policy_get_size(dap_chain_policy_t *a_policy)
 {
     return a_policy ? a_policy->deactivate.count * sizeof(uint32_t) + sizeof(dap_chain_policy_t) : 0;
-}
\ No newline at end of file
+}
diff --git a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
index a026bc1dc1a51f6ed9948fb8c8d627d0158db8dd..4d01df76bf416a21f4e51d76bea13dcfa3678348 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -97,8 +97,6 @@ static int s_cli_dag_poa(int argc, char ** argv, void **a_str_reply);
 static bool s_seed_mode = false;
 static bool s_debug_more = false;
 
-#define DAG_ROUND_NEW_TTL 3600 // 1 hour
-
 /**
  * @brief
  * init consensus dag_poa
@@ -911,8 +909,7 @@ dap_list_t *dap_chain_cs_dag_poa_get_auth_certs(dap_chain_t *a_chain, size_t *a_
 
     dap_list_t *l_keys_list = NULL;
     for (size_t i = 0; i < l_poa_pvt->auth_certs_count; ++i)
-    {
         l_keys_list = dap_list_append(l_keys_list, dap_cert_to_pkey(l_poa_pvt->auth_certs[i]));
-    }
+
     return l_keys_list;
 }
diff --git a/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h b/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h
index f34c153eacd9198528464d8f97cad2b764ffc482..ddc0bd63d82e5c79d610cb202194ba0254408b91 100644
--- a/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h
+++ b/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h
@@ -35,8 +35,9 @@ typedef struct dap_chain_cs_dag_poa
     void * _inheritor;
 } dap_chain_cs_dag_poa_t;
 
-#define DAP_CHAIN_CS_DAG_POA(a) ( (dap_chain_cs_dag_poa_t *) (a)->_inheritor)
+#define DAG_ROUND_NEW_TTL 600 // 10 min
 
+#define DAP_CHAIN_CS_DAG_POA(a) ( (dap_chain_cs_dag_poa_t *) (a)->_inheritor)
 
 int dap_chain_cs_dag_poa_init();
 void dap_chain_cs_dag_poa_deinit(void);
diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index fd7f38e5a2562db12c6db1bf3de4a45fa2fbc146..2a3f3dc54942cbd6a0eb82a4d6c3487bd44fe349 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -37,12 +37,9 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 #include "dap_chain_net_srv_stake_pos_delegate.h"
 #include "dap_chain_ledger.h"
 #include "dap_cli_server.h"
-#include "dap_chain_node_cli_cmd.h"
 
 #define LOG_TAG "dap_chain_cs_esbocs"
 
-static const dap_chain_cell_id_t c_cell_id_hardfork = { .uint64 = INT64_MIN }; // 0x800...
-
 enum s_esbocs_session_state {
     DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_START,
     DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_PROC,
@@ -184,8 +181,9 @@ DAP_STATIC_INLINE uint16_t s_get_round_skip_timeout(dap_chain_esbocs_session_t *
 int dap_chain_cs_esbocs_init()
 {
     dap_chain_cs_callbacks_t l_callbacks = { .callback_init = s_callback_new,
-                                             .callback_stop = s_callback_stop,
+                                             .callback_load = s_callback_created,
                                              .callback_start = s_callback_start,
+                                             .callback_stop = s_callback_stop,
                                              .callback_purge = s_callback_purge };
     dap_chain_cs_add(DAP_CHAIN_ESBOCS_CS_TYPE_STR, l_callbacks);
     dap_stream_ch_proc_add(DAP_STREAM_CH_ESBOCS_ID,
@@ -264,7 +262,7 @@ static int s_callback_new(dap_chain_t *a_chain, dap_config_t *a_chain_cfg)
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
     int l_dot_pos = strlen(l_auth_certs_prefix), l_len = l_dot_pos + 16, l_pos2 = 0;
     char l_cert_name[l_len];
-    dap_strncpy(l_cert_name, l_auth_certs_prefix, l_dot_pos);
+    dap_strncpy(l_cert_name, l_auth_certs_prefix, l_len);
     for (i = 0; i < l_auth_certs_count; ++i) {
         dap_cert_t *l_cert_cur;
         l_pos2 = snprintf(l_cert_name + l_dot_pos, 16, ".%u", i);
@@ -593,7 +591,7 @@ static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cf
         }
         if (l_order->srv_uid.uint64 != DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID)
             continue;
-        dap_sign_t *l_order_sign = (dap_sign_t*)(l_order->ext_n_sign + l_order->ext_size);
+        dap_sign_t *l_order_sign = (dap_sign_t *)(l_order->ext_n_sign + l_order->ext_size);
         if (!dap_pkey_compare_with_sign(l_esbocs_pvt->block_sign_pkey, l_order_sign))
             continue;
         if (!l_order_service)
@@ -743,14 +741,16 @@ int dap_chain_esbocs_set_min_validators_count(dap_chain_t *a_chain, uint16_t a_n
     return 0;
 }
 
-int dap_chain_esbocs_set_hardfork_prepare(dap_chain_t *a_chain, uint64_t a_block_num, dap_list_t *a_trusted_addrs, json_object* a_changed_addrs)
+int dap_chain_esbocs_set_hardfork_prepare(dap_chain_t *a_chain, uint64_t a_block_num, dap_list_t *a_trusted_addrs, json_object *a_changed_addrs)
 {
     uint64_t l_last_num = a_chain->callback_count_atom(a_chain);
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
     dap_chain_esbocs_t *l_esbocs = DAP_CHAIN_ESBOCS(l_blocks);
     l_esbocs->hardfork_from = dap_max(l_last_num, a_block_num);
-    l_esbocs->hardfork_trusted_addrs = a_trusted_addrs;
-    l_esbocs->hardfork_changed_addrs = a_changed_addrs;
+    if (a_trusted_addrs)
+        l_esbocs->hardfork_trusted_addrs = a_trusted_addrs;
+    if (a_changed_addrs)
+        l_esbocs->hardfork_changed_addrs = a_changed_addrs;
     return a_block_num && a_block_num < l_last_num ? 1 : 0;
 }
 
@@ -759,6 +759,11 @@ int dap_chain_esbocs_set_hardfork_complete(dap_chain_t *a_chain)
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
     dap_chain_esbocs_t *l_esbocs = DAP_CHAIN_ESBOCS(l_blocks);
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
+    dap_list_free_full(l_esbocs->hardfork_trusted_addrs, NULL);
+    l_esbocs->hardfork_trusted_addrs = NULL;
+    json_object_put(l_esbocs->hardfork_changed_addrs);
+    l_esbocs->hardfork_changed_addrs = NULL;
+    l_esbocs->hardfork_from = 0;
     l_esbocs->session->is_hardfork = false;
     l_net->pub.ledger->is_hardfork_state = false;
     return 0;
@@ -1148,7 +1153,7 @@ static bool s_session_round_new(void *a_arg)
     a_session->ts_stage_entry = 0;
 
     dap_hash_fast_t l_last_block_hash;
-    dap_chain_get_atom_last_hash(a_session->chain, a_session->is_hardfork ? c_dap_chain_cell_id_null : c_cell_id_hardfork, &l_last_block_hash);
+    dap_chain_get_atom_last_hash(a_session->chain, a_session->is_hardfork ? c_dap_chain_cell_id_null : c_dap_chain_cell_id_hardfork, &l_last_block_hash);
     if (!dap_hash_fast_compare(&l_last_block_hash, &a_session->cur_round.last_block_hash) ||
             (!dap_hash_fast_is_blank(&l_last_block_hash) &&
                 dap_hash_fast_is_blank(&a_session->cur_round.last_block_hash))) {
@@ -1220,11 +1225,19 @@ static bool s_session_round_new(void *a_arg)
     a_session->sync_failed = false;
     a_session->listen_ensure = 0;
     uint64_t l_cur_atom_count = a_session->chain->callback_count_atom(a_session->chain);
-    a_session->is_hardfork = a_session->esbocs->hardfork_from && l_cur_atom_count >= a_session->esbocs->hardfork_from;
-    if (l_cur_atom_count && l_cur_atom_count == a_session->esbocs->hardfork_from) {
-        dap_time_t l_last_block_timestamp = 0;
-        dap_chain_get_atom_last_hash_num_ts(a_session->chain, c_cell_id_hardfork, NULL, NULL, &l_last_block_timestamp);
-        dap_chain_node_hardfork_prepare(a_session->chain, l_last_block_timestamp, a_session->esbocs->hardfork_trusted_addrs, a_session->esbocs->hardfork_changed_addrs);
+    if (!a_session->is_hardfork) {
+        a_session->is_hardfork = a_session->esbocs->hardfork_from && l_cur_atom_count == a_session->esbocs->hardfork_from;
+        if (a_session->is_hardfork) {
+            dap_time_t l_last_block_timestamp = 0;
+            dap_chain_get_atom_last_hash_num_ts(a_session->chain, c_dap_chain_cell_id_null, NULL, NULL, &l_last_block_timestamp);
+            int rc = dap_chain_node_hardfork_prepare(a_session->chain, l_last_block_timestamp,
+                                                     a_session->esbocs->hardfork_trusted_addrs,
+                                                     a_session->esbocs->hardfork_changed_addrs);
+            if (rc) {
+                log_it(L_ERROR, "Can't start hardfork process with code %d, see log for more details", rc);
+                a_session->is_hardfork = false;
+            }
+        }
     }
     return false;
 }
@@ -1332,14 +1345,6 @@ static int s_signs_sort_callback(dap_list_t *a_sign1, dap_list_t *a_sign2)
 
 static bool s_session_directive_ready(dap_chain_esbocs_session_t *a_session, bool *a_kick, dap_chain_addr_t *a_signing_addr)
 {
-    size_t l_list_length = dap_list_length(a_session->cur_round.all_validators);
-    if (a_session->cur_round.total_validators_synced * 3 < l_list_length * 2) {
-        log_it(L_INFO, "Not enough validators online for directive, %u * 3 < %zu * 2",
-                       a_session->cur_round.total_validators_synced, l_list_length );
-        return false; // Not a valid round, less than 2/3 participants
-    }
-    debug_if(PVT(a_session->esbocs)->debug, L_MSG, "Current consensus online %hu from %zu is acceptable, so issue the directive",
-                                                    a_session->cur_round.total_validators_synced, l_list_length);
     dap_chain_esbocs_penalty_item_t *l_item, *l_tmp;
     HASH_ITER(hh, a_session->penalty, l_item, l_tmp) {
         int l_key_state = dap_chain_net_srv_stake_key_delegated(&l_item->signing_addr);
@@ -1360,6 +1365,14 @@ static bool s_session_directive_ready(dap_chain_esbocs_session_t *a_session, boo
         }
     }
     if (l_item) {
+        size_t l_list_length = dap_list_length(a_session->cur_round.all_validators);
+        if (a_session->cur_round.total_validators_synced * 3 < l_list_length * 2) {
+            log_it(L_INFO, "Not enough validators online for directive, %u * 3 < %zu * 2",
+                           a_session->cur_round.total_validators_synced, l_list_length );
+            return false; // Not a valid round, less than 2/3 participants
+        }
+        debug_if(PVT(a_session->esbocs)->debug, L_MSG, "Current consensus online %hu from %zu is acceptable, so issue the directive",
+                                                        a_session->cur_round.total_validators_synced, l_list_length);
         *a_signing_addr = l_item->signing_addr;
         return true;
     } else
@@ -2582,8 +2595,11 @@ static void s_session_packet_in(dap_chain_esbocs_session_t *a_session, dap_chain
                         l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
                             l_message->hdr.attempt_num, l_candidate_hash_str);
             size_t l_offset = dap_chain_block_get_sign_offset(l_store->candidate, l_store->candidate_size);
+            uint32_t l_hash_type = DAP_SIGN_HASH_TYPE_DEFAULT;
+            if (dap_chain_policy_activated(DAP_CHAIN_POLICY_PUBLIC_KEY_HASH_SIGN_VALIDATORS, a_session->chain->net_id.uint64))
+                l_hash_type = DAP_SIGN_ADD_PKEY_HASHING_FLAG(l_hash_type);
             dap_sign_t *l_candidate_sign = dap_sign_create_with_hash_type(PVT(l_session->esbocs)->blocks_sign_key,
-                                            l_store->candidate, l_offset + sizeof(l_store->candidate->hdr), DAP_SIGN_ADD_PKEY_HASHING_FLAG(DAP_SIGN_HASH_TYPE_DEFAULT));
+                                            l_store->candidate, l_offset + sizeof(l_store->candidate->hdr), l_hash_type);
             size_t l_candidate_sign_size = dap_sign_get_size(l_candidate_sign);
             s_message_send(l_session, DAP_CHAIN_ESBOCS_MSG_TYPE_COMMIT_SIGN, l_candidate_hash,
                            l_candidate_sign, l_candidate_sign_size, l_session->cur_round.validators_list);
@@ -2788,7 +2804,10 @@ static void s_message_send(dap_chain_esbocs_session_t *a_session, uint8_t a_mess
                                                            NODE_ADDR_FP_ARGS_S(l_validator->node_addr));
             l_message->hdr.recv_addr = l_validator->node_addr;
             l_message->hdr.sign_size = 0;
-            dap_sign_t *l_sign = dap_sign_create_with_hash_type( PVT(a_session->esbocs)->blocks_sign_key, l_message, l_message_size, DAP_SIGN_ADD_PKEY_HASHING_FLAG(DAP_SIGN_HASH_TYPE_DEFAULT) );
+            uint32_t l_hash_type = DAP_SIGN_HASH_TYPE_DEFAULT;
+            if (dap_chain_policy_activated(DAP_CHAIN_POLICY_PUBLIC_KEY_HASH_SIGN_VALIDATORS, a_session->chain->net_id.uint64))
+                l_hash_type = DAP_SIGN_ADD_PKEY_HASHING_FLAG(l_hash_type);
+            dap_sign_t *l_sign = dap_sign_create_with_hash_type( PVT(a_session->esbocs)->blocks_sign_key, l_message, l_message_size, l_hash_type);
             size_t l_sign_size = dap_sign_get_size(l_sign);
             l_message->hdr.sign_size = l_sign_size;
             dap_chain_esbocs_message_t *l_message_signed = DAP_REALLOC_RET_IF_FAIL(l_message, l_message_size + l_sign_size, l_sign, l_message);
@@ -2836,6 +2855,10 @@ static size_t s_callback_block_sign(dap_chain_cs_blocks_t *a_blocks, dap_chain_b
 
 static uint64_t s_get_precached_key_hash(dap_list_t **a_precached_keys_list, dap_sign_t *a_source_sign, dap_hash_fast_t *a_result)
 {
+    if (DAP_SIGN_GET_PKEY_HASHING_FLAG(a_source_sign->header.hash_type)) {
+        *a_result = *(dap_hash_fast_t *)a_source_sign->pkey_n_sign;
+        return 0;
+    }
     bool l_found = false;
     struct precached_key *l_key = NULL;
     dap_list_t *l_cur;
@@ -2921,6 +2944,7 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_bl
             log_it(L_WARNING, "Can't process non-hardfork block %s with generation meta", dap_hash_fast_to_str_static(a_block_hash));
             return -303;
         }
+        return 0;
     }
 
     size_t l_block_size = a_block_size; // /* Can't calc it for many old bugged blocks */ dap_chain_block_get_size(a_block);
diff --git a/modules/datum/include/dap_chain_datum_decree.h b/modules/datum/include/dap_chain_datum_decree.h
index 29b8c93fbc43db97bd4f49f572c6920941cee3e7..6a00498094c074fb67a9dbbc390ae4748d39c632 100644
--- a/modules/datum/include/dap_chain_datum_decree.h
+++ b/modules/datum/include/dap_chain_datum_decree.h
@@ -80,6 +80,7 @@ DAP_STATIC_INLINE size_t dap_chain_datum_decree_get_size(dap_chain_datum_decree_
 #define DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_PKEY_UPDATE             0x0010
 #define DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK_COMPLETE             0x0011
 #define DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_POLICY                        0x0012
+#define DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK_VALIDATORS           0x0013
 
 // DECREE TSD types
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_VALUE                               0x0100
@@ -91,18 +92,18 @@ DAP_STATIC_INLINE size_t dap_chain_datum_decree_get_size(dap_chain_datum_decree_
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HASH                                0x0107
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_VALUE                         0x0108
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_SIGNING_ADDR                  0x0109
+#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_ACTION                              0x010A
+#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_SIGNATURE_TYPE                      0x010B
+#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_BLOCK_NUM                           0x010C
+#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_PKEY                          0x010D
+#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_POLICY_EXECUTE                      0x010E
+#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_GENERATION                          0x010F
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR                           0x0110
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_MIN_VALUE                     0x0111
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_MIN_SIGNERS_COUNT             0x0112
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HOST                                0x0113
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STRING                              0x0115
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HARDFORK_CHANGED_ADDRS              0x0116
-#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_ACTION                              0x010A
-#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_SIGNATURE_TYPE                      0x010B
-#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_BLOCK_NUM                           0x010C
-#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_PKEY                          0x010D
-#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_POLICY_EXECUTE                      0x010E 
-
 
 #ifdef __cplusplus
 extern "C" {
diff --git a/modules/ledger/dap_chain_ledger.c b/modules/ledger/dap_chain_ledger.c
index 74ca761fac7bb0361ef6eeccaa40787e096b0bd8..d4f132c1d6d5dffb8c0f63a2a5539a5bb710b3c2 100644
--- a/modules/ledger/dap_chain_ledger.c
+++ b/modules/ledger/dap_chain_ledger.c
@@ -956,12 +956,19 @@ const char *dap_ledger_tx_tag_str_by_uid(dap_chain_srv_uid_t a_service_uid)
  * Delete all transactions from the cache
  */
 void dap_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
+{
+    dap_ledger_tx_purge(a_ledger, a_preserve_db);
+    dap_ledger_token_purge(a_ledger, a_preserve_db);
+    dap_ledger_decree_purge(a_ledger);
+    PVT(a_ledger)->load_end = false;
+}
+
+void dap_ledger_tx_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
 {
     dap_return_if_fail(a_ledger);
     dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
 
     pthread_rwlock_wrlock(&l_ledger_pvt->ledger_rwlock);
-    pthread_rwlock_wrlock(&l_ledger_pvt->tokens_rwlock);
     pthread_rwlock_wrlock(&l_ledger_pvt->threshold_txs_rwlock);
     pthread_rwlock_wrlock(&l_ledger_pvt->balance_accounts_rwlock);
     pthread_rwlock_wrlock(&l_ledger_pvt->stake_lock_rwlock);
@@ -993,30 +1000,6 @@ void dap_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
         DAP_DELETE(l_gdb_group);
     }
 
-    /* Delete tokens and their emissions */
-    dap_ledger_token_item_t *l_token_current, *l_token_tmp;
-    dap_ledger_token_emission_item_t *l_emission_current, *l_emission_tmp;
-    HASH_ITER(hh, l_ledger_pvt->tokens, l_token_current, l_token_tmp) {
-        HASH_DEL(l_ledger_pvt->tokens, l_token_current);
-        pthread_rwlock_wrlock(&l_token_current->token_emissions_rwlock);
-        HASH_ITER(hh, l_token_current->token_emissions, l_emission_current, l_emission_tmp) {
-            HASH_DEL(l_token_current->token_emissions, l_emission_current);
-            DAP_DEL_MULTY(l_emission_current->datum_token_emission, l_emission_current);
-        }
-        pthread_rwlock_unlock(&l_token_current->token_emissions_rwlock);
-        pthread_rwlock_destroy(&l_token_current->token_emissions_rwlock);
-        DAP_DEL_MULTY(l_token_current->datum_token, l_token_current->datum_token, l_token_current->auth_pkeys, l_token_current->auth_pkey_hashes,
-            l_token_current->tx_recv_allow, l_token_current->tx_recv_block, l_token_current->tx_send_allow, l_token_current->tx_send_block, l_token_current);
-    }
-    if (!a_preserve_db) {
-        l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_TOKENS_STR);
-        dap_global_db_erase_table(l_gdb_group, NULL, NULL);
-        DAP_DELETE(l_gdb_group);
-        l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_EMISSIONS_STR);
-        dap_global_db_erase_table(l_gdb_group, NULL, NULL);
-        DAP_DELETE(l_gdb_group);
-    }
-
     /* Delete stake-lock items */
     dap_ledger_stake_lock_item_t *l_stake_item_current, *l_stake_item_tmp;
     HASH_ITER(hh, l_ledger_pvt->emissions_for_stake_lock, l_stake_item_current, l_stake_item_tmp) {
@@ -1034,23 +1017,52 @@ void dap_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
         HASH_DEL(l_ledger_pvt->threshold_txs, l_item_current);
         if (!is_ledger_mapped(l_ledger_pvt))
             DAP_DELETE(l_item_current->tx);
-        DAP_DELETE(l_item_current);
+        DAP_DEL_Z(l_item_current);
     }
 
     l_ledger_pvt->ledger_items         = NULL;
     l_ledger_pvt->balance_accounts     = NULL;
-    l_ledger_pvt->tokens               = NULL;
     l_ledger_pvt->threshold_txs        = NULL;
 
     pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock);
-    pthread_rwlock_unlock(&l_ledger_pvt->tokens_rwlock);
     pthread_rwlock_unlock(&l_ledger_pvt->threshold_txs_rwlock);
     pthread_rwlock_unlock(&l_ledger_pvt->balance_accounts_rwlock);
     pthread_rwlock_unlock(&l_ledger_pvt->stake_lock_rwlock);
+}
 
-    l_ledger_pvt->load_end = false;
+void dap_ledger_token_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
+{
+    dap_return_if_fail(a_ledger);
+    dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
 
-    dap_ledger_decree_purge(a_ledger);
+    pthread_rwlock_wrlock(&l_ledger_pvt->tokens_rwlock);
+
+    /* Delete tokens and their emissions */
+    dap_ledger_token_item_t *l_token_current, *l_token_tmp;
+    dap_ledger_token_emission_item_t *l_emission_current, *l_emission_tmp;
+    HASH_ITER(hh, l_ledger_pvt->tokens, l_token_current, l_token_tmp) {
+        HASH_DEL(l_ledger_pvt->tokens, l_token_current);
+        pthread_rwlock_wrlock(&l_token_current->token_emissions_rwlock);
+        HASH_ITER(hh, l_token_current->token_emissions, l_emission_current, l_emission_tmp) {
+            HASH_DEL(l_token_current->token_emissions, l_emission_current);
+            DAP_DEL_MULTY(l_emission_current->datum_token_emission, l_emission_current);
+        }
+        pthread_rwlock_unlock(&l_token_current->token_emissions_rwlock);
+        pthread_rwlock_destroy(&l_token_current->token_emissions_rwlock);
+        DAP_DEL_MULTY(l_token_current->datum_token, l_token_current->datum_token, l_token_current->auth_pkeys, l_token_current->auth_pkey_hashes,
+            l_token_current->tx_recv_allow, l_token_current->tx_recv_block, l_token_current->tx_send_allow, l_token_current->tx_send_block, l_token_current);
+    }
+    if (!a_preserve_db) {
+        char *l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_TOKENS_STR);
+        dap_global_db_erase_table(l_gdb_group, NULL, NULL);
+        DAP_DELETE(l_gdb_group);
+        l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_EMISSIONS_STR);
+        dap_global_db_erase_table(l_gdb_group, NULL, NULL);
+        DAP_DELETE(l_gdb_group);
+    }
+
+    l_ledger_pvt->tokens               = NULL;
+    pthread_rwlock_unlock(&l_ledger_pvt->tokens_rwlock);
 }
 
 /**
diff --git a/modules/ledger/dap_chain_ledger_decree.c b/modules/ledger/dap_chain_ledger_decree.c
index 95b561c6e67483678d199f3f7905df908c66bcd8..3b47512e2563a2daa175bbea0a7aeced91e9b3f7 100644
--- a/modules/ledger/dap_chain_ledger_decree.c
+++ b/modules/ledger/dap_chain_ledger_decree.c
@@ -600,26 +600,42 @@ const char *l_ban_addr;
                 log_it(L_WARNING, "Can't apply this decree to specified chain");
                 return -115;
             }
+            dap_tsd_t *l_generation = dap_tsd_find(a_decree->data_n_signs, a_decree->header.data_size, DAP_CHAIN_DATUM_DECREE_TSD_TYPE_GENERATION);
+            if (!l_generation || l_generation->size != sizeof(uint16_t)) {
+                log_it(L_WARNING, "Can't apply this decree, it has no chain generation set");
+                return -116;
+            }
             if (!a_apply)
                 break;
+            if (*(uint16_t *)l_generation->data < l_chain->generation)
+                return 0;       // Old generation hardfork already completed
             dap_list_t *l_addrs = dap_tsd_find_all(a_decree->data_n_signs, a_decree->header.data_size,
                                                    DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR, sizeof(dap_stream_node_addr_t));
+            dap_tsd_t *l_changed_addrs = dap_tsd_find(a_decree->data_n_signs, a_decree->header.data_size, DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HARDFORK_CHANGED_ADDRS);
             dap_hash_fast(a_decree, dap_chain_datum_decree_get_size(a_decree), &l_chain->hardfork_decree_hash);
-            dap_tsd_t* l_changed_addrs = dap_tsd_find(a_decree->data_n_signs, a_decree->header.data_size,DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HARDFORK_CHANGED_ADDRS);
             return dap_chain_esbocs_set_hardfork_prepare(l_chain, l_block_num, l_addrs, json_tokener_parse((char *)l_changed_addrs->data));
         }
-        case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_POLICY: {
+        case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK_VALIDATORS: {
+            dap_chain_t *l_chain = dap_chain_find_by_id(a_net->pub.id, a_decree->header.common_decree_params.chain_id);
+            if (!l_chain) {
+                log_it(L_WARNING, "Specified chain not found");
+                return -106;
+            }
+            if (dap_strcmp(dap_chain_get_cs_type(l_chain), "esbocs")) {
+                log_it(L_WARNING, "Can't apply this decree to specified chain");
+                return -115;
+            }
+            dap_tsd_t *l_generation = dap_tsd_find(a_decree->data_n_signs, a_decree->header.data_size, DAP_CHAIN_DATUM_DECREE_TSD_TYPE_GENERATION);
+            if (!l_generation || l_generation->size != sizeof(uint16_t)) {
+                log_it(L_WARNING, "Can't apply this decree, it has no chain generation set");
+                return -116;
+            }
             if (!a_apply)
                 break;
-            dap_chain_policy_t *l_policy = NULL;
-            if ( !(l_policy = dap_chain_datum_decree_get_policy(a_decree)) ){
-                log_it(L_WARNING,"Can't get policy from decree.");
-                return -105;
-            }
-            l_policy = DAP_DUP_SIZE_RET_VAL_IF_FAIL(l_policy, dap_chain_policy_get_size(l_policy), -106);
-            if (DAP_FLAG_CHECK(l_policy->activate.flags, DAP_CHAIN_POLICY_FLAG_ACTIVATE_BY_BLOCK_NUM))
-                l_policy->activate.chain_union.chain = dap_chain_find_by_id(a_net->pub.id, l_policy->activate.chain_union.chain_id);
-            return dap_chain_policy_add(l_policy, a_net->pub.id.uint64);
+            if (*(uint16_t *)l_generation->data < l_chain->generation)
+                return 0;       // Old generation hardfork already completed
+            dap_hash_fast(a_decree, dap_chain_datum_decree_get_size(a_decree), &l_chain->hardfork_decree_hash);
+            return dap_chain_esbocs_set_hardfork_prepare(l_chain, 0, NULL, NULL);
         }
         case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK_COMPLETE: {
             dap_chain_t *l_chain = dap_chain_find_by_id(a_net->pub.id, a_decree->header.common_decree_params.chain_id);
@@ -635,6 +651,19 @@ const char *l_ban_addr;
                 break;
             return dap_chain_esbocs_set_hardfork_complete(l_chain);
         }
+        case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_POLICY: {
+            if (!a_apply)
+                break;
+            dap_chain_policy_t *l_policy = NULL;
+            if ( !(l_policy = dap_chain_datum_decree_get_policy(a_decree)) ){
+                log_it(L_WARNING,"Can't get policy from decree.");
+                return -105;
+            }
+            l_policy = DAP_DUP_SIZE_RET_VAL_IF_FAIL(l_policy, dap_chain_policy_get_size(l_policy), -106);
+            if (DAP_FLAG_CHECK(l_policy->activate.flags, DAP_CHAIN_POLICY_FLAG_ACTIVATE_BY_BLOCK_NUM))
+                l_policy->activate.chain_union.chain = dap_chain_find_by_id(a_net->pub.id, l_policy->activate.chain_union.chain_id);
+            return dap_chain_policy_add(l_policy, a_net->pub.id.uint64);
+        }
         default:
             return -1;
     }
diff --git a/modules/ledger/include/dap_chain_ledger.h b/modules/ledger/include/dap_chain_ledger.h
index 65ca7447d18752446c44075340a1fb6b8ab4493e..0a1d3a1205609ae845d5ee6be5f7e99d9d7f4243 100644
--- a/modules/ledger/include/dap_chain_ledger.h
+++ b/modules/ledger/include/dap_chain_ledger.h
@@ -396,6 +396,8 @@ dap_chain_token_ticker_str_t dap_ledger_tx_calculate_main_ticker_(dap_ledger_t *
  * Delete all transactions from the cache
  */
 void dap_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db);
+void dap_ledger_tx_purge(dap_ledger_t *a_ledger, bool a_preserve_db);
+void dap_ledger_token_purge(dap_ledger_t *a_ledger, bool a_preserve_db);
 
 /**
  * Return number transactions from the cache
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 2d2d40b8d2463c6096b7d21ab9eb4ff0c1f092c2..0b04a97d0f89ed10aeb40743f47facc94ca7bced 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -1907,7 +1907,7 @@ static int s_chains_init_all(dap_chain_net_t *a_net, const char *a_path, uint16_
             }
             if ( l_chain->callback_get_poa_certs ) {
                 uint16_t l_min_count = 0;
-                a_net->pub.keys = dap_list_append(a_net->pub.keys, l_chain->callback_get_poa_certs(l_chain, NULL, &l_min_count));
+                a_net->pub.keys = dap_list_concat(a_net->pub.keys, l_chain->callback_get_poa_certs(l_chain, NULL, &l_min_count));
                 a_net->pub.keys_min_count += l_min_count;
             }
         } else {
diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c
index 5e4e4276c282fe30bc5ce3c1b07da59275c91c73..8c7a2fa1cdc89cadeb2237b5d2e6372554761c16 100644
--- a/modules/net/dap_chain_node.c
+++ b/modules/net/dap_chain_node.c
@@ -19,33 +19,16 @@
  along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdlib.h>
-#include <stdio.h>
-#include <time.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <string.h>
-
-#ifdef WIN32
-#include <winsock2.h>
-#include <windows.h>
-#include <mswsock.h>
-#include <ws2tcpip.h>
-#include <io.h>
-#include <pthread.h>
-#else
-#include <sys/socket.h>
-#include <netinet/in.h>
-#endif
-
+#include "dap_common.h"
 #include "dap_hash.h"
+#include "dap_chain_cell.h"
 #include "dap_chain_net.h"
 #include "dap_global_db.h"
 #include "dap_chain_node.h"
 #include "dap_chain_node_client.h"
 #include "dap_chain_cs_esbocs.h" // TODO set RPC callbacks for exclude consensus specific dependency
 #include "dap_chain_cs_blocks.h" // TODO set RPC callbacks for exclude storage type specific dependency
+#include "dap_chain_net_srv_stake_pos_delegate.h" // TODO set RPC callbacks for exclude service specific dependency
 #include "dap_chain_ledger.h"
 #include "dap_cli_server.h"
 #include "dap_chain_srv.h"
@@ -542,6 +525,10 @@ int dap_chain_node_hardfork_prepare(dap_chain_t *a_chain, dap_time_t a_last_bloc
         return log_it(L_ERROR, "Can't prepare harfork for chain type %s is not supported", dap_chain_get_cs_type(a_chain)), -2;
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
     assert(l_net);
+    if (dap_chain_net_srv_stake_hardfork_data_verify(l_net, &a_chain->hardfork_decree_hash)) {
+        log_it(L_ERROR, "Stake delegate data verifying with hardfork decree failed");
+        return -3;
+    }
     struct hardfork_states *l_states = DAP_NEW_Z_RET_VAL_IF_FAIL(struct hardfork_states, -1, NULL);
     l_states->balances = dap_ledger_states_aggregate(l_net->pub.ledger, a_last_block_timestamp, &l_states->condouts, a_changed_addrs);
     l_states->anchors = dap_ledger_anchors_aggregate(l_net->pub.ledger);
@@ -562,6 +549,11 @@ int dap_chain_node_hardfork_prepare(dap_chain_t *a_chain, dap_time_t a_last_bloc
     l_states->trusted_addrs = a_trusted_addrs;
     a_chain->hardfork_data = l_states;
     a_chain->generation++;
+    dap_chain_purge(a_chain);
+    dap_ledger_tx_purge(l_net->pub.ledger, false);
+    dap_chain_srv_purge_all(a_chain->net_id);
+    dap_chain_cell_close(a_chain, a_chain->cells->id);
+    dap_chain_cell_open(a_chain, "8000000000000000.dchaincell", 'w'); //dap_chain_cell_create(a_chain, c_dap_chain_cell_id_hardfork);
     l_net->pub.ledger->is_hardfork_state = true;
     return 0;
 }
diff --git a/modules/node-cli/dap_chain_node_cli.c b/modules/node-cli/dap_chain_node_cli.c
index e8be71cff066739de431108f31dfb2d57051794b..41b2d87d23c180a59f3795967324255351b8c386 100644
--- a/modules/node-cli/dap_chain_node_cli.c
+++ b/modules/node-cli/dap_chain_node_cli.c
@@ -114,105 +114,6 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
                                         "? [<command>]\n"
                                         "\tObtain help for <command> or get the total list of the commands\n"
                                         );
-    dap_cli_server_cmd_add ("token_update", com_token_update, "Token update",
-                            "\nPrivate or CF20 token update\n"
-                            "token_update -net <net_name> [-chain <chain_name>] -token <existing_token_ticker> -type <CF20|private> [-total_supply_change <value>] "
-                            "-certs <name_certs> [-flag_set <flag>] [-flag_unset <flag>] [-total_signs_valid <value>] [-description <value>] "
-                            "[-tx_receiver_allowed <value>] [-tx_receiver_blocked <value>] [-tx_sender_allowed <value>] [-tx_sender_blocked <value>] "
-                            "[-add_cert <name_certs>] [-remove_certs <pkeys_hash>]\n"
-                            "==Flags==\n"
-                            "\tALL_BLOCKED: \t\t\t\tBlocks all permissions.\n"
-                            "\tALL_ALLOWED: \t\t\t\tAllows all permissions unless they are blocked. Be careful with this mode.\n"
-                            "\tALL_FROZEN: \t\t\t\tTemporarily freezes all permissions\n"
-                            "\tALL_UNFROZEN: \t\t\t\tUnfreezes all frozen permissions\n"
-                            "\tSTATIC_ALL: \t\t\t\tBlocks manipulations with a token after declaration. Tokens are declared statically.\n"
-                            "\tSTATIC_FLAGS: \t\t\t\tBlocks manipulations with token flags after declaration.\n"
-                            "\tSTATIC_PERMISSIONS_ALL: \t\tBlocks all manipulations with permissions list after declaration.\n"
-                            "\tSTATIC_PERMISSIONS_DATUM_TYPE: \t\tBlocks all manipulations with datum permissions list after declaration.\n"
-                            "\tSTATIC_PERMISSIONS_TX_SENDER: \t\tBlocks all manipulations with transaction senders permissions list after declaration.\n"
-                            "\tSTATIC_PERMISSIONS_TX_RECEIVER: \tBlocks all manipulations with transaction receivers permissions list after declaration.\n"
-                            "\n"
-                            "==Params==\n"
-                            "General:\n"
-                            "\t -total_supply_change <value>:\t\t Sets the maximum amount of token supply. Specify “INF” to set unlimited total supply.\n"
-                            "\t -certs <name_certs>:\t\t\t Here use the very certificates which were used to sign the token being updated.\n"
-                            "Additional:\n"
-                            "\t -description <token_description>:\t Shows updated description for this token.\n"
-                            "Installing and removing the flag:\n"
-                            "\t -flag_set <flag_name>:\t\t\t Adds specified flag to the list of active flags.\n"
-                            "\t -flag_unset <flag_name>:\t\t Removes specified flag from the list of active flags.\n"
-                            "Work with the number of signatures required for the issue:\n"
-                            "\t -total_signs_valid <value>:\t\t Sets the minimum amount of valid signatures.\n"
-                            "\t -add_certs <cert_list>:\t\t Adds certificates to the certificates list of the token.\n"
-                            "\t -remove_certs <pkeys_hash>:\t\t Removes certificates from the certificates list using theirs public key hashes.\n"
-                            "Tx receiver addresses allowed/blocked:\n"
-                            "\t -tx_receiver_allowed <wallet_addr>:\t Adds specified wallet address to the list of allowed receivers.\n"
-                            "\t -tx_receiver_blocked <wallet_addr>:\t Adds specified wallet address to the list of blocked receivers.\n"
-                            "\nTx sender addresses allowed/blocked:\n"
-                            "\t -tx_sender_allowed <wallet_addr>:\t Adds specified wallet address to the list of allowed senders.\n"
-                            "\t -tx_sender_blocked <wallet_addr>:\t Adds specified wallet address to the list of blocked senders.\n"
-                            "\n"
-    );
-    dap_cli_server_cmd_add ("wallet", com_tx_wallet, "Wallet operations",
-                            "wallet list\n"
-                            "wallet new -w <wallet_name> [-sign <sign_type>] [-restore <hex_value> | -restore_legacy <restore_string>] [-net <net_name>] [-force] [-password <password>]\n"
-                            "wallet info {-addr <addr> | -w <wallet_name>} -net <net_name>\n"
-                            "wallet activate -w <wallet_name> -password <password> [-ttl <password_ttl_in_minutes>]\n"
-                            "wallet deactivate -w <wallet_name>>\n"
-                            "wallet convert -w <wallet_name> -password <password> | -remove_password }\n");
-    // Token commands
-    dap_cli_server_cmd_add ("token_update", com_token_update, "Token update",
-                            "\nPrivate or CF20 token update\n"
-                            "token_update -net <net_name> [-chain <chain_name>] -token <existing_token_ticker> -type <CF20|private> [-total_supply_change <value>] "
-                            "-certs <name_certs> [-flag_set <flag>] [-flag_unset <flag>] [-total_signs_valid <value>] [-description <value>] "
-                            "[-tx_receiver_allowed <value>] [-tx_receiver_blocked <value>] [-tx_sender_allowed <value>] [-tx_sender_blocked <value>] "
-                            "[-add_cert <name_certs>] [-remove_certs <pkeys_hash>]\n"
-                            "==Flags==\n"
-                            "\tALL_BLOCKED: \t\t\t\tBlocks all permissions.\n"
-                            "\tALL_ALLOWED: \t\t\t\tAllows all permissions unless they are blocked. Be careful with this mode.\n"
-                            "\tALL_FROZEN: \t\t\t\tTemporarily freezes all permissions\n"
-                            "\tALL_UNFROZEN: \t\t\t\tUnfreezes all frozen permissions\n"
-                            "\tSTATIC_ALL: \t\t\t\tBlocks manipulations with a token after declaration. Tokens are declared statically.\n"
-                            "\tSTATIC_FLAGS: \t\t\t\tBlocks manipulations with token flags after declaration.\n"
-                            "\tSTATIC_PERMISSIONS_ALL: \t\tBlocks all manipulations with permissions list after declaration.\n"
-                            "\tSTATIC_PERMISSIONS_DATUM_TYPE: \t\tBlocks all manipulations with datum permissions list after declaration.\n"
-                            "\tSTATIC_PERMISSIONS_TX_SENDER: \t\tBlocks all manipulations with transaction senders permissions list after declaration.\n"
-                            "\tSTATIC_PERMISSIONS_TX_RECEIVER: \tBlocks all manipulations with transaction receivers permissions list after declaration.\n"
-                            "\n"
-                            "==Params==\n"
-                            "General:\n"
-                            "\t -total_supply_change <value>:\t\t Sets the maximum amount of token supply. Specify “INF” to set unlimited total supply.\n"
-                            "\t -certs <name_certs>:\t\t\t Here use the very certificates which were used to sign the token being updated.\n"
-                            "Additional:\n"
-                            "\t -description <token_description>:\t Shows updated description for this token.\n"
-                            "Installing and removing the flag:\n"
-                            "\t -flag_set <flag_name>:\t\t\t Adds specified flag to the list of active flags.\n"
-                            "\t -flag_unset <flag_name>:\t\t Removes specified flag from the list of active flags.\n"
-                            "Work with the number of signatures required for the issue:\n"
-                            "\t -total_signs_valid <value>:\t\t Sets the minimum amount of valid signatures.\n"
-                            "\t -add_certs <cert_list>:\t\t Adds certificates to the certificates list of the token.\n"
-                            "\t -remove_certs <pkeys_hash>:\t\t Removes certificates from the certificates list using theirs public key hashes.\n"
-                            "Tx receiver addresses allowed/blocked:\n"
-                            "\t -tx_receiver_allowed <wallet_addr>:\t Adds specified wallet address to the list of allowed receivers.\n"
-                            "\t -tx_receiver_blocked <wallet_addr>:\t Adds specified wallet address to the list of blocked receivers.\n"
-                            "\nTx sender addresses allowed/blocked:\n"
-                            "\t -tx_sender_allowed <wallet_addr>:\t Adds specified wallet address to the list of allowed senders.\n"
-                            "\t -tx_sender_blocked <wallet_addr>:\t Adds specified wallet address to the list of blocked senders.\n"
-                            "\n"
-    );
-    dap_cli_server_cmd_add ("wallet", com_tx_wallet, "Wallet operations",
-                            "wallet list\n"
-                            "wallet new -w <wallet_name> [-sign <sign_type>] [-restore <hex_value> | -restore_legacy <restore_string>] [-net <net_name>] [-force] [-password <password>]\n"
-                            "wallet info {-addr <addr> | -w <wallet_name>} -net <net_name>\n"
-                            "wallet activate -w <wallet_name> -password <password> [-ttl <password_ttl_in_minutes>]\n"
-                            "wallet deactivate -w <wallet_name> -password <password>\n"
-                            "wallet convert -w <wallet_name> -password <password>\n"
-                            "wallet outputs {-addr <addr> | -w <wallet_name>} -net <net_name> -token <token_tiker> [-value <uint256_value>]");
-
-
-    // Token commands
-
-
     // Token commands
     dap_cli_server_cmd_add ("token_decl", com_token_decl, "Token declaration",
             "Simple token declaration:\n"
@@ -263,18 +164,56 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
             
             "Hint:\n"
             "\texample coins amount syntax (only natural) 1.0 123.4567\n"
-            "\texample datoshi amount syntax (only integer) 1 20 0.4321e+4\n\n");
+            "\texample datoshi amount syntax (only integer) 1 20 0.4321e+4\n\n"
+    );
+    dap_cli_server_cmd_add ("token_decl_sign", com_token_decl_sign, "Token declaration add sign",
+            "token_decl_sign -net <net_name> [-chain <chain_name>] -datum <datum_hash> -certs <certs_list>\n"
+            "\t Sign existent <datum_hash> in mempool with <certs_list>\n"
+    );
 
+    dap_cli_server_cmd_add ("token_update", com_token_update, "Token update",
+                            "\nPrivate or CF20 token update\n"
+                            "token_update -net <net_name> [-chain <chain_name>] -token <existing_token_ticker> -type <CF20|private> [-total_supply_change <value>] "
+                            "-certs <name_certs> [-flag_set <flag>] [-flag_unset <flag>] [-total_signs_valid <value>] [-description <value>] "
+                            "[-tx_receiver_allowed <value>] [-tx_receiver_blocked <value>] [-tx_sender_allowed <value>] [-tx_sender_blocked <value>] "
+                            "[-add_cert <name_certs>] [-remove_certs <pkeys_hash>]\n"
+                            "==Flags==\n"
+                            "\tALL_BLOCKED: \t\t\t\tBlocks all permissions.\n"
+                            "\tALL_ALLOWED: \t\t\t\tAllows all permissions unless they are blocked. Be careful with this mode.\n"
+                            "\tALL_FROZEN: \t\t\t\tTemporarily freezes all permissions\n"
+                            "\tALL_UNFROZEN: \t\t\t\tUnfreezes all frozen permissions\n"
+                            "\tSTATIC_ALL: \t\t\t\tBlocks manipulations with a token after declaration. Tokens are declared statically.\n"
+                            "\tSTATIC_FLAGS: \t\t\t\tBlocks manipulations with token flags after declaration.\n"
+                            "\tSTATIC_PERMISSIONS_ALL: \t\tBlocks all manipulations with permissions list after declaration.\n"
+                            "\tSTATIC_PERMISSIONS_DATUM_TYPE: \t\tBlocks all manipulations with datum permissions list after declaration.\n"
+                            "\tSTATIC_PERMISSIONS_TX_SENDER: \t\tBlocks all manipulations with transaction senders permissions list after declaration.\n"
+                            "\tSTATIC_PERMISSIONS_TX_RECEIVER: \tBlocks all manipulations with transaction receivers permissions list after declaration.\n"
+                            "\n"
+                            "==Params==\n"
+                            "General:\n"
+                            "\t -total_supply_change <value>:\t\t Sets the maximum amount of token supply. Specify “INF” to set unlimited total supply.\n"
+                            "\t -certs <name_certs>:\t\t\t Here use the very certificates which were used to sign the token being updated.\n"
+                            "Additional:\n"
+                            "\t -description <token_description>:\t Shows updated description for this token.\n"
+                            "Installing and removing the flag:\n"
+                            "\t -flag_set <flag_name>:\t\t\t Adds specified flag to the list of active flags.\n"
+                            "\t -flag_unset <flag_name>:\t\t Removes specified flag from the list of active flags.\n"
+                            "Work with the number of signatures required for the issue:\n"
+                            "\t -total_signs_valid <value>:\t\t Sets the minimum amount of valid signatures.\n"
+                            "\t -add_certs <cert_list>:\t\t Adds certificates to the certificates list of the token.\n"
+                            "\t -remove_certs <pkeys_hash>:\t\t Removes certificates from the certificates list using theirs public key hashes.\n"
+                            "Tx receiver addresses allowed/blocked:\n"
+                            "\t -tx_receiver_allowed <wallet_addr>:\t Adds specified wallet address to the list of allowed receivers.\n"
+                            "\t -tx_receiver_blocked <wallet_addr>:\t Adds specified wallet address to the list of blocked receivers.\n"
+                            "\nTx sender addresses allowed/blocked:\n"
+                            "\t -tx_sender_allowed <wallet_addr>:\t Adds specified wallet address to the list of allowed senders.\n"
+                            "\t -tx_sender_blocked <wallet_addr>:\t Adds specified wallet address to the list of blocked senders.\n"
+                            "\n"
+    );
     dap_cli_server_cmd_add("token_update_sign", com_token_decl_sign, "Token update add sign to datum",
                                         "token_update_sign -net <net_name> [-chain <chain_name>] -datum <datum_hash> -certs <cert_list>\n"
                                         "\t Sign existent <datum hash> in mempool with <certs_list>\n"
     );
-    // Token commands
-
-    dap_cli_server_cmd_add ("token_decl_sign", com_token_decl_sign, "Token declaration add sign",
-            "token_decl_sign -net <net_name> [-chain <chain_name>] -datum <datum_hash> -certs <certs_list>\n"
-            "\t Sign existent <datum_hash> in mempool with <certs_list>\n"
-            );
 
     dap_cli_server_cmd_add ("token_emit", com_token_emit, "Token emission",
                             "token_emit { sign -emission <hash> | -token <mempool_token_ticker> -emission_value <value> -addr <addr> } "
@@ -283,6 +222,15 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
                             "\texample coins amount syntax (only natural) 1.0 123.4567\n"
                             "\texample datoshi amount syntax (only integer) 1 20 0.4321e+4\n\n");
 
+    dap_cli_server_cmd_add ("wallet", com_tx_wallet, "Wallet operations",
+                            "wallet list\n"
+                            "wallet new -w <wallet_name> [-sign <sign_type>] [-restore <hex_value> | -restore_legacy <restore_string>] [-net <net_name>] [-force] [-password <password>]\n"
+                            "wallet info {-addr <addr> | -w <wallet_name>} -net <net_name>\n"
+                            "wallet activate -w <wallet_name> -password <password> [-ttl <password_ttl_in_minutes>]\n"
+                            "wallet deactivate -w <wallet_name> -password <password>\n"
+                            "wallet convert -w <wallet_name> -password <password>\n"
+                            "wallet outputs {-addr <addr> | -w <wallet_name>} -net <net_name> -token <token_tiker> [-value <uint256_value>]");
+
     dap_cli_server_cmd_add("mempool", com_mempool, "Command for working with mempool",
                            "mempool list -net <net_name> [-chain <chain_name>] [-addr <addr>] [-brief] [-limit] [-offset]\n"
                            "\tList mempool (entries or transaction) for (selected chain network or wallet)\n"
@@ -380,7 +328,8 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
     // Decree create command
     dap_cli_server_cmd_add ("decree", cmd_decree, "Work with decree",
             "decree create [common] -net <net_name> [-chain <chain_name>] -decree_chain <chain_name> -certs <certs_list> {-fee <net_fee_value> -to_addr <net_fee_wallet_addr> |"
-                                                                                                                        " -hardfork_from <atom_number> [-trusted_addrs <node_addresses>] |"
+                                                                                                                        " -hardfork_from <atom_number> [-trusted_addrs <node_addr1,node_add2,...>] [-addr_pairs <\"old_addr:new_addr\",\"old_addr1:new_addr1\"...>] |"
+                                                                                                                        " -hardfork_retry |"
                                                                                                                         " -hardfork_complete |"
                                                                                                                         " -new_certs <new_owners_certs_list> |"
                                                                                                                         " -signs_verify <value>}\n"
@@ -389,7 +338,9 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
             "\t -fee <value>: sets network fee\n"
             "\t -to_addr <wallet_addr>: sets wallet addr for network fee\n"
             "\t -hardfork_from <atom_number>: start hardfork routine from specified block number\n"
-            "\t -trusted_addrs <node_addresses>: addresses of nodes who can provide service state datums for hardfork routine\n"
+            "\t -trusted_addrs <node_addr1,node_add2,...>: addresses of nodes who can provide service state datums for hardfork routine\n"
+            "\t -addr_pairs <\"old_addr:new_addr\",\"old_addr1:new_addr1\"...>: blockchain addresses of wallets pairs moving balances from old_addr to new_addr with hardfork routine\n"
+            "\t -hardfork_complete: try to retry unsucsessful hardfork routine immediately\n"
             "\t -hardfork_complete: finilize hardfork routine immediately\n"
             "\t -new_certs <certs_list>: sets new owners set for net\n"
             "\t -signs_verify <value>: sets minimum number of owners needed to sign decree\n\n"
diff --git a/modules/node-cli/dap_chain_node_cli_cmd.c b/modules/node-cli/dap_chain_node_cli_cmd.c
index e4d2c80e442210927b275eb9d80ef0ca02771bdf..17deea48175c1ee5871e014d271f220d06517467 100644
--- a/modules/node-cli/dap_chain_node_cli_cmd.c
+++ b/modules/node-cli/dap_chain_node_cli_cmd.c
@@ -60,7 +60,6 @@
 #include "dap_global_db_driver.h"
 #include "dap_chain_node_client.h"
 #include "dap_chain_node_cli_cmd.h"
-#include "dap_chain_node_cli_cmd_tx.h"
 #include "dap_net.h"
 #include "dap_chain_net_balancer.h"
 #include "dap_chain_cell.h"
@@ -88,9 +87,6 @@
 #include "dap_chain_net_srv_stake_pos_delegate.h"
 #include "dap_chain_policy.h"
 
-
-#include "dap_chain_net_tx.h"
-
 #define LOG_TAG "chain_node_cli_cmd"
 
 int _cmd_mempool_add_ca(dap_chain_net_t *a_net, dap_chain_t *a_chain, dap_cert_t *a_cert, void **a_str_reply);
@@ -4114,7 +4110,7 @@ int cmd_decree(int a_argc, char **a_argv, void **a_str_reply)
             uint64_t l_param_value = strtoll(l_param_value_str, NULL, 10);
             if (!l_param_value && dap_strcmp(l_param_value_str, "0")) {
                 log_it(L_ERROR, "Can't converts %s to atom number", l_param_value_str);
-                return -1;
+                return -100;
             }
             l_tsd = dap_tsd_create(DAP_CHAIN_DATUM_DECREE_TSD_TYPE_BLOCK_NUM, &l_param_value, sizeof(l_param_value));
             if (!l_tsd) {
@@ -4123,11 +4119,14 @@ int cmd_decree(int a_argc, char **a_argv, void **a_str_reply)
                 return -1;
             }
             l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
-            if (dap_chain_net_srv_stake_hardfork_data_export(l_net, &l_tsd_list)){
-                log_it(L_ERROR, "Can't add stake delegate data to hardfork decree");
+
+            l_tsd = dap_tsd_create(DAP_CHAIN_DATUM_DECREE_TSD_TYPE_GENERATION, &l_chain->generation, sizeof(l_chain->generation));
+            if (!l_tsd) {
+                log_it(L_CRITICAL, "%s", c_error_memory_alloc);
                 dap_list_free_full(l_tsd_list, NULL);
                 return -1;
             }
+            l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
 
             const char *l_addr_pairs = NULL;
             if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-addr_pairs", &l_addr_pairs)) {
@@ -4174,6 +4173,19 @@ int cmd_decree(int a_argc, char **a_argv, void **a_str_reply)
                     l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
                 }
                 dap_strfreev(l_addrs);
+
+                if (dap_chain_net_srv_stake_hardfork_data_export(l_net, &l_tsd_list)) {
+                    log_it(L_ERROR, "Can't add stake delegate data to hardfork decree");
+                    dap_list_free_full(l_tsd_list, NULL);
+                    return -300;
+                }
+            }
+        } else if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-hardfork_retry", &l_param_value_str)) {
+            l_subtype = DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK_VALIDATORS;
+            if (dap_chain_net_srv_stake_hardfork_data_export(l_net, &l_tsd_list)) {
+                log_it(L_ERROR, "Can't add stake delegate data to hardfork decree");
+                dap_list_free_full(l_tsd_list, NULL);
+                return -300;
             }
         } else if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-hardfork_complete", &l_param_value_str)) {
             l_subtype = DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK_COMPLETE;
diff --git a/modules/node-cli/dap_chain_node_cli_cmd_token.c b/modules/node-cli/dap_chain_node_cli_cmd_token.c
index 545bdf336c7bb6d0f6a78fec59bca1eaa6f33a78..881e01d333391ad9edc79c5db3e6a22626b3f47d 100644
--- a/modules/node-cli/dap_chain_node_cli_cmd_token.c
+++ b/modules/node-cli/dap_chain_node_cli_cmd_token.c
@@ -972,9 +972,12 @@ int com_token_decl(int a_argc, char ** a_argv, void **a_str_reply)
     }
     bool l_placed = dap_global_db_set_sync(l_gdb_group_mempool, l_key_str, l_datum, l_datum_size, false) == 0;
     DAP_DELETE(l_gdb_group_mempool);
-    dap_json_rpc_error_add(*a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_TOKEN_DECL_OK,
-                     "Datum %s with token %s is%s placed in datum pool",
-                                      l_key_str_out, l_ticker, l_placed ? "" : " not");
+
+    json_object *json_obj_out = json_object_new_object();
+    char *l_str_reply_tmp = dap_strdup_printf("Datum %s with token %s is%s placed in datum pool", l_key_str_out, l_ticker, l_placed ? "" : " not");
+    json_object_object_add(json_obj_out, "result", json_object_new_string(l_str_reply_tmp));
+    DAP_DELETE(l_str_reply_tmp);
+    json_object_array_add(*a_json_arr_reply, json_obj_out);
     DAP_DELETE(l_key_str);
     DAP_DELETE(l_datum);
 
diff --git a/modules/node-cli/include/dap_chain_node_cli_cmd.h b/modules/node-cli/include/dap_chain_node_cli_cmd.h
index d00d909680f1de7f7d175a2bcb2367dc0b3e4a01..9bd9f8508ac9252f750e89b973111cca98e259c4 100644
--- a/modules/node-cli/include/dap_chain_node_cli_cmd.h
+++ b/modules/node-cli/include/dap_chain_node_cli_cmd.h
@@ -451,6 +451,13 @@ int com_exit(int a_argc, char **a_argv, void **a_str_reply);
 int cmd_gdb_import(int a_argc, char **a_argv, void **a_str_reply);
 int cmd_gdb_export(int a_argc, char **a_argv, void **a_str_reply);
 int com_mempool(int a_argc, char **a_argv, void **a_str_reply);
+
+/**
+ * decree command
+ *
+ */
+int cmd_decree(int a_argc, char **a_argv, void **a_str_reply);
+
 /**
  * Place public CA into the mempool
  */
@@ -482,4 +489,4 @@ int com_policy(int a_argc, char **a_argv, void **a_str_reply);
 
 #ifdef __cplusplus
 }
-#endif
\ No newline at end of file
+#endif
diff --git a/modules/node-cli/include/dap_chain_node_cli_cmd_tx.h b/modules/node-cli/include/dap_chain_node_cli_cmd_tx.h
index 82b7c1b13ab404916a36d2a28e1f369591b43c0e..11a8d2e78c4db0ba802551f19b740cd1c91894fb 100644
--- a/modules/node-cli/include/dap_chain_node_cli_cmd_tx.h
+++ b/modules/node-cli/include/dap_chain_node_cli_cmd_tx.h
@@ -115,12 +115,6 @@ int com_ledger(int a_argc, char ** a_argv, void **a_str_reply);
  */
 int com_token(int a_argc, char ** a_argv, void **a_str_reply);
 
-/**
- * decree command
- *
- */
-int cmd_decree(int a_argc, char **a_argv, void **a_str_reply);
-
 #ifdef __cplusplus
 }
-#endif
\ No newline at end of file
+#endif
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 e042e897cf286f54025455136a1c6b34a09c1b8c..5986354159a9d377a8b79db1ab1a41ce31666497 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
@@ -188,6 +188,7 @@ static dap_pkey_t *s_get_pkey_by_hash_callback(const uint8_t *a_hash)
         else
             HASH_FIND(hh, l_srv_stake->itemlist, a_hash, sizeof(dap_hash_fast_t), l_stake);
     }
+    dap_list_free(l_srv_stake_list);
     return l_stake ? l_stake->pkey : NULL; 
 }
 
@@ -4394,6 +4395,47 @@ int dap_chain_net_srv_stake_hardfork_data_import(dap_chain_net_id_t a_net_id, da
     return 0;
 }
 
+int dap_chain_net_srv_stake_hardfork_data_verify(dap_chain_net_t *a_net, dap_hash_fast_t *a_hardfork_decree_hash)
+{
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_net->pub.id);
+    dap_chain_datum_decree_t *l_decree = dap_ledger_decree_get_by_hash(l_net, a_hardfork_decree_hash, NULL);
+    if (!l_decree) {
+        log_it(L_ERROR, "Can't find hardfork decree by hash %s", dap_hash_fast_to_str_static(a_hardfork_decree_hash));
+        return -1;
+    }
+    // get key lis from net
+    dap_list_t *l_current_list = NULL;
+    if (dap_chain_net_srv_stake_hardfork_data_export(a_net, &l_current_list)) {
+        log_it(L_ERROR, "Can't export hardfork data from net %s", a_net->pub.name);
+        return -2;
+    }
+    dap_list_t *l_verify_list = dap_tsd_find_all(l_decree->data_n_signs, l_decree->header.data_size,
+                                                 DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HASH, sizeof(dap_hash_fast_t));
+    if (dap_list_length(l_current_list) != dap_list_length(l_verify_list)) {
+        log_it(L_ERROR, "Exported hardfork data size differs from decrees one");
+        dap_list_free_full(l_current_list, NULL);
+        dap_list_free(l_verify_list);
+        return -3;
+    }
+    for (dap_list_t *it = l_current_list, *vf = l_verify_list; it; it = it->next, vf = vf->next) {
+        dap_tsd_t *l_current = it->data, *l_verify = vf->data;
+        size_t l_verify_size = dap_tsd_size(l_current);
+        if (l_verify_size != dap_tsd_size(l_verify)) {
+            log_it(L_ERROR, "Exported hardfork TSD data size differs from decrees one");
+            dap_list_free_full(l_current_list, NULL);
+            dap_list_free(l_verify_list);
+            return -4;
+        }
+        if (memcmp(l_current, l_verify, l_verify_size)) {
+            log_it(L_ERROR, "Exported hardfork TSD data differs from decrees one by content");
+            dap_list_free_full(l_current_list, NULL);
+            dap_list_free(l_verify_list);
+            return -5;
+        }
+    }
+    return 0;
+}
+
 /**
  * @brief switch key delegate table
  * @param a_net_id net id to switch
@@ -4418,4 +4460,4 @@ int dap_chain_net_srv_stake_switch_table(dap_chain_net_id_t a_net_id, bool a_to_
     }
     l_srv_stake->hardfork.in_process = a_to_sandbox;
     return 0;
-}
\ No newline at end of file
+}
diff --git a/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h b/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h
index ff21ac8e41c4caab0192b6ba5f7be946bee551ab..3b8c7080e068031501b0f5aef90fc28b37e49bf6 100644
--- a/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h
+++ b/modules/service/stake/include/dap_chain_net_srv_stake_pos_delegate.h
@@ -82,4 +82,5 @@ void dap_chain_net_srv_stake_add_approving_decree_info(dap_chain_datum_decree_t
 void dap_chain_net_srv_stake_remove_approving_decree_info(dap_chain_net_t *a_net, dap_chain_addr_t *a_signing_addr);
 int dap_chain_net_srv_stake_hardfork_data_export(dap_chain_net_t *a_net, dap_list_t **a_out);
 int dap_chain_net_srv_stake_hardfork_data_import(dap_chain_net_id_t a_net_id, dap_hash_fast_t *a_hardfork_decree_hash);
-int dap_chain_net_srv_stake_switch_table(dap_chain_net_id_t a_net_id, bool a_to_sandbox);
\ No newline at end of file
+int dap_chain_net_srv_stake_hardfork_data_verify(dap_chain_net_t *a_net, dap_hash_fast_t *a_hardfork_decree_hash);
+int dap_chain_net_srv_stake_switch_table(dap_chain_net_id_t a_net_id, bool a_to_sandbox);
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 253c1ad2dd480d81ce43864744c4ab974ef49e69..4fdeac631f3fe15139d02c0fbbd449c2f155bf6d 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -2005,10 +2005,6 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t *a_chain,
                 log_it(L_ERROR, "Can't accept hardfork genesis block %s: error in hardfork data restoring", dap_hash_fast_to_str_static(a_atom_hash));
                 return ATOM_REJECT;
             }
-            if (dap_chain_net_srv_stake_switch_table(a_chain->net_id, false)) {  // return to main
-                log_it(L_CRITICAL, "Can't accept hardfork genesis block %s: error in switching to main table", dap_hash_fast_to_str_static(a_atom_hash));
-                return ATOM_REJECT;
-            }
         } else {
             char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
             dap_hash_fast_to_str(&PVT(l_blocks)->static_genesis_block_hash, l_hash_str, sizeof(l_hash_str));
@@ -2096,12 +2092,17 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t *a_chain,
             HASH_FIND(hh, l_blocks_pvt->hal, &l_block_hash, sizeof(l_block_hash), l_hash_found);
             if (!l_hash_found) {
                 log_it(L_WARNING, "Block %s rejected by block verificator", dap_hash_fast_to_str_static(a_atom_hash));
-                return ATOM_REJECT;
+                ret = ATOM_REJECT;
             }
         }
     } else if (ret == ATOM_MOVE_TO_THRESHOLD) {
         debug_if(s_debug_more,L_DEBUG,"%s","Can't find valid previous block in chain or forked branches.");
-        return ATOM_REJECT;
+        ret = ATOM_REJECT;
+    }
+    if (l_is_genesis && l_generation && a_chain->generation < l_generation &&
+            dap_chain_net_srv_stake_switch_table(a_chain->net_id, false)) {  // return to main
+        log_it(L_CRITICAL, "Can't accept hardfork genesis block %s: error in switching to main table", dap_hash_fast_to_str_static(a_atom_hash));
+        ret = ATOM_REJECT;
     }
     return ret;
 }
@@ -2571,7 +2572,7 @@ static size_t s_callback_add_datums(dap_chain_t *a_chain, dap_chain_datum_t **a_
         if (!l_blocks->block_new) {
             dap_chain_block_cache_t *l_bcache_last = HASH_LAST(l_blocks_pvt->blocks);
             l_blocks->block_new = dap_chain_block_new(&l_bcache_last->block_hash, &l_blocks->block_new_size);
-            l_blocks->block_new->hdr.cell_id.uint64 = a_chain->cells->id.uint64;
+            l_blocks->block_new->hdr.cell_id = a_chain->hardfork_data ? c_dap_chain_cell_id_hardfork : c_dap_chain_cell_id_null;
             l_blocks->block_new->hdr.chain_id.uint64 = l_blocks->chain->id.uint64;
         }
         l_blocks->block_new_size = dap_chain_block_datum_add(&l_blocks->block_new, l_blocks->block_new_size, l_datum, l_datum_size);
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index 265eb541dea586b41fbd5298ab28612d1ad31f0f..cc05a77946f5ab2f36d6ff9235f5c8ecba7af7b5 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -504,7 +504,8 @@ static unsigned s_chain_callback_prefetched_atoms_add(dap_chain_t *a_chain) {
     dap_chain_cs_dag_event_item_t *l_event_item, *l_tmp;
     HASH_ITER(hh, PVT(l_dag)->events_prefetched, l_event_item, l_tmp) {
         HASH_DEL(PVT(l_dag)->events_prefetched, l_event_item);
-        s_chain_callback_atom_add(a_chain, l_event_item->event, l_event_item->event_size, &l_event_item->datum_hash, false);
+        s_chain_callback_atom_add(a_chain, l_event_item->event, l_event_item->event_size, &l_event_item->hash, false);
+        DAP_DELETE(l_event_item);
         a_chain->load_progress = (int)((float)++i/q * 100 + 0.5);
     }
     return i;
@@ -547,24 +548,14 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
     }
     bool l_load_mode = dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id));
     dap_chain_cs_dag_event_item_t *l_event_item;
-    if (l_load_mode) {
-        assert( (intptr_t)a_atom_hash % alignof(dap_chain_cs_dag_event_item_t) == 0 );
-        union {
-            dap_hash_fast_t *hash;
-            dap_chain_cs_dag_event_item_t *item;
-        } l_punner = { .hash = a_atom_hash };
-        l_event_item = l_punner.item; //(dap_chain_cs_dag_event_item_t*)(a_atom_hash); // Guaranteed by C1x §6.7.2.1.13
-        l_event_item->ts_added = dap_time_now();
-    } else {
-        l_event_item = DAP_NEW(dap_chain_cs_dag_event_item_t);
-        *l_event_item = (dap_chain_cs_dag_event_item_t) {
-            .hash       = *a_atom_hash,
-            .ts_added   = dap_time_now(),
-            .event      = a_chain->is_mapped ? l_event : DAP_DUP_SIZE(l_event, a_atom_size),
-            .event_size = a_atom_size,
-            .ts_created = l_event->header.ts_created
-        };
-    }
+    l_event_item = DAP_NEW(dap_chain_cs_dag_event_item_t);
+    *l_event_item = (dap_chain_cs_dag_event_item_t) {
+        .hash       = *a_atom_hash,
+        .ts_added   = dap_time_now(),
+        .event      = a_chain->is_mapped ? l_event : DAP_DUP_SIZE(l_event, a_atom_size),
+        .event_size = a_atom_size,
+        .ts_created = l_event->header.ts_created
+    };
 
     switch (ret) {
     case ATOM_MOVE_TO_THRESHOLD: {
@@ -605,7 +596,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
             debug_if(s_debug_more, L_WARNING, "... added with ledger code %d", l_consensus_check);
             break;
         }
-
+        HASH_ADD(hh, PVT(l_dag)->events, hash, sizeof(l_event_item->hash), l_event_item);
         s_dag_events_lasts_process_new_last_event(l_dag, l_event_item);
         dap_chain_atom_notify(l_dag->chain, l_event_item->event->header.cell_id, &l_event_item->hash, (const byte_t*)l_event_item->event, l_event_item->event_size);
         dap_chain_atom_add_from_threshold(a_chain);
@@ -818,7 +809,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t *a_c
     // genesis or seed mode
     if ( !l_event->header.hash_count ) {
         if ( s_seed_mode ) /* TODO: lock with mutex too. Is this yet used?...*/
-            return PVT(l_dag)->events
+            return !PVT(l_dag)->events
                 ? log_it(L_NOTICE,"Treating event %s as genesis. Time to turn seed mode off!", dap_hash_fast_to_str_static(a_atom_hash)), ATOM_ACCEPT
                 : ( log_it(L_ERROR, "Genesis event is already present! Turn off seed mode and try again!"), ATOM_REJECT );
         if ( l_dag->is_static_genesis_event ) {
@@ -882,20 +873,12 @@ void s_dag_events_lasts_delete_linked_with_event(dap_chain_cs_dag_t * a_dag, dap
     }
 }
 
-void s_dag_events_lasts_process_new_last_event(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_item_t * a_event_item){
+void s_dag_events_lasts_process_new_last_event(dap_chain_cs_dag_t *a_dag, dap_chain_cs_dag_event_item_t *a_event_item)
+{
     //delete linked with event
     s_dag_events_lasts_delete_linked_with_event(a_dag, a_event_item->event);
-
     //add self
-    dap_chain_cs_dag_event_item_t * l_event_last= DAP_NEW_Z(dap_chain_cs_dag_event_item_t);
-    if (!l_event_last) {
-        log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-        return;
-    }
-    l_event_last->ts_added = a_event_item->ts_added;
-    l_event_last->event = a_event_item->event;
-    l_event_last->event_size = a_event_item->event_size;
-    dap_hash_fast(l_event_last->event, a_event_item->event_size,&l_event_last->hash );
+    dap_chain_cs_dag_event_item_t *l_event_last = DAP_DUP_RET_IF_FAIL(a_event_item);
     HASH_ADD(hh,PVT(a_dag)->events_lasts_unlinked,hash, sizeof(l_event_last->hash),l_event_last);
 }