diff --git a/CMakeLists.txt b/CMakeLists.txt
index cb475b591e18d82736167b25857ac4c58332f58d..87f693ce8f15040dec97208f3d0ec55173b55224 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -52,6 +52,7 @@ endif(NOT DAP_INT128_SUPPORT)
 if (BUILD_CELLFRAME_SDK_TESTS)
     enable_testing()
     add_definitions("-DDAP_LEDGER_TEST")
+    add_definitions("-DDAP_CHAIN_BLOCKS_TEST")
 endif()
 
 if (BUILD_WITH_ZIP)
diff --git a/dap-sdk b/dap-sdk
index fef9c1e0ed18345ba26aa8ffe610cc83a55899f2..41abc05d56f0a54a3d1158726aa6f70c030effa2 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit fef9c1e0ed18345ba26aa8ffe610cc83a55899f2
+Subproject commit 41abc05d56f0a54a3d1158726aa6f70c030effa2
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 953b3bd2fa67436160376ad997e8b418f8a8f12d..2bec84dd237bee32e8c33dce017618f091227549 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -798,6 +798,10 @@ const char* dap_chain_get_path(dap_chain_t *a_chain)
 }
 
 void dap_chain_atom_notify(dap_chain_cell_t *a_chain_cell, dap_hash_fast_t *a_hash, const uint8_t *a_atom, size_t a_atom_size) {
+#ifdef DAP_CHAIN_BLOCKS_TEST
+    return;
+#endif
+
     if ( !a_chain_cell->chain->atom_notifiers )
         return;
     dap_list_t *l_iter;
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index 874a84e6db7c53586fb8ca8f3b11359e21a16022..7034d04aa6fefb3f72740630f13e603cee2a45a9 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -290,7 +290,10 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell)
     if (a_chain->is_mapped) {
         a_cell->map_pos = a_cell->map + sizeof(dap_chain_cell_file_header_t);
         for (uint64_t l_el_size = 0; a_cell->map_pos < a_cell->map_end && ( l_el_size = *(uint64_t*)a_cell->map_pos ); ++q, a_cell->map_pos += l_el_size) {
-            a_chain->callback_atom_add(a_chain, (dap_chain_atom_ptr_t)(a_cell->map_pos += sizeof(uint64_t)), l_el_size);
+            dap_hash_fast_t l_atom_hash = {};
+            dap_chain_atom_ptr_t l_atom = (dap_chain_atom_ptr_t)(a_cell->map_pos += sizeof(uint64_t));
+            dap_hash_fast(l_atom, l_el_size, &l_atom_hash);
+            a_chain->callback_atom_add(a_chain, l_atom, l_el_size, &l_atom_hash);
         }
         fseek(a_cell->file_storage, a_cell->map_pos - a_cell->map, SEEK_SET);
     } else { 
@@ -316,8 +319,12 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell)
                 l_ret = -6;
                 break;
             }
-            if ( a_chain->callback_atom_add(a_chain, l_element, l_el_size) != ATOM_ACCEPT )
+            dap_hash_fast_t l_atom_hash = {};
+            dap_hash_fast(l_element, l_el_size, &l_atom_hash);
+            dap_chain_atom_verify_res_t l_res = a_chain->callback_atom_add(a_chain, l_element, l_el_size, &l_atom_hash);
+            if (l_res != ATOM_ACCEPT && l_res != ATOM_FORK) {
                 DAP_DELETE(l_element);
+            }
             ++q;
         }
         fseek(a_cell->file_storage, l_full_size, SEEK_SET);
diff --git a/modules/chain/dap_chain_ch.c b/modules/chain/dap_chain_ch.c
index 6b74b128727f49fdf73106d47a271a42120e7549..bc96f36faad0c0c125868d8a69f7f83d32a30948 100644
--- a/modules/chain/dap_chain_ch.c
+++ b/modules/chain/dap_chain_ch.c
@@ -621,9 +621,12 @@ static bool s_sync_in_chains_callback(void *a_arg)
         return false;
     }
     char *l_atom_hash_str = NULL;
+    l_atom_hash_str = DAP_NEW_STACK_SIZE(char, DAP_CHAIN_HASH_FAST_STR_SIZE); 
+    dap_hash_fast_t l_atom_hash = {}; 
+    dap_hash_fast(l_atom, l_atom_size, &l_atom_hash); 
     if (s_debug_more)
         dap_get_data_hash_str_static(l_atom, l_atom_size, l_atom_hash_str);
-    dap_chain_atom_verify_res_t l_atom_add_res = l_chain->callback_atom_add(l_chain, l_atom, l_atom_size);
+    dap_chain_atom_verify_res_t l_atom_add_res = l_chain->callback_atom_add(l_chain, l_atom, l_atom_size, &l_atom_hash);
     bool l_ack_send = false;
     switch (l_atom_add_res) {
     case ATOM_PASS:
@@ -642,6 +645,14 @@ static bool s_sync_in_chains_callback(void *a_arg)
         debug_if(s_debug_more, L_WARNING, "Atom with hash %s for %s:%s rejected", l_atom_hash_str, l_chain->net_name, l_chain->name);
         break;
     }
+    case ATOM_FORK: {
+        debug_if(s_debug_more, L_WARNING, "Atom with hash %s for %s:%s added to a fork branch.", l_atom_hash_str, l_chain->net_name, l_chain->name);
+        if (dap_chain_atom_save(l_chain->cells, l_atom, l_atom_size, NULL) < 0)
+            log_it(L_ERROR, "Can't save atom %s to the file", l_atom_hash_str);
+        else
+            l_ack_send = true;
+        break;
+    }
     default:
         log_it(L_CRITICAL, "Wtf is this ret code? %d", l_atom_add_res);
         break;
diff --git a/modules/chain/dap_chain_cs.c b/modules/chain/dap_chain_cs.c
index d61a52a22a9e84e8543cfa1e6d5a7372105bde84..5d5420556ffaac66494005f36fe2f3fde934f0cc 100644
--- a/modules/chain/dap_chain_cs.c
+++ b/modules/chain/dap_chain_cs.c
@@ -121,7 +121,15 @@ void dap_chain_cs_add (const char * a_cs_str,  dap_chain_callback_new_cfg_t a_ca
 int dap_chain_cs_create(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
 {
     dap_chain_callback_new_cfg_item_t *l_item = NULL;
+#if defined(DAP_CHAIN_BLOCKS_TEST) || defined(DAP_LEDGER_TEST)
+    const char *l_consensus = NULL;
+    if (a_chain->id.uint64 == 0)
+        l_consensus = dap_strdup("dag_poa");
+    else
+        l_consensus = dap_strdup("esbocs");
+#else
     const char *l_consensus = dap_config_get_item_str( a_chain_cfg, "chain", "consensus");
+#endif
     if(l_consensus)
         HASH_FIND_STR(s_cs_callbacks, l_consensus, l_item );
     if (l_item) {
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index f0c360640563ecfd161b013d67cee6561e4aca15..cb3f76092c2751259ec4d68e6e26b0488190be37 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -61,14 +61,15 @@ typedef struct dap_chain_datum_iter {
 } dap_chain_datum_iter_t;
 
 typedef enum dap_chain_atom_verify_res{
-    ATOM_ACCEPT = 0, ATOM_PASS, ATOM_REJECT, ATOM_MOVE_TO_THRESHOLD
+    ATOM_ACCEPT = 0, ATOM_PASS, ATOM_REJECT, ATOM_MOVE_TO_THRESHOLD, ATOM_FORK
 } dap_chain_atom_verify_res_t;
 
 static const char* const dap_chain_atom_verify_res_str[] = {
     [ATOM_ACCEPT]   = "accepted",
     [ATOM_PASS]     = "skipped",
     [ATOM_REJECT]   = "rejected",
-    [ATOM_MOVE_TO_THRESHOLD] = "thresholded"
+    [ATOM_MOVE_TO_THRESHOLD] = "thresholded",
+    [ATOM_FORK] = "forked"
 };
 
 typedef enum dap_chain_iter_op {
@@ -84,9 +85,9 @@ typedef void (*dap_chain_callback_t)(dap_chain_t *);
 typedef int (*dap_chain_callback_new_cfg_t)(dap_chain_t *, dap_config_t *);
 typedef void (*dap_chain_callback_ptr_t)(dap_chain_t *, void * );
 
-typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_t)(dap_chain_t *, dap_chain_atom_ptr_t, size_t );
+typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_t)(dap_chain_t *, dap_chain_atom_ptr_t, size_t, dap_hash_fast_t*);
 typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_form_treshold_t)(dap_chain_t *, size_t *);
-typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_verify_t)(dap_chain_t *, dap_chain_atom_ptr_t , size_t);
+typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_verify_t)(dap_chain_t *, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t*);
 typedef size_t (*dap_chain_callback_atom_get_hdr_size_t)(void);
 
 typedef dap_chain_atom_iter_t * (*dap_chain_callback_atom_iter_create_t)(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_hash_from);
diff --git a/modules/chain/tests/CMakeLists.txt b/modules/chain/tests/CMakeLists.txt
index 6b4acedc87a31503ec16492c47bbe1e8f29ff392..69f2e3f0ffe89e13cbed7675364773a4e26b717f 100755
--- a/modules/chain/tests/CMakeLists.txt
+++ b/modules/chain/tests/CMakeLists.txt
@@ -7,7 +7,7 @@ file(GLOB DAP_CHAIN_TESTS_SRC *.c)
 
 add_executable(${PROJECT_NAME} ${DAP_CHAIN_TESTS_SRC} ${DAP_CHAIN_TESTS_HEADERS})
 
-target_link_libraries(${PROJECT_NAME} dap_test dap_core dap_chain dap_chain_wallet)
+target_link_libraries(${PROJECT_NAME} dap_test dap_core dap_chain dap_chain_wallet dap_chain_net_srv_vpn dap_chain_cs_blocks dap_chain_cs_dag_poa)
 
 if (DARWIN)
     target_link_libraries(${PROJECT_NAME} bz2)
diff --git a/modules/chain/tests/dap_chain_ledger_tests.c b/modules/chain/tests/dap_chain_ledger_tests.c
index 81246a5e86694957a3e518759127c89b17bd0ee8..65ab04d6b278bcaf66ab412c0a8b7561297d46f0 100644
--- a/modules/chain/tests/dap_chain_ledger_tests.c
+++ b/modules/chain/tests/dap_chain_ledger_tests.c
@@ -4,12 +4,25 @@
 #include "dap_cert.h"
 #include "dap_chain_wallet.h"
 #include "dap_math_ops.h"
+#include "dap_config.h"
+#include "dap_chain.h"
 #include "dap_chain_net.h"
+#include "dap_chain_common.h"
+#include "dap_chain_net_srv_vpn.h"
+#include "dap_chain_net_srv_stake_lock.h"
+#include "dap_chain_net_srv_stake_pos_delegate.h"
+#include "dap_chain_net_decree.h"
+#include "dap_chain_block.h"
+#include "dap_chain_cs_blocks.h"
+#include "dap_chain_cs_esbocs.h"
+#include "dap_chain_cs.h"
+#include "dap_chain_cs_dag_poa.h"
 
 static const uint64_t s_fee = 2;
 static const uint64_t s_total_supply = 500;
 static const uint64_t s_standard_value_tx = 500;
-static const char* s_token_ticker = "TestCoins";
+static const char* s_token_ticker = "TestCoin";
+static const char* s_delegated_token_ticker = "mTestCoin";
 
 dap_chain_datum_token_t  *dap_ledger_test_create_datum_decl(dap_cert_t *a_cert, size_t *a_token_size,
                                                                   const char *a_token_ticker, uint256_t a_total_supply,
@@ -87,26 +100,610 @@ dap_chain_datum_tx_t *dap_ledger_test_create_tx(dap_enc_key_t *a_key_from, dap_c
     return l_tx;
 }
 
-void dap_ledger_test_double_spending(
-        dap_ledger_t *a_ledger, dap_hash_fast_t *a_prev_hash, dap_enc_key_t  *a_from_key, dap_chain_net_id_t a_net_id) {
-    dap_print_module_name("dap_ledger_double_spending");
+dap_chain_datum_tx_t *dap_ledger_test_create_tx_full(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev,
+                                                      dap_chain_addr_t *a_addr_to, uint256_t a_value, dap_ledger_t *a_ledger) {
+
+    dap_chain_addr_t l_addr = {0};
+    dap_chain_addr_fill_from_key(&l_addr, a_key_from, a_ledger->net->pub.id);
+    dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev);
+    int l_out_idx = 0;
+    dap_chain_tx_out_t *l_tx_prev_out = (dap_chain_tx_out_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT, NULL);
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(a_hash_prev, 0);
+    dap_chain_tx_out_t *l_out = dap_chain_datum_tx_item_out_create(a_addr_to, a_value);
+    uint256_t l_change = {};
+    SUBTRACT_256_256(l_tx_prev_out->header.value, a_value, &l_change);
+    dap_chain_tx_out_t *l_out_change = dap_chain_datum_tx_item_out_create(&l_addr, l_change);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out);
+    dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from);
+    DAP_DEL_Z(l_in);
+    DAP_DEL_Z(l_out);
+    return l_tx;
+}
+
+dap_chain_datum_tx_t *dap_ledger_test_create_tx_cond(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev,
+                                                      dap_chain_addr_t *a_addr_to, uint256_t a_value, dap_ledger_t *a_ledger) {
+    dap_chain_addr_t l_addr = {0};
+    dap_chain_addr_fill_from_key(&l_addr, a_key_from, a_ledger->net->pub.id);
+    dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev);
+    int l_out_idx = 0;
+    dap_chain_tx_out_t *l_tx_prev_out = (dap_chain_tx_out_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT, NULL);
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(a_hash_prev, 0);
+    dap_chain_net_srv_uid_t l_srv_uid = {.uint64 = 1};
+    dap_chain_net_srv_price_unit_uid_t l_uint_type = {.enm = SERV_UNIT_SEC};
+    dap_pkey_t *l_pkey = dap_pkey_from_enc_key(a_key_from);
+    dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_pay(l_pkey, l_srv_uid, a_value, uint256_0, l_uint_type, NULL, 0);
+    uint256_t l_change = {};
+    SUBTRACT_256_256(l_tx_prev_out->header.value, a_value, &l_change);
+    dap_chain_tx_out_t *l_out_change = dap_chain_datum_tx_item_out_create(&l_addr, l_change);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_cond);
+    dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from);
+    DAP_DEL_Z(l_in);
+    DAP_DEL_Z(l_out_cond);
+    DAP_DEL_Z(l_out_change);
+    return l_tx;
+}
+
+dap_chain_datum_tx_t *dap_ledger_test_create_spend_tx_cond(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev,
+                                                      dap_enc_key_t *a_key_to, uint256_t a_value, dap_ledger_t *a_ledger) {
+    dap_chain_addr_t l_addr = {0};
+    dap_chain_addr_fill_from_key(&l_addr, a_key_from, a_ledger->net->pub.id);
+    // get previous transaction
+    dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev);
+     // get previous cond out
+    int l_out_idx = 0;
+    dap_chain_tx_out_cond_t *l_tx_prev_out = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT_COND, NULL);
+
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    dap_chain_tx_in_cond_t *l_in_cond = dap_chain_datum_tx_item_in_cond_create(a_hash_prev, 1, 0);
+
+    // create conditional output
+    dap_chain_net_srv_uid_t l_srv_uid = {.uint64 = 1};
+    dap_chain_net_srv_price_unit_uid_t l_unit_type = {.enm = SERV_UNIT_SEC};
+    dap_pkey_t *l_pkey = dap_pkey_from_enc_key(a_key_from);
+    uint256_t l_cond_change = {};
+    SUBTRACT_256_256(l_tx_prev_out->header.value, a_value, &l_cond_change);
+    dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_pay(l_pkey, l_tx_prev_out->header.srv_uid, l_cond_change, uint256_0, l_tx_prev_out->subtype.srv_pay.unit, NULL, 0);
+
+    // create receipt
+    dap_chain_datum_tx_receipt_t * l_receipt = dap_chain_datum_tx_receipt_create(l_srv_uid, l_unit_type, 1, a_value, NULL, 0);
+    // Sign with our wallet
+    l_receipt = dap_chain_datum_tx_receipt_sign_add(l_receipt, a_key_to);
+    l_receipt = dap_chain_datum_tx_receipt_sign_add(l_receipt, a_key_from);
+    
+    
+    // add all items to tx
+    dap_chain_addr_t l_addr_to = {0};
+    dap_chain_addr_fill_from_key(&l_addr_to, a_key_to, a_ledger->net->pub.id);
+    dap_chain_tx_out_t *l_out_change = dap_chain_datum_tx_item_out_create(&l_addr_to, a_value);
+    dap_chain_datum_tx_add_item(&l_tx, (byte_t*)l_receipt);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_cond);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_cond);
+    dap_chain_datum_tx_add_sign_item(&l_tx, a_key_to);
+    DAP_DEL_Z(l_in_cond);
+    DAP_DEL_Z(l_out_cond);
+    DAP_DEL_Z(l_receipt);
+    DAP_DEL_Z(l_out_change);
+    return l_tx;
+}
+
+dap_chain_datum_tx_t *dap_ledger_test_create_return_from_tx_cond(dap_chain_hash_fast_t *a_hash_prev,
+                                                      dap_enc_key_t *a_key_to, dap_ledger_t *a_ledger) {
+    // get previous transaction
+    dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev);
+     // get previous cond out
+    int l_out_idx = 1;
+    dap_chain_tx_out_cond_t *l_tx_prev_out = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT_COND, NULL);
+
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    dap_chain_tx_in_cond_t *l_in_cond = dap_chain_datum_tx_item_in_cond_create(a_hash_prev, 1, 0);
+
+    // add all items to tx
+    dap_chain_addr_t l_addr_to = {0};
+    dap_chain_addr_fill_from_key(&l_addr_to, a_key_to, a_ledger->net->pub.id);
+    dap_chain_tx_out_t *l_out_change = dap_chain_datum_tx_item_out_create(&l_addr_to, l_tx_prev_out->header.value);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_cond);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change);
+    dap_chain_datum_tx_add_sign_item(&l_tx, a_key_to);
+    DAP_DEL_Z(l_in_cond);
+    DAP_DEL_Z(l_out_change);
+    return l_tx;
+}
+
+dap_chain_datum_tx_t *dap_ledger_test_create_stake_tx_cond(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev, uint256_t a_value, dap_ledger_t *a_ledger) {
+    dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
+    // get previous transaction
+    dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev);
+     // get previous cond out
+    int l_out_idx = 0;
+    dap_chain_tx_out_t *l_tx_prev_out = (dap_chain_tx_out_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT, NULL);
+    
+    dap_chain_addr_t l_addr_to = {0};
+    dap_chain_addr_fill_from_key(&l_addr_to, a_key_from, a_ledger->net->pub.id);
+
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(a_hash_prev, 0);
+
+    dap_chain_tx_in_ems_t *l_in_ems = DAP_NEW_Z(dap_chain_tx_in_ems_t);
+    l_in_ems->header.type = TX_ITEM_TYPE_IN_EMS;
+    l_in_ems->header.token_emission_chain_id.uint64 = 0;
+    memset(&l_in_ems->header.token_emission_hash, 0, sizeof(l_in_ems->header.token_emission_hash));
+    strcpy(l_in_ems->header.ticker, s_delegated_token_ticker);
+
+    dap_time_t a_time_staking = 1;
+    dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake_lock(
+                                                l_uid, a_value, a_time_staking, uint256_0);
+
+    // add all items to tx
+    uint256_t value_change = {};
+    SUBTRACT_256_256(l_tx_prev_out->header.value, a_value, &value_change);
+    dap_chain_tx_out_ext_t *l_out_change = dap_chain_datum_tx_item_out_ext_create(&l_addr_to, value_change, s_token_ticker);
+    uint256_t a_delegated_value = {};
+    MULT_256_COIN(a_value, dap_chain_coins_to_balance("0.1"), &a_delegated_value);
+    dap_chain_tx_out_ext_t *l_out_delegated = dap_chain_datum_tx_item_out_ext_create(&l_addr_to, a_delegated_value, s_delegated_token_ticker);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_tx_out_cond);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_delegated);   
+    dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from);
+    DAP_DEL_Z(l_in);
+    DAP_DEL_Z(l_in_ems);
+    DAP_DEL_Z(l_out_change);
+    DAP_DEL_Z(l_out_delegated);
+    DAP_DEL_Z(l_tx_out_cond);
+
+    return l_tx;
+}
+
+dap_chain_datum_tx_t *dap_ledger_test_create_unstake_tx_cond(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev, uint256_t a_value, dap_ledger_t *a_ledger) {
+    dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
+    // get previous transaction
+    dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev);
+     // get previous cond out
+    int l_out_idx = 0;
+    dap_chain_tx_out_cond_t *l_tx_prev_out_cond = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_out_cond_get(l_tx_prev, 
+                                                                            DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, &l_out_idx);
+    
+    if(!l_tx_prev_out_cond || l_tx_prev_out_cond->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK)
+        return NULL;
+
+    l_out_idx = 4;
+    dap_chain_tx_out_ext_t *l_tx_prev_out_ext = (dap_chain_tx_out_ext_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT_EXT, NULL);
+
+    dap_chain_addr_t l_addr_to = {0};
+    dap_chain_addr_fill_from_key(&l_addr_to, a_key_from, a_ledger->net->pub.id);
+
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    dap_chain_tx_in_t *l_in_ext = dap_chain_datum_tx_item_in_create(a_hash_prev, 2);
+
+    dap_chain_tx_in_cond_t *l_in_cond = dap_chain_datum_tx_item_in_cond_create(a_hash_prev, 0, 0);
+    dap_chain_tx_out_ext_t *l_out_change = dap_chain_datum_tx_item_out_ext_create(&l_addr_to, l_tx_prev_out_cond->header.value, s_token_ticker);
+    dap_chain_addr_t l_addr_burning = {0};
+    dap_chain_tx_out_ext_t *l_out_burn = dap_chain_datum_tx_item_out_ext_create(&l_addr_burning, l_tx_prev_out_ext->header.value, s_delegated_token_ticker);
+
+
+    // add all items to tx
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ext);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_cond);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_burn);   
+    dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from);
+    
+    DAP_DEL_Z(l_in_ext);
+    DAP_DEL_Z(l_out_change);
+    DAP_DEL_Z(l_in_cond);
+    DAP_DEL_Z(l_out_burn);
+
+    return l_tx;
+}
+
+
+int dap_ledger_test_create_reward_decree(dap_chain_t *a_chain, dap_chain_net_id_t a_net_id, uint256_t a_value, dap_cert_t *a_cert)
+{
+    // Create decree
+    size_t l_tsd_total_size = sizeof(dap_tsd_t) + sizeof(uint256_t);
+    size_t l_decree_size = sizeof(dap_chain_datum_decree_t) + l_tsd_total_size;
+    dap_chain_datum_decree_t *l_decree = DAP_NEW_Z_SIZE(dap_chain_datum_decree_t, l_decree_size);
+    if (!l_decree) {
+        return -1;
+    }
+    // Fill the header
+    l_decree->decree_version = DAP_CHAIN_DATUM_DECREE_VERSION;
+    l_decree->header.ts_created = dap_time_now();
+    l_decree->header.type = DAP_CHAIN_DATUM_DECREE_TYPE_COMMON;
+    l_decree->header.common_decree_params.net_id = a_net_id;
+    l_decree->header.common_decree_params.chain_id = a_chain->id;
+    l_decree->header.common_decree_params.cell_id = (dap_chain_cell_id_t){.uint64 = 0};
+    l_decree->header.sub_type = DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_REWARD;
+    l_decree->header.data_size = l_tsd_total_size;
+    // Fill a TSD section
+    dap_tsd_t *l_tsd = (dap_tsd_t *)l_decree->data_n_signs;
+    l_tsd->type = DAP_CHAIN_DATUM_DECREE_TSD_TYPE_VALUE;
+    l_tsd->size = sizeof(uint256_t);
+    *(uint256_t*)(l_tsd->data) = a_value;
+    // Sign it
+    dap_sign_t *l_sign = dap_cert_sign(a_cert, l_decree, l_decree_size, 0);
+    if (!l_sign) {
+        DAP_DELETE(l_decree);
+        return -2;
+    }
+    size_t l_sign_size = dap_sign_get_size(l_sign);
+    l_decree_size += l_sign_size;
+    l_decree->header.signs_size = l_sign_size;
+    void *l_decree_rl = DAP_REALLOC(l_decree, l_decree_size);
+    if (!l_decree_rl) {
+        DAP_DELETE(l_decree);
+        return -3;
+    } else
+        l_decree = l_decree_rl;
+    memcpy(l_decree->data_n_signs + l_tsd_total_size, l_sign, l_sign_size);
+    DAP_DELETE(l_sign);
+
+    // dap_chain_datum_t *l_datum = dap_chain_datum_create(DAP_CHAIN_DATUM_DECREE, l_decree, l_decree_size);
+
+    dap_hash_fast_t l_decree_hash = {};
+    dap_hash_fast(l_decree, l_decree_size, &l_decree_hash);
+    // a_chain->callback_atom_add();
+    dap_assert_PIF(dap_chain_net_decree_apply(&l_decree_hash, l_decree, a_chain)==0, "Decree applying:");
+    return 0;
+}
+
+/* int dap_ledger_test_create_reward_tx(dap_chain_t *a_chain, dap_enc_key_t *a_key_to, int block_num, dap_hash_fast_t a_block_hash, uint256_t a_value, dap_ledger_t *a_ledger)
+{
+
+    dap_chain_t *l_chain = a_chain;
+    //add tx
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    dap_pkey_t *l_sign_pkey = dap_pkey_from_enc_key(a_key_to);
+    dap_hash_fast_t l_sign_pkey_hash;
+    dap_pkey_get_hash(l_sign_pkey, &l_sign_pkey_hash);
+    uint256_t l_value_out = uint256_0;
+    dap_ledger_t *l_ledger = a_ledger;
+
+    uint256_t l_reward_value = l_chain->callback_calc_reward(l_chain, a_block_hash, l_sign_pkey);
+    dap_assert_PIF(!IS_ZERO_256(l_reward_value), "Reward calculating:");
+    dap_assert_PIF(dap_ledger_is_used_reward(l_ledger, &a_block_hash, &l_sign_pkey_hash), "Reward is collected. ");
+    //add 'in_reward' items
+    dap_chain_datum_tx_add_in_reward_item(&l_tx, &a_block_hash);
+    SUM_256_256(l_value_out, l_reward_value, &l_value_out);
+
+    DAP_DELETE(l_sign_pkey);
+    uint256_t l_net_fee = uint256_0, l_total_fee = uint256_0;
+    dap_chain_addr_t l_addr_fee = c_dap_chain_addr_blank;
+ 
+    // Check and apply sovereign tax for this key
+    uint256_t l_value_tax = {};
+    dap_chain_net_srv_stake_item_t *l_key_item = dap_chain_net_srv_stake_check_pkey_hash(l_chain->net_id, &l_sign_pkey_hash);
+    if (l_key_item && !IS_ZERO_256(l_key_item->sovereign_tax) &&
+                !dap_chain_addr_is_blank(&l_key_item->sovereign_addr)) {
+        MULT_256_COIN(l_value_out, l_key_item->sovereign_tax, &l_value_tax);
+        if (compare256(l_value_tax, l_value_out) < 1)
+            SUBTRACT_256_256(l_value_out, l_value_tax, &l_value_out);
+    }
+    //add 'out' items
+    if (!IS_ZERO_256(l_value_out)) {
+        if (dap_chain_datum_tx_add_out_item(&l_tx, a_addr_to, l_value_out) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            log_it(L_WARNING, "Can't create out item in transaction fee");
+            return NULL;
+        }
+    }
+    if (!IS_ZERO_256(l_value_tax)) {
+        if (dap_chain_datum_tx_add_out_item(&l_tx, &l_key_item->sovereign_addr, l_value_tax) != 1) {
+            dap_chain_datum_tx_delete(l_tx);
+            log_it(L_WARNING, "Can't create out item in transaction fee");
+            return NULL;
+        }
+    }
+    // add 'sign' item
+    if(dap_chain_datum_tx_add_sign_item(&l_tx, a_sign_key) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        log_it(L_WARNING, "Can't sign item in transaction fee");
+        return NULL;
+    }
+
+    return 0;
+} */
+
+void dap_ledger_test_create_delegate_key_approve_decree()
+{
+
+}
+
+/*dap_chain_datum_tx_t *dap_ledger_test_create_delegate_tx_cond(dap_enc_key_t *a_key_from, dap_chain_hash_fast_t *a_hash_prev, dap_chain_hash_fast_t *a_stake_tx_hash,
+                                                                     uint256_t a_value, dap_ledger_t *a_ledger) {
+    dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_LOCK_ID };
+    // get previous transaction
+    dap_chain_datum_tx_t *l_tx_prev = dap_ledger_tx_find_by_hash(a_ledger, a_hash_prev);
+     // get previous cond out
+    int l_out_idx = 0;
+    dap_chain_tx_out_t *l_tx_prev_out = (dap_chain_tx_out_t *)dap_chain_datum_tx_item_get(l_tx_prev, &l_out_idx, TX_ITEM_TYPE_OUT, NULL);
+    
+    dap_chain_addr_t l_addr_to = {0};
+    dap_chain_addr_fill_from_key(&l_addr_to, a_key_from, a_ledger->net->pub.id);
+
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+    dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(a_hash_prev, 0);
+
+    dap_chain_tx_in_ems_t *l_in_ems = DAP_NEW_Z(dap_chain_tx_in_ems_t);
+    l_in_ems->header.type = TX_ITEM_TYPE_IN_EMS;
+    l_in_ems->header.token_emission_chain_id.uint64 = 0;
+    memset(&l_in_ems->header.token_emission_hash, 0, sizeof(l_in_ems->header.token_emission_hash));
+    strcpy(l_in_ems->header.ticker, s_delegated_token_ticker);
+
+    uint64_t a_time_staking = 1;
+    dap_chain_tx_out_cond_t* l_tx_out_cond = dap_chain_datum_tx_item_out_cond_create_srv_stake(
+                                                l_uid, a_value, a_key_from, );
+
+    // add all items to tx
+    uint256_t value_change = {};
+    SUBTRACT_256_256(l_tx_prev_out->header.value, a_value, &value_change);
+    SUBTRACT_256_256(value_change, dap_chain_uint256_from(s_fee), &value_change);
+    dap_chain_tx_out_ext_t *l_out_change = dap_chain_datum_tx_item_out_ext_create(&l_addr_to, value_change, s_token_ticker);
+    uint256_t a_delegated_value = {};
+    MULT_256_COIN(a_value, dap_chain_coins_to_balance("0.1"), &a_delegated_value);
+    dap_chain_tx_out_ext_t *l_out_delegated = dap_chain_datum_tx_item_out_ext_create(&l_addr_to, a_delegated_value, s_delegated_token_ticker);
+    dap_chain_tx_out_cond_t *l_cond_fee = dap_chain_datum_tx_item_out_cond_create_fee(dap_chain_uint256_from(s_fee));
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_in_ems);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_tx_out_cond);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_cond_fee);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_change);
+    dap_chain_datum_tx_add_item(&l_tx, (const uint8_t*) l_out_delegated);   
+    dap_chain_datum_tx_add_sign_item(&l_tx, a_key_from);
+    DAP_DEL_Z(l_in);
+    DAP_DEL_Z(l_cond_fee);
+    DAP_DEL_Z(l_in_ems);
+    DAP_DEL_Z(l_out_change);
+    DAP_DEL_Z(l_out_delegated);
+    DAP_DEL_Z(l_tx_out_cond);
+
+    return l_tx;
+}*/
+
+
+uint256_t dap_ledger_test_print_balance(dap_ledger_t *a_ledger, const dap_chain_addr_t *a_addr)
+{
+    uint256_t l_balance_after = dap_ledger_calc_balance(a_ledger, a_addr, s_token_ticker);
+    char *l_balanse_str = dap_chain_balance_print(l_balance_after);
+    dap_test_msg("Balance = %s %s", l_balanse_str, s_token_ticker);
+    DAP_DELETE(l_balanse_str);
+    return l_balance_after;
+}
+
+uint256_t dap_ledger_test_print_delegate_balance(dap_ledger_t *a_ledger, const dap_chain_addr_t *a_addr)
+{
+    uint256_t l_balance_after = dap_ledger_calc_balance(a_ledger, a_addr, s_delegated_token_ticker);
+    char *l_balanse_str = dap_chain_balance_print(l_balance_after);
+    dap_test_msg("Balance = %s %s", l_balanse_str, s_delegated_token_ticker);
+    DAP_DELETE(l_balanse_str);
+    return l_balance_after;
+}
+
+int dap_ledger_test_add_new_datum (uint16_t a_datum_type, void* a_datum, size_t a_datum_size, dap_chain_t *a_chain, dap_chain_hash_fast_t *a_datum_hash)
+{
+    dap_chain_datum_t* l_new_datum = dap_chain_datum_create(a_datum_type, a_datum, a_datum_size);
+    size_t l_new_datum_size = a_datum_size + sizeof(l_new_datum->header);
+    int status = dap_chain_datum_add(a_chain, l_new_datum, l_new_datum_size, a_datum_hash);
+    dap_assert(status == 0, "Test of transaction adding to ledger:");
+    return status;
+}
+
+dap_hash_fast_t dap_ledger_test_add_tx(dap_chain_net_t *a_net, dap_chain_datum_tx_t *a_tx) 
+{
+    dap_chain_t *l_chain_main = dap_chain_net_get_chain_by_name(a_net, "test_chain_main");
+    dap_assert(a_tx, "Test of creating tx:"); 
+    size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
+    dap_hash_fast_t l_hash = {};
+    dap_hash_fast(a_tx, l_tx_size, &l_hash);
+    dap_ledger_test_add_new_datum (DAP_CHAIN_DATUM_TX, a_tx, l_tx_size, l_chain_main, &l_hash);
+    return l_hash;
+}
+    
+
+
+void dap_ledger_test_datums_removing(dap_ledger_t *a_ledger, dap_hash_fast_t *a_prev_hash, dap_enc_key_t  *a_from_key, dap_chain_net_id_t a_net_id) 
+{
+    dap_print_module_name("dap_ledger_test_datums_removing");
     dap_cert_t *l_first_cert = dap_cert_generate_mem_with_seed("newCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, "FMknbirh8*^#$RYU*H", 18);
+    dap_chain_addr_t l_addr = {0};
+    dap_chain_addr_fill_from_key(&l_addr, a_from_key, a_net_id);
+    uint256_t l_balance_before = dap_ledger_test_print_balance(a_ledger, &l_addr);
     dap_chain_addr_t l_addr_first = {0};
     dap_chain_addr_fill_from_key(&l_addr_first, l_first_cert->enc_key, a_net_id);
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_net_id);
+    dap_chain_t *l_chain_main = dap_chain_net_get_chain_by_name(l_net, "test_chain_main");
+    
+    // Check common tx removing
+    dap_chain_datum_tx_t *l_first_tx = dap_ledger_test_create_tx_full(a_from_key, a_prev_hash, &l_addr_first, dap_chain_uint256_from(1U), l_net->pub.ledger);
+    dap_chain_hash_fast_t l_first_tx_hash = dap_ledger_test_add_tx(l_net, l_first_tx);
+
+    dap_ledger_test_print_balance(a_ledger, &l_addr);
+
+    dap_chain_datum_tx_t *l_second_tx = dap_ledger_test_create_tx_full(a_from_key, &l_first_tx_hash, &l_addr_first, dap_chain_uint256_from(1U), l_net->pub.ledger);
+    dap_assert(l_second_tx, "Test of creating second tx:");  
+    dap_chain_hash_fast_t l_second_tx_hash = {0};
+    dap_hash_fast(l_second_tx, dap_chain_datum_tx_get_size(l_second_tx), &l_second_tx_hash);
+    dap_assert(!dap_ledger_tx_add(a_ledger, l_second_tx, &l_second_tx_hash, false), "Test of second transaction adding to ledger:");
+    dap_ledger_test_print_balance(a_ledger, &l_addr);
+
+    // try to remove spent tx
+    dap_assert(dap_ledger_tx_remove(a_ledger, l_first_tx, &l_first_tx_hash), "Test of removing spent transaction:");
+    dap_assert(!dap_ledger_tx_remove(a_ledger, l_second_tx, &l_second_tx_hash), "Test of removing second transaction:");
+    dap_assert(!dap_ledger_tx_remove(a_ledger, l_first_tx, &l_first_tx_hash), "Test of removing first transaction:");
+    uint256_t l_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr);
+    dap_assert(!compare256(l_balance_before, l_balance_after), "Compare balance before creating transactions and after removing them. Must be equal:");
+
+    // check cond tx removing 
+    {
+    dap_chain_datum_tx_t *l_cond_tx = dap_ledger_test_create_tx_cond(a_from_key, a_prev_hash,
+                                                                       &l_addr_first, dap_chain_uint256_from(1U),a_ledger);
+    dap_assert_PIF(l_cond_tx, "Test of creating conditional transaction:");  
+    dap_chain_hash_fast_t l_cond_tx_hash = {0};
+    dap_hash_fast(l_cond_tx, dap_chain_datum_tx_get_size(l_first_tx), &l_cond_tx_hash);
+    dap_assert(!dap_ledger_tx_add(a_ledger, l_cond_tx, &l_cond_tx_hash, false), "Test of conditional transaction adding to ledger:");
+    dap_ledger_test_print_balance(a_ledger, &l_addr);
+    dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_tx, &l_cond_tx_hash), "Test of conditional transaction removing from ledger:");
+    l_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr);
+    dap_assert(!compare256(l_balance_before, l_balance_after), "Compare balance before creating transactions and after removing them. Must be equal:");
+    }
+
+    // try to spend cond tx 
+    {
+    dap_chain_datum_tx_t *l_cond_tx = dap_ledger_test_create_tx_cond(a_from_key, a_prev_hash,&l_addr_first, dap_chain_uint256_from(2U),a_ledger);
+    dap_assert_PIF(l_cond_tx, "Test of creating conditional transaction:"); 
+    dap_hash_fast_t l_cond_tx_hash = {};
+    dap_hash_fast(l_cond_tx, dap_chain_datum_tx_get_size(l_cond_tx), &l_cond_tx_hash);
+    dap_assert(!dap_ledger_tx_add(a_ledger, l_cond_tx, &l_cond_tx_hash, false), "Test of conditional transaction adding to ledger:");
+    dap_ledger_test_print_balance(a_ledger, &l_addr);
+
+    dap_cert_t *l_cond_spender_cert = dap_cert_generate_mem_with_seed("newCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, "FMknbirh8*^#$RYU*q", 18);
+    dap_chain_addr_t l_cond_spender_addr = {0};
+    dap_chain_addr_fill_from_key(&l_cond_spender_addr, l_cond_spender_cert->enc_key, a_net_id);
+    uint256_t l_cond_spending_balance_before = dap_ledger_test_print_balance(a_ledger, &l_cond_spender_addr);
+    dap_chain_datum_tx_t *l_cond_spendind_tx = dap_ledger_test_create_spend_tx_cond(a_from_key, &l_cond_tx_hash, l_cond_spender_cert->enc_key, dap_chain_uint256_from(1U),a_ledger);
+    dap_chain_hash_fast_t l_spend_cond_tx_hash = {0};
+    dap_hash_fast(l_cond_spendind_tx, dap_chain_datum_tx_get_size(l_cond_spendind_tx), &l_spend_cond_tx_hash);
+    dap_assert(!dap_ledger_tx_add(a_ledger, l_cond_spendind_tx, &l_spend_cond_tx_hash, false), "Test adding of transaction spending to a conditional transaction  to ledger:");
+    uint256_t l_cond_spending_balance_after = dap_ledger_test_print_balance(a_ledger, &l_cond_spender_addr);
+    dap_assert(!compare256(l_cond_spending_balance_after, dap_chain_uint256_from(1U)), "Check balance after spending:");
+    dap_ledger_test_print_balance(a_ledger, &l_cond_spender_addr);
+    dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_spendind_tx, &l_spend_cond_tx_hash), "Test removing of transaction spending to a conditional transaction  to ledger:");
+    l_cond_spending_balance_after = dap_ledger_test_print_balance(a_ledger, &l_cond_spender_addr);
+    dap_assert(!compare256(l_cond_spending_balance_before, l_cond_spending_balance_after), "Test spender balance after removing:");
+    dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_tx, &l_cond_tx_hash), "Test of conditional transaction removing from ledger:");
+    l_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr);
+    dap_assert(!compare256(l_balance_before, l_balance_after), "Compare balance before creating transactions and after removing them. Must be equal:");
+    }
+
+    // try to return funds from conditional tx and delete this tx
+    {
+    dap_chain_datum_tx_t *l_cond_tx = dap_ledger_test_create_tx_cond(a_from_key, a_prev_hash, &l_addr_first, dap_chain_uint256_from(2U),a_ledger);
+    dap_hash_fast_t l_cond_tx_hash = {};
+    dap_hash_fast(l_cond_tx, dap_chain_datum_tx_get_size(l_cond_tx), &l_cond_tx_hash);
+    dap_assert(!dap_ledger_tx_add(a_ledger, l_cond_tx, &l_cond_tx_hash, false), "Adding of cond transaction to ledger is");
+
+    dap_cert_t *l_cond_spending_cert = dap_cert_generate_mem_with_seed("newCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, "FMknbirh8*^#$RYU*q", 18);
+    dap_chain_addr_t l_cond_spending_addr = {0};
+    dap_chain_addr_fill_from_key(&l_cond_spending_addr, l_cond_spending_cert->enc_key, a_net_id);
+    uint256_t l_cond_spending_balance_before = dap_ledger_test_print_balance(a_ledger, &l_cond_spending_addr);
+    dap_chain_datum_tx_t *l_cond_returning_tx = dap_ledger_test_create_return_from_tx_cond(&l_cond_tx_hash, a_from_key ,a_ledger);
+    dap_chain_hash_fast_t l_cond_returning_tx_hash = {0};
+    dap_hash_fast(l_cond_returning_tx, dap_chain_datum_tx_get_size(l_cond_returning_tx), &l_cond_returning_tx_hash);
+    int err_code = dap_ledger_tx_add(a_ledger, l_cond_returning_tx, &l_cond_returning_tx_hash, false);
+    printf("err_code = %s\n", dap_ledger_tx_check_err_str(err_code));
+    dap_assert(!err_code, "Returning of funds from cond transaction is");
+    uint256_t l_cond_spending_balance_after = dap_ledger_test_print_balance(a_ledger, &l_cond_spending_addr);
+    dap_assert(compare256(l_cond_spending_balance_after, dap_chain_uint256_from(2U)), "Returning of funds from conditional tx from ledger testing");
+
+    dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_returning_tx, &l_cond_returning_tx_hash), "Tx cond removing from ledger is ");
+    l_cond_spending_balance_after = dap_ledger_test_print_balance(a_ledger, &l_cond_spending_addr);
+    dap_assert(!compare256(l_cond_spending_balance_before, l_cond_spending_balance_after), "Removing conditional tx from ledger testing");
+
+    dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_tx, &l_cond_tx_hash), "Tx cond removing from ledger is ");
+    l_cond_spending_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr);
+    dap_assert(!compare256(l_balance_before, l_cond_spending_balance_after), "Removing conditional tx from ledger testing");
+    }
+
+    // check stake adding and removing
+    {
+    dap_chain_datum_tx_t *l_cond_tx = dap_ledger_test_create_stake_tx_cond(a_from_key, a_prev_hash, dap_chain_uint256_from(20U), a_ledger);
+    dap_hash_fast_t l_cond_tx_hash = {};
+    dap_hash_fast(l_cond_tx, dap_chain_datum_tx_get_size(l_cond_tx), &l_cond_tx_hash);
+    int err_code = dap_ledger_tx_add(a_ledger, l_cond_tx, &l_cond_tx_hash, false);
+    printf("err_code = %s\n", dap_ledger_tx_check_err_str(err_code));
+    dap_assert(!err_code, "Adding of stake cond transaction to ledger is");
+
+    dap_assert(!dap_ledger_tx_remove(a_ledger, l_cond_tx, &l_cond_tx_hash), "Test of stake conditional transaction removing from ledger:");
+    l_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr);
+    dap_assert(!compare256(l_balance_before, l_balance_after), "Compare balance before creating stake transactions and after removing them. Must be equal:")
+    }
+
+    // check stake and unstake adding and removing
+    {
+    // Create stake lock tx
+    dap_chain_datum_tx_t *l_stake_cond_tx = dap_ledger_test_create_stake_tx_cond(a_from_key, a_prev_hash, dap_chain_uint256_from(20U), a_ledger);
+    dap_hash_fast_t l_stake_cond_tx_hash = {};
+    dap_hash_fast(l_stake_cond_tx, dap_chain_datum_tx_get_size(l_stake_cond_tx), &l_stake_cond_tx_hash);
+    int err_code = dap_ledger_tx_add(a_ledger, l_stake_cond_tx, &l_stake_cond_tx_hash, false);
+    printf("err_code = %s\n", dap_ledger_tx_check_err_str(err_code));
+    dap_assert(!err_code, "Adding of stake cond transaction to ledger is");
+    sleep(3);
+    // Create stake unlock tx
+    uint256_t l_balance_before_unstaking = dap_ledger_test_print_balance(a_ledger, &l_addr);
+    uint256_t l_balance_delegated_before_unstaking = dap_ledger_test_print_delegate_balance(a_ledger, &l_addr);
+    dap_assert(!compare256(l_balance_delegated_before_unstaking, dap_chain_uint256_from(2U)), "Compare delegated token balance before creating unstake transactions:")
+    
+    dap_chain_datum_tx_t *l_unstake_cond_tx = dap_ledger_test_create_unstake_tx_cond(a_from_key, &l_stake_cond_tx_hash, dap_chain_uint256_from(20U), a_ledger);
+    dap_hash_fast_t l_unstake_cond_tx_hash = {};
+    dap_hash_fast(l_unstake_cond_tx, dap_chain_datum_tx_get_size(l_stake_cond_tx), &l_unstake_cond_tx_hash);
+    err_code = dap_ledger_tx_add(a_ledger, l_unstake_cond_tx, &l_unstake_cond_tx_hash, false);
+    printf("err_code = %s\n", dap_ledger_tx_check_err_str(err_code));
+    dap_assert(!err_code, "Adding of unstake cond transaction to ledger is");
+    uint256_t l_balance_delegated_after_unstaking = dap_ledger_test_print_delegate_balance(a_ledger, &l_addr);
+    dap_assert(!compare256(l_balance_delegated_after_unstaking, uint256_0), "Compare delegated token balance after creating unstake transactions:")
+    
+    err_code = dap_ledger_tx_remove(a_ledger, l_unstake_cond_tx, &l_unstake_cond_tx_hash);
+    printf("err_code = %s\n", dap_ledger_tx_check_err_str(err_code));
+    dap_assert(!err_code, "Test of unstake conditional transaction removing from ledger:");
+    l_balance_after = dap_ledger_test_print_balance(a_ledger, &l_addr);
+    dap_assert(!compare256(l_balance_delegated_after_unstaking, uint256_0), "Compare delegated token balance after removing unstake transaction:")
+    uint256_t l_balance_delegated_after_removing_unstaking = dap_ledger_test_print_delegate_balance(a_ledger, &l_addr);
+    dap_assert(!compare256(l_balance_before_unstaking, l_balance_after), "Compare balance after creating unstake transactions and after removing them. Must be equal:")
+
+    // Check delegation
+
+    
+    
+
+    // Check rewards
+    
+
+    }
+
+    // Check vote removing 
+    {
+
+    }
+
+    // Check voting removing
+    {
+
+    }
+
+    // Check exchanger
+    {
+
+    }
+
+
+}
+
+dap_hash_fast_t dap_ledger_test_double_spending(
+    dap_ledger_t *a_ledger, dap_hash_fast_t *a_prev_hash, dap_enc_key_t  *a_from_key, dap_chain_addr_t a_addr_to, dap_chain_net_id_t a_net_id) {
+    dap_print_module_name("dap_ledger_double_spending");
     dap_chain_datum_tx_t *l_first_tx = dap_ledger_test_create_tx(a_from_key, a_prev_hash,
-                                                                       &l_addr_first, dap_chain_uint256_from(s_standard_value_tx - s_fee));
+                                                                       &a_addr_to, dap_chain_uint256_from(s_standard_value_tx - s_fee));
     dap_assert_PIF(l_first_tx, "Can't creating base transaction.");
     dap_chain_hash_fast_t l_first_tx_hash = {0};
     dap_hash_fast(l_first_tx, dap_chain_datum_tx_get_size(l_first_tx), &l_first_tx_hash);
-    dap_assert_PIF(!dap_ledger_tx_add(a_ledger, l_first_tx, &l_first_tx_hash, false), "Can't added first transaction on ledger");
+    dap_assert_PIF(!dap_ledger_tx_add(a_ledger, l_first_tx, &l_first_tx_hash, false), "Can't add first transaction on ledger");
     //uint256_t l_balance = dap_ledger_calc_balance(a_ledger, &l_addr_first, s_token_ticker);
     // Second tx
     dap_chain_datum_tx_t *l_second_tx = dap_ledger_test_create_tx(a_from_key, a_prev_hash,
-                                                                       &l_addr_first, dap_chain_uint256_from(s_standard_value_tx - s_fee));
+                                                                       &a_addr_to, dap_chain_uint256_from(s_standard_value_tx - s_fee));
     dap_chain_hash_fast_t l_second_tx_hash = {0};
     dap_hash_fast(l_second_tx, dap_chain_datum_tx_get_size(l_second_tx), &l_second_tx_hash);
     dap_assert_PIF(dap_ledger_tx_add(a_ledger, l_second_tx, &l_second_tx_hash, false), "Added second transaction on ledger");
     dap_pass_msg("The verification test is not able to make two normal transactions per one basic transaction.");
+    return l_first_tx_hash; 
 }
 
 void dap_ledger_test_excess_supply(dap_ledger_t *a_ledger, dap_cert_t *a_cert, dap_chain_addr_t *a_addr){
@@ -366,20 +963,43 @@ void dap_ledger_test_write_back_list(dap_ledger_t *a_ledger, dap_cert_t *a_cert,
 }
 
 void dap_ledger_test_run(void){
+    dap_set_appname("cellframe-node");
+    dap_assert_PIF(dap_chain_cs_blocks_init() == 0, "Initialization of dap consensus block: ");
+    dap_assert_PIF(dap_chain_cs_esbocs_init() == 0, "Initialization of esbocs: ");
+    dap_assert_PIF(dap_chain_cs_dag_init() == 0, "Initialization of esbocs: ");
+    dap_assert_PIF(dap_chain_cs_dag_poa_init() == 0, "Initialization of esbocs: ");
+    dap_chain_net_srv_stake_lock_init();
     dap_chain_net_srv_stake_pos_delegate_init();
-    dap_chain_net_id_t l_iddn = {0};
-    sscanf("0xFA0", "0x%16"DAP_UINT64_FORMAT_x, &l_iddn.uint64);
+    dap_assert_PIF(!dap_chain_net_srv_init(), "Srv initializstion");
+    
     dap_print_module_name("dap_ledger");
     uint16_t l_flags = 0;
     l_flags |= DAP_LEDGER_CHECK_TOKEN_EMISSION;
-    dap_chain_net_t *l_net = DAP_NEW_Z(dap_chain_net_t);
-    l_net->pub.id = l_iddn;
-    l_net->pub.native_ticker = s_token_ticker;
-    l_net->pub.name = "Snet";
+    dap_chain_net_test_init();
+    dap_chain_net_id_t l_iddn = {.uint64 = 0};
+    sscanf("0xFA0", "0x%16"DAP_UINT64_FORMAT_x, &l_iddn.uint64);
+    dap_chain_net_t *l_net = dap_chain_net_by_id(l_iddn);
     dap_ledger_t *l_ledger = dap_ledger_create(l_net, l_flags);
+    l_net->pub.ledger = l_ledger;
+
+    dap_chain_t *l_chain_zero =  dap_chain_create(l_net->pub.name, "test_chain_zerochain", l_net->pub.id, (dap_chain_id_t){.uint64 = 0});
+    dap_config_t l_cfg = {};
+    dap_assert_PIF(dap_chain_cs_create(l_chain_zero, &l_cfg) == 0, "Chain cs dag_poa creating: ");
+    DL_APPEND(l_net->pub.chains, l_chain_zero);
+
+    dap_chain_t *l_chain_main =  dap_chain_create(l_net->pub.name, "test_chain_main", l_net->pub.id, (dap_chain_id_t){.uint64 = 1});
+    dap_assert_PIF(dap_chain_cs_create(l_chain_main, &l_cfg) == 0, "Chain esbocs cs creating: ");
+    DL_APPEND(l_net->pub.chains, l_chain_main);
+
+    dap_assert_PIF(!dap_chain_net_decree_init(l_net), "Decree initialization:");
+
     char *l_seed_ph = "H58i9GJKbn91238937^#$t6cjdf";
     size_t l_seed_ph_size = strlen(l_seed_ph);
     dap_cert_t *l_cert = dap_cert_generate_mem_with_seed("testCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, l_seed_ph, l_seed_ph_size);
+
+    dap_assert_PIF(dap_ledger_test_create_reward_decree(l_chain_main, l_net->pub.id,  dap_chain_uint256_from(2), l_cert)==0, "Reward decree creating:");
+
+
     size_t l_token_decl_size = 0;
     dap_chain_datum_token_t *l_token_decl = dap_ledger_test_create_datum_decl(l_cert,
                                                                                     &l_token_decl_size, s_token_ticker,
@@ -401,6 +1021,20 @@ void dap_ledger_test_run(void){
     int l_emi_check = dap_ledger_token_emission_add_check(l_ledger, (byte_t*)l_emi_sign, l_emi_size, &l_emi_hash);
     dap_assert_PIF(l_emi_check == 0, "check emission for add in ledger");
     dap_assert_PIF(!dap_ledger_token_emission_add(l_ledger, (byte_t*)l_emi_sign, l_emi_size, &l_emi_hash, false), "Added emission in ledger");
+
+    // Declarate delegated token
+    dap_chain_datum_token_tsd_delegate_from_stake_lock_t l_tsd_section;
+    strcpy((char *)l_tsd_section.ticker_token_from, s_token_ticker);
+    l_tsd_section.emission_rate = dap_chain_coins_to_balance("0.1");//	TODO: 'm' 1:10 tokens
+    dap_tsd_t * l_tsd = dap_tsd_create_scalar(DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_DELEGATE_EMISSION_FROM_STAKE_LOCK, l_tsd_section);
+    l_token_decl = dap_ledger_test_create_datum_decl(l_cert, &l_token_decl_size, s_delegated_token_ticker,
+                                                     uint256_0, (byte_t*)l_tsd, dap_tsd_size(l_tsd), DAP_CHAIN_DATUM_TOKEN_FLAG_NONE);
+    dap_assert_PIF(l_token_decl || l_token_decl_size == 0, "Generate delegated token declaration.");
+    l_check_added_decl_token = 0;
+    l_check_added_decl_token = dap_ledger_token_decl_add_check(l_ledger, l_token_decl, l_token_decl_size);
+    dap_assert_PIF(l_check_added_decl_token == 0, "Checking whether it is possible to add a token declaration to ledger.");
+    dap_assert_PIF(!dap_ledger_token_add(l_ledger, l_token_decl, l_token_decl_size), "Adding token declaration to ledger.");
+
     //first base tx
     dap_chain_datum_tx_t *l_base_tx = dap_ledger_test_create_datum_base_tx(l_emi_sign, &l_emi_hash, l_addr, l_cert);
     size_t l_base_tx_size = dap_chain_datum_tx_get_size(l_base_tx);
@@ -414,7 +1048,7 @@ void dap_ledger_test_run(void){
 	SUM_256_256(l_balance,l_fee,&l_balance);
     dap_assert_PIF(!compare256(l_balance, l_balance_example), "Checking the availability of the necessary balance "
                                                              "on the wallet after the first transaction.");
-    dap_pass_msg("Validation of the declaration of the tocen, creation of an emission and a basic transaction using this in the ledger.");
+    dap_pass_msg("Validation of the declaration of the token, creation of an emission and a basic transaction using this in the ledger.");
     //second base tx
     dap_chain_datum_tx_t  *l_base_tx_second = dap_ledger_test_create_datum_base_tx(l_emi_sign, &l_emi_hash, l_addr, l_cert);
     size_t l_base_tx_size2 = dap_chain_datum_tx_get_size(l_base_tx_second);
@@ -428,8 +1062,15 @@ void dap_ledger_test_run(void){
     } else {
         dap_fail("Checking for a failure to add a second base transaction for the same issue to the ledger.");
     }	
-    dap_ledger_test_double_spending(l_ledger, &l_hash_btx, l_cert->enc_key, l_iddn);
+
+    dap_cert_t *l_first_cert = dap_cert_generate_mem_with_seed("newCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, "FMknbirh8*^#$RYU*L", 18);
+    dap_chain_addr_t l_addr_first = {0};
+    dap_chain_addr_fill_from_key(&l_addr_first, l_first_cert->enc_key, l_iddn);
+    dap_hash_fast_t l_first_tx_hash = dap_ledger_test_double_spending(l_ledger, &l_hash_btx, l_cert->enc_key, l_addr_first, l_iddn);
     dap_ledger_test_excess_supply(l_ledger, l_cert, &l_addr);
+    //dap_ledger_test_datums_adding(l_ledger, &l_hash_btx, l_cert->enc_key, l_iddn);//check adding all types of datums into ledger
+    dap_ledger_test_datums_removing(l_ledger, &l_first_tx_hash, l_first_cert->enc_key, l_iddn);//check removing all types of datums from ledger
     dap_ledger_test_write_back_list(l_ledger, l_cert, l_iddn);
-	
+    
+
 }
diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
index ff58899f5bd79b9a33e03c6f4d39e9fecaaaba8b..86ad365619ef305be5fdf0db46b769d5c9e9fa2c 100644
--- a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
+++ b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
@@ -38,7 +38,7 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 #include "dap_stream_ch_chain_net_srv.h"
 #include "dap_stream_ch_chain_net_srv_pkt.h"
 #include "dap_stream_ch_proc.h"
-#include "dap_stream_ch_chain_net_srv.h"
+
 
 #define LOG_TAG "dap_stream_ch_chain_net_srv"
 #define SRV_PAY_GDB_GROUP "local.srv_pay"
@@ -273,11 +273,14 @@ char *dap_stream_ch_chain_net_srv_create_statistic_report()
     return dap_string_free(l_ret, false);
 }
 
-void dap_stream_ch_chain_net_srv_tx_cond_added_cb(UNUSED_ARG void *a_arg, UNUSED_ARG dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
+void dap_stream_ch_chain_net_srv_tx_cond_added_cb(UNUSED_ARG void *a_arg, UNUSED_ARG dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chan_ledger_notify_opcodes_t a_opcode)
 {
 // sanity check
     dap_return_if_pass(!a_tx);
 // func work
+    if(a_opcode != DAP_LEDGER_NOTIFY_OPCODE_ADDED)
+        return;
+        
     dap_chain_net_srv_grace_usage_t *l_item = NULL;
     dap_hash_fast_t l_tx_cond_hash = {0};
     dap_chain_tx_out_cond_t *l_out_cond = dap_chain_datum_tx_out_cond_get(a_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, NULL);
diff --git a/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h b/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h
index 7f1970fb4fecfd180da2186ab7d600deec7fab93..82bc5ee1acd098b474e675f1c4fa7a5a8d314422 100644
--- a/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h
+++ b/modules/channel/chain-net-srv/include/dap_stream_ch_chain_net_srv.h
@@ -58,5 +58,5 @@ typedef struct dap_stream_ch_chain_net_srv {
 
 int dap_stream_ch_chain_net_srv_init(dap_chain_net_srv_t *a_srv);
 
-void dap_stream_ch_chain_net_srv_tx_cond_added_cb(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx);
+void dap_stream_ch_chain_net_srv_tx_cond_added_cb(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chan_ledger_notify_opcodes_t a_opcode);
 char *dap_stream_ch_chain_net_srv_create_statistic_report();
diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c
index 882801198265c0f878af36cbcde027b0b27b8175..6f5b32842a2ad59997ee77c6532bf514e14674ae 100644
--- a/modules/common/dap_chain_datum_tx_items.c
+++ b/modules/common/dap_chain_datum_tx_items.c
@@ -272,7 +272,7 @@ dap_chain_tx_in_ems_t *dap_chain_datum_tx_item_in_ems_create(dap_chain_id_t a_id
     }
     l_item->header.type = TX_ITEM_TYPE_IN_EMS;
     l_item->header.token_emission_chain_id.uint64 = a_id.uint64;
-    l_item->header.token_emission_hash = *a_datum_token_hash;;
+    l_item->header.token_emission_hash = *a_datum_token_hash;
     strncpy(l_item->header.ticker, a_ticker, sizeof(l_item->header.ticker) - 1);
     return l_item;
 }
diff --git a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
index 00edeaf8229419998365351c91a0f804e3eb8324..d8d9d41f1689f1344cf949be9f96d332152c5ffe 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -363,6 +363,7 @@ static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     dap_chain_cs_dag_poa_pvt_t *l_poa_pvt = PVT(l_poa);
     pthread_rwlock_init(&l_poa_pvt->rounds_rwlock, NULL);
     // PoA rounds
+#ifndef DAP_LEDGER_TEST
     l_poa_pvt->confirmations_timeout = dap_config_get_item_uint32_default(a_chain_cfg,"dag-poa","confirmations_timeout",600);
     l_poa_pvt->auto_confirmation = dap_config_get_item_bool_default(a_chain_cfg,"dag-poa","auto_confirmation",true);
     l_poa_pvt->auto_round_complete = dap_config_get_item_bool_default(a_chain_cfg,"dag-poa","auto_round_complete",true);
@@ -406,6 +407,15 @@ static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
         }
     }
 
+#else
+    l_poa_pvt->auth_certs_count = 1;
+    l_poa_pvt->auth_certs = DAP_NEW_Z_SIZE ( dap_cert_t *, l_poa_pvt->auth_certs_count * sizeof(dap_cert_t *));
+    char *l_seed_ph = "H58i9GJKbn91238937^#$t6cjdf";
+    size_t l_seed_ph_size = strlen(l_seed_ph);
+    dap_cert_t *l_cert = dap_cert_generate_mem_with_seed("testCert", DAP_ENC_KEY_TYPE_SIG_PICNIC, l_seed_ph, l_seed_ph_size);
+    l_poa_pvt->auth_certs[0] = l_cert;
+#endif
+
     return 0;
 }
 
@@ -620,7 +630,7 @@ static bool s_callback_round_event_to_chain_callback_get_round_item(dap_global_d
         l_dag->round_completed = dap_max(l_new_atom->header.round_id, l_dag->round_current);
         int l_verify_datum = dap_chain_net_verify_datum_for_add(l_dag->chain, l_datum, &l_chosen_item->round_info.datum_hash);
         if (!l_verify_datum) {
-            dap_chain_atom_verify_res_t l_res = l_dag->chain->callback_atom_add(l_dag->chain, l_new_atom, l_event_size);
+            dap_chain_atom_verify_res_t l_res = l_dag->chain->callback_atom_add(l_dag->chain, l_new_atom, l_event_size, &l_chosen_item->round_info.datum_hash);
             if (l_res == ATOM_ACCEPT)
                 s_poa_round_clean(l_dag->chain);
             log_it(L_INFO, "Event %s from round %"DAP_UINT64_FORMAT_U" %s",
diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index 948fe73c2f8f6237b3d57119795ed7758fef3a95..3be2d5eac35c7445781ffcfdcb8002bc58eb25ac 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -1588,7 +1588,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);
-    if (l_blocks->chain->callback_atom_verify(l_blocks->chain, a_candidate, a_candidate_size) == ATOM_ACCEPT) {
+    if (l_blocks->chain->callback_atom_verify(l_blocks->chain, a_candidate, a_candidate_size, a_candidate_hash) == ATOM_ACCEPT) {
         // validation - OK, gen event Approve
         s_message_send(a_session, DAP_CHAIN_ESBOCS_MSG_TYPE_APPROVE, a_candidate_hash,
                        NULL, 0, a_session->cur_round.validators_list);
@@ -1682,7 +1682,7 @@ static bool s_session_candidate_to_chain(dap_chain_esbocs_session_t *a_session,
         return false;
     }
     bool res = false;
-    dap_chain_atom_verify_res_t l_res = a_session->chain->callback_atom_add(a_session->chain, a_candidate, a_candidate_size);
+    dap_chain_atom_verify_res_t l_res = a_session->chain->callback_atom_add(a_session->chain, a_candidate, a_candidate_size, a_candidate_hash);
     const char *l_candidate_hash_str = dap_chain_hash_fast_to_str_static(a_candidate_hash);
     switch (l_res) {
     case ATOM_ACCEPT:
diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c
index e0068e9e6ffa304996f2db05713322d9fd8eb46f..26c509a75ba995ee3ae9c84e97c7ce30d185f073 100644
--- a/modules/net/dap_chain_ledger.c
+++ b/modules/net/dap_chain_ledger.c
@@ -64,9 +64,14 @@ typedef struct dap_ledger_verificator {
     int subtype;    // hash key
     dap_ledger_verificator_callback_t callback;
     dap_ledger_updater_callback_t callback_added;
+    dap_ledger_updater_callback_t callback_deleted;
     UT_hash_handle hh;
 } dap_ledger_verificator_t;
 
+typedef struct dap_chain_ledger_votings_callbacks{
+    dap_chain_ledger_voting_callback_t voting_callback;
+    dap_chain_ledger_voting_delete_callback_t voting_delete_callback;
+} dap_chain_ledger_votings_callbacks_t;
 typedef struct dap_ledger_service_info {
     dap_chain_net_srv_uid_t service_uid;    // hash key
     char tag_str[32];   // tag string name
@@ -80,7 +85,7 @@ static dap_ledger_service_info_t *s_services;
 static  pthread_rwlock_t s_verificators_rwlock;
 static  pthread_rwlock_t s_services_rwlock;
 
-static dap_chain_ledger_voting_callback_t s_voting_callback;
+static dap_chain_ledger_votings_callbacks_t s_voting_callbacks;
 
 #define MAX_OUT_ITEMS   10
 
@@ -363,7 +368,7 @@ static int s_sort_ledger_tx_item(dap_ledger_tx_item_t* a, dap_ledger_tx_item_t*
 
 static size_t s_threshold_emissions_max = 1000;
 static size_t s_threshold_txs_max = 10000;
-static bool s_debug_more = false;
+static bool s_debug_more = true;
 static size_t s_threshold_free_timer_tick = 900000; // 900000 ms = 15 minutes.
 
 struct json_object *wallet_info_json_collect(dap_ledger_t *a_ledger, dap_ledger_wallet_balance_t* a_bal);
@@ -1203,14 +1208,18 @@ static bool s_ledger_token_supply_check(dap_ledger_token_item_t *a_token_item, u
     return s_ledger_token_supply_check_unsafe(a_token_item, a_value);
 }
 
-static bool s_ledger_token_supply_check_update(dap_ledger_t *a_ledger, dap_ledger_token_item_t *a_token_item, uint256_t a_value)
+static bool s_ledger_token_supply_check_update(dap_ledger_t *a_ledger, dap_ledger_token_item_t *a_token_item, uint256_t a_value, bool a_for_removing)
 {
     assert(a_token_item);
-    if (IS_ZERO_256(a_token_item->total_supply) || IS_ZERO_256(a_value))
+    if ((IS_ZERO_256(a_token_item->total_supply) || IS_ZERO_256(a_value)))
         return true;
-    if (!s_ledger_token_supply_check_unsafe(a_token_item, a_value))
+    if (!s_ledger_token_supply_check_unsafe(a_token_item, a_value) && !a_for_removing)
         return false;
-    int l_overflow = SUBTRACT_256_256(a_token_item->current_supply, a_value, &a_token_item->current_supply);
+    int l_overflow = false;
+    if(a_for_removing)
+        l_overflow = SUM_256_256(a_token_item->current_supply, a_value, &a_token_item->current_supply);
+    else
+        l_overflow = SUBTRACT_256_256(a_token_item->current_supply, a_value, &a_token_item->current_supply);
     assert(!l_overflow);
     const char *l_balance; dap_uint256_to_char(a_token_item->current_supply, &l_balance);
     log_it(L_NOTICE, "New current supply %s for token %s", l_balance, a_token_item->ticker);
@@ -3063,7 +3072,7 @@ int dap_ledger_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_emissi
             }
             //Update value in ledger memory object
             if (!s_ledger_token_supply_check_update(a_ledger, l_token_item,
-                                                    l_token_emission_item->datum_token_emission->hdr.value)) {
+                                                    l_token_emission_item->datum_token_emission->hdr.value, false)) {
                 DAP_DELETE(l_token_emission_item->datum_token_emission);
                 DAP_DELETE(l_token_emission_item);
                 return DAP_LEDGER_EMISSION_ADD_CHECK_VALUE_EXEEDS_CURRENT_SUPPLY;
@@ -3502,7 +3511,6 @@ dap_hash_fast_t* dap_ledger_get_first_chain_tx_hash(dap_ledger_t *a_ledger, dap_
         dap_chain_tx_out_cond_t *l_out_cond_temp = dap_chain_datum_tx_out_cond_get(l_prev_tx_temp, l_type, NULL);
         if (l_out_cond_temp){
             l_item_idx = l_in_cond_temp->header.tx_out_prev_idx;
-            
             l_hash = l_in_cond_temp->header.tx_prev_hash;
         }
         l_prev_tx = l_prev_tx_temp;
@@ -3825,13 +3833,14 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
                                      dap_list_t **a_list_tx_out,
                                       char **a_main_ticker,
                                       dap_chain_net_srv_uid_t *a_tag,
-                                      dap_chain_tx_tag_action_type_t *a_action)
+                                      dap_chain_tx_tag_action_type_t *a_action, 
+                                      bool a_check_for_removing)
 {
     if (!a_tx) {
         log_it(L_DEBUG, "NULL transaction, check broken");
         return DAP_LEDGER_TX_CHECK_NULL_TX;
     }
-    if (!dap_chain_net_get_load_mode(a_ledger->net) && !a_from_threshold) {
+    if (!dap_chain_net_get_load_mode(a_ledger->net) && !a_from_threshold && !a_check_for_removing) {
         dap_ledger_tx_item_t *l_ledger_item;
         pthread_rwlock_rdlock(&PVT(a_ledger)->ledger_rwlock);
         HASH_FIND(hh, PVT(a_ledger)->ledger_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_ledger_item);
@@ -3926,7 +3935,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
                 dap_chain_tx_in_ems_t *l_in_ems_check = l_iter->data;
                 if (l_tx_in_ems != l_in_ems_check &&
                         l_in_ems_check->header.type == TX_ITEM_TYPE_IN_EMS &&
-                        dap_hash_fast_compare(&l_in_ems_check->header.token_emission_hash, l_emission_hash)) {
+                        dap_hash_fast_compare(&l_in_ems_check->header.token_emission_hash, l_emission_hash) && !a_check_for_removing) {
                     debug_if(s_debug_more, L_ERROR, "Emission output already used in current tx");
                     l_err_num = DAP_LEDGER_TX_CHECK_PREV_OUT_ALREADY_USED_IN_CURRENT_TX;
                     break;
@@ -3941,7 +3950,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
                 if (!dap_hash_fast_is_blank(l_emission_hash)) {
                     dap_hash_fast_t cur_tx_hash;
                     dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &cur_tx_hash);
-                    if (!dap_hash_fast_is_blank(&l_stake_lock_emission->tx_used_out)) {
+                    if (!dap_hash_fast_is_blank(&l_stake_lock_emission->tx_used_out) && !a_check_for_removing) {
                         if (!dap_hash_fast_compare(&cur_tx_hash, &l_stake_lock_emission->tx_used_out))
                             debug_if(s_debug_more, L_WARNING, "stake_lock_emission already present in cache for IN_EMS [%s]", l_token);
                         else
@@ -3952,7 +3961,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
                     l_tx_stake_lock = dap_ledger_tx_find_by_hash(a_ledger, l_emission_hash);
                 } else {
                     // 2. The only allowed item with girdled emission
-                    if (l_girdled_ems_used) {
+                    if (l_girdled_ems_used && !a_check_for_removing) {
                         debug_if(s_debug_more, L_WARNING, "stake_lock_emission is used out for IN_EMS [%s]", l_token);
                         l_err_num = DAP_LEDGER_TX_CHECK_STAKE_LOCK_IN_EMS_ALREADY_USED;
                         break;
@@ -4077,7 +4086,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
                 l_bound_item->type = TX_ITEM_TYPE_IN_EMS_LOCK;
             } else if ( (l_emission_item = s_emission_item_find(a_ledger, l_token, l_emission_hash, &l_bound_item->token_item)) ) {
                 // 3. Check AUTH token emission
-                if (!dap_hash_fast_is_blank(&l_emission_item->tx_used_out)) {
+                if (!dap_hash_fast_is_blank(&l_emission_item->tx_used_out)  && !a_check_for_removing) {
                     debug_if(s_debug_more, L_WARNING, "Emission for IN_EMS [%s] is already used", l_tx_in_ems->header.ticker);
                     l_err_num = DAP_LEDGER_TX_CHECK_IN_EMS_ALREADY_USED;
                     break;
@@ -4098,7 +4107,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
                 dap_chain_tx_in_reward_t *l_in_reward_check = l_iter->data;
                 if (l_tx_in_reward != l_in_reward_check &&
                         l_in_reward_check->type == TX_ITEM_TYPE_IN_REWARD &&
-                        dap_hash_fast_compare(&l_in_reward_check->block_hash, l_block_hash)) {
+                        dap_hash_fast_compare(&l_in_reward_check->block_hash, l_block_hash) && !a_check_for_removing) {
                     debug_if(s_debug_more, L_ERROR, "Reward for this block sign already used in current tx");
                     l_err_num = DAP_LEDGER_TX_CHECK_PREV_OUT_ALREADY_USED_IN_CURRENT_TX;
                     break;
@@ -4121,7 +4130,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
             // 3. Check if already spent reward
             dap_ledger_reward_key_t l_search_key = { .block_hash = *l_block_hash, .sign_pkey_hash = l_tx_first_sign_pkey_hash };
             dap_ledger_reward_item_t *l_reward_item = s_find_reward(a_ledger, &l_search_key);
-            if (l_reward_item) {
+            if (l_reward_item && !a_check_for_removing) {
                 l_err_num = DAP_LEDGER_TX_CHECK_REWARD_ITEM_ALREADY_USED;
                 char l_block_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE],
                      l_sign_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE],
@@ -4157,7 +4166,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
                 l_err_num = DAP_LEDGER_TX_CHECK_TICKER_NOT_FOUND;
                 break;
             }
-            if (!s_ledger_token_supply_check(l_token_item, l_value)) {
+            if (!s_ledger_token_supply_check(l_token_item, l_value) && !a_check_for_removing) {
                 l_err_num = DAP_LEDGER_TX_CHECK_TOKEN_EMS_VALUE_EXEEDS_CUR_SUPPLY;
                 break;
             }
@@ -4186,7 +4195,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
                     if (l_tx_in != l_in_check &&
                             l_in_check->header.type == TX_ITEM_TYPE_IN &&
                             l_in_check->header.tx_out_prev_idx == l_tx_prev_out_idx &&
-                            dap_hash_fast_compare(&l_in_check->header.tx_prev_hash, l_tx_prev_hash)) {
+                            dap_hash_fast_compare(&l_in_check->header.tx_prev_hash, l_tx_prev_hash) && !a_check_for_removing) {
                         debug_if(s_debug_more, L_ERROR, "This previous tx output already used in current tx");
                         l_err_num = DAP_LEDGER_TX_CHECK_PREV_OUT_ALREADY_USED_IN_CURRENT_TX;
                         break;
@@ -4204,7 +4213,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
                     if (l_tx_in_cond != l_in_cond_check &&
                             l_in_cond_check->header.type == TX_ITEM_TYPE_IN_COND &&
                             l_in_cond_check->header.tx_out_prev_idx == l_tx_prev_out_idx &&
-                            dap_hash_fast_compare(&l_in_cond_check->header.tx_prev_hash, l_tx_prev_hash)) {
+                            dap_hash_fast_compare(&l_in_cond_check->header.tx_prev_hash, l_tx_prev_hash) && !a_check_for_removing) {
                         debug_if(s_debug_more, L_ERROR, "This previous tx output already used in current tx");
                         l_err_num = DAP_LEDGER_TX_CHECK_PREV_OUT_ALREADY_USED_IN_CURRENT_TX;
                         break;
@@ -4218,11 +4227,11 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
             l_tx_prev = s_find_datum_tx_by_hash(a_ledger, l_tx_prev_hash, &l_item_out, false);
             char l_tx_prev_hash_str[DAP_HASH_FAST_STR_SIZE];
             dap_hash_fast_to_str(l_tx_prev_hash, l_tx_prev_hash_str, DAP_HASH_FAST_STR_SIZE);
-            if (!l_tx_prev) { // Unchained transaction or previous TX was already spent and removed from ledger
+            if (!l_tx_prev && !a_check_for_removing) { // Unchained transaction or previous TX was already spent and removed from ledger
                 debug_if(s_debug_more && !a_from_threshold, L_DEBUG, "No previous transaction was found for hash %s", l_tx_prev_hash_str);
                 l_err_num = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS;
                 break;
-            } else if (l_item_out->cache_data.ts_spent) {
+            } else if (l_item_out->cache_data.ts_spent && !a_check_for_removing) {
                 l_err_num = DAP_LEDGER_TX_CHECK_OUT_ITEM_ALREADY_USED;
                 debug_if(s_debug_more, L_WARNING, "All 'out' items of previous tx %s were already spent", l_tx_prev_hash_str);
                 break;
@@ -4234,7 +4243,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
 
             // 2. Check if out in previous transaction has spent
             dap_hash_fast_t l_spender = {};
-            if (s_ledger_tx_hash_is_used_out_item(l_item_out, l_tx_prev_out_idx, &l_spender)) {
+            if (s_ledger_tx_hash_is_used_out_item(l_item_out, l_tx_prev_out_idx, &l_spender) && !a_check_for_removing) {
                 l_err_num = DAP_LEDGER_TX_CHECK_OUT_ITEM_ALREADY_USED;
                 char l_hash[DAP_CHAIN_HASH_FAST_STR_SIZE];
                 dap_chain_hash_fast_to_str(&l_spender, l_hash, sizeof(l_hash));
@@ -4648,10 +4657,11 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
         }
     }
 
+
     dap_list_t *l_items_voting;
     if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTING, NULL))) {
-        if (s_voting_callback){
-            if (!s_voting_callback(a_ledger, TX_ITEM_TYPE_VOTING, a_tx, false)){
+        if (s_voting_callbacks.voting_callback){
+            if (!s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTING, a_tx, false)){
                 debug_if(s_debug_more, L_WARNING, "Verificator check error for voting.");
                 l_err_num = DAP_LEDGER_TX_CHECK_VERIFICATOR_CHECK_FAILURE;
             }
@@ -4661,8 +4671,8 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
         }
         dap_list_free(l_items_voting);
     }else if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTE, NULL))) {
-       if (s_voting_callback){
-           if (!s_voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, false)){
+       if (s_voting_callbacks.voting_callback){
+           if (!s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, false)){
                debug_if(s_debug_more, L_WARNING, "Verificator check error for vote.");
                l_err_num = DAP_LEDGER_TX_CHECK_VERIFICATOR_CHECK_FAILURE;
            }
@@ -4717,7 +4727,7 @@ int dap_ledger_tx_add_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,
     }
 
     int l_ret_check = dap_ledger_tx_cache_check(a_ledger, a_tx, a_datum_hash,
-                                                      false, NULL, NULL, NULL, NULL, NULL);
+                                                      false, NULL, NULL, NULL, NULL, NULL, false);
     if(s_debug_more) {
         char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
         dap_chain_hash_fast_to_str(a_datum_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
@@ -4809,7 +4819,7 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
 
     if( (l_ret_check = dap_ledger_tx_cache_check(a_ledger, a_tx, a_tx_hash, a_from_threshold,
                                                        &l_list_bound_items, &l_list_tx_out,
-                                                       &l_main_token_ticker, &l_tag, &l_action))) {
+                                                       &l_main_token_ticker, &l_tag, &l_action, false))) {
         if (l_ret_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS ||
                 l_ret_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION) {
             if (!l_from_threshold) {
@@ -4889,7 +4899,7 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
         }
 
         if ((l_type == TX_ITEM_TYPE_IN_EMS_LOCK || l_type == TX_ITEM_TYPE_IN_REWARD) &&
-                !s_ledger_token_supply_check_update(a_ledger, l_bound_item->token_item, l_bound_item->value))
+                !s_ledger_token_supply_check_update(a_ledger, l_bound_item->token_item, l_bound_item->value, false))
             log_it(L_ERROR, "Insufficient supply for token %s", l_bound_item->token_item->ticker);
 
         switch (l_type) {
@@ -5078,17 +5088,15 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
         }
     }
     dap_list_t *l_items_voting;
-    if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTING, NULL)) && s_voting_callback) {
+    if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTING, NULL)) && s_voting_callbacks.voting_callback) {
         dap_list_free(l_items_voting);
-        s_voting_callback(a_ledger, TX_ITEM_TYPE_VOTING, a_tx, true);
+        s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTING, a_tx, true);
     }
-    else if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTE, NULL)) && s_voting_callback) {
+    else if ((l_items_voting = dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTE, NULL)) && s_voting_callbacks.voting_callback) {
         dap_list_free(l_items_voting);
-        s_voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, true);
+        s_voting_callbacks.voting_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx, true);
     }
 
-
-
     // add transaction to the cache list
     dap_ledger_tx_item_t *l_tx_item = DAP_NEW_Z(dap_ledger_tx_item_t);
     if ( !l_tx_item ) {
@@ -5121,13 +5129,13 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
     dap_list_t *l_notifier;
     DL_FOREACH(PVT(a_ledger)->tx_add_notifiers, l_notifier) {
         dap_ledger_tx_notifier_t *l_notify = (dap_ledger_tx_notifier_t*)l_notifier->data;
-        l_notify->callback(l_notify->arg, a_ledger, l_tx_item->tx);
+        l_notify->callback(l_notify->arg, a_ledger, l_tx_item->tx, DAP_LEDGER_NOTIFY_OPCODE_ADDED);
     }
     if (l_cross_network) {
         dap_list_t *l_notifier;
         DL_FOREACH(PVT(a_ledger)->bridged_tx_notifiers, l_notifier) {
             dap_ledger_bridged_tx_notifier_t *l_notify = l_notifier->data;
-            l_notify->callback(a_ledger, a_tx, a_tx_hash, l_notify->arg);
+            l_notify->callback(a_ledger, a_tx, a_tx_hash, l_notify->arg, DAP_LEDGER_NOTIFY_OPCODE_ADDED);
         }
     }
     // Count TPS
@@ -5169,6 +5177,298 @@ FIN:
     return l_ret;
 }
 
+/**
+ * @brief Remove transaction from the cache list
+ * @param a_ledger
+ * @param a_tx
+ * @param a_tx_hash
+ * @param a_from_threshold
+ * @return return 1 OK, -1 error
+ */
+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 l_ret = 0;
+    dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
+    dap_list_t *l_list_bound_items = NULL;
+    dap_list_t *l_list_tx_out = NULL;
+    char *l_main_token_ticker = NULL;
+
+    char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
+    dap_chain_hash_fast_to_str(a_tx_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
+
+    // Get boundary items list into l_list_bound_items
+    // Get tx outs list into l_list_tx_out
+    int l_ret_check;
+    if( (l_ret_check = dap_ledger_tx_cache_check(a_ledger, a_tx, a_tx_hash, false,
+                                                       &l_list_bound_items, &l_list_tx_out,
+                                                       &l_main_token_ticker, NULL, NULL, true))) {
+        debug_if(s_debug_more, L_WARNING, "dap_ledger_tx_remove() tx %s not passed the check: %s ", l_tx_hash_str,
+                    dap_ledger_tx_check_err_str(l_ret_check));
+        return l_ret_check;
+    }
+
+    dap_ledger_tx_item_t *l_ledger_item;
+    pthread_rwlock_rdlock(&PVT(a_ledger)->ledger_rwlock);
+    HASH_FIND(hh, PVT(a_ledger)->ledger_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_ledger_item);
+    pthread_rwlock_unlock(&PVT(a_ledger)->ledger_rwlock);
+    if (l_ledger_item && l_ledger_item->cache_data.n_outs_used != 0) {     // transaction already present in the cache list
+        return DAP_LEDGER_TX_CHECK_OUT_ITEM_ALREADY_USED;
+    }
+    
+    // find all bound pairs 'in' and 'out'
+    size_t l_outs_used = dap_list_length(l_list_bound_items);
+
+    dap_store_obj_t *l_cache_used_outs = NULL;
+    char *l_ledger_cache_group = NULL;
+    if (PVT(a_ledger)->cached) {
+        dap_store_obj_t *l_cache_used_outs = DAP_NEW_Z_SIZE(dap_store_obj_t, sizeof(dap_store_obj_t) * (l_outs_used));
+        if ( !l_cache_used_outs ) {
+            log_it(L_CRITICAL, "Memory allocation error");
+            l_ret = -1;
+            goto FIN;
+        }
+        l_ledger_cache_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_TXS_STR);
+    }
+    const char *l_cur_token_ticker = NULL;
+
+    // Update balance : raise all bound items to balances
+    int l_spent_idx = 0;
+    for (dap_list_t *it = l_list_bound_items; it; it = it->next) {
+        dap_ledger_tx_bound_t *l_bound_item = it->data;
+        dap_chain_tx_item_type_t l_type = l_bound_item->type;
+        if ((l_type == TX_ITEM_TYPE_IN_EMS_LOCK || l_type == TX_ITEM_TYPE_IN_REWARD) &&
+                !s_ledger_token_supply_check_update(a_ledger, l_bound_item->token_item, l_bound_item->value, true))
+            log_it(L_ERROR, "Insufficient supply for token %s", l_bound_item->token_item->ticker);
+
+        switch (l_type) {
+        case TX_ITEM_TYPE_IN_EMS:
+            // Mark it as unused
+            memset(&(l_bound_item->emission_item->tx_used_out), 0, sizeof(dap_hash_fast_t));
+            s_ledger_emission_cache_update(a_ledger, l_bound_item->emission_item);
+            l_outs_used--; // Do not calc this output with tx used items
+            continue;
+
+        case TX_ITEM_TYPE_IN_EMS_LOCK:
+            if (l_bound_item->stake_lock_item) { // Legacy stake lock emission
+                // Mark it as used with current tx hash
+                memset(&(l_bound_item->stake_lock_item->tx_used_out), 0, sizeof(dap_hash_fast_t));
+                s_ledger_stake_lock_cache_update(a_ledger, l_bound_item->stake_lock_item);
+            }
+            l_outs_used--; // Do not calc this output with tx used items
+            continue;
+
+        case TX_ITEM_TYPE_IN_REWARD: {
+            dap_ledger_reward_item_t *l_item = NULL;
+            pthread_rwlock_wrlock(&l_ledger_pvt->rewards_rwlock);
+            HASH_FIND(hh, l_ledger_pvt->rewards, &l_bound_item->reward_key, sizeof(l_bound_item->reward_key), l_item);
+            if(l_item){
+                HASH_DEL(l_ledger_pvt->rewards, l_item);
+                DAP_DEL_Z(l_item);
+            }
+                
+            pthread_rwlock_unlock(&l_ledger_pvt->rewards_rwlock);
+        }
+        l_outs_used--; // Do not calc this output with tx used items
+        continue;
+
+        case TX_ITEM_TYPE_IN: {
+            dap_ledger_wallet_balance_t *wallet_balance = NULL;
+            l_cur_token_ticker = l_bound_item->in.token_ticker;
+            char *l_addr_str = dap_chain_addr_to_str(&l_bound_item->in.addr_from);
+            char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_cur_token_ticker, (char*)NULL);
+            pthread_rwlock_rdlock(&PVT(a_ledger)->balance_accounts_rwlock);
+            HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance);
+            pthread_rwlock_unlock(&PVT(a_ledger)->balance_accounts_rwlock);
+            if (wallet_balance) {
+                if(s_debug_more) {
+                    char *l_balance = dap_chain_balance_print(l_bound_item->value);
+                    log_it(L_DEBUG,"REFUND %s from addr: %s because tx was removed.", l_balance, l_wallet_balance_key);
+                    DAP_DELETE(l_balance);
+                }
+                SUM_256_256(wallet_balance->balance, l_bound_item->value, &wallet_balance->balance);
+                // Update the cache
+                s_balance_cache_update(a_ledger, wallet_balance);
+            } else {
+                if(s_debug_more)
+                    log_it(L_ERROR,"!!! Attempt to SPEND from some non-existent balance !!!: %s %s", l_addr_str, l_cur_token_ticker);
+            }
+            DAP_DELETE(l_wallet_balance_key);
+        } break;
+
+        case TX_ITEM_TYPE_IN_COND: { // all balance deducts performed with previous conditional transaction
+            // Update service items if any
+            dap_ledger_verificator_t *l_verificator;
+            int l_tmp = l_bound_item->cond->header.subtype;
+            pthread_rwlock_rdlock(&s_verificators_rwlock);
+            HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
+            pthread_rwlock_unlock(&s_verificators_rwlock);
+            if (l_verificator && l_verificator->callback_deleted)
+                l_verificator->callback_deleted(a_ledger, a_tx, l_bound_item->cond);
+        } break;
+
+        default:
+            log_it(L_ERROR, "Unknown item type %d in ledger TX bound for IN part", l_type);
+            break;
+        }
+
+        // add a used output memset(&(l_bound_item->stake_lock_item->tx_used_out), 0, sizeof(dap_hash_fast_t));
+        dap_ledger_tx_item_t *l_prev_item_out = l_bound_item->prev_item;
+        memset(&(l_prev_item_out->cache_data.tx_hash_spent_fast[l_bound_item->prev_out_idx]), 0, sizeof(dap_hash_fast_t));
+        l_prev_item_out->cache_data.n_outs_used--;
+        if (PVT(a_ledger)->cached) {
+            // mirror it in the cache
+            size_t l_tx_size = dap_chain_datum_tx_get_size(l_prev_item_out->tx);
+            size_t l_tx_cache_sz = l_tx_size + sizeof(l_prev_item_out->cache_data);
+            byte_t *l_tx_cache = DAP_NEW_Z_SIZE(byte_t, l_tx_cache_sz);
+            memcpy(l_tx_cache, &l_prev_item_out->cache_data, sizeof(l_prev_item_out->cache_data));
+            memcpy(l_tx_cache + sizeof(l_prev_item_out->cache_data), l_prev_item_out->tx, l_tx_size);
+            char *l_tx_i_hash = dap_chain_hash_fast_to_str_new(&l_prev_item_out->tx_hash_fast);
+            l_cache_used_outs[l_spent_idx] = (dap_store_obj_t) {
+                    .key        = l_tx_i_hash,
+                    .value      = l_tx_cache,
+                    .value_len  = l_tx_cache_sz,
+                    .group      = l_ledger_cache_group
+            };
+            l_cache_used_outs[l_spent_idx].timestamp = 0;
+        }
+        // mark previous transactions as used with the extra timestamp
+        if(l_prev_item_out->cache_data.n_outs_used != l_prev_item_out->cache_data.n_outs)
+            l_prev_item_out->cache_data.ts_spent = 0;
+
+        if (l_type == TX_ITEM_TYPE_IN || l_type == TX_ITEM_TYPE_IN_COND) {
+            l_spent_idx++;
+        }
+    }
+
+    // Update balance: deducts all outs from balances
+    bool l_multichannel = false;
+    bool l_cross_network = false;
+    for (dap_list_t *l_tx_out = l_list_tx_out; l_tx_out; l_tx_out = dap_list_next(l_tx_out)) {
+        if (!l_tx_out->data) {
+            debug_if(s_debug_more, L_WARNING, "Can't detect tx ticker or matching output, can't append balances cache");
+            continue;
+        }
+        dap_chain_tx_item_type_t l_type = *(uint8_t *)l_tx_out->data;
+        if (l_type == TX_ITEM_TYPE_OUT_COND) {
+            // Update service items if any
+            dap_chain_tx_out_cond_t *l_cond = (dap_chain_tx_out_cond_t *)l_tx_out->data;
+            dap_ledger_verificator_t *l_verificator;
+            int l_tmp = l_cond->header.subtype;
+            pthread_rwlock_rdlock(&s_verificators_rwlock);
+            HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
+            pthread_rwlock_unlock(&s_verificators_rwlock);
+            if (l_verificator && l_verificator->callback_deleted)
+                l_verificator->callback_deleted(a_ledger, a_tx, NULL);
+            continue;   // balance raise will be with next conditional transaction
+        }
+
+        dap_chain_addr_t *l_addr = NULL;
+        uint256_t l_value = {};
+        switch (l_type) {
+        case TX_ITEM_TYPE_OUT: {
+            dap_chain_tx_out_t *l_out_item_256 = (dap_chain_tx_out_t *)l_tx_out->data;
+            l_addr = &l_out_item_256->addr;
+            l_value = l_out_item_256->header.value;
+            l_cur_token_ticker = l_main_token_ticker;
+        } break;
+        case TX_ITEM_TYPE_OUT_OLD: {
+            dap_chain_tx_out_old_t *l_out_item = (dap_chain_tx_out_old_t *)l_tx_out->data;
+            l_addr = &l_out_item->addr;
+            l_value = GET_256_FROM_64(l_out_item->header.value);
+            l_cur_token_ticker = l_main_token_ticker;
+        } break;
+        case TX_ITEM_TYPE_OUT_EXT: {
+            dap_chain_tx_out_ext_t *l_out_item_ext_256 = (dap_chain_tx_out_ext_t *)l_tx_out->data;
+            l_addr = &l_out_item_ext_256->addr;
+            l_value = l_out_item_ext_256->header.value;
+            l_cur_token_ticker = l_out_item_ext_256->token;
+            l_multichannel = true;
+        } break;
+        default:
+            log_it(L_DEBUG, "Unknown item type %d", l_type);
+            break;
+        }
+        if (!l_addr)
+            continue;
+        else if (l_addr->net_id.uint64 != a_ledger->net->pub.id.uint64 &&
+                 !dap_chain_addr_is_blank(l_addr))
+            l_cross_network = true;
+        char *l_addr_str = dap_chain_addr_to_str(l_addr);
+        dap_ledger_wallet_balance_t *wallet_balance = NULL;
+        char *l_wallet_balance_key = dap_strjoin(" ", l_addr_str, l_cur_token_ticker, (char*)NULL);
+        if(s_debug_more) {
+            char *l_balance = dap_chain_balance_print(l_value);
+            log_it(L_DEBUG, "GOT %s to addr: %s", l_balance, l_wallet_balance_key);
+            DAP_DELETE(l_balance);
+        }
+        pthread_rwlock_rdlock(&l_ledger_pvt->balance_accounts_rwlock);
+        HASH_FIND_STR(PVT(a_ledger)->balance_accounts, l_wallet_balance_key, wallet_balance);
+        pthread_rwlock_unlock(&l_ledger_pvt->balance_accounts_rwlock);
+        if (wallet_balance) {
+            //if(s_debug_more)
+            //    log_it(L_DEBUG, "Balance item is present in cache");
+            SUBTRACT_256_256(wallet_balance->balance, l_value, &wallet_balance->balance);
+            DAP_DELETE (l_wallet_balance_key);
+            // Update the cache
+            s_balance_cache_update(a_ledger, wallet_balance);
+        } else {
+            log_it(L_CRITICAL, "Wallet is not presented in cache. Can't substract out value from balance.");
+        }
+    }
+
+    if (dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTING, NULL) && s_voting_callbacks.voting_delete_callback)
+        s_voting_callbacks.voting_delete_callback(a_ledger, TX_ITEM_TYPE_VOTING, a_tx);
+    else if (dap_chain_datum_tx_items_get((dap_chain_datum_tx_t*) a_tx, TX_ITEM_TYPE_VOTE, NULL) && s_voting_callbacks.voting_delete_callback)
+        s_voting_callbacks.voting_delete_callback(a_ledger, TX_ITEM_TYPE_VOTE, a_tx);
+
+
+    // remove transaction from ledger 
+    dap_ledger_tx_item_t *l_tx_item = NULL;
+    pthread_rwlock_wrlock(&l_ledger_pvt->ledger_rwlock);
+    HASH_FIND(hh, l_ledger_pvt->ledger_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_tx_item);
+    if (l_tx_item)
+        HASH_DEL(l_ledger_pvt->ledger_items, l_tx_item);
+    pthread_rwlock_unlock(&l_ledger_pvt->ledger_rwlock);
+    
+    // Callable callback
+    dap_list_t *l_notifier;
+    DL_FOREACH(PVT(a_ledger)->tx_add_notifiers, l_notifier) {
+        dap_ledger_tx_notifier_t *l_notify = (dap_ledger_tx_notifier_t*)l_notifier->data;
+        l_notify->callback(l_notify->arg, a_ledger, l_tx_item->tx, DAP_LEDGER_NOTIFY_OPCODE_DELETED);
+    }
+    if (l_cross_network) {
+        dap_list_t *l_notifier;
+        DL_FOREACH(PVT(a_ledger)->bridged_tx_notifiers, l_notifier) {
+            dap_ledger_bridged_tx_notifier_t *l_notify = l_notifier->data;
+            l_notify->callback(a_ledger, a_tx, a_tx_hash, l_notify->arg, DAP_LEDGER_NOTIFY_OPCODE_DELETED);
+        }
+    }
+
+    if (PVT(a_ledger)->cached) {
+        // Add it to cache
+        dap_global_db_del_sync(l_ledger_cache_group, l_tx_hash_str);
+        // Apply it with single DB transaction
+        if (dap_global_db_set_raw(l_cache_used_outs, l_outs_used, NULL, NULL))
+            debug_if(s_debug_more, L_WARNING, "Ledger cache mismatch");
+    }
+FIN:
+    if (l_list_bound_items)
+        dap_list_free_full(l_list_bound_items, NULL);
+    if (l_list_tx_out)
+        dap_list_free(l_list_tx_out);
+    DAP_DEL_Z(l_main_token_ticker);
+    if (PVT(a_ledger)->cached) {
+        for (size_t i = 1; i < l_outs_used; i++) {
+            DAP_DEL_Z(l_cache_used_outs[i].key);
+            DAP_DEL_Z(l_cache_used_outs[i].value);
+        }
+        DAP_DEL_Z(l_cache_used_outs);
+        DAP_DEL_Z(l_ledger_cache_group);
+    }
+    return l_ret;
+}
+
+
 static bool s_ledger_tps_callback(void *a_arg)
 {
     dap_ledger_private_t *l_ledger_pvt = (dap_ledger_private_t *)a_arg;
@@ -5184,6 +5484,7 @@ static bool s_ledger_tps_callback(void *a_arg)
 
 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)
 {
+#ifndef DAP_LEDGER_TEST
     if (dap_chain_net_get_load_mode(a_ledger->net)) {
         if (PVT(a_ledger)->cache_tx_check_callback)
             PVT(a_ledger)->cache_tx_check_callback(a_ledger, a_tx_hash);
@@ -5201,6 +5502,7 @@ int dap_ledger_tx_load(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_c
         if (l_tx_item)
             return DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS;
     }
+#endif
     return dap_ledger_tx_add(a_ledger, a_tx, a_tx_hash, false);
 }
 
@@ -5973,7 +6275,7 @@ dap_list_t *dap_ledger_get_list_tx_outs(dap_ledger_t *a_ledger, const char *a_to
 
 
 // Add new verificator callback with associated subtype. Returns 1 if callback replaced, -1 error, overwise returns 0
-int dap_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_ledger_verificator_callback_t a_callback, dap_ledger_updater_callback_t a_callback_added)
+int dap_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_ledger_verificator_callback_t a_callback, dap_ledger_updater_callback_t a_callback_added, dap_ledger_updater_callback_t a_callback_deleted)
 {
     dap_ledger_verificator_t *l_new_verificator;
     int l_tmp = (int)a_subtype;
@@ -5992,23 +6294,26 @@ int dap_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_le
     l_new_verificator->subtype = (int)a_subtype;
     l_new_verificator->callback = a_callback;
     l_new_verificator->callback_added = a_callback_added;
+    l_new_verificator->callback_deleted = a_callback_deleted;
     pthread_rwlock_wrlock(&s_verificators_rwlock);
     HASH_ADD_INT(s_verificators, subtype, l_new_verificator);
     pthread_rwlock_unlock(&s_verificators_rwlock);
     return 0;
 }
 
-int dap_chain_ledger_voting_verificator_add(dap_chain_ledger_voting_callback_t a_callback)
+int dap_chain_ledger_voting_verificator_add(dap_chain_ledger_voting_callback_t a_callback, dap_chain_ledger_voting_delete_callback_t a_callback_delete)
 {
     if (!a_callback)
         return -1;
 
-    if (s_voting_callback){
-        s_voting_callback = a_callback;
+    if (!s_voting_callbacks.voting_callback || !s_voting_callbacks.voting_delete_callback){
+        s_voting_callbacks.voting_callback = a_callback;
+        s_voting_callbacks.voting_delete_callback = a_callback_delete;
         return 1;
     }
 
-    s_voting_callback = a_callback;
+    s_voting_callbacks.voting_callback = a_callback;
+    s_voting_callbacks.voting_delete_callback = a_callback_delete;
     return 0;
 }
 
@@ -6286,7 +6591,7 @@ const char *dap_ledger_tx_calculate_main_ticker(dap_ledger_t *a_ledger, dap_chai
 {
     char *l_main_ticker = NULL;
     dap_chain_hash_fast_t *l_tx_hash = dap_chain_node_datum_tx_calc_hash(a_tx);
-    int l_rc = dap_ledger_tx_cache_check(a_ledger, a_tx, l_tx_hash, false, NULL, NULL, &l_main_ticker, NULL, NULL);  
+    int l_rc = dap_ledger_tx_cache_check(a_ledger, a_tx, l_tx_hash, false, NULL, NULL, &l_main_ticker, NULL, NULL, false);  
     if (l_rc == DAP_LEDGER_TX_ALREADY_CACHED)
         l_main_ticker = (char *)dap_ledger_tx_get_token_ticker_by_hash(a_ledger, l_tx_hash);
     DAP_DEL_Z(l_tx_hash);
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index c2648d9ae3faa9d8eff2251fb146a786d3149d33..2e6da3ae0d3e9f765b288e583824552f458438f6 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -1831,6 +1831,30 @@ void dap_chain_net_delete(dap_chain_net_t *a_net)
     DAP_DELETE(a_net);
 }
 
+#ifdef DAP_LEDGER_TEST
+int dap_chain_net_test_init()
+{
+    dap_chain_net_id_t l_iddn = {0};
+    sscanf("0xFA0", "0x%16"DAP_UINT64_FORMAT_x, &l_iddn.uint64);
+    dap_chain_net_t *l_net = s_net_new(&l_iddn, "Snet", "TestCoin", "root");
+    
+    
+    // l_net->pub.id.uint64 = l_iddn.uint64;
+    // l_net->pub.native_ticker = "TestCoin";
+    // l_net->pub.name = "Snet";
+
+    dap_chain_net_item_t *l_net_item = DAP_NEW_Z(dap_chain_net_item_t);
+    dap_strncpy(l_net_item->name, "Snet", DAP_CHAIN_NET_NAME_MAX);
+    l_net_item->chain_net = l_net;
+    l_net_item->net_id.uint64 = l_net->pub.id.uint64;
+
+    HASH_ADD(hh2, s_net_ids, net_id, sizeof(l_net_item->net_id), l_net_item);
+
+    return 0;
+}
+#endif
+
+
 /**
  * @brief load network config settings from cellframe-node.cfg file
  *
@@ -2120,7 +2144,6 @@ int s_net_init(const char *a_net_name, uint16_t a_acl_idx)
     dap_chain_net_decree_init(l_net);
 
     l_net->pub.config = l_cfg;
-
     return 0;
 }
 
@@ -3214,6 +3237,68 @@ int dap_chain_datum_add(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t
     return 0;
 }
 
+/**
+ * @brief Add datum to the ledger or smth else
+ * @param a_chain
+ * @param a_datum
+ * @param a_datum_size
+ * @return
+ */
+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)
+{
+    size_t l_datum_data_size = a_datum->header.data_size;
+    if (a_datum_size < l_datum_data_size + sizeof(a_datum->header)) {
+        log_it(L_INFO,"Corrupted datum rejected: wrong size %zd not equal or less than datum size %zd",a_datum->header.data_size+ sizeof (a_datum->header),
+               a_datum_size );
+        return -101;
+    }
+    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_DECREE: {
+            /*dap_chain_datum_decree_t *l_decree = (dap_chain_datum_decree_t *)a_datum->data;
+            size_t l_decree_size = dap_chain_datum_decree_get_size(l_decree);
+            if (l_decree_size != l_datum_data_size) {
+                log_it(L_WARNING, "Corrupted decree, datum size %zd is not equal to size of decree %zd", l_datum_data_size, l_decree_size);
+                return -102;
+            }*/
+            return 0; //dap_chain_net_decree_load(l_decree, a_chain, a_datum_hash);
+        }
+        case DAP_CHAIN_DATUM_ANCHOR: {
+            dap_chain_datum_anchor_t *l_anchor = (dap_chain_datum_anchor_t *)a_datum->data;
+            size_t l_anchor_size = dap_chain_datum_anchor_get_size(l_anchor);
+            if (l_anchor_size != l_datum_data_size) {
+                log_it(L_WARNING, "Corrupted anchor, datum size %zd is not equal to size of anchor %zd", l_datum_data_size, l_anchor_size);
+                return -102;
+            }
+            return dap_chain_net_anchor_unload(l_anchor, a_chain);
+        }
+        case DAP_CHAIN_DATUM_TOKEN_DECL:
+            return 0;//dap_ledger_token_load(l_ledger, a_datum->data, a_datum->header.data_size);
+
+        case DAP_CHAIN_DATUM_TOKEN_EMISSION:
+            return 0;//dap_ledger_token_emission_load(l_ledger, a_datum->data, a_datum->header.data_size, a_datum_hash);
+
+        case DAP_CHAIN_DATUM_TX: {
+            dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)a_datum->data;
+            size_t l_tx_size = dap_chain_datum_tx_get_size(l_tx);
+            if (l_tx_size != l_datum_data_size) {
+                log_it(L_WARNING, "Corrupted trnsaction, datum size %zd is not equal to size of TX %zd", l_datum_data_size, l_tx_size);
+                return -102;
+            }
+            return dap_ledger_tx_remove(l_ledger, l_tx, a_datum_hash);
+        }
+        case DAP_CHAIN_DATUM_CA:
+            return 0;//dap_cert_chain_file_save(a_datum, a_chain->net_name);
+
+        case DAP_CHAIN_DATUM_SIGNER:
+        case DAP_CHAIN_DATUM_CUSTOM:
+            break;
+        default:
+            return -666;
+    }
+    return 0;
+}
+
 bool dap_chain_net_get_load_mode(dap_chain_net_t * a_net)
 {
     return PVT(a_net)->load_mode;
@@ -3238,6 +3323,11 @@ int dap_chain_net_add_reward(dap_chain_net_t *a_net, uint256_t a_reward, uint64_
     return 0;
 }
 
+void dap_chain_net_remove_last_reward(dap_chain_net_t *a_net)
+{
+    DL_DELETE(PVT(a_net)->rewards, PVT(a_net)->rewards);
+}
+
 uint256_t dap_chain_net_get_reward(dap_chain_net_t *a_net, uint64_t a_block_num)
 {
     struct block_reward *l_reward;
diff --git a/modules/net/dap_chain_net_anchor.c b/modules/net/dap_chain_net_anchor.c
index 50c9024ad925a43e1fdac60f9ea1265080ffb7d4..e51977539f5a02d1da142b607e63d645261fd1c7 100644
--- a/modules/net/dap_chain_net_anchor.c
+++ b/modules/net/dap_chain_net_anchor.c
@@ -26,11 +26,15 @@
 #include "dap_common.h"
 #include "dap_sign.h"
 #include "dap_pkey.h"
+#include "dap_chain.h"
+#include "dap_chain_cell.h"
 #include "dap_chain_common.h"
 #include "dap_chain_ledger.h"
+#include "dap_chain_datum_decree.h"
+#include "dap_chain_net_srv_stake_pos_delegate.h"
 #include "dap_chain_net.h"
+#include "dap_chain_net_tx.h"
 #include "dap_chain_net_decree.h"
-#include "dap_chain_datum_decree.h"
 #include "dap_chain_datum_anchor.h"
 
 #define LOG_TAG "chain_net_anchor"
@@ -165,6 +169,222 @@ int dap_chain_net_anchor_load(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *
     return ret_val;
 }
 
+dap_chain_datum_anchor_t * s_find_previous_anchor(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain)
+{
+    if (!a_anchor || !a_chain){
+        log_it(L_ERROR,"Params are NULL");
+        return NULL;
+    }
+
+    dap_chain_datum_anchor_t * l_ret_anchor = NULL;
+
+    dap_hash_fast_t l_old_decrere_hash = {};
+    if (dap_chain_datum_anchor_get_hash_from_data(a_anchor, &l_old_decrere_hash) != 0)
+        return NULL;
+    dap_chain_datum_decree_t *l_old_decree = dap_chain_net_decree_get_by_hash(&l_old_decrere_hash, NULL);
+    uint16_t l_old_decree_type = l_old_decree->header.type;
+    uint16_t l_old_decree_subtype = l_old_decree->header.sub_type;
+
+    dap_chain_cell_t *l_cell = a_chain->cells;
+    size_t l_atom_size = 0;
+    dap_chain_atom_iter_t *l_atom_iter = a_chain->callback_atom_iter_create(a_chain, l_cell->id, 0);
+    dap_chain_atom_ptr_t l_atom = a_chain->callback_atom_iter_get(l_atom_iter, DAP_CHAIN_ITER_OP_LAST, &l_atom_size);
+    while(l_atom && l_atom_size){
+        size_t l_datums_count = 0;
+        dap_chain_datum_t **l_datums = a_chain->callback_atom_get_datums(l_atom, l_atom_size, &l_datums_count);
+        dap_chain_datum_t *l_datum, *l_datum2;
+        for(size_t l_datum_n = 0; l_datum_n < l_datums_count; l_datum_n++) {
+            if ( ! (l_datum = l_datums[l_datum_n]) )
+                continue;
+
+            if (l_datum->header.type_id != DAP_CHAIN_DATUM_ANCHOR || a_anchor == (dap_chain_datum_anchor_t *)l_datum->data)
+                continue;
+
+            dap_chain_datum_anchor_t *l_curr_anchor = (dap_chain_datum_anchor_t *)l_datum->data;
+            dap_hash_fast_t l_hash = {};
+            if (dap_chain_datum_anchor_get_hash_from_data(l_curr_anchor, &l_hash) != 0)
+                continue;
+            
+            bool l_is_applied = false;
+            dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(&l_hash, &l_is_applied);
+            if (!l_decree)
+                continue;
+
+            if (l_decree->header.type == l_old_decree_type && l_old_decree_type == DAP_CHAIN_DATUM_DECREE_TYPE_COMMON && 
+                l_old_decree_subtype == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE &&
+                l_decree->header.sub_type == DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_APPROVE){
+                
+                dap_chain_addr_t l_addr_old, l_addr_new = {};
+                if (dap_chain_datum_decree_get_stake_signing_addr(l_old_decree, &l_addr_old)){
+                    continue;
+                }
+
+                if (dap_chain_datum_decree_get_stake_signing_addr(l_decree, &l_addr_new)){
+                    continue;
+                }
+
+                if(dap_chain_addr_compare(&l_addr_old, &l_addr_new)){
+                    l_ret_anchor = l_curr_anchor;
+                    dap_chain_net_decree_reset_applied(a_chain, &l_hash);
+                break;
+                }
+            } else if (l_decree->header.type == l_old_decree_type && l_decree->header.sub_type == l_old_decree_subtype){
+                // check addr if l_decree type is stake approve
+                l_ret_anchor = l_curr_anchor;
+                dap_chain_net_decree_reset_applied(a_chain, &l_hash);
+                break;
+            }
+        }
+        DAP_DEL_Z(l_datums);
+        if (l_ret_anchor)
+            break;
+        // go to previous atom
+        l_atom = a_chain->callback_atom_iter_get(l_atom_iter, DAP_CHAIN_ITER_OP_PREV, &l_atom_size);
+    }
+    a_chain->callback_atom_iter_delete(l_atom_iter);
+
+    return l_ret_anchor;
+}
+
+int dap_chain_net_anchor_unload(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain)
+{
+    int ret_val = 0;
+
+    if (!a_anchor || !a_chain)
+    {
+        log_it(L_WARNING,"Invalid arguments. a_decree and a_chain must be not NULL");
+        return -107;
+    }
+
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
+
+    if (!l_net->pub.decree)
+    {
+        log_it(L_WARNING,"Decree is not inited!");
+        return -108;
+    }
+
+    if ((ret_val = dap_chain_net_anchor_verify(l_net, a_anchor, dap_chain_datum_anchor_get_size(a_anchor))) != 0)
+    {
+        log_it(L_WARNING,"Decree is not pass verification!");
+        return ret_val;
+    }
+
+    dap_hash_fast_t l_hash = {};
+    if (dap_chain_datum_anchor_get_hash_from_data(a_anchor, &l_hash) != 0)
+        return -110;
+            
+    dap_chain_datum_decree_t *l_decree = dap_chain_net_decree_get_by_hash(&l_hash, NULL);
+    if (!l_decree)
+        return -111;
+
+    if(l_decree->header.type == DAP_CHAIN_DATUM_DECREE_TYPE_COMMON){
+        switch (l_decree->header.sub_type)
+        {
+            case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_FEE:{
+                dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor, a_chain);
+                if (l_new_anchor){// if previous anchor is founded apply it
+                    dap_chain_hash_fast_t l_hash = {0};
+                    if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){
+                        log_it(L_WARNING,"Can not find datum hash in anchor data");
+                        return -109;
+                    }
+
+                    if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){
+                        log_it(L_WARNING,"Decree applying failed");
+                        return ret_val;
+                    }
+                } else {
+                    dap_chain_addr_t a_addr = c_dap_chain_addr_blank;
+                    if (!dap_chain_net_tx_set_fee(a_chain->net_id, uint256_0, a_addr)){
+                        log_it(L_ERROR, "Can't set fee value for network %s", dap_chain_net_by_id(a_chain->net_id)->pub.name);
+                        ret_val = -100;
+                    }
+                }
+            }
+            break;
+            case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_APPROVE:{
+                // Invalidate canceled stake
+                dap_chain_addr_t l_signing_addr = {};
+                if ((ret_val = dap_chain_datum_decree_get_stake_signing_addr(l_decree, &l_signing_addr)) != 0){
+                log_it(L_WARNING,"Can't get signing address from decree.");
+                    return -105;
+                }
+                dap_chain_net_srv_stake_key_invalidate(&l_signing_addr);
+            }
+            break;
+            case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_INVALIDATE:{
+                // Find previous anchor with this stake approve and apply it 
+                dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor, a_chain);
+                if (l_new_anchor){// if previous anchor is founded apply it
+                    dap_chain_hash_fast_t l_hash = {0};
+                    if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){
+                        log_it(L_WARNING,"Can not find datum hash in anchor data");
+                        return -109;
+                    }
+                    if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){
+                        log_it(L_WARNING,"Decree applying failed");
+                        return ret_val;
+                    }
+                }
+            }
+            break;
+            case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_MIN_VALUE:{
+                dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor, a_chain);
+                if (l_new_anchor){// if previous anchor is founded apply it
+                    dap_chain_hash_fast_t l_hash = {0};
+                    if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){
+                        log_it(L_WARNING,"Can not find datum hash in anchor data");
+                        return -109;
+                    }
+                    if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){
+                        log_it(L_WARNING,"Decree applying failed");
+                        return ret_val;
+                    }
+                } else {
+                    dap_chain_addr_t a_addr = {};
+                    dap_chain_net_srv_stake_set_allowed_min_value(a_chain->net_id, dap_chain_coins_to_balance("1.0"));
+                }
+            }
+            break;
+            case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_STAKE_MIN_VALIDATORS_COUNT:{
+                dap_chain_datum_anchor_t * l_new_anchor = s_find_previous_anchor(a_anchor, a_chain);
+                if (l_new_anchor){// if previous anchor is founded apply it
+                    dap_chain_hash_fast_t l_hash = {0};
+                    if ((ret_val = dap_chain_datum_anchor_get_hash_from_data(l_new_anchor, &l_hash)) != 0){
+                        log_it(L_WARNING,"Can not find datum hash in anchor data");
+                        return -109;
+                    }
+
+                    if((ret_val = dap_chain_net_decree_apply(&l_hash, NULL, a_chain))!=0){
+                        log_it(L_WARNING,"Decree applying failed");
+                        return ret_val;
+                    }
+                } else {
+                    dap_chain_esbocs_set_min_validators_count(a_chain, 0);                    
+                }
+            }
+            break;
+            case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_REWARD:{
+                // find previous anchor with rewarrd and apply it
+                dap_chain_net_remove_last_reward(dap_chain_net_by_id(a_chain->net_id));
+            }
+            break;
+            case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_OWNERS:
+            case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_OWNERS_MIN:
+            case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_BAN:
+            case DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_UNBAN:
+                ret_val = -1;
+            default:
+                break;
+        }
+    } else if(l_decree->header.type == DAP_CHAIN_DATUM_DECREE_TYPE_SERVICE){
+
+    }
+
+    return ret_val;
+}
+
 // Private functions
 static bool s_verify_pubkeys (dap_sign_t *a_sign, dap_sign_t **a_decree_signs, size_t a_num_of_decree_sign)
 {
diff --git a/modules/net/dap_chain_net_decree.c b/modules/net/dap_chain_net_decree.c
index 2e717d59e0afadd6c4f7b4edfd04c14962ff87b7..e30a3d28afb38a121c7ea93c79a36b73bb2fda0d 100644
--- a/modules/net/dap_chain_net_decree.c
+++ b/modules/net/dap_chain_net_decree.c
@@ -239,7 +239,7 @@ int dap_chain_net_decree_apply(dap_hash_fast_t *a_decree_hash, dap_chain_datum_d
 
     l_net = dap_chain_net_by_id(a_chain->net_id);
 
-    if (!l_net->pub.decree)
+    if (!l_net || !l_net->pub.decree)
     {
         log_it(L_WARNING,"Decree is not inited!");
         return -108;
@@ -326,6 +326,20 @@ int dap_chain_net_decree_load(dap_chain_datum_decree_t * a_decree, dap_chain_t *
     return dap_chain_net_decree_apply(a_decree_hash, a_decree, a_chain);
 }
 
+int dap_chain_net_decree_reset_applied(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_decree_hash)
+{
+    if (!a_chain || !a_decree_hash)
+        return -1;
+    struct decree_hh* l_decree_hh = NULL;
+    HASH_FIND(hh, s_decree_hh, a_decree_hash, sizeof(dap_hash_fast_t), l_decree_hh);
+    if (!l_decree_hh)
+        return -2;
+
+    l_decree_hh->is_applied = false;
+
+    return 0;
+}
+
 dap_chain_datum_decree_t *dap_chain_net_decree_get_by_hash(dap_hash_fast_t *a_hash, bool *is_applied)
 {
     struct decree_hh* l_decree_hh = NULL;
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 1e668e7933db5c50f5d9ea57c75046885b2f206d..6080007ce9f25eb9300a2a57e284e7144d11c7e9 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -3702,7 +3702,11 @@ int com_mempool(int a_argc, char **a_argv, void **a_str_reply)
             return -2;
         }
     }
-    dap_chain_node_cli_cmd_values_parse_net_chain_for_json(&arg_index, a_argc, a_argv, &l_chain, &l_net, CHAIN_TYPE_INVALID);
+    int cmd_parse_status = dap_chain_node_cli_cmd_values_parse_net_chain_for_json(&arg_index, a_argc, a_argv, &l_chain, &l_net, CHAIN_TYPE_INVALID);
+    if (cmd_parse_status != 0){
+        dap_json_rpc_error_add(cmd_parse_status, "Request parsing error (code: %d)", cmd_parse_status);
+            return cmd_parse_status;
+    }
     const char *l_hash_out_type = "hex";
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-H", &l_hash_out_type);
     const char *l_datum_hash_in = NULL;
diff --git a/modules/net/include/dap_chain_ledger.h b/modules/net/include/dap_chain_ledger.h
index ab4105e834b18fa98dffadeb9f289ab9a66579a6..f39bee757e3a0be0ab49769d084d9b8c848bed22 100644
--- a/modules/net/include/dap_chain_ledger.h
+++ b/modules/net/include/dap_chain_ledger.h
@@ -117,6 +117,10 @@ typedef enum dap_ledger_token_decl_add_err{
     DAP_LEDGER_TOKEN_DECL_ADD_UNKNOWN /* MAX */
 } dap_ledger_token_decl_add_err_t;
 
+typedef enum dap_chan_ledger_notify_opcodes{
+    DAP_LEDGER_NOTIFY_OPCODE_ADDED = 'a', // 0x61
+    DAP_LEDGER_NOTIFY_OPCODE_DELETED = 'd', // 0x64 
+} dap_chan_ledger_notify_opcodes_t;
 typedef enum dap_chain_tx_tag_action_type {    
 
     //subtags, till 32
@@ -149,13 +153,15 @@ typedef struct dap_ledger_datum_iter {
 
 typedef bool (*dap_ledger_verificator_callback_t)(dap_ledger_t *a_ledger, dap_chain_tx_out_cond_t *a_tx_out_cond, dap_chain_datum_tx_t *a_tx_in, bool a_owner);
 typedef void (*dap_ledger_updater_callback_t)(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_prev_cond);
-typedef void (* dap_ledger_tx_add_notify_t)(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx);
-typedef void (* dap_ledger_bridged_tx_notify_t)(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, void *a_arg);
+typedef void (* dap_ledger_tx_add_notify_t)(void *a_arg, dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chan_ledger_notify_opcodes_t a_opcode);
+typedef void (* dap_ledger_bridged_tx_notify_t)(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash, void *a_arg, dap_chan_ledger_notify_opcodes_t a_opcode);
 typedef bool (*dap_ledger_cache_tx_check_callback_t)(dap_ledger_t *a_ledger, dap_hash_fast_t *a_tx_hash);
 typedef struct dap_chain_net dap_chain_net_t;
 typedef bool (*dap_chain_ledger_voting_callback_t)(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx, bool a_apply);
+typedef bool (*dap_chain_ledger_voting_delete_callback_t)(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx);
 typedef bool (*dap_ledger_tag_check_callback_t)(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_datum_tx_item_groups_t *a_items_grp, dap_chain_tx_tag_action_type_t *a_action);
 
+
 //Change this UUID to automatically reload ledger cache on next node startup
 #define DAP_LEDGER_CACHE_RELOAD_ONCE_UUID "0c92b759-a565-448f-b8bd-99103dacf7fc"
 
@@ -226,7 +232,7 @@ DAP_STATIC_INLINE char *dap_ledger_get_gdb_group(dap_ledger_t *a_ledger, const c
  */
 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);
 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);
-
+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);
 
@@ -317,7 +323,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger,
                                         dap_list_t **a_list_tx_out, 
                                         char **a_main_ticker,
                                         dap_chain_net_srv_uid_t *a_tag,
-                                        dap_chain_tx_tag_action_type_t *a_action);
+                                        dap_chain_tx_tag_action_type_t *a_action, bool a_check_for_removing);
 
 const char *dap_ledger_tx_calculate_main_ticker(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, int *a_ledger_rc);
 
@@ -400,9 +406,9 @@ dap_list_t *dap_ledger_get_list_tx_cond_outs(dap_ledger_t *a_ledger, const char
                                              dap_chain_tx_out_cond_subtype_t a_subtype, uint256_t *a_value_transfer);
 // Add new verificator callback with associated subtype. Returns 1 if callback replaced, overwise returns 0
 int dap_ledger_verificator_add(dap_chain_tx_out_cond_subtype_t a_subtype, dap_ledger_verificator_callback_t a_callback,
-                                     dap_ledger_updater_callback_t a_callback_added);
+                                     dap_ledger_updater_callback_t a_callback_added, dap_ledger_updater_callback_t a_callback_deleted);
 // Add new verificator callback for voting. Returns 1 if callback replaced, overwise returns 0
-int dap_chain_ledger_voting_verificator_add(dap_chain_ledger_voting_callback_t a_callback);
+int dap_chain_ledger_voting_verificator_add(dap_chain_ledger_voting_callback_t a_callback, dap_chain_ledger_voting_delete_callback_t a_callback_delete);
 // Getting a list of transactions from the ledger.
 dap_list_t * dap_ledger_get_txs(dap_ledger_t *a_ledger, size_t a_count, size_t a_page, bool a_reverse, bool a_unspent_only);
 
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index e30e47952cee2a47c4dde36cf4b1750b42c8ff88..e98b723bd74d11e90d4d6e61d30046c14c02fb25 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -91,6 +91,9 @@ typedef bool (dap_chain_datum_filter_func_t)(dap_chain_datum_t *a_datum, dap_cha
 
 int dap_chain_net_init(void);
 void dap_chain_net_deinit(void);
+#ifdef DAP_LEDGER_TEST
+int dap_chain_net_test_init();
+#endif
 
 DAP_STATIC_INLINE uint64_t dap_chain_net_get_cur_addr_int(dap_chain_net_t *a_net) { return g_node_addr.uint64; }
 
@@ -146,6 +149,7 @@ bool dap_chain_net_remove_validator_from_clusters(dap_chain_t *a_chain, dap_stre
 dap_global_db_cluster_t *dap_chain_net_get_mempool_cluster(dap_chain_t *a_chain);
 
 int dap_chain_net_add_reward(dap_chain_net_t *a_net, uint256_t a_reward, uint64_t a_block_num);
+void dap_chain_net_remove_last_reward(dap_chain_net_t *a_net);
 uint256_t dap_chain_net_get_reward(dap_chain_net_t *a_net, uint64_t a_block_num);
 int dap_chain_net_link_add(dap_chain_net_t *a_net, dap_stream_node_addr_t *a_addr, const char *a_host, uint16_t a_port);
 
@@ -197,6 +201,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);
+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);
 void dap_chain_net_announce_addrs(dap_chain_net_t *a_net);
diff --git a/modules/net/include/dap_chain_net_anchor.h b/modules/net/include/dap_chain_net_anchor.h
index 34f8f084a86b86d66a48d5371cad83d5c52cac0f..1a44cab2a1f10439cd03d4c91b355c78d3380355 100644
--- a/modules/net/include/dap_chain_net_anchor.h
+++ b/modules/net/include/dap_chain_net_anchor.h
@@ -26,3 +26,4 @@
 
 int dap_chain_net_anchor_verify(dap_chain_net_t *a_net, dap_chain_datum_anchor_t * a_anchor, size_t a_data_size);
 int dap_chain_net_anchor_load(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain);
+int dap_chain_net_anchor_unload(dap_chain_datum_anchor_t * a_anchor, dap_chain_t *a_chain);
\ No newline at end of file
diff --git a/modules/net/include/dap_chain_net_decree.h b/modules/net/include/dap_chain_net_decree.h
index c8dc68956cb65e7b7f58f711bea6744ee4901eb2..95b035c5650e961a774ba519e5672cf793716442 100644
--- a/modules/net/include/dap_chain_net_decree.h
+++ b/modules/net/include/dap_chain_net_decree.h
@@ -39,5 +39,7 @@ void dap_chain_net_decree_purge(dap_chain_net_t *a_net);
 int dap_chain_net_decree_apply(dap_hash_fast_t *a_decree_hash, dap_chain_datum_decree_t * a_decree, dap_chain_t *a_chain);
 int dap_chain_net_decree_verify(dap_chain_net_t *a_net, dap_chain_datum_decree_t *a_decree, size_t a_data_size, dap_chain_hash_fast_t *a_decree_hash);
 int dap_chain_net_decree_load(dap_chain_datum_decree_t * a_decree, dap_chain_t *a_chain, dap_chain_hash_fast_t *a_decree_hash);
+int dap_chain_net_decree_reset_applied(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_decree_hash);
+
 
 dap_chain_datum_decree_t *dap_chain_net_decree_get_by_hash(dap_hash_fast_t *a_hash, bool *is_applied);
diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c
index 1b08433f5e70f07a7feb0a7edf6545b41de06a27..48365bb435d8f1e803857650f3fdaa6177b834d6 100644
--- a/modules/net/srv/dap_chain_net_srv.c
+++ b/modules/net/srv/dap_chain_net_srv.c
@@ -90,8 +90,8 @@ static int s_str_to_price_unit(const char *a_price_unit_str, dap_chain_net_srv_p
  */
 int dap_chain_net_srv_init()
 {
-    dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, s_pay_verificator_callback, NULL);
-    dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE, s_fee_verificator_callback, NULL);
+    dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY, s_pay_verificator_callback, NULL, NULL);
+    dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE, s_fee_verificator_callback, NULL, NULL);
 
     dap_cli_server_cmd_add ("net_srv", s_cli_net_srv, "Network services managment",
         "net_srv -net <net_name> order find [-direction {sell | buy}] [-srv_uid <service_UID>] [-price_unit <price_unit>]"
@@ -108,13 +108,6 @@ int dap_chain_net_srv_init()
         "net_srv get_limits -net <net_name> -srv_uid <Service_UID> -provider_pkey_hash <Service_provider_public_key_hash> -client_pkey_hash <Client_public_key_hash>\n"
         "net_srv report\n"
         "\tGet report about srv usage"
-#ifdef DAP_MODULES_DYNAMIC
-        "\tOrder create\n"
-            "net_srv -net <net_name> order static [save | delete]\n"
-            "\tStatic nodelist create/delete\n"
-            "net_srv -net <net_name> order recheck\n"
-            "\tCheck the availability of orders\n"
-#endif
         );
 
     s_load_all();
diff --git a/modules/service/stake/dap_chain_net_srv_stake_lock.c b/modules/service/stake/dap_chain_net_srv_stake_lock.c
index 71bca901ff808d3fc143445313443af895af4bda..47f2127497a39564490e96e82f2ac9e4919232f7 100644
--- a/modules/service/stake/dap_chain_net_srv_stake_lock.c
+++ b/modules/service/stake/dap_chain_net_srv_stake_lock.c
@@ -249,7 +249,7 @@ static bool s_tag_check_staking(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_
  */
 int dap_chain_net_srv_stake_lock_init()
 {
-    dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, s_stake_lock_callback_verificator, s_stake_lock_callback_updater);
+    dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_LOCK, s_stake_lock_callback_verificator, s_stake_lock_callback_updater, NULL);
     dap_cli_server_cmd_add("stake_lock", s_cli_stake_lock, "Stake lock service commands",
        "Command:"
                 "stake_lock hold\n"
diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
index e09ab6159f91eb2590ba1d82c817eacc2b36d0fe..6531e9f550dd2d0311dc98dbf878928aafe8bd9e 100644
--- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
+++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
@@ -52,7 +52,10 @@ static bool s_stake_verificator_callback(dap_ledger_t *a_ledger, dap_chain_tx_ou
                                                       dap_chain_datum_tx_t *a_tx_in, bool a_owner);
 static void s_stake_updater_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_cond);
 
+static void s_stake_deleted_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_cond);
+
 static void s_cache_data(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_addr_t *a_signing_addr);
+static void s_uncache_data(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_addr_t *a_signing_addr);
 
 static dap_list_t *s_srv_stake_list = NULL;
 
@@ -88,7 +91,7 @@ static bool s_tag_check_key_delegation(dap_ledger_t *a_ledger, dap_chain_datum_t
  */
 int dap_chain_net_srv_stake_pos_delegate_init()
 {
-    dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, s_stake_verificator_callback, s_stake_updater_callback);
+    dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_POS_DELEGATE, s_stake_verificator_callback, s_stake_updater_callback, s_stake_deleted_callback);
     dap_cli_server_cmd_add("srv_stake", s_cli_srv_stake, "Delegated stake service commands",
             "\t\t=== Commands for work with orders ===\n"
     "srv_stake order create [fee] -net <net_name> -value <value> -cert <priv_cert_name> [-H {hex(default) | base58}]\n"
@@ -291,6 +294,15 @@ static void s_stake_updater_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_
     s_cache_data(a_ledger, a_tx, l_signing_addr);
 }
 
+static void s_stake_deleted_callback(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_tx_out_cond_t *a_cond)
+{
+    if (!a_cond)
+        return;
+    dap_chain_addr_t *l_signing_addr = &a_cond->subtype.srv_stake_pos_delegate.signing_addr;
+    dap_chain_net_srv_stake_key_invalidate(l_signing_addr);
+    s_uncache_data(a_ledger, a_tx, l_signing_addr);
+}
+
 static bool s_srv_stake_is_poa_cert(dap_chain_net_t *a_net, dap_enc_key_t *a_key)
 {
     bool l_is_poa_cert = false;
@@ -2908,6 +2920,19 @@ static void s_cache_data(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap
         log_it(L_WARNING, "Stake service cache mismatch");
 }
 
+static void s_uncache_data(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_addr_t *a_signing_addr)
+{
+    if (!dap_ledger_cache_enabled(a_ledger))
+        return;
+    dap_chain_hash_fast_t l_hash = {};
+    dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_hash);
+    char l_data_key[DAP_CHAIN_HASH_FAST_STR_SIZE];
+    dap_chain_hash_fast_to_str(&l_hash, l_data_key, sizeof(l_data_key));
+    char *l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_GDB_GROUP);
+    if (dap_global_db_del_sync(l_gdb_group, l_data_key))
+        log_it(L_WARNING, "Stake service cache mismatch");
+}
+
 dap_chain_net_srv_stake_item_t *dap_chain_net_srv_stake_check_pkey_hash(dap_chain_net_id_t a_net_id, dap_hash_fast_t *a_pkey_hash)
 {
     dap_chain_net_srv_stake_t *l_srv_stake = s_srv_stake_by_net_id(a_net_id);
diff --git a/modules/service/voting/dap_chain_net_srv_voting.c b/modules/service/voting/dap_chain_net_srv_voting.c
index 5cff28c80877efea6e445d05a7b5ea28f99033ad..ffecdaf7cf139585cbbdf1fed9db023c86084722 100644
--- a/modules/service/voting/dap_chain_net_srv_voting.c
+++ b/modules/service/voting/dap_chain_net_srv_voting.c
@@ -95,6 +95,7 @@ static int s_datum_tx_voting_coin_check_cond_out(dap_chain_net_t *a_net, dap_has
 /// -1 error, 0 - unspent, 1 - spent
 static int s_datum_tx_voting_coin_check_spent(dap_chain_net_t *a_net, dap_hash_fast_t a_voting_hash, dap_hash_fast_t a_tx_prev_hash, int a_out_idx);
 static bool s_datum_tx_voting_verification_callback(dap_ledger_t *a_ledger, dap_chain_tx_item_type_t a_type, dap_chain_datum_tx_t *a_tx_in, 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);
 static int s_cli_voting(int argc, char **argv, void **a_str_reply);
 
 static bool s_tag_check_voting(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,  dap_chain_datum_tx_item_groups_t *a_items_grp, dap_chain_tx_tag_action_type_t *a_action)
@@ -117,7 +118,7 @@ static bool s_tag_check_voting(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_t
 int dap_chain_net_srv_voting_init()
 {
     pthread_rwlock_init(&s_votings_rwlock, NULL);
-    dap_chain_ledger_voting_verificator_add(s_datum_tx_voting_verification_callback);
+    dap_chain_ledger_voting_verificator_add(s_datum_tx_voting_verification_callback, s_datum_tx_voting_verification_delete_callback);
     dap_cli_server_cmd_add("voting", s_cli_voting, "Voting commands.", ""
                             "voting create -net <net_name> -question <\"Question_string\"> -options <\"Option0\", \"Option1\" ... \"OptionN\"> [-expire <voting_expire_time_in_RCF822>] [-max_votes_count <Votes_count>] [-delegated_key_required] [-vote_changing_allowed] -fee <value_datoshi> -w <fee_wallet_name>\n"
                             "voting vote -net <net_name> -hash <voting_hash> -option_idx <option_index> [-cert <delegate_cert_name>] -fee <value_datoshi> -w <fee_wallet_name>\n"
@@ -492,6 +493,76 @@ bool s_datum_tx_voting_verification_callback(dap_ledger_t *a_ledger, dap_chain_t
     return false;
 }
 
+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 l_hash = {};
+    dap_hash_fast(a_tx_in, dap_chain_datum_tx_get_size(a_tx_in), &l_hash);
+
+    if (a_type == TX_ITEM_TYPE_VOTING){
+        dap_chain_net_votings_t * l_voting = NULL;
+        pthread_rwlock_wrlock(&s_votings_rwlock);
+        HASH_FIND(hh, s_votings, &l_hash, sizeof(dap_hash_fast_t), l_voting);
+        if(!l_voting){
+            char* l_hash_str = dap_hash_fast_to_str_new(&l_hash);
+            log_it(L_ERROR, "Can't find voting with hash %s in net %s", l_hash_str, a_ledger->net->pub.name);
+            DAP_DEL_Z(l_hash_str);
+            pthread_rwlock_unlock(&s_votings_rwlock);
+            return false;
+        }
+        HASH_DEL(s_votings, l_voting);
+        pthread_rwlock_unlock(&s_votings_rwlock);
+
+        if (l_voting->voting_params.option_offsets_list)
+            dap_list_free_full(l_voting->voting_params.option_offsets_list, NULL);
+
+        if(l_voting->votes)
+            dap_list_free_full(l_voting->votes, NULL);
+
+        dap_chain_net_voting_cond_outs_t *l_el = NULL, *l_tmp = NULL;
+        if(l_voting->voting_spent_cond_outs && l_voting->voting_spent_cond_outs->hh.tbl->num_items){
+            HASH_ITER(hh, l_voting->voting_spent_cond_outs, l_el, l_tmp){
+                if (l_el){
+                    HASH_DEL(l_voting->voting_spent_cond_outs, l_el);
+                    DAP_DELETE(l_el);
+                }
+            }
+        }
+
+        DAP_DELETE(l_voting);
+
+        return true;
+    } else if (a_type == TX_ITEM_TYPE_VOTE){
+        dap_chain_tx_vote_t *l_vote_tx_item = (dap_chain_tx_vote_t *)dap_chain_datum_tx_item_get(a_tx_in, 0, TX_ITEM_TYPE_VOTE, NULL);
+        if(!l_vote_tx_item){
+            log_it(L_ERROR, "Can't find vote item");
+            return false;
+        }
+
+        dap_chain_net_votings_t * l_voting = NULL;
+        pthread_rwlock_wrlock(&s_votings_rwlock);
+        HASH_FIND(hh, s_votings, &l_vote_tx_item->voting_hash, sizeof(dap_hash_fast_t), l_voting);
+        pthread_rwlock_unlock(&s_votings_rwlock);
+        if(!l_voting || l_voting->net_id.uint64 != a_ledger->net->pub.id.uint64) {
+            char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_hash);
+            log_it(L_ERROR, "Can't find voting with hash %s in net %s", l_hash_str, a_ledger->net->pub.name);
+            DAP_DELETE(l_hash_str);
+            return false;
+        }
+
+        dap_list_t *l_vote = l_voting->votes;
+        while(l_vote){
+            if (dap_hash_fast_compare(&((dap_chain_net_vote_t *)l_vote->data)->vote_hash, &l_hash)){
+                // Delete vote
+                l_voting->votes = dap_list_remove(l_voting->votes, l_vote->data);
+                break;
+            }
+            l_vote = l_vote->next;
+        }
+    }
+
+    return true;
+}
+
 static dap_list_t* s_get_options_list_from_str(const char* a_str)
 {
     dap_list_t* l_ret = NULL;
diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c
index 4b6423062287fda667929c1351a82d331e246aa0..071532d299e54b1bc5df121e883d92cab7c7d771 100644
--- a/modules/service/xchange/dap_chain_net_srv_xchange.c
+++ b/modules/service/xchange/dap_chain_net_srv_xchange.c
@@ -143,7 +143,7 @@ static bool s_tag_check_xchange(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_
  */
 int dap_chain_net_srv_xchange_init()
 {
-    dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, s_xchange_verificator_callback, NULL);
+    dap_ledger_verificator_add(DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE, s_xchange_verificator_callback, NULL, NULL);
     dap_cli_server_cmd_add("srv_xchange", s_cli_srv_xchange, "eXchange service commands",
 
     "srv_xchange order create -net <net_name> -token_sell <token_ticker> -token_buy <token_ticker> -w <wallet_name>"
diff --git a/modules/type/blocks/CMakeLists.txt b/modules/type/blocks/CMakeLists.txt
index 32900e1ceca6f6b3b31c58ea195193eabb766f9b..3770f285fde25cf498200ae5b8af9f18757fcdd1 100644
--- a/modules/type/blocks/CMakeLists.txt
+++ b/modules/type/blocks/CMakeLists.txt
@@ -6,6 +6,10 @@ file(GLOB DAP_CHAIN_BLOCK_HEADERS include/*.h)
 
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_BLOCK_SRCS} ${DAP_CHAIN_BLOCK_HEADERS})
 
+if(BUILD_CELLFRAME_SDK_TESTS)
+    add_subdirectory(tests)
+endif()
+
 target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_cli_server dap_chain_net)
 target_include_directories(${PROJECT_NAME} INTERFACE .)
 target_include_directories(${PROJECT_NAME} PUBLIC include)
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 07b1d8375b5e63c17b30078213fb66a534dd41ae..931f8f326b3b0a397a1fd26a04e54f54e358adbd 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -60,6 +60,9 @@ typedef struct dap_chain_cs_blocks_pvt
     // All the blocks are here. In feature should be limited with 1000 when the rest would be loaded from file when needs them
     dap_chain_block_cache_t * blocks;
 
+    size_t forked_br_cnt;
+    dap_chain_block_forked_branch_t **forked_branches; // list of lists with atoms in side branches
+
     // Chunks treshold
     dap_chain_block_chunks_t * chunks;
     dap_chain_block_datum_index_t *datum_index; // To find datum in blocks
@@ -88,12 +91,14 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void **a_str_reply);
 // Setup BFT consensus and select the longest chunk
 static void s_bft_consensus_setup(dap_chain_cs_blocks_t * a_blocks);
 
+static bool s_chain_find_atom(dap_chain_block_cache_t* a_blocks, dap_chain_hash_fast_t* a_atom_hash);
+
 // Callbacks
 static void s_callback_delete(dap_chain_t * a_chain);
 // Accept new block
-static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t);
+static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t * a_atom_hash);
 //    Verify new block
-static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t);
+static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t * a_atom_hash);
 
 //    Get block header size
 static size_t s_callback_atom_get_static_hdr_size(void);
@@ -1415,6 +1420,35 @@ static int s_add_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_ca
 }
 
 
+static int s_delete_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_cache_t *a_block_cache)
+{
+    if (! a_block_cache->datum_count){
+        log_it(L_WARNING,"Block %s has no datums at all, can't remove anything from ledger", a_block_cache->block_hash_str);
+        return 1; // No errors just empty block
+    }
+    int l_ret = 0;
+
+    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){
+        dap_hash_fast_t *l_datum_hash = a_block_cache->datum_hash + i;
+        dap_chain_datum_t *l_datum = a_block_cache->datum[i];
+        int l_res = dap_chain_datum_remove(a_blocks->chain, l_datum, l_datum_size, l_datum_hash);
+        l_ret++;
+
+        pthread_rwlock_wrlock(&PVT(a_blocks)->datums_rwlock);
+        dap_chain_block_datum_index_t *l_datum_index = NULL;
+        HASH_FIND(hh, PVT(a_blocks)->datum_index, l_datum_hash, sizeof(dap_hash_fast_t), l_datum_index);
+        if (l_datum_index)
+            HASH_DEL(PVT(a_blocks)->datum_index, l_datum_index);
+        pthread_rwlock_unlock(&PVT(a_blocks)->datums_rwlock);
+    }
+    debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str,
+             l_ret == (int)a_block_cache->datum_count ? "all correct" : "there are rejected datums");
+    return l_ret;
+}
+
 /**
  * @brief s_add_atom_to_blocks
  * @param a_blocks
@@ -1495,6 +1529,69 @@ static void s_bft_consensus_setup(dap_chain_cs_blocks_t * a_blocks)
     }
 }
 
+static void s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_block_cache_t * a_bcache, uint64_t current_block_idx, dap_chain_cell_t *a_cell)
+{
+    dap_chain_cs_blocks_t * l_blocks = a_blocks;
+    if (!a_blocks){
+        log_it(L_ERROR,"a_blocks is NULL");
+        return;
+    }
+
+    if (!a_bcache){
+        log_it(L_ERROR,"a_bcache is NULL");
+        return;
+    }
+
+    if (!a_bcache->forked_branches){
+        log_it(L_ERROR,"This block is not a forked.");
+        return;
+    }
+
+    // Find longest forked branch 
+    dap_list_t *l_branch = a_bcache->forked_branches;
+    dap_chain_block_forked_branch_t *l_longest_branch_cache_ptr = l_branch ? (dap_chain_block_forked_branch_t*)l_branch->data : NULL;
+    uint64_t l_longest_branch_length = current_block_idx;
+    while (l_branch){
+        uint64_t l_branch_length = dap_list_length(((dap_chain_block_forked_branch_t*)l_branch->data)->forked_branch_atoms);
+        if (l_branch_length > l_longest_branch_length){
+            l_longest_branch_length = l_branch_length;
+            l_longest_branch_cache_ptr = (dap_chain_block_forked_branch_t*)l_branch->data;
+        }
+        l_branch = l_branch->next;
+    }
+
+    if (current_block_idx < l_longest_branch_length){
+        // Switch branches
+        dap_list_t *l_new_forked_branch = NULL;
+        // First we must to remove all blocks from main branch to forked 
+        // branch and delete all datums in this atoms from storages
+        dap_chain_block_cache_t *l_atom = (dap_chain_block_cache_t *)a_bcache->hh.tbl->tail->prev, 
+                                *l_tmp = (dap_chain_block_cache_t *)a_bcache;
+        unsigned l_curr_index;
+        for (l_atom = l_atom->hh.next, l_curr_index = 0; 
+            current_block_idx > l_curr_index; l_atom = l_atom->hh.prev, l_curr_index++){
+                l_new_forked_branch = dap_list_prepend(l_new_forked_branch, l_atom);
+                HASH_DEL(a_bcache, l_atom);
+                --PVT(l_blocks)->blocks_count;
+                s_delete_atom_datums(l_blocks, l_atom);
+            }
+
+        // Next we add all atoms into HT and their datums into storages
+        dap_list_t * new_main_branch = l_longest_branch_cache_ptr->forked_branch_atoms;
+        while(new_main_branch){
+            dap_chain_block_cache_t *l_curr_atom = (dap_chain_block_cache_t *)(new_main_branch->data);
+            ++PVT(l_blocks)->blocks_count;
+            HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_curr_atom->block_hash), l_curr_atom);
+            debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", l_curr_atom);
+            s_add_atom_datums(l_blocks, l_curr_atom);
+            dap_chain_atom_notify(a_cell, &l_curr_atom->block_hash, (byte_t*)l_curr_atom->block, l_curr_atom->block_size);
+            new_main_branch = new_main_branch->next;
+        }
+        dap_list_free(l_longest_branch_cache_ptr->forked_branch_atoms);
+        l_longest_branch_cache_ptr->forked_branch_atoms = l_new_forked_branch;
+    }
+}
+
 /**
  * @brief s_callback_atom_add
  * @details Accept new atom in blockchain
@@ -1503,26 +1600,23 @@ static void s_bft_consensus_setup(dap_chain_cs_blocks_t * a_blocks)
  * @param a_atom_size
  * @return
  */
-static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom , size_t a_atom_size)
+static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom , size_t a_atom_size, dap_hash_fast_t *a_atom_hash)
 {
     dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
     dap_chain_block_t * l_block = (dap_chain_block_t *) a_atom;
 
-    dap_chain_hash_fast_t l_block_hash;
-    dap_hash_fast(l_block, a_atom_size, &l_block_hash);
+    dap_chain_hash_fast_t l_block_hash = *a_atom_hash;
 
     dap_chain_block_cache_t * l_block_cache = NULL;
-    pthread_rwlock_wrlock(& PVT(l_blocks)->rwlock);
-    HASH_FIND(hh, PVT(l_blocks)->blocks, &l_block_hash, sizeof(l_block_hash), l_block_cache);
-    if (l_block_cache) {
-        debug_if(s_debug_more, L_DEBUG, "... %s is already present", l_block_cache->block_hash_str);
-        pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
-        return ATOM_PASS;
-    }
-    dap_chain_atom_verify_res_t ret = s_callback_atom_verify(a_chain, a_atom, a_atom_size);
+
+    dap_chain_atom_verify_res_t ret = s_callback_atom_verify(a_chain, a_atom, a_atom_size, &l_block_hash);
+    dap_hash_t *l_prev_hash_meta_data = (dap_hash_t *)dap_chain_block_meta_get(l_block, a_atom_size, DAP_CHAIN_BLOCK_META_PREV);
+    dap_hash_t l_block_prev_hash = l_prev_hash_meta_data ? *l_prev_hash_meta_data : (dap_hash_t){};
+
     switch (ret) {
-    case ATOM_ACCEPT: {
+    case ATOM_ACCEPT:{
         dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_chain, l_block->hdr.cell_id);
+#ifndef DAP_CHAIN_BLOCKS_TEST
         if ( !dap_chain_net_get_load_mode( dap_chain_net_by_id(a_chain->net_id)) ) {
             if ( (ret = dap_chain_atom_save(l_cell, a_atom, a_atom_size, &l_block_hash)) < 0 ) {
                 log_it(L_ERROR, "Can't save atom to file, code %d", ret);
@@ -1533,22 +1627,66 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
                 l_cell->map_pos += a_atom_size;
             }
             ret = ATOM_PASS;
-        }         
-        if ( !(l_block_cache = dap_chain_block_cache_new(&l_block_hash, l_block, a_atom_size,
-                                                         PVT(l_blocks)->blocks_count + 1, !a_chain->is_mapped)) )
-        {
-            log_it(L_DEBUG, "... corrupted block");
+        }
+#endif
+        l_block_cache = dap_chain_block_cache_new(&l_block_hash, l_block, a_atom_size, PVT(l_blocks)->blocks_count + 1, !a_chain->is_mapped);
+        if (!l_block_cache) {
+            log_it(L_DEBUG, "%s", "... corrupted block");
             pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
             return ATOM_REJECT;
         }
         debug_if(s_debug_more, L_DEBUG, "... new block %s", l_block_cache->block_hash_str);
-        HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_block_cache->block_hash), l_block_cache);
-        ++PVT(l_blocks)->blocks_count;
-        debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", a_atom);
-        s_add_atom_datums(l_blocks, l_block_cache);
-        dap_chain_atom_notify(l_cell, &l_block_cache->block_hash, (byte_t*)l_block, a_atom_size);
-        dap_chain_atom_add_from_threshold(a_chain);
-        break;
+
+        dap_chain_block_cache_t * l_prev_bcache = NULL, *l_tmp = NULL;
+        uint64_t l_current_item_index = 0;
+        dap_chain_cs_blocks_pvt_t *l_block_pvt = PVT(l_blocks);
+        pthread_rwlock_wrlock(& PVT(l_blocks)->rwlock);
+        l_prev_bcache = l_block_pvt->blocks ? l_block_pvt->blocks->hh.tbl->tail->prev : NULL;
+        if (l_prev_bcache){
+            for (l_prev_bcache = l_prev_bcache->hh.next; 
+                l_prev_bcache && l_current_item_index < DAP_FORK_MAX_DEPTH; 
+                l_current_item_index++, l_prev_bcache = l_prev_bcache->hh.prev){
+                if (l_prev_bcache && dap_hash_fast_compare(&l_prev_bcache->block_hash, &l_block_prev_hash)){
+                    ++PVT(l_blocks)->blocks_count;
+                    HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_block_cache->block_hash), l_block_cache);
+                    debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", a_atom);
+                    s_add_atom_datums(l_blocks, l_block_cache);
+                    dap_chain_atom_notify(l_cell, &l_block_cache->block_hash, (byte_t*)l_block, a_atom_size);
+                    dap_chain_atom_add_from_threshold(a_chain);
+                    pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
+                    return ATOM_ACCEPT;
+                }
+
+                if(l_prev_bcache && l_prev_bcache->forked_branches){
+                    // Check forked branches
+                    dap_list_t * l_forked_branches = l_prev_bcache->forked_branches;
+                    while(l_forked_branches){
+                        dap_chain_block_forked_branch_t *l_cur_branch_cache = (dap_chain_block_forked_branch_t*)l_forked_branches->data;
+                        dap_chain_block_cache_t * l_branch_last_bcache = (dap_chain_block_cache_t *)(dap_list_last(l_cur_branch_cache->forked_branch_atoms))->data;
+                        if(dap_hash_fast_compare(&l_branch_last_bcache->block_hash, &l_block_prev_hash)){
+                            l_cur_branch_cache->forked_branch_atoms = dap_list_append(l_cur_branch_cache->forked_branch_atoms, l_block_cache);
+                            s_select_longest_branch(l_blocks, l_prev_bcache, l_current_item_index, l_cell);
+                            pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
+                            debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED to a forked branch.", a_atom);
+                            return ATOM_FORK;
+                        }
+                        l_forked_branches = l_forked_branches->next;
+                    }
+                }
+            }
+        } else {
+            HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_block_cache->block_hash), l_block_cache);
+            ++PVT(l_blocks)->blocks_count;
+            pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
+            debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", a_atom);
+            s_add_atom_datums(l_blocks, l_block_cache);
+            dap_chain_atom_notify(l_cell, &l_block_cache->block_hash, (byte_t*)l_block, a_atom_size);
+            dap_chain_atom_add_from_threshold(a_chain);
+            return ret;
+        }
+        pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
+        debug_if(s_debug_more, L_DEBUG, "Verified atom %p: REJECTED", a_atom);
+        return ATOM_REJECT;
     }
     case ATOM_MOVE_TO_THRESHOLD:
         // TODO: reimplement and enable threshold for blocks
@@ -1561,6 +1699,52 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
     case ATOM_REJECT:
         debug_if(s_debug_more, L_DEBUG, "Verified atom %p: REJECTED", a_atom);
         break;
+    case ATOM_FORK:{
+        dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_chain, l_block->hdr.cell_id);
+#ifndef DAP_CHAIN_BLOCKS_TEST
+        if ( !dap_chain_net_get_load_mode( dap_chain_net_by_id(a_chain->net_id)) ) {
+            if ( (ret = dap_chain_atom_save(l_cell, a_atom, a_atom_size, &l_block_hash)) < 0 ) {
+                log_it(L_ERROR, "Can't save atom to file, code %d", ret);
+                pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
+                return ATOM_REJECT;
+            } else if (a_chain->is_mapped) {
+                l_block = (dap_chain_block_t*)( l_cell->map_pos += sizeof(uint64_t) );  // Switching to mapped area
+                l_cell->map_pos += a_atom_size;
+            }
+            ret = ATOM_PASS;
+        }
+#endif
+        l_block_cache = dap_chain_block_cache_new(&l_block_hash, l_block, a_atom_size, PVT(l_blocks)->blocks_count + 1, !a_chain->is_mapped);
+        if (!l_block_cache) {
+            log_it(L_DEBUG, "%s", "... corrupted block");
+            pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
+            return ATOM_REJECT;
+        }
+        debug_if(s_debug_more, L_DEBUG, "... new block %s", l_block_cache->block_hash_str);
+        dap_chain_block_cache_t *l_prev_bcache = NULL, *l_tmp = NULL;
+        pthread_rwlock_wrlock(& PVT(l_blocks)->rwlock);
+        HASH_FIND(hh, PVT(l_blocks)->blocks, &l_block_prev_hash, sizeof(dap_hash_fast_t), l_prev_bcache);
+        if (l_prev_bcache && dap_hash_fast_compare(&l_prev_bcache->block_hash, &l_block_prev_hash)){
+            // make forked branch list
+            dap_chain_block_forked_branch_t *forked_branch_cache = DAP_NEW_Z(dap_chain_block_forked_branch_t);
+            dap_list_t *forked_branch = NULL;
+            forked_branch = dap_list_append(forked_branch, l_block_cache);
+            forked_branch_cache->connected_block = l_prev_bcache;
+            forked_branch_cache->forked_branch_atoms = forked_branch;
+            PVT(l_blocks)->forked_br_cnt++;
+            PVT(l_blocks)->forked_branches = DAP_REALLOC_COUNT(PVT(l_blocks)->forked_branches, PVT(l_blocks)->forked_br_cnt);
+            PVT(l_blocks)->forked_branches[PVT(l_blocks)->forked_br_cnt-1] = forked_branch_cache;
+            l_prev_bcache->forked_branches = dap_list_append(l_prev_bcache->forked_branches, PVT(l_blocks)->forked_branches[PVT(l_blocks)->forked_br_cnt-1]);
+            pthread_rwlock_unlock(& PVT(l_blocks)->rwlock);
+            debug_if(s_debug_more, L_DEBUG, "Fork is made successfuly.");
+            return ATOM_FORK;
+        }
+        pthread_rwlock_unlock(& PVT(l_blocks)->rwlock);
+        return ATOM_REJECT;
+    }
+    case ATOM_PASS:
+        debug_if(s_debug_more, L_DEBUG, "... %s is already present", l_block_cache->block_hash_str);
+        return ATOM_REJECT;
     default:
         debug_if(s_debug_more, L_DEBUG, "Unknown verification ret code %d", ret);
         break;
@@ -1576,14 +1760,14 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
  * @param a_atom_size
  * @return
  */
-static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom , size_t a_atom_size)
+static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom , size_t a_atom_size, dap_chain_hash_fast_t * a_atom_hash)
 {
     dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
     assert(l_blocks);
     dap_chain_cs_blocks_pvt_t * l_blocks_pvt = PVT(l_blocks);
     assert(l_blocks_pvt);
     dap_chain_block_t * l_block = (dap_chain_block_t *) a_atom;
-    dap_chain_hash_fast_t l_block_hash;
+    dap_chain_hash_fast_t l_block_hash = *a_atom_hash;
 
     if(sizeof (l_block->hdr) >= a_atom_size){
         log_it(L_WARNING,"Size of block is %zd that is equal or less then block's header size %zd",a_atom_size,sizeof (l_block->hdr));
@@ -1592,7 +1776,6 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain,
 
     // Hard accept list
     if (l_blocks_pvt->hal) {
-        dap_hash_fast(l_block, a_atom_size, &l_block_hash);
         struct cs_blocks_hal_item *l_hash_found = NULL;
         HASH_FIND(hh, l_blocks_pvt->hal, &l_block_hash, sizeof(l_block_hash), l_hash_found);
         if (l_hash_found) {
@@ -1605,25 +1788,25 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain,
         return  ATOM_REJECT;
     }
 
-    // Parse metadata
-    bool l_is_genesis = dap_chain_block_meta_get(l_block, a_atom_size, DAP_CHAIN_BLOCK_META_GENESIS);
-    dap_hash_t *l_prev_hash_meta_data = (dap_hash_t *)dap_chain_block_meta_get(l_block, a_atom_size, DAP_CHAIN_BLOCK_META_PREV);
-    dap_hash_t l_block_prev_hash = l_prev_hash_meta_data ? *l_prev_hash_meta_data : (dap_hash_t){};
-
     // 2nd level consensus
     if(l_blocks->callback_block_verify)
         if (l_blocks->callback_block_verify(l_blocks, l_block, a_atom_size))
             return ATOM_REJECT;
 
+// Parse metadata
+    bool l_is_genesis = dap_chain_block_meta_get(l_block, a_atom_size, DAP_CHAIN_BLOCK_META_GENESIS);
+    dap_hash_t *l_prev_hash_meta_data = (dap_hash_t *)dap_chain_block_meta_get(l_block, a_atom_size, DAP_CHAIN_BLOCK_META_PREV);
+    dap_hash_t l_block_prev_hash = l_prev_hash_meta_data ? *l_prev_hash_meta_data : (dap_hash_t){};
+
     // genesis or seed mode
     if (l_is_genesis) {
-        if (!l_blocks_pvt->blocks) {
-            dap_hash_fast(l_block, a_atom_size, &l_block_hash);
+        if (!PVT(l_blocks)->blocks) {
+#ifndef DAP_CHAIN_BLOCKS_TEST
             if (s_seed_mode)
                 log_it(L_NOTICE, "Accepting new genesis block");
 
-            else if(dap_hash_fast_compare(&l_block_hash,&l_blocks_pvt->static_genesis_block_hash)
-                    &&!dap_hash_fast_is_blank(&l_block_hash))
+            else if(dap_hash_fast_compare(&l_block_hash,&PVT(l_blocks)->static_genesis_block_hash)
+                    && !dap_hash_fast_is_blank(&l_block_hash))
                 log_it(L_NOTICE, "Accepting static genesis block");
             else{
                 char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE] = { '\0' };
@@ -1631,6 +1814,9 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain,
                 log_it(L_WARNING,"Cant accept genesis block: seed mode not enabled or hash mismatch with static genesis block %s in configuration", l_hash_str);
                 return ATOM_REJECT;
             }
+#else
+        PVT(l_blocks)->genesis_block_hash = *a_atom_hash;
+#endif
         } else {
             log_it(L_WARNING,"Cant accept genesis block: already present data in blockchain");
             return ATOM_REJECT;
@@ -1638,9 +1824,41 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain,
     } else {
         dap_chain_block_cache_t *l_bcache_last = PVT(l_blocks)->blocks ? PVT(l_blocks)->blocks->hh.tbl->tail->prev : NULL;
         l_bcache_last = l_bcache_last ? l_bcache_last->hh.next : PVT(l_blocks)->blocks;
-        if (!l_bcache_last || !dap_hash_fast_compare(&l_bcache_last->block_hash, &l_block_prev_hash))
-            return ATOM_MOVE_TO_THRESHOLD;
+
+        if (l_bcache_last && dap_hash_fast_compare(&l_bcache_last->block_hash, &l_block_prev_hash))
+            return ATOM_ACCEPT;
+
+        dap_chain_block_cache_t *l_prev_bcache = NULL, *l_tmp = NULL;
+        pthread_rwlock_rdlock(& PVT(l_blocks)->rwlock);
+        HASH_ITER(hh, PVT(l_blocks)->blocks, l_prev_bcache, l_tmp){
+            if(l_prev_bcache && dap_hash_fast_compare(&l_prev_bcache->block_hash, a_atom_hash)){
+                pthread_rwlock_unlock(& PVT(l_blocks)->rwlock);
+                return ATOM_PASS;
+            }
+
+            if (l_prev_bcache && dap_hash_fast_compare(&l_prev_bcache->block_hash, &l_block_prev_hash)){
+                pthread_rwlock_unlock(& PVT(l_blocks)->rwlock);
+                return ATOM_FORK;
+            }
+
+            if(l_prev_bcache && l_prev_bcache->forked_branches){
+                // Check forked branches
+                dap_list_t * l_forked_branches = l_prev_bcache->forked_branches;
+                while(l_forked_branches){
+                    dap_list_t *forked_branch = ((dap_chain_block_forked_branch_t *)l_forked_branches->data)->forked_branch_atoms;                    
+                    dap_chain_block_cache_t *l_forked_branch_last_block = (dap_chain_block_cache_t *)(dap_list_last(forked_branch)->data);
+                    if(l_forked_branch_last_block && dap_hash_fast_compare(&l_forked_branch_last_block->block_hash, &l_block_prev_hash)){
+                        pthread_rwlock_unlock(& PVT(l_blocks)->rwlock);
+                        return ATOM_ACCEPT;
+                    }
+                    l_forked_branches = l_forked_branches->next;
+                }
+            }
+        }
+        pthread_rwlock_unlock(& PVT(l_blocks)->rwlock);
+        return ATOM_MOVE_TO_THRESHOLD;
     }
+
     return ATOM_ACCEPT;
 }
 
@@ -1789,6 +2007,7 @@ static dap_chain_atom_ptr_t s_callback_atom_iter_get(dap_chain_atom_iter_t *a_at
     dap_return_val_if_fail(a_atom_iter, NULL);
     dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS(a_atom_iter->chain);
     dap_chain_cs_blocks_pvt_t *l_blocks_pvt = l_blocks ? PVT(l_blocks) : NULL;
+    dap_chain_atom_ptr_t l_ret = NULL;
     assert(l_blocks_pvt);
     pthread_rwlock_rdlock(&l_blocks_pvt->rwlock);
     switch (a_operation) {
@@ -1813,7 +2032,7 @@ static dap_chain_atom_ptr_t s_callback_atom_iter_get(dap_chain_atom_iter_t *a_at
         a_atom_iter->cur_size   = l_item->block_size;
         a_atom_iter->cur_hash   = &l_item->block_hash;
         a_atom_iter->cur_num    = l_item->block_number;
-    } else
+    } else 
         *a_atom_iter = (dap_chain_atom_iter_t) { .chain = a_atom_iter->chain,
                                                  .cell_id = a_atom_iter->cell_id };
     pthread_rwlock_unlock(&l_blocks_pvt->rwlock);
diff --git a/modules/type/blocks/include/dap_chain_block_cache.h b/modules/type/blocks/include/dap_chain_block_cache.h
index d69e2e652778d4a44dbc6576d31106ba6bdbd6ba..27dfe470955c5a810400118a42885c55c646b4ca 100644
--- a/modules/type/blocks/include/dap_chain_block_cache.h
+++ b/modules/type/blocks/include/dap_chain_block_cache.h
@@ -60,6 +60,9 @@ typedef struct dap_chain_block_cache {
     // Pointer to block itself
     dap_chain_block_t * block;
 
+    // List for keeping pointers to list of atoms in side branches
+    dap_list_t *forked_branches;
+
     // Links to prev and next block
     struct dap_chain_block_cache * prev;
     struct dap_chain_block_cache * next;
@@ -68,6 +71,12 @@ typedef struct dap_chain_block_cache {
     UT_hash_handle hh;
 } dap_chain_block_cache_t;
 
+
+typedef struct dap_chain_block_forked_branch {
+    dap_chain_block_cache_t *connected_block; // pointer to a block connected with this forked branch
+    dap_list_t *forked_branch_atoms;
+} dap_chain_block_forked_branch_t;
+
 int dap_chain_block_cache_init();
 void dap_chain_block_cache_deinit();
 
@@ -79,6 +88,6 @@ int dap_chain_block_cache_update(dap_chain_block_cache_t *a_block_cache, dap_has
 void dap_chain_block_cache_delete(dap_chain_block_cache_t *a_block_cache);
 
 // Get the list of 'out_cond' items from previous transactions with summary out value. Put this summary value to a_value_out
-dap_list_t * dap_chain_block_get_list_tx_cond_outs_with_val(dap_ledger_t *a_ledger,dap_chain_block_cache_t * a_block_cache,uint256_t *a_value_out);
+dap_list_t * dap_chain_block_get_list_tx_cond_outs_with_val(dap_ledger_t *a_ledger, dap_chain_block_cache_t * a_block_cache, uint256_t *a_value_out);
 
 
diff --git a/modules/type/blocks/include/dap_chain_cs_blocks.h b/modules/type/blocks/include/dap_chain_cs_blocks.h
index 2c2e7de3952fbd60505ca000a57a708bbc44d3cc..bb40da5a247e6a4fbb0adf662dd5650a6deaf976 100644
--- a/modules/type/blocks/include/dap_chain_cs_blocks.h
+++ b/modules/type/blocks/include/dap_chain_cs_blocks.h
@@ -32,6 +32,8 @@
 #define DAP_CHAIN_CS_BLOCKS_MAX_BLOCK_SIZE (256 * 1024) // 256 KB
 #endif
 
+#define DAP_FORK_MAX_DEPTH 100
+
 #define DAP_REWARD_INIT_TIMESTAMP 1700870400UL // 25 Nov 2023 00:00:00 GMT
 
 typedef struct dap_chain_cs_blocks dap_chain_cs_blocks_t;
diff --git a/modules/type/blocks/tests/CMakeLists.txt b/modules/type/blocks/tests/CMakeLists.txt
new file mode 100755
index 0000000000000000000000000000000000000000..fe565847877a0886ef0f82c49241269a20af7376
--- /dev/null
+++ b/modules/type/blocks/tests/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(blocks-test)
+
+file(GLOB DAP_CHAIN_TESTS_HEADERS include/*.h)
+file(GLOB DAP_CHAIN_TESTS_SRC *.c)
+
+add_executable(${PROJECT_NAME} ${DAP_CHAIN_TESTS_SRC} ${DAP_CHAIN_TESTS_HEADERS})
+
+target_link_libraries(${PROJECT_NAME} dap_test dap_core dap_chain dap_chain_cs_blocks )
+
+if (DARWIN)
+    target_link_libraries(${PROJECT_NAME} bz2)
+endif()
+
+target_include_directories(${PROJECT_NAME} PUBLIC include)
+
+add_test(
+    NAME blocks-test
+    COMMAND blocks-test
+)
diff --git a/modules/type/blocks/tests/dap_chain_blocks_test.c b/modules/type/blocks/tests/dap_chain_blocks_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..15c84870405a35e8f2e80f8f7fdda696e8c76f4e
--- /dev/null
+++ b/modules/type/blocks/tests/dap_chain_blocks_test.c
@@ -0,0 +1,152 @@
+#include "dap_test.h"
+#include "dap_config.h"
+#include "dap_chain_net.h"
+#include "dap_chain_common.h"
+#include "dap_chain_block.h"
+#include "dap_chain_cs_blocks.h"
+#include "dap_chain_cs_esbocs.h"
+#include "dap_chain_cs.h"
+// #include "dap_chain_cs_blocks.h"
+
+dap_hash_fast_t dap_chain_block_test_add_new_block (dap_hash_fast_t *a_prev_block_hash, dap_chain_t *a_chain)
+{
+    size_t l_block_size = 0;
+    dap_hash_fast_t l_block_hash = {};
+    dap_chain_block_t * l_block = dap_chain_block_new(a_prev_block_hash, &l_block_size);
+    dap_assert_PIF(l_block != NULL, "Creating of block:");
+    dap_hash_fast(l_block, l_block_size, &l_block_hash);
+    // dap_test_msg("Created genesis block %s", dap_chain_hash_fast_to_str_static(&l_block_hash));
+    dap_chain_atom_verify_res_t ret_val = a_chain->callback_atom_add(a_chain, (dap_chain_atom_ptr_t)l_block, l_block_size, &l_block_hash);
+    dap_assert_PIF( (ret_val == ATOM_ACCEPT || ret_val == ATOM_FORK), "Adding of block: ");
+
+    return l_block_hash;
+}
+
+bool dap_chain_block_test_compare_chain_hash_lists(dap_chain_t* a_chain, dap_list_t* a_atoms_hash_list)
+{
+    dap_chain_cell_id_t l_cell_id = {.uint64 = 1};
+    size_t l_atom_size_from_iter = 0;
+    dap_chain_atom_iter_t *l_iter = a_chain->callback_atom_iter_create(a_chain, l_cell_id, NULL);
+    dap_list_t *l_branch_temp = NULL;
+    dap_chain_atom_ptr_t l_atom = a_chain->callback_atom_iter_get(l_iter, DAP_CHAIN_ITER_OP_FIRST, &l_atom_size_from_iter);
+    for (dap_list_t *l_branch_temp = a_atoms_hash_list; l_branch_temp && l_atom; 
+        l_branch_temp = l_branch_temp->next, l_atom = a_chain->callback_atom_iter_get(l_iter, DAP_CHAIN_ITER_OP_NEXT, &l_atom_size_from_iter)){
+        dap_test_msg("Check block %s and %s", dap_chain_hash_fast_to_str_static(l_iter->cur_hash), 
+                                            dap_chain_hash_fast_to_str_static((dap_hash_fast_t*)l_branch_temp->data));
+        if (!dap_hash_fast_compare(l_iter->cur_hash, (dap_hash_fast_t*)l_branch_temp->data)){
+            a_chain->callback_atom_iter_delete(l_iter);
+            return false;
+        }
+
+    }
+    a_chain->callback_atom_iter_delete(l_iter);
+    return true;
+}
+
+void dap_chain_blocks_test()
+{
+    dap_test_msg("Start of cs block testing...");
+    dap_assert_PIF(dap_chain_cs_blocks_init() == 0, "Initialization of dap consensus block: ");
+
+    dap_assert_PIF(dap_chain_cs_esbocs_init() == 0, "Initialization of esbocs: ");
+
+    const char *l_chain_net_name = "testnet";
+    const char *l_chain_name = "testchain";
+    dap_chain_net_id_t l_chain_net_id = {.uint64 = 1}; 
+    dap_chain_id_t l_chain_id = {.uint64 = 1};
+
+    dap_chain_t *l_chain =  dap_chain_create(l_chain_net_name, l_chain_name, l_chain_net_id, l_chain_id);
+    dap_config_t l_cfg = {};
+    dap_assert_PIF(dap_chain_cs_create(l_chain, &l_cfg) == 0, "Chain cs creating: ");
+
+    dap_hash_fast_t l_forked_block_hash = {};
+    dap_hash_fast_t l_block_hash = {};
+    dap_list_t *l_first_branch_atoms_list = NULL;
+    dap_list_t *l_second_branch_atoms_list = NULL;
+    dap_list_t *l_third_branch_atoms_list = NULL;
+
+    dap_test_msg("Add genesis block...");
+    l_block_hash = dap_chain_block_test_add_new_block (NULL, l_chain);
+    dap_hash_fast_t *l_block_hash_copy = DAP_DUP(&l_block_hash);
+    l_first_branch_atoms_list = dap_list_append(l_first_branch_atoms_list, l_block_hash_copy);
+    l_second_branch_atoms_list = dap_list_append(l_second_branch_atoms_list, l_block_hash_copy);
+    l_third_branch_atoms_list = dap_list_append(l_third_branch_atoms_list, l_block_hash_copy);
+
+    dap_test_msg("Add second block...");
+    l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain);
+    l_block_hash_copy = DAP_DUP(&l_block_hash);
+    l_first_branch_atoms_list = dap_list_append(l_first_branch_atoms_list, l_block_hash_copy);
+    l_second_branch_atoms_list = dap_list_append(l_second_branch_atoms_list, l_block_hash_copy);
+    l_third_branch_atoms_list = dap_list_append(l_third_branch_atoms_list, l_block_hash_copy);
+    l_forked_block_hash = l_block_hash;
+
+    dap_test_msg("Add 2 blocks to main branch...");
+    for (int i = 0; i < 2; i++){
+        l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain);
+        l_block_hash_copy = DAP_DUP(&l_block_hash);
+        l_first_branch_atoms_list = dap_list_append(l_first_branch_atoms_list, l_block_hash_copy);
+    }
+    
+    dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_first_branch_atoms_list), "Check chain after atoms adding to the main branch ");
+
+    /* ========================== Forked branches testing ======================= */
+    /* ========================== Add first forked branch ======================= */
+    dap_test_msg("Add forked branch...");
+    l_block_hash = dap_chain_block_test_add_new_block (&l_forked_block_hash, l_chain);
+    l_block_hash_copy = DAP_DUP(&l_block_hash);
+    l_second_branch_atoms_list = dap_list_append(l_second_branch_atoms_list, l_block_hash_copy);
+
+    dap_test_msg("Add another atom to the forked branch...");
+    l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain);
+    l_block_hash_copy = DAP_DUP(&l_block_hash);
+    l_second_branch_atoms_list = dap_list_append(l_second_branch_atoms_list, l_block_hash_copy);
+
+    dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_first_branch_atoms_list), "Check branches is not switched: ");
+
+    dap_test_msg("Add third atom to the forked branch...");
+    l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain);
+    l_block_hash_copy = DAP_DUP(&l_block_hash);
+    l_second_branch_atoms_list = dap_list_append(l_second_branch_atoms_list, l_block_hash_copy);
+
+    dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_second_branch_atoms_list), "Check branches is switched: ");
+
+    dap_test_msg("Add block to former main branch");
+    l_block_hash = dap_chain_block_test_add_new_block ((dap_hash_fast_t*)dap_list_last(l_first_branch_atoms_list)->data, l_chain);
+    l_block_hash_copy = DAP_DUP(&l_block_hash);
+    l_first_branch_atoms_list = dap_list_append(l_first_branch_atoms_list, l_block_hash_copy);
+
+    dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_second_branch_atoms_list), "Check branches is not switched: ");
+
+
+    dap_test_msg("Add another block to former main branch");
+    l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain);
+    l_block_hash_copy = DAP_DUP(&l_block_hash);
+    l_first_branch_atoms_list = dap_list_append(l_first_branch_atoms_list, l_block_hash_copy);
+
+    dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_first_branch_atoms_list), "Check branches is switched: ");
+
+
+    /* ========================== Add second forked branch ======================= */
+    dap_test_msg("Add atom to second forked branch...");
+    l_block_hash = dap_chain_block_test_add_new_block (&l_forked_block_hash, l_chain);
+    l_block_hash_copy = DAP_DUP(&l_block_hash);
+    l_third_branch_atoms_list = dap_list_append(l_third_branch_atoms_list, l_block_hash_copy);
+
+    for (int i = 0; i < 3; i++){
+        dap_test_msg("Add atom to second forked branch...");
+        l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain);
+        l_block_hash_copy = DAP_DUP(&l_block_hash);
+        l_third_branch_atoms_list = dap_list_append(l_third_branch_atoms_list, l_block_hash_copy);
+    }
+
+    dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_first_branch_atoms_list), "Check branches is not switched: ");
+
+    dap_test_msg("Add 5th atom to second forked branch...");
+    l_block_hash = dap_chain_block_test_add_new_block (&l_block_hash, l_chain);
+    l_block_hash_copy = DAP_DUP(&l_block_hash);
+    l_third_branch_atoms_list = dap_list_append(l_third_branch_atoms_list, l_block_hash_copy);
+
+    dap_assert_PIF(dap_chain_block_test_compare_chain_hash_lists(l_chain, l_third_branch_atoms_list), "Check branches is switched: ");
+
+    dap_pass_msg("Fork handling test: ")
+}
\ No newline at end of file
diff --git a/modules/type/blocks/tests/include/dap_chain_blocks_test.h b/modules/type/blocks/tests/include/dap_chain_blocks_test.h
new file mode 100644
index 0000000000000000000000000000000000000000..093ee4fc158f6c9de7a584e46e4a2fc294ef2d2c
--- /dev/null
+++ b/modules/type/blocks/tests/include/dap_chain_blocks_test.h
@@ -0,0 +1,3 @@
+#include "dap_chain_cs_blocks.h"
+
+void dap_chain_blocks_test();
\ No newline at end of file
diff --git a/modules/type/blocks/tests/main.c b/modules/type/blocks/tests/main.c
new file mode 100644
index 0000000000000000000000000000000000000000..26e8ea5b328105c9e5aa0a7519c5843e7ac2b257
--- /dev/null
+++ b/modules/type/blocks/tests/main.c
@@ -0,0 +1,8 @@
+#include "dap_chain_blocks_test.h"
+
+int main()
+{
+    dap_chain_blocks_test();
+
+    return 0;
+}
\ No newline at end of file
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index 0d34f54c50eb43739c1017bd50337b1c997d0bf1..5b047189d38d65ad49d8f9b5b7c9af2f6a034dd9 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -96,9 +96,9 @@ static void s_dap_chain_cs_dag_threshold_free(dap_chain_cs_dag_t *a_dag);
 static dap_chain_cs_dag_event_item_t *s_dag_proc_treshold(dap_chain_cs_dag_t *a_dag);
 
 // Atomic element organization callbacks
-static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t);                      //    Accept new event in dag
+static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t *a_atom_hash);                      //    Accept new event in dag
 static dap_chain_atom_ptr_t s_chain_callback_atom_add_from_treshold(dap_chain_t * a_chain, size_t *a_event_size_out);                    //    Accept new event in dag from treshold
-static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t);                   //    Verify new event in dag
+static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t *a_atom_hash);                   //    Verify new event in dag
 static size_t s_chain_callback_atom_get_static_hdr_size(void);                               //    Get dag event header size
 
 static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create(dap_chain_t * a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_hash_from);
@@ -278,9 +278,13 @@ static int s_chain_cs_dag_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     l_dag->is_add_directly = dap_config_get_item_bool_default(a_chain_cfg,"dag","is_add_directly",false);
     l_dag->datum_add_hashes_count = dap_config_get_item_uint16_default(a_chain_cfg,"dag","datum_add_hashes_count",1);
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
+#ifndef DAP_LEDGER_TEST
     l_dag->gdb_group_events_round_new = dap_strdup_printf(l_dag->is_celled ? "dag-%s-%s-%016llx-round.new" : "dag-%s-%s-round.new",
                                           l_net->pub.gdb_groups_prefix, a_chain->name, 0LLU);
-
+#else
+    l_dag->gdb_group_events_round_new = dap_strdup_printf(l_dag->is_celled ? "dag-%s-%s-%016llx-round.new" : "dag-%s-%s-round.new",
+                                        "Snet", a_chain->name, 0LLU);
+#endif
     PVT(l_dag)->treshold_fee_timer = dap_interval_timer_create(900000, (dap_timer_callback_t)s_dap_chain_cs_dag_threshold_free, l_dag);
 
     log_it (L_NOTICE, "DAG chain initialized (%s)", l_dag->is_single_line ? "single line" : "multichain");
@@ -443,15 +447,25 @@ static int s_sort_event_item(dap_chain_cs_dag_event_item_t* a, dap_chain_cs_dag_
  * @param a_atom_size
  * @return 0 if verified and added well, otherwise if not
  */
-static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size)
+static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_hash_fast_t *a_atom_hash)
 {
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG(a_chain);
     dap_chain_cs_dag_event_t * l_event = (dap_chain_cs_dag_event_t *) a_atom;
 
-    dap_chain_cs_dag_event_item_t *l_event_item = NULL;
-    dap_chain_hash_fast_t l_event_hash;
-    dap_chain_cs_dag_event_calc_hash(l_event, a_atom_size, &l_event_hash);
-    if (s_debug_more) {
+    dap_chain_cs_dag_event_item_t * l_event_item = DAP_NEW_Z(dap_chain_cs_dag_event_item_t);
+    if (!l_event_item) {
+        log_it(L_CRITICAL, "Memory allocation error");
+        return ATOM_REJECT;
+    }
+    pthread_mutex_t *l_events_mutex = &PVT(l_dag)->events_mutex;
+    l_event_item->event = l_event;
+    l_event_item->event_size = a_atom_size;
+    l_event_item->ts_added = dap_time_now();
+
+    dap_chain_hash_fast_t l_event_hash = *a_atom_hash;
+    l_event_item->hash = l_event_hash;
+
+    if(s_debug_more) {
         char l_event_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE] = { '\0' };
         dap_chain_hash_fast_to_str(&l_event_hash, l_event_hash_str, sizeof(l_event_hash_str));
         log_it(L_DEBUG, "Processing event: %s ... (size %zd)", l_event_hash_str,a_atom_size);
@@ -464,7 +478,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
     // verify hashes and consensus
     switch (ret) {
     case ATOM_ACCEPT:
-        ret = s_chain_callback_atom_verify(a_chain, a_atom, a_atom_size);
+        ret = s_chain_callback_atom_verify(a_chain, a_atom, a_atom_size, &l_event_hash);
         if (ret == ATOM_MOVE_TO_THRESHOLD) {
             if (!s_threshold_enabled /*&& !dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id))*/)
                 ret = ATOM_REJECT;
@@ -694,7 +708,7 @@ static bool s_chain_callback_datums_pool_proc(dap_chain_t *a_chain, dap_chain_da
     dap_hash_fast(l_event, l_event_size, &l_event_hash);
     bool l_res = false;
     if (l_dag->is_add_directly) {
-        dap_chain_atom_verify_res_t l_verify_res = s_chain_callback_atom_add(a_chain, l_event, l_event_size);
+        dap_chain_atom_verify_res_t l_verify_res = s_chain_callback_atom_add(a_chain, l_event, l_event_size, &l_event_hash);
         DAP_DELETE(l_event);
         if (l_verify_res != ATOM_ACCEPT) {
             log_it(L_ERROR, "Can't add new event to the file, atom verification result %d", l_verify_res);
@@ -763,7 +777,7 @@ static bool s_event_verify_size(dap_chain_cs_dag_event_t *a_event, size_t a_even
  * @param a_atom
  * @return
  */
-static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t  a_atom,size_t a_atom_size)
+static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t  a_atom,size_t a_atom_size, dap_chain_hash_fast_t *a_atom_hash)
 {
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG(a_chain);
     dap_chain_cs_dag_event_t * l_event = (dap_chain_cs_dag_event_t *) a_atom;
@@ -777,11 +791,9 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_
         debug_if(s_debug_more, L_WARNING, "Event from another chain, possible corrupted event");
         return ATOM_REJECT;
     }
-
+    dap_chain_hash_fast_t l_event_hash = *a_atom_hash;
     // Hard accept list
     if (l_dag->hal) {
-        dap_chain_hash_fast_t l_event_hash = { };
-        dap_chain_cs_dag_event_calc_hash(l_event,a_atom_size, &l_event_hash);
         dap_chain_cs_dag_hal_item_t *l_hash_found = NULL;
         pthread_mutex_lock(l_events_mutex);
         HASH_FIND(hh, l_dag->hal, &l_event_hash, sizeof(l_event_hash), l_hash_found);
@@ -806,8 +818,6 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_
         }
 
         if (l_dag->is_static_genesis_event ){
-            dap_chain_hash_fast_t l_event_hash;
-            dap_chain_cs_dag_event_calc_hash(l_event,a_atom_size, &l_event_hash);
             if ( memcmp( &l_event_hash, &l_dag->static_genesis_event_hash, sizeof(l_event_hash) ) != 0 ){
                 char l_event_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE], l_genesis_event_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
                 dap_chain_hash_fast_to_str(&l_event_hash, l_event_hash_str, sizeof(l_event_hash_str));
@@ -1398,7 +1408,9 @@ static int s_cli_dag(int argc, char ** argv, void **a_str_reply)
                     continue;
                 dap_chain_cs_dag_event_round_item_t *l_round_item = (dap_chain_cs_dag_event_round_item_t *)l_objs[i].value;
                 dap_chain_cs_dag_event_t *l_event = (dap_chain_cs_dag_event_t *)l_round_item->event_n_signs;
+                dap_hash_fast_t l_event_hash = {};
                 size_t l_event_size = l_round_item->event_size;
+                dap_hash_fast(l_event, l_event_size, &l_event_hash);
                 int l_ret_event_verify;
                 if ( ( l_ret_event_verify = l_dag->callback_cs_verify (l_dag,l_event,l_event_size) ) !=0 ){// if consensus accept the event
                     dap_string_append_printf( l_str_ret_tmp,
@@ -1410,7 +1422,7 @@ static int s_cli_dag(int argc, char ** argv, void **a_str_reply)
                     dap_string_append_printf( l_str_ret_tmp, "Event %s verification passed\n", l_objs[i].key);
                     // If not verify only mode we add
                     if ( ! l_verify_only ){
-                        if (s_chain_callback_atom_add(l_chain, l_event, l_event_size) != ATOM_ACCEPT) { // Add new atom in chain
+                        if (s_chain_callback_atom_add(l_chain, l_event, l_event_size, &l_event_hash) != ATOM_ACCEPT) { // Add new atom in chain
                             dap_string_append_printf(l_str_ret_tmp, "Event %s not added in chain\n", l_objs[i].key);
                         } else {
                             // add event to delete
diff --git a/modules/type/none/dap_chain_cs_none.c b/modules/type/none/dap_chain_cs_none.c
index f76440baafe884c0dce476b4d306219004df105a..78e2681936c66295956f14250f693a08ab139ee9 100644
--- a/modules/type/none/dap_chain_cs_none.c
+++ b/modules/type/none/dap_chain_cs_none.c
@@ -60,8 +60,8 @@ typedef struct dap_nonconsensus_private {
 #define PVT(a) ((a) ? (dap_nonconsensus_private_t *)(a)->_internal : NULL)
 
 // Atomic element organization callbacks
-static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t, size_t); //    Accept new event in gdb
-static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t, size_t); //    Verify new event in gdb
+static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t, size_t, dap_hash_fast_t *a_atom_hash); //    Accept new event in gdb
+static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t, size_t, dap_hash_fast_t *a_atom_hash); //    Verify new event in gdb
 static size_t s_nonconsensus_callback_atom_get_static_hdr_size(void); //    Get gdb event header size
 
 static dap_chain_atom_iter_t* s_nonconsensus_callback_atom_iter_create(dap_chain_t * a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_hash_from);
@@ -127,7 +127,9 @@ static void s_changes_callback_notify(dap_store_obj_t *a_obj, void *a_arg)
     dap_chain_t *l_chain = a_arg;
     if (dap_store_obj_get_type(a_obj) == DAP_GLOBAL_DB_OPTYPE_DEL)
         return;
-    s_nonconsensus_callback_atom_add(l_chain, (dap_chain_datum_t *)a_obj->value, a_obj->value_len);
+    dap_hash_fast_t l_hash = {};
+    dap_hash_fast(a_obj->value, a_obj->value_len, &l_hash);
+    s_nonconsensus_callback_atom_add(l_chain, (dap_chain_datum_t *)a_obj->value, a_obj->value_len, &l_hash);
 }
 
 int s_nonconsensus_callback_created(dap_chain_t *a_chain, dap_config_t UNUSED_ARG *a_chain_cfg)
@@ -261,7 +263,9 @@ static void s_nonconsensus_ledger_load(dap_chain_t *a_chain)
     for (size_t i = 0; l_values && i < l_values_count; i++) {
         dap_global_db_obj_t *it = l_values + i;
         // load ledger
-        s_nonconsensus_callback_atom_add(a_chain, it->value, it->value_len);
+        dap_hash_fast_t l_hash = {};
+        dap_hash_fast(it->value, it->value_len, &l_hash);
+        s_nonconsensus_callback_atom_add(a_chain, it->value, it->value_len, &l_hash);
         log_it(L_DEBUG,"Load mode, doesn't save item %s:%s", it->key, l_nochain_pvt->group_datums);
     }
     dap_global_db_objs_delete(l_values, l_values_count);
@@ -303,7 +307,7 @@ static size_t s_nonconsensus_callback_datums_pool_proc(dap_chain_t * a_chain, da
  * @param a_atom_size atom size
  * @return dap_chain_atom_verify_res_t
  */
-static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size)
+static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_hash_fast_t *a_atom_hash)
 {
     if (NULL == a_chain) {
         log_it(L_WARNING, "Arguments is NULL for s_nonconsensus_callback_atom_add");
@@ -312,9 +316,8 @@ static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t
     dap_nonconsensus_t * l_nochain = DAP_NONCONSENSUS(a_chain);
     dap_nonconsensus_private_t *l_nochain_priv = PVT(l_nochain);
     dap_chain_datum_t *l_datum = (dap_chain_datum_t*) a_atom;
-    dap_hash_fast_t l_datum_hash;
-    dap_hash_fast(l_datum->data, l_datum->header.data_size, &l_datum_hash);
-    if (dap_chain_datum_add(a_chain, l_datum, a_atom_size, &l_datum_hash))
+    dap_hash_fast_t l_datum_hash = *a_atom_hash;
+    if(dap_chain_datum_add(a_chain, l_datum, a_atom_size, &l_datum_hash))
         return ATOM_REJECT;
 
     dap_nonconsensus_datum_hash_item_t * l_hash_item = DAP_NEW_Z(dap_nonconsensus_datum_hash_item_t);
@@ -323,7 +326,7 @@ static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t
         return ATOM_REJECT;
     }
     size_t l_datum_size = dap_chain_datum_size(l_datum);
-    dap_hash_fast(l_datum->data,l_datum->header.data_size,&l_hash_item->datum_data_hash );
+    l_hash_item->datum_data_hash = l_datum_hash;
     dap_chain_hash_fast_to_str(&l_hash_item->datum_data_hash, l_hash_item->key, sizeof(l_hash_item->key));
     DL_APPEND(l_nochain_priv->hash_items, l_hash_item);
     if (!l_nochain_priv->is_load_mode && a_chain->atom_notifiers) {
@@ -345,7 +348,7 @@ static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_add(dap_chain_t
  * @param a_atom_size size of atom
  * @return dap_chain_atom_verify_res_t
  */
-static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size)
+static dap_chain_atom_verify_res_t s_nonconsensus_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_hash_fast_t *a_atom_hash)
 {
     (void) a_chain;
     (void) a_atom;