diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 29bc7d426a3d387907dd373e41525644440e6298..40dd5a09aac75d5f8d27ad9e3e7d923b3f6c9803 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -147,7 +147,9 @@ void dap_chain_set_cs_type(dap_chain_t *a_chain, const char *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);
+    ret += dap_chain_cs_purge(a_chain);
+    dap_chain_cell_close_all(a_chain);
+    return ret;
 }
 
 /**
@@ -348,6 +350,15 @@ static bool s_datum_in_chain_types(uint16_t datum_type, dap_chain_type_t *chain_
 	return (false);
 }
 
+bool dap_chain_datum_type_supported_by_chain(dap_chain_t *a_chain, uint16_t a_datum_type)
+{
+    dap_return_val_if_fail(a_chain, false);
+    for (uint16_t i = 0; i < a_chain->datum_types_count; i++)
+        if (s_chain_type_convert(a_chain->datum_types[i]) == a_datum_type)
+            return true;
+    return false;
+}
+
 /**
  * @brief dap_chain_load_from_cfg
  * Loading chain from config file
@@ -706,7 +717,8 @@ void dap_chain_atom_confirmed_notify_add(dap_chain_t *a_chain, dap_chain_callbac
  */
 bool dap_chain_get_atom_last_hash_num_ts(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_atom_hash, uint64_t *a_atom_num, dap_time_t *a_atom_timestamp)
 {
-    dap_return_val_if_fail(a_atom_hash || a_atom_num, false);
+    dap_return_val_if_fail(a_chain && a_chain->callback_atom_iter_create &&
+                           a_chain->callback_atom_iter_get && a_chain->callback_atom_iter_delete, false);
     dap_chain_atom_iter_t *l_iter = a_chain->callback_atom_iter_create(a_chain, a_cell_id, NULL);
     if (!l_iter)
         return false;
diff --git a/modules/chain/dap_chain_srv.c b/modules/chain/dap_chain_srv.c
index 7d9d9ce1b34538c1521713ab9ea55b161f8abe61..625026a9967e91decf3a8b26b2e3fdffbb242adb 100644
--- a/modules/chain/dap_chain_srv.c
+++ b/modules/chain/dap_chain_srv.c
@@ -44,28 +44,28 @@ struct service_list {
 // list of active services
 static struct service_list *s_srv_list = NULL;
 // for separate access to s_srv_list
-static pthread_mutex_t s_srv_list_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_rwlock_t s_srv_list_lock = PTHREAD_RWLOCK_INITIALIZER;
 
 void dap_chain_srv_deinit()
 {
     struct service_list *it, *tmp;
-    pthread_mutex_lock(&s_srv_list_mutex);
+    int err = pthread_rwlock_wrlock(&s_srv_list_lock);
+    assert(!err);
     HASH_ITER(hh, s_srv_list, it, tmp) {
         // Clang bug at this, l_service_item should change at every loop cycle
         HASH_DEL(s_srv_list, it);
         dap_list_t *itl, *tmpl;
         DL_FOREACH_SAFE(it->networks, itl, tmpl) {
             struct network_service *l_service = itl->data;
-            if (it->callbacks.delete)
-                it->callbacks.delete(l_service->service);
-            else
-                DAP_DEL_Z(l_service->service);
+            if (it->callbacks.purge)
+                it->callbacks.purge(l_service->net_id, l_service->service);
+            DAP_DEL_Z(l_service->service);
             DAP_DELETE(l_service);
             DAP_DELETE(itl);
         }
         DAP_DELETE(it);
     }
-    pthread_mutex_unlock(&s_srv_list_mutex);
+    pthread_rwlock_unlock(&s_srv_list_lock);
 }
 
 
@@ -73,17 +73,18 @@ int dap_chain_srv_add(dap_chain_srv_uid_t a_uid, const char *a_name, dap_chain_s
 {
     struct service_list *l_service_item = NULL;
 
-    pthread_mutex_lock(&s_srv_list_mutex);
+    int err = pthread_rwlock_wrlock(&s_srv_list_lock);
+    assert(!err);
     HASH_FIND(hh, s_srv_list, &a_uid, sizeof(a_uid), l_service_item);
     if (l_service_item) {
         log_it(L_ERROR, "Already present service with 0x%016"DAP_UINT64_FORMAT_X, a_uid.uint64);
-        pthread_mutex_unlock(&s_srv_list_mutex);
+        pthread_rwlock_unlock(&s_srv_list_lock);
         return -1;
     }
     l_service_item = DAP_NEW_Z(struct service_list);
     if (!l_service_item) {
         log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-        pthread_mutex_unlock(&s_srv_list_mutex);
+        pthread_rwlock_unlock(&s_srv_list_lock);
         return -2;
     }
     l_service_item->uuid = a_uid;
@@ -92,7 +93,7 @@ int dap_chain_srv_add(dap_chain_srv_uid_t a_uid, const char *a_name, dap_chain_s
     if (a_static_callbacks)
         l_service_item->callbacks = *a_static_callbacks;
     HASH_ADD(hh, s_srv_list, uuid, sizeof(a_uid), l_service_item);
-    pthread_mutex_unlock(&s_srv_list_mutex);
+    pthread_rwlock_unlock(&s_srv_list_lock);
     return 0;
 }
 
@@ -109,23 +110,25 @@ static struct network_service *s_net_service_find(struct service_list *a_service
 static struct service_list *s_service_find(dap_chain_srv_uid_t a_srv_uid)
 {
     struct service_list *l_service_item = NULL;
-    pthread_mutex_lock(&s_srv_list_mutex);
+    int err = pthread_rwlock_rdlock(&s_srv_list_lock);
+    assert(!err);
     HASH_FIND(hh, s_srv_list, &a_srv_uid, sizeof(dap_chain_srv_uid_t), l_service_item);
-    pthread_mutex_unlock(&s_srv_list_mutex);
+    pthread_rwlock_unlock(&s_srv_list_lock);
     return l_service_item;
 }
 
 static struct service_list *s_find_by_name(const char *a_name)
 {
     dap_return_val_if_fail(a_name, NULL);
-    pthread_mutex_lock(&s_srv_list_mutex);
+    int err = pthread_rwlock_rdlock(&s_srv_list_lock);
+    assert(!err);
     for (struct service_list *it = s_srv_list; it; it = it->hh.next) {
         if (!dap_strcmp(it->name, a_name)) {
-            pthread_mutex_unlock(&s_srv_list_mutex);
+            pthread_rwlock_unlock(&s_srv_list_lock);
             return it;
         }
     }
-    pthread_mutex_unlock(&s_srv_list_mutex);
+    pthread_rwlock_unlock(&s_srv_list_lock);
     return NULL;
 }
 
@@ -146,21 +149,21 @@ int dap_chain_srv_start(dap_chain_net_id_t a_net_id, const char *a_name, dap_con
 int dap_chain_srv_delete(dap_chain_srv_uid_t a_srv_uid)
 {
     struct service_list *l_service_item = NULL;
-    pthread_mutex_lock(&s_srv_list_mutex);
+    int err = pthread_rwlock_wrlock(&s_srv_list_lock);
+    assert(!err);
     HASH_FIND(hh, s_srv_list, &a_srv_uid, sizeof(a_srv_uid), l_service_item);
     if (!l_service_item) {
-        pthread_mutex_unlock(&s_srv_list_mutex);
+        pthread_rwlock_unlock(&s_srv_list_lock);
         return -1;
     }
     HASH_DEL(s_srv_list, l_service_item);
-    pthread_mutex_unlock(&s_srv_list_mutex);
+    pthread_rwlock_unlock(&s_srv_list_lock);
     dap_list_t *it, *tmp;
     DL_FOREACH_SAFE(l_service_item->networks, it, tmp) {
         struct network_service *l_service = it->data;
-        if (l_service_item->callbacks.delete)
-            l_service_item->callbacks.delete(l_service->service);
-        else
-            DAP_DEL_Z(l_service->service);
+        if (l_service_item->callbacks.purge)
+            l_service_item->callbacks.purge(l_service->net_id, l_service->service);
+        DAP_DEL_Z(l_service->service);
         DAP_DELETE(l_service);
         DAP_DELETE(it);
     }
@@ -171,9 +174,9 @@ int dap_chain_srv_delete(dap_chain_srv_uid_t a_srv_uid)
 int dap_chain_srv_purge(dap_chain_net_id_t a_net_id, dap_chain_srv_uid_t a_srv_uid)
 {
     struct service_list *l_service_item = s_service_find(a_srv_uid);
-    if (l_service_item && s_net_service_find(l_service_item, a_net_id) &&
-            l_service_item->callbacks.purge)
-        return l_service_item->callbacks.purge(a_net_id);
+    struct network_service *l_service = s_net_service_find(l_service_item, a_net_id);
+    if (l_service_item && l_service_item->callbacks.purge && l_service)
+        return l_service_item->callbacks.purge(l_service->net_id, l_service->service);
     return 0;
 }
 
@@ -184,12 +187,17 @@ int dap_chain_srv_purge(dap_chain_net_id_t a_net_id, dap_chain_srv_uid_t a_srv_u
 int dap_chain_srv_purge_all(dap_chain_net_id_t a_net_id)
 {
     int ret = 0;
-    pthread_mutex_lock(&s_srv_list_mutex);
-    for (struct service_list *it = s_srv_list; it; it = it->hh.next) {
-        if (s_net_service_find(it, a_net_id) && it->callbacks.purge)
-            ret += it->callbacks.purge(a_net_id);
+    int err = pthread_rwlock_rdlock(&s_srv_list_lock);
+    assert(!err);
+    for (struct service_list *it = s_srv_list; it; it = it->hh.next) {      
+        if (!it->callbacks.purge)
+            continue;
+        struct network_service *l_service = s_net_service_find(it, a_net_id);
+        if (!l_service)
+            continue;
+        ret += it->callbacks.purge(l_service->net_id, l_service->service);
     }
-    pthread_mutex_unlock(&s_srv_list_mutex);
+    pthread_rwlock_unlock(&s_srv_list_lock);
     return ret;
 }
 
@@ -200,19 +208,26 @@ int dap_chain_srv_purge_all(dap_chain_net_id_t a_net_id)
 dap_chain_srv_hardfork_state_t *dap_chain_srv_hardfork_all(dap_chain_net_id_t a_net_id)
 {
     dap_chain_srv_hardfork_state_t *ret = NULL;
-    pthread_mutex_lock(&s_srv_list_mutex);
+    int err = pthread_rwlock_rdlock(&s_srv_list_lock);
+    assert(!err);
     for (struct service_list *it = s_srv_list; it; it = it->hh.next) {
-        if (s_net_service_find(it, a_net_id) && it->callbacks.hardfork_prepare) {
-            dap_chain_srv_hardfork_state_t *l_state = DAP_NEW_Z(dap_chain_srv_hardfork_state_t), *cur, *tmp;
-            if (!l_state)
-                DL_FOREACH_SAFE(ret, cur, tmp)
-                    DAP_DELETE(cur);
-            l_state->uid = it->uuid;
-            l_state->data = it->callbacks.hardfork_prepare(a_net_id, &l_state->size, &l_state->count);
-            DL_APPEND(ret, l_state);
+        if (!it->callbacks.hardfork_prepare)
+            continue;
+        struct network_service *l_service = s_net_service_find(it, a_net_id);
+        if (!l_service)
+            continue;
+        dap_chain_srv_hardfork_state_t *l_state = DAP_NEW_Z(dap_chain_srv_hardfork_state_t), *cur, *tmp;
+        if (!l_state) {
+            log_it(L_CRITICAL, "%s", c_error_memory_alloc);
+            DL_FOREACH_SAFE(ret, cur, tmp)
+                DAP_DELETE(cur);
+            break;
         }
+        l_state->uid = it->uuid;
+        l_state->data = it->callbacks.hardfork_prepare(a_net_id, &l_state->size, &l_state->count, l_service->service);
+        DL_APPEND(ret, l_state);
     }
-    pthread_mutex_unlock(&s_srv_list_mutex);
+    pthread_rwlock_unlock(&s_srv_list_lock);
     return ret;
 }
 
@@ -231,12 +246,13 @@ int dap_chain_srv_load_state(dap_chain_net_id_t a_net_id, dap_chain_srv_uid_t a_
 json_object *dap_chain_srv_get_fees(dap_chain_net_id_t a_net_id)
 {
     json_object *ret = json_object_new_array();
-    pthread_mutex_lock(&s_srv_list_mutex);
+    int err = pthread_rwlock_rdlock(&s_srv_list_lock);
+    assert(!err);
     for (struct service_list *it = s_srv_list; it; it = it->hh.next) {
         if (s_net_service_find(it, a_net_id) && it->callbacks.get_fee_descr)
             json_object_array_add(ret, it->callbacks.get_fee_descr(a_net_id));
     }
-    pthread_mutex_unlock(&s_srv_list_mutex);
+    pthread_rwlock_unlock(&s_srv_list_lock);
     return ret;
 }
 
@@ -289,11 +305,12 @@ dap_chain_srv_uid_t dap_chain_srv_get_uid_by_name(const char *a_name)
 size_t dap_chain_srv_count(dap_chain_net_id_t a_net_id)
 {
     size_t l_count = 0;
-    pthread_mutex_lock(&s_srv_list_mutex);
+    int err = pthread_rwlock_rdlock(&s_srv_list_lock);
+    assert(!err);
     for (struct service_list *it = s_srv_list; it; it = it->hh.next)
         if (s_net_service_find(it, a_net_id))
             l_count++;
-    pthread_mutex_unlock(&s_srv_list_mutex);
+    pthread_rwlock_unlock(&s_srv_list_lock);
     return l_count;
 }
 
@@ -304,11 +321,12 @@ size_t dap_chain_srv_count(dap_chain_net_id_t a_net_id)
 dap_list_t *dap_chain_srv_list(dap_chain_net_id_t a_net_id)
 {
     dap_list_t *l_list = NULL;
-    pthread_mutex_lock(&s_srv_list_mutex);
+    int err = pthread_rwlock_rdlock(&s_srv_list_lock);
+    assert(!err);
     // Iterate services and save them to list
     for (struct service_list *it = s_srv_list; it; it = it->hh.next)
         if (s_net_service_find(it, a_net_id))
             l_list = dap_list_append(l_list, DAP_DUP(&it->uuid));
-    pthread_mutex_unlock(&s_srv_list_mutex);
+    pthread_rwlock_unlock(&s_srv_list_lock);
     return l_list;
 }
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index 0fd5a0b9c519b62a97472ec951c8200263fdb6e4..5dcc3ad3605e902175795ed04595da20cdbc0be0 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -33,7 +33,7 @@
 #ifdef DAP_TPS_TEST
 #define DAP_CHAIN_ATOM_MAX_SIZE (100 * 1024 * 1024)
 #else
-#define DAP_CHAIN_ATOM_MAX_SIZE (8 * 1024 * 1024) // 8 MB
+#define DAP_CHAIN_ATOM_MAX_SIZE (10 * 1024 * 1024) // 10 MB
 #endif
 
 typedef struct dap_chain dap_chain_t;
@@ -330,3 +330,4 @@ int dap_cert_chain_file_save(dap_chain_datum_t *datum, char *net_name);
 const char *dap_chain_type_to_str(dap_chain_type_t a_chain_type);
 const char *dap_chain_get_path(dap_chain_t *a_chain);
 const char *dap_chain_get_cs_type(dap_chain_t *l_chain);
+bool dap_chain_datum_type_supported_by_chain(dap_chain_t *a_chain, uint16_t a_datum_type);
diff --git a/modules/chain/include/dap_chain_cell.h b/modules/chain/include/dap_chain_cell.h
index 93df11693216782639678f536674814efbea8bd2..658a8b90e2ddcd1e4d755218317b5582ec153f2a 100644
--- a/modules/chain/include/dap_chain_cell.h
+++ b/modules/chain/include/dap_chain_cell.h
@@ -78,6 +78,9 @@ typedef struct dap_chain_cell_decl{
 int dap_chain_cell_init(void);
 int dap_chain_cell_open(dap_chain_t *a_chain, const char *a_filename, const char a_mode);
 int dap_chain_cell_open_by_id(dap_chain_t *a_chain, const dap_chain_cell_id_t a_cell_id, const char a_mode);
+DAP_STATIC_INLINE int dap_chain_cell_create(dap_chain_t *a_chain, const dap_chain_cell_id_t a_cell_id) {
+    return dap_chain_cell_open_by_id(a_chain, a_cell_id, 'w');
+}
 
 DAP_INLINE dap_chain_cell_t *dap_chain_cell_find_by_id(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id) {
     dap_chain_cell_t *l_cell = NULL;
diff --git a/modules/chain/include/dap_chain_srv.h b/modules/chain/include/dap_chain_srv.h
index beff7340011130ff7347372d5ab6f9a9008d0998..d016e93204cf6559829423dbd45bf196cb34bdc3 100644
--- a/modules/chain/include/dap_chain_srv.h
+++ b/modules/chain/include/dap_chain_srv.h
@@ -38,15 +38,13 @@ typedef void * (*dap_chain_srv_callback_start_t)(dap_chain_net_id_t a_net_id, da
 // Process service decree
 typedef void (*dap_chain_srv_callback_decree_t)(dap_chain_net_id_t a_net_id, int a_decree_type, dap_tsd_t *a_params, size_t a_params_size);
 // Purge service callback
-typedef int (*dap_chain_srv_callback_purge_t)(dap_chain_net_id_t a_net_id);
+typedef int (*dap_chain_srv_callback_purge_t)(dap_chain_net_id_t a_net_id, void *a_service_internal);
 // Get fee service callback
 typedef json_object * (*dap_chain_srv_callback_get_fee)(dap_chain_net_id_t a_net_id);
 // Hardfork prepare service callback
-typedef byte_t * (*dap_chain_srv_callback_hardfork_prepare_t)(dap_chain_net_id_t a_net_id, uint64_t *a_state_size, uint32_t *a_state_count);
+typedef byte_t * (*dap_chain_srv_callback_hardfork_prepare_t)(dap_chain_net_id_t a_net_id, uint64_t *a_state_size, uint32_t *a_state_count, void *a_service_internal);
 // Hardfork data load service callback
 typedef int (*dap_chain_srv_callback_hardfork_data_t)(dap_chain_net_id_t a_net_id, byte_t *a_state, uint64_t a_state_size, uint32_t a_state_count);
-// Delete service callback
-typedef void (*dap_chain_srv_callback_delete_t)(void *);
 
 typedef struct dap_chain_static_srv_callbacks {
     // Init
@@ -61,8 +59,6 @@ typedef struct dap_chain_static_srv_callbacks {
     dap_chain_srv_callback_hardfork_prepare_t hardfork_prepare;
     // Hardfork data load
     dap_chain_srv_callback_hardfork_data_t hardfork_load;
-    // Delete for internal service clean exit
-    dap_chain_srv_callback_delete_t delete;
     // And no more =)
 } dap_chain_static_srv_callbacks_t;
 
diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index c7f2dcfab8c58e966f20c2352c79929d8913642d..a5096b6d21f76733413db2eb78d86bbeee8f9862 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -741,12 +741,21 @@ 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)
+bool dap_chain_esbocs_hardfork_engaged(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);
+    return l_esbocs->hardfork_generation;
+}
+
+int dap_chain_esbocs_set_hardfork_prepare(dap_chain_t *a_chain, uint16_t l_generation, 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);
+    if (l_generation)
+        l_esbocs->hardfork_generation = l_generation;
     if (a_trusted_addrs)
         l_esbocs->hardfork_trusted_addrs = a_trusted_addrs;
     if (a_changed_addrs)
@@ -763,9 +772,10 @@ int dap_chain_esbocs_set_hardfork_complete(dap_chain_t *a_chain)
     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->hardfork_generation = l_esbocs->hardfork_from = 0;
     l_esbocs->session->is_hardfork = false;
     l_net->pub.ledger->is_hardfork_state = false;
+    dap_chain_net_srv_stake_hardfork_tx_update(l_net);
     return 0;
 }
 
@@ -886,7 +896,7 @@ static dap_list_t *s_get_validators_list(dap_chain_esbocs_t *a_esbocs, dap_hash_
     dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(a_esbocs);
     dap_list_t *l_ret = NULL;
     dap_list_t *l_validators = NULL;
-    if (l_esbocs_pvt->poa_mode) { // UNDO after debug
+    if (!l_esbocs_pvt->poa_mode) {
         if (a_excluded_list_size) {
             l_validators =  dap_chain_net_srv_stake_get_validators(a_esbocs->chain->net_id, false, NULL);
             uint16_t l_excluded_num = *a_excluded_list;
@@ -1059,7 +1069,11 @@ static void s_session_send_startsync(void *a_arg)
     if (a_session->cur_round.sync_sent)
         return;     // Sync message already was sent
     dap_chain_hash_fast_t l_last_block_hash;
-    dap_chain_get_atom_last_hash(a_session->chain, c_dap_chain_cell_id_null, &l_last_block_hash);
+    dap_chain_get_atom_last_hash(a_session->chain,          // Actually not working. TODO implement cells in type storage
+                                 a_session->is_hardfork ? c_dap_chain_cell_id_hardfork : c_dap_chain_cell_id_null,
+                                 &l_last_block_hash);
+    if (dap_hash_fast_is_blank(&a_session->cur_round.last_block_hash))
+        memset(&l_last_block_hash, 0, sizeof(dap_hash_fast_t)); // Workaround for unimpemented storage cell_id request
     a_session->ts_round_sync_start = dap_time_now();
     if (!dap_hash_fast_compare(&l_last_block_hash, &a_session->cur_round.last_block_hash))
         return;     // My last block hash has changed, skip sync message
@@ -1236,7 +1250,8 @@ static bool s_session_round_new(void *a_arg)
             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;
-            }
+            } else
+                a_session->cur_round.last_block_hash = (dap_hash_fast_t) { };
         }
     }
     return false;
@@ -1366,7 +1381,7 @@ static bool s_session_directive_ready(dap_chain_esbocs_session_t *a_session, boo
     if (l_ready) {
         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",
+            log_it(L_INFO, "Not enough validators online to issue 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
         }
@@ -1713,13 +1728,13 @@ static void s_session_candidate_submit(dap_chain_esbocs_session_t *a_session)
                 l_candidate_size = dap_chain_block_meta_add(&l_candidate, l_candidate_size, DAP_CHAIN_BLOCK_META_EXCLUDED_KEYS,
                                                             a_session->cur_round.excluded_list, (*a_session->cur_round.excluded_list + 1) * sizeof(uint16_t));
         }
-        if (a_session->is_hardfork) {
+        if (a_session->is_hardfork && l_candidate_size) {
             if (dap_chain_block_meta_get(l_candidate, l_candidate_size, DAP_CHAIN_BLOCK_META_GENESIS) && l_candidate_size)
                 l_candidate_size = dap_chain_block_meta_add(&l_candidate, l_candidate_size, DAP_CHAIN_BLOCK_META_LINK,
                                                         &l_chain->hardfork_decree_hash, sizeof(l_chain->hardfork_decree_hash));
             if (l_candidate_size)
                 l_candidate_size = dap_chain_block_meta_add(&l_candidate, l_candidate_size, DAP_CHAIN_BLOCK_META_GENERATION,
-                                                            &l_chain->generation, sizeof(uint16_t));
+                                                            &a_session->esbocs->hardfork_generation, sizeof(uint16_t));
         }
         if (l_candidate_size) {
             dap_hash_fast(l_candidate, l_candidate_size, &l_candidate_hash);
@@ -2911,21 +2926,7 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_bl
             return -3;
         }
         if (l_esbocs->session->is_hardfork) {
-            uint8_t *l_generation = dap_chain_block_meta_get(a_block, a_block_size, DAP_CHAIN_BLOCK_META_GENERATION);
-            if (!l_generation || *(uint16_t *)l_generation != a_blocks->chain->generation) {
-                log_it(L_WARNING, "Can't process hardfork block %s with incorrect generation meta", dap_hash_fast_to_str_static(a_block_hash));
-                return -302;
-            }
-            // Addtionally verify datums vs internal states
-            size_t l_datums_count = 0;
-            dap_chain_datum_t **l_datums = dap_chain_block_get_datums(a_block, a_block_size, &l_datums_count);
-            for (size_t i = 0; i < l_datums_count; i++) {
-                int ret = dap_chain_node_hardfork_check(a_blocks->chain, l_datums[i]);
-                if (ret) {
-                    log_it(L_WARNING, "Can't process hardfork block %s with datums verification error", dap_hash_fast_to_str_static(a_block_hash));
-                    return ret;
-                }
-            }
+            uint16_t l_genesis_corr = 0;
             // compare hardfork decree hashes
             if (dap_chain_block_meta_get(a_block, a_block_size, DAP_CHAIN_BLOCK_META_GENESIS)) {
                 dap_hash_fast_t *l_hardfork_decree_hash = (dap_hash_fast_t *)dap_chain_block_meta_get(a_block, a_block_size, DAP_CHAIN_BLOCK_META_LINK);
@@ -2939,6 +2940,22 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_bl
                     DAP_DELETE(l_candidate_hash_str);
                     return -301;
                 }
+                l_genesis_corr = 1;
+            }
+            uint8_t *l_generation = dap_chain_block_meta_get(a_block, a_block_size, DAP_CHAIN_BLOCK_META_GENERATION);
+            if (!l_generation || *(uint16_t *)l_generation != a_blocks->chain->generation + l_genesis_corr) {
+                log_it(L_WARNING, "Can't process hardfork block %s with incorrect generation meta", dap_hash_fast_to_str_static(a_block_hash));
+                return -302;
+            }
+            // Addtionally verify datums vs internal states
+            size_t l_datums_count = 0;
+            dap_chain_datum_t **l_datums = dap_chain_block_get_datums(a_block, a_block_size, &l_datums_count);
+            for (size_t i = 0; i < l_datums_count; i++) {
+                int ret = dap_chain_node_hardfork_check(a_blocks->chain, l_datums[i]);
+                if (ret) {
+                    log_it(L_WARNING, "Can't process hardfork block %s with datums verification error", dap_hash_fast_to_str_static(a_block_hash));
+                    return ret;
+                }
             }
         } else if (dap_chain_block_meta_get(a_block, a_block_size, DAP_CHAIN_BLOCK_META_GENERATION)) {
             log_it(L_WARNING, "Can't process non-hardfork block %s with generation meta", dap_hash_fast_to_str_static(a_block_hash));
diff --git a/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h b/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h
index a2dd6e2c70a53b4257f6ffa17e64030be4a05197..522046373b40c1eff9236df995aa4b34785f1efa 100644
--- a/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h
+++ b/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h
@@ -123,6 +123,7 @@ typedef struct dap_chain_esbocs {
     dap_chain_t *chain;
     dap_chain_cs_blocks_t *blocks;
     dap_chain_esbocs_session_t *session;
+    uint16_t hardfork_generation;
     uint64_t hardfork_from;
     json_object *hardfork_changed_addrs;
     dap_list_t *hardfork_trusted_addrs;
@@ -269,6 +270,7 @@ int dap_chain_esbocs_set_min_validators_count(dap_chain_t *a_chain, uint16_t a_n
 uint16_t dap_chain_esbocs_get_min_validators_count(dap_chain_net_id_t a_net_id);
 int dap_chain_esbocs_set_emergency_validator(dap_chain_t *a_chain, bool a_add, uint32_t a_sign_type, dap_hash_fast_t *a_validator_hash);
 int dap_chain_esbocs_set_signs_struct_check(dap_chain_t *a_chain, bool a_enable);
-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, uint16_t l_generation, uint64_t a_block_num, dap_list_t *a_trusted_addrs, json_object* a_changed_addrs);
 int dap_chain_esbocs_set_hardfork_complete(dap_chain_t *a_chain);
+bool dap_chain_esbocs_hardfork_engaged(dap_chain_t *a_chain);
 void dap_chain_esbocs_change_debug_mode(dap_chain_t *a_chain, bool a_enable);
diff --git a/modules/datum/include/dap_chain_datum_decree.h b/modules/datum/include/dap_chain_datum_decree.h
index 6a00498094c074fb67a9dbbc390ae4748d39c632..c61b645c9b31457a5d3239261788144f6e171b29 100644
--- a/modules/datum/include/dap_chain_datum_decree.h
+++ b/modules/datum/include/dap_chain_datum_decree.h
@@ -80,7 +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
+#define DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK_RETRY                0x0013
 
 // DECREE TSD types
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_VALUE                               0x0100
diff --git a/modules/ledger/dap_chain_ledger_anchor.c b/modules/ledger/dap_chain_ledger_anchor.c
index e7fb5078f3919179abe09ce789c0a908fe4dc61b..56e073d0b4007e8546cb3402cbe6df8bc3ab4bcb 100644
--- a/modules/ledger/dap_chain_ledger_anchor.c
+++ b/modules/ledger/dap_chain_ledger_anchor.c
@@ -171,13 +171,59 @@ int dap_ledger_anchor_load(dap_chain_datum_anchor_t *a_anchor, dap_chain_t *a_ch
             return -1;
         }
         l_new_anchor->anchor_hash = *a_anchor_hash;
-        l_new_anchor->anchor = a_anchor;
+        dap_chain_datum_anchor_t *l_anchor = a_anchor;
+        if (!a_chain->is_mapped) {
+            l_anchor = DAP_DUP_SIZE(a_anchor, dap_chain_datum_anchor_get_size(a_anchor));
+            if (!l_anchor) {
+                log_it(L_CRITICAL, "Memory allocation error");
+                pthread_rwlock_unlock(&l_ledger_pvt->decrees_rwlock);
+                return -1;
+            }
+        }
+        l_new_anchor->anchor = l_anchor;
+        l_new_anchor->storage_chain_id = a_chain->id;
         HASH_ADD_BYHASHVALUE(hh, l_ledger_pvt->anchors, anchor_hash, sizeof(dap_hash_fast_t), l_hash_value, l_new_anchor);
     }
     pthread_rwlock_unlock(&l_ledger_pvt->decrees_rwlock);
     return ret_val;
 }
 
+int dap_ledger_anchor_purge(dap_ledger_t *a_ledger, dap_chain_id_t a_chain_id)
+{
+    dap_return_val_if_fail(a_ledger, -1);
+    dap_chain_t *l_chain = dap_chain_find_by_id(a_ledger->net->pub.id, a_chain_id);
+    if (!l_chain) {
+        log_it(L_ERROR, "Can't find chain 0x016%" DAP_UINT64_FORMAT_x "in net %s", a_chain_id.uint64, a_ledger->net->pub.name);
+        return -2;
+    }
+    if (!dap_chain_datum_type_supported_by_chain(l_chain, DAP_CHAIN_DATUM_ANCHOR))
+        return 0;
+    dap_ledger_anchor_item_t *it = NULL, *tmp;
+    dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
+    pthread_rwlock_wrlock(&l_ledger_pvt->decrees_rwlock);
+    HASH_ITER(hh, l_ledger_pvt->anchors, it, tmp) {
+        if (it->storage_chain_id.uint64 != a_chain_id.uint64)
+            continue;
+        HASH_DEL(l_ledger_pvt->anchors, it);
+        dap_hash_fast_t l_decree_hash;
+        if (!dap_chain_datum_anchor_get_hash_from_data(it->anchor, &l_decree_hash)) {
+            dap_ledger_decree_item_t *l_decree = NULL;
+            HASH_FIND(hh, l_ledger_pvt->decrees, &l_decree_hash, sizeof(dap_hash_fast_t), l_decree);
+            if (l_decree) {
+                l_decree->is_applied = l_decree->wait_for_apply = false;
+                l_decree->anchor_hash = (dap_hash_fast_t) { };
+            } else
+                log_it(L_ERROR, "Corrupted datum anchor, can't get decree by hash %s", dap_hash_fast_to_str_static(&l_decree_hash));
+        } else
+            log_it(L_ERROR, "Corrupted datum anchor %s, can't get decree hash from it", dap_hash_fast_to_str_static(&it->anchor_hash));
+        if (!l_chain->is_mapped)
+            DAP_DELETE(it->anchor);
+        DAP_DELETE(it);
+    }
+    pthread_rwlock_unlock(&l_ledger_pvt->decrees_rwlock);
+    return 0;
+}
+
 static dap_ledger_anchor_item_t *s_find_anchor(dap_ledger_t *a_ledger, dap_hash_fast_t *a_anchor_hash)
 {
     dap_ledger_anchor_item_t *l_anchor = NULL;
diff --git a/modules/ledger/dap_chain_ledger_decree.c b/modules/ledger/dap_chain_ledger_decree.c
index 1e692d3beb198cdc5d79a1df4776317133563a73..cb6aa5de91129dfe836206544e01d71c177e6bbf 100644
--- a/modules/ledger/dap_chain_ledger_decree.c
+++ b/modules/ledger/dap_chain_ledger_decree.c
@@ -53,15 +53,18 @@ void dap_ledger_decree_init(dap_ledger_t *a_ledger) {
         log_it(L_WARNING, "PoA certificates for net %s not found", a_ledger->net->pub.name);
 }
 
-static int s_decree_clear(dap_ledger_t *a_ledger)
+static int s_decree_clear(dap_ledger_t *a_ledger, dap_chain_id_t a_chain_id)
 {
     dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
-    dap_list_free_full(l_ledger_pvt->decree_owners_pkeys, NULL);
     dap_ledger_decree_item_t *l_cur_decree, *l_tmp;
     pthread_rwlock_wrlock(&l_ledger_pvt->decrees_rwlock);
     HASH_ITER(hh, l_ledger_pvt->decrees, l_cur_decree, l_tmp) {
+        if (l_cur_decree->storage_chain_id.uint64 != a_chain_id.uint64)
+            continue;
         HASH_DEL(l_ledger_pvt->decrees, l_cur_decree);
-        if ( l_cur_decree->decree && !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 )
+        if ( l_cur_decree->decree &&
+             !dap_chain_find_by_id(l_cur_decree->decree->header.common_decree_params.net_id,
+                                   l_cur_decree->storage_chain_id)->is_mapped )
             DAP_DELETE(l_cur_decree->decree);
         DAP_DELETE(l_cur_decree);
     }
@@ -69,10 +72,18 @@ static int s_decree_clear(dap_ledger_t *a_ledger)
     return 0;
 }
 
-void dap_ledger_decree_purge(dap_ledger_t *a_ledger)
+int dap_ledger_decree_purge(dap_ledger_t *a_ledger)
 {
-    s_decree_clear(a_ledger);
-    //dap_ledger_decree_create(a_ledger);
+    dap_return_val_if_fail(a_ledger, -1);
+    int ret = 0;
+    for (dap_chain_t *l_chain = a_ledger->net->pub.chains; l_chain; l_chain = l_chain->next) {
+        if (dap_chain_datum_type_supported_by_chain(l_chain, DAP_CHAIN_DATUM_DECREE)) {
+            ret += s_decree_clear(a_ledger, l_chain->id);
+            dap_list_free_full(PVT(a_ledger)->decree_owners_pkeys, NULL);
+        } else
+            ret += dap_ledger_anchor_purge(a_ledger, l_chain->id);
+    }
+    return ret;
 }
 
 static int s_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, bool a_anchored)
@@ -205,6 +216,7 @@ int dap_ledger_decree_apply(dap_hash_fast_t *a_decree_hash, dap_chain_datum_decr
             return -1;
         }
         l_new_decree->decree_hash = *a_decree_hash;
+        l_new_decree->storage_chain_id = a_chain->id;
         HASH_ADD_BYHASHVALUE(hh, l_ledger_pvt->decrees, decree_hash, sizeof(dap_hash_fast_t), l_hash_value, l_new_decree);
     }
     pthread_rwlock_unlock(&l_ledger_pvt->decrees_rwlock);
@@ -608,15 +620,17 @@ const char *l_ban_addr;
             }
             if (!a_apply)
                 break;
-            if (*(uint16_t *)l_generation->data < l_chain->generation)
+            uint16_t l_hardfork_generation = *(uint16_t *)l_generation->data;
+            if (l_hardfork_generation <= 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);
-            return dap_chain_esbocs_set_hardfork_prepare(l_chain, l_block_num, l_addrs, json_tokener_parse((char *)l_changed_addrs->data));
+            json_object *l_changed_addrs_json = l_changed_addrs ? json_tokener_parse((char *)l_changed_addrs->data) : NULL;
+            return dap_chain_esbocs_set_hardfork_prepare(l_chain, l_hardfork_generation, l_block_num, l_addrs, l_changed_addrs_json);
         }
-        case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK_VALIDATORS: {
+        case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK_RETRY: {
             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");
@@ -626,17 +640,12 @@ 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)
+            if (!dap_chain_esbocs_hardfork_engaged(l_chain))
                 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);
+            return dap_chain_esbocs_set_hardfork_prepare(l_chain, 0, 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);
@@ -763,12 +772,13 @@ int s_aggregate_anchor(dap_ledger_t *a_ledger, dap_ledger_hardfork_anchors_t **a
             log_it(L_CRITICAL, "%s", c_error_memory_alloc);
             return -1;
         }
-        if (a_subtype != DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE && a_subtype != DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_UNBAN)
+        if (a_subtype != DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE &&      // Do not aagregate stake anchors, it will be transferred with
+                a_subtype != DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_APPROVE &&     // hardfork decree data linked to genesis block
+                a_subtype != DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_UNBAN)
             DL_APPEND(*a_out_list, l_exist);
     } else {
-        if (l_exist->decree_subtype == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_APPROVE ||
-                l_exist->decree_subtype == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_BAN) {
-            assert(a_subtype == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE || a_subtype == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_UNBAN);
+        if (l_exist->decree_subtype == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_BAN) {
+            assert(a_subtype == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_UNBAN);
             DL_DELETE(*a_out_list, l_exist);
         } else
             l_exist->anchor = a_anchor;
@@ -776,13 +786,15 @@ int s_aggregate_anchor(dap_ledger_t *a_ledger, dap_ledger_hardfork_anchors_t **a
     return 0;
 }
 
-dap_ledger_hardfork_anchors_t *dap_ledger_anchors_aggregate(dap_ledger_t *a_ledger)
+dap_ledger_hardfork_anchors_t *dap_ledger_anchors_aggregate(dap_ledger_t *a_ledger, dap_chain_id_t a_chain_id)
 {
     dap_ledger_hardfork_anchors_t *ret = NULL;
     dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
     pthread_rwlock_rdlock(&l_ledger_pvt->decrees_rwlock);
     for (dap_ledger_decree_item_t *it = l_ledger_pvt->decrees; it; it = it->hh.next)
-        if (it->is_applied && !dap_hash_fast_is_blank(&it->anchor_hash)) {
+        if (it->is_applied &&
+                it->decree->header.common_decree_params.chain_id.uint64 == a_chain_id.uint64 &&
+                !dap_hash_fast_is_blank(&it->anchor_hash)) {
             dap_chain_datum_anchor_t *l_anchor = dap_ledger_anchor_find(a_ledger, &it->anchor_hash);
             if (!l_anchor) {
                 char l_anchor_hash_str[DAP_HASH_FAST_STR_SIZE];
diff --git a/modules/ledger/dap_chain_ledger_tx.c b/modules/ledger/dap_chain_ledger_tx.c
index 461f3dd75a6e3738658cae54cc1febba9f9ea8a3..1706654159538b4bff783a149c5bc6959613992c 100644
--- a/modules/ledger/dap_chain_ledger_tx.c
+++ b/modules/ledger/dap_chain_ledger_tx.c
@@ -277,7 +277,7 @@ static int s_tx_cache_check(dap_ledger_t *a_ledger,
     int l_prev_tx_count = 0;
 
     // 1. Verify signature in current transaction
-    if (!a_from_threshold && dap_chain_datum_tx_verify_sign(a_tx, 0))
+    if (!a_from_threshold && !a_ledger->is_hardfork_state && dap_chain_datum_tx_verify_sign(a_tx, 0))
         return DAP_LEDGER_CHECK_NOT_ENOUGH_VALID_SIGNS;
 
     // ----------------------------------------------------------------
@@ -2515,7 +2515,8 @@ static int s_aggregate_out_cond(dap_ledger_hardfork_condouts_t **a_ret_list, dap
         log_it(L_CRITICAL, "%s", c_error_memory_alloc);
         return -1;
     }
-    *l_new_condout = (dap_ledger_hardfork_condouts_t) { .hash = *a_tx_hash, .cond = a_out_cond, .sign = a_sign, .ticker = a_token_ticker };
+    *l_new_condout = (dap_ledger_hardfork_condouts_t) { .hash = *a_tx_hash, .cond = a_out_cond, .sign = a_sign };
+    dap_strncpy(l_new_condout->ticker, a_token_ticker, DAP_CHAIN_TICKER_SIZE_MAX);
     l_new_condout->trackers = s_trackers_aggregate_hardfork(a_ledger, NULL, a_trackers, a_hardfork_start_time);
     DL_APPEND(*a_ret_list, l_new_condout);
     return 0;
@@ -2536,8 +2537,9 @@ static dap_chain_addr_t* s_change_addr(struct json_object *a_json, dap_chain_add
     return NULL;
 }
 
-dap_ledger_hardfork_balances_t *dap_ledger_states_aggregate(dap_ledger_t *a_ledger, dap_time_t a_hardfork_decree_creation_time, dap_ledger_hardfork_condouts_t **l_cond_outs_list, json_object * a_changed_addrs)
+dap_ledger_hardfork_balances_t *dap_ledger_states_aggregate(dap_ledger_t *a_ledger, dap_time_t a_hardfork_decree_creation_time, dap_ledger_hardfork_condouts_t **l_cond_outs_list, json_object *a_changed_addrs)
 {
+    dap_return_val_if_fail(a_ledger, NULL);
     dap_ledger_hardfork_balances_t *ret = NULL;
     dap_ledger_hardfork_condouts_t *l_cond_ret = NULL;
     dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
@@ -2594,6 +2596,7 @@ dap_ledger_hardfork_balances_t *dap_ledger_states_aggregate(dap_ledger_t *a_ledg
                     continue;
                 }
                 s_aggregate_out_cond(&l_cond_ret, a_ledger, l_out, l_tx_sign, &it->tx_hash_fast, it->cache_data.token_ticker, a_hardfork_decree_creation_time, l_trackers);
+                break;
             }
             default:
                 log_it(L_ERROR, "Unexpected item type %hhu", l_tx_item_type);
@@ -2602,5 +2605,7 @@ dap_ledger_hardfork_balances_t *dap_ledger_states_aggregate(dap_ledger_t *a_ledg
         }
     }
     pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock);
+    if (l_cond_outs_list)
+        *l_cond_outs_list = l_cond_ret;
     return ret;
 }
diff --git a/modules/ledger/include/dap_chain_ledger.h b/modules/ledger/include/dap_chain_ledger.h
index ad3a3a3f2647e0d7dd5c9dd382c5e584661e8990..2de3e3060dd7fe1db3d4ee990a8b05c324e51d33 100644
--- a/modules/ledger/include/dap_chain_ledger.h
+++ b/modules/ledger/include/dap_chain_ledger.h
@@ -64,7 +64,7 @@ typedef struct dap_ledger_hardfork_condouts {
     dap_hash_fast_t hash;
     dap_chain_tx_out_cond_t *cond;
     dap_chain_tx_sig_t *sign;
-    const char *ticker;
+    char ticker[DAP_CHAIN_TICKER_SIZE_MAX];
     dap_list_t *trackers;
     struct dap_ledger_hardfork_condouts *prev, *next;
 } dap_ledger_hardfork_condouts_t;
@@ -498,9 +498,9 @@ dap_chain_tx_out_cond_t* dap_chain_ledger_get_tx_out_cond_linked_to_tx_in_cond(d
 void dap_ledger_load_end(dap_ledger_t *a_ledger);
 dap_pkey_t *dap_ledger_find_pkey_by_hash(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_pkey_hash);
 
-//int dap_ledger_decree_create(dap_ledger_t *a_ledger);
 void dap_ledger_decree_init(dap_ledger_t *a_ledger);
-void dap_ledger_decree_purge(dap_ledger_t *a_ledger);
+int dap_ledger_decree_purge(dap_ledger_t *a_ledger);
+int dap_ledger_anchor_purge(dap_ledger_t *a_ledger, dap_chain_id_t a_chain_id);
 
 uint16_t dap_ledger_decree_get_min_num_of_signers(dap_ledger_t *a_ledger);
 uint16_t dap_ledger_decree_get_num_of_owners(dap_ledger_t *a_ledger);
@@ -516,9 +516,10 @@ int dap_ledger_anchor_verify(dap_chain_net_t *a_net, dap_chain_datum_anchor_t *
 int dap_ledger_anchor_load(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain, dap_hash_fast_t *a_anchor_hash);
 int dap_ledger_anchor_unload(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain, dap_hash_fast_t *a_anchor_hash);
 dap_chain_datum_anchor_t *dap_ledger_anchor_find(dap_ledger_t *a_ledger, dap_hash_fast_t *a_anchor_hash);
+int dap_ledger_anchor_purge(dap_ledger_t *a_ledger, dap_chain_id_t a_chain_id);
 
 dap_ledger_hardfork_balances_t *dap_ledger_states_aggregate(dap_ledger_t *a_ledger, dap_time_t a_hardfork_decree_creation_time, dap_ledger_hardfork_condouts_t **l_cond_outs_list, json_object* a_changed_addrs);
-dap_ledger_hardfork_anchors_t *dap_ledger_anchors_aggregate(dap_ledger_t *a_ledger);
+dap_ledger_hardfork_anchors_t *dap_ledger_anchors_aggregate(dap_ledger_t *a_ledger, dap_chain_id_t a_chain_id);
 
 uint256_t dap_ledger_coin_get_uncoloured_value(dap_ledger_t *a_ledger, dap_hash_fast_t *a_voting_hash, dap_hash_fast_t *a_tx_hash, int a_out_idx);
 dap_list_t *dap_ledger_tx_get_trackers(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_tx_hash, uint32_t a_out_idx);
diff --git a/modules/ledger/include/dap_chain_ledger_pvt.h b/modules/ledger/include/dap_chain_ledger_pvt.h
index 5932e43064a235eb73b436ba10536b4bcba967a4..44a4bd50e9332973cb2f3f9e6838888862643097 100644
--- a/modules/ledger/include/dap_chain_ledger_pvt.h
+++ b/modules/ledger/include/dap_chain_ledger_pvt.h
@@ -149,12 +149,14 @@ typedef struct dap_ledger_decree_item {
     bool wait_for_apply, is_applied;
     dap_chain_datum_decree_t *decree;
     dap_hash_fast_t anchor_hash;
+    dap_chain_id_t storage_chain_id;
     UT_hash_handle hh;
 } dap_ledger_decree_item_t;
 
 typedef struct dap_ledger_anchor_item {
     dap_hash_fast_t anchor_hash;
     dap_chain_datum_anchor_t *anchor;
+    dap_chain_id_t storage_chain_id;
     UT_hash_handle hh;
 } dap_ledger_anchor_item_t;
 
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index a32dfbcdbdf2b32d1237cbb62eb0c1030b432a8e..e9d516eeb3f9608293c59ec218c902d71bc67306 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -1656,7 +1656,7 @@ static int s_cli_net(int argc, char **argv, void **reply)
                 } else {
                     json_object_put(l_jobj_list_ca);
                     json_object *l_jobj_str_ret = json_object_new_string("No entries found");
-                    if (!l_jobj_list_ca) {
+                    if (!l_jobj_str_ret) {
                         json_object_put(l_jobj_return);
                         dap_json_rpc_allocation_error(*a_json_arr_reply);
                         return DAP_JSON_RPC_ERR_CODE_MEMORY_ALLOCATED;
diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c
index 8c7a2fa1cdc89cadeb2237b5d2e6372554761c16..dc7b67434b7b9bd351fa838849148831aa6cca4a 100644
--- a/modules/net/dap_chain_node.c
+++ b/modules/net/dap_chain_node.c
@@ -59,14 +59,12 @@ typedef struct dap_chain_node_net_states_info {
 #define node_info_v1_shift ( sizeof(uint16_t) + 16 + sizeof(dap_chain_node_role_t) )
 
 enum hardfork_state {
-    STATE_START = 0,
-    STATE_ANCHORS,
+    STATE_ANCHORS = 0,
     STATE_BALANCES,
     STATE_CONDOUTS,
     STATE_FEES,
     STATE_SERVICES,
-    STATE_MEMPOOL,
-    STATE_FINISH
+    STATE_MEMPOOL
 };
 
 struct hardfork_states {
@@ -237,11 +235,10 @@ void dap_chain_node_list_cluster_del_callback(dap_store_obj_t *a_obj, void *a_ar
         dap_chain_node_client_t *l_client = dap_chain_node_client_connect_default_channels(l_net, l_node_info);
         if (l_client)
             l_ret = dap_chain_node_client_wait(l_client, NODE_CLIENT_STATE_ESTABLISHED, 30000);
-        // dap_chain_node_client_close_unsafe(l_client);  del in s_go_stage_on_client_worker_unsafe
+        // dap_chain_node_client_close_unsafe(l_client); TODO unexpected del in s_go_stage_on_client_worker_unsafe
     }
     if (l_ret == 0) {
         dap_global_db_set_sync(a_obj->group, a_obj->key, a_obj->value, a_obj->value_len, a_obj->flags & DAP_GLOBAL_DB_RECORD_PINNED);
-        // dap_global_db_set_raw_sync(a_obj, 1);
     } else {
         log_it(L_DEBUG, "Can't do handshake with %s [ %s : %u ] delete from node list", a_obj->key, l_node_info->ext_host, l_node_info->ext_port);
         dap_del_global_db_obj_by_ttl(a_obj);
@@ -529,9 +526,10 @@ int dap_chain_node_hardfork_prepare(dap_chain_t *a_chain, dap_time_t a_last_bloc
         log_it(L_ERROR, "Stake delegate data verifying with hardfork decree failed");
         return -3;
     }
+    log_it(L_ATT, "Starting data prepare for hardfork of chain '%s' for net '%s'", a_chain->name, l_net->pub.name);
     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);
+    l_states->anchors = dap_ledger_anchors_aggregate(l_net->pub.ledger, a_chain->id);
     l_states->fees = dap_chain_cs_blocks_fees_aggregate(a_chain);
     size_t l_state_size = 0;
     l_states->service_states = dap_chain_srv_hardfork_all(l_net->pub.id);
@@ -548,13 +546,7 @@ 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;
+    dap_chain_cell_create(a_chain, c_dap_chain_cell_id_hardfork);
     return 0;
 }
 
@@ -661,11 +653,9 @@ int dap_chain_node_hardfork_process(dap_chain_t *a_chain)
         return log_it(L_ERROR, "Can't process chain with no harfork data. Use dap_chain_node_hardfork_prepare() for collect it first"), -2;
     struct hardfork_states *l_states = a_chain->hardfork_data;
     switch (l_states->state_current) {
-    case STATE_START:
-        l_states->state_current = STATE_ANCHORS;
     case STATE_ANCHORS:
         for (dap_ledger_hardfork_anchors_t *it = l_states->anchors; it; it = it->next) {
-            dap_chain_datum_t *l_datum_anchor = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, it->anchor, dap_chain_datum_anchor_get_size(it->anchor));
+            dap_chain_datum_t *l_datum_anchor = dap_chain_datum_create(DAP_CHAIN_DATUM_ANCHOR, it->anchor, dap_chain_datum_anchor_get_size(it->anchor));
             if (!l_datum_anchor)
                 return -2;
             if (!a_chain->callback_add_datums(a_chain, &l_datum_anchor, 1)) {
@@ -677,7 +667,6 @@ int dap_chain_node_hardfork_process(dap_chain_t *a_chain)
             }
             DAP_DELETE(l_datum_anchor);
         }
-        l_states->state_current = STATE_BALANCES;
     case STATE_BALANCES:
         for (dap_ledger_hardfork_balances_t *it = l_states->balances; it; it = it->next) {
             dap_chain_datum_t *l_tx = s_datum_tx_create(&it->addr, it->ticker, it->value, it->trackers);
@@ -690,7 +679,6 @@ int dap_chain_node_hardfork_process(dap_chain_t *a_chain)
             }
             DAP_DELETE(l_tx);
         }
-        l_states->state_current = STATE_CONDOUTS;
     case STATE_CONDOUTS:
         for (dap_ledger_hardfork_condouts_t *it = l_states->condouts; it; it = it->next) {
             dap_chain_datum_t *l_cond_tx = s_cond_tx_create(it->cond, it->sign, &it->hash, it->ticker, it->trackers);
@@ -703,7 +691,6 @@ int dap_chain_node_hardfork_process(dap_chain_t *a_chain)
             }
             DAP_DELETE(l_cond_tx);
         }
-        l_states->state_current = STATE_FEES;
     case STATE_FEES:
         for (dap_chain_cs_blocks_hardfork_fees_t *it = l_states->fees; it; it = it->next) {
             dap_chain_datum_t *l_fee_tx = s_fee_tx_create(it->fees_n_rewards_sum, it->owner_sign);
@@ -717,7 +704,6 @@ int dap_chain_node_hardfork_process(dap_chain_t *a_chain)
             }
             DAP_DELETE(l_fee_tx);
         }
-        l_states->state_current = STATE_SERVICES;
     case STATE_SERVICES:
         for (dap_chain_srv_hardfork_state_t *it = l_states->service_states; it; it = it->next) {
             if (it->uid.uint64 >= (uint64_t)INT64_MIN)       // MSB is set
@@ -742,12 +728,10 @@ int dap_chain_node_hardfork_process(dap_chain_t *a_chain)
             if (l_break)
                 break;
         }
-        l_states->state_current = STATE_MEMPOOL;
     case STATE_MEMPOOL: {
         char *l_gdb_group_mempool = dap_chain_mempool_group_new(a_chain);
         size_t l_objs_count = 0;
         dap_store_obj_t *l_objs = dap_global_db_get_all_raw_sync(l_gdb_group_mempool, &l_objs_count);
-        bool l_nothing_processed = true;
         for (size_t i = 0; i < l_objs_count; i++) {
             if (dap_store_obj_get_type(l_objs +i) == DAP_GLOBAL_DB_OPTYPE_DEL)
                 continue;
@@ -782,16 +766,10 @@ int dap_chain_node_hardfork_process(dap_chain_t *a_chain)
             }
             if (dap_chain_node_mempool_process(a_chain, l_datum, l_objs[i].key, NULL))
                 dap_global_db_del(l_gdb_group_mempool, l_objs[i].key, NULL, NULL);
-            else
-                l_nothing_processed = false;
         }
         dap_store_obj_free(l_objs, l_objs_count);
         DAP_DELETE(l_gdb_group_mempool);
-        if (l_nothing_processed)
-            l_states->state_current = STATE_FINISH;
-    }
-    case STATE_FINISH:
-        break;
+    } break;
     // No default here
     }
     return 0;
@@ -885,6 +863,22 @@ int s_hardfork_check(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_
     }
     switch (a_datum->header.type_id) {
 
+    case DAP_CHAIN_DATUM_ANCHOR: {
+        dap_ledger_hardfork_anchors_t *l_found = NULL,
+                                       l_sought = { .anchor = (dap_chain_datum_anchor_t *)a_datum->data };
+
+        DL_SEARCH(a_chain->hardfork_data->anchors, l_found, &l_sought, s_compare_anchors);
+        if (l_found) {
+            if (a_remove) {
+                DL_DELETE(a_chain->hardfork_data->anchors, l_found);
+                DAP_DELETE(l_found);
+                if (!a_chain->hardfork_data->anchors)
+                    a_chain->hardfork_data->state_current = STATE_BALANCES;
+            }
+            break;
+        }
+    } break;
+
     case DAP_CHAIN_DATUM_TX: {
         dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)a_datum->data;
         if (!l_tx->header.ts_created /* TODO add || l_tx->header.ts_created other criteria */) {
@@ -936,15 +930,16 @@ int s_hardfork_check(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_
                         log_it(L_WARNING, "Illegal harfork datum tx TSD TICKER size %u", l_tsd->size);
                         return -8;
                     }
-                    dap_stpcpy((char *)l_conitional.ticker, (char *)l_tsd->data);
+                    dap_strncpy(l_conitional.ticker, (char *)l_tsd->data, DAP_CHAIN_TICKER_SIZE_MAX);
                     break;
                 case DAP_CHAIN_DATUM_TX_TSD_TYPE_HARDFORK_TRACKER:
                     if (l_out)
                         l_regular.trackers = dap_list_append(l_regular.trackers, l_tsd->data);
                     else
                         l_conitional.trackers = dap_list_append(l_conitional.trackers, l_tsd->data);
+                    break;
                 default:
-                    log_it(L_WARNING, "Illegal harfork datum tx TSD item type %d", l_tsd->type);
+                    log_it(L_WARNING, "Illegal harfork datum tx TSD item type 0x%X", l_tsd->type);
                     return -7;
                 }
             } break;
@@ -958,27 +953,41 @@ int s_hardfork_check(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_
             dap_ledger_hardfork_balances_t *l_found = NULL;
             DL_SEARCH(a_chain->hardfork_data->balances, l_found, &l_regular, s_compare_balances);
             if (l_found) {
-                if (a_remove)
+                if (a_remove) {
                     DL_DELETE(a_chain->hardfork_data->balances, l_found);
+                    dap_list_free_full(l_found->trackers, NULL);
+                    DAP_DELETE(l_found);
+                    if (!a_chain->hardfork_data->balances)
+                        a_chain->hardfork_data->state_current = STATE_CONDOUTS;
+                }
                 break;
             }
         } else if (l_conitional.cond) {
-            if (l_conitional.cond->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STACK) {
+            if (l_conitional.cond->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STACK) {
+                dap_ledger_hardfork_condouts_t *l_found = NULL;
+                DL_SEARCH(a_chain->hardfork_data->condouts, l_found, &l_conitional, s_compare_condouts);
+                if (l_found) {
+                    if (a_remove) {
+                        DL_DELETE(a_chain->hardfork_data->condouts, l_found);
+                        dap_list_free_full(l_found->trackers, NULL);
+                        DAP_DELETE(l_found);
+                        if (!a_chain->hardfork_data->condouts)
+                            a_chain->hardfork_data->state_current = STATE_FEES;
+                    }
+                    break;
+                }
+            } else {
                 dap_chain_cs_blocks_hardfork_fees_t *l_found = NULL,
                                                      l_sought = { .fees_n_rewards_sum = l_conitional.cond->header.value,
                                                                   .owner_sign = dap_chain_datum_tx_item_sig_get_sign(l_conitional.sign) };
                 DL_SEARCH(a_chain->hardfork_data->fees, l_found, &l_sought, s_compare_fees);
                 if (l_found) {
-                    if (a_remove)
+                    if (a_remove) {
                         DL_DELETE(a_chain->hardfork_data->fees, l_found);
-                    break;
-                }
-            } else {
-                dap_ledger_hardfork_condouts_t *l_found = NULL;
-                DL_SEARCH(a_chain->hardfork_data->condouts, l_found, &l_conitional, s_compare_condouts);
-                if (l_found) {
-                    if (a_remove)
-                        DL_DELETE(a_chain->hardfork_data->condouts, l_found);
+                        DAP_DELETE(l_found);
+                        if (!a_chain->hardfork_data->fees)
+                            a_chain->hardfork_data->state_current = STATE_SERVICES;
+                    }
                     break;
                 }
             }
@@ -987,19 +996,10 @@ int s_hardfork_check(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_
             return -8;
         }
         // Clean memory
-
-    } break;
-
-    case DAP_CHAIN_DATUM_ANCHOR: {
-        dap_ledger_hardfork_anchors_t *l_found = NULL,
-                                       l_sought = { .anchor = (dap_chain_datum_anchor_t *)a_datum->data };
-
-        DL_SEARCH(a_chain->hardfork_data->anchors, l_found, &l_sought, s_compare_anchors);
-        if (l_found) {
-            if (a_remove)
-                DL_DELETE(a_chain->hardfork_data->anchors, l_found);
-            break;
-        }
+        if (l_regular.trackers)
+            dap_list_free(l_regular.trackers);
+        if (l_conitional.trackers)
+            dap_list_free(l_conitional.trackers);
     } break;
 
     case DAP_CHAIN_DATUM_SERVICE_STATE: {
@@ -1008,8 +1008,12 @@ int s_hardfork_check(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_
 
         DL_SEARCH(a_chain->hardfork_data->service_states, l_found, &l_sought, s_compare_service_states);
         if (l_found) {
-            if (a_remove)
+            if (a_remove) {
                 DL_DELETE(a_chain->hardfork_data->service_states, l_found);
+                DAP_DEL_MULTY(l_found->data, l_found);
+                if (!a_chain->hardfork_data->service_states)
+                    a_chain->hardfork_data->state_current = STATE_MEMPOOL;
+            }
             break;
         }
         dap_hash_str_t l_key = dap_get_data_hash_str(a_datum->data, a_datum->header.data_size);
@@ -1023,11 +1027,12 @@ int s_hardfork_check(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_
                 dap_global_db_del(l_gdb_group_mempool, l_objs[i].key, NULL, NULL);
                 break;
             }
+
 #define m_ret(rc) { \
-    dap_store_obj_free(l_objs, l_objs_count); \
-    DAP_DELETE(l_gdb_group_mempool); \
-    return rc; \
-}
+        dap_store_obj_free(l_objs, l_objs_count); \
+        DAP_DELETE(l_gdb_group_mempool); \
+        return rc; \
+    }
             if (dap_store_obj_get_type(l_objs +i) == DAP_GLOBAL_DB_OPTYPE_DEL) {
                 log_it(L_WARNING, "Mempool record %s already deleted, can' process", l_objs[i].key);
                 m_ret(-8);
diff --git a/modules/node-cli/dap_chain_node_cli_cmd.c b/modules/node-cli/dap_chain_node_cli_cmd.c
index bd940670a7bd985a622307f7791ab0e1f3717fc1..4b62ba1375116de8e03792995d19496a693f7ec8 100644
--- a/modules/node-cli/dap_chain_node_cli_cmd.c
+++ b/modules/node-cli/dap_chain_node_cli_cmd.c
@@ -4120,8 +4120,8 @@ 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);
-
-            l_tsd = dap_tsd_create(DAP_CHAIN_DATUM_DECREE_TSD_TYPE_GENERATION, &l_chain->generation, sizeof(l_chain->generation));
+            uint16_t l_generation = l_chain->generation + 1;
+            l_tsd = dap_tsd_create(DAP_CHAIN_DATUM_DECREE_TSD_TYPE_GENERATION, &l_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);
@@ -4174,15 +4174,15 @@ 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;
-                }
+            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;
+            l_subtype = DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK_RETRY;
             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);
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 63a91272c32ba8d39d78815ade8cf478d8599f6f..835fbbe90f6ea5829f145e78c768745f14d1a7c3 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
@@ -131,8 +131,7 @@ static json_object* s_dap_chain_net_srv_stake_reward_all(json_object* a_json_arr
 static bool s_debug_more = false;
 
 static void *s_pos_delegate_start(dap_chain_net_id_t a_net_id, dap_config_t UNUSED_ARG *a_config);
-static void s_pos_delegate_delete(void *a_service_internal);
-static int s_pos_delegate_purge(dap_chain_net_id_t a_net_id);
+static int s_pos_delegate_purge(dap_chain_net_id_t a_net_id, void *a_service_internal);
 static json_object *s_pos_delegate_get_fee_validators_json(dap_chain_net_id_t a_net_id);
 bool s_tax_callback(dap_chain_net_id_t a_net_id, dap_hash_fast_t *a_pkey_hash, dap_chain_addr_t *a_addr_out, uint256_t *a_value_out);
 
@@ -247,7 +246,6 @@ int dap_chain_net_srv_stake_pos_delegate_init()
     s_debug_more = dap_config_get_item_bool_default(g_config, "stake", "debug_more", s_debug_more);
     dap_sign_set_pkey_by_hash_callback(s_get_pkey_by_hash_callback);
     dap_chain_static_srv_callbacks_t l_callbacks = { .start = s_pos_delegate_start,
-                                                     .delete = s_pos_delegate_delete,
                                                      .purge = s_pos_delegate_purge,
                                                      .get_fee_descr = s_pos_delegate_get_fee_validators_json };
     dap_chain_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID };
@@ -270,33 +268,6 @@ static void *s_pos_delegate_start(dap_chain_net_id_t a_net_id, dap_config_t UNUS
     return l_srv_stake;
 }
 
-/**
- * @brief delete ht and hh concretic net from s_srv_stake 
- */
-static void s_pos_delegate_delete(void *a_service_internal)
-{
-    struct srv_stake *l_srv_stake = a_service_internal;
-    dap_return_if_fail(l_srv_stake);
-    dap_chain_net_srv_stake_item_t *l_stake = NULL, *l_tmp = NULL;
-    HASH_ITER(ht, l_srv_stake->tx_itemlist, l_stake, l_tmp) {
-        // Clang bug at this, l_stake should change at every loop cycle
-        HASH_DELETE(ht, l_srv_stake->tx_itemlist, l_stake);
-    }
-    HASH_ITER(hh, l_srv_stake->itemlist, l_stake, l_tmp) {
-        HASH_DEL(l_srv_stake->itemlist, l_stake);
-        s_srv_stake_item_free((void *)l_stake);
-    }
-    HASH_ITER(hh, l_srv_stake->hardfork.sandbox, l_stake, l_tmp) {
-        HASH_DEL(l_srv_stake->hardfork.sandbox, l_stake);
-        s_srv_stake_item_free((void *)l_stake);
-    }
-    struct cache_item *l_cache_item = NULL, *l_cache_tmp = NULL;
-    HASH_ITER(hh, l_srv_stake->cache, l_cache_item, l_cache_tmp) {
-        HASH_DEL(l_srv_stake->cache, l_cache_item);
-        DAP_DELETE(l_cache_item);
-    }
-}
-
 void dap_chain_net_srv_stake_pos_delegate_deinit()
 {
     dap_chain_srv_delete((dap_chain_srv_uid_t) { .uint64 = DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_ID });
@@ -494,27 +465,20 @@ static void s_stake_recalculate_weights(dap_chain_net_id_t a_net_id)
     while (s_weights_truncate(l_srv_stake, l_limit_min));
 }
 
-static void s_stake_key_delegate_sandbox(struct srv_stake *a_srv_stake, dap_chain_addr_t *a_signing_addr, dap_pkey_t *a_pkey)
+static void s_stake_add_tx(dap_chain_net_t *a_net, dap_chain_net_srv_stake_item_t *a_stake)
 {
-    dap_return_if_pass(!a_srv_stake || !a_signing_addr || !a_pkey);
-    log_it(L_NOTICE, "Add key %s delegation in hardfork process", dap_hash_fast_to_str_static(&a_signing_addr->data.hash_fast));
-    dap_chain_net_srv_stake_item_t *l_stake = NULL;
-    bool l_found = false;
-    HASH_FIND(hh, a_srv_stake->hardfork.sandbox, &a_signing_addr->data.hash_fast, sizeof(dap_hash_fast_t), l_stake);
-    if (!l_stake)
-        l_stake = DAP_NEW_Z_RET_IF_FAIL(dap_chain_net_srv_stake_item_t);
-    else
-        l_found = true;
-    if (dap_pkey_get_size(l_stake->pkey)) {
-        log_it(L_DEBUG, "Full pkey by hash %s was replaced", dap_hash_fast_to_str_static(&a_signing_addr->data.hash_fast));
-        DAP_DELETE(l_stake->pkey);
-    }
-    l_stake->pkey = DAP_DUP_SIZE(a_pkey, dap_pkey_get_size(a_pkey));
-    if (!l_found) {
-        l_stake->signing_addr = *a_signing_addr;
-        HASH_ADD(hh, a_srv_stake->hardfork.sandbox, signing_addr.data.hash_fast, sizeof(dap_hash_fast_t), l_stake);
+    dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(a_net->pub.ledger, &a_stake->tx_hash);
+    if (!l_tx)
+        return;
+    dap_chain_tx_out_cond_t *l_cond = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, NULL);
+    if (l_cond && (l_cond->tsd_size == dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, dap_pkey_get_size(a_stake->pkey)))) {
+        dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR);
+        a_stake->sovereign_addr = dap_tsd_get_scalar(l_tsd, dap_chain_addr_t);
+        l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE);
+        a_stake->sovereign_tax = dap_tsd_get_scalar(l_tsd, uint256_t);
+        if (compare256(a_stake->sovereign_tax, dap_chain_balance_coins_scan("1.0")) == 1)
+            a_stake->sovereign_tax = dap_chain_balance_coins_scan("1.0");
     }
-    return;
 }
 
 void dap_chain_net_srv_stake_key_delegate(dap_chain_net_t *a_net, dap_chain_addr_t *a_signing_addr, dap_chain_datum_decree_t *a_decree,
@@ -534,7 +498,8 @@ void dap_chain_net_srv_stake_key_delegate(dap_chain_net_t *a_net, dap_chain_addr
         l_stake = DAP_NEW_Z(dap_chain_net_srv_stake_item_t);
     else {
         l_found = true;
-        HASH_DELETE(ht, l_srv_stake->tx_itemlist, l_stake);
+        if (!l_srv_stake->hardfork.in_process)
+            HASH_DELETE(ht, l_srv_stake->tx_itemlist, l_stake);
     }
     l_stake->net = a_net;
     l_stake->node_addr = *a_node_addr;
@@ -551,20 +516,16 @@ void dap_chain_net_srv_stake_key_delegate(dap_chain_net_t *a_net, dap_chain_addr
     }
     if (!l_found)
         HASH_ADD(hh, l_srv_stake->itemlist, signing_addr.data.hash_fast, sizeof(dap_hash_fast_t), l_stake);
+    if (l_srv_stake->hardfork.in_process) {
+        const char *l_value_str; dap_uint256_to_char(a_value, &l_value_str);
+        log_it(L_DEBUG, "Added key with fingerprint %s and locked value %s for node " NODE_ADDR_FP_STR,
+                                dap_chain_hash_fast_to_str_static(&a_signing_addr->data.hash_fast), l_value_str, NODE_ADDR_FP_ARGS(a_node_addr));
+        s_stake_recalculate_weights(a_signing_addr->net_id);
+        return;
+    }
     if (!dap_hash_fast_is_blank(&l_stake->tx_hash)) {
         HASH_ADD(ht, l_srv_stake->tx_itemlist, tx_hash, sizeof(dap_hash_fast_t), l_stake);
-        dap_chain_datum_tx_t *l_tx = dap_ledger_tx_find_by_hash(a_net->pub.ledger, &l_stake->tx_hash);
-        if (l_tx) {
-            dap_chain_tx_out_cond_t *l_cond = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, NULL);
-            if (l_cond && (l_cond->tsd_size == dap_chain_datum_tx_item_out_cond_create_srv_stake_get_tsd_size(true, dap_pkey_get_size(l_stake->pkey)))) {
-                dap_tsd_t *l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_ADDR);
-                l_stake->sovereign_addr = dap_tsd_get_scalar(l_tsd, dap_chain_addr_t);
-                l_tsd = dap_tsd_find(l_cond->tsd, l_cond->tsd_size, DAP_CHAIN_TX_OUT_COND_TSD_VALUE);
-                l_stake->sovereign_tax = dap_tsd_get_scalar(l_tsd, uint256_t);
-                if (compare256(l_stake->sovereign_tax, dap_chain_balance_coins_scan("1.0")) == 1)
-                    l_stake->sovereign_tax = dap_chain_balance_coins_scan("1.0");
-            }
-        }
+        s_stake_add_tx(a_net, l_stake);
     }
     dap_chain_esbocs_add_validator_to_clusters(a_net->pub.id, a_node_addr);
     const char *l_value_str; dap_uint256_to_char(a_value, &l_value_str);
@@ -832,20 +793,43 @@ int dap_chain_net_srv_stake_load_cache(dap_chain_net_t *a_net)
     return 0;
 }
 
-static int s_pos_delegate_purge(dap_chain_net_id_t a_net_id)
+static int s_pos_delegate_purge(dap_chain_net_id_t a_net_id, void *a_service_internal)
 {
-    dap_ledger_t *l_ledger = dap_chain_net_by_id(a_net_id)->pub.ledger;
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_net_id);
+    if (!l_net)
+        return -1;
+    dap_ledger_t *l_ledger = l_net->pub.ledger;
     char *l_gdb_group = dap_ledger_get_gdb_group(l_ledger, DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_GDB_GROUP);
     dap_global_db_erase_table(l_gdb_group, NULL, NULL);
     DAP_DELETE(l_gdb_group);
-    struct srv_stake *l_srv_stake = s_srv_stake_by_net_id(a_net_id);
-    s_pos_delegate_delete(l_srv_stake);
+    char *l_approved_group = s_get_approved_group(l_net);
+    dap_global_db_erase_table(l_approved_group, NULL, NULL);
+    DAP_DELETE(l_approved_group);
+
+    struct srv_stake *l_srv_stake = (struct srv_stake *)a_service_internal;
+    dap_chain_net_srv_stake_item_t *l_stake = NULL, *l_tmp = NULL;
+    HASH_ITER(ht, l_srv_stake->tx_itemlist, l_stake, l_tmp) {
+        // Clang bug at this, l_stake should change at every loop cycle
+        HASH_DELETE(ht, l_srv_stake->tx_itemlist, l_stake);
+    }
+    HASH_ITER(hh, l_srv_stake->itemlist, l_stake, l_tmp) {
+        HASH_DEL(l_srv_stake->itemlist, l_stake);
+        s_srv_stake_item_free((void *)l_stake);
+    }
+    HASH_ITER(hh, l_srv_stake->hardfork.sandbox, l_stake, l_tmp) {
+        HASH_DEL(l_srv_stake->hardfork.sandbox, l_stake);
+        s_srv_stake_item_free((void *)l_stake);
+    }
+    struct cache_item *l_cache_item = NULL, *l_cache_tmp = NULL;
+    HASH_ITER(hh, l_srv_stake->cache, l_cache_item, l_cache_tmp) {
+        HASH_DEL(l_srv_stake->cache, l_cache_item);
+        DAP_DELETE(l_cache_item);
+    }
     memset(l_srv_stake, 0, sizeof(*l_srv_stake));
     l_srv_stake->delegate_allowed_min = dap_chain_balance_coins_scan("1.0");
     return 0;
 }
 
-
 // Freeze staker's funds when delegating a key
 static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_t * a_net, dap_enc_key_t *a_key,
                                                uint256_t a_value, uint256_t a_fee,
@@ -1158,7 +1142,8 @@ dap_chain_datum_decree_t *dap_chain_net_srv_stake_decree_approve(dap_chain_net_t
         return NULL;
     }
 
-    if(dap_chain_net_srv_stake_verify_key_and_node(&l_tx_out_cond->subtype.srv_stake_pos_delegate.signing_addr, &l_tx_out_cond->subtype.srv_stake_pos_delegate.signer_node_addr)){
+    if(dap_chain_net_srv_stake_verify_key_and_node(&l_tx_out_cond->subtype.srv_stake_pos_delegate.signing_addr,
+                                                   &l_tx_out_cond->subtype.srv_stake_pos_delegate.signer_node_addr)){
         log_it(L_WARNING, "Key and node verification error");
         return NULL;
     }
@@ -4329,40 +4314,12 @@ int dap_chain_net_srv_stake_hardfork_data_import(dap_chain_net_id_t a_net_id, da
         log_it(L_ERROR, "Can't find hardfork decree by hash %s", dap_hash_fast_to_str_static(a_hardfork_decree_hash));
         return -1;
     }
-    // temporary save poa pkeys
-    dap_list_t *l_current_list = NULL;
-
     struct srv_stake *l_srv_stake = s_srv_stake_by_net_id(a_net_id);
     if (!l_srv_stake)
         return -2;
-    if (l_srv_stake->hardfork.in_process && l_srv_stake->hardfork.sandbox) {
-        log_it(L_ERROR, "Temp hardfork table already existed in net %"DAP_UINT64_FORMAT_U, a_net_id.uint64);
-        return -3;
-    }
-    dap_chain_net_srv_stake_item_t *l_stake, *l_tmp;
-    HASH_ITER(hh, l_srv_stake->itemlist, l_stake, l_tmp) {
-        if (dap_hash_fast_is_blank(&l_stake->tx_hash)) {
-            l_current_list = dap_list_append(l_current_list, l_stake);
-            HASH_DEL(l_srv_stake->itemlist, l_stake);
-        }
-    }
-    // clean prev table
-    if (!l_srv_stake->hardfork.in_process)
-        s_pos_delegate_purge(a_net_id);
-    
-    // restore poa keys
-    for ( dap_list_t* l_iter = dap_list_first(l_current_list); l_iter; l_iter = l_iter->next) {
-        l_stake = (dap_chain_net_srv_stake_item_t *)l_iter->data;
-        if (l_srv_stake->hardfork.in_process) {
-            s_stake_key_delegate_sandbox(l_srv_stake, &l_stake->signing_addr, l_stake->pkey);
-        } else {
-            dap_chain_net_srv_stake_key_delegate(l_net, &l_stake->signing_addr, NULL, l_stake->value, &l_stake->node_addr, l_stake->pkey);
-        }
-    }
-    dap_list_free_full(l_current_list, s_srv_stake_item_free);
 
-    l_current_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));
-    for ( dap_list_t* l_iter = dap_list_first(l_current_list); l_iter; l_iter = l_iter->next) {
+    dap_list_t *l_current_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));
+    for (dap_list_t *l_iter = dap_list_first(l_current_list); l_iter; l_iter = l_iter->next) {
         dap_chain_datum_decree_t *l_current_decree = dap_ledger_decree_get_by_hash(l_net, (dap_hash_fast_t *)((dap_tsd_t *)l_iter->data)->data, NULL);
         if (!l_decree) {
             log_it(L_ERROR, "Can't find delegate decree by hash %s", dap_hash_fast_to_str_static((dap_hash_fast_t *)((dap_tsd_t *)l_iter->data)->data));
@@ -4384,12 +4341,9 @@ int dap_chain_net_srv_stake_hardfork_data_import(dap_chain_net_id_t a_net_id, da
             dap_list_free_full(l_current_list, NULL);
             return -4;
         }
-        if (l_srv_stake->hardfork.in_process) {
-            s_stake_key_delegate_sandbox(l_srv_stake, &l_addr, dap_chain_datum_decree_get_pkey(l_current_decree));
-        } else {
-            dap_chain_net_srv_stake_key_delegate(l_net, &l_addr, l_current_decree, l_value, &l_node_addr, dap_chain_datum_decree_get_pkey(l_current_decree));
+        dap_chain_net_srv_stake_key_delegate(l_net, &l_addr, l_current_decree, l_value, &l_node_addr, dap_chain_datum_decree_get_pkey(l_current_decree));
+        if (!l_srv_stake->hardfork.in_process)
             dap_chain_net_srv_stake_add_approving_decree_info(l_current_decree, l_net);
-        }
     }
     dap_list_free_full(l_current_list, NULL);
     return 0;
@@ -4444,20 +4398,47 @@ int dap_chain_net_srv_stake_hardfork_data_verify(dap_chain_net_t *a_net, dap_has
  */
 int dap_chain_net_srv_stake_switch_table(dap_chain_net_id_t a_net_id, bool a_to_sandbox)
 {
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_net_id);
     struct srv_stake *l_srv_stake = s_srv_stake_by_net_id(a_net_id);
-    if (!l_srv_stake)
+    if (!l_srv_stake || !l_net)
         return -1;
     if (l_srv_stake->hardfork.in_process == a_to_sandbox) {
         log_it(L_DEBUG, "Key delegate table already switched to %s table", a_to_sandbox ? "sandbox" : "main");
         return -2;
     }
-    if (!a_to_sandbox) { // free temp table if switch to main
-        dap_chain_net_srv_stake_item_t *l_stake = NULL, *l_tmp = NULL;
-        HASH_ITER(hh, l_srv_stake->hardfork.sandbox, l_stake, l_tmp) {
+    if (l_srv_stake->hardfork.sandbox && a_to_sandbox) {
+        log_it(L_ERROR, "Temp hardfork table already existed in net %"DAP_UINT64_FORMAT_U, a_net_id.uint64);
+        return -3;
+    }
+    if (a_to_sandbox) {
+        // switch to sandbox
+        l_srv_stake->hardfork.sandbox = l_srv_stake->itemlist;
+        l_srv_stake->itemlist = NULL;
+        // restore poa keys
+        for (dap_chain_net_srv_stake_item_t *it = l_srv_stake->hardfork.sandbox; it; it = it->hh.next)
+            if (dap_hash_fast_is_blank(&it->tx_hash)) {
+                dap_chain_net_srv_stake_item_t *l_poa = DAP_DUP_RET_VAL_IF_FAIL(it, -4);
+                l_poa->pkey = DAP_DUP_SIZE_RET_VAL_IF_FAIL(it->pkey, dap_pkey_get_size(it->pkey), -4);
+                HASH_ADD(hh, l_srv_stake->itemlist, signing_addr.data.hash_fast, sizeof(dap_hash_fast_t), l_poa);
+            }
+    } else { // free temp table if switch to main
+        dap_chain_net_srv_stake_item_t *l_stake, *l_tmp;
+        HASH_ITER(hh, l_srv_stake->itemlist, l_stake, l_tmp) {
             HASH_DEL(l_srv_stake->itemlist, l_stake);
-            s_srv_stake_item_free((void *)l_stake);
+            s_srv_stake_item_free(l_stake);
         }
+        l_srv_stake->itemlist = l_srv_stake->hardfork.sandbox;
+        l_srv_stake->hardfork.sandbox = NULL;
     }
     l_srv_stake->hardfork.in_process = a_to_sandbox;
     return 0;
 }
+
+void dap_chain_net_srv_stake_hardfork_tx_update(dap_chain_net_t *a_net)
+ {
+     struct srv_stake *l_srv_stake = s_srv_stake_by_net_id(a_net->pub.id);
+     if (!l_srv_stake)
+         return log_it(L_ERROR, "Can't update tx list: no stake service found by net id %" DAP_UINT64_FORMAT_U, a_net->pub.id.uint64);
+     for (dap_chain_net_srv_stake_item_t *it = l_srv_stake->itemlist; it; it = it->hh.next)
+         s_stake_add_tx(a_net, it);
+ }
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 3b8c7080e068031501b0f5aef90fc28b37e49bf6..129135e631499c30e905ff09289c5b6fb6320683 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
@@ -84,3 +84,4 @@ int dap_chain_net_srv_stake_hardfork_data_export(dap_chain_net_t *a_net, dap_lis
 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_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);
+void dap_chain_net_srv_stake_hardfork_tx_update(dap_chain_net_t *a_net);
diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index e4c4a55cc157dee21d9d0178e53fdf6951f473c6..3847e37142e3129ccb8e255c2c16c4655a882d7d 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -64,7 +64,8 @@ struct srv_voting {
 
 static void *s_callback_start(dap_chain_net_id_t UNUSED_ARG a_net_id, dap_config_t UNUSED_ARG *a_config);
 static void s_callback_delete(void *a_service_internal);
-static byte_t *s_votings_backup(dap_chain_net_id_t a_net_id, uint64_t *a_state_size, uint32_t *a_state_count);
+static int s_callback_purge(dap_chain_net_id_t a_net_id, void *a_service_internal);
+static byte_t *s_votings_backup(dap_chain_net_id_t a_net_id, uint64_t *a_state_size, uint32_t *a_state_count, void *a_service_internal);
 static int s_votings_restore(dap_chain_net_id_t a_net_id, byte_t *a_state, uint64_t a_state_size, uint32_t a_states_count);
 
 static int s_voting_ledger_verificator_callback(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx_in, dap_hash_fast_t *a_tx_hash, bool a_apply);
@@ -102,7 +103,11 @@ int dap_chain_net_srv_voting_init()
 
     
     dap_chain_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_VOTING_ID };
-    dap_chain_static_srv_callbacks_t l_srv_callbacks = { .start = s_callback_start, .delete = s_callback_delete, .hardfork_prepare = s_votings_backup, .hardfork_load = s_votings_restore };
+    dap_chain_static_srv_callbacks_t l_srv_callbacks = { .start = s_callback_start,
+                                                         .purge = s_callback_purge,
+                                                         .hardfork_prepare = s_votings_backup,
+                                                         .hardfork_load = s_votings_restore
+                                                       };
     int ret = dap_chain_srv_add(l_uid, DAP_CHAIN_SRV_VOTING_LITERAL, &l_srv_callbacks);
     if (ret) {
         log_it(L_ERROR, "Can't register voting service");
@@ -132,7 +137,7 @@ static void *s_callback_start(dap_chain_net_id_t UNUSED_ARG a_net_id, dap_config
     return l_service_internal;
 }
 
-static void s_callback_delete(void *a_service_internal)
+static int s_callback_purge(dap_chain_net_id_t UNUSED_ARG a_net_id, void *a_service_internal)
 {
     struct srv_voting *l_service_internal = a_service_internal;
     struct voting *it = NULL, *tmp;
@@ -141,7 +146,7 @@ static void s_callback_delete(void *a_service_internal)
         s_voting_clear(it);
         DAP_DELETE(it);
     }
-    DAP_DELETE(l_service_internal);
+    return 0;
 }
 
 static inline struct voting *s_votings_ht_get(dap_chain_net_id_t a_net_id)
@@ -1407,13 +1412,13 @@ static size_t s_voting_serial_size_calc(struct voting *a_voting, size_t *a_votes
     return ret;
 }
 
-static byte_t *s_votings_backup(dap_chain_net_id_t a_net_id, uint64_t *a_state_size, uint32_t *a_state_count)
+static byte_t *s_votings_backup(dap_chain_net_id_t a_net_id, uint64_t *a_state_size, uint32_t *a_state_count, void *a_service_internal)
 {
     if (a_state_count)
         *a_state_count = 0;
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_net_id);
     assert(l_net);
-    struct voting *votings_ht = s_votings_ht_get(l_net->pub.id);
+    struct voting *votings_ht = a_service_internal ? ((struct srv_voting *)a_service_internal)->ht : NULL;
     if (!votings_ht) {
         log_it(L_INFO, "No data to backup for voting service for net id 0x%016" DAP_UINT64_FORMAT_x, l_net->pub.id.uint64);
         return NULL;
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn.c b/modules/service/vpn/dap_chain_net_srv_vpn.c
index 75332bfc0549ac82dbe0ecd8f68024e0d42305d0..42be26474d86bdaa3eb00cfbf8ae1d00c0070924 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn.c
@@ -862,11 +862,12 @@ static void *s_vpn_service_create(dap_chain_net_id_t a_net_id, dap_config_t *a_c
     return l_srv;
 }
 
-static void s_vpn_service_delete(void *a_service)
+static int s_vpn_service_delete(dap_chain_net_id_t a_net_id, void *a_service)
 {
     dap_chain_net_srv_t *l_srv = a_service;
     DAP_DELETE(l_srv->_pvt);
     dap_chain_net_srv_del(l_srv);
+    return 0;
 }
 
 
@@ -905,7 +906,7 @@ int dap_chain_net_srv_vpn_init()
         return -4;
     }
     dap_chain_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_VPN_ID };
-    dap_chain_static_srv_callbacks_t l_callbacks = { .start = s_vpn_service_create, .delete = s_vpn_service_delete };
+    dap_chain_static_srv_callbacks_t l_callbacks = { .start = s_vpn_service_create, .purge = s_vpn_service_delete };
     dap_chain_srv_add(l_uid, "VPN", &l_callbacks);
 
     dap_stream_ch_proc_add(DAP_CHAIN_NET_SRV_VPN_CH_ID, s_ch_vpn_new, s_ch_vpn_delete, s_ch_packet_in,
diff --git a/modules/type/blocks/dap_chain_block.c b/modules/type/blocks/dap_chain_block.c
index c02e3cb673ebb9b47ae099fbfa0df0e22fcf8f5f..0e6d2421450bdd6186c16e60ca1b36001f9992c1 100644
--- a/modules/type/blocks/dap_chain_block.c
+++ b/modules/type/blocks/dap_chain_block.c
@@ -81,9 +81,6 @@ dap_chain_block_t *dap_chain_block_new(dap_chain_hash_fast_t *a_prev_block, size
         l_block_size = dap_chain_block_meta_add(&l_block, l_block_size, DAP_CHAIN_BLOCK_META_NONCE,
                                                 &l_nonce, sizeof(uint64_t));
     }
-    /*if (l_block_size && a_block_reward)
-        l_block_size = dap_chain_block_meta_add(&l_block, l_block_size, DAP_CHAIN_BLOCK_META_REWARD,
-                                               a_block_reward, sizeof(uint256_t));*/
     if (!l_block_size) {
         log_it(L_ERROR, "Can't add meta to block");
         DAP_DEL_Z(l_block);
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 253fb58de7b3aa3824a457a686a5ccf47e65a0c1..6e034e231d906486a40d87f48fcbdadee6561473 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -23,7 +23,7 @@
 #include <pthread.h>
 #include "dap_common.h"
 #include "dap_chain.h"
-#include "dap_chain_cell.h"
+#include "dap_chain_srv.h"
 #include "dap_chain_cs.h"
 #include "dap_chain_cs_blocks.h"
 #include "dap_chain_block.h"
@@ -1542,7 +1542,6 @@ static int s_callback_cs_blocks_purge(dap_chain_t *a_chain)
         l_datum_index = NULL;
     }
     pthread_rwlock_unlock(&PVT(l_blocks)->datums_rwlock);
-    dap_chain_cell_close_all(a_chain);
     return 0;
 }
 
@@ -1640,19 +1639,6 @@ static int s_delete_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block
     return l_ret;
 }
 
-/**
- * @brief s_add_atom_to_blocks
- * @param a_blocks
- * @param a_block_cache
- * @return
- */
-static void s_add_atom_to_blocks(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_cache_t *a_block_cache)
-{
-
-    return;
-}
-
-
 static bool s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_block_cache_t * a_bcache, uint64_t a_main_branch_length)
 {
     dap_chain_cs_blocks_t * l_blocks = a_blocks;
@@ -1772,21 +1758,19 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
         if ( !dap_chain_net_get_load_mode(l_net) ) {
             int l_err = dap_chain_atom_save(a_chain, l_block->hdr.cell_id, a_atom, a_atom_size, a_atom_new ? &l_block_hash : NULL, (char**)&l_block);
             if (l_err) {
-                dap_chain_net_srv_stake_switch_table(a_chain->net_id, false);
                 log_it(L_ERROR, "Can't save atom to file, code %d", l_err);
                 return ATOM_REJECT;
             }
         }
 #endif
         if (!( 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) )) {
-            dap_chain_net_srv_stake_switch_table(a_chain->net_id, false);
             log_it(L_ERROR, "Block %s is corrupted!", l_block_cache->block_hash_str);
             return dap_chain_net_get_load_mode(l_net) ? ATOM_CORRUPTED : ATOM_REJECT;
         }
         debug_if(s_debug_more, L_DEBUG, "... new block %s", l_block_cache->block_hash_str);
 
         pthread_rwlock_wrlock(& PVT(l_blocks)->rwlock);
-        if (PVT(l_blocks)->blocks){
+        if (!l_block_cache->is_genesis) {
             dap_chain_block_cache_t *l_last_block = HASH_LAST(PVT(l_blocks)->blocks);
             if (l_last_block && dap_hash_fast_compare(&l_last_block->block_hash, &l_block_prev_hash)){
                 ++PVT(l_blocks)->blocks_count;
@@ -1860,7 +1844,8 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
                 }
             }
 
-        } else {
+        } else { // Block is genesis
+
             uint8_t *l_generation_meta = dap_chain_block_meta_get(l_block, a_atom_size, DAP_CHAIN_BLOCK_META_GENERATION);
             uint16_t l_generation = l_generation_meta ? *(uint16_t *)l_generation_meta : 0;
             if (l_generation && a_chain->generation < l_generation) {
@@ -1869,6 +1854,12 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
                     log_it(L_ERROR, "Can't find hardfork decree hash in candidate block meta");
                     return ATOM_REJECT;
                 }
+                a_chain->generation++;
+                dap_ledger_anchor_purge(l_net->pub.ledger, a_chain->id);
+                dap_ledger_tx_purge(l_net->pub.ledger, false);
+                dap_chain_srv_purge_all(a_chain->net_id);
+                dap_chain_purge(a_chain);
+                l_net->pub.ledger->is_hardfork_state = true;
                 if (dap_chain_net_srv_stake_hardfork_data_import(a_chain->net_id, l_hardfork_decree_hash)) { // True import
                     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;
@@ -2503,7 +2494,7 @@ static void s_datum_iter_fill(dap_chain_datum_iter_t *a_datum_iter, dap_chain_bl
         a_datum_iter->ret_code = a_datum_index->ret_code;
         a_datum_iter->action = a_datum_index->action;
         a_datum_iter->uid = a_datum_index->service_uid;    
-        a_datum_iter->token_ticker = dap_strcmp(a_datum_index->token_ticker, "0") ? a_datum_index->token_ticker : NULL;
+        a_datum_iter->token_ticker = dap_strcmp(a_datum_index->token_ticker, "") ? a_datum_index->token_ticker : NULL;
     } else {
         a_datum_iter->cur = NULL;
         a_datum_iter->cur_hash = NULL;
@@ -2612,7 +2603,9 @@ 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);
+            if (a_chain->hardfork_data && l_bcache_last->block->hdr.cell_id.uint64 != c_dap_chain_cell_id_hardfork.uint64)
+                l_bcache_last = NULL;       // Workaround until separate cells storages will be realized
+            l_blocks->block_new = dap_chain_block_new(l_bcache_last ? &l_bcache_last->block_hash : NULL, &l_blocks->block_new_size);
             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;
         }