diff --git a/CMakeLists.txt b/CMakeLists.txt
index a422e01edacf89dad3d9e889529368bcf7a7a71e..de17da8a1f309ba795421066b3caaacabd957e39 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -37,6 +37,8 @@ else()
     #    add_definitions(-DDAP_DISABLE_INT128=FALSE)
 endif(NOT DAP_INT128_SUPPORT)
 
+#set(BUILD_CELLFRAME_SDK_TESTS ON)
+
 if (BUILD_CELLFRAME_SDK_TESTS)
     enable_testing()
     add_definitions("-DDAP_CHAIN_LEDGER_TEST")
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 65395b01266043333f414b1883261e99cfef8585..4b777752b72e7cdc5ab013a56ef797d60b37fbc2 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -91,33 +91,6 @@ void dap_chain_deinit(void)
 
 }
 
-
-/**
- * @brief dap_chain_deinit
- * note: require dap_chain_enum_unlock() after
- */
-dap_chain_t* dap_chain_enum(void** a_item)
-{
-    // if a_item == 0x1 then first item
-    dap_chain_item_t *l_item_start = ( *a_item == (void*) 0x1) ? s_chain_items : (dap_chain_item_t*) *a_item;
-    dap_chain_item_t *l_item = NULL;
-    dap_chain_item_t *l_item_tmp = NULL;
-    pthread_rwlock_rdlock(&s_chain_items_rwlock);
-    HASH_ITER(hh, l_item_start, l_item, l_item_tmp) {
-        *a_item = l_item_tmp;
-        return l_item->chain;
-    }
-    return NULL ;
-}
-
-/**
- * @brief dap_chain_enum_unlock
- */
-void dap_chain_enum_unlock(void)
-{
-    pthread_rwlock_unlock(&s_chain_items_rwlock);
-}
-
 /**
  * @brief 
  * create dap chain object
@@ -138,7 +111,6 @@ dap_chain_t * dap_chain_create(dap_ledger_t* a_ledger, const char * a_chain_net_
     l_ret->net_name = strdup (a_chain_net_name);
     l_ret->ledger = a_ledger;
     pthread_rwlock_init(&l_ret->rwlock, NULL);
-    pthread_rwlock_init(&l_ret->atoms_rwlock,NULL);
     pthread_rwlock_init(&l_ret->cell_rwlock,NULL);
     dap_chain_item_t * l_ret_item = DAP_NEW_Z(dap_chain_item_t);
     l_ret_item->chain = l_ret;
@@ -191,7 +163,6 @@ void dap_chain_delete(dap_chain_t * a_chain)
     a_chain->autoproc_datum_types_count = 0;
     DAP_DELETE(a_chain->autoproc_datum_types);
     pthread_rwlock_destroy(&a_chain->rwlock);
-    pthread_rwlock_destroy(&a_chain->atoms_rwlock);
     pthread_rwlock_destroy(&a_chain->cell_rwlock);
     pthread_rwlock_destroy(&a_chain->rwlock);
     pthread_rwlock_unlock(&s_chain_items_rwlock);
@@ -397,18 +368,15 @@ dap_chain_t * dap_chain_load_from_cfg(dap_ledger_t* a_ledger, const char * a_cha
                         }
                     }
                 }
-            }
-            l_chain_id.uint64 = l_chain_id_u;
-
-            if (l_chain_id_str)
-                log_it (L_NOTICE, "Chain id 0x%016"DAP_UINT64_FORMAT_x"  ( \"%s\" )", l_chain_id.uint64, l_chain_id_str);
-            else {
-                log_it (L_ERROR,"Wasn't recognized '%s' string as chain net id, hex or dec", l_chain_id_str);
+            } else {
+                log_it (L_ERROR, "Wasn't found chain id string in config");
                 dap_config_close(l_cfg);
                 return NULL;
-
             }
 
+            l_chain_id.uint64 = l_chain_id_u;
+            log_it (L_NOTICE, "Chain id 0x%016"DAP_UINT64_FORMAT_x"  ( \"%s\" )", l_chain_id.uint64, l_chain_id_str);
+
             // Read chain name
             if ( ( l_chain_name = dap_config_get_item_str(l_cfg,"chain","name") ) == NULL )
 			{
@@ -768,53 +736,6 @@ int dap_cert_chain_file_save(dap_chain_datum_t *datum, char *net_name)
     return l_ret;
 }
 
-int dap_chain_datum_unledgered_search_iter(dap_chain_datum_t* a_datum, dap_chain_t* a_chain)
-{
-    /* Only for datum types which do not appear in ledger */
-    switch (a_datum->header.type_id) {
-    case DAP_CHAIN_DATUM_TOKEN_DECL:
-    case DAP_CHAIN_DATUM_TOKEN_EMISSION:
-    case DAP_CHAIN_DATUM_TX:
-        return 0;
-    /* The types above are checked while adding to ledger, otherwise let's unfold the chains */
-    default: {
-        if (!a_chain->callback_atom_get_datums) {
-            log_it(L_WARNING, "No callback set to fetch datums from atom in chain '%s'", a_chain->name);
-            return -2;
-        }
-        int l_found = 0;
-        dap_chain_hash_fast_t l_datum_hash;
-        dap_hash_fast(a_datum->data, a_datum->header.data_size, &l_datum_hash);
-        dap_chain_atom_iter_t *l_atom_iter = a_chain->callback_atom_iter_create(a_chain, a_chain->cells->id, 0);
-        size_t l_atom_size = 0;
-        for (dap_chain_atom_ptr_t l_atom = a_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
-             l_atom && l_atom_size && !l_found;
-             l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter, &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);
-            for (size_t i = 0; i < l_datums_count; ++i) {
-                if (l_datums[i]->header.type_id != a_datum->header.type_id) {
-                    break;
-                }
-                dap_chain_hash_fast_t l_datum_i_hash;
-                dap_hash_fast(l_datums[i]->data, l_datums[i]->header.data_size, &l_datum_i_hash);
-                if (!memcmp(&l_datum_i_hash, &l_datum_hash, DAP_CHAIN_HASH_FAST_SIZE)) {
-                    char l_datum_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
-                    dap_hash_fast_to_str(&l_datum_hash, l_datum_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE);
-                    log_it(L_INFO, "Datum %s found in chain %lu", l_datum_hash_str, a_chain->id.uint64);
-                    l_found = 1;
-                    break;
-                }
-            }
-            DAP_DEL_Z(l_datums);
-        }
-        a_chain->callback_atom_iter_delete(l_atom_iter);
-        return l_found;
-    } /* default */
-    }
-}
-
 const char* dap_chain_get_path(dap_chain_t *a_chain){
     return DAP_CHAIN_PVT(a_chain)->file_storage_dir;
 }
diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index 911f7d94e024d7fe880272afd2a0897e22b47182..2c5d66611bc9271dad31725da77de0151c15ac32 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -2380,7 +2380,7 @@ void dap_chain_ledger_set_fee(dap_ledger_t *a_ledger, uint256_t a_fee, dap_chain
     PVT(a_ledger)->fee_addr = a_fee_addr;
 }
 
-int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size)
+int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size, dap_chain_hash_fast_t *a_emission_hash)
 {
     if (!a_token_emission || !a_token_emission_size)
         return -100;
@@ -2402,21 +2402,18 @@ int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_
     }
 
     // check if such emission is already present in table
-    dap_chain_hash_fast_t l_token_emission_hash = { };
-    //dap_chain_hash_fast_t * l_token_emission_hash_ptr = &l_token_emission_hash;
-    dap_hash_fast(a_token_emission, a_token_emission_size, &l_token_emission_hash);
     pthread_rwlock_rdlock(l_token_item ? &l_token_item->token_emissions_rwlock
                                        : &l_ledger_pvt->threshold_emissions_rwlock);
     HASH_FIND(hh,l_token_item ? l_token_item->token_emissions : l_ledger_pvt->threshold_emissions,
-              &l_token_emission_hash, sizeof(l_token_emission_hash), l_token_emission_item);
+              a_emission_hash, sizeof(*a_emission_hash), l_token_emission_item);
     unsigned long long l_threshold_emissions_count = HASH_COUNT( l_ledger_pvt->threshold_emissions);
     pthread_rwlock_unlock(l_token_item ? &l_token_item->token_emissions_rwlock
                                        : &l_ledger_pvt->threshold_emissions_rwlock);
     if(l_token_emission_item ) {
         if(s_debug_more) {
             char l_token_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
-            dap_chain_hash_fast_to_str(&l_token_emission_hash, l_token_hash_str, sizeof(l_token_hash_str));
-            if ( l_token_emission_item->datum_token_emission->hdr.version == 2 ) {
+            dap_chain_hash_fast_to_str(a_emission_hash, l_token_hash_str, sizeof(l_token_hash_str));
+            if ( l_token_emission_item->datum_token_emission->hdr.version >= 2 ) {
                 char *l_balance = dap_chain_balance_print(l_token_emission_item->datum_token_emission->hdr.value_256);
                 log_it(L_ERROR, "Can't add token emission datum of %s %s ( %s ): already present in cache",
                         l_balance, l_token_ticker, l_token_hash_str);
@@ -2628,7 +2625,7 @@ static inline int s_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_e
 {
     dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
     dap_chain_ledger_token_emission_item_t * l_token_emission_item = NULL;
-    int l_ret = dap_chain_ledger_token_emission_add_check(a_ledger, a_token_emission, a_token_emission_size);
+    int l_ret = dap_chain_ledger_token_emission_add_check(a_ledger, a_token_emission, a_token_emission_size, a_emission_hash);
     if (l_ret) {
         if (l_ret == DAP_CHAIN_CS_VERIFY_CODE_NO_DECREE) { // TODO remove emissions threshold
             if (HASH_COUNT(l_ledger_pvt->threshold_emissions) < s_threshold_emissions_max) {
@@ -2825,17 +2822,16 @@ dap_chain_ledger_stake_lock_item_t *s_emissions_for_stake_lock_item_find(dap_led
 }
 
 
-int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size)
+int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token_emission,
+                                         size_t a_token_emission_size, dap_hash_fast_t *a_token_emission_hash)
 {
-    dap_chain_hash_fast_t l_token_emission_hash = {};
-    dap_hash_fast(a_token_emission, a_token_emission_size, &l_token_emission_hash);
     if (PVT(a_ledger)->load_mode) {
         dap_chain_ledger_token_emission_item_t *l_token_emission_item;
         dap_chain_ledger_token_item_t *l_token_item, *l_item_tmp;
         pthread_rwlock_rdlock(&PVT(a_ledger)->tokens_rwlock);
         HASH_ITER(hh, PVT(a_ledger)->tokens, l_token_item, l_item_tmp) {
             pthread_rwlock_rdlock(&l_token_item->token_emissions_rwlock);
-            HASH_FIND(hh, l_token_item->token_emissions, &l_token_emission_hash, sizeof(l_token_emission_hash),
+            HASH_FIND(hh, l_token_item->token_emissions, a_token_emission_hash, sizeof(*a_token_emission_hash),
                     l_token_emission_item);
             pthread_rwlock_unlock(&l_token_item->token_emissions_rwlock);
             if (l_token_emission_item) {
@@ -2845,14 +2841,14 @@ int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token
         }
         pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
         pthread_rwlock_rdlock(&PVT(a_ledger)->threshold_emissions_rwlock);
-        HASH_FIND(hh, PVT(a_ledger)->threshold_emissions, &l_token_emission_hash, sizeof(l_token_emission_hash),
+        HASH_FIND(hh, PVT(a_ledger)->threshold_emissions, a_token_emission_hash, sizeof(*a_token_emission_hash),
                 l_token_emission_item);
         pthread_rwlock_unlock(&PVT(a_ledger)->threshold_emissions_rwlock);
         if (l_token_emission_item) {
             return -5;
         }
     }
-    return dap_chain_ledger_token_emission_add(a_ledger, a_token_emission, a_token_emission_size, &l_token_emission_hash, false);
+    return dap_chain_ledger_token_emission_add(a_ledger, a_token_emission, a_token_emission_size, a_token_emission_hash, false);
 }
 
 dap_chain_ledger_token_emission_item_t *s_emission_item_find(dap_ledger_t *a_ledger,
@@ -3932,22 +3928,26 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
  * @param a_tx
  * @return
  */
-int dap_chain_ledger_tx_add_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
+int dap_chain_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)
 {
-    if(!a_tx)
-        return -2;
-    dap_hash_fast_t l_tx_hash;
-    dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_tx_hash);
+    if (!a_tx)
+        return -200;
+
+    size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
+    if (l_tx_size != a_datum_size) {
+        log_it (L_WARNING, "Inconsistent datum TX with data_size=%zu, tx_size=%zu", a_datum_size, l_tx_size);
+        return -202;
+    }
 
     int l_ret_check;
-    if( (l_ret_check = dap_chain_ledger_tx_cache_check(a_ledger, a_tx, &l_tx_hash, false,
+    if( (l_ret_check = dap_chain_ledger_tx_cache_check(a_ledger, a_tx, a_datum_hash, false,
                                                        NULL, NULL, NULL)) < 0) {
         debug_if(s_debug_more, L_DEBUG, "dap_chain_ledger_tx_add_check() tx not passed the check: code %d ", l_ret_check);
         return l_ret_check;
     }
     if(s_debug_more) {
         char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
-        dap_chain_hash_fast_to_str(&l_tx_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
+        dap_chain_hash_fast_to_str(a_datum_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
         log_it ( L_INFO, "dap_chain_ledger_tx_add_check() check passed for tx %s", l_tx_hash_str);
     }
     return 0;
@@ -4030,7 +4030,7 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
             log_it(L_ERROR, "NULL tx detected");
         return -1;
     }
-    int ret = 1;
+    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;
@@ -4246,7 +4246,7 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
                     dap_chain_hash_fast_to_str(&l_tx_prev_hash_to_del, l_tx_prev_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE);
                     log_it(L_ERROR, "Can't delete previous transactions because hash=%s not found", l_tx_prev_hash_str);
                 }
-                ret = -100;
+                l_ret = -100;
                 l_outs_used = i;
                 goto FIN;
             }
@@ -4256,7 +4256,7 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
                     dap_chain_hash_fast_to_str(&l_tx_prev_hash_to_del, l_tx_prev_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE);
                     log_it(L_ERROR, "Can't delete previous transactions with hash=%s", l_tx_prev_hash_str);
                 }
-                ret = -101;
+                l_ret = -101;
                 l_outs_used = i;
                 goto FIN;
             }
@@ -4397,7 +4397,6 @@ static inline int s_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, d
     }
     if (!a_from_threshold)
         s_threshold_txs_proc(a_ledger);
-    ret = 1;
 FIN:
     if (l_list_bound_items)
         dap_list_free_full(l_list_bound_items, NULL);
@@ -4410,7 +4409,7 @@ FIN:
     }
     DAP_DELETE(l_gdb_group);
     DAP_DELETE(l_cache_used_outs);
-    return ret;
+    return l_ret;
 }
 
 static bool s_ledger_tps_callback(void *a_arg)
@@ -4428,34 +4427,30 @@ static bool s_ledger_tps_callback(void *a_arg)
 
 int dap_chain_ledger_tx_load(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_chain_hash_fast_t *a_tx_hash)
 {
-    dap_chain_hash_fast_t l_tx_hash;
-    dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_tx_hash);
-    if (a_tx_hash)
-        *a_tx_hash = l_tx_hash;
     if (PVT(a_ledger)->load_mode) {
         if (PVT(a_ledger)->cache_tx_check_callback)
-            PVT(a_ledger)->cache_tx_check_callback(&l_tx_hash);
+            PVT(a_ledger)->cache_tx_check_callback(a_tx_hash);
         dap_chain_ledger_tx_item_t *l_tx_item;
         unsigned l_hash_value;
-        HASH_VALUE(&l_tx_hash, sizeof(dap_chain_hash_fast_t), l_hash_value);
+        HASH_VALUE(a_tx_hash, sizeof(dap_chain_hash_fast_t), l_hash_value);
         pthread_rwlock_rdlock(&PVT(a_ledger)->ledger_rwlock);
-        HASH_FIND_BYHASHVALUE(hh, PVT(a_ledger)->ledger_items, &l_tx_hash, sizeof(dap_chain_hash_fast_t), l_hash_value, l_tx_item);
+        HASH_FIND_BYHASHVALUE(hh, PVT(a_ledger)->ledger_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_hash_value, l_tx_item);
         if (l_tx_item) {
             pthread_rwlock_unlock(&PVT(a_ledger)->ledger_rwlock);
             return 1;
         }
-        HASH_FIND_BYHASHVALUE(hh, PVT(a_ledger)->threshold_txs, &l_tx_hash, sizeof(dap_chain_hash_fast_t), l_hash_value, l_tx_item);
+        HASH_FIND_BYHASHVALUE(hh, PVT(a_ledger)->threshold_txs, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_hash_value, l_tx_item);
         if (l_tx_item) {
             pthread_rwlock_unlock(&PVT(a_ledger)->ledger_rwlock);
             return DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS;
         }
         dap_chain_ledger_tx_spent_item_t *l_tx_spent_item;
-        HASH_FIND_BYHASHVALUE(hh, PVT(a_ledger)->spent_items, &l_tx_hash, sizeof(dap_chain_hash_fast_t), l_hash_value, l_tx_spent_item);
+        HASH_FIND_BYHASHVALUE(hh, PVT(a_ledger)->spent_items, a_tx_hash, sizeof(dap_chain_hash_fast_t), l_hash_value, l_tx_spent_item);
         pthread_rwlock_unlock(&PVT(a_ledger)->ledger_rwlock);
         if (l_tx_spent_item)
             return 1;
     }
-    return dap_chain_ledger_tx_add(a_ledger, a_tx, &l_tx_hash, false);
+    return dap_chain_ledger_tx_add(a_ledger, a_tx, a_tx_hash, false);
 }
 
 /**
@@ -5110,7 +5105,7 @@ uint256_t dap_chain_ledger_tx_cache_get_out_cond_value(dap_ledger_t *a_ledger, d
  * @param a_addr_from
  * @param a_value_need
  * @param a_value_transfer
- * @return list of list_used_item_t
+ * @return list of dap_chain_tx_used_out_item_t
  */
 dap_list_t *dap_chain_ledger_get_list_tx_outs_with_val(dap_ledger_t *a_ledger, const char *a_token_ticker, const dap_chain_addr_t *a_addr_from,
                                                        uint256_t a_value_need, uint256_t *a_value_transfer)
@@ -5162,7 +5157,7 @@ dap_list_t *dap_chain_ledger_get_list_tx_outs_with_val(dap_ledger_t *a_ledger, c
             }
             // Check whether used 'out' items
             if (!dap_chain_ledger_tx_hash_is_used_out_item (a_ledger, &l_tx_cur_hash, l_out_idx_tmp)) {
-                list_used_item_t *l_item = DAP_NEW_Z(list_used_item_t);
+                dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t);
                 l_item->tx_hash_fast = l_tx_cur_hash;
                 l_item->num_idx_out = l_out_idx_tmp;
                 l_item->value = l_value;
@@ -5296,7 +5291,7 @@ dap_list_t *dap_chain_ledger_get_list_tx_cond_outs_with_val(dap_ledger_t *a_ledg
                 continue;
             }
             if (!IS_ZERO_256(l_value)) {
-                list_used_item_t *l_item = DAP_NEW(list_used_item_t);
+                dap_chain_tx_used_out_item_t *l_item = DAP_NEW(dap_chain_tx_used_out_item_t);
                 l_item->tx_hash_fast = l_tx_cur_hash;
                 l_item->num_idx_out = l_out_idx_tmp;
                 l_item->value = l_value;
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index 1e537d2fc1b89d535299c52aef829e58a387c5c1..7c15030437b8d05b8aa2c2867137cfc33db0a471 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -45,17 +45,26 @@ typedef struct dap_ledger dap_ledger_t;
 typedef const void * dap_chain_atom_ptr_t;
 
 // Atomic element iterator
-typedef struct dap_chain_atom_iter{
+typedef struct dap_chain_atom_iter {
     dap_chain_t *chain;
     dap_chain_atom_ptr_t cur;
+    size_t cur_size;
     dap_chain_hash_fast_t *cur_hash;
     dap_chain_cell_id_t cell_id;
     bool with_treshold;
     bool found_in_treshold;
-    size_t cur_size;
     void *cur_item;
 } dap_chain_atom_iter_t;
 
+typedef struct dap_chain_datum_iter {
+    dap_chain_t *chain;
+    dap_chain_datum_t *cur;
+    size_t cur_size;
+    dap_chain_hash_fast_t *cur_hash;
+    dap_chain_hash_fast_t *cur_atom_hash;
+    int ret_code;
+    void *cur_item;
+} dap_chain_datum_iter_t;
 
 typedef enum dap_chain_atom_verify_res{
     ATOM_ACCEPT = 0, ATOM_PASS, ATOM_REJECT, ATOM_MOVE_TO_THRESHOLD
@@ -83,11 +92,16 @@ typedef dap_chain_atom_iter_t* (*dap_chain_callback_atom_iter_create_t)(dap_chai
 typedef dap_chain_atom_iter_t* (*dap_chain_callback_atom_iter_create_from_t)(dap_chain_t * ,dap_chain_atom_ptr_t, size_t);
 typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_get_first_t)(dap_chain_atom_iter_t * , size_t*);
 
+typedef dap_chain_datum_iter_t * (*dap_chain_datum_callback_iter_create_t)(dap_chain_t *);
+typedef dap_chain_datum_t * (*dap_chain_datum_callback_iter_get_first_t)(dap_chain_datum_iter_t *);
+typedef dap_chain_datum_t * (*dap_chain_datum_callback_iter_get_next_t)(dap_chain_datum_iter_t *);
+typedef void (*dap_chain_datum_callback_iter_delete_t)(dap_chain_datum_iter_t *);
+
 typedef dap_chain_datum_t** (*dap_chain_callback_atom_get_datum_t)(dap_chain_atom_ptr_t, size_t, size_t * );
 typedef dap_time_t (*dap_chain_callback_atom_get_timestamp_t)(dap_chain_atom_ptr_t);
 
 typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_find_by_hash_t)(dap_chain_atom_iter_t * ,dap_chain_hash_fast_t *,size_t*);
-typedef dap_chain_datum_tx_t * (*dap_chain_callback_tx_find_by_hash_t)(dap_chain_t *, dap_chain_hash_fast_t *, dap_chain_hash_fast_t *);
+typedef dap_chain_datum_t * (*dap_chain_callback_datum_find_by_hash_t)(dap_chain_t *, dap_chain_hash_fast_t *, dap_chain_hash_fast_t *, int *);
 
 typedef dap_chain_atom_ptr_t (*dap_chain_callback_block_find_by_hash_t)(dap_chain_t * ,dap_chain_hash_fast_t *);
 
@@ -147,8 +161,6 @@ typedef struct dap_chain {
     struct dap_chain * next;
     struct dap_chain * prev;
 
-    // read/write atoms rwlock
-    pthread_rwlock_t atoms_rwlock;
     pthread_rwlock_t cell_rwlock;
 
     dap_chain_callback_new_cfg_t callback_created;
@@ -170,7 +182,7 @@ typedef struct dap_chain {
     dap_chain_callback_atom_get_timestamp_t callback_atom_get_timestamp;
 
     dap_chain_callback_atom_iter_find_by_hash_t callback_atom_find_by_hash;
-    dap_chain_callback_tx_find_by_hash_t callback_tx_find_by_hash;
+    dap_chain_callback_datum_find_by_hash_t callback_datum_find_by_hash;
 
     dap_chain_callback_block_find_by_hash_t callback_block_find_by_tx_hash;
 
@@ -196,12 +208,11 @@ typedef struct dap_chain {
 //    dap_chain_callback_notify_t callback_notify;
 //    void *callback_notify_arg;
 
-    /*
     dap_chain_datum_callback_iter_create_t callback_datum_iter_create;
     dap_chain_datum_callback_iter_get_first_t callback_datum_iter_get_first;
     dap_chain_datum_callback_iter_get_first_t callback_datum_iter_get_next;
     dap_chain_datum_callback_iter_delete_t callback_datum_iter_delete;
-*/
+
     void * _pvt; // private data
     void * _inheritor; // inheritor object
 } dap_chain_t;
@@ -221,11 +232,7 @@ typedef struct dap_chain_atom_notifier {
 int dap_chain_init(void);
 void dap_chain_deinit(void);
 
-dap_chain_t* dap_chain_enum(void** a_item);
-void dap_chain_enum_unlock(void);
-
-
-dap_chain_t * dap_chain_create(dap_ledger_t* a_ledger,const char * a_chain_net_name, const char * a_chain_name, dap_chain_net_id_t a_chain_net_id, dap_chain_id_t a_chain_id );
+dap_chain_t *dap_chain_create(dap_ledger_t* a_ledger,const char * a_chain_net_name, const char * a_chain_name, dap_chain_net_id_t a_chain_net_id, dap_chain_id_t a_chain_id );
 
 int dap_chain_load_all (dap_chain_t * a_chain);
 int dap_chain_save_all (dap_chain_t * a_chain);
@@ -244,5 +251,4 @@ bool dap_chain_get_atom_last_hash(dap_chain_t *a_chain, dap_hash_fast_t *a_atom_
 ssize_t dap_chain_atom_save(dap_chain_t *a_chain, const uint8_t *a_atom, size_t a_atom_size, dap_chain_cell_id_t a_cell_id);
 void dap_chain_add_mempool_notify_callback(dap_chain_t *a_chain, dap_store_obj_callback_notify_t a_callback, void *a_cb_arg);
 int dap_cert_chain_file_save(dap_chain_datum_t *datum, char *net_name);
-int dap_chain_datum_unledgered_search_iter(dap_chain_datum_t* a_datum, dap_chain_t* a_chain);
 const char* dap_chain_get_path(dap_chain_t *a_chain);
diff --git a/modules/chain/include/dap_chain_ledger.h b/modules/chain/include/dap_chain_ledger.h
index daf04624b0516eaf96b567cb47b4905e15f43713..f7fa73671f51a8aa1a21fefd178a2082c936ee68 100644
--- a/modules/chain/include/dap_chain_ledger.h
+++ b/modules/chain/include/dap_chain_ledger.h
@@ -119,7 +119,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,
 int dap_chain_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_chain_ledger_tx_add_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx);
+int dap_chain_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);
 
 /**
  * Print list transaction from ledger
@@ -161,10 +161,10 @@ dap_list_t * dap_chain_ledger_token_auth_pkeys_hashes(dap_ledger_t *a_ledger, co
  */
 int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size,
                                         dap_hash_fast_t *a_emission_hash, bool a_from_threshold);
-int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size);
+int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size, dap_hash_fast_t *a_token_emission_hash);
 
 // Check if it addable
-int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size);
+int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size, dap_chain_hash_fast_t *a_emission_hash);
 
 /* Add stake-lock item */
 int dap_chain_ledger_emission_for_stake_lock_item_add(dap_ledger_t *a_ledger, const dap_chain_hash_fast_t *a_tx_hash);
diff --git a/modules/chain/tests/dap_chain_ledger_tests.c b/modules/chain/tests/dap_chain_ledger_tests.c
index b361edd464fe7f287ac5e8ec6485c2532e1e4968..da64d64ce39b8e4ba83c2f4351374a2481b981f4 100644
--- a/modules/chain/tests/dap_chain_ledger_tests.c
+++ b/modules/chain/tests/dap_chain_ledger_tests.c
@@ -53,7 +53,6 @@ dap_chain_datum_tx_t *dap_chain_ledger_test_create_datum_base_tx(
 	uint256_t l_value_need = a_emi->hdr.value_256;
     dap_chain_datum_tx_t *l_tx = DAP_NEW_Z_SIZE(dap_chain_datum_tx_t, sizeof(dap_chain_datum_tx_t));
     l_tx->header.ts_created = time(NULL);
-    dap_chain_hash_fast_t l_tx_prev_hash = { 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;
@@ -97,14 +96,14 @@ void dap_chain_ledger_test_double_spending(
     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_chain_ledger_tx_add(a_ledger, l_first_tx, &l_first_tx_hash, false) == 1, "Can't added first transaction on ledger");
-    uint256_t l_balance = dap_chain_ledger_calc_balance(a_ledger, &l_addr_first, s_token_ticker);
+    dap_assert_PIF(!dap_chain_ledger_tx_add(a_ledger, l_first_tx, &l_first_tx_hash, false), "Can't added first transaction on ledger");
+    //uint256_t l_balance = dap_chain_ledger_calc_balance(a_ledger, &l_addr_first, s_token_ticker);
     // Second tx
     dap_chain_datum_tx_t *l_second_tx = dap_chain_ledger_test_create_tx(a_from_key, a_prev_hash,
                                                                        &l_addr_first, 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_chain_ledger_tx_add(a_ledger, l_second_tx, &l_second_tx_hash, false) != 1, "Added second transaction on ledger");
+    dap_assert_PIF(dap_chain_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.");
 }
 
@@ -164,7 +163,6 @@ void dap_chain_ledger_test_write_back_list(dap_ledger_t *a_ledger, dap_cert_t *a
     addr_key_container_t *l_addr_3 = gen_addr(a_net_id);
     addr_key_container_t *l_addr_4 = gen_addr(a_net_id);
     //Check white list
-    dap_hash_fast_t l_btx_addr4_hash = {0};
     {
         size_t l_decl_size = 0;
         char *l_token_ticker = "TestWL";
@@ -229,28 +227,27 @@ void dap_chain_ledger_test_write_back_list(dap_ledger_t *a_ledger, dap_cert_t *a
         dap_hash_fast(l_emi_whi, dap_chain_datum_emission_get_size((uint8_t*)l_emi_whi), &l_emi_whi_hash);
         dap_assert_PIF(!dap_chain_ledger_token_emission_add(a_ledger, (byte_t*)l_emi_whi, dap_chain_datum_emission_get_size((byte_t*)l_emi_whi),
                                             &l_emi_whi_hash, false),
-                       "Can't added emission in white address");
+                       "Can't add emission in white address");
         dap_chain_datum_tx_t *l_btx_addr1 = dap_chain_ledger_test_create_datum_base_tx(l_emi_whi, &l_emi_whi_hash,
                                                                                       *l_addr_1->addr, a_cert);
         dap_hash_fast_t l_btx_addr1_hash = {0};
         dap_hash_fast(l_btx_addr1, dap_chain_datum_tx_get_size(l_btx_addr1), &l_btx_addr1_hash);
         int l_ledger_add_code = dap_chain_ledger_tx_add(a_ledger, l_btx_addr1, &l_btx_addr1_hash, false);
-        char *l_ledger_tx_add_str = dap_strdup_printf("Can't added base tx in white address. Code: %d", l_ledger_add_code);
-        dap_assert_PIF(l_ledger_add_code == 1,
-                       l_ledger_tx_add_str);
+        char *l_ledger_tx_add_str = dap_strdup_printf("Can't add base tx in white address. Code: %d", l_ledger_add_code);
+        dap_assert_PIF(!l_ledger_add_code, l_ledger_tx_add_str);
         DAP_DELETE(l_ledger_tx_add_str);
         dap_hash_fast_t l_tx_addr4_hash = {0};
         dap_chain_datum_tx_t *l_tx_to_addr4 = dap_chain_ledger_test_create_tx(l_addr_1->enc_key, &l_btx_addr1_hash,
                                                                               l_addr_4->addr, dap_chain_uint256_from(s_total_supply-s_fee));
         dap_hash_fast(l_tx_to_addr4, dap_chain_datum_tx_get_size(l_tx_to_addr4), &l_tx_addr4_hash);
-        dap_assert_PIF(dap_chain_ledger_tx_add(a_ledger, l_tx_to_addr4, &l_tx_addr4_hash, false) == 1,
-                       "Can't added transaction to address from white list in ledger");
+        dap_assert_PIF(!dap_chain_ledger_tx_add(a_ledger, l_tx_to_addr4, &l_tx_addr4_hash, false),
+                       "Can't add transaction to address from white list in ledger");
         dap_chain_datum_tx_t *l_tx_to_addr3 = dap_chain_ledger_test_create_tx(l_addr_4->enc_key, &l_tx_addr4_hash,
                                                                               l_addr_3->addr, dap_chain_uint256_from(s_total_supply-s_fee));
         dap_hash_fast_t l_tx_addr3_hash = {0};
         dap_hash_fast(l_tx_to_addr3, dap_chain_datum_tx_get_size(l_tx_to_addr3), &l_tx_addr3_hash);
         int res_add_tx = dap_chain_ledger_tx_add(a_ledger, l_tx_to_addr3, &l_tx_addr3_hash, false);
-        if (res_add_tx == 1) {
+        if (!res_add_tx) {
             dap_fail("It was possible to carry out a transaction to a forbidden address");
         } else {
             dap_pass_msg("Transaction to banned address failed.");
@@ -349,8 +346,8 @@ void dap_chain_ledger_test_write_back_list(dap_ledger_t *a_ledger, dap_cert_t *a
                                                                                        *l_addr_2->addr, a_cert);
         dap_hash_fast_t l_btx_addr2_hash = {0};
         dap_hash_fast(l_btx_addr2, dap_chain_datum_tx_get_size(l_btx_addr2), &l_btx_addr2_hash);
-        dap_assert_PIF(dap_chain_ledger_tx_add(a_ledger, l_btx_addr2, &l_btx_addr2_hash, false) == 1,
-                       "Can't added base tx in white address");
+        dap_assert_PIF(!dap_chain_ledger_tx_add(a_ledger, l_btx_addr2, &l_btx_addr2_hash, false),
+                       "Can't add base tx in white address");
         //Check tx in addr from block list
         dap_chain_datum_tx_t *l_tx_to_addr1 = dap_chain_ledger_test_create_tx(l_addr_4->enc_key, &l_btx_addr2_hash,
                                                                               l_addr_1->addr, dap_chain_uint256_from(s_total_supply));
@@ -392,17 +389,18 @@ void dap_chain_ledger_test_run(void){
     dap_chain_datum_token_emission_t *l_emi = dap_chain_datum_emission_create(dap_chain_uint256_from(s_total_supply), s_token_ticker, &l_addr);
     dap_chain_datum_token_emission_t *l_emi_sign = dap_chain_datum_emission_add_sign(l_cert->enc_key, l_emi);
     size_t l_emi_size = dap_chain_datum_emission_get_size((byte_t*)l_emi_sign);
-    int l_emi_check = dap_chain_ledger_token_emission_add_check(l_ledger, (byte_t*)l_emi_sign, l_emi_size);
     dap_chain_hash_fast_t l_emi_hash = {0};
-    dap_assert_PIF(l_emi_check == 0, "check emission for add in ledger");
     dap_hash_fast(l_emi, l_emi_size, &l_emi_hash);
+    int l_emi_check = dap_chain_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_chain_ledger_token_emission_add(l_ledger, (byte_t*)l_emi_sign, l_emi_size, &l_emi_hash, false), "Added emission in ledger");
     //first base tx
-    dap_chain_datum_tx_t  *l_base_tx = dap_chain_ledger_test_create_datum_base_tx(l_emi_sign, &l_emi_hash, l_addr, l_cert);
-    dap_assert_PIF(!dap_chain_ledger_tx_add_check(l_ledger, l_base_tx), "Check can added base tx in ledger");
+    dap_chain_datum_tx_t *l_base_tx = dap_chain_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);
     dap_hash_fast_t l_hash_btx = {0};
-    dap_hash_fast(l_base_tx, dap_chain_datum_tx_get_size(l_base_tx), &l_hash_btx);
-    dap_assert_PIF(dap_chain_ledger_tx_add(l_ledger, l_base_tx, &l_hash_btx, false) == 1, "Added base tx in ledger.");
+    dap_hash_fast(l_base_tx, l_base_tx_size, &l_hash_btx);
+    dap_assert_PIF(!dap_chain_ledger_tx_add_check(l_ledger, l_base_tx, l_base_tx_size, &l_hash_btx), "Check can added base tx in ledger");
+    dap_assert_PIF(!dap_chain_ledger_tx_add(l_ledger, l_base_tx, &l_hash_btx, false), "Added base tx in ledger.");
     uint256_t l_balance_example = dap_chain_uint256_from(s_standard_value_tx);
     uint256_t l_balance = dap_chain_ledger_calc_balance(l_ledger, &l_addr, s_token_ticker);	
 	uint256_t l_fee = dap_chain_uint256_from(s_fee);
@@ -412,12 +410,13 @@ void dap_chain_ledger_test_run(void){
     dap_pass_msg("Validation of the declaration of the tocen, 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_chain_ledger_test_create_datum_base_tx(l_emi_sign, &l_emi_hash, l_addr, l_cert);
-    if (dap_chain_ledger_tx_add_check(l_ledger, l_base_tx_second)) {
+    size_t l_base_tx_size2 = dap_chain_datum_tx_get_size(l_base_tx_second);
+    dap_hash_fast_t l_hash_btx_second = {0};
+    dap_hash_fast(l_base_tx_second, l_base_tx_size2, &l_hash_btx_second);
+    if (dap_chain_ledger_tx_add_check(l_ledger, l_base_tx_second, l_base_tx_size2, &l_hash_btx_second)) {
         dap_pass_msg("Checking can added second base tx in ledger");
     }
-    dap_hash_fast_t l_hash_btx_second = {0};
-    dap_hash_fast(l_base_tx_second, dap_chain_datum_tx_get_size(l_base_tx_second), &l_hash_btx_second);
-    if (dap_chain_ledger_tx_add(l_ledger, l_base_tx_second, &l_hash_btx_second, false) != 1){
+    if (dap_chain_ledger_tx_add(l_ledger, l_base_tx_second, &l_hash_btx_second, false)){
         dap_pass_msg("Checking for a failure to add a second base transaction for the same issue to the ledger.");
     } else {
         dap_fail("Checking for a failure to add a second base transaction for the same issue to the ledger.");
diff --git a/modules/common/dap_chain_datum_tx.c b/modules/common/dap_chain_datum_tx.c
index 6d9b329728e48d4be6172eb36ef0bdd298be892a..6fdbfb13f137271b4fadb0e3fc7c499210fc1a7f 100644
--- a/modules/common/dap_chain_datum_tx.c
+++ b/modules/common/dap_chain_datum_tx.c
@@ -109,7 +109,7 @@ uint256_t dap_chain_datum_tx_add_in_item_list(dap_chain_datum_tx_t **a_tx, dap_l
     dap_list_t *l_list_tmp = a_list_used_out;
     uint256_t l_value_to_items = {}; // how many datoshi to transfer
     while (l_list_tmp) {
-        list_used_item_t *l_item = l_list_tmp->data;
+        dap_chain_tx_used_out_item_t *l_item = l_list_tmp->data;
         if (dap_chain_datum_tx_add_in_item(a_tx, &l_item->tx_hash_fast, l_item->num_idx_out) == 1) {
             SUM_256_256(l_value_to_items, l_item->value, &l_value_to_items);
         }
@@ -147,7 +147,7 @@ uint256_t dap_chain_datum_tx_add_in_cond_item_list(dap_chain_datum_tx_t **a_tx,
    dap_list_t *l_list_tmp = a_list_used_out_cound;
    uint256_t l_value_to_items = {};
    while (l_list_tmp) {
-       list_used_item_t *l_item = l_list_tmp->data;
+       dap_chain_tx_used_out_item_t *l_item = l_list_tmp->data;
        if (!dap_chain_datum_tx_add_in_cond_item(a_tx, &l_item->tx_hash_fast, l_item->num_idx_out,0)) {
            SUM_256_256(l_value_to_items, l_item->value, &l_value_to_items);
        }
diff --git a/modules/common/include/dap_chain_common.h b/modules/common/include/dap_chain_common.h
index bac63b331a4e0cf7bbc7948234e28b603c059f9e..c50abe1681d57dc7efcc85ba3782a998d81663ac 100644
--- a/modules/common/include/dap_chain_common.h
+++ b/modules/common/include/dap_chain_common.h
@@ -109,7 +109,7 @@ DAP_STATIC_INLINE int dap_chain_node_addr_from_str(dap_chain_node_addr_t *a_addr
 {
     if (sscanf(a_addr_str, NODE_ADDR_FP_STR, NODE_ADDR_FPS_ARGS(a_addr)) == 4)
         return 0;
-    if (sscanf(a_addr_str, "0x%016"DAP_UINT64_FORMAT_x, &a_addr->uint64) == 1)
+    if (sscanf(a_addr_str, "0x%016" DAP_UINT64_FORMAT_x, &a_addr->uint64) == 1)
         return 0;
     return -1;
 }
diff --git a/modules/common/include/dap_chain_datum.h b/modules/common/include/dap_chain_datum.h
index 62d8c8d130e9df227c94c01c178be620a674e80d..b4ada48ae9a28b4398500fe587098cd46709874e 100644
--- a/modules/common/include/dap_chain_datum.h
+++ b/modules/common/include/dap_chain_datum.h
@@ -131,23 +131,6 @@ typedef struct dap_chain_datum{
     byte_t data[]; /// Stored datum body
 } DAP_ALIGN_PACKED dap_chain_datum_t;
 
-
-struct dap_chain;
-typedef struct dap_chain dap_chain_t;
-
-typedef struct dap_chain_datum_iter{
-    dap_chain_t * chain;
-    dap_chain_datum_t * cur;
-    void * cur_item;
-    void * atom_iter;
-} dap_chain_datum_iter_t;
-
-typedef dap_chain_datum_iter_t* (*dap_chain_datum_callback_iter_create_t)(dap_chain_t * );
-typedef dap_chain_datum_t* (*dap_chain_datum_callback_iter_get_first_t)(dap_chain_datum_iter_t * );
-typedef dap_chain_datum_t* (*dap_chain_datum_callback_iter_get_next_t)(dap_chain_datum_iter_t *  );
-typedef void (*dap_chain_datum_callback_iter_delete_t)(dap_chain_datum_iter_t *  );
-
-
 /**
  * @brief dap_chain_datum_size
  * @param a_datum
diff --git a/modules/common/include/dap_chain_datum_tx_in.h b/modules/common/include/dap_chain_datum_tx_in.h
index d4e2bc68f303f4da7c273f8c8119afc44b372919..fcc2361c0594d537409972ea244e2eebe88fd661 100644
--- a/modules/common/include/dap_chain_datum_tx_in.h
+++ b/modules/common/include/dap_chain_datum_tx_in.h
@@ -40,9 +40,8 @@ typedef struct dap_chain_tx_in{
     } header; /// Only header's hash is used for verification
 } DAP_ALIGN_PACKED dap_chain_tx_in_t;
 
-typedef struct list_used_item {
+typedef struct dap_chain_tx_used_out_item {
     dap_chain_hash_fast_t tx_hash_fast;
     uint32_t num_idx_out;
-    uint8_t padding[4];
     uint256_t value;
-} list_used_item_t;
+} dap_chain_tx_used_out_item_t;
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 4a195c08806a81215a1220b125f358c2994f45f4..01b1b0d5c065876e894ffda13a518afbbe434f4b 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -569,11 +569,10 @@ static void s_callback_round_event_to_chain_callback_get_round_item(dap_global_d
     if (l_chosen_item) {
         size_t l_event_size = l_chosen_item->event_size;
         dap_chain_cs_dag_event_t *l_new_atom = (dap_chain_cs_dag_event_t *)DAP_DUP_SIZE(l_chosen_item->event_n_signs, l_event_size);
-        char *l_event_hash_hex_str, *l_datum_hash_str;
+        char *l_event_hash_hex_str;
         dap_get_data_hash_str_static(l_new_atom, l_event_size, l_event_hash_hex_str);
         dap_chain_datum_t *l_datum = dap_chain_cs_dag_event_get_datum(l_new_atom, l_event_size);
-        dap_get_data_hash_str_static(l_datum, dap_chain_datum_size(l_datum), l_datum_hash_str);
-        int l_verify_datum = dap_chain_net_verify_datum_for_add(dap_chain_net_by_id(l_dag->chain->net_id), l_datum);
+        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);
             if (l_res == ATOM_ACCEPT) {
@@ -590,6 +589,8 @@ static void s_callback_round_event_to_chain_callback_get_round_item(dap_global_d
                    l_event_hash_hex_str, l_arg->round_id, dap_chain_atom_verify_res_str[l_res]);
         } else {
             DAP_DELETE(l_new_atom);
+            char l_datum_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
+            dap_chain_hash_fast_to_str(&l_chosen_item->round_info.datum_hash, l_datum_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE);
             log_it(L_INFO, "Event %s from round %"DAP_UINT64_FORMAT_U" not added into chain, because the inner datum %s doesn't pass verification (error %d)",
                    l_event_hash_hex_str, l_arg->round_id, l_datum_hash_str, l_verify_datum);
         }
diff --git a/modules/consensus/none/dap_chain_cs_none.c b/modules/consensus/none/dap_chain_cs_none.c
index 96731e5774fe7117c44f40fe9b7d3dd10e922dee..608ea742ffe1cd4c9cc7cc9ece14dc0e1858a2dd 100644
--- a/modules/consensus/none/dap_chain_cs_none.c
+++ b/modules/consensus/none/dap_chain_cs_none.c
@@ -363,7 +363,9 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
     dap_chain_gdb_t * l_gdb = DAP_CHAIN_GDB(a_chain);
     dap_chain_gdb_private_t *l_gdb_priv = PVT(l_gdb);
     dap_chain_datum_t *l_datum = (dap_chain_datum_t*) a_atom;
-    if(dap_chain_datum_add(a_chain, l_datum, a_atom_size, NULL))
+    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))
         return ATOM_REJECT;
 
     dap_chain_gdb_datum_hash_item_t * l_hash_item = DAP_NEW_Z(dap_chain_gdb_datum_hash_item_t);
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index f761fb8c23b48107f610817d93d385de568e20c0..ba72fe5a03c508d4defb77a2251f85b84ba621fa 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -429,7 +429,7 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
 
         // Add in and remove out used items
         while(l_list_tmp) {
-            list_used_item_t *l_item = l_list_tmp->data;
+            dap_chain_tx_used_out_item_t *l_item = l_list_tmp->data;
             char l_in_hash_str[70];
 
             dap_chain_hash_fast_to_str(&l_item->tx_hash_fast,l_in_hash_str,sizeof (l_in_hash_str) );
@@ -530,7 +530,7 @@ int dap_chain_mempool_tx_create_massive( dap_chain_t * a_chain, dap_enc_key_t *a
                     continue;
                 }
                 if ( memcmp(&l_out->addr, a_addr_from, sizeof (*a_addr_from))==0 ){
-                    list_used_item_t *l_item_back = DAP_NEW_Z(list_used_item_t);
+                    dap_chain_tx_used_out_item_t *l_item_back = DAP_NEW_Z(dap_chain_tx_used_out_item_t);
                     l_item_back->tx_hash_fast = l_tx_new_hash;
                     l_item_back->num_idx_out = l_out_idx_tmp;
                     l_item_back->value = l_value_back;
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index a38703a27067b7a106b36c68b1e8b3955adc8cc3..3c3baa7fb92fc4f34ff398da0076780ba7944b6f 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -283,7 +283,7 @@ static void s_update_links_timer_callback(void *a_arg){
     //Updated links
     size_t l_count_downlinks = 0;
     dap_stream_connection_t ** l_downlinks = dap_stream_connections_get_downlinks(&l_count_downlinks);
-    DAP_DELETE(l_downlinks);
+    DAP_DEL_Z(l_downlinks);
     dap_chain_node_addr_t *l_current_addr = dap_chain_net_get_cur_addr(l_net);
     dap_chain_node_info_t *l_node_info = dap_chain_node_info_read(l_net, l_current_addr);
     if (!l_node_info)
@@ -2771,7 +2771,7 @@ int s_net_load(dap_chain_net_t *a_net)
     uint32_t l_timeout = dap_config_get_item_uint32_default(g_config, "node_client", "timer_update_states", 600);
     PVT(l_net)->main_timer = dap_interval_timer_create(l_timeout * 1000, s_main_timer_callback, l_net);
     log_it(L_INFO, "Chain network \"%s\" initialized",l_net->pub.name);
-    PVT(l_net)->update_links_timer = dap_interval_timer_create(600000, s_update_links_timer_callback, l_net);
+    PVT(l_net)->update_links_timer = dap_interval_timer_create(600 * 1000, s_update_links_timer_callback, l_net);
 
     dap_config_close(l_cfg);
 
@@ -3149,87 +3149,6 @@ bool dap_chain_net_get_flag_sync_from_zero( dap_chain_net_t * a_net)
     return PVT(a_net)->flags &F_DAP_CHAIN_NET_SYNC_FROM_ZERO ;
 }
 
-
-void s_proc_mempool_callback_load(dap_global_db_context_t *a_global_db_context,
-                                  int a_rc, const char *a_group,
-                                  const size_t a_values_total, const size_t a_values_count,
-                                  dap_global_db_obj_t *a_values, void *a_arg)
-{
-    dap_chain_t * l_chain = (dap_chain_t*) a_arg;
-    dap_chain_net_t * l_net = dap_chain_net_by_id( l_chain->net_id );
-    if(a_values_count) {
-        log_it(L_INFO, "%s.%s: Found %zu records :", l_net->pub.name, l_chain->name,
-                a_values_count);
-        size_t l_datums_size = a_values_count;
-        dap_chain_datum_t ** l_datums = DAP_NEW_Z_SIZE(dap_chain_datum_t*,
-                sizeof(dap_chain_datum_t*) * l_datums_size);
-        size_t l_objs_size_tmp = (a_values_count > 15) ? min(a_values_count, 10) : a_values_count;
-        for(size_t i = 0; i < a_values_count; i++) {
-            dap_chain_datum_t * l_datum = (dap_chain_datum_t*) a_values[i].value;
-            int l_dup_or_skip = dap_chain_datum_unledgered_search_iter(l_datum, l_chain);
-            if (l_dup_or_skip) {
-                log_it(L_WARNING, "Datum unledgered search returned '%d', delete it from mempool", l_dup_or_skip);
-                dap_global_db_del_unsafe(a_global_db_context, a_group, a_values[i].key);
-                l_datums[i] = NULL;
-                continue;
-            }
-
-            int l_verify_datum = dap_chain_net_verify_datum_for_add( l_net, l_datum) ;
-            if (l_verify_datum != 0){
-                log_it(L_WARNING, "Datum doesn't pass verifications (code %d), delete such datum from pool", l_verify_datum);
-                dap_global_db_del_unsafe(a_global_db_context, a_group, a_values[i].key);
-                l_datums[i] = NULL;
-            } else {
-                l_datums[i] = l_datum;
-                if(i < l_objs_size_tmp) {
-                    char buf[50] = { '\0' };
-                    const char *l_type = NULL;
-                    DAP_DATUM_TYPE_STR(l_datum->header.type_id, l_type)
-                    dap_time_t l_ts_create = (dap_time_t) l_datum->header.ts_create;
-                    log_it(L_INFO, "\t\t0x%s: type_id=%s ts_create=%s data_size=%u",
-                            a_values[i].key, l_type,
-                            dap_ctime_r(&l_ts_create, buf), l_datum->header.data_size);
-                }
-            }
-        }
-        size_t l_objs_processed = l_chain->callback_add_datums(l_chain, l_datums, l_datums_size);
-        // Delete processed objects
-        size_t l_objs_processed_tmp = (l_objs_processed > 15) ? min(l_objs_processed, 10) : l_objs_processed;
-        for (size_t i = 0; i < l_objs_processed; i++) {
-            dap_global_db_del_unsafe(a_global_db_context, a_group, a_values[i].key);
-            log_it(L_WARNING, "New event created, removed datum 0x%s from mempool \n", a_values[i].key);
-        }
-        debug_if(l_objs_processed < l_datums_size, L_WARNING, "%s.%s: %zu records not processed",
-                 l_net->pub.name, l_chain->name, l_datums_size - l_objs_processed);
-        dap_global_db_objs_delete(a_values, a_values_count);
-
-        // Cleanup datums array
-        if (l_datums){
-            for (size_t i = 0; i < a_values_count; i++) {
-                DAP_DEL_Z(l_datums[i]);
-            }
-            DAP_DELETE(l_datums);
-        }
-    } else {
-        log_it(L_INFO, "%s.%s: No records in mempool", l_net->pub.name, l_chain ? l_chain->name : "[no chain]");
-    }
-}
-
-
-/**
- * @brief dap_chain_net_proc_datapool
- * @param a_net
- */
-void dap_chain_net_proc_mempool (dap_chain_net_t * a_net)
-{
-    dap_chain_t *l_chain;
-    DL_FOREACH(a_net->pub.chains, l_chain) {
-        char *l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
-        dap_global_db_get_all(l_gdb_group_mempool,0,s_proc_mempool_callback_load, l_chain);
-        DAP_DELETE(l_gdb_group_mempool);
-    }
-}
-
 /**
  * @brief dap_chain_net_get_extra_gdb_group
  * @param a_net
@@ -3248,6 +3167,13 @@ bool dap_chain_net_get_extra_gdb_group(dap_chain_net_t *a_net, dap_chain_node_ad
     return false;
 }
 
+void dap_chain_net_proc_mempool(dap_chain_net_t *a_net)
+{
+    dap_chain_t *l_chain;
+    DL_FOREACH(a_net->pub.chains, l_chain)
+        dap_chain_node_mempool_process_all(l_chain, true);
+}
+
 /**
  * @brief dap_chain_net_verify_datum_for_add
  * process datum verification process. Can be:
@@ -3259,25 +3185,30 @@ bool dap_chain_net_get_extra_gdb_group(dap_chain_net_t *a_net, dap_chain_node_ad
  * @param a_datum
  * @return
  */
-int dap_chain_net_verify_datum_for_add(dap_chain_net_t *a_net, dap_chain_datum_t * a_datum )
+int dap_chain_net_verify_datum_for_add(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, dap_hash_fast_t *a_datum_hash)
 {
-    if( ! a_datum)
+    if (!a_datum)
         return -10;
-    if( ! a_net )
+    if (!a_chain)
         return -11;
-    switch ( a_datum->header.type_id) {
-        case DAP_CHAIN_DATUM_TX:
-            return dap_chain_ledger_tx_add_check( a_net->pub.ledger, (dap_chain_datum_tx_t*)a_datum->data );
-        case DAP_CHAIN_DATUM_TOKEN_DECL:
-            return dap_chain_ledger_token_decl_add_check( a_net->pub.ledger, (dap_chain_datum_token_t *)a_datum->data, a_datum->header.data_size);
-        case DAP_CHAIN_DATUM_TOKEN_EMISSION:
-            return dap_chain_ledger_token_emission_add_check( a_net->pub.ledger, a_datum->data, a_datum->header.data_size );
-        case DAP_CHAIN_DATUM_DECREE:
-            return dap_chain_net_decree_verify((dap_chain_datum_decree_t*)a_datum->data, a_net, a_datum->header.data_size, NULL);
-        case DAP_CHAIN_DATUM_ANCHOR:
-            return dap_chain_net_anchor_verify((dap_chain_datum_anchor_t*)a_datum->data, a_datum->header.data_size);
-    default: return 0;
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
+    switch (a_datum->header.type_id) {
+    case DAP_CHAIN_DATUM_TX:
+        return dap_chain_ledger_tx_add_check(l_net->pub.ledger, (dap_chain_datum_tx_t *)a_datum->data, a_datum->header.data_size, a_datum_hash);
+    case DAP_CHAIN_DATUM_TOKEN_DECL:
+        return dap_chain_ledger_token_decl_add_check(l_net->pub.ledger, (dap_chain_datum_token_t *)a_datum->data, a_datum->header.data_size);
+    case DAP_CHAIN_DATUM_TOKEN_EMISSION:
+        return dap_chain_ledger_token_emission_add_check(l_net->pub.ledger, a_datum->data, a_datum->header.data_size, a_datum_hash);
+    case DAP_CHAIN_DATUM_DECREE:
+        return dap_chain_net_decree_verify((dap_chain_datum_decree_t *)a_datum->data, l_net, a_datum->header.data_size, a_datum_hash);
+    case DAP_CHAIN_DATUM_ANCHOR:
+        return dap_chain_net_anchor_verify((dap_chain_datum_anchor_t *)a_datum->data, a_datum->header.data_size);
+    default:
+        if (a_chain->callback_datum_find_by_hash &&
+                a_chain->callback_datum_find_by_hash(a_chain, a_datum_hash, NULL, NULL))
+            return -1;
     }
+    return 0;
 }
 
 /**
@@ -3380,18 +3311,14 @@ static uint8_t *s_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash)
 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)
 {
     dap_list_t *l_list = NULL;
-    if(!a_net)
-//        return l_list;
-//    void *l_chain_tmp = (void*) 0x1;
-//    dap_chain_t *l_chain_cur;
+    if (!a_net)
         return NULL;
-    void *l_chain_tmp = (void*) 0x1;
-    dap_chain_t *l_chain_cur = a_chain ? a_chain : dap_chain_enum(&l_chain_tmp);
+    dap_chain_t *l_chain_cur = a_chain ? a_chain : a_net->pub.chains;
     size_t l_sz;
 
     while(l_chain_cur) {
         // Use chain only for selected net and with callback_atom_get_datums
-        if(a_net->pub.id.uint64 == l_chain_cur->net_id.uint64 && l_chain_cur->callback_atom_get_datums)
+        if (l_chain_cur->callback_atom_get_datums)
         {
             dap_chain_cell_t *l_cell = l_chain_cur->cells;
             size_t l_atom_size = 0;
@@ -3406,29 +3333,19 @@ dap_list_t* dap_chain_datum_list(dap_chain_net_t *a_net, dap_chain_t *a_chain, d
                     if ( ! (l_datum = l_datums[l_datum_n]) )
                         continue;
 
-                    if ( a_filter_func)
-                        if ( !a_filter_func(l_datum, l_chain_cur, a_filter_func_param) )
-                            continue;
-//                    if(l_datum) {
-//                        // If there is a filter, then check the datum in it
-//                        if(a_filter_func) {
-//                            if(a_filter_func(l_datum, l_chain_cur, a_filter_func_param))
-//                                l_list = dap_list_append(l_list, l_datum);
-//                        }
-//                        else
-//                            l_list = dap_list_append(l_list, l_datum);
-//                    }
+                    if (a_filter_func && !a_filter_func(l_datum, l_chain_cur, a_filter_func_param))
+                        continue;
                     /*
                     * Make a copy of the datum, copy is placed into the list,
                     * so don't forget to free whole list
                     */
-                   l_sz = sizeof(dap_chain_datum_t) + l_datum->header.data_size + 16;
-                   l_datum2 = DAP_NEW_Z_SIZE(dap_chain_datum_t, l_sz);
-                   assert ( l_datum2 );
-                   memcpy(l_datum2, l_datum, l_sz);
+                    l_sz = sizeof(dap_chain_datum_t) + l_datum->header.data_size + 16;
+                    l_datum2 = DAP_NEW_Z_SIZE(dap_chain_datum_t, l_sz);
+                    assert ( l_datum2 );
+                    memcpy(l_datum2, l_datum, l_sz);
 
-                   /* Add new entry into the list */
-                   l_list = dap_list_append(l_list, l_datum2);
+                    /* Add new entry into the list */
+                    l_list = dap_list_append(l_list, l_datum2);
 
                 }
                 DAP_DEL_Z(l_datums);
@@ -3441,8 +3358,7 @@ dap_list_t* dap_chain_datum_list(dap_chain_net_t *a_net, dap_chain_t *a_chain, d
         if(a_chain)
             break;
         // go to next chain
-        dap_chain_enum_unlock();
-        l_chain_cur = dap_chain_enum(&l_chain_tmp);
+        l_chain_cur = l_chain_cur->next;
     }
     return l_list;
 }
@@ -3454,28 +3370,30 @@ dap_list_t* dap_chain_datum_list(dap_chain_net_t *a_net, dap_chain_t *a_chain, d
  * @param a_datum_size
  * @return
  */
-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_tx_hash)
+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)
 {
     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 equel or less datum size %zd",a_datum->header.data_size+ sizeof (a_datum->header),
+    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;
     }
     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;
-            if(sizeof(l_decree->header) + l_decree->header.data_size + l_decree->header.signs_size > l_datum_data_size){
-                log_it(L_WARNING, "Corrupted decree, size %zd is smaller than ever decree header's size %zd", l_datum_data_size, sizeof(l_decree->header));
+        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 dap_chain_net_decree_load(l_decree, a_chain);
+            return 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;
-            if(sizeof(l_anchor->header) + l_anchor->header.data_size + l_anchor->header.signs_size > l_datum_data_size){
-                log_it(L_WARNING, "Corrupted anchor, size %zd is smaller than ever anchor header's size %zd", l_datum_data_size, sizeof(l_anchor->header));
-                return -103;
+        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_load(l_anchor, a_chain);
         }
@@ -3483,18 +3401,21 @@ int dap_chain_datum_add(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, size_t
             return dap_chain_ledger_token_load(a_chain->ledger, (dap_chain_datum_token_t *)a_datum->data, a_datum->header.data_size);
 
         case DAP_CHAIN_DATUM_TOKEN_EMISSION:
-            return dap_chain_ledger_token_emission_load(a_chain->ledger, a_datum->data, a_datum->header.data_size);
+            return dap_chain_ledger_token_emission_load(a_chain->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;
-            // Check tx correcntess
-            int res = dap_chain_ledger_tx_load(a_chain->ledger, l_tx, a_tx_hash);
-            return res == 1 ? 0 : res;
+        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_chain_ledger_tx_load(a_chain->ledger, l_tx, a_datum_hash);
         }
         case DAP_CHAIN_DATUM_CA:
             return dap_cert_chain_file_save(a_datum, a_chain->net_name);
+
         case DAP_CHAIN_DATUM_SIGNER:
-            break;
         case DAP_CHAIN_DATUM_CUSTOM:
             break;
         default:
diff --git a/modules/net/dap_chain_net_anchor.c b/modules/net/dap_chain_net_anchor.c
index fa330f1ef7a5d949d7622bd64c88382743cc9cbe..4e8ac387c31c7e23abe20bba62e6b56462701fa3 100644
--- a/modules/net/dap_chain_net_anchor.c
+++ b/modules/net/dap_chain_net_anchor.c
@@ -38,7 +38,7 @@ static bool s_verify_pubkeys(dap_sign_t *a_sign, dap_sign_t **a_decree_signs, si
 static inline dap_sign_t *s_concate_all_signs_in_array(dap_sign_t *a_in_signs, size_t a_signs_size, size_t *a_sings_count, size_t *a_signs_arr_size);
 
 // Public functions
-int dap_chain_net_anchor_verify(dap_chain_datum_anchor_t * a_anchor, size_t a_data_size)
+int dap_chain_net_anchor_verify(dap_chain_datum_anchor_t *a_anchor, size_t a_data_size)
 {
     if (a_data_size < sizeof(dap_chain_datum_anchor_t)) {
         log_it(L_WARNING, "Anchor size is too small");
diff --git a/modules/net/dap_chain_net_decree.c b/modules/net/dap_chain_net_decree.c
index 152848407419f74fdc51ed0df864f03b5d7806bc..a334887a54080d69e104c230cd89a922880f2d64 100644
--- a/modules/net/dap_chain_net_decree.c
+++ b/modules/net/dap_chain_net_decree.c
@@ -147,7 +147,7 @@ int s_decree_verify_tsd(dap_chain_datum_decree_t * a_decree, dap_chain_net_t *a_
     return ret_val;
 }
 
-int dap_chain_net_decree_verify(dap_chain_datum_decree_t *a_decree, dap_chain_net_t *a_net, size_t a_data_size, dap_hash_fast_t *a_decree_hash)
+int dap_chain_net_decree_verify(dap_chain_datum_decree_t *a_decree, dap_chain_net_t *a_net, size_t a_data_size, dap_chain_hash_fast_t *a_decree_hash)
 {
     if (a_data_size < sizeof(dap_chain_datum_decree_t)) {
         log_it(L_WARNING, "Decree size is too small");
@@ -162,14 +162,10 @@ int dap_chain_net_decree_verify(dap_chain_datum_decree_t *a_decree, dap_chain_ne
         return -122;
     }
 
-    dap_hash_fast_t l_decree_hash;
-    dap_hash_fast(a_decree, a_data_size, &l_decree_hash);
-    if (a_decree_hash)
-        *a_decree_hash = l_decree_hash;
     struct decree_hh *l_decree_hh = NULL;
-    HASH_FIND(hh, s_decree_hh, &l_decree_hash, sizeof(dap_hash_fast_t), l_decree_hh);
+    HASH_FIND(hh, s_decree_hh, a_decree_hash, sizeof(dap_hash_fast_t), l_decree_hh);
     if (l_decree_hh)
-        return DAP_DECREE_IS_PRESENT;
+        return -123;
 
     dap_chain_datum_decree_t *l_decree = a_decree;
     // Get pkeys sign from decree datum
@@ -227,14 +223,14 @@ int dap_chain_net_decree_verify(dap_chain_datum_decree_t *a_decree, dap_chain_ne
 
     if (l_signs_verify_counter < l_min_signs) {
         log_it(L_WARNING,"Not enough valid signatures, get %hu from %hu", l_signs_verify_counter, l_min_signs);
-        return -106;
+        return -107;
     }
 
     // check tsd-section
     if (s_decree_verify_tsd(a_decree, a_net))
     {
         log_it(L_WARNING,"TSD checking error. Decree verification failed");
-        return -106;
+        return -108;
     }
 
     return 0;
@@ -302,7 +298,7 @@ int dap_chain_net_decree_apply(dap_hash_fast_t *a_decree_hash, dap_chain_datum_d
     return ret_val;
 }
 
-int dap_chain_net_decree_load(dap_chain_datum_decree_t * a_decree, dap_chain_t *a_chain)
+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 ret_val = 0;
     if (!a_chain || !a_chain)
@@ -319,15 +315,14 @@ int dap_chain_net_decree_load(dap_chain_datum_decree_t * a_decree, dap_chain_t *
         return -108;
     }
 
-    dap_hash_fast_t l_hash = {};
     size_t l_data_size = dap_chain_datum_decree_get_size(a_decree);
 
-    if ((ret_val = dap_chain_net_decree_verify(a_decree, l_net, l_data_size, &l_hash)) != 0) {
+    if ((ret_val = dap_chain_net_decree_verify(a_decree, l_net, l_data_size, a_decree_hash)) != 0) {
         log_it(L_ERROR,"Decree verification failed!");
         return ret_val;
     }
 
-    return dap_chain_net_decree_apply(&l_hash, a_decree, a_chain);
+    return dap_chain_net_decree_apply(a_decree_hash, a_decree, a_chain);
 }
 
 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/dap_chain_net_tx.c b/modules/net/dap_chain_net_tx.c
index 6461036c9cdf4ed9792579bab4f7c2884460132e..6253b664fe356614d2b79e989eb638041c675514 100644
--- a/modules/net/dap_chain_net_tx.c
+++ b/modules/net/dap_chain_net_tx.c
@@ -577,43 +577,37 @@ uint256_t dap_chain_net_get_tx_total_value(dap_chain_net_t * a_net, dap_chain_da
  * @param a_search_type
  * @return
  */
-dap_chain_datum_tx_t * dap_chain_net_get_tx_by_hash(dap_chain_net_t * a_net, dap_chain_hash_fast_t * a_tx_hash,
-                                                     dap_chain_net_tx_search_type_t a_search_type)
+dap_chain_datum_tx_t *dap_chain_net_get_tx_by_hash(dap_chain_net_t *a_net, dap_chain_hash_fast_t *a_tx_hash,
+                                                   dap_chain_net_tx_search_type_t a_search_type)
 {
-    dap_ledger_t * l_ledger = a_net->pub.ledger;
-    dap_chain_datum_tx_t * l_tx = NULL;
-
+    dap_ledger_t *l_ledger = a_net->pub.ledger;
     switch (a_search_type) {
-        case TX_SEARCH_TYPE_NET:
-        case TX_SEARCH_TYPE_CELL:
-        case TX_SEARCH_TYPE_LOCAL:
-        case TX_SEARCH_TYPE_CELL_SPENT:
-        case TX_SEARCH_TYPE_NET_SPENT: {
-
-            if ( ! l_tx ){
-                // pass all chains
-                for ( dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next){
-                    if ( l_chain->callback_tx_find_by_hash ){
-                        // try to find transaction in chain ( inside shard )
-                        l_tx = l_chain->callback_tx_find_by_hash(l_chain, a_tx_hash, NULL);
-                        if (l_tx) {
-                            if ((a_search_type == TX_SEARCH_TYPE_CELL_SPENT ||
-                                    a_search_type == TX_SEARCH_TYPE_NET_SPENT) &&
-                                    (!dap_chain_ledger_tx_spent_find_by_hash(l_ledger, a_tx_hash)))
-                                return NULL;
-                            break;
-                        }
-                    }
-                }
-            }
-        } break;
-
-        case TX_SEARCH_TYPE_NET_UNSPENT:
-        case TX_SEARCH_TYPE_CELL_UNSPENT:
-            l_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, a_tx_hash);
-            break;
+    case TX_SEARCH_TYPE_NET:
+    case TX_SEARCH_TYPE_CELL:
+    case TX_SEARCH_TYPE_LOCAL:
+    case TX_SEARCH_TYPE_CELL_SPENT:
+    case TX_SEARCH_TYPE_NET_SPENT:
+        // pass all chains
+        for (dap_chain_t * l_chain = a_net->pub.chains; l_chain; l_chain = l_chain->next) {
+            if (!l_chain->callback_datum_find_by_hash)
+                return NULL;
+            // try to find transaction in chain ( inside shard )
+            int l_ret_code;
+            dap_chain_datum_t *l_datum = l_chain->callback_datum_find_by_hash(l_chain, a_tx_hash, NULL, &l_ret_code);
+            if (!l_datum || l_datum->header.type_id != DAP_CHAIN_DATUM_TX)
+                return NULL;
+            if ((a_search_type == TX_SEARCH_TYPE_CELL_SPENT ||
+                    a_search_type == TX_SEARCH_TYPE_NET_SPENT) &&
+                    (!dap_chain_ledger_tx_spent_find_by_hash(l_ledger, a_tx_hash)))
+                return NULL;
+            return (dap_chain_datum_tx_t *)l_datum->data;
+        }
+    case TX_SEARCH_TYPE_NET_UNSPENT:
+    case TX_SEARCH_TYPE_CELL_UNSPENT:
+        return dap_chain_ledger_tx_find_by_hash(l_ledger, a_tx_hash);
+    default:;
     }
-    return l_tx;
+    return NULL;
 }
 
 static struct net_fee {
diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c
index bd2a1250e054626f3dd7dfc3bade4eb1ba2ffc43..a190fa3426574d89d5979e8bab30d82cb47a474d 100644
--- a/modules/net/dap_chain_node.c
+++ b/modules/net/dap_chain_node.c
@@ -206,13 +206,23 @@ bool dap_chain_node_mempool_need_process(dap_chain_t *a_chain, dap_chain_datum_t
 }
 
 /* Return true if processed datum should be deleted from mempool */
-bool dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum) {
-    if (!a_chain->callback_add_datums)
+bool dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, const char *a_datum_hash_str)
+{
+    if (!a_chain->callback_add_datums) {
+        log_it(L_ERROR, "Not found chain callback for datums processing");
         return false;
-    if (dap_chain_datum_unledgered_search_iter(a_datum, a_chain))
-            return true; /* Already chained, no need to keep duplicates */
-    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
-    int l_verify_datum = dap_chain_net_verify_datum_for_add(l_net, a_datum);
+    }
+    dap_hash_fast_t l_datum_hash, l_real_hash;
+    if (dap_chain_hash_fast_from_hex_str(a_datum_hash_str, &l_datum_hash)) {
+        log_it(L_WARNING, "Can't get datum hash from hash string");
+        return false;
+    }
+    dap_hash_fast(a_datum->data, a_datum->header.data_size, &l_real_hash);
+    if (!dap_hash_fast_compare(&l_datum_hash, &l_real_hash)) {
+        log_it(L_WARNING, "Datum hash from mempool key and real datum hash are different");
+        return false;
+    }
+    int l_verify_datum = dap_chain_net_verify_datum_for_add(a_chain, a_datum, &l_datum_hash);
     if (l_verify_datum != 0 &&
             l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS &&
             l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION &&
@@ -263,7 +273,7 @@ void dap_chain_node_mempool_process_all(dap_chain_t *a_chain, bool a_force)
                     }
                 }
 
-                if (dap_chain_node_mempool_process(a_chain, l_datum)) {
+                if (dap_chain_node_mempool_process(a_chain, l_datum, l_objs[i].key)) {
                     // Delete processed objects
                     log_it(L_INFO, " ! Delete datum %s from mempool", l_objs[i].key);
                     dap_global_db_del(l_gdb_group_mempool, l_objs[i].key, NULL, NULL);
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 142fa5ee9b3fea0972ce6fe429b6c1023ef631d4..8c266c652e2b4fb8377de960e5d43ae2d2c4422b 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -2951,15 +2951,6 @@ int com_mempool_proc(int a_argc, char **a_argv, char **a_str_reply)
     dap_chain_t * l_chain = NULL;
     dap_chain_net_t * l_net = NULL;
 
-    const char * l_hash_out_type = NULL;
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-H", &l_hash_out_type);
-    if(!l_hash_out_type)
-        l_hash_out_type = "hex";
-    if(dap_strcmp(l_hash_out_type,"hex") && dap_strcmp(l_hash_out_type,"base58")) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "invalid parameter -H, valid values: -H <hex | base58>");
-        return -1;
-    }
-
     dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index, a_argc, a_argv, a_str_reply, &l_chain, &l_net);
     if (!l_net || !l_chain)
         return -1;
@@ -2969,10 +2960,6 @@ int com_mempool_proc(int a_argc, char **a_argv, char **a_str_reply)
         *a_str_reply = NULL;
     }
 
-    char * l_gdb_group_mempool = NULL, *l_gdb_group_mempool_tmp;
-    l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
-    l_gdb_group_mempool_tmp = l_gdb_group_mempool;
-
     // If full or light it doesnt work
     if(dap_chain_net_get_role(l_net).enums>= NODE_ROLE_FULL){
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Need master node role or higher for network %s to process this command", l_net->pub.name);
@@ -2982,89 +2969,85 @@ int com_mempool_proc(int a_argc, char **a_argv, char **a_str_reply)
     const char * l_datum_hash_str = NULL;
     int ret = 0;
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-datum", &l_datum_hash_str);
-    if(l_datum_hash_str) {
-        char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
-        dap_string_t * l_str_tmp = dap_string_new(NULL);
-        size_t l_datum_size=0;
-        const char *l_datum_hash_out_str;
-        char *l_datum_hash_hex_str;
-        char *l_datum_hash_base58_str;
-        // datum hash may be in hex or base58 format
-        if(!dap_strncmp(l_datum_hash_str, "0x", 2) || !dap_strncmp(l_datum_hash_str, "0X", 2)) {
-            l_datum_hash_hex_str = dap_strdup(l_datum_hash_str);
-            l_datum_hash_base58_str = dap_enc_base58_from_hex_str_to_str(l_datum_hash_str);
-        }
-        else {
-            l_datum_hash_hex_str = dap_enc_base58_to_hex_str_from_str(l_datum_hash_str);
-            l_datum_hash_base58_str = dap_strdup(l_datum_hash_str);
-        }
-        if(!dap_strcmp(l_hash_out_type,"hex"))
-            l_datum_hash_out_str = l_datum_hash_hex_str;
-        else
-            l_datum_hash_out_str = l_datum_hash_base58_str;
+    if (!l_datum_hash_str) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! %s requires -datum <datum hash> option", a_argv[0]);
+        return -5;
+    }
+    char *l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool_new(l_chain);
+    dap_string_t * l_str_tmp = dap_string_new(NULL);
+    size_t l_datum_size=0;
 
-        dap_chain_datum_t * l_datum = l_datum_hash_hex_str ? (dap_chain_datum_t*) dap_global_db_get_sync(l_gdb_group_mempool, l_datum_hash_hex_str,
-                                                                                       &l_datum_size, NULL, NULL ) : NULL;
-        size_t l_datum_size2 = l_datum? dap_chain_datum_size( l_datum): 0;
-        if (l_datum_size != l_datum_size2) {
-            ret = -8;
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Corrupted datum %s, size by datum headers is %zd when in mempool is only %zd bytes",
-                                              l_datum_hash_hex_str, l_datum_size2, l_datum_size);
-        } else {
-            if (l_datum) {
-                char buf[50];
-                dap_time_t l_ts_create = (dap_time_t)l_datum->header.ts_create;
-                const char *l_type = NULL;
-                DAP_DATUM_TYPE_STR(l_datum->header.type_id, l_type);
-                dap_string_append_printf(l_str_tmp, "hash %s: type_id=%s ts_create=%s data_size=%u\n",
-                        l_datum_hash_out_str, l_type,
-                        dap_ctime_r(&l_ts_create, buf), l_datum->header.data_size);
-                int l_verify_datum= dap_chain_net_verify_datum_for_add( l_net, l_datum) ;
-                int l_dup_or_skip = dap_chain_datum_unledgered_search_iter(l_datum, l_chain);
-                if (l_dup_or_skip) {
-                    dap_string_append_printf(l_str_tmp, "Error! Datum unledgered search returned '%d'", l_dup_or_skip);
-                    dap_global_db_del_sync(l_datum_hash_hex_str, l_gdb_group_mempool);
-                    ret = -10;
-                } else {
-                    int l_verify_datum = dap_chain_net_verify_datum_for_add( l_net, l_datum) ;
-                    if (l_verify_datum != 0){
-                        dap_string_append_printf(l_str_tmp, "Error! Datum doesn't pass verifications (code %d) examine node log files",
-                                                 l_verify_datum);
-                        ret = -9;
-                    } else {
-                        if (l_chain->callback_add_datums) {
-                            if (l_chain->callback_add_datums(l_chain, &l_datum, 1) == 0) {
-                                dap_string_append_printf(l_str_tmp, "Error! Datum doesn't pass verifications, examine node log files");
-                                ret = -6;
-                            } else {
-                                dap_string_append_printf(l_str_tmp, "Datum processed well. ");
-                                if (!dap_global_db_del_sync(l_datum_hash_hex_str, l_gdb_group_mempool)){
-                                    dap_string_append_printf(l_str_tmp, "Warning! Can't delete datum from mempool!");
-                                } else
-                                    dap_string_append_printf(l_str_tmp, "Removed datum from mempool.");
-                            }
-                        } else {
-                            dap_string_append_printf(l_str_tmp, "Error! Can't move to no-concensus chains from mempool");
-                            ret = -1;
-                        }
-                    }
-                }
-                dap_string_append_printf(l_str_tmp, "\n");
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_tmp->str);
-                dap_string_free(l_str_tmp, true);
+    char *l_datum_hash_hex_str;
+    // datum hash may be in hex or base58 format
+    if(dap_strncmp(l_datum_hash_str, "0x", 2) && dap_strncmp(l_datum_hash_str, "0X", 2))
+        l_datum_hash_hex_str = dap_enc_base58_to_hex_str_from_str(l_datum_hash_str);
+    else
+        l_datum_hash_hex_str = dap_strdup(l_datum_hash_str);
+
+    dap_chain_datum_t * l_datum = l_datum_hash_hex_str ? (dap_chain_datum_t*) dap_global_db_get_sync(l_gdb_group_mempool, l_datum_hash_hex_str,
+                                                                                   &l_datum_size, NULL, NULL ) : NULL;
+    DAP_DELETE(l_gdb_group_mempool);
+    size_t l_datum_size2 = l_datum? dap_chain_datum_size( l_datum): 0;
+    if (l_datum_size != l_datum_size2) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Corrupted datum %s, size by datum headers is %zd when in mempool is only %zd bytes",
+                                          l_datum_hash_hex_str, l_datum_size2, l_datum_size);
+        DAP_DELETE(l_datum_hash_hex_str);
+        return -8;
+    }
+    if (!l_datum) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Can't find datum %s", l_datum_hash_str);
+        DAP_DELETE(l_datum_hash_hex_str);
+        return -4;
+    }
+    dap_hash_fast_t l_datum_hash, l_real_hash;
+    if (dap_chain_hash_fast_from_hex_str(l_datum_hash_hex_str, &l_datum_hash)) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Can't convert datum hash string %s to digital form",
+                                          l_datum_hash_hex_str);
+        DAP_DELETE(l_datum_hash_hex_str);
+        return -7;
+    }
+    dap_hash_fast(l_datum->data, l_datum->header.data_size, &l_real_hash);
+    if (!dap_hash_fast_compare(&l_datum_hash, &l_real_hash)) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Datum's real hash doesn't match datum's hash string %s",
+                                          l_datum_hash_hex_str);
+        DAP_DELETE(l_datum_hash_hex_str);
+        return -6;
+    }
+    char buf[50];
+    dap_time_t l_ts_create = (dap_time_t)l_datum->header.ts_create;
+    const char *l_type = NULL;
+    DAP_DATUM_TYPE_STR(l_datum->header.type_id, l_type);
+    dap_string_append_printf(l_str_tmp, "hash %s: type_id=%s ts_create=%s data_size=%u\n",
+            l_datum_hash_str, l_type,
+            dap_ctime_r(&l_ts_create, buf), l_datum->header.data_size);
+    int l_verify_datum = dap_chain_net_verify_datum_for_add(l_chain, l_datum, &l_datum_hash) ;
+    if (l_verify_datum != 0){
+        dap_string_append_printf(l_str_tmp, "Error! Datum doesn't pass verifications (code %d) examine node log files",
+                                 l_verify_datum);
+        ret = -9;
+    } else {
+        if (l_chain->callback_add_datums) {
+            if (l_chain->callback_add_datums(l_chain, &l_datum, 1) == 0) {
+                dap_string_append_printf(l_str_tmp, "Error! Datum doesn't pass verifications, examine node log files");
+                ret = -6;
             } else {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Can't find datum %s", l_datum_hash_str);
-                ret = -4;
+                dap_string_append_printf(l_str_tmp, "Datum processed well. ");
+                if (dap_global_db_del_sync(l_datum_hash_hex_str, l_gdb_group_mempool)){
+                    dap_string_append_printf(l_str_tmp, "Warning! Can't delete datum from mempool!");
+                } else
+                    dap_string_append_printf(l_str_tmp, "Removed datum from mempool.");
             }
+        } else {
+            dap_string_append_printf(l_str_tmp, "Error! Can't move to no-concensus chains from mempool");
+            ret = -1;
         }
-        DAP_DELETE(l_gdb_group_mempool);
-        DAP_DELETE(l_datum_hash_hex_str);
-        DAP_DELETE(l_datum_hash_base58_str);
-    } else {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! %s requires -datum <datum hash> option", a_argv[0]);
-        ret = -5;
     }
-    return  ret;
+    dap_string_append_printf(l_str_tmp, "\n");
+    dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_tmp->str);
+    dap_string_free(l_str_tmp, true);
+
+    DAP_DELETE(l_datum_hash_hex_str);
+    return ret;
 }
 
 /**
@@ -5128,7 +5111,7 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply)
 
     if(!l_token_ticker) {
         dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-token'");
-        return -6;
+        return -3;
     }
     dap_chain_net_t * l_net = dap_chain_net_by_name(l_net_name);
     dap_ledger_t *l_ledger = l_net ? l_net->pub.ledger : NULL;
@@ -5166,10 +5149,15 @@ int com_tx_create(int a_argc, char **a_argv, char **a_str_reply)
         const char *l_native_ticker = l_net->pub.native_ticker;
         bool not_native = dap_strcmp(l_token_ticker, l_native_ticker);
 
+        if (!l_wallet_fee_name) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "tx_create requires parameter '-wallet_fee' to be a valid wallet name");
+            return -10;
+        }
+
         l_wallet_fee = dap_chain_wallet_open(l_wallet_fee_name, c_wallets_path);
         if((!l_wallet_fee)&&(not_native)) {
             dap_cli_server_cmd_set_reply_text(a_str_reply, "wallet %s does not exist", l_wallet_fee_name);
-            return -9;
+            return -11;
         }
 
         if(!l_wallet_fee){
@@ -5320,7 +5308,7 @@ int com_tx_verify(int a_argc, char **a_argv, char **a_str_reply)
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified tx not found");
         return -3;
     }
-    int l_ret = dap_chain_ledger_tx_add_check(l_net->pub.ledger, l_tx);
+    int l_ret = dap_chain_ledger_tx_add_check(l_net->pub.ledger, l_tx, l_tx_size, &l_tx_hash);
     if (l_ret) {
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Specified tx verify fail with return code=%d", l_ret);
         return -4;
diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c
index 00613d86f327a4a378a32467f655f191b93dd6f4..6be9eb83ca05444f287c980c6b5b715006488b1f 100644
--- a/modules/net/dap_chain_node_cli_cmd_tx.c
+++ b/modules/net/dap_chain_node_cli_cmd_tx.c
@@ -121,22 +121,25 @@ static bool s_dap_chain_datum_tx_out_data(dap_chain_datum_tx_t *a_datum,
  */
 char* dap_db_history_tx(dap_chain_hash_fast_t* a_tx_hash, dap_chain_t * a_chain, const char *a_hash_out_type)
 {
-    if (!a_chain->callback_tx_find_by_hash) {
-        log_it(L_WARNING, "Not defined callback_tx_find_by_hash for chain \"%s\"", a_chain->name);
+    if (!a_chain->callback_datum_find_by_hash) {
+        log_it(L_WARNING, "Not defined callback_datum_find_by_hash for chain \"%s\"", a_chain->name);
         return NULL;
     }
 
     dap_string_t *l_str_out = dap_string_new(NULL);
     dap_hash_fast_t l_atom_hash = {};
-    dap_chain_datum_tx_t *l_tx = a_chain->callback_tx_find_by_hash(a_chain, a_tx_hash, &l_atom_hash);
+    int l_ret_code = 0;
+    dap_chain_datum_t *l_datum = a_chain->callback_datum_find_by_hash(a_chain, a_tx_hash, &l_atom_hash, &l_ret_code);
+    dap_chain_datum_tx_t *l_tx = l_datum  && l_datum->header.type_id == DAP_CHAIN_DATUM_TX ?
+                                 (dap_chain_datum_tx_t *)l_datum->data : NULL;
 
     if (l_tx) {
         char *l_atom_hash_str = dap_strcmp(a_hash_out_type, "hex")
                 ? dap_enc_base58_encode_hash_to_str(&l_atom_hash)
                 : dap_chain_hash_fast_to_str_new(&l_atom_hash);
         const char *l_tx_token_ticker = dap_chain_ledger_tx_get_token_ticker_by_hash(a_chain->ledger, a_tx_hash);
-        dap_string_append_printf(l_str_out, "%s TX with atom %s\n", l_tx_token_ticker ? "ACCEPTED" : "DECLINED",
-                                                                    l_atom_hash_str);
+        dap_string_append_printf(l_str_out, "%s TX with atom %s (ret_code %d)\n", l_tx_token_ticker ? "ACCEPTED" : "DECLINED",
+                                                                    l_atom_hash_str, l_ret_code);
         DAP_DELETE(l_atom_hash_str);
         dap_chain_datum_dump_tx(l_tx, l_tx_token_ticker, l_str_out, a_hash_out_type, a_tx_hash);
     } else {
@@ -152,7 +155,7 @@ char* dap_db_history_tx(dap_chain_hash_fast_t* a_tx_hash, dap_chain_t * a_chain,
 static void s_tx_header_print(dap_string_t *a_str_out, dap_chain_tx_hash_processed_ht_t **a_tx_data_ht,
                               dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_atom_hash,
                               const char *a_hash_out_type, dap_ledger_t *a_ledger,
-                              dap_chain_hash_fast_t *a_tx_hash)
+                              dap_chain_hash_fast_t *a_tx_hash, int a_ret_code)
 {
     bool l_declined = false;
     // transaction time
@@ -181,8 +184,8 @@ static void s_tx_header_print(dap_string_t *a_str_out, dap_chain_tx_hash_process
         l_tx_hash_str = dap_enc_base58_encode_hash_to_str(a_tx_hash);
         l_atom_hash_str = dap_enc_base58_encode_hash_to_str(a_atom_hash);
     }
-    dap_string_append_printf(a_str_out, "%s TX hash %s (atom %s) \n\t%s", l_declined ? "DECLINED" : "ACCEPTED",
-                                                                          l_tx_hash_str, l_atom_hash_str, l_time_str);
+    dap_string_append_printf(a_str_out, "%s TX hash %s with atom %s (ret code %d) \n\t%s", l_declined ? "DECLINED" : "ACCEPTED",
+                                                                          l_tx_hash_str, l_atom_hash_str, a_ret_code, l_time_str);
     DAP_DELETE(l_tx_hash_str);
     DAP_DELETE(l_atom_hash_str);
 }
@@ -206,17 +209,6 @@ char* dap_db_history_addr(dap_chain_addr_t *a_addr, dap_chain_t *a_chain, const
 
     dap_string_t *l_str_out = dap_string_new(NULL);
     dap_chain_tx_hash_processed_ht_t *l_tx_data_ht = NULL;
-    // load transactions
-    dap_chain_atom_iter_t *l_atom_iter = a_chain->callback_atom_iter_create(a_chain, a_chain->cells->id, 0);
-    size_t l_atom_size=0;
-    dap_chain_atom_ptr_t l_atom = a_chain->callback_atom_iter_get_first(l_atom_iter, &l_atom_size);
-    if (!l_atom) {
-        return NULL;
-    }
-    if (!a_chain->callback_atom_get_datums) {
-        log_it(L_WARNING, "Not defined callback_atom_get_datums for chain \"%s\"", a_chain->name);
-        return NULL;
-    }
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
     if (!l_net) {
         log_it(L_WARNING, "Can't find net by specified chain %s", a_chain->name);
@@ -224,177 +216,179 @@ char* dap_db_history_addr(dap_chain_addr_t *a_addr, dap_chain_t *a_chain, const
     }
     dap_ledger_t *l_ledger = l_net->pub.ledger;
     const char *l_native_ticker = l_net->pub.native_ticker;
+    if (!a_chain->callback_datum_iter_create) {
+        log_it(L_WARNING, "Not defined callback_datum_iter_create for chain \"%s\"", a_chain->name);
+        return NULL;
+    }
+    // load transactions
+    dap_chain_datum_iter_t *l_datum_iter = a_chain->callback_datum_iter_create(a_chain);
 
-    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);
-        for (size_t d = 0; d < l_datums_count; d++) {
-            dap_chain_datum_t *l_datum = l_datums ? l_datums[d] : NULL;
-            if (!l_datum || l_datum->header.type_id != DAP_CHAIN_DATUM_TX) {
-                // go to next datum
-                continue;
+    for (dap_chain_datum_t *l_datum = a_chain->callback_datum_iter_get_first(l_datum_iter);
+                            l_datum;
+                            l_datum = a_chain->callback_datum_iter_get_next(l_datum_iter))
+    {
+        if (l_datum->header.type_id != DAP_CHAIN_DATUM_TX)
+            // go to next datum
+            continue;
+        // it's a transaction
+        dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data;
+        dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_ALL, NULL);
+        if (!l_list_in_items) // a bad tx
+            continue;
+        // all in items should be from the same address
+        dap_chain_addr_t *l_src_addr = NULL;
+        bool l_base_tx = false;
+        const char *l_noaddr_token = NULL;
+
+        dap_hash_fast_t l_tx_hash;
+        dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
+        const char *l_src_token = dap_chain_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_tx_hash);
+
+        int l_src_subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_UNDEFINED;
+        for (dap_list_t *it = l_list_in_items; it; it = it->next) {
+            dap_chain_hash_fast_t *l_tx_prev_hash;
+            int l_tx_prev_out_idx;
+            dap_chain_datum_tx_t *l_tx_prev = NULL;
+            switch (*(byte_t *)it->data) {
+            case TX_ITEM_TYPE_IN: {
+                dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)it->data;
+                l_tx_prev_hash = &l_tx_in->header.tx_prev_hash;
+                l_tx_prev_out_idx = l_tx_in->header.tx_out_prev_idx;
+            } break;
+            case TX_ITEM_TYPE_IN_COND: {
+                dap_chain_tx_in_cond_t *l_tx_in_cond = (dap_chain_tx_in_cond_t *)it->data;
+                l_tx_prev_hash = &l_tx_in_cond->header.tx_prev_hash;
+                l_tx_prev_out_idx = l_tx_in_cond->header.tx_out_prev_idx;
+            } break;
+            case TX_ITEM_TYPE_IN_EMS: {
+                dap_chain_tx_in_ems_t *l_in_ems = (dap_chain_tx_in_ems_t *)it->data;
+                l_base_tx = true;
+                l_noaddr_token = l_in_ems->header.ticker;
             }
-            // it's a transaction
-            dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data;
-            dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_ALL, NULL);
-            if (!l_list_in_items) { // a bad tx
+            default:
                 continue;
             }
-            // all in items should be from the same address
-            dap_chain_addr_t *l_src_addr = NULL;
-            bool l_base_tx = false;
-            const char *l_noaddr_token = NULL;
-
-            dap_hash_fast_t l_tx_hash;
-            dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
-            const char *l_src_token = dap_chain_ledger_tx_get_token_ticker_by_hash(l_ledger, &l_tx_hash);
-
-            int l_src_subtype = DAP_CHAIN_TX_OUT_COND_SUBTYPE_UNDEFINED;
-            for (dap_list_t *it = l_list_in_items; it; it = it->next) {
-                dap_chain_hash_fast_t *l_tx_prev_hash;
-                int l_tx_prev_out_idx;
-                dap_chain_datum_tx_t *l_tx_prev = NULL;
-                switch (*(byte_t *)it->data) {
-                case TX_ITEM_TYPE_IN: {
-                    dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)it->data;
-                    l_tx_prev_hash = &l_tx_in->header.tx_prev_hash;
-                    l_tx_prev_out_idx = l_tx_in->header.tx_out_prev_idx;
-                } break;
-                case TX_ITEM_TYPE_IN_COND: {
-                    dap_chain_tx_in_cond_t *l_tx_in_cond = (dap_chain_tx_in_cond_t *)it->data;
-                    l_tx_prev_hash = &l_tx_in_cond->header.tx_prev_hash;
-                    l_tx_prev_out_idx = l_tx_in_cond->header.tx_out_prev_idx;
-                } break;
-                case TX_ITEM_TYPE_IN_EMS: {
-                    dap_chain_tx_in_ems_t *l_in_ems = (dap_chain_tx_in_ems_t *)it->data;
-                    l_base_tx = true;
-                    l_noaddr_token = l_in_ems->header.ticker;
-                }
-                default:
-                    continue;
-                }
 
-                l_tx_prev = a_chain->callback_tx_find_by_hash(a_chain, l_tx_prev_hash, NULL);
-                if (l_tx_prev) {
-                    uint8_t *l_prev_out_union = dap_chain_datum_tx_item_get_nth(l_tx_prev, TX_ITEM_TYPE_OUT_ALL, l_tx_prev_out_idx);
-                    if (!l_prev_out_union)
-                        continue;
-                    switch (*l_prev_out_union) {
-                    case TX_ITEM_TYPE_OUT:
-                        l_src_addr = &((dap_chain_tx_out_t *)l_prev_out_union)->addr;
-                        break;
-                    case TX_ITEM_TYPE_OUT_EXT:
-                        l_src_addr = &((dap_chain_tx_out_ext_t *)l_prev_out_union)->addr;
-                        break;
-                    case TX_ITEM_TYPE_OUT_COND:
-                        l_src_subtype = ((dap_chain_tx_out_cond_t *)l_prev_out_union)->header.subtype;
-                        if (l_src_subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
-                            l_noaddr_token = l_native_ticker;
-                        else
-                            l_noaddr_token = l_src_token;
-                    default:
-                        break;
-                    }
-                }
-                if (l_src_addr && !dap_chain_addr_compare(l_src_addr, a_addr))
-                    break;  //it's not our addr
-            }
-            dap_list_free(l_list_in_items);
-
-            // find OUT items
-            bool l_header_printed = false;
-            uint256_t l_fee_sum = {};
-            dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_ALL, NULL);
-            for (dap_list_t *it = l_list_out_items; it; it = it->next) {
-                dap_chain_addr_t *l_dst_addr = NULL;
-                uint8_t l_type = *(uint8_t *)it->data;
-                uint256_t l_value;
-                const char *l_dst_token = NULL;
-                switch (l_type) {
+            dap_chain_datum_t *l_datum = a_chain->callback_datum_find_by_hash(a_chain, l_tx_prev_hash, NULL, NULL);
+            l_tx_prev = l_datum  && l_datum->header.type_id == DAP_CHAIN_DATUM_TX ? (dap_chain_datum_tx_t *)l_datum->data : NULL;
+            if (l_tx_prev) {
+                uint8_t *l_prev_out_union = dap_chain_datum_tx_item_get_nth(l_tx_prev, TX_ITEM_TYPE_OUT_ALL, l_tx_prev_out_idx);
+                if (!l_prev_out_union)
+                    continue;
+                switch (*l_prev_out_union) {
                 case TX_ITEM_TYPE_OUT:
-                    l_dst_addr = &((dap_chain_tx_out_t *)it->data)->addr;
-                    l_value = ((dap_chain_tx_out_t *)it->data)->header.value;
-                    l_dst_token = l_src_token;
+                    l_src_addr = &((dap_chain_tx_out_t *)l_prev_out_union)->addr;
                     break;
                 case TX_ITEM_TYPE_OUT_EXT:
-                    l_dst_addr = &((dap_chain_tx_out_ext_t *)it->data)->addr;
-                    l_value = ((dap_chain_tx_out_ext_t *)it->data)->header.value;
-                    l_dst_token = ((dap_chain_tx_out_ext_t *)it->data)->token;
+                    l_src_addr = &((dap_chain_tx_out_ext_t *)l_prev_out_union)->addr;
                     break;
                 case TX_ITEM_TYPE_OUT_COND:
-                    l_value = ((dap_chain_tx_out_cond_t *)it->data)->header.value;
-                    if (((dap_chain_tx_out_cond_t *)it->data)->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) {
-                        SUM_256_256(l_fee_sum, ((dap_chain_tx_out_cond_t *)it->data)->header.value, &l_fee_sum);
-                        l_dst_token = l_native_ticker;
-                    } else
-                        l_dst_token = l_src_token;
+                    l_src_subtype = ((dap_chain_tx_out_cond_t *)l_prev_out_union)->header.subtype;
+                    if (l_src_subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE)
+                        l_noaddr_token = l_native_ticker;
+                    else
+                        l_noaddr_token = l_src_token;
                 default:
                     break;
                 }
-                if (l_src_addr && l_dst_addr && dap_chain_addr_compare(l_dst_addr, l_src_addr) &&
-                        dap_strcmp(l_dst_token, l_noaddr_token))
-                    continue;   // sent to self (coinback)
-                if (l_src_addr && dap_chain_addr_compare(l_src_addr, a_addr) &&
-                        dap_strcmp(l_dst_token, l_noaddr_token)) {
-                    if (!l_header_printed) {
-                        s_tx_header_print(l_str_out, &l_tx_data_ht, l_tx, l_atom_iter->cur_hash, a_hash_out_type, l_ledger, &l_tx_hash);
-                        l_header_printed = true;
-                    }
-                    const char *l_dst_addr_str = l_dst_addr ? dap_chain_addr_to_str(l_dst_addr)
-                                                            : dap_chain_tx_out_cond_subtype_to_str(
-                                                                  ((dap_chain_tx_out_cond_t *)it->data)->header.subtype);
-                    char *l_value_str = dap_chain_balance_print(l_value);
-                    char *l_coins_str = dap_chain_balance_to_coins(l_value);
-                    dap_string_append_printf(l_str_out, "\tsend %s (%s) %s to %s\n",
-                                             l_coins_str,
-                                             l_value_str,
-                                             l_dst_token ? l_dst_token : "UNKNOWN",
-                                             l_dst_addr_str);
-                    if (l_dst_addr)
-                        DAP_DELETE(l_dst_addr_str);
-                    DAP_DELETE(l_value_str);
-                    DAP_DELETE(l_coins_str);
-                }
-                if (l_dst_addr && dap_chain_addr_compare(l_dst_addr, a_addr)) {
-                    if (!l_header_printed) {
-                        s_tx_header_print(l_str_out, &l_tx_data_ht, l_tx, l_atom_iter->cur_hash, a_hash_out_type, l_ledger, &l_tx_hash);
-                        l_header_printed = true;
-                    }
-                    const char *l_src_addr_str = NULL, *l_src_str;
-                    if (l_base_tx)
-                        l_src_str = "emission";
-                    else if (l_src_addr && dap_strcmp(l_dst_token, l_noaddr_token))
-                        l_src_str = l_src_addr_str = dap_chain_addr_to_str(l_src_addr);
-                    else
-                        l_src_str = dap_chain_tx_out_cond_subtype_to_str(l_src_subtype);
-                    char *l_value_str = dap_chain_balance_print(l_value);
-                    char *l_coins_str = dap_chain_balance_to_coins(l_value);
-                    dap_string_append_printf(l_str_out, "\trecv %s (%s) %s from %s\n",
-                                             l_coins_str,
-                                             l_value_str,
-                                             l_dst_token ? l_dst_token : "UNKNOWN",
-                                             l_src_str);
-                    DAP_DEL_Z(l_src_addr_str);
-                    DAP_DELETE(l_value_str);
-                    DAP_DELETE(l_coins_str);
+            }
+            if (l_src_addr && !dap_chain_addr_compare(l_src_addr, a_addr))
+                break;  //it's not our addr
+        }
+        dap_list_free(l_list_in_items);
+
+        // find OUT items
+        bool l_header_printed = false;
+        uint256_t l_fee_sum = {};
+        dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_ALL, NULL);
+        for (dap_list_t *it = l_list_out_items; it; it = it->next) {
+            dap_chain_addr_t *l_dst_addr = NULL;
+            uint8_t l_type = *(uint8_t *)it->data;
+            uint256_t l_value;
+            const char *l_dst_token = NULL;
+            switch (l_type) {
+            case TX_ITEM_TYPE_OUT:
+                l_dst_addr = &((dap_chain_tx_out_t *)it->data)->addr;
+                l_value = ((dap_chain_tx_out_t *)it->data)->header.value;
+                l_dst_token = l_src_token;
+                break;
+            case TX_ITEM_TYPE_OUT_EXT:
+                l_dst_addr = &((dap_chain_tx_out_ext_t *)it->data)->addr;
+                l_value = ((dap_chain_tx_out_ext_t *)it->data)->header.value;
+                l_dst_token = ((dap_chain_tx_out_ext_t *)it->data)->token;
+                break;
+            case TX_ITEM_TYPE_OUT_COND:
+                l_value = ((dap_chain_tx_out_cond_t *)it->data)->header.value;
+                if (((dap_chain_tx_out_cond_t *)it->data)->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE) {
+                    SUM_256_256(l_fee_sum, ((dap_chain_tx_out_cond_t *)it->data)->header.value, &l_fee_sum);
+                    l_dst_token = l_native_ticker;
+                } else
+                    l_dst_token = l_src_token;
+            default:
+                break;
+            }
+            if (l_src_addr && l_dst_addr && dap_chain_addr_compare(l_dst_addr, l_src_addr) &&
+                    dap_strcmp(l_dst_token, l_noaddr_token))
+                continue;   // sent to self (coinback)
+            if (l_src_addr && dap_chain_addr_compare(l_src_addr, a_addr) &&
+                    dap_strcmp(l_dst_token, l_noaddr_token)) {
+                if (!l_header_printed) {
+                    s_tx_header_print(l_str_out, &l_tx_data_ht, l_tx, l_datum_iter->cur_atom_hash,
+                                      a_hash_out_type, l_ledger, &l_tx_hash, l_datum_iter->ret_code);
+                    l_header_printed = true;
                 }
+                const char *l_dst_addr_str = l_dst_addr ? dap_chain_addr_to_str(l_dst_addr)
+                                                        : dap_chain_tx_out_cond_subtype_to_str(
+                                                              ((dap_chain_tx_out_cond_t *)it->data)->header.subtype);
+                char *l_value_str = dap_chain_balance_print(l_value);
+                char *l_coins_str = dap_chain_balance_to_coins(l_value);
+                dap_string_append_printf(l_str_out, "\tsend %s (%s) %s to %s\n",
+                                         l_coins_str,
+                                         l_value_str,
+                                         l_dst_token ? l_dst_token : "UNKNOWN",
+                                         l_dst_addr_str);
+                if (l_dst_addr)
+                    DAP_DELETE(l_dst_addr_str);
+                DAP_DELETE(l_value_str);
+                DAP_DELETE(l_coins_str);
             }
-            dap_list_free(l_list_out_items);
-            // fee for base TX in native token
-            if (l_header_printed && l_base_tx && !dap_strcmp(l_native_ticker, l_src_token)) {
-                char *l_fee_value_str = dap_chain_balance_print(l_fee_sum);
-                char *l_fee_coins_str = dap_chain_balance_to_coins(l_fee_sum);
-                dap_string_append_printf(l_str_out, "\t\tpay %s (%s) fee\n",
-                                                   l_fee_value_str, l_fee_coins_str);
-                DAP_DELETE(l_fee_value_str);
-                DAP_DELETE(l_fee_coins_str);
+            if (l_dst_addr && dap_chain_addr_compare(l_dst_addr, a_addr)) {
+                if (!l_header_printed) {
+                    s_tx_header_print(l_str_out, &l_tx_data_ht, l_tx, l_datum_iter->cur_atom_hash,
+                                      a_hash_out_type, l_ledger, &l_tx_hash, l_datum_iter->ret_code);
+                    l_header_printed = true;
+                }
+                const char *l_src_addr_str = NULL, *l_src_str;
+                if (l_base_tx)
+                    l_src_str = "emission";
+                else if (l_src_addr && dap_strcmp(l_dst_token, l_noaddr_token))
+                    l_src_str = l_src_addr_str = dap_chain_addr_to_str(l_src_addr);
+                else
+                    l_src_str = dap_chain_tx_out_cond_subtype_to_str(l_src_subtype);
+                char *l_value_str = dap_chain_balance_print(l_value);
+                char *l_coins_str = dap_chain_balance_to_coins(l_value);
+                dap_string_append_printf(l_str_out, "\trecv %s (%s) %s from %s\n",
+                                         l_coins_str,
+                                         l_value_str,
+                                         l_dst_token ? l_dst_token : "UNKNOWN",
+                                         l_src_str);
+                DAP_DEL_Z(l_src_addr_str);
+                DAP_DELETE(l_value_str);
+                DAP_DELETE(l_coins_str);
             }
         }
-        DAP_DELETE(l_datums);
-        // go to next atom (event or block)
-        l_atom = a_chain->callback_atom_iter_get_next(l_atom_iter, &l_atom_size);
+        dap_list_free(l_list_out_items);
+        // fee for base TX in native token
+        if (l_header_printed && l_base_tx && !dap_strcmp(l_native_ticker, l_src_token)) {
+            char *l_fee_value_str = dap_chain_balance_print(l_fee_sum);
+            char *l_fee_coins_str = dap_chain_balance_to_coins(l_fee_sum);
+            dap_string_append_printf(l_str_out, "\t\tpay %s (%s) fee\n",
+                                               l_fee_value_str, l_fee_coins_str);
+            DAP_DELETE(l_fee_value_str);
+            DAP_DELETE(l_fee_coins_str);
+        }
     }
-    a_chain->callback_atom_iter_delete(l_atom_iter);
+    a_chain->callback_datum_iter_delete(l_datum_iter);
     // delete hashes
     s_dap_chain_tx_hash_processed_ht_free(&l_tx_data_ht);
     // if no history
@@ -615,13 +609,10 @@ int com_ledger(int a_argc, char ** a_argv, char **a_str_reply)
     const char *l_addr_base58 = NULL;
     const char *l_wallet_name = NULL;
     const char *l_net_str = NULL;
-    const char *l_chain_str = NULL;
     const char *l_tx_hash_str = NULL;
+    const char *l_hash_out_type = NULL;
 
-    dap_chain_t * l_chain = NULL;
     dap_chain_net_t * l_net = NULL;
-
-    const char * l_hash_out_type = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-H", &l_hash_out_type);
     if(!l_hash_out_type)
         l_hash_out_type = "hex";
@@ -745,9 +736,6 @@ int com_ledger(int a_argc, char ** a_argv, char **a_str_reply)
         DAP_DELETE(l_str_out);
         DAP_DELETE(l_addr);
         s_dap_chain_tx_hash_processed_ht_free(&l_list_tx_hash_processd);
-        // all chain
-        if(!l_chain)
-            dap_chain_enum_unlock();
         dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_ret->str);
         dap_string_free(l_str_ret, true);
         return 0;       
@@ -886,7 +874,6 @@ int com_token(int a_argc, char ** a_argv, char **a_str_reply)
     int arg_index = 1;
     const char *l_net_str = NULL;
     dap_chain_net_t * l_net = NULL;
-    dap_chain_tx_hash_processed_ht_t *l_list_tx_hash_processd = NULL;
 
     const char * l_hash_out_type = NULL;
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-H", &l_hash_out_type);
@@ -921,23 +908,14 @@ int com_token(int a_argc, char ** a_argv, char **a_str_reply)
     if(l_cmd == CMD_LIST) {
         dap_string_t *l_str_out = dap_string_new(NULL);
         size_t l_token_num_total = 0;
-        // get first chain
-        void *l_chain_tmp = (void*)0x1;
-        dap_chain_t *l_chain_cur = dap_chain_enum(&l_chain_tmp);
-        while(l_chain_cur) {
-            // only selected net
-            if(l_net->pub.id.uint64 == l_chain_cur->net_id.uint64) {
-                size_t l_token_num = 0;
-                char *token_list_str = dap_db_history_token_list(l_chain_cur, NULL, l_hash_out_type, &l_token_num);
-                if(token_list_str)
-                    dap_string_append(l_str_out, token_list_str);
-                l_token_num_total += l_token_num;
-            }
-            // next chain
-            dap_chain_enum_unlock();
-            l_chain_cur = dap_chain_enum(&l_chain_tmp);
+        dap_chain_t *l_chain_cur;
+        DL_FOREACH(l_net->pub.chains, l_chain_cur) {
+            size_t l_token_num = 0;
+            char *token_list_str = dap_db_history_token_list(l_chain_cur, NULL, l_hash_out_type, &l_token_num);
+            if(token_list_str)
+                dap_string_append(l_str_out, token_list_str);
+            l_token_num_total += l_token_num;
         }
-        dap_chain_enum_unlock();
         //total
         dap_string_append_printf(l_str_out, "---------------\ntokens: %zu\n", l_token_num_total);
         dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_out->str);
@@ -956,24 +934,15 @@ int com_token(int a_argc, char ** a_argv, char **a_str_reply)
 
             dap_string_t *l_str_out = dap_string_new(NULL);
             size_t l_token_num_total = 0;
-            // get first chain
-            void *l_chain_tmp = (void*)0x1;
-            dap_chain_t *l_chain_cur = dap_chain_enum(&l_chain_tmp);
-            while(l_chain_cur) {
-                // only selected net
-                if(l_net->pub.id.uint64 == l_chain_cur->net_id.uint64) {
-                    size_t l_token_num = 0;
-                    // filter - token name
-                    char *token_list_str = dap_db_history_token_list(l_chain_cur, l_token_name_str, l_hash_out_type, &l_token_num);
-                    if(token_list_str)
-                        dap_string_append(l_str_out, token_list_str);
-                    l_token_num_total += l_token_num;
-                }
-                // next chain
-                dap_chain_enum_unlock();
-                l_chain_cur = dap_chain_enum(&l_chain_tmp);
+            dap_chain_t *l_chain_cur;
+            DL_FOREACH(l_net->pub.chains, l_chain_cur) {
+                size_t l_token_num = 0;
+                // filter - token name
+                char *token_list_str = dap_db_history_token_list(l_chain_cur, l_token_name_str, l_hash_out_type, &l_token_num);
+                if(token_list_str)
+                    dap_string_append(l_str_out, token_list_str);
+                l_token_num_total += l_token_num;
             }
-            dap_chain_enum_unlock();
             if(!l_token_num_total)
                 dap_string_append_printf(l_str_out, "token '%s' not found\n", l_token_name_str);
             dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_out->str);
@@ -985,6 +954,7 @@ int com_token(int a_argc, char ** a_argv, char **a_str_reply)
         dap_cli_server_cmd_set_reply_text(a_str_reply, "The cellframe-node-cli token tx command is deprecated and no longer supported.\n");
         return 0;
 #if 0
+        dap_chain_tx_hash_processed_ht_t *l_list_tx_hash_processd = NULL;
         enum { SUBCMD_TX_NONE, SUBCMD_TX_ALL, SUBCMD_TX_ADDR };
         // find subcommand
         int l_subcmd = CMD_NONE;
diff --git a/modules/net/dap_chain_node_dns_client.c b/modules/net/dap_chain_node_dns_client.c
index c86d9e282635e355d5fbb753ed297879cf6e2874..3b8ed6a71547e60a53d1a653daacc1576b92be76 100644
--- a/modules/net/dap_chain_node_dns_client.c
+++ b/modules/net/dap_chain_node_dns_client.c
@@ -23,6 +23,7 @@
     along with any DapChain SDK based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include "dap_net.h"
 #include "dap_events.h"
 #include "dap_timerfd.h"
 #include "dap_chain_node_dns_server.h"
@@ -190,7 +191,10 @@ int dap_chain_node_info_dns_request(dap_worker_t *a_worker, struct in_addr a_add
                            dap_dns_client_node_info_request_success_callback_t a_callback_success,
                            dap_dns_client_node_info_request_error_callback_t a_callback_error,void * a_callbacks_arg)
 {
-    log_it(L_INFO, "DNS request for bootstrap nodelist  %s : %d, net %s", inet_ntoa(a_addr), a_port, a_name);
+    char l_addr_str[INET_ADDRSTRLEN] = {};
+    inet_ntop(AF_INET, &a_addr, l_addr_str, INET_ADDRSTRLEN);
+
+    log_it(L_INFO, "DNS request for bootstrap nodelist  %s : %d, net %s", l_addr_str, a_port, a_name);
 
     struct dns_client * l_dns_client = DAP_NEW_Z(struct dns_client);
     if(!l_dns_client)
diff --git a/modules/net/dap_chain_node_ping.c b/modules/net/dap_chain_node_ping.c
index 6a54f4ac2c8c5e0df7bad85236db1c0852138e9e..bca79553f727c792bc4bcc8c1abc9a05d006400d 100644
--- a/modules/net/dap_chain_node_ping.c
+++ b/modules/net/dap_chain_node_ping.c
@@ -70,7 +70,7 @@
 #include "iputils/iputils.h"
 
 #include "dap_common.h"
-//#include "dap_client.h"
+#include "dap_net.h"
 #include "dap_strfuncs.h"
 #include "dap_chain_node_cli.h"
 #include "dap_chain_node_ping.h"
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index 25b14cf485762b212b7c14f7c3c5e3efc338e605..f35d789ae62f3ab4f4a504302b21b6e13a5cf08c 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -132,7 +132,7 @@ static inline const char * dap_chain_net_state_to_str(dap_chain_net_state_t a_st
 }
 
 void dap_chain_net_delete( dap_chain_net_t * a_net);
-void dap_chain_net_proc_mempool (dap_chain_net_t * a_net);
+void dap_chain_net_proc_mempool(dap_chain_net_t *a_net);
 void dap_chain_net_set_flag_sync_from_zero(dap_chain_net_t * a_net, bool a_flag_sync_from_zero);
 bool dap_chain_net_get_flag_sync_from_zero( dap_chain_net_t * a_net);
 
@@ -188,7 +188,7 @@ char *dap_chain_net_get_gdb_group_mempool_by_chain_type(dap_chain_net_t *a_net,
 dap_chain_net_t **dap_chain_net_list(uint16_t *a_size);
 bool dap_chain_net_get_extra_gdb_group(dap_chain_net_t *a_net, dap_chain_node_addr_t a_node_addr);
 
-int dap_chain_net_verify_datum_for_add(dap_chain_net_t *a_net, dap_chain_datum_t * a_datum );
+int dap_chain_net_verify_datum_for_add(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, dap_hash_fast_t *a_datum_hash);
 int dap_chain_net_add_downlink(dap_chain_net_t *a_net, dap_stream_worker_t *a_worker, dap_stream_ch_uuid_t a_ch_uuid, dap_events_socket_uuid_t a_esocket_uuid);
 void dap_chain_net_add_gdb_notify_callback(dap_chain_net_t *a_net, dap_store_obj_callback_notify_t a_callback, void *a_cb_arg);
 void dap_chain_net_sync_gdb_broadcast(dap_global_db_context_t *a_context, dap_store_obj_t *a_obj, void *a_arg);
@@ -203,6 +203,6 @@ void dap_chain_net_sync_gdb_broadcast(dap_global_db_context_t *a_context, dap_st
  */
 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_tx_hash);
+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);
 
 bool dap_chain_net_get_load_mode(dap_chain_net_t * a_net);
diff --git a/modules/net/include/dap_chain_net_decree.h b/modules/net/include/dap_chain_net_decree.h
index 18cbaf32dee98b403c83fb4e05b169435d299e6b..255ab44326996643b451ea4fc0a0335c2dc614da 100644
--- a/modules/net/include/dap_chain_net_decree.h
+++ b/modules/net/include/dap_chain_net_decree.h
@@ -32,15 +32,13 @@ typedef struct decree_params {
     dap_chain_addr_t *fee_addr;
 }   dap_chain_net_decree_t;
 
-#define DAP_DECREE_IS_PRESENT -1110
-
 int dap_chain_net_decree_init(dap_chain_net_t *a_net);
 int dap_chain_net_decree_deinit(dap_chain_net_t *a_net);
 
 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_datum_decree_t *a_decree, dap_chain_net_t *a_net, size_t a_data_size, dap_hash_fast_t *a_decree_hash);
-int dap_chain_net_decree_load(dap_chain_datum_decree_t * a_decree, dap_chain_t *a_chain);
+int dap_chain_net_decree_verify(dap_chain_datum_decree_t *a_decree, dap_chain_net_t *a_net, 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);
 
 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/include/dap_chain_node.h b/modules/net/include/dap_chain_node.h
index a098bdcc2857db54def923b8dcfd90aec4c0b3f4..56ee4dd853165545ecd135f54c7470becec5321c 100644
--- a/modules/net/include/dap_chain_node.h
+++ b/modules/net/include/dap_chain_node.h
@@ -155,7 +155,7 @@ inline static char* dap_chain_node_addr_to_hash_str(dap_chain_node_addr_t *addre
 }
 
 bool dap_chain_node_mempool_need_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum);
-bool dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum);
+bool dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, const char *a_datum_hash_str);
 void dap_chain_node_mempool_process_all(dap_chain_t *a_chain, bool a_force);
 bool dap_chain_node_mempool_autoproc_init();
 void dap_chain_node_mempool_autoproc_deinit();
diff --git a/modules/type/blocks/dap_chain_block_cache.c b/modules/type/blocks/dap_chain_block_cache.c
index 732ab4998c676513b44efbc5b3e212cc65498644..b374fc923cd6158b03e6c671f56cd43854d146a6 100644
--- a/modules/type/blocks/dap_chain_block_cache.c
+++ b/modules/type/blocks/dap_chain_block_cache.c
@@ -124,36 +124,12 @@ int dap_chain_block_cache_update(dap_chain_block_cache_t *a_block_cache, dap_has
         DAP_DELETE(a_block_cache->datum);
         return -2;
     }
-    dap_chain_datum_t *l_datum;
-    for (size_t i = 0; i < a_block_cache->datum_count && (l_datum = a_block_cache->datum[i]); i++) {
-        if (l_datum->header.data_size == 0 || l_datum->header.type_id != DAP_CHAIN_DATUM_TX)
-            break;
-        dap_chain_hash_fast_t l_tx_hash;
-        dap_hash_fast(l_datum->data,l_datum->header.data_size, &l_tx_hash);
-
-        dap_chain_block_cache_tx_index_t *l_tx_index = NULL;
-        HASH_FIND(hh, a_block_cache->tx_index, &l_tx_hash, sizeof (l_tx_hash), l_tx_index);
-        if (!l_tx_index) {
-            l_tx_index = DAP_NEW_Z(dap_chain_block_cache_tx_index_t);
-            l_tx_index->tx_hash = l_tx_hash;
-            l_tx_index->tx = (dap_chain_datum_tx_t*)l_datum->data;
-            HASH_ADD(hh, a_block_cache->tx_index, tx_hash, sizeof(l_tx_hash), l_tx_index);
-        }
-    }
-    return 0;
-}
 
-/**
- * @brief dap_chain_block_cache_get_tx_by_hash
- * @param a_block_cache
- * @param a_tx_hash
- * @return
- */
-dap_chain_datum_tx_t* dap_chain_block_cache_get_tx_by_hash (dap_chain_block_cache_t * a_block_cache, dap_chain_hash_fast_t * a_tx_hash)
-{
-    dap_chain_block_cache_tx_index_t * l_tx_index = NULL;
-    HASH_FIND(hh, a_block_cache->tx_index, a_tx_hash,sizeof (*a_tx_hash), l_tx_index);
-    return l_tx_index? l_tx_index->tx : NULL;
+    a_block_cache->datum_hash = DAP_NEW_Z_SIZE(dap_hash_fast_t, a_block_cache->datum_count * sizeof(dap_hash_fast_t));
+    for (size_t i = 0; i < a_block_cache->datum_count; i++)
+        dap_hash_fast(a_block_cache->datum[i]->data, a_block_cache->datum[i]->header.data_size, &a_block_cache->datum_hash[i]);
+
+    return 0;
 }
 
 /**
@@ -164,13 +140,9 @@ void dap_chain_block_cache_delete(dap_chain_block_cache_t * a_block_cache)
 {
     DAP_DEL_Z(a_block_cache->block_hash_str);
     DAP_DEL_Z(a_block_cache->datum);
+    DAP_DEL_Z(a_block_cache->datum_hash);
     DAP_DEL_Z(a_block_cache->meta);
     DAP_DEL_Z(a_block_cache->links_hash);
-    dap_chain_block_cache_tx_index_t *l_tx_cur, *l_tmp;
-    HASH_ITER(hh, a_block_cache->tx_index, l_tx_cur, l_tmp) {
-        HASH_DEL(a_block_cache->tx_index, l_tx_cur);
-        DAP_FREE(l_tx_cur);
-    }
     DAP_DELETE(a_block_cache);
 }
 
@@ -179,27 +151,28 @@ void dap_chain_block_cache_delete(dap_chain_block_cache_t * a_block_cache)
  * @param a_ledger
  * @param a_block_cache
  * @param a_value_out
- * @return list of list_used_item_t
+ * @return list of dap_chain_tx_used_out_item_t
  */
-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,
+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 *l_list_used_out = NULL; // list of transaction with 'out' items
-    dap_chain_block_cache_tx_index_t *l_tx_cur, *l_tmp;
     dap_chain_tx_out_cond_t *l_tx_out_cond = NULL;
     uint256_t l_value_transfer = {};    
-    HASH_ITER(hh, a_block_cache->tx_index, l_tx_cur, l_tmp) {
+    for (size_t i = 0; i < a_block_cache->datum_count; i++) {
+        if (a_block_cache->datum[i]->header.type_id != DAP_CHAIN_DATUM_TX)
+            continue;
+        dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)a_block_cache->datum[i]->data;
         int l_out_idx_tmp = 0;
-        if (NULL == (l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_tx_cur->tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE,
+        if (NULL == (l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE,
                                                                      &l_out_idx_tmp)))
-        {
-            dap_list_free_full(l_list_used_out, NULL);
-            return NULL;
-        }
+            continue;
+
         //Check whether used 'out' items
-        if (!dap_chain_ledger_tx_hash_is_used_out_item (a_ledger, &l_tx_cur->tx_hash, l_out_idx_tmp)) {
-            list_used_item_t *l_item = DAP_NEW_Z(list_used_item_t);
-            l_item->tx_hash_fast = l_tx_cur->tx_hash;
+        dap_hash_fast_t *l_tx_hash = a_block_cache->datum_hash + i;
+        if (!dap_chain_ledger_tx_hash_is_used_out_item (a_ledger, l_tx_hash, l_out_idx_tmp)) {
+            dap_chain_tx_used_out_item_t *l_item = DAP_NEW_Z(dap_chain_tx_used_out_item_t);
+            l_item->tx_hash_fast = *l_tx_hash;
             l_item->num_idx_out = l_out_idx_tmp;
             l_item->value = l_tx_out_cond->header.value;
             l_list_used_out = dap_list_append(l_list_used_out, l_item);
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 2b6b5d437bf2761b3ebff034cc56eb0f3bba04bc..ff9b1277254887d99cf5c1ffc013d642e62434af 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -39,14 +39,14 @@
 
 #define LOG_TAG "dap_chain_cs_blocks"
 
-typedef struct dap_chain_tx_block_index
-{
-    int res;
+typedef struct dap_chain_block_datum_index {
+    dap_chain_hash_fast_t datum_hash;
+    int ret_code;
     time_t ts_added;
-    dap_chain_hash_fast_t tx_hash;
-    dap_chain_hash_fast_t block_hash;
+    dap_chain_block_cache_t *block_cache;
+    size_t datum_index;
     UT_hash_handle hh;
-} dap_chain_tx_block_index_t;
+} dap_chain_block_datum_index_t;
 
 typedef struct dap_chain_cs_blocks_pvt
 {
@@ -61,7 +61,8 @@ typedef struct dap_chain_cs_blocks_pvt
     // Chunks treshold
     dap_chain_block_chunks_t * chunks;
 
-    dap_chain_tx_block_index_t * tx_block_index; // To find block hash by tx hash
+    pthread_rwlock_t datums_rwlock;
+    dap_chain_block_datum_index_t *datum_index; // To find datum in blocks
 
     // General links
     dap_chain_block_cache_t * block_cache_first; // Mapped area start
@@ -70,7 +71,6 @@ typedef struct dap_chain_cs_blocks_pvt
     dap_chain_hash_fast_t static_genesis_block_hash;
 
     uint64_t blocks_count;
-    uint64_t difficulty;
 
     time_t time_between_blocks_minimum; // Minimal time between blocks
     bool is_celled;
@@ -103,11 +103,11 @@ static size_t s_callback_atom_get_static_hdr_size(void);
 static dap_chain_atom_iter_t *s_callback_atom_iter_create(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, bool a_with_treshold);
 static dap_chain_atom_iter_t* s_callback_atom_iter_create_from(dap_chain_t *  ,
                                                                      dap_chain_atom_ptr_t , size_t);
-
-
 static dap_chain_atom_ptr_t s_callback_atom_iter_find_by_hash(dap_chain_atom_iter_t * a_atom_iter ,
                                                                        dap_chain_hash_fast_t * a_atom_hash, size_t * a_atom_size);
-static dap_chain_datum_tx_t *s_callback_atom_iter_find_by_tx_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_tx_hash, dap_chain_hash_fast_t *a_block_hash);
+static dap_chain_datum_t *s_callback_datum_find_by_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_datum_hash,
+                                                        dap_chain_hash_fast_t *a_block_hash, int *a_ret_code);
+
 static dap_chain_atom_ptr_t s_callback_block_find_by_tx_hash(dap_chain_t * a_chain, dap_chain_hash_fast_t * a_tx_hash);
 
 static dap_chain_datum_t** s_callback_atom_get_datums(dap_chain_atom_ptr_t a_atom, size_t a_atom_size, size_t * a_datums_count);
@@ -125,6 +125,12 @@ static dap_list_t *s_block_parse_str_list(const char * a_hash_str,size_t * a_has
 // Delete iterator
 static void s_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_iter );                  //    Get the fisrt block
 
+// Datum ops
+static dap_chain_datum_iter_t *s_chain_callback_datum_iter_create(dap_chain_t *a_chain);
+static void s_chain_callback_datum_iter_delete(dap_chain_datum_iter_t *a_datum_iter);
+static dap_chain_datum_t *s_chain_callback_datum_iter_get_first(dap_chain_datum_iter_t *a_datum_iter); // Get the fisrt datum from blocks
+static dap_chain_datum_t *s_chain_callback_datum_iter_get_next(dap_chain_datum_iter_t *a_datum_iter); // Get the next datum from blocks
+
 static size_t s_callback_add_datums(dap_chain_t * a_chain, dap_chain_datum_t ** a_datums, size_t a_datums_count);
 
 static void s_callback_cs_blocks_purge(dap_chain_t *a_chain);
@@ -216,11 +222,17 @@ int dap_chain_cs_blocks_new(dap_chain_t * a_chain, dap_config_t * a_chain_config
     a_chain->callback_atom_iter_get_links = s_callback_atom_iter_get_links; // Get the next element from chain from the current one
     a_chain->callback_atom_iter_get_lasts = s_callback_atom_iter_get_lasts;
 
+    // Datum operations callbacks
+    a_chain->callback_datum_iter_create = s_chain_callback_datum_iter_create; // Datum iterator create
+    a_chain->callback_datum_iter_delete = s_chain_callback_datum_iter_delete; // Datum iterator delete
+    a_chain->callback_datum_iter_get_first = s_chain_callback_datum_iter_get_first; // Get the fisrt datum from chain
+    a_chain->callback_datum_iter_get_next = s_chain_callback_datum_iter_get_next; // Get the next datum from chain from the current one
+
     a_chain->callback_atom_get_datums = s_callback_atom_get_datums;
     a_chain->callback_atom_get_timestamp = s_chain_callback_atom_get_timestamp;
 
     a_chain->callback_atom_find_by_hash = s_callback_atom_iter_find_by_hash;
-    a_chain->callback_tx_find_by_hash = s_callback_atom_iter_find_by_tx_hash;
+    a_chain->callback_datum_find_by_hash = s_callback_datum_find_by_hash;
 
     a_chain->callback_block_find_by_tx_hash = s_callback_block_find_by_tx_hash;
 
@@ -455,16 +467,14 @@ static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply)
                                                                                               &l_datum_size, NULL, NULL);
             l_datums[0] = l_datum;
             for (size_t i = 0; i < l_datums_count; i++) {
-                char *l_datums_datum_hash_str;
-                dap_get_data_hash_str_static(l_datums[i]->data, l_datums[i]->header.data_size, l_datums_datum_hash_str);
-                bool l_err = dap_chain_node_mempool_process(l_chain, l_datums[i]);
+                bool l_err = dap_chain_node_mempool_process(l_chain, l_datums[i], l_subcmd_str_arg);
                 if (l_err) {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Error! Datum %s doesn't pass verifications, examine node log files",
-                                                      l_datums_datum_hash_str);
+                                                      l_subcmd_str_arg);
                     ret = -9;
                 } else {
                    log_it(L_INFO, "Pass datum %s from mempool to block in the new forming round ",
-                                                     l_datums_datum_hash_str);
+                                                     l_subcmd_str_arg);
                    ret = 0;
                 }
                 if (l_err)
@@ -616,9 +626,8 @@ static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply)
                 }
 
                 pthread_rwlock_rdlock(&PVT(l_blocks)->rwlock);
-                dap_string_t * l_str_tmp = dap_string_new(NULL);
-                dap_chain_block_cache_t * l_block_cache = NULL,*l_block_cache_tmp = NULL;               
-                HASH_ITER(hh,PVT(l_blocks)->block_cache_first,l_block_cache, l_block_cache_tmp ) {
+                dap_string_t * l_str_tmp = dap_string_new(NULL);             
+                for (dap_chain_block_cache_t *l_block_cache = PVT(l_blocks)->blocks; l_block_cache; l_block_cache = l_block_cache->hh.next) {
                     char l_buf[50];
                     time_t l_ts = l_block_cache->block->hdr.ts_created;
                     ctime_r(&l_ts, l_buf);
@@ -628,18 +637,15 @@ static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply)
                         if(!dap_pkey_compare_with_sign(l_pub_key, l_sign))
                             continue;
                         if(l_unspent_fl){
-                            dap_chain_block_cache_tx_index_t *l_tx_cur, *l_tmp;
-                            //dap_chain_tx_out_cond_t *l_tx_out_cond = NULL;
                             bool fl_found = false;
-                            HASH_ITER(hh, l_block_cache->tx_index, l_tx_cur, l_tmp)
-                            {
+                            for (size_t i = 0; i < l_block_cache->datum_count; i++) {
+                                if (l_block_cache->datum[i]->header.type_id != DAP_CHAIN_DATUM_TX)
+                                    continue;
+                                dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_block_cache->datum[i]->data;
                                 int l_out_idx_tmp = 0;
-                                if (NULL == dap_chain_datum_tx_out_cond_get(l_tx_cur->tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE,&l_out_idx_tmp))
-                                {
+                                if (NULL == dap_chain_datum_tx_out_cond_get(l_tx, DAP_CHAIN_TX_OUT_COND_SUBTYPE_FEE, &l_out_idx_tmp))
                                     continue;
-                                }
-                                if(!dap_chain_ledger_tx_hash_is_used_out_item(l_net->pub.ledger,&l_tx_cur->tx_hash,l_out_idx_tmp))
-                                {
+                                if (!dap_chain_ledger_tx_hash_is_used_out_item(l_net->pub.ledger, l_block_cache->datum_hash + i, l_out_idx_tmp)) {
                                     fl_found = true;
                                     break;
                                 }
@@ -862,11 +868,10 @@ static void s_callback_cs_blocks_purge(dap_chain_t *a_chain)
 /**
  * @brief s_add_atom_to_ledger
  * @param a_blocks
- * @param a_ledger
  * @param a_block_cache
  * @return
  */
-static int s_add_atom_to_ledger(dap_chain_cs_blocks_t * a_blocks, dap_ledger_t * a_ledger, dap_chain_block_cache_t * a_block_cache)
+static int s_add_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 add anything to ledger", a_block_cache->block_hash_str);
@@ -886,27 +891,20 @@ static int s_add_atom_to_ledger(dap_chain_cs_blocks_t * a_blocks, dap_ledger_t *
                    a_block_cache->block_hash_str, l_block_offset,l_datum_size );
             break;
         }
-        dap_hash_fast_t l_tx_hash;
-        int l_res = dap_chain_datum_add(a_blocks->chain, l_datum, l_datum_size, &l_tx_hash);
-        //if (!l_res) {
+        dap_hash_fast_t *l_datum_hash = a_block_cache->datum_hash + i;
+        int l_res = dap_chain_datum_add(a_blocks->chain, l_datum, l_datum_size, l_datum_hash);
         l_ret++;
-        if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
-            // Save tx hash -> block_hash link in hash table
-            dap_chain_tx_block_index_t * l_tx_block= DAP_NEW_Z(dap_chain_tx_block_index_t);
-            l_tx_block->ts_added = time(NULL);
-            l_tx_block->block_hash = a_block_cache->block_hash;
-            l_tx_block->tx_hash = l_tx_hash;
-            l_tx_block->res = l_res;
-            pthread_rwlock_wrlock( &PVT(a_blocks)->rwlock );
-            HASH_ADD(hh, PVT(a_blocks)->tx_block_index, tx_hash, sizeof(l_tx_block->tx_hash), l_tx_block);
-            pthread_rwlock_unlock( &PVT(a_blocks)->rwlock );
-        }
-        //} else {
-            /* @RRL: disabled due spaming ...
-            debug_if(s_debug_more, L_ERROR, "Can't load datum #%zu (%s) from block %s to ledger: code %d", i,
-                     dap_chain_datum_type_id_to_str(l_datum->header.type_id), a_block_cache->block_hash_str, l_res);
-            */
-        //}
+        // Save datum hash -> block_hash link in hash table
+        dap_chain_block_datum_index_t *l_datum_index = DAP_NEW_Z(dap_chain_block_datum_index_t);
+        l_datum_index->ts_added = time(NULL);
+        l_datum_index->block_cache = a_block_cache;
+        l_datum_index->datum_hash = *l_datum_hash;
+        l_datum_index->ret_code = l_res;
+        l_datum_index->datum_index = i;
+        pthread_rwlock_wrlock(&PVT(a_blocks)->datums_rwlock);
+        HASH_ADD(hh, PVT(a_blocks)->datum_index, datum_hash, sizeof(*l_datum_hash), l_datum_index);
+        pthread_rwlock_unlock(&PVT(a_blocks)->datums_rwlock);
+
     }
     return l_ret;
 }
@@ -915,14 +913,13 @@ static int s_add_atom_to_ledger(dap_chain_cs_blocks_t * a_blocks, dap_ledger_t *
 /**
  * @brief s_add_atom_to_blocks
  * @param a_blocks
- * @param a_ledger
  * @param a_block_cache
  * @return
  */
-static int s_add_atom_to_blocks(dap_chain_cs_blocks_t * a_blocks, dap_ledger_t * a_ledger, dap_chain_block_cache_t * a_block_cache )
+static int s_add_atom_to_blocks(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_cache_t *a_block_cache )
 {
     int l_res = 0;
-    l_res = s_add_atom_to_ledger(a_blocks, a_ledger, a_block_cache);
+    l_res = s_add_atom_datums(a_blocks, a_block_cache);
     debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str,
                                                             l_res == (int)a_block_cache->datum_count ?
                                                             "all correct" : "but ledger declined");
@@ -986,7 +983,7 @@ static void s_bft_consensus_setup(dap_chain_cs_blocks_t * a_blocks)
                     if (a_blocks->callback_block_verify)
                         l_check_res = a_blocks->callback_block_verify(a_blocks, l_block_cache->block, l_block_cache->block_size);
                     if (!l_check_res)
-                        l_check_res = s_add_atom_to_blocks(a_blocks, a_blocks->chain->ledger, l_block_cache);
+                        l_check_res = s_add_atom_to_blocks(a_blocks, l_block_cache);
                     if ( l_check_res != 0 ){
                         log_it(L_WARNING,"Can't move block %s from chunk to main chain - data inside wasn't verified: code %d",
                                             l_block_cache->block_hash_str, l_check_res);
@@ -1046,7 +1043,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
         ret = ATOM_REJECT; // TODO remove it when threshold will work
 
     if( ret == ATOM_ACCEPT){
-        int l_consensus_check = s_add_atom_to_blocks(l_blocks, a_chain->ledger, l_block_cache);
+        int l_consensus_check = s_add_atom_to_blocks(l_blocks, l_block_cache);
         if(l_consensus_check == 1){
              debug_if(s_debug_more, L_DEBUG, "... added");
         }else if (l_consensus_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS){
@@ -1231,21 +1228,21 @@ static dap_chain_atom_ptr_t s_callback_atom_iter_find_by_hash(dap_chain_atom_ite
  * @param a_atom_hash
  * @return
  */
-static dap_chain_datum_tx_t *s_callback_atom_iter_find_by_tx_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_tx_hash, dap_chain_hash_fast_t *a_block_hash)
+static dap_chain_datum_t *s_callback_datum_find_by_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_datum_hash,
+                                                        dap_chain_hash_fast_t *a_block_hash, int *a_ret_code)
 {
     dap_chain_cs_blocks_t * l_cs_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
-    dap_chain_tx_block_index_t * l_tx_block_index = NULL;
-    HASH_FIND(hh, PVT(l_cs_blocks)->tx_block_index,a_tx_hash, sizeof (*a_tx_hash), l_tx_block_index);
-    if (l_tx_block_index){
-        dap_chain_block_cache_t *l_block_cache = dap_chain_block_cs_cache_get_by_hash(l_cs_blocks, &l_tx_block_index->block_hash);
-        if ( l_block_cache){
-            if (a_block_hash)
-                *a_block_hash = l_tx_block_index->block_hash;
-            return dap_chain_block_cache_get_tx_by_hash(l_block_cache, a_tx_hash);
-        }else
-            return NULL;
-    }else
+    dap_chain_block_datum_index_t *l_datum_index = NULL;
+    pthread_rwlock_rdlock(&PVT(l_cs_blocks)->datums_rwlock);
+    HASH_FIND(hh, PVT(l_cs_blocks)->datum_index, a_datum_hash, sizeof (*a_datum_hash), l_datum_index);
+    pthread_rwlock_unlock(&PVT(l_cs_blocks)->datums_rwlock);
+    if (!l_datum_index || !l_datum_index->block_cache)
         return NULL;
+    if (a_block_hash)
+        *a_block_hash = l_datum_index->block_cache->block_hash;
+    if (a_ret_code)
+        *a_ret_code = l_datum_index->ret_code;
+    return l_datum_index->block_cache->datum[l_datum_index->datum_index];
 }
 
 /**
@@ -1257,16 +1254,13 @@ static dap_chain_datum_tx_t *s_callback_atom_iter_find_by_tx_hash(dap_chain_t *a
 static dap_chain_atom_ptr_t s_callback_block_find_by_tx_hash(dap_chain_t * a_chain, dap_chain_hash_fast_t * a_tx_hash)
 {
     dap_chain_cs_blocks_t * l_cs_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
-    dap_chain_tx_block_index_t * l_tx_block_index = NULL;
-    HASH_FIND(hh, PVT(l_cs_blocks)->tx_block_index,a_tx_hash, sizeof (*a_tx_hash), l_tx_block_index);
-    if (l_tx_block_index){
-        dap_chain_block_cache_t *l_block_cache = dap_chain_block_cs_cache_get_by_hash(l_cs_blocks, &l_tx_block_index->block_hash);
-        if ( l_block_cache){
-            return l_block_cache;
-        }else
-            return NULL;
-    }else
+    dap_chain_block_datum_index_t *l_datum_index = NULL;
+    pthread_rwlock_rdlock(&PVT(l_cs_blocks)->datums_rwlock);
+    HASH_FIND(hh, PVT(l_cs_blocks)->datum_index, a_tx_hash, sizeof (*a_tx_hash), l_datum_index);
+    pthread_rwlock_unlock(&PVT(l_cs_blocks)->datums_rwlock);
+    if (!l_datum_index)
         return NULL;
+    return l_datum_index->block_cache;
 }
 
 /**
@@ -1416,6 +1410,59 @@ static void s_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_iter)
     DAP_DELETE(a_atom_iter);
 }
 
+static dap_chain_datum_iter_t *s_chain_callback_datum_iter_create(dap_chain_t *a_chain)
+{
+    dap_chain_datum_iter_t *l_ret = DAP_NEW_Z(dap_chain_datum_iter_t);
+    l_ret->chain = a_chain;
+    return l_ret;
+}
+
+static void s_chain_callback_datum_iter_delete(dap_chain_datum_iter_t *a_datum_iter)
+{
+    DAP_DELETE(a_datum_iter);
+}
+
+static void s_datum_iter_fill(dap_chain_datum_iter_t *a_datum_iter, dap_chain_block_datum_index_t *a_datum_index)
+{
+    a_datum_iter->cur_item = a_datum_index;
+    if (a_datum_index) {
+        a_datum_iter->cur = a_datum_index->block_cache->datum[a_datum_index->datum_index];
+        a_datum_iter->cur_size = dap_chain_datum_size(a_datum_iter->cur);
+        a_datum_iter->cur_hash = &a_datum_index->datum_hash;
+        a_datum_iter->cur_atom_hash = &a_datum_index->block_cache->block_hash;
+        a_datum_iter->ret_code = a_datum_index->ret_code;
+    } else {
+        a_datum_iter->cur = NULL;
+        a_datum_iter->cur_hash = NULL;
+        a_datum_iter->cur_atom_hash = NULL;
+        a_datum_iter->cur_size = 0;
+        a_datum_iter->ret_code = 0;
+    }
+}
+
+static dap_chain_datum_t *s_chain_callback_datum_iter_get_first(dap_chain_datum_iter_t *a_datum_iter)
+{
+    dap_chain_cs_blocks_t * l_cs_blocks = DAP_CHAIN_CS_BLOCKS(a_datum_iter->chain);
+    pthread_rwlock_rdlock(&PVT(l_cs_blocks)->datums_rwlock);
+    dap_chain_block_datum_index_t *l_datum_index = PVT(l_cs_blocks)->datum_index;
+    s_datum_iter_fill(a_datum_iter, l_datum_index);
+    pthread_rwlock_unlock(&PVT(l_cs_blocks)->datums_rwlock);
+    return a_datum_iter->cur;
+}
+
+static dap_chain_datum_t *s_chain_callback_datum_iter_get_next(dap_chain_datum_iter_t *a_datum_iter)
+{
+    dap_chain_cs_blocks_t * l_cs_blocks = DAP_CHAIN_CS_BLOCKS(a_datum_iter->chain);
+    pthread_rwlock_rdlock(&PVT(l_cs_blocks)->datums_rwlock);
+    dap_chain_block_datum_index_t *l_datum_index = a_datum_iter->cur_item;
+    if (l_datum_index)
+        l_datum_index = l_datum_index->hh.next;
+    s_datum_iter_fill(a_datum_iter, l_datum_index);
+    pthread_rwlock_unlock(&PVT(l_cs_blocks)->datums_rwlock);
+    return a_datum_iter->cur;
+}
+
+
 static dap_chain_block_t *s_new_block_move(dap_chain_cs_blocks_t *a_blocks, size_t *a_new_block_size)
 {
     size_t l_ret_size = 0;
diff --git a/modules/type/blocks/include/dap_chain_block_cache.h b/modules/type/blocks/include/dap_chain_block_cache.h
index 3d608ba6e422316df0e550c59894409e6cd3728e..b0cbfdac0cebf64a5aae3e3160dd36c5ecd73fe1 100644
--- a/modules/type/blocks/include/dap_chain_block_cache.h
+++ b/modules/type/blocks/include/dap_chain_block_cache.h
@@ -30,14 +30,7 @@
 
 typedef struct dap_chain_cs_blocks dap_chain_cs_blocks_t;
 
-typedef struct dap_chain_block_cache_tx_index
-{
-    dap_chain_hash_fast_t tx_hash;
-    dap_chain_datum_tx_t* tx;
-    UT_hash_handle hh;
-} dap_chain_block_cache_tx_index_t;
-
-typedef struct dap_chain_block_cache{
+typedef struct dap_chain_block_cache {
     // Block's general non-nested attributes
     dap_chain_hash_fast_t block_hash;
     char* block_hash_str;
@@ -49,7 +42,7 @@ typedef struct dap_chain_block_cache{
     // Block's datums
     size_t datum_count;
     dap_chain_datum_t ** datum;
-    dap_chain_block_cache_tx_index_t * tx_index;
+    dap_hash_fast_t *datum_hash;
 
     // Block's metadatas
     size_t meta_count;
@@ -93,9 +86,8 @@ dap_chain_block_cache_t *dap_chain_block_cache_new(dap_chain_cs_blocks_t *a_bloc
 dap_chain_block_cache_t *dap_chain_block_cache_dup(dap_chain_block_cache_t *a_block);
 int dap_chain_block_cache_update(dap_chain_block_cache_t *a_block_cache, dap_hash_fast_t *a_block_hash);
 void dap_chain_block_cache_delete(dap_chain_block_cache_t *a_block_cache);
-dap_chain_datum_tx_t *dap_chain_block_cache_get_tx_by_hash(dap_chain_block_cache_t *a_block_cache, dap_chain_hash_fast_t *a_tx_hash);
-// Get the list of 'out_cond' items from previous transactions with summary out value
-// Put this summary value to a_value_out
+
+// 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);
 
 
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index 95e9efacdf06e487bb2220f31283ee07ffcb70f0..8fc47e70fbec840fa8ac381cfa693c0fafc1d7be 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -59,10 +59,12 @@
 
 typedef struct dap_chain_cs_dag_event_item {
     dap_chain_hash_fast_t hash;
+    dap_chain_hash_fast_t datum_hash;
     dap_nanotime_t ts_added;
     dap_chain_cs_dag_event_t *event;
     size_t event_size;
-    UT_hash_handle hh, th;
+    int ret_code;
+    UT_hash_handle hh, hh_select, hh_datums;
 } dap_chain_cs_dag_event_item_t;
 
 typedef struct dap_chain_cs_dag_blocked {
@@ -72,15 +74,16 @@ typedef struct dap_chain_cs_dag_blocked {
 
 
 typedef struct dap_chain_cs_dag_pvt {
-    pthread_rwlock_t events_rwlock;
+    pthread_mutex_t events_mutex;
     dap_chain_cs_dag_event_item_t * events;
-    dap_chain_cs_dag_event_item_t * tx_events;
+    dap_chain_cs_dag_event_item_t * datums;
     dap_chain_cs_dag_event_item_t * events_treshold;
     dap_chain_cs_dag_event_item_t * events_treshold_conflicted;
     dap_chain_cs_dag_event_item_t * events_lasts_unlinked;
     dap_chain_cs_dag_blocked_t *removed_events_from_treshold;
     dap_interval_timer_t mempool_timer;
     dap_interval_timer_t treshold_fee_timer;
+    size_t tx_count;
 } dap_chain_cs_dag_pvt_t;
 
 #define PVT(a) ((dap_chain_cs_dag_pvt_t *) a->_pvt )
@@ -88,7 +91,7 @@ typedef struct dap_chain_cs_dag_pvt {
 
 static void s_dap_chain_cs_dag_purge(dap_chain_t *a_chain);
 static void s_dap_chain_cs_dag_threshold_free(dap_chain_cs_dag_t *a_dag);
-dap_chain_cs_dag_event_item_t* dap_chain_cs_dag_proc_treshold(dap_chain_cs_dag_t * a_dag, dap_ledger_t * a_ledger);
+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
@@ -103,7 +106,8 @@ static dap_chain_atom_iter_t* s_chain_callback_atom_iter_create_from(dap_chain_t
 
 static dap_chain_atom_ptr_t s_chain_callback_atom_iter_find_by_hash(dap_chain_atom_iter_t * a_atom_iter ,
                                                                        dap_chain_hash_fast_t * a_atom_hash, size_t * a_atom_size);
-static dap_chain_datum_tx_t *s_chain_callback_atom_find_by_tx_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_tx_hash, dap_chain_hash_fast_t *a_event_hash);
+static dap_chain_datum_t *s_chain_callback_atom_find_by_datum_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_datum_hash,
+                                                                   dap_chain_hash_fast_t *a_event_hash, int *a_ret_code);
 static dap_chain_datum_t** s_chain_callback_atom_get_datum(dap_chain_atom_ptr_t a_event, size_t a_atom_size, size_t *a_datums_count);
 static dap_time_t s_chain_callback_atom_get_timestamp(dap_chain_atom_ptr_t a_atom) { return ((dap_chain_cs_dag_event_t *)a_atom)->header.ts_created; }
 //    Get event(s) from dag
@@ -119,13 +123,12 @@ static void s_chain_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_ite
 
 static bool s_chain_callback_datums_pool_proc(dap_chain_t * a_chain, dap_chain_datum_t *a_datum);
 static size_t s_callback_add_datums(dap_chain_t *a_chain, dap_chain_datum_t **a_datums, size_t a_datums_count);
+
 // Datum ops
-/*
-static dap_chain_datum_iter_t* s_chain_callback_datum_iter_create(dap_chain_t * a_chain );
-static void s_chain_callback_datum_iter_delete(dap_chain_datum_iter_t * a_iter );
-static dap_chain_datum_t* s_chain_callback_datum_iter_get_first( dap_chain_datum_iter_t * a_datum_iter ); // Get the fisrt datum from dag
-static dap_chain_datum_t* s_chain_callback_datum_iter_get_next( dap_chain_datum_iter_t * a_datum_iter ); // Get the next datum from dag
-*/
+static dap_chain_datum_iter_t *s_chain_callback_datum_iter_create(dap_chain_t *a_chain);
+static void s_chain_callback_datum_iter_delete(dap_chain_datum_iter_t *a_datum_iter);
+static dap_chain_datum_t *s_chain_callback_datum_iter_get_first(dap_chain_datum_iter_t *a_datum_iter); // Get the fisrt datum from dag
+static dap_chain_datum_t *s_chain_callback_datum_iter_get_next(dap_chain_datum_iter_t *a_datum_iter); // Get the next datum from dag
 
 static int s_cli_dag(int argc, char ** argv, char **str_reply);
 void s_dag_events_lasts_process_new_last_event(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_event_item_t * a_event_item);
@@ -226,7 +229,11 @@ int dap_chain_cs_dag_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     l_dag->_pvt = DAP_NEW_Z(dap_chain_cs_dag_pvt_t);
     l_dag->chain = a_chain;
 
-    pthread_rwlock_init(& PVT(l_dag)->events_rwlock,NULL);
+    pthread_mutexattr_t l_mutex_attr;
+    pthread_mutexattr_init(&l_mutex_attr);
+    pthread_mutexattr_settype(&l_mutex_attr, PTHREAD_MUTEX_RECURSIVE);
+    pthread_mutex_init(&PVT(l_dag)->events_mutex, &l_mutex_attr);
+    pthread_mutexattr_destroy(&l_mutex_attr);
 
     a_chain->callback_delete = dap_chain_cs_dag_delete;
     a_chain->callback_purge = s_dap_chain_cs_dag_purge;
@@ -250,17 +257,15 @@ int dap_chain_cs_dag_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     a_chain->callback_atom_get_timestamp = s_chain_callback_atom_get_timestamp;
 
     a_chain->callback_atom_find_by_hash = s_chain_callback_atom_iter_find_by_hash;
-    a_chain->callback_tx_find_by_hash = s_chain_callback_atom_find_by_tx_hash;
+    a_chain->callback_datum_find_by_hash = s_chain_callback_atom_find_by_datum_hash;
 
     a_chain->callback_add_datums = s_callback_add_datums;
 
     // Datum operations callbacks
-/*
     a_chain->callback_datum_iter_create = s_chain_callback_datum_iter_create; // Datum iterator create
     a_chain->callback_datum_iter_delete = s_chain_callback_datum_iter_delete; // Datum iterator delete
     a_chain->callback_datum_iter_get_first = s_chain_callback_datum_iter_get_first; // Get the fisrt datum from chain
     a_chain->callback_datum_iter_get_next = s_chain_callback_datum_iter_get_next; // Get the next datum from chain from the current one
-*/
 
     // Get tx list
     a_chain->callback_get_txs = s_dap_chain_callback_get_txs;
@@ -325,7 +330,7 @@ static void s_dap_chain_cs_dag_threshold_free(dap_chain_cs_dag_t *a_dag) {
     dap_chain_cs_dag_pvt_t *l_pvt = PVT(a_dag);
     dap_chain_cs_dag_event_item_t *l_current = NULL, *l_tmp = NULL;
     dap_nanotime_t  l_time_cut_off = dap_nanotime_now() - dap_nanotime_from_sec(7200); //7200 sec = 2 hours.
-    pthread_rwlock_wrlock(&l_pvt->events_rwlock);
+    pthread_mutex_lock(&l_pvt->events_mutex);
     //Fee treshold
     HASH_ITER(hh, l_pvt->events_treshold, l_current, l_tmp) {
         if (l_current->ts_added < l_time_cut_off) {
@@ -351,13 +356,14 @@ static void s_dap_chain_cs_dag_threshold_free(dap_chain_cs_dag_t *a_dag) {
             DAP_DELETE(l_hash_dag);
         }
     }
-    pthread_rwlock_unlock(&l_pvt->events_rwlock);
+    pthread_mutex_unlock(&l_pvt->events_mutex);
 }
 
 static void s_dap_chain_cs_dag_purge(dap_chain_t *a_chain)
 {
     dap_chain_cs_dag_pvt_t *l_dag_pvt = PVT(DAP_CHAIN_CS_DAG(a_chain));
-    pthread_rwlock_wrlock(&l_dag_pvt->events_rwlock);
+    pthread_mutex_lock(&l_dag_pvt->events_mutex);
+    HASH_CLEAR(hh_datums, l_dag_pvt->datums);
     dap_chain_cs_dag_event_item_t *l_event_current, *l_event_tmp;
     // Clang bug at this, l_event_current should change at every loop cycle
     HASH_ITER(hh, l_dag_pvt->events, l_event_current, l_event_tmp) {
@@ -376,11 +382,7 @@ static void s_dap_chain_cs_dag_purge(dap_chain_t *a_chain)
         HASH_DEL(l_dag_pvt->events_treshold_conflicted, l_event_current);
         DAP_DELETE(l_event_current);
     }
-    HASH_ITER(hh, l_dag_pvt->tx_events, l_event_current, l_event_tmp) {
-        HASH_DEL(l_dag_pvt->tx_events, l_event_current);
-        DAP_DELETE(l_event_current);
-    }
-    pthread_rwlock_unlock(&l_dag_pvt->events_rwlock);
+    pthread_mutex_unlock(&l_dag_pvt->events_mutex);
     dap_chain_cell_t *l_cell_cur, *l_cell_tmp;
     HASH_ITER(hh, a_chain->cells, l_cell_cur, l_cell_tmp) {
         dap_chain_cell_close(l_cell_cur);
@@ -396,7 +398,7 @@ void dap_chain_cs_dag_delete(dap_chain_t * a_chain)
 {
     s_dap_chain_cs_dag_purge(a_chain);
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG ( a_chain );
-    pthread_rwlock_destroy(& PVT(l_dag)->events_rwlock);
+    pthread_mutex_destroy(& PVT(l_dag)->events_mutex);
     dap_interval_timer_delete(PVT(l_dag)->mempool_timer);
     if(l_dag->callback_delete )
         l_dag->callback_delete(l_dag);
@@ -407,7 +409,7 @@ void dap_chain_cs_dag_delete(dap_chain_t * a_chain)
 }
 
 
-static int s_dap_chain_add_atom_to_ledger(dap_chain_cs_dag_t * a_dag, dap_ledger_t * a_ledger, dap_chain_cs_dag_event_item_t * a_event_item)
+static int s_dap_chain_add_datum(dap_chain_cs_dag_t *a_dag, dap_chain_cs_dag_event_item_t *a_event_item)
 {
     dap_chain_datum_t *l_datum = (dap_chain_datum_t*) dap_chain_cs_dag_event_get_datum(a_event_item->event, a_event_item->event_size);
     if(a_event_item->event_size< sizeof(l_datum->header) ){
@@ -420,39 +422,33 @@ static int s_dap_chain_add_atom_to_ledger(dap_chain_cs_dag_t * a_dag, dap_ledger
         log_it(L_WARNING, "Corrupted event, too big size %zd in header when event's size max is only %zd", l_datum_size, l_datum_size_max);
         return -1;
     }
-    dap_hash_fast_t l_tx_hash = {};
-    if(dap_chain_datum_add(a_dag->chain,l_datum, l_datum_size, &l_tx_hash) == 0) {
-        pthread_rwlock_t * l_events_rwlock = &PVT(a_dag)->events_rwlock;
-        if  (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
-            unsigned l_hash_item_hashv;
-            HASH_VALUE(&l_tx_hash, sizeof(l_tx_hash), l_hash_item_hashv);
-            dap_chain_cs_dag_event_item_t *l_tx_event;
-            int l_err = pthread_rwlock_wrlock(l_events_rwlock);
-            HASH_FIND_BYHASHVALUE(hh, PVT(a_dag)->tx_events, &l_tx_hash, sizeof(l_tx_event->hash),
-                                  l_hash_item_hashv, l_tx_event);
-            if (!l_tx_event) {
-                l_tx_event = DAP_NEW_Z(dap_chain_cs_dag_event_item_t);
-                l_tx_event->ts_added = a_event_item->ts_added;
-                l_tx_event->event = a_event_item->event;
-                l_tx_event->event_size = a_event_item->event_size;
-                l_tx_event->hash = l_tx_hash;
-                HASH_ADD_BYHASHVALUE(hh, PVT(a_dag)->tx_events, hash, sizeof(l_tx_event->hash),
-                                     l_hash_item_hashv, l_tx_event);
-            }
-            if (l_err != EDEADLK)
-                pthread_rwlock_unlock(l_events_rwlock);
-        }
-        return 0;
-    } else
-        return -1;
+    dap_hash_fast_t l_datum_hash;
+    dap_hash_fast(l_datum->data, l_datum->header.data_size, &l_datum_hash);
+    int l_ret = dap_chain_datum_add(a_dag->chain, l_datum, l_datum_size, &l_datum_hash);
+    if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX)  // && l_ret == 0
+        PVT(a_dag)->tx_count++;
+    a_event_item->ts_added = a_event_item->ts_added;
+    a_event_item->datum_hash = l_datum_hash;
+    a_event_item->ret_code = l_ret;
+    unsigned l_hash_item_hashv;
+    HASH_VALUE(&l_datum_hash, sizeof(l_datum_hash), l_hash_item_hashv);
+    pthread_mutex_lock(&PVT(a_dag)->events_mutex);
+    dap_chain_cs_dag_event_item_t *l_datum_present = NULL;
+    HASH_FIND_BYHASHVALUE(hh_datums, PVT(a_dag)->datums, &l_datum_hash, sizeof(l_datum_hash),
+                          l_hash_item_hashv, l_datum_present);
+    if (!l_datum_present)
+        HASH_ADD_BYHASHVALUE(hh_datums, PVT(a_dag)->datums, datum_hash, sizeof(l_datum_hash),
+                             l_hash_item_hashv, a_event_item);
+    pthread_mutex_unlock(&PVT(a_dag)->events_mutex);
+    return l_ret;
 }
 
-static int s_dap_chain_add_atom_to_events_table(dap_chain_cs_dag_t * a_dag, dap_ledger_t * a_ledger, dap_chain_cs_dag_event_item_t * a_event_item )
+static int s_dap_chain_add_atom_to_events_table(dap_chain_cs_dag_t *a_dag, dap_chain_cs_dag_event_item_t *a_event_item)
 {
-    int l_ledger_res = s_dap_chain_add_atom_to_ledger(a_dag, a_ledger, a_event_item);
+    int l_ledger_res = s_dap_chain_add_datum(a_dag, a_event_item);
     if (s_debug_more) {
-        char l_buf_hash[128] = {'\0'};
-        dap_chain_hash_fast_to_str(&a_event_item->hash,l_buf_hash,sizeof(l_buf_hash)-1);
+        char l_buf_hash[DAP_CHAIN_HASH_FAST_STR_SIZE] = {'\0'};
+        dap_chain_hash_fast_to_str(&a_event_item->hash, l_buf_hash, sizeof(l_buf_hash));
         log_it(L_DEBUG,"Dag event %s checked, add it to ledger", l_buf_hash);
         if (l_ledger_res != 0)
             log_it(L_WARNING,"Dag event %s checked, but ledger declined: code %d", l_buf_hash, l_ledger_res);
@@ -481,7 +477,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
     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 = DAP_NEW_Z(dap_chain_cs_dag_event_item_t);
-    pthread_rwlock_t * l_events_rwlock = &PVT(l_dag)->events_rwlock;
+    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();
@@ -496,11 +492,11 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
         log_it(L_DEBUG, "Processing event: %s... (size %zd)", l_event_hash_str,a_atom_size);
     }
 
-    pthread_rwlock_rdlock(l_events_rwlock);
+    pthread_mutex_lock(l_events_mutex);
     // check if we already have this event
     dap_chain_atom_verify_res_t ret = s_dap_chain_check_if_event_is_present(PVT(l_dag)->events, &l_event_item->hash) ||
             s_dap_chain_check_if_event_is_present(PVT(l_dag)->events_treshold, &l_event_item->hash) ? ATOM_PASS : ATOM_ACCEPT;
-    pthread_rwlock_unlock(l_events_rwlock);
+    pthread_mutex_unlock(l_events_mutex);
 
     // verify hashes and consensus
     switch (ret) {
@@ -528,7 +524,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
 
     switch (ret) {
     case ATOM_MOVE_TO_THRESHOLD:
-        pthread_rwlock_wrlock(l_events_rwlock);
+        pthread_mutex_lock(l_events_mutex);
         dap_chain_cs_dag_blocked_t *el = NULL;
         HASH_FIND(hh, PVT(l_dag)->removed_events_from_treshold, &l_event_item->hash, sizeof(dap_chain_hash_fast_t), el);
         if (!el) {
@@ -541,10 +537,10 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
             if (s_debug_more)
                 log_it(L_DEBUG, "... rejected because the atom was removed from the threshold.");
         }
-        pthread_rwlock_unlock(l_events_rwlock);
+        pthread_mutex_unlock(l_events_mutex);
         break;
     case ATOM_ACCEPT: {
-        int l_consensus_check = s_dap_chain_add_atom_to_events_table(l_dag, a_chain->ledger, l_event_item);
+        int l_consensus_check = s_dap_chain_add_atom_to_events_table(l_dag, l_event_item);
         switch (l_consensus_check) {
         case 0:
             if(s_debug_more)
@@ -568,10 +564,10 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
                 log_it(L_WARNING, "... added with ledger code %d", l_consensus_check);
             break;
         }
-        pthread_rwlock_wrlock(l_events_rwlock);
+        pthread_mutex_lock(l_events_mutex);
         HASH_ADD(hh, PVT(l_dag)->events,hash, sizeof(l_event_item->hash), l_event_item);
         s_dag_events_lasts_process_new_last_event(l_dag, l_event_item);
-        pthread_rwlock_unlock(l_events_rwlock);
+        pthread_mutex_unlock(l_events_mutex);
     } break;
     default:
         DAP_DELETE(l_event_item); // Neither added, nor freed
@@ -589,9 +585,9 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
  */
 static dap_chain_atom_ptr_t s_chain_callback_atom_add_from_treshold(dap_chain_t * a_chain, size_t *a_event_size_out)
 {
-    dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG(a_chain);
-    dap_chain_cs_dag_event_item_t *l_item = dap_chain_cs_dag_proc_treshold(l_dag, a_chain->ledger);
-    if(l_item) {
+    dap_chain_cs_dag_t *l_dag = DAP_CHAIN_CS_DAG(a_chain);
+    dap_chain_cs_dag_event_item_t *l_item = s_dag_proc_treshold(l_dag);
+    if (l_item) {
         if(a_event_size_out)
             *a_event_size_out = l_item->event_size;
         return l_item->event;
@@ -655,28 +651,28 @@ static bool s_chain_callback_datums_pool_proc(dap_chain_t *a_chain, dap_chain_da
 
     /* Prepare round */
     if (l_hashes && l_hashes_size) {
-        pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+        pthread_mutex_lock(&PVT(l_dag)->events_mutex);
         if (!HASH_COUNT(PVT(l_dag)->events_lasts_unlinked)) {
-            pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+            pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
             log_it(L_INFO, "Nothing to link");
             return false;
         }
         /* We'll use modification-safe iteration thru the additional hashtable thus the chosen events will not repeat */
 #define always_true(ev) true
         dap_chain_cs_dag_event_item_t *l_tmp = NULL, *l_cur_ev, *l_tmp_ev;
-        HASH_SELECT(th, l_tmp, hh, PVT(l_dag)->events_lasts_unlinked, always_true); /* Always true predicate */
-        pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
-        while ((l_hashes_linked < l_hashes_size) && (HASH_CNT(th, l_tmp) > 0)) {
-            int l_random_id = rand() % HASH_CNT(th, l_tmp), l_hash_id = 0;
-            HASH_ITER(th, l_tmp, l_cur_ev, l_tmp_ev) {
+        HASH_SELECT(hh_select, l_tmp, hh, PVT(l_dag)->events_lasts_unlinked, always_true); /* Always true predicate */
+        pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
+        while ((l_hashes_linked < l_hashes_size) && (HASH_CNT(hh_select, l_tmp) > 0)) {
+            int l_random_id = rand() % HASH_CNT(hh_select, l_tmp), l_hash_id = 0;
+            HASH_ITER(hh_select, l_tmp, l_cur_ev, l_tmp_ev) {
                 if (l_hash_id++ == l_random_id) {
                     l_hashes[l_hashes_linked++] = l_cur_ev->hash;
-                    HASH_DELETE(th, l_tmp, l_cur_ev);
+                    HASH_DELETE(hh_select, l_tmp, l_cur_ev);
                     break;
                 }
             }
         }
-        HASH_CLEAR(th, l_tmp);
+        HASH_CLEAR(hh_select, l_tmp);
         if (l_hashes_linked < l_hashes_size) {
             log_it(L_ERROR, "No enough unlinked events present (only %lu of %lu), a dummy round?", l_hashes_linked, l_hashes_size);
             return false;
@@ -736,9 +732,9 @@ static bool s_chain_callback_datums_pool_proc(dap_chain_t *a_chain, dap_chain_da
 dap_chain_cs_dag_event_t* dap_chain_cs_dag_find_event_by_hash(dap_chain_cs_dag_t * a_dag, dap_chain_hash_fast_t * a_hash)
 {
     dap_chain_cs_dag_event_item_t* l_event_item = NULL;
-    pthread_rwlock_rdlock(&PVT(a_dag)->events_rwlock);
+    pthread_mutex_lock(&PVT(a_dag)->events_mutex);
     HASH_FIND(hh, PVT(a_dag)->events ,a_hash,sizeof(*a_hash), l_event_item);
-    pthread_rwlock_unlock(&PVT(a_dag)->events_rwlock);
+    pthread_mutex_unlock(&PVT(a_dag)->events_mutex);
     dap_chain_cs_dag_event_t * l_event = l_event_item? l_event_item->event: NULL;
     return l_event;
 }
@@ -778,7 +774,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_
     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_atom_verify_res_t res = ATOM_ACCEPT;
-    pthread_rwlock_t *l_events_rwlock = &PVT(l_dag)->events_rwlock;
+    pthread_mutex_t *l_events_mutex = &PVT(l_dag)->events_mutex;
     if (l_event->header.version) {
         if (s_debug_more)
             log_it(L_WARNING, "Unsupported event version, possible corrupted event");
@@ -799,9 +795,9 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_
         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_rwlock_rdlock(l_events_rwlock);
+        pthread_mutex_lock(l_events_mutex);
         HASH_FIND(hh, l_dag->hal, &l_event_hash, sizeof(l_event_hash), l_hash_found);
-        pthread_rwlock_unlock(l_events_rwlock);
+        pthread_mutex_unlock(l_events_mutex);
         if (l_hash_found) {
             return ATOM_ACCEPT;
         }
@@ -841,9 +837,9 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_
         for (size_t i = 0; i< l_event->header.hash_count; i++) {
             dap_chain_hash_fast_t * l_hash =  ((dap_chain_hash_fast_t *) l_event->hashes_n_datum_n_signs) + i;
             dap_chain_cs_dag_event_item_t * l_event_search = NULL;
-            pthread_rwlock_rdlock(l_events_rwlock);
+            pthread_mutex_lock(l_events_mutex);
             HASH_FIND(hh, PVT(l_dag)->events ,l_hash ,sizeof (*l_hash),  l_event_search);
-            pthread_rwlock_unlock(l_events_rwlock);
+            pthread_mutex_unlock(l_events_mutex);
             if (l_event_search == NULL) {
                 if(s_debug_more) {
                     char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
@@ -953,15 +949,15 @@ int dap_chain_cs_dag_event_verify_hashes_with_treshold(dap_chain_cs_dag_t * a_da
 }
 
 /**
- * @brief dap_chain_cs_dag_proc_treshold
+ * @brief s_dag_proc_treshold
  * @param a_dag
  * @returns true if some atoms were moved from threshold to events
  */
-dap_chain_cs_dag_event_item_t* dap_chain_cs_dag_proc_treshold(dap_chain_cs_dag_t * a_dag, dap_ledger_t * a_ledger)
+dap_chain_cs_dag_event_item_t* s_dag_proc_treshold(dap_chain_cs_dag_t * a_dag)
 {
     bool res = false;
     dap_chain_cs_dag_event_item_t * l_event_item = NULL, * l_event_item_tmp = NULL;
-    pthread_rwlock_wrlock(&PVT(a_dag)->events_rwlock);
+    pthread_mutex_lock(&PVT(a_dag)->events_mutex);
     int l_count = HASH_COUNT(PVT(a_dag)->events_treshold);
     log_it(L_DEBUG, "*** %d events in threshold", l_count);
     HASH_ITER(hh, PVT(a_dag)->events_treshold, l_event_item, l_event_item_tmp) {
@@ -972,7 +968,7 @@ dap_chain_cs_dag_event_item_t* dap_chain_cs_dag_proc_treshold(dap_chain_cs_dag_t
                 log_it(L_DEBUG, "Processing event (threshold): %s...", l_event_hash_str);
                 DAP_DELETE(l_event_hash_str);
             }
-            int l_add_res = s_dap_chain_add_atom_to_events_table(a_dag, a_ledger, l_event_item);
+            int l_add_res = s_dap_chain_add_atom_to_events_table(a_dag, l_event_item);
             HASH_DEL(PVT(a_dag)->events_treshold, l_event_item);
             if (!l_add_res) {
                 HASH_ADD(hh, PVT(a_dag)->events, hash, sizeof(l_event_item->hash), l_event_item);
@@ -991,7 +987,7 @@ dap_chain_cs_dag_event_item_t* dap_chain_cs_dag_proc_treshold(dap_chain_cs_dag_t
             HASH_ADD(hh, PVT(a_dag)->events_treshold_conflicted, hash, sizeof (l_event_item->hash), l_event_item);
         }
     }
-    pthread_rwlock_unlock(&PVT(a_dag)->events_rwlock);
+    pthread_mutex_unlock(&PVT(a_dag)->events_mutex);
     return res ? l_event_item : NULL;
 }
 
@@ -1043,7 +1039,6 @@ static dap_chain_atom_iter_t *s_chain_callback_atom_iter_create(dap_chain_t *a_c
     l_atom_iter->chain = a_chain;
     l_atom_iter->cell_id = a_cell_id;
     l_atom_iter->with_treshold = a_with_treshold;
-    pthread_rwlock_rdlock(&a_chain->atoms_rwlock);
 #ifdef WIN32
     log_it(L_DEBUG, "! %p create caller id %lu", l_atom_iter, GetThreadId(GetCurrentThread()));
 #endif
@@ -1091,6 +1086,8 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first(dap_chain_atom_
     a_atom_iter->cur_item = NULL;
     dap_chain_cs_dag_event_item_t *l_item_tmp, *l_item_cur;
     int found = 0;
+
+    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
     HASH_ITER(hh, l_dag_pvt->events, l_item_cur, l_item_tmp) {
         if (l_item_cur->event->header.cell_id.uint64 == a_atom_iter->cell_id.uint64) {
             a_atom_iter->cur_item = l_item_cur;
@@ -1108,6 +1105,7 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_first(dap_chain_atom_
             }
         }
     }
+    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
 
     if ( a_atom_iter->cur_item ){
         a_atom_iter->cur = ((dap_chain_cs_dag_event_item_t*) a_atom_iter->cur_item)->event;
@@ -1136,7 +1134,7 @@ static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_lasts( dap_chain_ato
 {
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG( a_atom_iter->chain );
     dap_chain_atom_ptr_t * l_ret = NULL;
-    pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
     size_t l_lasts_size = HASH_COUNT( PVT(l_dag)->events_lasts_unlinked );
     if ( l_lasts_size > 0 ) {
         if( a_lasts_size)
@@ -1151,7 +1149,7 @@ static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_lasts( dap_chain_ato
             i++;
         }
     }
-    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
     return l_ret;
 }
 
@@ -1183,9 +1181,9 @@ static dap_chain_atom_ptr_t* s_chain_callback_atom_iter_get_links( dap_chain_ato
                 dap_chain_hash_fast_t * l_link_hash = (dap_chain_hash_fast_t *)
                         (l_event->hashes_n_datum_n_signs +
                         i*sizeof(*l_link_hash));
-                pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+                pthread_mutex_lock(&PVT(l_dag)->events_mutex);
                 HASH_FIND(hh, PVT(l_dag)->events,l_link_hash,sizeof(*l_link_hash),l_link_item);
-                pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+                pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
                 if ( l_link_item ){
                     l_ret[i] = l_link_item->event;
                     (*a_links_size_array)[i] = l_link_item->event_size;
@@ -1219,9 +1217,9 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_find_by_hash(dap_chain_at
 {
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG( a_atom_iter->chain );
     dap_chain_cs_dag_event_item_t * l_event_item = NULL;
-    pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
     HASH_FIND(hh, PVT(l_dag)->events,a_atom_hash,sizeof(*a_atom_hash),l_event_item);
-    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
     if ( l_event_item ){
         a_atom_iter->cur_item = l_event_item;
         a_atom_iter->cur = l_event_item->event;
@@ -1234,20 +1232,30 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_find_by_hash(dap_chain_at
         return NULL;
 }
 
-
-static dap_chain_datum_tx_t *s_chain_callback_atom_find_by_tx_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_tx_hash, dap_chain_hash_fast_t *a_event_hash)
+/**
+ * @brief s_chain_callback_atom_find_by_datum_hash
+ * @param IN a_chain
+ * @param IN a_datum_hash
+ * @param OUT a_event_hash
+ * @param OUT a_ret_code
+ * @return
+ */
+static dap_chain_datum_t *s_chain_callback_atom_find_by_datum_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_datum_hash,
+                                                                   dap_chain_hash_fast_t *a_event_hash, int *a_ret_code)
 {
-    dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG( a_chain );
-    dap_chain_cs_dag_event_item_t * l_event_item = NULL;
-    pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
-    HASH_FIND(hh, PVT(l_dag)->tx_events, a_tx_hash, sizeof(*a_tx_hash), l_event_item);
-    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+    dap_chain_cs_dag_t *l_dag = DAP_CHAIN_CS_DAG( a_chain );
+    dap_chain_cs_dag_event_item_t *l_event_item = NULL;
+    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
+    HASH_FIND(hh_datums, PVT(l_dag)->datums, a_datum_hash, sizeof(*a_datum_hash), l_event_item);
+    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
     if ( l_event_item ){
         dap_chain_datum_t *l_datum = dap_chain_cs_dag_event_get_datum(l_event_item->event, l_event_item->event_size);
         if (l_datum && l_datum->header.data_size) {
             if (a_event_hash)
                 *a_event_hash = l_event_item->hash;
-            return (dap_chain_datum_tx_t *)l_datum->data;
+            if (a_ret_code)
+                *a_ret_code = l_event_item->ret_code;
+            return l_datum;
         }
     }
     return NULL;
@@ -1274,6 +1282,7 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next( dap_chain_atom_
         dap_chain_cs_dag_pvt_t *l_dag_pvt = PVT(l_dag);
         assert(l_dag_pvt);
         l_event_item = l_dag_pvt->events_treshold;
+        pthread_mutex_lock(&PVT(l_dag)->events_mutex);
         while (l_event_item) {
             if (l_event_item && l_event_item->event->header.cell_id.uint64 == a_atom_iter->cell_id.uint64) {
                 a_atom_iter->found_in_treshold = 1;
@@ -1281,9 +1290,8 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next( dap_chain_atom_
             }
             l_event_item = (dap_chain_cs_dag_event_item_t *)l_event_item->hh.next;
         }
+        pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
     }
-
-
     // if l_event_item=NULL then items are over
     a_atom_iter->cur_item = l_event_item;
     a_atom_iter->cur = l_event_item ? l_event_item->event : NULL;
@@ -1301,13 +1309,63 @@ static dap_chain_atom_ptr_t s_chain_callback_atom_iter_get_next( dap_chain_atom_
  */
 static void s_chain_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_iter )
 {
-    pthread_rwlock_unlock(&a_atom_iter->chain->atoms_rwlock);
 #ifdef WIN32
     log_it(L_DEBUG, "! Delete caller id %lu", GetThreadId(GetCurrentThread()));
 #endif
     DAP_DELETE(a_atom_iter);
 }
 
+static dap_chain_datum_iter_t *s_chain_callback_datum_iter_create(dap_chain_t *a_chain)
+{
+    dap_chain_datum_iter_t *l_ret = DAP_NEW_Z(dap_chain_datum_iter_t);
+    l_ret->chain = a_chain;
+    return l_ret;
+}
+
+static void s_chain_callback_datum_iter_delete(dap_chain_datum_iter_t *a_datum_iter)
+{
+    DAP_DELETE(a_datum_iter);
+}
+
+static void s_datum_iter_fill(dap_chain_datum_iter_t *a_datum_iter, dap_chain_cs_dag_event_item_t *a_event_item)
+{
+    a_datum_iter->cur_item = a_event_item;
+    if (a_event_item) {
+        a_datum_iter->cur = dap_chain_cs_dag_event_get_datum(a_event_item->event, a_event_item->event_size);
+        a_datum_iter->cur_size = dap_chain_datum_size(a_datum_iter->cur);
+        a_datum_iter->cur_hash = &a_event_item->datum_hash;
+        a_datum_iter->cur_atom_hash = &a_event_item->hash;
+        a_datum_iter->ret_code = a_event_item->ret_code;
+    } else {
+        a_datum_iter->cur = NULL;
+        a_datum_iter->cur_hash = NULL;
+        a_datum_iter->cur_size = 0;
+        a_datum_iter->ret_code = 0;
+    }
+}
+
+static dap_chain_datum_t *s_chain_callback_datum_iter_get_first(dap_chain_datum_iter_t *a_datum_iter)
+{
+    dap_chain_cs_dag_t *l_dag = DAP_CHAIN_CS_DAG(a_datum_iter->chain);
+    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
+    dap_chain_cs_dag_event_item_t *l_item = PVT(l_dag)->datums;
+    s_datum_iter_fill(a_datum_iter, l_item);
+    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
+    return a_datum_iter->cur;
+}
+
+static dap_chain_datum_t *s_chain_callback_datum_iter_get_next(dap_chain_datum_iter_t *a_datum_iter)
+{
+    dap_chain_cs_dag_t *l_dag = DAP_CHAIN_CS_DAG(a_datum_iter->chain);
+    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
+    dap_chain_cs_dag_event_item_t *l_item = a_datum_iter->cur_item;
+    if (l_item)
+        l_item = l_item->hh_datums.next;
+    s_datum_iter_fill(a_datum_iter, l_item);
+    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
+    return a_datum_iter->cur;
+}
+
 /**
  * @brief s_cli_dag
  * @param argc
@@ -1599,13 +1657,13 @@ static int s_cli_dag(int argc, char ** argv, char **a_str_reply)
                 ret = 0;
             } else {
                 dap_chain_cs_dag_event_item_t * l_event_item = NULL;
-                pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+                pthread_mutex_lock(&PVT(l_dag)->events_mutex);
                 HASH_FIND(hh,PVT(l_dag)->events,&l_event_hash,sizeof(l_event_hash),l_event_item);
-                pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+                pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
                 if (l_event_item) {
-                    pthread_rwlock_wrlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
                     HASH_DELETE(hh, PVT(l_dag)->events, l_event_item);
-                    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
                     if(!dap_strcmp(l_hash_out_type, "hex")) {
                         log_it(L_WARNING, "Dropped event %s from chains! Hope you know what are you doing!",
                                l_event_hash_hex_str);
@@ -1651,9 +1709,9 @@ static int s_cli_dag(int argc, char ** argv, char **a_str_reply)
                     }
                 } else if (l_from_events_str && strcmp(l_from_events_str,"events_lasts") == 0) {
                     dap_chain_cs_dag_event_item_t * l_event_item = NULL;
-                    pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
                     HASH_FIND(hh,PVT(l_dag)->events_lasts_unlinked,&l_event_hash,sizeof(l_event_hash),l_event_item);
-                    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
                     if ( l_event_item )
                         l_event = l_event_item->event;
                     else {
@@ -1664,9 +1722,9 @@ static int s_cli_dag(int argc, char ** argv, char **a_str_reply)
                     }
                 } else if (!l_from_events_str || strcmp(l_from_events_str,"events") == 0) {
                     dap_chain_cs_dag_event_item_t * l_event_item = NULL;
-                    pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
                     HASH_FIND(hh,PVT(l_dag)->events,&l_event_hash,sizeof(l_event_hash),l_event_item);
-                    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
                     if ( l_event_item ) {
                         l_event = l_event_item->event;
                         l_event_size = l_event_item->event_size;
@@ -1678,9 +1736,9 @@ static int s_cli_dag(int argc, char ** argv, char **a_str_reply)
                     }
                 } else if (l_from_events_str && strcmp(l_from_events_str,"threshold") == 0) {
                     dap_chain_cs_dag_event_item_t * l_event_item = NULL;
-                    pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
                     HASH_FIND(hh,PVT(l_dag)->events_treshold,&l_event_hash,sizeof(l_event_hash),l_event_item);
-                    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
                     if (l_event_item)
                         l_event = l_event_item->event;
                     else {
@@ -1814,7 +1872,7 @@ static int s_cli_dag(int argc, char ** argv, char **a_str_reply)
                     dap_string_free(l_str_tmp, true);
                 } else if (!l_from_events_str || (strcmp(l_from_events_str,"events") == 0)) {
                     dap_string_t * l_str_tmp = dap_string_new(NULL);
-                    pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
                     dap_chain_cs_dag_event_item_t * l_event_item = NULL,*l_event_item_tmp = NULL;
                     HASH_ITER(hh,PVT(l_dag)->events,l_event_item, l_event_item_tmp ) {
                         char buf[50];
@@ -1825,14 +1883,14 @@ static int s_cli_dag(int argc, char ** argv, char **a_str_reply)
                         DAP_DELETE(l_event_item_hash_str);
                     }
                     size_t l_events_count = HASH_COUNT(PVT(l_dag)->events);
-                    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
                     dap_string_append_printf(l_str_tmp,"%s.%s have total %zu events :\n",
                                              l_net->pub.name, l_chain->name, l_events_count);
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_tmp->str);
                     dap_string_free(l_str_tmp, true);
                  }else if (l_from_events_str && (strcmp(l_from_events_str,"threshold") == 0) ){
                     dap_string_t * l_str_tmp = dap_string_new(NULL);
-                    pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
                     dap_chain_cs_dag_event_item_t * l_event_item = NULL,*l_event_item_tmp = NULL;
                     dap_string_append_printf(l_str_tmp,"\nDAG threshold events:\n");
                     HASH_ITER(hh,PVT(l_dag)->events_treshold,l_event_item, l_event_item_tmp ) {
@@ -1844,7 +1902,7 @@ static int s_cli_dag(int argc, char ** argv, char **a_str_reply)
                         DAP_DELETE(l_event_item_hash_str);
                     }
                     size_t l_events_count = HASH_COUNT(PVT(l_dag)->events_treshold);
-                    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+                    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
                     dap_string_append_printf(l_str_tmp,"%s.%s have total %zu events in threshold :\n",
                                              l_net->pub.name, l_chain->name, l_events_count);
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_tmp->str);
@@ -1930,10 +1988,9 @@ static int s_cli_dag(int argc, char ** argv, char **a_str_reply)
     return ret;
 }
 
-static size_t s_dap_chain_callback_get_count_tx(dap_chain_t *a_chain){
-    dap_chain_cs_dag_t *l_dag = DAP_CHAIN_CS_DAG(a_chain);
-    size_t l_count = HASH_COUNT(PVT(l_dag)->tx_events);
-    return l_count;
+static size_t s_dap_chain_callback_get_count_tx(dap_chain_t *a_chain)
+{
+    return PVT(DAP_CHAIN_CS_DAG(a_chain))->tx_count;
 }
 
 
@@ -1951,22 +2008,21 @@ static dap_list_t *s_dap_chain_callback_get_txs(dap_chain_t *a_chain, size_t a_c
     dap_list_t *l_list = NULL;
     size_t l_counter = 0;
     size_t l_end = l_offset + a_count;
-    for (dap_chain_cs_dag_event_item_t *ptr = PVT(l_dag)->tx_events; ptr != NULL && l_counter < l_end; ptr = ptr->hh.next){
-        if (l_counter >= l_offset){
-            dap_chain_datum_t *l_datum = dap_chain_cs_dag_event_get_datum(ptr->event, ptr->event_size);
+    for (dap_chain_cs_dag_event_item_t *ptr = PVT(l_dag)->datums; ptr != NULL && l_counter < l_end; ptr = ptr->hh_datums.next){
+        dap_chain_datum_t *l_datum = dap_chain_cs_dag_event_get_datum(ptr->event, ptr->event_size);
+        if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX && l_counter++ >= l_offset) {
             dap_chain_datum_tx_t  *l_tx = (dap_chain_datum_tx_t*)l_datum->data;
             l_list = dap_list_append(l_list, l_tx);
         }
-        l_counter++;
     }
     return l_list;
 }
 
 static size_t s_dap_chain_callback_get_count_atom(dap_chain_t *a_chain){
     dap_chain_cs_dag_t  *l_dag = DAP_CHAIN_CS_DAG(a_chain);
-    pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
     size_t l_count = HASH_COUNT(PVT(l_dag)->events);
-    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
     return l_count;
 }
 
@@ -1979,7 +2035,7 @@ static dap_list_t *s_callback_get_atoms(dap_chain_t *a_chain, size_t a_count, si
         return NULL;
     }
     size_t l_offset = a_count * (a_page - 1);
-    pthread_rwlock_rdlock(&PVT(l_dag)->events_rwlock);
+    pthread_mutex_lock(&PVT(l_dag)->events_mutex);
     size_t l_count = HASH_COUNT(l_dag_pvt->events);
     if (a_page < 2)
         l_offset = 0;
@@ -2003,6 +2059,6 @@ static dap_list_t *s_callback_get_atoms(dap_chain_t *a_chain, size_t a_count, si
         }
         l_counter++;
     }
-    pthread_rwlock_unlock(&PVT(l_dag)->events_rwlock);
+    pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
     return l_list;
 }