diff --git a/dap-sdk b/dap-sdk
index 5a92226d095b1df1996c1122de2dbe636b139ffc..5c58976798909feee535cbff8b2b7e80028aad1c 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 5a92226d095b1df1996c1122de2dbe636b139ffc
+Subproject commit 5c58976798909feee535cbff8b2b7e80028aad1c
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index a4d6e53543ca655200af7d631f6aa34e91502328..9ed29c5e98dff8ed0f00037751b948b19843700d 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -727,7 +727,7 @@ void dap_chain_atom_confirmed_notify_add(dap_chain_t *a_chain, dap_chain_callbac
  * @param a_atom_hash
  * @return
  */
-bool dap_chain_get_atom_last_hash_num(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)
+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_chain_atom_iter_t *l_iter = a_chain->callback_atom_iter_create(a_chain, a_cell_id, NULL);
@@ -738,6 +738,8 @@ bool dap_chain_get_atom_last_hash_num(dap_chain_t *a_chain, dap_chain_cell_id_t
         *a_atom_hash = l_iter->cur_hash ? *l_iter->cur_hash : (dap_hash_fast_t){0};
     if (a_atom_num)
         *a_atom_num = l_iter->cur_num;
+    if (a_atom_timestamp)
+        *a_atom_timestamp = l_iter->cur_ts;
     a_chain->callback_atom_iter_delete(l_iter);
     return true;
 }
diff --git a/modules/chain/dap_chain_srv.c b/modules/chain/dap_chain_srv.c
index 9a405ce2d694e8652f260c04d4290547f866abaa..cfd839651c307b6766b0bd6c2aec2eff915925f6 100644
--- a/modules/chain/dap_chain_srv.c
+++ b/modules/chain/dap_chain_srv.c
@@ -197,14 +197,23 @@ int dap_chain_srv_purge_all(dap_chain_net_id_t a_net_id)
  * @brief dap_chain_srv_hardfork_all
  * @param a_net_id
  */
-void dap_chain_srv_hardfork_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);
     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)
-            it->callbacks.hardfork(a_net_id);
+        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);
+        }
     }
     pthread_mutex_unlock(&s_srv_list_mutex);
+    return ret;
 }
 
 /**
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index f2fa23094a003f1621b2be0cc640e82d434a873b..467e1b01bbac2863e86fba89f651aa464b813454 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 (256 * 1024) // 256 KB
+#define DAP_CHAIN_ATOM_MAX_SIZE (8 * 1024 * 1024) // 8 MB
 #endif
 
 typedef struct dap_chain dap_chain_t;
@@ -240,6 +240,7 @@ typedef struct dap_chain {
 
     dap_config_t *config;
 
+    struct hardfork_states *hardfork_data;
     void * _pvt; // private data
     void * _inheritor; // inheritor object
 } dap_chain_t;
@@ -275,6 +276,7 @@ typedef struct dap_chain_pvt {
     char *cs_type;
     bool cs_started;
     bool need_reorder;
+
 } dap_chain_pvt_t;
 
 #define DAP_CHAIN_PVT(a) ((dap_chain_pvt_t *)a->_pvt)
@@ -315,10 +317,10 @@ void dap_chain_datum_notify(dap_chain_cell_t *a_chain_cell,  dap_hash_fast_t *a_
 void dap_chain_datum_removed_notify(dap_chain_cell_t *a_chain_cell,  dap_hash_fast_t *a_hash);
 void dap_chain_atom_add_from_threshold(dap_chain_t *a_chain);
 dap_chain_atom_ptr_t dap_chain_get_atom_by_hash(dap_chain_t * a_chain, dap_chain_hash_fast_t * a_atom_hash, size_t * a_atom_size);
-bool dap_chain_get_atom_last_hash_num(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);
+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_STATIC_INLINE bool dap_chain_get_atom_last_hash(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_atom_hash)
 {
-    return dap_chain_get_atom_last_hash_num(a_chain, a_cell_id, a_atom_hash, NULL);
+    return dap_chain_get_atom_last_hash_num_ts(a_chain, a_cell_id, a_atom_hash, NULL, NULL);
 }
 ssize_t dap_chain_atom_save(dap_chain_cell_t *a_chain_cell, const uint8_t *a_atom, size_t a_atom_size, dap_hash_fast_t *a_new_atom_hash);
 int dap_cert_chain_file_save(dap_chain_datum_t *datum, char *net_name);
diff --git a/modules/chain/include/dap_chain_srv.h b/modules/chain/include/dap_chain_srv.h
index 1ca29339d9f647059cca62b54361ddd682f04f7a..91be1dda009513ffeb53c7e4829bd23049cc28e2 100644
--- a/modules/chain/include/dap_chain_srv.h
+++ b/modules/chain/include/dap_chain_srv.h
@@ -41,8 +41,10 @@ typedef void (*dap_chain_srv_callback_decree_t)(dap_chain_net_id_t a_net_id, int
 typedef int (*dap_chain_srv_callback_purge_t)(dap_chain_net_id_t a_net_id);
 // Get fee service callback
 typedef json_object * (*dap_chain_srv_callback_get_fee)(dap_chain_net_id_t a_net_id);
-// Hardfork service callback
-typedef int (*dap_chain_srv_callback_hardfork_t)(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);
+// 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 *);
 
@@ -55,13 +57,23 @@ typedef struct dap_chain_static_srv_callbacks {
     dap_chain_srv_callback_purge_t purge;
     // Get service fee
     dap_chain_srv_callback_get_fee get_fee_descr;
-    // Hardfork
-    dap_chain_srv_callback_hardfork_t hardfork;
+    // Hardfork prepare
+    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;
 
+typedef struct dap_chain_srv_hardfork_state {
+    dap_chain_srv_uid_t uid;
+    byte_t *data;
+    uint64_t size;
+    uint32_t count;
+    struct dap_chain_srv_hardfork_state *prev, *next;
+} dap_chain_srv_hardfork_state_t;
+
 // Fees section
 typedef enum dap_chain_srv_fee_tsd_type {
     TSD_FEE = 0x0001,
@@ -107,5 +119,5 @@ dap_list_t *dap_chain_srv_list(dap_chain_net_id_t a_net_id);
 
 int dap_chain_srv_purge(dap_chain_net_id_t a_net_id, dap_chain_srv_uid_t a_srv_uid);
 int dap_chain_srv_purge_all(dap_chain_net_id_t a_net_id);
-void dap_chain_srv_hardfork_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);
 json_object *dap_chain_srv_get_fees(dap_chain_net_id_t a_net_id);
diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index ed9be96ca95993a2c53268eff58167f0e02ac73f..3c9d78d16e0f172639f564dbf2a50b104c900ea0 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -41,6 +41,8 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 
 #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,
@@ -213,11 +215,11 @@ void dap_chain_cs_esbocs_deinit(void)
 {
 }
 
-void dap_chain_esbocs_change_debug_mode(dap_chain_t *a_chain, bool a_enable){
-    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);    
-    dap_chain_esbocs_t *l_esbocs = l_blocks->_inheritor;
-    dap_chain_esbocs_pvt_t * l_esbocs_pvt = PVT(l_esbocs);    
-    l_esbocs_pvt->debug = a_enable;
+void dap_chain_esbocs_change_debug_mode(dap_chain_t *a_chain, bool a_enable)
+{
+    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
+    dap_chain_esbocs_t *l_esbocs = DAP_CHAIN_ESBOCS(l_blocks);
+    PVT(l_esbocs)->debug = a_enable;
 }
 
 static int s_callback_new(dap_chain_t *a_chain, dap_config_t *a_chain_cfg)
@@ -736,6 +738,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)
+{
+    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;
+    return a_block_num && a_block_num < l_last_num ? 1 : 0;
+}
+
 static int s_callback_purge(dap_chain_t *a_chain)
 {
     dap_return_val_if_fail(a_chain && !strcmp(dap_chain_get_cs_type(a_chain), DAP_CHAIN_ESBOCS_CS_TYPE_STR), -1);
@@ -1121,7 +1133,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, c_dap_chain_cell_id_null, &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);
     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))) {
@@ -1192,6 +1204,13 @@ static bool s_session_round_new(void *a_arg)
     a_session->new_round_enqueued = false;
     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);
+    }
     return false;
 }
 
@@ -1648,7 +1667,10 @@ static void s_session_candidate_submit(dap_chain_esbocs_session_t *a_session)
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(l_chain);
     size_t l_candidate_size = 0;
     dap_hash_fast_t l_candidate_hash = {0};
-    dap_chain_node_mempool_process_all(a_session->chain, false);
+    if (a_session->is_hardfork)
+        dap_chain_node_hardfork_process(a_session->chain);
+    else
+        dap_chain_node_mempool_process_all(a_session->chain, false);
     dap_chain_block_t *l_candidate = l_blocks->callback_new_block_move(l_blocks, &l_candidate_size);
     if (l_candidate && l_candidate_size) {
         if (PVT(a_session->esbocs)->emergency_mode)
@@ -1707,8 +1729,7 @@ static void s_session_candidate_verify(dap_chain_esbocs_session_t *a_session, da
     }
     // Process candidate
     a_session->processing_candidate = a_candidate;
-    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_session->chain);
-    dap_chain_atom_verify_res_t l_verify_status = l_blocks->chain->callback_atom_verify(l_blocks->chain, a_candidate, a_candidate_size, a_candidate_hash);
+    dap_chain_atom_verify_res_t l_verify_status = a_session->chain->callback_atom_verify(a_session->chain, a_candidate, a_candidate_size, a_candidate_hash);
     if (l_verify_status == ATOM_ACCEPT || l_verify_status == ATOM_FORK) {
         // validation - OK, gen event Approve
         s_message_send(a_session, DAP_CHAIN_ESBOCS_MSG_TYPE_APPROVE, a_candidate_hash,
@@ -2837,9 +2858,17 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_bl
     dap_chain_esbocs_t *l_esbocs = DAP_CHAIN_ESBOCS(a_blocks);
     dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(l_esbocs);
 
-    if (l_esbocs->session && l_esbocs->session->processing_candidate == a_block)
+    if (l_esbocs->session && l_esbocs->session->processing_candidate == a_block) {
         // It's a block candidate, don't check signs
-        return a_block->hdr.version > 1 ? 0 : -3;
+        if (a_block->hdr.version <= 1) {
+            log_it(L_WARNING, "Illegal block version %d", a_block->hdr.version);
+            return -3;
+        }
+        if (a_blocks->is_hardfork_state) {
+            // Addtionally verify datums vs internal states
+
+        }
+    }
 
     size_t l_block_size = a_block_size; // /* Can't calc it for many old bugged blocks */ dap_chain_block_get_size(a_block);
     size_t l_signs_count = 0;
diff --git a/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h b/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h
index 643bcc2c1f192acdc4277d741cac22bfcdd11216..c86591e1b449daf6a4aa4beb6a036140c6f0d324 100644
--- a/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h
+++ b/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h
@@ -23,7 +23,6 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 */
 #pragma once
 
-#include "dap_timerfd.h"
 #include "dap_chain.h"
 #include "dap_chain_block.h"
 #include "dap_chain_cs_blocks.h"
@@ -124,6 +123,8 @@ typedef struct dap_chain_esbocs {
     dap_chain_t *chain;
     dap_chain_cs_blocks_t *blocks;
     dap_chain_esbocs_session_t *session;
+    uint64_t hardfork_from;
+    dap_list_t *hardfork_trusted_addrs;
     dap_time_t last_directive_vote_timestamp, last_directive_accept_timestamp,
                last_submitted_candidate_timestamp, last_accepted_block_timestamp;
     void *_pvt;
@@ -197,7 +198,8 @@ typedef struct dap_chain_esbocs_session {
     unsigned int listen_ensure;
     dap_chain_node_addr_t my_addr;
     uint8_t state, old_state;
-    bool cs_timer, round_fast_forward, sync_failed, new_round_enqueued, is_actual_hash;
+    bool cs_timer, round_fast_forward, sync_failed,
+         new_round_enqueued, is_actual_hash, is_hardfork;
     dap_global_db_driver_hash_t db_hash;
     dap_chain_addr_t my_signing_addr;
 } dap_chain_esbocs_session_t;
@@ -266,5 +268,5 @@ 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);
 void dap_chain_esbocs_change_debug_mode(dap_chain_t *a_chain, bool a_enable);
diff --git a/modules/datum/dap_chain_datum_decree.c b/modules/datum/dap_chain_datum_decree.c
index e2f613465fc7df5721c6a5c110a3f366ed4c6283..bb2798467b37d176babd469dd35a60a7ae7294b3 100644
--- a/modules/datum/dap_chain_datum_decree.c
+++ b/modules/datum/dap_chain_datum_decree.c
@@ -71,7 +71,16 @@ int dap_chain_datum_decree_get_fee_addr(dap_chain_datum_decree_t *a_decree, dap_
 dap_list_t *dap_chain_datum_decree_get_owners(dap_chain_datum_decree_t *a_decree, uint16_t *a_owners_num)
 {
     dap_return_val_if_fail(a_decree && a_owners_num, NULL);
-    dap_list_t *l_ret = dap_tsd_find_all(a_decree->data_n_signs, a_decree->header.data_size, DAP_CHAIN_DATUM_DECREE_TSD_TYPE_OWNER);
+    dap_list_t *l_ret = dap_tsd_find_all(a_decree->data_n_signs, a_decree->header.data_size, DAP_CHAIN_DATUM_DECREE_TSD_TYPE_OWNER, 0);
+    dap_list_t *it, *tmp;
+    DL_FOREACH_SAFE(l_ret, it, tmp) {
+        dap_tsd_t *l_tsd = it->data;
+        if (l_tsd->size < sizeof(dap_pkey_t) || l_tsd->size != sizeof(dap_pkey_t) + ((dap_pkey_t *)l_tsd->data)->header.size) {
+            log_it(L_ERROR, "Incorrect size %u of owner pkey", l_tsd->size);
+            DL_DELETE(l_ret, it);
+            DAP_DEL_MULTY(it->data, it);
+        }
+    }
     if (a_owners_num)
         *a_owners_num = (uint16_t)dap_list_length(l_ret);
     return l_ret;
@@ -105,7 +114,7 @@ int dap_chain_datum_decree_get_stake_signing_addr(dap_chain_datum_decree_t *a_de
     return l_tsd && l_tsd->size == sizeof(dap_chain_addr_t) ? ( _dap_tsd_get_scalar(l_tsd, a_signing_addr), 0 ) : 1;
 }
 
-int dap_chain_datum_decree_get_stake_signer_node_addr(dap_chain_datum_decree_t *a_decree, dap_chain_node_addr_t *a_node_addr)
+int dap_chain_datum_decree_get_node_addr(dap_chain_datum_decree_t *a_decree, dap_chain_node_addr_t *a_node_addr)
 {
     dap_return_val_if_fail(a_decree && a_node_addr, -1);
     dap_tsd_t *l_tsd = dap_tsd_find(a_decree->data_n_signs, a_decree->header.data_size, DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR);
@@ -149,6 +158,13 @@ int dap_chain_datum_decree_get_ban_addr(dap_chain_datum_decree_t *a_decree, cons
     return l_tsd ? ( *a_addr = dap_tsd_get_string_const(l_tsd), !dap_strcmp(*a_addr, DAP_TSD_CORRUPTED_STRING) ) : 1;
 }
 
+int dap_chain_datum_decree_get_atom_num(dap_chain_datum_decree_t *a_decree, uint64_t *a_atom_num)
+{
+    dap_return_val_if_fail(a_decree && a_atom_num, -1);
+    dap_tsd_t *l_tsd = dap_tsd_find(a_decree->data_n_signs, a_decree->header.data_size, DAP_CHAIN_DATUM_DECREE_TSD_TYPE_BLOCK_NUM);
+    return l_tsd && l_tsd->size == sizeof(uint64_t) ? ( _dap_tsd_get_scalar(l_tsd, a_atom_num), 0 ) : 1;
+}
+
 /**
  * @brief get pkey from decree tsd
  * @param a_decree
@@ -329,7 +345,16 @@ void dap_chain_datum_decree_dump_json(json_object *a_json_out, dap_chain_datum_d
                 break;
             }
             json_object_object_add(a_json_out, "pkey type", json_object_new_string( dap_pkey_type_to_str(((dap_pkey_t *)(l_tsd->data))->header.type) ));
-            break; 
+            break;
+        case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_BLOCK_NUM:
+            if (l_tsd->size != sizeof(uint64_t)) {
+                json_object_object_add(a_json_out, "Signature type", json_object_new_string("WRONG SIZE"));
+                break;
+            }
+            uint64_t l_num = 0;
+            _dap_tsd_get_scalar(l_tsd, &l_type);
+            json_object_object_add(a_json_out, "Signature type", json_object_new_uint64(l_num));
+            break;
         default:
             json_object_object_add(a_json_out, "UNKNOWN_TYPE_TSD_SECTION", json_object_new_string(""));
             break;
diff --git a/modules/datum/dap_chain_datum_tx_items.c b/modules/datum/dap_chain_datum_tx_items.c
index b3c066ad7f26b745de70611dd0a5f4076427a0d8..67c32bbaecdabcba5cc45bb24e1aeff0b3f8c772 100644
--- a/modules/datum/dap_chain_datum_tx_items.c
+++ b/modules/datum/dap_chain_datum_tx_items.c
@@ -191,7 +191,8 @@ dap_chain_tx_in_reward_t *dap_chain_datum_tx_item_in_reward_create(dap_chain_has
 /**
  * Create tsd section
  */
-dap_chain_tx_tsd_t *dap_chain_datum_tx_item_tsd_create(void *a_data, int a_type, size_t a_size) {
+dap_chain_tx_tsd_t *dap_chain_datum_tx_item_tsd_create(const void *a_data, int a_type, size_t a_size)
+{
     if (!a_data || !a_size) {
         return NULL;
     }
@@ -279,6 +280,16 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_fee(uint256_t a
     return l_item;
 }
 
+dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_fee_stack(uint256_t a_value)
+{
+    dap_return_val_if_pass(IS_ZERO_256(a_value), NULL);
+    dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_tx_out_cond_t, NULL, NULL);
+    l_item->header.item_type = TX_ITEM_TYPE_OUT_COND;
+    l_item->header.value = a_value;
+    l_item->header.subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STACK;
+    return l_item;
+}
+
 /**
  * Create item dap_chain_tx_out_cond_t
  *
@@ -426,6 +437,19 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_emit_delega
     return l_item;
 }
 
+dap_chain_tx_sig_t *dap_chain_tx_sig_create(dap_sign_t *a_sign)
+{
+    dap_return_val_if_fail(a_sign, NULL);
+    size_t l_chain_sign_size = dap_sign_get_size(a_sign); // sign data
+    dap_chain_tx_sig_t *l_tx_sig = DAP_NEW_Z_SIZE_RET_VAL_IF_FAIL(dap_chain_tx_sig_t, sizeof(dap_chain_tx_sig_t)
+                                                                                      + l_chain_sign_size, NULL, NULL);
+    l_tx_sig->header.type = TX_ITEM_TYPE_SIG;
+    l_tx_sig->header.version = 1;
+    l_tx_sig->header.sig_size = (uint32_t)l_chain_sign_size;
+    memcpy(l_tx_sig->sig, a_sign, l_chain_sign_size);
+    return l_tx_sig;
+}
+
 /**
  * Create item dap_chain_tx_sig_t
  *
@@ -445,13 +469,9 @@ dap_chain_tx_sig_t *dap_chain_datum_tx_item_sign_create(dap_enc_key_t *a_key, da
     DAP_DELETE(l_tx);
     if (!l_chain_sign)
         return NULL;
-    size_t l_chain_sign_size = dap_sign_get_size(l_chain_sign); // sign data
-    dap_chain_tx_sig_t *l_tx_sig = DAP_NEW_Z_SIZE(dap_chain_tx_sig_t,
-            sizeof(dap_chain_tx_sig_t) + l_chain_sign_size);
-    l_tx_sig->header.type = TX_ITEM_TYPE_SIG;
-    l_tx_sig->header.version = 1;
-    l_tx_sig->header.sig_size = (uint32_t)l_chain_sign_size;
-    memcpy(l_tx_sig->sig, l_chain_sign, l_chain_sign_size);
+    dap_chain_tx_sig_t *l_tx_sig = dap_chain_tx_sig_create(l_chain_sign);
+    if (!l_tx_sig)
+        return NULL;
     DAP_DELETE(l_chain_sign);
     return l_tx_sig;
 }
diff --git a/modules/datum/include/dap_chain_datum_decree.h b/modules/datum/include/dap_chain_datum_decree.h
index da4a463cad660ee3718795f59a5f2fd6fa506273..9cb2ddda2942eb6d772dec69c76b27b14a8531c6 100644
--- a/modules/datum/include/dap_chain_datum_decree.h
+++ b/modules/datum/include/dap_chain_datum_decree.h
@@ -129,12 +129,15 @@ DAP_STATIC_INLINE const char *dap_chain_datum_decree_subtype_to_str(uint16_t a_d
         return "DECREE_COMMON_SUBTYPE_CHECK_SIGNS_STRUCTURE";
     case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_PKEY_UPDATE:
         return "DECREE_COMMON_SUBTYPE_STAKE_UPDATE";
+    case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK:
+        return "DECREE_COMMON_SUBTYPE_HARDFORK";
     default:
         return "DECREE_SUBTYPE_UNKNOWN";
     }
 }
 
-DAP_STATIC_INLINE uint16_t dap_chain_datum_decree_type_from_str(const char *a_decree_type) {
+DAP_STATIC_INLINE uint16_t dap_chain_datum_decree_type_from_str(const char *a_decree_type)
+{
     if (!dap_strcmp(a_decree_type, "fee")){
         return DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_FEE;
     } else if (!dap_strcmp(a_decree_type, "owners")) {
@@ -163,6 +166,8 @@ DAP_STATIC_INLINE uint16_t dap_chain_datum_decree_type_from_str(const char *a_de
         return DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_CHECK_SIGNS_STRUCTURE;
     } else if (!dap_strcmp(a_decree_type, "stake_update")) {
         return DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_PKEY_UPDATE;
+    } else if (!dap_strcmp(a_decree_type, "hardfork_prepare")) {
+        return DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK;
     } else {
         return 0;
     }
@@ -204,6 +209,8 @@ DAP_STATIC_INLINE const char *dap_chain_datum_decree_tsd_type_to_str(uint16_t a_
          return "DAP_CHAIN_DATUM_DECREE_TSD_TYPE_SIGNATURE_TYPE";
     case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_PKEY:
          return "DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_PKEY";
+    case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_BLOCK_NUM:
+         return "DAP_CHAIN_DATUM_DECREE_TSD_TYPE_BLOCK_NUM";
     default:
         return "DECREE_TSD_TYPE_UNKNOWN";
     }
@@ -286,12 +293,12 @@ int dap_chain_datum_decree_get_value(dap_chain_datum_decree_t *a_decree, uint256
 int dap_chain_datum_decree_get_stake_signing_addr(dap_chain_datum_decree_t *a_decree, dap_chain_addr_t *a_signing_addr);
 
 /**
- * @brief dap_chain_datum_decree_get_stake_signer_node_addr get signer node address
+ * @brief dap_chain_datum_decree_get_node_addr get signer node address
  * @param a_decree pointer to decree
  * @param a_node_addr pointer to signer node address buffer
  * @return result code. 0 - success
  */
-int dap_chain_datum_decree_get_stake_signer_node_addr(dap_chain_datum_decree_t *a_decree, dap_chain_node_addr_t *a_node_addr);
+int dap_chain_datum_decree_get_node_addr(dap_chain_datum_decree_t *a_decree, dap_chain_node_addr_t *a_node_addr);
 
 /**
  * @brief dap_chain_datum_decree_get_stake_min_value get minimum stake value
@@ -312,6 +319,7 @@ int dap_chain_datum_decree_get_action(dap_chain_datum_decree_t *a_decree, uint8_
 int dap_chain_datum_decree_get_signature_type(dap_chain_datum_decree_t *a_decree, uint32_t *a_signature_type);
 int dap_chain_datum_decree_get_ban_addr(dap_chain_datum_decree_t *a_decree, const char **a_addr);
 dap_pkey_t *dap_chain_datum_decree_get_pkey(dap_chain_datum_decree_t *a_decree);
+int dap_chain_datum_decree_get_atom_num(dap_chain_datum_decree_t *a_decree, uint64_t *a_atom_num);
 
 /**
  * @breif dap_chain_datum_decree_dump Dump information about decree
diff --git a/modules/datum/include/dap_chain_datum_tx_items.h b/modules/datum/include/dap_chain_datum_tx_items.h
index c8be707da1c3666b5b0c959d4097b450c8d99f08..397a10cdc243ebf0ad9f35f458c52de4b273ab0a 100644
--- a/modules/datum/include/dap_chain_datum_tx_items.h
+++ b/modules/datum/include/dap_chain_datum_tx_items.h
@@ -109,7 +109,7 @@ dap_chain_tx_in_t* dap_chain_datum_tx_item_in_create(dap_chain_hash_fast_t *a_tx
 
 dap_chain_tx_in_reward_t *dap_chain_datum_tx_item_in_reward_create(dap_chain_hash_fast_t *a_block_hash);
 
-dap_chain_tx_tsd_t *dap_chain_datum_tx_item_tsd_create(void *a_data, int a_type, size_t a_size);
+dap_chain_tx_tsd_t *dap_chain_datum_tx_item_tsd_create(const void *a_data, int a_type, size_t a_size);
 
 dap_chain_tx_in_cond_t* dap_chain_datum_tx_item_in_cond_create(dap_chain_hash_fast_t *a_tx_prev_hash, uint32_t a_tx_out_prev_idx,
                                                                uint32_t a_receipt_idx);
@@ -135,6 +135,13 @@ dap_chain_tx_out_ext_t* dap_chain_datum_tx_item_out_ext_create(const dap_chain_a
  */
 dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_fee(uint256_t a_value);
 
+/**
+ * Create item dap_chain_tx_out_cond_t with fee_stack subtype
+ *
+ * return item, NULL Error
+ */
+dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_fee_stack(uint256_t a_value);
+
 /**
  * Create item dap_chain_tx_out_cond_t
  *
@@ -178,6 +185,13 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_emit_delega
                                                                                    uint32_t a_signs_min, dap_hash_fast_t *a_pkey_hashes,
                                                                                    size_t a_pkey_hashes_count);
 
+/**
+ * Create item dap_chain_tx_sig_t
+ *
+ * return item, NULL Error
+ */
+dap_chain_tx_sig_t *dap_chain_tx_sig_create(dap_sign_t *a_sign);
+
 /**
  * Create item dap_chain_tx_sig_t
  *
diff --git a/modules/datum/include/dap_chain_datum_tx_out_cond.h b/modules/datum/include/dap_chain_datum_tx_out_cond.h
index c765295b495278e152d52381d88bf6054204e2b3..e743afd559f710946ff73fe4ad8f0b1eecf057c0 100644
--- a/modules/datum/include/dap_chain_datum_tx_out_cond.h
+++ b/modules/datum/include/dap_chain_datum_tx_out_cond.h
@@ -37,6 +37,7 @@ enum dap_chain_tx_out_cond_subtype {
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE = 0x04,
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK = 0x06,
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_EMIT_DELEGATE = 0x07,
+    DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE_STACK = 0x08,
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_ALL = 0xFF
 };
 typedef byte_t dap_chain_tx_out_cond_subtype_t;
diff --git a/modules/datum/include/dap_chain_datum_tx_tsd.h b/modules/datum/include/dap_chain_datum_tx_tsd.h
index 810988af0fe298a81232abe52b13ed9f66350c12..d63d96d244fe09be2fbf7e147ba323748bcb70b3 100644
--- a/modules/datum/include/dap_chain_datum_tx_tsd.h
+++ b/modules/datum/include/dap_chain_datum_tx_tsd.h
@@ -4,6 +4,10 @@
 #include "dap_chain_common.h"
 #include "dap_tsd.h"
 
+#define DAP_CHAIN_DATUM_TX_TSD_TYPE_HARDFORK_TICKER         0xf001
+#define DAP_CHAIN_DATUM_TX_TSD_TYPE_HARDFORK_TX_HASH        0xf002
+#define DAP_CHAIN_DATUM_TX_TSD_TYPE_HARDFORK_TRACKER        0xf0fa
+
 typedef struct dap_chain_tx_tsd {
     struct {
         dap_chain_tx_item_type_t type;
diff --git a/modules/ledger/dap_chain_ledger_decree.c b/modules/ledger/dap_chain_ledger_decree.c
index 1756af8d5eb44af543d41e2c8e43ecf1e2e0e5af..e30532b2698792cdbe9f00d92e37f39ac9c80dd7 100644
--- a/modules/ledger/dap_chain_ledger_decree.c
+++ b/modules/ledger/dap_chain_ledger_decree.c
@@ -328,15 +328,16 @@ static bool s_verify_pkey (dap_sign_t *a_sign, dap_chain_net_t *a_net)
 
 static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain_net_t *a_net, bool a_apply, bool a_anchored)
 {
-    uint256_t l_value;
-    uint32_t l_sign_type;
-    uint16_t l_owners_num;
-    uint8_t l_action;
-    dap_chain_addr_t l_addr = {};
-    dap_hash_fast_t l_hash = {};
-    dap_chain_node_addr_t l_node_addr = {};
-    dap_list_t *l_owners_list = NULL;
-    const char *l_ban_addr;
+uint256_t l_value;
+uint64_t l_block_num;
+uint32_t l_sign_type;
+uint16_t l_owners_num;
+uint8_t l_action;
+dap_chain_addr_t l_addr = {};
+dap_hash_fast_t l_hash = {};
+dap_chain_node_addr_t l_node_addr = {};
+dap_list_t *l_owners_list = NULL;
+const char *l_ban_addr;
 
     dap_return_val_if_fail(a_decree && a_net, -112);
 
@@ -398,7 +399,7 @@ static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain
                 log_it(L_WARNING,"Can't get signing address from decree.");
                 return -107;
             }
-            if (dap_chain_datum_decree_get_stake_signer_node_addr(a_decree, &l_node_addr)){
+            if (dap_chain_datum_decree_get_node_addr(a_decree, &l_node_addr)){
                 log_it(L_WARNING,"Can't get signer node address from decree.");
                 return -108;
             }
@@ -525,8 +526,8 @@ static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain
             if (!a_apply)
                 break;
             uint64_t l_cur_block_num = l_chain->callback_count_atom(l_chain);
-            dap_chain_net_add_reward(a_net, l_value, l_cur_block_num);
-        } break;
+            return dap_chain_net_add_reward(a_net, l_value, l_cur_block_num);
+        }
         case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_MAX_WEIGHT: {
             if (dap_chain_datum_decree_get_value(a_decree, &l_value)) {
                 log_it(L_WARNING,"Can't get value from decree.");
@@ -548,10 +549,11 @@ static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain
             if (!a_apply)
                 break;
             dap_chain_net_srv_stake_set_percent_max(a_net->pub.id, l_value);
-        } break;
+            return 0;
+        }
         case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_CHECK_SIGNS_STRUCTURE: {
             if (dap_chain_datum_decree_get_action(a_decree, &l_action)) {
-                log_it(L_WARNING,"Can't get action from decree.");
+                log_it(L_WARNING, "Can't get action from decree.");
                 return -103;
             }
             dap_chain_t *l_chain = dap_chain_find_by_id(a_net->pub.id, a_decree->header.common_decree_params.chain_id);
@@ -565,8 +567,8 @@ static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain
             }
             if (!a_apply)
                 break;
-            dap_chain_esbocs_set_signs_struct_check(l_chain, l_action);
-        } break;
+            return dap_chain_esbocs_set_signs_struct_check(l_chain, l_action);
+        }
         case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_EMERGENCY_VALIDATORS: {
             if (dap_chain_datum_decree_get_action(a_decree, &l_action)) {
                 log_it(L_WARNING,"Can't get action from decree.");
@@ -591,8 +593,27 @@ static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain
             }
             if (!a_apply)
                 break;
-            dap_chain_esbocs_set_emergency_validator(l_chain, l_action, l_sign_type, &l_hash);
-        } break;
+            return dap_chain_esbocs_set_emergency_validator(l_chain, l_action, l_sign_type, &l_hash);
+        }
+        case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK:
+            if (dap_chain_datum_decree_get_atom_num(a_decree, &l_block_num)) {
+                log_it(L_WARNING, "Can't get atom number from hardfork prepare decree");
+                return -103;
+            }
+            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;
+            }
+            if (!a_apply)
+                break;
+            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));
+            return dap_chain_esbocs_set_hardfork_prepare(l_chain, l_block_num, l_addrs);
         default:
             return -1;
     }
@@ -632,26 +653,75 @@ const dap_list_t *dap_ledger_decree_get_owners_pkeys(dap_ledger_t *a_ledger)
     return PVT(a_ledger)->decree_owners_pkeys;
 }
 
-static int s_compare_anchors(dap_ledger_hardfork_anchors_t *a_list1, dap_ledger_hardfork_anchors_t *a_list2)
+static bool s_compare_anchors(dap_ledger_t *a_ledger, dap_ledger_hardfork_anchors_t *a_exist, dap_ledger_hardfork_anchors_t *a_comp)
 {
-    return a_list1->decree_subtype != a_list2->decree_subtype;
+    bool l_stake_type = false, l_ban_type = false;
+    switch (a_comp->decree_subtype) {
+    case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_APPROVE:
+    case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE:
+        if (a_exist->decree_subtype != DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_APPROVE &&
+                a_exist->decree_subtype != DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE)
+            return false;
+        l_stake_type = true;
+        break;
+    case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_BAN:
+    case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_UNBAN:
+        if (a_exist->decree_subtype != DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_BAN &&
+                a_exist->decree_subtype != DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_UNBAN)
+            return false;
+        l_ban_type = true;
+        break;
+    default:
+        return a_exist->decree_subtype == a_comp->decree_subtype;
+    }
+    dap_hash_fast_t l_exist_hash = {}, l_comp_hash = {};
+    dap_chain_datum_anchor_get_hash_from_data(a_comp->anchor, &l_comp_hash);
+    dap_chain_datum_anchor_get_hash_from_data(a_exist->anchor, &l_exist_hash);
+    dap_chain_datum_decree_t *l_comp_decree = dap_ledger_decree_get_by_hash(a_ledger->net, &l_comp_hash, NULL);
+    dap_chain_datum_decree_t *l_exist_decree = dap_ledger_decree_get_by_hash(a_ledger->net, &l_exist_hash, NULL);
+    if (l_ban_type) {
+        const char *l_comp_ban_addr = NULL, *l_exist_ban_addr = NULL;
+        dap_chain_datum_decree_get_ban_addr(l_comp_decree, &l_comp_ban_addr);
+        dap_chain_datum_decree_get_ban_addr(l_exist_decree, &l_exist_ban_addr);
+        if (!dap_strcmp(l_comp_ban_addr, l_exist_ban_addr))
+            return true;
+        return false;
+    }
+    if (l_stake_type) {
+        dap_chain_addr_t l_comp_addr = {}, l_exist_addr = {};
+        dap_chain_datum_decree_get_stake_signing_addr(l_comp_decree, &l_comp_addr);
+        dap_chain_datum_decree_get_stake_signing_addr(l_exist_decree, &l_exist_addr);
+        if (!dap_chain_addr_is_blank(&l_comp_addr) && dap_chain_addr_compare(&l_comp_addr, &l_exist_addr))
+            return true;
+        return false;
+    }
+    return assert(false), false;
 }
 
 
-int s_aggregate_anchor(dap_ledger_hardfork_anchors_t **a_out_list, uint16_t a_subtype, dap_chain_datum_anchor_t *a_anchor)
+int s_aggregate_anchor(dap_ledger_t *a_ledger, dap_ledger_hardfork_anchors_t **a_out_list, uint16_t a_subtype, dap_chain_datum_anchor_t *a_anchor)
 {
     dap_ledger_hardfork_anchors_t l_new_anchor = { .anchor = a_anchor, .decree_subtype = a_subtype };
-    dap_ledger_hardfork_anchors_t *l_exist = NULL;
-    DL_SEARCH(*a_out_list, l_exist, &l_new_anchor, s_compare_anchors);
+    dap_ledger_hardfork_anchors_t *l_exist = NULL, *l_tmp;
+    DL_FOREACH_SAFE(*a_out_list, l_exist, l_tmp)
+        if (s_compare_anchors(a_ledger, l_exist, &l_new_anchor))
+            break;
     if (!l_exist) {
         l_exist = DAP_DUP(&l_new_anchor);
         if (!l_exist) {
             log_it(L_CRITICAL, "%s", c_error_memory_alloc);
             return -1;
         }
-        DL_APPEND(*a_out_list, l_exist);
-    } else
-        l_exist->anchor = a_anchor;
+        if (a_subtype != DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE && 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);
+            DL_DELETE(*a_out_list, l_exist);
+        } else
+            l_exist->anchor = a_anchor;
+    }
     return 0;
 }
 
@@ -670,7 +740,12 @@ dap_ledger_hardfork_anchors_t *dap_ledger_anchors_aggregate(dap_ledger_t *a_ledg
                                             l_anchor_hash_str, dap_hash_fast_to_str_static(&it->decree_hash));
                 continue;
             }
-            s_aggregate_anchor(&ret, it->decree->header.sub_type, l_anchor);
+            dap_hash_fast_t l_decree_hash;
+            if (dap_chain_datum_anchor_get_hash_from_data(l_anchor, &l_decree_hash)) {
+                log_it(L_ERROR, "Corrupted datum anchor %s, can't get decree hash from it", dap_hash_fast_to_str_static(&it->anchor_hash));
+                continue;
+            }
+            s_aggregate_anchor(a_ledger, &ret, it->decree->header.sub_type, l_anchor);
         }
     pthread_rwlock_unlock(&l_ledger_pvt->decrees_rwlock);
     return ret;
diff --git a/modules/ledger/dap_chain_ledger_tx.c b/modules/ledger/dap_chain_ledger_tx.c
index 3808b0dbedecaba09d52a74628374f129aa92c84..5a199adf42e02b4978571122a494021a3491d1ad 100644
--- a/modules/ledger/dap_chain_ledger_tx.c
+++ b/modules/ledger/dap_chain_ledger_tx.c
@@ -1175,7 +1175,7 @@ int s_compare_trackers(dap_list_t *a_tracker1, dap_list_t *a_tracker2)
     return memcmp(&l_tracker1->voting_hash, &l_tracker2->voting_hash, sizeof(dap_hash_fast_t));
 }
 
-dap_list_t *s_trackers_concatenate(dap_ledger_t *a_ledger, dap_list_t *a_trackers, dap_list_t *a_added, dap_time_t a_ts_creation_time)
+dap_list_t *s_trackers_aggregate(dap_ledger_t *a_ledger, dap_list_t *a_trackers, dap_list_t *a_added, dap_time_t a_ts_creation_time)
 {
     if (!s_voting_callbacks.voting_expire_callback)
         return a_trackers;
@@ -1363,7 +1363,7 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
         // Gather colour information from previous outputs
         dap_ledger_tx_item_t *l_prev_item_out = l_bound_item->prev_item;
         l_prev_item_out->out_metadata[l_bound_item->prev_out_idx].tx_spent_hash_fast = *a_tx_hash;
-        l_trackers_mover = s_trackers_concatenate(a_ledger, l_trackers_mover,
+        l_trackers_mover = s_trackers_aggregate(a_ledger, l_trackers_mover,
                                                   l_prev_item_out->out_metadata[l_bound_item->prev_out_idx].trackers, a_tx->header.ts_created);
         // add a used output
         l_prev_item_out->cache_data.n_outs_used++;
@@ -1401,7 +1401,7 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
         assert(l_vote_tx_item);
         l_new_tracker->voting_hash = l_vote_tx_item->voting_hash;
         dap_list_t *l_new_vote = dap_list_append(NULL, l_new_tracker);
-        l_trackers_mover = s_trackers_concatenate(a_ledger, l_trackers_mover, l_new_vote, a_tx->header.ts_created);
+        l_trackers_mover = s_trackers_aggregate(a_ledger, l_trackers_mover, l_new_vote, a_tx->header.ts_created);
     }
 
     //Update balance : raise
@@ -1951,7 +1951,30 @@ int dap_ledger_tx_load(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_c
     return dap_ledger_tx_add(a_ledger, a_tx, a_tx_hash, false, a_datum_index_data);
 }
 
+int dap_ledger_tx_load_hardfork_data(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_hash_fast_t *a_tx_hash, dap_ledger_datum_iter_data_t *a_datum_index_data)
+{
+    dap_return_val_if_fail(a_ledger && a_tx && a_tx_hash, -1);
 
+    byte_t *l_item = NULL;
+    size_t l_tx_item_size = 0;
+    TX_ITEM_ITER_TX(l_item, l_tx_item_size, a_tx) {
+        if (*l_item != TX_ITEM_TYPE_TSD)
+            continue;
+        dap_tsd_t *l_tsd = (dap_tsd_t *)((dap_chain_tx_tsd_t *)l_item)->tsd;
+        if (l_tsd->type != DAP_CHAIN_DATUM_TX_TSD_TYPE_HARDFORK_TRACKER)
+            continue;
+        if (l_tsd->size != sizeof(dap_ledger_tracker_t))
+            return log_it(L_ERROR, "Incorrect size of TSD tracker section %u (need %zu)", l_tsd->size, sizeof(dap_ledger_tracker_t)), -2;
+        dap_ledger_tx_item_t *l_item_tx = NULL;
+        s_tx_find_by_hash(a_ledger, a_tx_hash, &l_item_tx, true);
+        if (!l_item_tx)
+            return log_it(L_ERROR, "Can't find hardfork tx %s in ledger", dap_hash_fast_to_str_static(a_tx_hash)), -3;
+        if (l_item_tx->cache_data.n_outs != 1)
+            return log_it(L_ERROR, "Can't add hardfork data to tx %s cause it's not a single-out tx", dap_hash_fast_to_str_static(a_tx_hash)), -4;
+        l_item_tx->out_metadata[0].trackers = dap_list_append(l_item_tx->out_metadata[0].trackers, l_tsd->data);
+    }
+    return 0;
+}
 
 static void s_ledger_stake_lock_cache_update(dap_ledger_t *a_ledger, dap_ledger_stake_lock_item_t *a_stake_lock_item)
 {
@@ -2423,27 +2446,27 @@ static int s_aggregate_out(dap_ledger_hardfork_balances_t **a_out_list, dap_ledg
                                     dap_chain_addr_to_str_static(a_addr), a_ticker, dap_uint256_to_char(a_value, NULL));
         return -2;
     }
-    l_exist->trackers = s_trackers_concatenate(a_ledger, l_exist->trackers, a_trackers, a_hardfork_start_time);
+    l_exist->trackers = s_trackers_aggregate(a_ledger, l_exist->trackers, a_trackers, a_hardfork_start_time);
     return 0;
 }
 
 static int s_aggregate_out_cond(dap_ledger_hardfork_condouts_t **a_ret_list, dap_ledger_t *a_ledger,
-                                dap_chain_tx_out_cond_t *a_out_cond, dap_sign_t *a_sign,
-                                dap_hash_fast_t *a_tx_hash, dap_time_t a_hardfork_start_time,
-                                dap_list_t *a_trackers)
+                                dap_chain_tx_out_cond_t *a_out_cond, dap_chain_tx_sig_t *a_sign,
+                                dap_hash_fast_t *a_tx_hash, const char *a_token_ticker,
+                                dap_time_t a_hardfork_start_time, dap_list_t *a_trackers)
 {
     dap_ledger_hardfork_condouts_t *l_new_condout = DAP_NEW_Z(dap_ledger_hardfork_condouts_t);
     if (!l_new_condout) {
         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 };
-    l_new_condout->trackers = s_trackers_concatenate(a_ledger, NULL, a_trackers, a_hardfork_start_time);
+    *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->trackers = s_trackers_aggregate(a_ledger, NULL, a_trackers, a_hardfork_start_time);
     DL_APPEND(*a_ret_list, l_new_condout);
     return 0;
 }
 
-dap_ledger_hardfork_balances_t *dap_ledger_states_aggregate(dap_ledger_t *a_ledger, dap_time_t a_hardfork_decree_creatiom_time, dap_ledger_hardfork_condouts_t **l_cond_outs_list)
+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)
 {
     dap_ledger_hardfork_balances_t *ret = NULL;
     dap_ledger_hardfork_condouts_t *l_cond_ret = NULL;
@@ -2465,17 +2488,17 @@ dap_ledger_hardfork_balances_t *dap_ledger_states_aggregate(dap_ledger_t *a_ledg
             switch(l_tx_item_type) {
             case TX_ITEM_TYPE_OUT: {
                 dap_chain_tx_out_t *l_out = (dap_chain_tx_out_t *)l_tx_item;
-                s_aggregate_out(&ret, a_ledger, it->cache_data.token_ticker, &l_out->addr, l_out->header.value, a_hardfork_decree_creatiom_time, l_trackers);
+                s_aggregate_out(&ret, a_ledger, it->cache_data.token_ticker, &l_out->addr, l_out->header.value, a_hardfork_decree_creation_time, l_trackers);
                 break;
             }
             case TX_ITEM_TYPE_OUT_OLD: {
                 dap_chain_tx_out_old_t *l_out = (dap_chain_tx_out_old_t *)l_tx_item;
-                s_aggregate_out(&ret, a_ledger, it->cache_data.token_ticker, &l_out->addr, GET_256_FROM_64(l_out->header.value), a_hardfork_decree_creatiom_time, l_trackers);
+                s_aggregate_out(&ret, a_ledger, it->cache_data.token_ticker, &l_out->addr, GET_256_FROM_64(l_out->header.value), a_hardfork_decree_creation_time, l_trackers);
                 break;
             }
             case TX_ITEM_TYPE_OUT_EXT: {
                 dap_chain_tx_out_ext_t *l_out = (dap_chain_tx_out_ext_t *)l_tx_item;
-                s_aggregate_out(&ret, a_ledger, l_out->token, &l_out->addr, l_out->header.value, a_hardfork_decree_creatiom_time, l_trackers);
+                s_aggregate_out(&ret, a_ledger, l_out->token, &l_out->addr, l_out->header.value, a_hardfork_decree_creation_time, l_trackers);
                 break;
             }
             case TX_ITEM_TYPE_OUT_COND: {
@@ -2489,12 +2512,12 @@ dap_ledger_hardfork_balances_t *dap_ledger_states_aggregate(dap_ledger_t *a_ledg
                     log_it(L_ERROR, "Can't find header TX for conditional TX %s", dap_hash_fast_to_str_static(&it->tx_hash_fast));
                     continue;
                 }
-                dap_sign_t *l_tx_sign = dap_chain_datum_tx_get_sign(l_tx, 0);
+                dap_chain_tx_sig_t *l_tx_sign = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get_nth(l_tx, TX_ITEM_TYPE_SIG, 0);
                 if (!l_tx_sign) {
                     log_it(L_ERROR, "Can't find sign for conditional TX %s", dap_hash_fast_to_str_static(&l_first_tx_hash));
                     continue;
                 }
-                s_aggregate_out_cond(&l_cond_ret, a_ledger, l_out, l_tx_sign, &it->tx_hash_fast, a_hardfork_decree_creatiom_time, l_trackers);
+                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);
             }
             default:
                 log_it(L_ERROR, "Unexpected item type %hhu", l_tx_item_type);
diff --git a/modules/ledger/include/dap_chain_ledger.h b/modules/ledger/include/dap_chain_ledger.h
index 5892b17f3d862b2ef54242663b61c111e5386823..e68e2e839592742856f68162a63283516012af90 100644
--- a/modules/ledger/include/dap_chain_ledger.h
+++ b/modules/ledger/include/dap_chain_ledger.h
@@ -43,13 +43,14 @@
 
 typedef struct dap_ledger {
     dap_chain_net_t *net;
+    bool is_hardfork_state;
     void *_internal;
 } dap_ledger_t;
 
 typedef struct dap_ledger_tracker {
     dap_hash_fast_t voting_hash;
     uint256_t colored_value;
-} dap_ledger_tracker_t;
+} DAP_ALIGN_PACKED dap_ledger_tracker_t;
 
 typedef struct dap_ledger_hardfork_balances {
     dap_chain_addr_t addr;
@@ -62,7 +63,8 @@ typedef struct dap_ledger_hardfork_balances {
 typedef struct dap_ledger_hardfork_condouts {
     dap_hash_fast_t hash;
     dap_chain_tx_out_cond_t *cond;
-    dap_sign_t *sign;
+    dap_chain_tx_sig_t *sign;
+    const char *ticker;
     dap_list_t *trackers;
     struct dap_ledger_hardfork_condouts *prev, *next;
 } dap_ledger_hardfork_condouts_t;
@@ -304,9 +306,9 @@ DAP_STATIC_INLINE char *dap_ledger_get_gdb_group(dap_ledger_t *a_ledger, const c
  * return 1 OK, -1 error
  */
 int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, bool a_from_threshold, dap_ledger_datum_iter_data_t *a_datum_index_data);
+int dap_ledger_tx_load_hardfork_data(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_hash_fast_t *a_tx_hash, dap_ledger_datum_iter_data_t *a_datum_index_data);
 int dap_ledger_tx_load(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_hash_fast_t *a_tx_hash, dap_ledger_datum_iter_data_t *a_datum_index_data);
 int dap_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash);
-
 int dap_ledger_tx_add_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, size_t a_datum_size, dap_hash_fast_t *a_datum_hash);
 
 /**
@@ -501,7 +503,7 @@ int dap_ledger_anchor_load(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_c
 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);
 
-dap_ledger_hardfork_balances_t *dap_ledger_states_aggregate(dap_ledger_t *a_ledger, dap_time_t a_hardfork_decree_creatiom_time, dap_ledger_hardfork_condouts_t **l_cond_outs_list);
+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);
 dap_ledger_hardfork_anchors_t *dap_ledger_anchors_aggregate(dap_ledger_t *a_ledger);
 
 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_prev_hash, int a_out_idx);
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index 393cf39417947c1a9754f26247b2a98999308db4..8555094d68e2ce8f143b3229570525ece92a5282 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -124,7 +124,7 @@ char *dap_chain_mempool_datum_add(const dap_chain_datum_t *a_datum, dap_chain_t
         DAP_DATUM_TYPE_STR(a_datum->header.type_id, l_type_str);
     }
 
-    char *l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+    char *l_gdb_group = dap_chain_mempool_group_new(a_chain);
     int l_res = dap_global_db_set_sync(l_gdb_group, l_key_str, a_datum, dap_chain_datum_size(a_datum), false);//, NULL, NULL);
     if (l_res == DAP_GLOBAL_DB_RC_SUCCESS)
         log_it(L_NOTICE, "Datum %s with hash %s was placed in mempool group %s", l_type_str, l_key_str_out, l_gdb_group);
@@ -748,7 +748,7 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
 
     }
     dap_list_free_full(l_list_used_out, NULL);
-    char *l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+    char *l_gdb_group = dap_chain_mempool_group_new(a_chain);
     dap_global_db_set_multiple_zc(l_gdb_group, l_objs, a_tx_num, s_tx_create_massive_gdb_save_callback, NULL);
     DAP_DEL_Z(l_gdb_group);
     return 0;
@@ -1162,7 +1162,7 @@ dap_chain_datum_token_emission_t *dap_chain_mempool_emission_get(dap_chain_t *a_
 dap_chain_datum_t *dap_chain_mempool_datum_get(dap_chain_t *a_chain, const char *a_datum_hash_str)
 {
     size_t l_datum_size;
-    char *l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+    char *l_gdb_group = dap_chain_mempool_group_new(a_chain);
     dap_chain_datum_t *l_datum = (dap_chain_datum_t *)dap_global_db_get_sync(l_gdb_group,
                                                     a_datum_hash_str, &l_datum_size, NULL, NULL );
     if (!l_datum) {
@@ -1223,245 +1223,6 @@ dap_chain_datum_token_emission_t *dap_chain_mempool_datum_emission_extract(dap_c
     return DAP_DUP_SIZE(l_emission, l_datum->header.data_size);
 }
 
-uint8_t* dap_datum_mempool_serialize(dap_datum_mempool_t *datum_mempool, size_t *size)
-{
-    size_t a_request_size = 2 * sizeof(uint16_t), shift_size = 0;
-    for(int i = 0; i < datum_mempool->datum_count; i++) {
-        a_request_size += dap_chain_datum_size(datum_mempool->data[i]) + sizeof(uint16_t);
-    }
-    uint8_t *l_ret = DAP_NEW_Z_SIZE_RET_VAL_IF_FAIL(uint8_t, a_request_size, NULL);
-    uint8_t *l_pos = dap_mempcpy(l_ret, &datum_mempool->version, sizeof(uint16_t));
-    l_pos = dap_mempcpy(l_pos, &datum_mempool->datum_count, sizeof(uint16_t));
-    for(int i = 0; i < datum_mempool->datum_count; i++) {
-        size_t size_one = dap_chain_datum_size(datum_mempool->data[i]);
-        l_pos = dap_mempcpy( dap_mempcpy(l_pos, &size_one, sizeof(uint16_t)), datum_mempool->data[i], size_one );
-    }
-    assert((size_t)(l_pos - l_ret) == a_request_size);
-    if(size)
-        *size = a_request_size;
-    return l_ret;
-}
-
-dap_datum_mempool_t * dap_datum_mempool_deserialize(uint8_t *a_datum_mempool_ser, size_t a_datum_mempool_ser_size)
-{
-    size_t shift_size = 0;
-    //uint8_t *a_datum_mempool_ser = DAP_NEW_Z_SIZE(uint8_t, datum_mempool_size / 2 + 1);
-    //datum_mempool_size = hex2bin(a_datum_mempool_ser, datum_mempool_str_in, datum_mempool_size) / 2;
-    dap_datum_mempool_t *datum_mempool = DAP_NEW_Z(dap_datum_mempool_t);
-    if (!datum_mempool) {
-        log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-        return NULL;
-    }
-    datum_mempool->version = *(uint16_t*)(a_datum_mempool_ser + shift_size);
-    shift_size += sizeof(uint16_t);
-    datum_mempool->datum_count = *(uint16_t*)(a_datum_mempool_ser + shift_size);
-    shift_size += sizeof(uint16_t);
-    datum_mempool->data = DAP_NEW_Z_SIZE(dap_chain_datum_t*, datum_mempool->datum_count * sizeof(dap_chain_datum_t*));
-    for(int i = 0; i < datum_mempool->datum_count; i++) {
-        uint16_t size_one = *(uint16_t*)(a_datum_mempool_ser + shift_size);
-        shift_size += sizeof(uint16_t);
-        datum_mempool->data[i] = DAP_DUP((dap_chain_datum_t*)(a_datum_mempool_ser + shift_size));
-        shift_size += size_one;
-    }
-    assert(shift_size == a_datum_mempool_ser_size);
-    return datum_mempool;
-}
-
-void dap_datum_mempool_clean(dap_datum_mempool_t *datum)
-{
-    if(!datum)
-        return;
-    for(int i = 0; i < datum->datum_count; i++) {
-        DAP_DELETE(datum->data[i]);
-    }
-    DAP_DELETE(datum->data);
-    datum->data = NULL;
-}
-
-void dap_datum_mempool_free(dap_datum_mempool_t *datum)
-{
-    dap_datum_mempool_clean(datum);
-    DAP_DELETE(datum);
-}
-
-/**
- *
- */
-static char* s_calc_datum_hash(const void *a_datum_str, size_t datum_size)
-{
-    dap_chain_hash_fast_t a_hash;
-    dap_hash_fast( a_datum_str, datum_size, &a_hash);
-    size_t a_str_max = (sizeof(a_hash.raw) + 1) * 2 + 2; /* heading 0x */
-    char *a_str = DAP_NEW_Z_SIZE(char, a_str_max);
-
-//    size_t hash_len = dap_chain_hash_fast_to_str(&a_hash, a_str, a_str_max);
-    dap_chain_hash_fast_to_str(&a_hash, a_str, a_str_max);
-
-//    if(!hash_len) {
-//        DAP_DELETE(a_str);
-//        return NULL;
-//    }
-
-    return a_str;
-}
-
-static void enc_http_reply_encode_new(struct dap_http_simple *a_http_simple, dap_enc_key_t * key,
-        enc_http_delegate_t * a_http_delegate)
-{
-    //dap_enc_key_t * key = dap_enc_ks_find_http(a_http_simple->http);
-    if(key == NULL) {
-        log_it(L_ERROR, "Can't find http key.");
-        return;
-    }
-    if(a_http_delegate->response) {
-
-        if(a_http_simple->reply)
-            DAP_DELETE(a_http_simple->reply);
-
-        size_t l_reply_size_max = dap_enc_code_out_size(a_http_delegate->key,
-                a_http_delegate->response_size,
-                DAP_ENC_DATA_TYPE_RAW);
-
-        a_http_simple->reply = DAP_NEW_SIZE(void, l_reply_size_max);
-        a_http_simple->reply_size = dap_enc_code(a_http_delegate->key,
-                a_http_delegate->response, a_http_delegate->response_size,
-                a_http_simple->reply, l_reply_size_max,
-                DAP_ENC_DATA_TYPE_RAW);
-
-        /*/ decode test
-         size_t l_response_dec_size_max = a_http_simple->reply_size ? a_http_simple->reply_size * 2 + 16 : 0;
-         char * l_response_dec = a_http_simple->reply_size ? DAP_NEW_Z_SIZE(char, l_response_dec_size_max) : NULL;
-         size_t l_response_dec_size = 0;
-         if(a_http_simple->reply_size)
-         l_response_dec_size = dap_enc_decode(a_http_delegate->key,
-         a_http_simple->reply, a_http_simple->reply_size,
-         l_response_dec, l_response_dec_size_max,
-         DAP_ENC_DATA_TYPE_RAW);
-         l_response_dec_size_max = 0;*/
-    }
-
-}
-
-/**
- * @brief
- * @param cl_st HTTP server instance
- * @param arg for return code
- */
-void chain_mempool_proc(struct dap_http_simple *cl_st, void * arg)
-{
-    http_status_code_t * return_code = (http_status_code_t*) arg;
-    // save key while it alive, i.e. still exist
-    dap_enc_key_t *l_enc_key = dap_enc_ks_find_http(cl_st->http_client);
-    //dap_enc_key_serialize_t *key_ser = dap_enc_key_serialize(key_tmp);
-    //dap_enc_key_t *key = dap_enc_key_deserialize(key_ser, sizeof(dap_enc_key_serialize_t));
-
-    // read header
-    dap_http_header_t *hdr_session_close_id =
-            (cl_st->http_client) ? dap_http_header_find(cl_st->http_client->in_headers, "SessionCloseAfterRequest") : NULL;
-    dap_http_header_t *hdr_key_id =
-            (hdr_session_close_id && cl_st->http_client) ? dap_http_header_find(cl_st->http_client->in_headers, "KeyID") : NULL;
-
-    enc_http_delegate_t *l_enc_delegate = enc_http_request_decode(cl_st);
-    if(l_enc_delegate) {
-        char *suburl = l_enc_delegate->url_path;
-        byte_t *l_request_data = l_enc_delegate->request_bytes;
-        size_t l_request_size = l_enc_delegate->request_size;
-        const char * l_gdb_datum_pool = dap_config_get_item_str_default(g_config, "mempool", "gdb_group", "datum-pool");
-        //printf("!!***!!! chain_mempool_proc arg=%d suburl=%s str=%s len=%d\n", arg, suburl, request_str, request_size);
-        if(l_request_data && l_request_size > 1) {
-            //  find what to do
-            uint8_t action = DAP_DATUM_MEMPOOL_NONE; //*(uint8_t*) request_str;
-            if(l_enc_delegate->url_path_size > 0) {
-                if(!strcmp(suburl, "add"))
-                    action = DAP_DATUM_MEMPOOL_ADD;
-                else if(!strcmp(suburl, "check"))
-                    action = DAP_DATUM_MEMPOOL_CHECK;
-                else if(!strcmp(suburl, "del"))
-                    action = DAP_DATUM_MEMPOOL_DEL;
-            }
-            dap_datum_mempool_t *datum_mempool =
-                    (action != DAP_DATUM_MEMPOOL_NONE) ?
-                            dap_datum_mempool_deserialize((uint8_t*) l_request_data, (size_t) l_request_size) : NULL;
-            if(datum_mempool){
-                dap_datum_mempool_free(datum_mempool);
-                char *a_key = s_calc_datum_hash(l_request_data, (size_t) l_request_size);
-                switch (action)
-                {
-                case DAP_DATUM_MEMPOOL_ADD: // add datum in base
-                    //a_value = DAP_NEW_Z_SIZE(char, request_size * 2);
-                    //bin2hex((char*) a_value, (const unsigned char*) request_str, request_size);
-                    if ( dap_global_db_set_sync(l_gdb_datum_pool, a_key, l_request_data, l_request_size, false) == 0 ) {
-                        *return_code = Http_Status_OK;
-                    }
-                    log_it(L_INFO, "Insert hash: key=%s result:%s", a_key,
-                            (*return_code == Http_Status_OK) ? "OK" : "False!");
-                    break;
-
-                case DAP_DATUM_MEMPOOL_CHECK: // check datum in base
-
-                    strcpy(cl_st->reply_mime, "text/text");
-                    size_t l_datum_size = 0;
-                    byte_t *l_datum = dap_global_db_get_sync( l_gdb_datum_pool, a_key,&l_datum_size,NULL,NULL );
-                    if(l_datum) {
-                        l_enc_delegate->response = strdup("1");
-                        DAP_DEL_Z(l_datum);
-                        log_it(L_INFO, "Check hash: key=%s result: Present", a_key);
-                    }
-                    else {
-                        l_enc_delegate->response = strdup("0");
-                        log_it(L_INFO, "Check hash: key=%s result: Absent", a_key);
-                    }
-                    l_enc_delegate->response_size = l_datum_size;
-                    *return_code = Http_Status_OK;
-                    enc_http_reply_encode_new(cl_st, l_enc_key, l_enc_delegate);
-                    break;
-
-                case DAP_DATUM_MEMPOOL_DEL: // delete datum in base
-                    strcpy(cl_st->reply_mime, "text/text");
-                    if (dap_global_db_del_sync(l_gdb_datum_pool, a_key) == 0){
-                        l_enc_delegate->response = dap_strdup("1");
-                        log_it(L_INFO, "Delete hash: key=%s result: Ok", a_key);
-                    } else {
-                        l_enc_delegate->response = dap_strdup("0");
-                        log_it(L_INFO, "Delete hash: key=%s result: False!", a_key);
-                    }
-                    // TODO rework to async processing and return result of delete action
-                    *return_code = Http_Status_OK;
-                    enc_http_reply_encode_new(cl_st, l_enc_key, l_enc_delegate);
-                    break;
-
-                default: // unsupported command
-                    log_it(L_INFO, "Unknown request=%s! key=%s", (suburl) ? suburl : "-", a_key);
-                    enc_http_delegate_delete(l_enc_delegate);
-                    dap_enc_ks_delete(hdr_key_id->value);
-                    *return_code = Http_Status_BadRequest;
-                    return;
-                }
-                DAP_DEL_Z(a_key);
-            } else
-                *return_code = Http_Status_BadRequest;
-        } else
-            *return_code = Http_Status_BadRequest;
-
-        enc_http_delegate_delete(l_enc_delegate);
-    } else
-        *return_code = Http_Status_Unauthorized;
-
-    if (hdr_session_close_id && !strcmp(hdr_session_close_id->value, "yes") && hdr_key_id)
-        // close session
-        dap_enc_ks_delete(hdr_key_id->value);
-}
-
-/**
- * @brief chain_mempool_add_proc
- * @param sh HTTP server instance
- * @param url URL string
- */
-void dap_chain_mempool_add_proc(dap_http_server_t * a_http_server, const char * a_url)
-{
-    dap_http_simple_proc_add(a_http_server, a_url, 4096, chain_mempool_proc);
-}
-
 /**
  * @breif dap_chain_mempool_filter
  * @param a_chain chain whose mempool will be filtered.
@@ -1474,7 +1235,7 @@ void dap_chain_mempool_filter(dap_chain_t *a_chain, int *a_removed){
         return;
     }
     int l_removed = 0;
-    char * l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+    char * l_gdb_group = dap_chain_mempool_group_new(a_chain);
     size_t l_objs_size = 0;
     dap_time_t l_cut_off_time = dap_time_now() - 3 * 24 * 3600; // 3 days
     char l_cut_off_time_str[DAP_TIME_STR_SIZE] = {'\0'};
diff --git a/modules/mempool/include/dap_chain_mempool.h b/modules/mempool/include/dap_chain_mempool.h
index a62d51a5e1c5971542edbb96c79ce279df9a28d2..ce8bcc98482c430801639835980e5cbd109d9e9e 100644
--- a/modules/mempool/include/dap_chain_mempool.h
+++ b/modules/mempool/include/dap_chain_mempool.h
@@ -51,11 +51,18 @@ int dap_datum_mempool_init(void);
 
 extern const char* c_dap_datum_mempool_gdb_group;
 
-uint8_t* dap_datum_mempool_serialize(dap_datum_mempool_t *datum_mempool, size_t *size);
-dap_datum_mempool_t * dap_datum_mempool_deserialize(uint8_t *datum_mempool_str, size_t size);
-
-void dap_datum_mempool_clean(dap_datum_mempool_t *datum);
-void dap_datum_mempool_free(dap_datum_mempool_t *datum);
+/**
+ * @brief dap_chain_net_get_gdb_group_mempool
+ * @param l_chain
+ * @return
+ */
+DAP_STATIC_INLINE char *dap_chain_mempool_group_new(dap_chain_t *a_chain)
+{
+    dap_chain_net_t *l_net = a_chain ? dap_chain_net_by_id(a_chain->net_id) : NULL;
+    return l_net
+            ? dap_strdup_printf("%s.chain-%s.mempool", l_net->pub.gdb_groups_prefix, a_chain->name)
+            : NULL;
+}
 
 void dap_chain_mempool_add_proc(dap_http_server_t * a_http_server, const char * a_url);
 
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 6e69d4d70d94118643432733a456f8be7e74f125..2d1ea5caf4796dfd11f9877d6f4c4b630ba56135 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -81,6 +81,7 @@
 #include "dap_chain_datum_decree.h"
 #include "dap_chain_datum_anchor.h"
 #include "dap_chain_node_client.h"
+#include "dap_chain_mempool.h"
 #include "dap_chain_net.h"
 #include "dap_chain_net_node_list.h"
 #include "dap_chain_net_tx.h"
@@ -2494,7 +2495,7 @@ char * dap_chain_net_get_gdb_group_mempool_by_chain_type(dap_chain_net_t *a_net,
     {
         for(int i = 0; i < l_chain->datum_types_count; i++) {
             if(l_chain->datum_types[i] == a_datum_type)
-                return dap_chain_net_get_gdb_group_mempool_new(l_chain);
+                return dap_chain_mempool_group_new(l_chain);
         }
     }
     return NULL;
@@ -2802,7 +2803,22 @@ int dap_chain_datum_add(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t
         case DAP_CHAIN_DATUM_CUSTOM:
             break;
         default:
-            return -666;
+            return -600;
+    }
+    return 0;
+}
+
+int dap_chain_datum_add_hardfork_data(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_datum_size, dap_hash_fast_t *a_datum_hash, void *a_datum_index_data)
+{
+    int ret = dap_chain_datum_add(a_chain, a_datum, a_datum_size, a_datum_hash, a_datum_index_data);
+    if (ret)
+        return ret;
+    dap_ledger_t *l_ledger = dap_chain_net_by_id(a_chain->net_id)->pub.ledger;
+    switch (a_datum->header.type_id) {
+    case DAP_CHAIN_DATUM_TX: {
+        return dap_ledger_tx_load_hardfork_data(l_ledger, (dap_chain_datum_tx_t *)a_datum->data, a_datum_hash, (dap_ledger_datum_iter_data_t *)a_datum_index_data);
+    }
+    default: return -601;
     }
     return 0;
 }
@@ -3209,12 +3225,13 @@ static void s_sync_timer_callback(void *a_arg)
     l_net_pvt->sync_context.cur_chain->state = CHAIN_SYNC_STATE_WAITING;
     dap_chain_ch_sync_request_t l_request = {};
     uint64_t l_last_num = 0;
-    if (!dap_chain_get_atom_last_hash_num(l_net_pvt->sync_context.cur_chain,
+    if (!dap_chain_get_atom_last_hash_num_ts(l_net_pvt->sync_context.cur_chain,
                                             l_net_pvt->sync_context.cur_cell
                                             ? l_net_pvt->sync_context.cur_cell->id
                                             : c_dap_chain_cell_id_null,
                                             &l_request.hash_from,
-                                            &l_last_num)) {
+                                            &l_last_num,
+                                            NULL)) {
         log_it(L_ERROR, "Can't get last atom hash and number for chain %s with net %s", l_net_pvt->sync_context.cur_chain->name,
                                                                                         l_net->pub.name);
         return;
diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c
index b240cf8e940daac71e616fe7e9aa65bef46ee953..39ad5ac774bcd427b5284c5de096f902c20af268 100644
--- a/modules/net/dap_chain_node.c
+++ b/modules/net/dap_chain_node.c
@@ -43,14 +43,19 @@
 #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"
+#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_ledger.h"
 #include "dap_cli_server.h"
-#include "dap_chain_net_balancer.h"
+#include "dap_chain_srv.h"
+#include "dap_chain_mempool.h"
+#include "dap_chain_datum_service_state.h"
+#include "dap_chain_node_client.h"
 
 #define LOG_TAG "dap_chain_node"
+
 #define DAP_CHAIN_NODE_NET_STATES_INFO_CURRENT_VERSION 2
+
 typedef struct dap_chain_node_net_states_info_v1 {
     dap_chain_node_addr_t address;
     uint64_t events_count;
@@ -69,6 +74,27 @@ 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_ANCHORS = 0,
+    STATE_BALANCES,
+    STATE_CONDOUTS,
+    STATE_FEES,
+    STATE_SERVICES,
+    STATE_MEMPOOL,
+    STATE_OVER
+};
+
+struct hardfork_states {
+    enum hardfork_state state_current;
+    size_t iterator;
+    dap_ledger_hardfork_anchors_t  *anchors;
+    dap_ledger_hardfork_balances_t *balances;
+    dap_ledger_hardfork_condouts_t *condouts;
+    dap_chain_cs_blocks_hardfork_fees_t *fees;
+    dap_chain_srv_hardfork_state_t *service_states;
+    dap_list_t *trusted_addrs;
+};
+
 static const uint64_t s_cmp_delta_timestamp = (uint64_t)1000 /*sec*/ * (uint64_t)1000000000;
 static const uint64_t s_cmp_delta_event = 0;
 static const uint64_t s_cmp_delta_atom = 10;
@@ -422,14 +448,14 @@ void dap_chain_node_mempool_process_all(dap_chain_t *a_chain, bool a_force)
         fclose(l_file);
     }
 #endif
-    char *l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(a_chain);
-    size_t l_objs_size = 0;
-    dap_global_db_obj_t *l_objs = dap_global_db_get_all_sync(l_gdb_group_mempool, &l_objs_size);
-    if (l_objs_size) {
+    char *l_gdb_group_mempool = dap_chain_mempool_group_new(a_chain);
+    size_t l_objs_count = 0;
+    dap_global_db_obj_t *l_objs = dap_global_db_get_all_sync(l_gdb_group_mempool, &l_objs_count);
+    if (l_objs_count) {
 #ifdef DAP_TPS_TEST
-        log_it(L_TPS, "Get %zu datums from mempool", l_objs_size);
+        log_it(L_TPS, "Get %zu datums from mempool", l_objs_count);
 #endif
-        for (size_t i = 0; i < l_objs_size; i++) {
+        for (size_t i = 0; i < l_objs_count; i++) {
             if (l_objs[i].value_len < sizeof(dap_chain_datum_t))
                 continue;
             dap_chain_datum_t *l_datum = (dap_chain_datum_t *)l_objs[i].value;
@@ -471,11 +497,305 @@ void dap_chain_node_mempool_process_all(dap_chain_t *a_chain, bool a_force)
                 }
             }
         }
-        dap_global_db_objs_delete(l_objs, l_objs_size);
+        dap_global_db_objs_delete(l_objs, l_objs_count);
     }
     DAP_DELETE(l_gdb_group_mempool);
 }
 
+dap_chain_datum_t **s_service_state_datums_create(dap_chain_srv_hardfork_state_t *a_state, size_t *a_datums_count)
+{
+    dap_chain_datum_t **ret = NULL;
+    size_t l_datums_count = 0;
+    const uint64_t l_max_step_size = DAP_CHAIN_ATOM_MAX_SIZE - sizeof(dap_chain_datum_service_state_t);
+    uint64_t l_step_size = dap_min(l_max_step_size, a_state->size);
+    byte_t *l_offset = a_state->data, *l_ptr = l_offset, *l_end = a_state->data + a_state->size * a_state->count;
+    while (l_offset < l_end) {
+        size_t l_cur_step_size = 0, i = 0;
+        while (l_cur_step_size < l_max_step_size && l_offset < l_end) {
+            size_t l_addition = dap_min((uint64_t)(l_end - l_offset), l_step_size);
+            l_cur_step_size += l_addition;
+            l_offset += l_addition;
+            i++;
+        }
+        dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_SERVICE_STATE, l_ptr, sizeof(dap_chain_datum_service_state_t) + l_cur_step_size);
+        ((dap_chain_datum_service_state_t *)l_datum->data)->srv_uid = a_state->uid;
+        ((dap_chain_datum_service_state_t *)l_datum->data)->states_count = i;
+        ret = DAP_REALLOC_RET_VAL_IF_FAIL(ret, sizeof(dap_chain_datum_t *) * (++l_datums_count), NULL, NULL);
+        ret[l_datums_count - 1] = l_datum;
+        l_ptr = l_offset;
+    }
+    assert(l_offset == l_end);
+    if (a_datums_count)
+        *a_datums_count = l_datums_count;
+    return ret;
+}
+
+int dap_chain_node_hardfork_prepare(dap_chain_t *a_chain, dap_time_t a_last_block_timestamp, dap_list_t *a_trusted_addrs)
+{
+    if (dap_strcmp(dap_chain_get_cs_type(a_chain), DAP_CHAIN_ESBOCS_CS_TYPE_STR))
+        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);
+    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);
+    l_states->anchors = dap_ledger_anchors_aggregate(l_net->pub.ledger);
+    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);
+    dap_chain_srv_hardfork_state_t *it, *tmp;
+    DL_FOREACH_SAFE(l_states->service_states, it, tmp) {
+        if (it->uid.uint64 < (uint64_t)INT64_MIN)       // MSB is not set
+            continue;
+        size_t l_datums_count = 0;
+        dap_chain_datum_t **l_datums = s_service_state_datums_create(it, &l_datums_count);
+        for (size_t i = 0; i < l_datums_count; i++)
+            DAP_DELETE(dap_chain_mempool_datum_add(l_datums[i], a_chain, "hex"));
+        DL_DELETE(l_states->service_states, it);
+        DAP_DELETE(it);
+    }
+    l_states->trusted_addrs = a_trusted_addrs;
+    a_chain->hardfork_data = l_states;
+    DAP_CHAIN_CS_BLOCKS(a_chain)->is_hardfork_state = true;
+    l_net->pub.ledger->is_hardfork_state = true;
+    return 0;
+}
+
+dap_chain_datum_t *s_datum_tx_create(dap_chain_addr_t *a_addr, const char *a_ticker, uint256_t a_value, dap_list_t *a_trackers)
+{
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    if (!l_tx)
+        return NULL;
+    if (dap_chain_datum_tx_add_out_ext_item(&l_tx, a_addr, a_value, a_ticker) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+    for (dap_list_t *it = a_trackers; it; it = it->next) {
+        dap_ledger_tracker_t *l_tracker = it->data;
+        dap_chain_tx_tsd_t *l_tracker_tsd = dap_chain_datum_tx_item_tsd_create(l_tracker, DAP_CHAIN_DATUM_TX_TSD_TYPE_HARDFORK_TRACKER, sizeof(dap_ledger_tracker_t));
+        if (!l_tracker_tsd) {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+        if (dap_chain_datum_tx_add_item(&l_tx, l_tracker_tsd) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+    }
+    dap_chain_datum_t *l_datum_tx = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, dap_chain_datum_tx_get_size(l_tx));
+    dap_chain_datum_tx_delete(l_tx);
+    return l_datum_tx;
+}
+
+dap_chain_datum_t *s_cond_tx_create(dap_chain_tx_out_cond_t *a_cond, dap_chain_tx_sig_t *a_sign, dap_hash_fast_t *a_hash, const char *a_ticker, dap_list_t *a_trackers)
+{
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    if (!l_tx)
+        return NULL;
+    if (dap_chain_datum_tx_add_item(&l_tx, a_cond) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+    if (dap_chain_datum_tx_add_item(&l_tx, a_sign) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+    dap_chain_tx_tsd_t *l_tx_hash_tsd = dap_chain_datum_tx_item_tsd_create(a_hash, DAP_CHAIN_DATUM_TX_TSD_TYPE_HARDFORK_TX_HASH, sizeof(dap_hash_fast_t));
+    if (!l_tx_hash_tsd) {
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+    if (dap_chain_datum_tx_add_item(&l_tx, l_tx_hash_tsd) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+    dap_chain_tx_tsd_t *l_ticker_tsd = dap_chain_datum_tx_item_tsd_create(a_ticker, DAP_CHAIN_DATUM_TX_TSD_TYPE_HARDFORK_TICKER, DAP_CHAIN_TICKER_SIZE_MAX);
+    if (!l_ticker_tsd) {
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+    if (dap_chain_datum_tx_add_item(&l_tx, l_ticker_tsd) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+    for (dap_list_t *it = a_trackers; it; it = it->next) {
+        dap_ledger_tracker_t *l_tracker = it->data;
+        dap_chain_tx_tsd_t *l_tracker_tsd = dap_chain_datum_tx_item_tsd_create(l_tracker, DAP_CHAIN_DATUM_TX_TSD_TYPE_HARDFORK_TRACKER, sizeof(dap_ledger_tracker_t));
+        if (!l_tracker_tsd) {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+        if (dap_chain_datum_tx_add_item(&l_tx, l_tracker_tsd) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            return NULL;
+        }
+    }
+    dap_chain_datum_t *l_datum_tx = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, dap_chain_datum_tx_get_size(l_tx));
+    dap_chain_datum_tx_delete(l_tx);
+    return l_datum_tx;
+}
+
+dap_chain_datum_t *s_fee_tx_create(uint256_t a_value, dap_sign_t *a_owner_sign)
+{
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    if (!l_tx)
+        return NULL;
+    dap_chain_tx_out_cond_t *l_cond = dap_chain_datum_tx_item_out_cond_create_fee_stack(a_value);
+    if (dap_chain_datum_tx_add_item(&l_tx, l_cond) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+    dap_chain_tx_sig_t *l_tx_sig = dap_chain_tx_sig_create(a_owner_sign);
+    if (dap_chain_datum_tx_add_item(&l_tx, l_tx_sig) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        return NULL;
+    }
+    dap_chain_datum_t *l_datum_tx = dap_chain_datum_create(DAP_CHAIN_DATUM_TX, l_tx, dap_chain_datum_tx_get_size(l_tx));
+    dap_chain_datum_tx_delete(l_tx);
+    return l_datum_tx;
+}
+
+int dap_chain_node_hardfork_process(dap_chain_t *a_chain)
+{
+    dap_return_val_if_fail(a_chain, -1);
+    if (!dap_chain_net_by_id(a_chain->net_id)->pub.mempool_autoproc)
+        return -2;
+    if (!a_chain->hardfork_data)
+        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_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));
+            if (!l_datum_anchor)
+                return -2;
+            if (!a_chain->callback_add_datums(a_chain, &l_datum_anchor, 1)) {
+                dap_hash_fast_t l_decree_hash;
+                dap_chain_datum_anchor_get_hash_from_data(it->anchor, &l_decree_hash);
+                log_it(L_NOTICE, "Hardfork processed to datum anchor for decree hash %s", dap_hash_fast_to_str_static(&l_decree_hash));
+                DAP_DELETE(l_datum_anchor);
+                break;
+            }
+            DAP_DELETE(l_datum_anchor);
+        }
+        break;
+    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);
+            if (!l_tx)
+                return -3;
+            if (!a_chain->callback_add_datums(a_chain, &l_tx, 1)) {
+                DAP_DELETE(l_tx);
+                log_it(L_NOTICE, "Hardfork processed to datum tx with addr %s", dap_chain_addr_to_str_static(&it->addr));
+                break;
+            }
+            DAP_DELETE(l_tx);
+        }
+        break;
+    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);
+            if (!l_cond_tx)
+                return -4;
+            if (!a_chain->callback_add_datums(a_chain, &l_cond_tx, 1)) {
+                DAP_DELETE(l_cond_tx);
+                log_it(L_NOTICE, "Hardfork processed to datum cond_tx with hash %s", dap_hash_fast_to_str_static(&it->hash));
+                break;
+            }
+            DAP_DELETE(l_cond_tx);
+        }
+        break;
+    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);
+            if (!l_fee_tx)
+                return -4;
+            if (!a_chain->callback_add_datums(a_chain, &l_fee_tx, 1)) {
+                DAP_DELETE(l_fee_tx);
+                dap_hash_fast_t l_pkey_hash; dap_sign_get_pkey_hash(it->owner_sign, &l_pkey_hash);
+                log_it(L_NOTICE, "Hardfork processed to datum fee_tx with hash %s", dap_hash_fast_to_str_static(&l_pkey_hash));
+                break;
+            }
+            DAP_DELETE(l_fee_tx);
+        }
+        break;
+    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
+                continue;
+            bool l_break = false;
+            size_t l_datums_count = 0;
+            dap_chain_datum_t **l_datums = s_service_state_datums_create(it, &l_datums_count);
+            for (size_t i = l_states->iterator; i < l_datums_count; i++) {
+                if (!a_chain->callback_add_datums(a_chain, l_datums + i, 1)) {
+                    log_it(L_NOTICE, "Hardfork processed to datum service_state with uid %" DAP_UINT64_FORMAT_x " and number %zu",
+                                        it->uid.uint64, i);
+                    // save iterator to state machine
+                    l_states->iterator = i;
+                    l_break = true;
+                    break;
+                }
+
+            }
+            for (size_t i = 0; i < l_datums_count; i++)
+                DAP_DELETE(l_datums[i]);
+            DAP_DEL_Z(l_datums);
+            if (l_break)
+                break;
+        }
+        break;
+    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);
+        if (!l_objs_count) {
+            l_states->state_current = STATE_OVER;
+            break;
+        }
+        bool l_nothing_processed = true;
+        for (size_t i = 0; i < l_objs_count; i++) {
+            if (l_objs[i].value_len < sizeof(dap_chain_datum_t))
+                continue;
+            if (!l_objs[i].sign)
+                continue;
+            dap_stream_node_addr_t l_addr = dap_stream_node_addr_from_sign(l_objs[i].sign);
+            bool l_addr_match = false;
+            for (dap_list_t *it = l_states->trusted_addrs; it; it = it->next) {
+                if (((dap_stream_node_addr_t *)it->data)->uint64 != l_addr.uint64)
+                    continue;
+                l_addr_match = true;
+                break;
+            }
+            if (!l_addr_match) {
+                log_it(L_WARNING, "Trying to inject hardfork service state datum from addr " NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(l_addr));
+                continue;
+            }
+            dap_chain_datum_t *l_datum = (dap_chain_datum_t *)l_objs[i].value;
+            if (dap_chain_datum_size(l_datum) != l_objs[i].value_len)
+                continue;
+            if (l_datum->header.type_id != DAP_CHAIN_DATUM_SERVICE_STATE)
+                continue;
+            if (dap_chain_node_mempool_process(a_chain, l_datum, l_objs[i].key))
+                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_OVER;
+    }
+
+    case STATE_OVER:
+        break;
+    // No default here
+    }
+    return 0;
+}
+
+int dap_chain_node_hardfork_confirm(dap_chain_t *a_chain, dap_chain_datum_t *a_datum)
+{
+    return 0;
+}
 
 /**
  * @brief
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index 2a5b858d68e2692b186f73a26346ae873e8bbd82..9cd99062a7e2ef74a0f84cbd215686b57781ed08 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -143,19 +143,6 @@ int dap_chain_net_link_add(dap_chain_net_t *a_net, dap_stream_node_addr_t *a_add
 
 void dap_chain_net_purge(dap_chain_net_t *l_net);
 
-/**
- * @brief dap_chain_net_get_gdb_group_mempool
- * @param l_chain
- * @return
- */
-DAP_STATIC_INLINE char *dap_chain_net_get_gdb_group_mempool_new(dap_chain_t *a_chain)
-{
-    dap_chain_net_t *l_net = a_chain ? dap_chain_net_by_id(a_chain->net_id) : NULL;
-    return l_net
-            ? dap_strdup_printf("%s.chain-%s.mempool", l_net->pub.gdb_groups_prefix, a_chain->name)
-            : NULL;
-}
-
 DAP_STATIC_INLINE char *dap_chain_net_get_gdb_group_nochain_new(dap_chain_t *a_chain)
 {
     dap_chain_net_t *l_net = a_chain ? dap_chain_net_by_id(a_chain->net_id) : NULL;
@@ -187,6 +174,7 @@ void dap_chain_net_srv_order_add_notify_callback(dap_chain_net_t *a_net, dap_sto
 dap_list_t *dap_chain_datum_list(dap_chain_net_t *a_net, dap_chain_t *a_chain, dap_chain_datum_filter_func_t *a_filter_func, void *a_filter_func_param);
 
 int dap_chain_datum_add(dap_chain_t * a_chain, dap_chain_datum_t *a_datum, size_t a_datum_size, dap_hash_fast_t *a_datum_hash, void *a_datum_index_data);
+int dap_chain_datum_add_hardfork_data(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_datum_size, dap_hash_fast_t *a_datum_hash, void *a_datum_index_data);
 int dap_chain_datum_remove(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t a_datum_size, dap_hash_fast_t *a_datum_hash);
 
 bool dap_chain_net_get_load_mode(dap_chain_net_t * a_net);
diff --git a/modules/net/include/dap_chain_node.h b/modules/net/include/dap_chain_node.h
index 28c72a6d4190d5f66c360f9ffd9d48aa1d4538ee..e1a0550c9edd8b70c71e854e752bf4949a2203dd 100644
--- a/modules/net/include/dap_chain_node.h
+++ b/modules/net/include/dap_chain_node.h
@@ -102,6 +102,10 @@ bool dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_d
 void dap_chain_node_mempool_process_all(dap_chain_t *a_chain, bool a_force);
 bool dap_chain_node_mempool_autoproc_init();
 inline static void dap_chain_node_mempool_autoproc_deinit() {}
+
+int dap_chain_node_hardfork_prepare(dap_chain_t *a_chain, dap_time_t a_last_block_timestamp, dap_list_t *a_trusted_addrs);
+int dap_chain_node_hardfork_process(dap_chain_t *a_chain);
+
 dap_list_t *dap_chain_node_get_states_list_sort(dap_chain_net_t *a_net, dap_chain_node_addr_t *a_ignored, size_t a_ignored_count);
 dap_string_t *dap_chain_node_states_info_read(dap_chain_net_t *a_net, dap_stream_node_addr_t a_addr);
 int dap_chain_node_cli_cmd_values_parse_net_chain_for_json(json_object* a_json_arr_reply, int *a_arg_index, int a_argc,
diff --git a/modules/node-cli/dap_chain_node_cli.c b/modules/node-cli/dap_chain_node_cli.c
index 9dde939f6347580165cda57e9ccb6e1f500d0e95..735e71f020a37472e983035f5563a0c4c8e9d895 100644
--- a/modules/node-cli/dap_chain_node_cli.c
+++ b/modules/node-cli/dap_chain_node_cli.c
@@ -380,7 +380,10 @@ 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> | -new_certs <new_owners_certs_list> | -signs_verify <value>}\n"
+            "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>] |"
+                                                                                                                        " -new_certs <new_owners_certs_list> |"
+                                                                                                                        " -signs_verify <value>}\n"
             "Creates common network decree in net <net_name>. Decree adds to chain -chain and applies to chain -decree_chain. If -chain and -decree_chain is different you must create anchor in -decree_chain that is connected to this decree."
             "\nCommon decree parameters:\n"
             "\t -fee <value>: sets network fee\n"
diff --git a/modules/node-cli/dap_chain_node_cli_cmd.c b/modules/node-cli/dap_chain_node_cli_cmd.c
index aba036a2148a7f8aa7d3f1d78044e00b7128db5e..dd06c89c80043e39faf7fa03370c7f7f9827db32 100644
--- a/modules/node-cli/dap_chain_node_cli_cmd.c
+++ b/modules/node-cli/dap_chain_node_cli_cmd.c
@@ -95,7 +95,7 @@ struct json_object *wallet_list_json_collect();
 dap_chain_t *s_get_chain_with_datum(dap_chain_net_t *a_net, const char *a_datum_hash) {
     dap_chain_t *l_chain = NULL;
     DL_FOREACH(a_net->pub.chains, l_chain) {
-        char *l_gdb_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+        char *l_gdb_mempool = dap_chain_mempool_group_new(l_chain);
         bool is_hash = dap_global_db_driver_is(l_gdb_mempool, a_datum_hash);
         DAP_DELETE(l_gdb_mempool);
         if (is_hash)
@@ -2145,7 +2145,7 @@ void s_com_mempool_list_print_for_chain(json_object* a_json_arr_reply, dap_chain
         DAP_DELETE(l_wallet_addr);
         return;
     }
-    char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+    char * l_gdb_group_mempool = dap_chain_mempool_group_new(a_chain);
     if(!l_gdb_group_mempool){
         dap_json_rpc_error_add(a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_MEMPOOL_LIST_CAN_NOT_GET_MEMPOOL_GROUP,
                                "%s.%s: chain not found\n", a_net->pub.name, a_chain->name);
@@ -2676,7 +2676,7 @@ void s_com_mempool_list_print_for_chain(json_object* a_json_arr_reply, dap_chain
 }
 
 static int mempool_delete_for_chain(dap_chain_t *a_chain, const char * a_datum_hash_str, json_object **a_json_arr_reply) {
-        char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+        char * l_gdb_group_mempool = dap_chain_mempool_group_new(a_chain);
         uint8_t *l_data_tmp = dap_global_db_get_sync(l_gdb_group_mempool, a_datum_hash_str,
                                                      NULL, NULL, NULL);
         if (!l_data_tmp) {
@@ -2764,7 +2764,7 @@ dap_chain_datum_t *s_com_mempool_check_datum_in_chain(dap_chain_t *a_chain, cons
 {
     if (!a_datum_hash_str)
         return NULL;
-    char *l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+    char *l_gdb_group_mempool = dap_chain_mempool_group_new(a_chain);
     uint8_t *l_data_tmp = dap_global_db_get_sync(l_gdb_group_mempool, a_datum_hash_str, NULL, NULL, NULL);
     DAP_DELETE(l_gdb_group_mempool);
     return (dap_chain_datum_t *)l_data_tmp;
@@ -2959,7 +2959,7 @@ int _cmd_mempool_proc(dap_chain_net_t *a_net, dap_chain_t *a_chain, const char *
     dap_chain_t *l_chain = !a_chain ? s_get_chain_with_datum(a_net, a_datum_hash) : a_chain;
 
     int ret = 0;
-    char *l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+    char *l_gdb_group_mempool = dap_chain_mempool_group_new(l_chain);
     if (!l_gdb_group_mempool){
         dap_json_rpc_error_add(*a_json_arr_reply, DAP_COM_MEMPOOL_PROC_LIST_ERROR_CAN_NOT_GROUP_NAME,
                                "Failed to get mempool group name on network %s", a_net->pub.name);
@@ -3213,13 +3213,13 @@ int _cmd_mempool_dump(dap_chain_net_t *a_net, dap_chain_t *a_chain, const char *
         return COM_DUMP_ERROR_NULL_IS_ARGUMENT_FUNCTION;
     }
     if (a_chain) {
-        char *l_group_mempool = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+        char *l_group_mempool = dap_chain_mempool_group_new(a_chain);
         _cmd_mempool_dump_from_group(a_net->pub.id, l_group_mempool, a_datum_hash, a_hash_out_type, a_json_arr_reply);
         DAP_DELETE(l_group_mempool);
     } else {
         dap_chain_t *l_chain = NULL;
         DL_FOREACH(a_net->pub.chains, l_chain){
-            char *l_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+            char *l_group_mempool = dap_chain_mempool_group_new(l_chain);
             if (!_cmd_mempool_dump_from_group(a_net->pub.id, l_group_mempool, a_datum_hash, a_hash_out_type, a_json_arr_reply)){
                 DAP_DELETE(l_group_mempool);
                 break;
@@ -3397,7 +3397,7 @@ int com_mempool(int a_argc, char **a_argv, void **a_str_reply)
                 return DAP_JSON_RPC_ERR_CODE_MEMORY_ALLOCATED;
             }
             if(l_chain) {
-                l_mempool_group = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+                l_mempool_group = dap_chain_mempool_group_new(l_chain);
                 size_t l_objs_count = 0;
                 dap_global_db_obj_t *l_objs = dap_global_db_get_all_sync(l_mempool_group, &l_objs_count);
                 dap_global_db_objs_delete(l_objs, l_objs_count);
@@ -3419,7 +3419,7 @@ int com_mempool(int a_argc, char **a_argv, void **a_str_reply)
                 json_object_array_add(l_jobj_chains, l_jobj_chain);
             } else {
                 DL_FOREACH(l_net->pub.chains, l_chain) {
-                    l_mempool_group = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+                    l_mempool_group = dap_chain_mempool_group_new(l_chain);
                     size_t l_objs_count = 0;
                     dap_global_db_obj_t *l_objs = dap_global_db_get_all_sync(l_mempool_group, &l_objs_count);
                     dap_global_db_objs_delete(l_objs, l_objs_count);
@@ -3503,7 +3503,7 @@ void _cmd_find_type_decree_in_chain(json_object *a_out, dap_chain_t *a_chain, ui
         }
     }
     if (a_where == ALL || a_where == MEMPOOL) {
-        char *l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+        char *l_gdb_group_mempool = dap_chain_mempool_group_new(a_chain);
         size_t l_mempool_count = 0;
         dap_global_db_obj_t *l_objs = dap_global_db_get_all_sync(l_gdb_group_mempool, &l_mempool_count);
         for (size_t i = 0; i < l_mempool_count; i++) {
@@ -4066,11 +4066,11 @@ int cmd_decree(int a_argc, char **a_argv, void **a_str_reply)
             *(uint256_t*)(l_tsd->data) = dap_uint256_scan_uninteger(l_param_value_str);
             l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
         } else if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-harfork_from", &l_param_value_str)) {
+            l_subtype = DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_HARDFORK;
             l_total_tsd_size += sizeof(dap_tsd_t) + sizeof(uint64_t);
             l_tsd = DAP_NEW_Z_SIZE(dap_tsd_t, l_total_tsd_size);
             if (!l_tsd) {
                 log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-                dap_list_free_full(l_tsd_list, NULL);
                 return -1;
             }
             l_tsd->type = DAP_CHAIN_DATUM_DECREE_TSD_TYPE_BLOCK_NUM;
@@ -4078,10 +4078,35 @@ int cmd_decree(int a_argc, char **a_argv, void **a_str_reply)
             *(uint64_t*)(l_tsd->data) = strtoll(l_param_value_str, NULL, 10);
             if (!*(uint64_t*)l_tsd->data && dap_strcmp(l_param_value_str, "0")) {
                 log_it(L_ERROR, "Can't converts %s to atom number", l_param_value_str);
-                dap_list_free_full(l_tsd_list, NULL);
+                DAP_DELETE(l_tsd);
                 return -1;
             }
             l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
+            if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-trusted_addrs", &l_param_addr_str)) {
+                char **l_addrs = dap_strsplit(l_param_addr_str, ",", 256);
+                for (uint16_t i = 0; l_addrs[i]; i++) {
+                    dap_stream_node_addr_t l_addr_cur;
+                    if (dap_stream_node_addr_from_str(&l_addr_cur, l_addrs[i])) {
+                        log_it(L_ERROR, "Can't convert %s to node addr", l_addrs[i]);
+                        dap_list_free_full(l_tsd_list, NULL);
+                        dap_strfreev(l_addrs);
+                        return -5;
+                    }
+                    l_tsd = DAP_NEW_Z_SIZE(dap_tsd_t, sizeof(dap_tsd_t) + sizeof(dap_stream_node_addr_t));
+                    if (!l_tsd) {
+                        log_it(L_CRITICAL, "%s", c_error_memory_alloc);
+                        dap_list_free_full(l_tsd_list, NULL);
+                        dap_strfreev(l_addrs);
+                        return -1;
+                    }
+                    l_tsd->type = DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR;
+                    l_tsd->size = sizeof(dap_stream_node_addr_t);
+
+                    l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
+                    l_total_tsd_size += sizeof(dap_tsd_t) + sizeof(dap_stream_node_addr_t);
+                }
+                dap_strfreev(l_addrs);
+            }
         } else if (dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-new_certs", &l_param_value_str)){
             l_subtype = DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_OWNERS;
             dap_cert_parse_str_list(l_param_value_str, &l_new_certs, &l_new_certs_count);
@@ -4232,7 +4257,7 @@ int cmd_decree(int a_argc, char **a_argv, void **a_str_reply)
                 return -105;
             }
 
-            char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+            char * l_gdb_group_mempool = dap_chain_mempool_group_new(l_chain);
             if(!l_gdb_group_mempool) {
                 l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_by_chain_type(l_net, CHAIN_TYPE_DECREE);
             }
@@ -5003,7 +5028,7 @@ static int s_check_cmd(int a_arg_index, int a_argc, char **a_argv, void **a_str_
     dap_chain_datum_t *l_datum = NULL;
     char *l_gdb_group = NULL;
 
-    l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+    l_gdb_group = dap_chain_mempool_group_new(l_chain);
     if (!l_gdb_group) {
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Not found network group for chain: %s", l_chain->name);
         l_ret = -1;
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 d839b90ce1a07c0ca0e97bec95f0df0525bb9727..938e5f665687f32e91421c10494a5be78c158e6b 100644
--- a/modules/node-cli/dap_chain_node_cli_cmd_token.c
+++ b/modules/node-cli/dap_chain_node_cli_cmd_token.c
@@ -156,7 +156,7 @@ int com_token_decl_sign(int a_argc, char **a_argv, void **a_str_reply)
             return -7;
         }
 
-        char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+        char * l_gdb_group_mempool = dap_chain_mempool_group_new(l_chain);
         if(!l_gdb_group_mempool) {
             l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_by_chain_type(l_net, CHAIN_TYPE_TOKEN);
         }
@@ -960,7 +960,7 @@ int com_token_decl(int a_argc, char ** a_argv, void **a_str_reply)
 
     // Add datum to mempool with datum_token hash as a key
     char *l_gdb_group_mempool = l_chain
-            ? dap_chain_net_get_gdb_group_mempool_new(l_chain)
+            ? dap_chain_mempool_group_new(l_chain)
             : dap_chain_net_get_gdb_group_mempool_by_chain_type(l_net, CHAIN_TYPE_TOKEN);
     if (!l_gdb_group_mempool) {
         dap_cli_server_cmd_set_reply_text(a_str_reply, "No suitable chain for placing token datum found");
@@ -1141,7 +1141,7 @@ int com_token_update(int a_argc, char ** a_argv, void **a_str_reply)
 
     // Add datum to mempool with datum_token hash as a key
     char *l_gdb_group_mempool = l_chain
-            ? dap_chain_net_get_gdb_group_mempool_new(l_chain)
+            ? dap_chain_mempool_group_new(l_chain)
             : dap_chain_net_get_gdb_group_mempool_by_chain_type(l_net, CHAIN_TYPE_TOKEN);
     if (!l_gdb_group_mempool) {
         dap_cli_server_cmd_set_reply_text(a_str_reply, "No suitable chain for placing token datum found");
@@ -1345,7 +1345,7 @@ int com_token_emit(int a_argc, char **a_argv, void **a_str_reply)
 
     //remove previous emission datum from mempool if have new signed emission datum
     if (l_emission_hash_str_remove) {
-        char *l_gdb_group_mempool_emission = dap_chain_net_get_gdb_group_mempool_new(l_chain_emission);
+        char *l_gdb_group_mempool_emission = dap_chain_mempool_group_new(l_chain_emission);
         dap_global_db_del_sync(l_gdb_group_mempool_emission, l_emission_hash_str_remove);
         DAP_DEL_Z(l_gdb_group_mempool_emission);
     }
diff --git a/modules/node-cli/dap_chain_node_cli_cmd_tx.c b/modules/node-cli/dap_chain_node_cli_cmd_tx.c
index 32abe86479941ee114c04513e27af28d7c24aa58..7a00029d9d945c84d07044e891f8fc5b17433e0b 100644
--- a/modules/node-cli/dap_chain_node_cli_cmd_tx.c
+++ b/modules/node-cli/dap_chain_node_cli_cmd_tx.c
@@ -2242,7 +2242,7 @@ void json_rpc_tx_create(json_object *a_param, json_object *a_reply){
         return ;
     }
 
-    char *l_gdb_group_mempool_base_tx = dap_chain_net_get_gdb_group_mempool_new(l_chain);// get group name for mempool
+    char *l_gdb_group_mempool_base_tx = dap_chain_mempool_group_new(l_chain);// get group name for mempool
     bool l_placed = !dap_global_db_set(l_gdb_group_mempool_base_tx, l_tx_hash_str, l_datum_tx, l_datum_tx_size, false, NULL, NULL);
 
     DAP_DELETE(l_datum_tx);
@@ -2396,7 +2396,7 @@ int com_tx_create_json(int a_argc, char ** a_argv, void **reply)
         return DAP_CHAIN_NODE_CLI_COM_TX_CREATE_JSON_CAN_CHECK_TX_ADD_LEDGER;
     }
 
-    char *l_gdb_group_mempool_base_tx = dap_chain_net_get_gdb_group_mempool_new(l_chain);// get group name for mempool
+    char *l_gdb_group_mempool_base_tx = dap_chain_mempool_group_new(l_chain);// get group name for mempool
     bool l_placed = !dap_global_db_set(l_gdb_group_mempool_base_tx, l_tx_hash_str, l_datum_tx, l_datum_tx_size, false, NULL, NULL);
 
     DAP_DEL_Z(l_datum_tx);
@@ -2822,7 +2822,7 @@ int com_tx_verify(int a_argc, char **a_argv, void **a_str_reply)
         }
     }
     size_t l_datum_size = 0;
-    char *l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+    char *l_gdb_group = dap_chain_mempool_group_new(l_chain);
     dap_chain_datum_t *l_datum = (dap_chain_datum_t*)dap_global_db_get_sync(l_gdb_group, l_hex_str_from58 ? l_hex_str_from58 : l_tx_hash_str, &l_datum_size, NULL, NULL);
     DAP_DEL_Z(l_hex_str_from58);
     if (!l_datum) {
diff --git a/modules/service/datum/dap_chain_net_srv_datum.c b/modules/service/datum/dap_chain_net_srv_datum.c
index b2e0e30bd10846afd9162ab6a099891e26518bc6..768e158fb136c8f26829c39c618f1cabdfdb5c20 100644
--- a/modules/service/datum/dap_chain_net_srv_datum.c
+++ b/modules/service/datum/dap_chain_net_srv_datum.c
@@ -131,7 +131,7 @@ static int s_srv_datum_cli(int argc, char ** argv, void **a_str_reply)
     dap_cli_server_cmd_find_option_val(argv, arg_index, argc, "datum", &l_datum_cmd_str);
     if ( l_datum_cmd_str != NULL ) {
         if ( strcmp(l_datum_cmd_str, "save") == 0) {
-            char * l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+            char * l_gdb_group = dap_chain_mempool_group_new(l_chain);
 
             size_t l_path_length = strlen(l_system_datum_folder)+8+strlen(l_datum_hash_str);
             char l_path[l_path_length];
@@ -237,7 +237,7 @@ void s_order_notficator(dap_store_obj_t *a_obj, void *a_arg)
     dap_chain_datum_tx_t *l_tx_cond = NULL;
     DL_FOREACH(l_net->pub.chains, l_chain) {
         size_t l_datum_size;
-        char *l_gdb_group = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+        char *l_gdb_group = dap_chain_mempool_group_new(l_chain);
         l_datum = (dap_chain_datum_t *)dap_global_db_get_sync(l_gdb_group, l_tx_cond_hash_str, &l_datum_size, NULL, NULL);
         if (l_datum)
             break;
diff --git a/modules/service/emit-delegate/dap_chain_net_srv_emit_delegate.c b/modules/service/emit-delegate/dap_chain_net_srv_emit_delegate.c
index f3681b556a305de6408e1265b576656052b24324..7046bcfb1b5c709a398e32b4fce670ce539d808d 100644
--- a/modules/service/emit-delegate/dap_chain_net_srv_emit_delegate.c
+++ b/modules/service/emit-delegate/dap_chain_net_srv_emit_delegate.c
@@ -683,7 +683,7 @@ static int s_cli_sign(int a_argc, char **a_argv, int a_arg_index, json_object **
         dap_json_rpc_error_add(*a_json_arr_reply, ERROR_PLACE, "Can't place transaction for delegated emission in mempool");
         return ERROR_PLACE;
     }
-    char *l_mempool_group = dap_chain_net_get_gdb_group_mempool_new(a_chain);
+    char *l_mempool_group = dap_chain_mempool_group_new(a_chain);
     dap_global_db_del_sync(l_mempool_group, l_tx_in_hash_str);
     DAP_DELETE(l_mempool_group);
     json_object * l_json_obj_create_val = json_object_new_object();
diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index 96b7ddc57c40266fe237a89bcb65326793dd403f..b6f3cd706d5a5f9713275aa699060c262a6e4fc7 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -64,6 +64,7 @@ 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_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);
 static bool s_datum_tx_voting_verification_delete_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);
@@ -100,7 +101,7 @@ 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 };
+    dap_chain_static_srv_callbacks_t l_srv_callbacks = { .start = s_callback_start, .delete = s_callback_delete, .hardfork_prepare = s_votings_backup };
     int ret = dap_chain_srv_add(l_uid, "voting", &l_srv_callbacks);
     if (ret) {
         log_it(L_ERROR, "Can't register voting service");
@@ -1426,59 +1427,49 @@ static size_t s_voting_serial_size_calc(struct voting *a_voting, size_t *a_votes
     return ret;
 }
 
-static int s_voting_dump(dap_chain_datum_t **a_dump_datum, struct voting *a_voting)
+static byte_t *s_votings_backup(dap_chain_net_id_t a_net_id, uint64_t *a_state_size, uint32_t *a_state_count)
 {
-    size_t l_votes_count = 0;
-    size_t l_voting_size = s_voting_serial_size_calc(a_voting, &l_votes_count);
-    dap_chain_datum_t *l_dump_datum = DAP_REALLOC(*a_dump_datum, dap_chain_datum_size(*a_dump_datum) + l_voting_size);
-    if (!l_dump_datum) {
-        DAP_DELETE(*a_dump_datum);
-        return -1;
-    }
-    l_dump_datum->header.data_size += l_voting_size;
-    struct voting_serial *cur = (struct voting_serial *)(l_dump_datum->data + l_dump_datum->header.data_size);
-    *cur = (struct voting_serial) {
-            .size = l_voting_size,
-            .hash = a_voting->hash,
-            .voting_start = a_voting->start_time,
-            .voting_expire = a_voting->params->voting_expire,
-            .votes_max_count = a_voting->params->votes_max_count,
-            .votes_count = l_votes_count,
-            .delegate_key_required = a_voting->params->delegate_key_required,
-            .vote_changing_allowed = a_voting->params->vote_changing_allowed
-    };
-    byte_t *l_tsd = dap_tsd_write(cur->question_n_options_n_votes, VOTING_TSD_TYPE_QUESTION, a_voting->params->question, strlen(a_voting->params->question));
-    for (dap_list_t *it = a_voting->params->options; it; it = it->next)
-        l_tsd = dap_tsd_write(l_tsd, VOTING_TSD_TYPE_OPTION, it->data, strlen(it->data));
-    for (dap_list_t *it = a_voting->votes; it; it = it->next)
-        l_tsd = dap_tsd_write(l_tsd, VOTING_TSD_TYPE_VOTE, it->data, sizeof(struct vote));
-    assert(l_tsd == l_dump_datum->data + l_dump_datum->header.data_size);
-    *a_dump_datum = l_dump_datum;
-    return 0;
-}
-
-static int s_votings_backup(dap_chain_net_t *a_net)
-{
-    struct voting *votings_ht = s_votings_ht_get(a_net->pub.id);
+    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);
     if (!votings_ht) {
-        log_it(L_INFO, "No data to backup for voting service for net id 0x%016" DAP_UINT64_FORMAT_x, a_net->pub.id.uint64);
-        return 0;
+        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;
     }
-    dap_chain_datum_t *l_hardfork_state_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_SERVICE_STATE, NULL, sizeof(dap_chain_datum_service_state_t));
-    if (!l_hardfork_state_datum)
-        return -1;
-    size_t i = 0;
-    for (struct voting *it = votings_ht; it; it = it->hh.next, i++) {
-        int ret = s_voting_dump(&l_hardfork_state_datum, it);
-        if (ret)
-            return ret;
+    size_t l_states_count = HASH_COUNT(votings_ht);
+    byte_t *ret = (byte_t *)DAP_NEW_Z_COUNT_RET_VAL_IF_FAIL(struct voting_serial, l_states_count, NULL, NULL);
+    size_t l_total_size = 0;
+    for (struct voting *it = votings_ht; it; it = it->hh.next) {
+        size_t l_votes_count = 0;
+        size_t l_voting_size = s_voting_serial_size_calc(it, &l_votes_count);
+        ret = DAP_REALLOC_RET_VAL_IF_FAIL(ret, l_total_size + l_voting_size, NULL, NULL);
+        struct voting_serial *cur = (struct voting_serial *)(ret + l_total_size);
+        l_total_size += l_voting_size;
+        *cur = (struct voting_serial) {
+                .size = l_voting_size,
+                .hash = it->hash,
+                .voting_start = it->start_time,
+                .voting_expire = it->params->voting_expire,
+                .votes_max_count = it->params->votes_max_count,
+                .votes_count = l_votes_count,
+                .delegate_key_required = it->params->delegate_key_required,
+                .vote_changing_allowed = it->params->vote_changing_allowed
+        };
+        byte_t *l_tsd = dap_tsd_write(cur->question_n_options_n_votes, VOTING_TSD_TYPE_QUESTION, it->params->question, strlen(it->params->question));
+        for (dap_list_t *lst = it->params->options; lst; lst = lst->next)
+            l_tsd = dap_tsd_write(l_tsd, VOTING_TSD_TYPE_OPTION, lst->data, strlen(lst->data));
+        for (dap_list_t *lst = it->votes; lst; lst = lst->next)
+            l_tsd = dap_tsd_write(l_tsd, VOTING_TSD_TYPE_VOTE, lst->data, sizeof(struct vote));
+        assert(l_tsd == ret + l_total_size);
     }
-    ((dap_chain_datum_service_state_t *)l_hardfork_state_datum->data)->srv_uid = (dap_chain_srv_uid_t) { .uint64 = DAP_CHAIN_NET_SRV_VOTING_ID };
-    ((dap_chain_datum_service_state_t *)l_hardfork_state_datum->data)->states_count = i;
-    dap_chain_t *l_chain = dap_chain_net_get_default_chain_by_chain_type(a_net, CHAIN_TYPE_TX);
-    char *l_datum_hash = dap_chain_mempool_datum_add(l_hardfork_state_datum, l_chain, "hex");
-    log_it(L_INFO, "Datum hash %s with voting service states successfully placed in mempool", l_datum_hash);
-    DAP_DELETE(l_datum_hash);
+    if (a_state_count)
+        *a_state_count = l_states_count;
+    if (a_state_size)
+        *a_state_size = l_total_size / l_states_count;
+    if (*a_state_size)
+        (*a_state_size)--;
     return 0;
 }
 
diff --git a/modules/type/blocks/dap_chain_block.c b/modules/type/blocks/dap_chain_block.c
index 7b7349c25e037c3dc3d71429fe4384c60bf6b4bf..2f5131931bbde985ec5b32942c79845e96c0cdd0 100644
--- a/modules/type/blocks/dap_chain_block.c
+++ b/modules/type/blocks/dap_chain_block.c
@@ -517,6 +517,7 @@ static uint8_t *s_meta_extract(dap_chain_block_meta_t *a_meta)
                s_meta_type_to_string(a_meta->hdr.type), a_meta->hdr.data_size, sizeof(uint8_t));
     break;
     case DAP_CHAIN_BLOCK_META_EXCLUDED_KEYS:
+    case DAP_CHAIN_BLOCK_META_GENERATION:
         if (a_meta->hdr.data_size >= sizeof(uint16_t)) {
             uint16_t l_expected_size = *(uint16_t *)a_meta->data + sizeof(uint16_t);
             if (!(l_expected_size % sizeof(uint16_t)) &&
@@ -578,12 +579,13 @@ int dap_chain_block_meta_extract(dap_chain_block_t *a_block, size_t a_block_size
                                     size_t *a_block_links_count,
                                     bool *a_is_genesis,
                                     uint64_t *a_nonce,
-                                    uint64_t *a_nonce2)
+                                    uint64_t *a_nonce2,
+                                    uint16_t *a_generation)
 {
     dap_return_val_if_fail(a_block && a_block_size, -1);
     // Check for meta that could be faced only once
     bool l_was_prev = false, l_was_genesis = false, l_was_anchor = false, l_was_nonce = false,
-         l_was_nonce2 = false, l_was_merkle = false, l_was_reward = false;
+         l_was_nonce2 = false, l_was_merkle = false, l_was_reward = false, l_was_generation = false;
     // Init links parsing
     size_t l_links_count = 0, l_links_count_max = 5;
     if (a_block_size < sizeof(a_block->hdr)) {
@@ -703,6 +705,20 @@ int dap_chain_block_meta_extract(dap_chain_block_t *a_block, size_t a_block_size
                     return -4;
             }
         break;
+        case DAP_CHAIN_BLOCK_META_GENERATION:
+            if (l_was_generation) {
+                log_it(L_WARNING, "Generaion number could be only one in the block, meta #%zu is ignored ", i);
+                break;
+            }
+            l_was_generation = true;
+            if (a_generation) {
+                l_meta_data = s_meta_extract(l_meta);
+                if (l_meta_data)
+                    *a_generation = *(uint16_t *)l_meta_data;
+                else
+                    return -4;
+            }
+        break;
         case DAP_CHAIN_BLOCK_META_EMERGENCY:
         case DAP_CHAIN_BLOCK_META_EXCLUDED_KEYS:
         case DAP_CHAIN_BLOCK_META_SYNC_ATTEMPT:
diff --git a/modules/type/blocks/dap_chain_block_cache.c b/modules/type/blocks/dap_chain_block_cache.c
index 707a6d4903d81f7ddbe039249f436c6ff8939b63..f05dea7a552d7c3b1bda961add3f82ca4a00a33f 100644
--- a/modules/type/blocks/dap_chain_block_cache.c
+++ b/modules/type/blocks/dap_chain_block_cache.c
@@ -115,7 +115,8 @@ int dap_chain_block_cache_update(dap_chain_block_cache_t *a_block_cache, dap_has
                                         &a_block_cache->links_hash_count,
                                         &a_block_cache->is_genesis,
                                         &a_block_cache->nonce,
-                                        &a_block_cache->nonce2))
+                                        &a_block_cache->nonce2,
+                                        &a_block_cache->generation))
         return -1;
 
     DAP_DEL_Z(a_block_cache->datum);
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index b98acbf16dc5d40042b231ee24f7e2181fb59836..67409a44d75efb02e10f5cdbc20bba6378dda6f3 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -694,7 +694,7 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void **a_str_reply)
         }break;
         case SUBCMD_NEW_DATUM_ADD:{
             size_t l_datums_count=1;
-            char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+            char * l_gdb_group_mempool = dap_chain_mempool_group_new(l_chain);
             dap_chain_datum_t ** l_datums = DAP_NEW_Z_SIZE(dap_chain_datum_t*,
                                                            sizeof(dap_chain_datum_t*)*l_datums_count);
             if (!l_datums) {
@@ -1525,8 +1525,9 @@ static int s_add_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_ca
 
     size_t l_block_offset = 0;
     size_t l_datum_size = 0;
-    for(size_t i=0; i<a_block_cache->datum_count && l_block_offset +sizeof(a_block_cache->block->hdr) < a_block_cache->block_size ;
-        i++, l_block_offset += l_datum_size ){
+    for (size_t i = 0;
+            i < a_block_cache->datum_count && l_block_offset + sizeof(a_block_cache->block->hdr) < a_block_cache->block_size;
+            i++, l_block_offset += l_datum_size) {
         dap_chain_datum_t *l_datum = a_block_cache->datum[i];
         size_t l_datum_data_size = l_datum->header.data_size;
         l_datum_size = l_datum_data_size + sizeof(l_datum->header);
@@ -1538,8 +1539,10 @@ static int s_add_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_ca
         dap_hash_fast_t *l_datum_hash = a_block_cache->datum_hash + i;
         dap_ledger_datum_iter_data_t l_datum_index_data = { .token_ticker = "0", .action = DAP_CHAIN_TX_TAG_ACTION_UNKNOWN , .uid.uint64 = 0 };
 
-        int l_res = dap_chain_datum_add(a_blocks->chain, l_datum, l_datum_size, l_datum_hash, &l_datum_index_data);
-        if (l_datum->header.type_id != DAP_CHAIN_DATUM_TX || l_res != DAP_LEDGER_CHECK_ALREADY_CACHED){ // If this is any datum other than a already cached transaction
+        int l_res = (a_block_cache->generation && a_block_cache->generation == a_blocks->generation)
+                ? dap_chain_datum_add_hardfork_data(a_blocks->chain, l_datum, l_datum_size, l_datum_hash, &l_datum_index_data)
+                : dap_chain_datum_add(a_blocks->chain, l_datum, l_datum_size, l_datum_hash, &l_datum_index_data);
+        if (l_datum->header.type_id != DAP_CHAIN_DATUM_TX || l_res != DAP_LEDGER_CHECK_ALREADY_CACHED) { // If this is any datum other than a already cached transaction
             l_ret++;
             if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX)
                 PVT(a_blocks)->tx_count++;  
@@ -1561,7 +1564,7 @@ static int s_add_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_ca
             HASH_ADD(hh, PVT(a_blocks)->datum_index, datum_hash, sizeof(*l_datum_hash), l_datum_index);
             pthread_rwlock_unlock(&PVT(a_blocks)->datums_rwlock);
             dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_blocks->chain, a_blocks->chain->active_cell_id);
-            dap_chain_datum_notify(l_cell, l_datum_hash, &l_datum_index->block_cache->block_hash, (byte_t*)l_datum, l_datum_size, l_res, l_datum_index_data.action, l_datum_index_data.uid);
+            dap_chain_datum_notify(l_cell, l_datum_hash, &l_datum_index->block_cache->block_hash, (byte_t *)l_datum, l_datum_size, l_res, l_datum_index_data.action, l_datum_index_data.uid);
         }
     }
     debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str,
@@ -2051,7 +2054,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t *a_chain,
         }
     }
 
-    if (ret == ATOM_FORK || ret == ATOM_ACCEPT) {
+    if (ret == ATOM_ACCEPT || (!l_blocks->is_hardfork_state && ret == ATOM_FORK)) {
         // 2nd level consensus
         if (l_blocks->callback_block_verify && l_blocks->callback_block_verify(l_blocks, l_block, a_atom_hash, /* Old bug, crutch for it */ a_atom_size)) {
             // Hard accept list
@@ -2767,12 +2770,12 @@ static int s_aggregate_fees(dap_chain_cs_blocks_hardfork_fees_t **a_out_list, da
     }
     switch (a_type) {
     case DAP_CHAIN_BLOCK_COLLECT_FEES:
-        if (SUM_256_256(l_exist->fees_sum, a_value, &l_exist->fees_sum)) {
+        if (SUM_256_256(l_exist->fees_n_rewards_sum, a_value, &l_exist->fees_n_rewards_sum)) {
             log_it(L_ERROR, "Integer overflow of hardfork aggregated data for not withdrowed fees");
             return -2;
         } break;
     case DAP_CHAIN_BLOCK_COLLECT_REWARDS:
-        if (SUM_256_256(l_exist->rewards_sum, a_value, &l_exist->rewards_sum)) {
+        if (SUM_256_256(l_exist->fees_n_rewards_sum, a_value, &l_exist->fees_n_rewards_sum)) {
             log_it(L_ERROR, "Integer overflow of hardfork aggregated data for not withdrowed rewards");
             return -2;
         } break;
diff --git a/modules/type/blocks/include/dap_chain_block.h b/modules/type/blocks/include/dap_chain_block.h
index a0407e390a52d9a2a759d96fd0ee9dca63d17271..c21e531057a10b39334f2337f4cd5476d05d3fdb 100644
--- a/modules/type/blocks/include/dap_chain_block.h
+++ b/modules/type/blocks/include/dap_chain_block.h
@@ -63,6 +63,7 @@ typedef struct dap_chain_block_meta{
 // Block metadata types
 
 #define DAP_CHAIN_BLOCK_META_GENESIS            0x01
+#define DAP_CHAIN_BLOCK_META_GENERATION         0x02
 #define DAP_CHAIN_BLOCK_META_PREV               0x10
 #define DAP_CHAIN_BLOCK_META_ANCHOR             0x11
 #define DAP_CHAIN_BLOCK_META_LINK               0x12
@@ -104,7 +105,8 @@ int dap_chain_block_meta_extract(dap_chain_block_t *a_block, size_t a_block_size
                                  size_t *a_block_links_count,
                                  bool *a_is_genesis,
                                  uint64_t *a_nonce,
-                                 uint64_t *a_nonce2);
+                                 uint64_t *a_nonce2,
+                                 uint16_t *a_generation);
 // Add datum in block
 size_t dap_chain_block_datum_add(dap_chain_block_t ** a_block_ptr, size_t a_block_size, dap_chain_datum_t * a_datum, size_t a_datum_size);
 size_t dap_chain_block_datum_del_by_hash(dap_chain_block_t ** a_block_ptr, size_t a_block_size, dap_chain_hash_fast_t* a_datum_hash);
diff --git a/modules/type/blocks/include/dap_chain_block_cache.h b/modules/type/blocks/include/dap_chain_block_cache.h
index 01d6e5801c22612719d2d873c3ed2b5899fa2f56..24eca3786dd8cc36cd05b4cbb3de864d5d077ec8 100644
--- a/modules/type/blocks/include/dap_chain_block_cache.h
+++ b/modules/type/blocks/include/dap_chain_block_cache.h
@@ -52,6 +52,7 @@ typedef struct dap_chain_block_cache {
     uint64_t nonce;
     uint64_t nonce2;
     bool is_genesis;
+    uint16_t generation;
 
     // Block's signatures
     size_t sign_count; // Number of signatures in block's tail
diff --git a/modules/type/blocks/include/dap_chain_cs_blocks.h b/modules/type/blocks/include/dap_chain_cs_blocks.h
index b792f244e7af083e0cdf77f840edc4d14174974a..d260fdcfa37f4ee110952495ed8a316c80e772c9 100644
--- a/modules/type/blocks/include/dap_chain_cs_blocks.h
+++ b/modules/type/blocks/include/dap_chain_cs_blocks.h
@@ -39,13 +39,14 @@ typedef dap_chain_block_t * (*dap_chain_cs_blocks_callback_block_create_t)(dap_c
                                                                                dap_chain_datum_t *,
                                                                                dap_chain_hash_fast_t *,
                                                                                size_t, size_t*);
-typedef struct dap_chain_cs_blocks
-{
-   dap_chain_t * chain;
-   // For new block creating
-   dap_chain_block_t * block_new;
+typedef struct dap_chain_cs_blocks {
+   dap_chain_t *chain;
+   dap_chain_block_t *block_new; // For new block creating
    size_t block_new_size;
 
+   bool is_hardfork_state;
+   uint16_t generation;
+
    dap_chain_cs_blocks_callback_t callback_delete;
    dap_chain_cs_blocks_callback_block_create_t callback_block_create;
    dap_chain_cs_blocks_callback_block_verify_t callback_block_verify;
@@ -80,8 +81,7 @@ typedef enum s_com_blocks_err{
 
 typedef struct dap_chain_cs_blocks_hardfork_fees {
     dap_sign_t *owner_sign;
-    uint256_t fees_sum;
-    uint256_t rewards_sum;
+    uint256_t fees_n_rewards_sum;
     struct dap_chain_cs_blocks_hardfork_fees *prev, *next;
 } dap_chain_cs_blocks_hardfork_fees_t;
 
@@ -91,6 +91,8 @@ int dap_chain_cs_blocks_init();
 void dap_chain_cs_blocks_deinit();
 dap_chain_block_cache_t *dap_chain_block_cache_get_by_hash(dap_chain_cs_blocks_t *a_blocks, dap_chain_hash_fast_t *a_block_hash);
 
+dap_chain_cs_blocks_hardfork_fees_t *dap_chain_cs_blocks_fees_aggregate(dap_chain_t *a_chain);
+
 DAP_STATIC_INLINE char *dap_chain_cs_blocks_get_fee_group(const char *a_net_name)
 {
     return dap_strdup_printf("local.%s.fees", a_net_name);