From b2e337bef380ec03a00e177faf42ac201768a8f5 Mon Sep 17 00:00:00 2001
From: "roman.padenkov" <roman.padenkov@demlabs.net>
Date: Wed, 13 Sep 2023 13:57:38 +0000
Subject: [PATCH] Hotfix 9408+

---
 dap-sdk                                       |   2 +-
 modules/channel/chain/dap_stream_ch_chain.c   |   2 +-
 modules/common/dap_chain_datum_tx_items.c     |   7 +-
 .../consensus/esbocs/dap_chain_cs_esbocs.c    |   2 +-
 modules/net/dap_chain_node_cli_cmd.c          |   6 +-
 modules/type/blocks/dap_chain_cs_blocks.c     | 271 +++++++++---------
 modules/type/dag/dap_chain_cs_dag.c           |  80 ++----
 7 files changed, 174 insertions(+), 196 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index 5c5f3376d3..3ef80ce7ee 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 5c5f3376d3cb3d53c582d82e472cdffce256aac8
+Subproject commit 3ef80ce7eefc7777c7fbb94101419318e7c59fce
diff --git a/modules/channel/chain/dap_stream_ch_chain.c b/modules/channel/chain/dap_stream_ch_chain.c
index 33e6e1c559..27efe47aee 100644
--- a/modules/channel/chain/dap_stream_ch_chain.c
+++ b/modules/channel/chain/dap_stream_ch_chain.c
@@ -783,7 +783,7 @@ static void s_gdb_in_pkt_proc_set_raw_callback(dap_global_db_context_t *a_global
 
     struct sync_request *l_sync_req = (struct sync_request*) a_arg;
     if( a_rc != 0){
-        log_it(L_ERROR, "Can't save GlobalDB request, code %d", a_rc);
+        debug_if(s_debug_more, L_ERROR, "Can't save GlobalDB request, code %d", a_rc);
         dap_worker_exec_callback_inter(a_global_db_context->queue_worker_callback_input[l_sync_req->worker->id],
                                     s_gdb_in_pkt_error_worker_callback, l_sync_req);
     }else{
diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c
index 22ef1f623d..22a5c15573 100644
--- a/modules/common/dap_chain_datum_tx_items.c
+++ b/modules/common/dap_chain_datum_tx_items.c
@@ -787,11 +787,10 @@ uint8_t *dap_chain_datum_tx_item_get_nth(dap_chain_datum_tx_t *a_tx, dap_chain_t
 {
     uint8_t *l_tx_item = NULL;
     int l_item_idx = 0;
-    for (int l_type_idx = 0; l_type_idx <= a_item_idx; l_type_idx++) {
+    for (int l_type_idx = 0; l_type_idx <= a_item_idx; ++l_type_idx, ++l_item_idx) {
         l_tx_item = dap_chain_datum_tx_item_get(a_tx, &l_item_idx, a_type, NULL);
         if (!l_tx_item)
             break;
-        ++l_item_idx;
     }
     return l_tx_item;
 }
@@ -809,9 +808,9 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_out_cond_get(dap_chain_datum_tx_t *a
     dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_ALL, NULL), *l_item;
     int l_prev_cond_idx = a_out_num ? *a_out_num : 0;
     dap_chain_tx_out_cond_t *l_res = NULL;
-    DL_FOREACH(l_list_out_items, l_item) {
+    for (dap_list_t *l_item = l_list_out_items; l_item; l_item = l_item->next, ++l_prev_cond_idx) {
         // Start from *a_out_num + 1 item if a_out_num != NULL
-        if (a_out_num && l_prev_cond_idx++ < *a_out_num)
+        if (a_out_num && l_prev_cond_idx < *a_out_num)
             continue;
         if (*(byte_t*)l_item->data == TX_ITEM_TYPE_OUT_COND &&
                 ((dap_chain_tx_out_cond_t*)l_item->data)->header.subtype == a_cond_type) {
diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index e9db643116..a574c1cb71 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -959,7 +959,7 @@ static uint64_t s_session_calc_current_round_id(dap_chain_esbocs_session_t *a_se
 static int s_signs_sort_callback(const void *a_sign1, const void *a_sign2)
 {
     dap_sign_t  *l_sign1 = (dap_sign_t*)((dap_list_t*)a_sign1)->data,
-                *l_sign2 = (dap_sign_t*)((dap_list_t*)a_sign1)->data;
+                *l_sign2 = (dap_sign_t*)((dap_list_t*)a_sign2)->data;
     if (!l_sign1 || !l_sign2) {
         log_it(L_CRITICAL, "Invalid element");
         return 0;
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 1f8d035bf0..960a8009d9 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -525,10 +525,10 @@ static int node_info_dump_with_reply(dap_chain_net_t * a_net, dap_chain_node_add
     int l_ret = 0;
     dap_string_t *l_string_reply = dap_string_new("Node dump:");
 
-    if (a_addr || a_alias) {
+    if ((a_addr && a_addr->uint64) || a_alias) {
         dap_chain_node_addr_t *l_addr = a_alias
                 ? dap_chain_node_alias_find(a_net, a_alias)
-                : a_addr && a_addr->uint64 ? DAP_DUP(a_addr) : NULL;
+                : DAP_DUP(a_addr);
 
         if (!l_addr) {
             log_it(L_ERROR, "Node address with specified params not found");
@@ -5920,7 +5920,7 @@ int com_tx_history(int a_argc, char ** a_argv, char **a_str_reply)
         DAP_DELETE(l_addr_str);
         DAP_DELETE(l_str_out);
     } else
-        l_str_ret = l_str_out;
+        dap_string_append_printf(l_str_ret, "%s", l_str_out);
     dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_ret->str);
     dap_string_free(l_str_ret, true);
     return 0;
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 9f4f7a121e..8f13d23ab3 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -54,23 +54,16 @@ struct cs_blocks_hal_item {
 
 typedef struct dap_chain_cs_blocks_pvt
 {
-    pthread_rwlock_t rwlock;
     // Parent link
     dap_chain_cs_blocks_t * cs_blocks;
 
     // All the blocks are here. In feature should be limited with 1000 when the rest would be loaded from file when needs them
     dap_chain_block_cache_t * blocks;
-    dap_chain_block_cache_t * blocks_tx_treshold;
 
     // Chunks treshold
     dap_chain_block_chunks_t * chunks;
-
-    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
-    dap_chain_block_cache_t * block_cache_last; // Last block in mapped area
     dap_chain_hash_fast_t genesis_block_hash;
     dap_chain_hash_fast_t static_genesis_block_hash;
 
@@ -80,9 +73,9 @@ typedef struct dap_chain_cs_blocks_pvt
     bool is_celled;
 
     dap_timerfd_t *fill_timer;
-    pthread_rwlock_t datums_lock;
     uint64_t fill_timeout;
 
+    pthread_rwlock_t rwlock, datums_rwlock;
     struct cs_blocks_hal_item *hal;
 } dap_chain_cs_blocks_pvt_t;
 
@@ -260,7 +253,7 @@ int dap_chain_cs_blocks_new(dap_chain_t * a_chain, dap_config_t * a_chain_config
     }
     l_cs_blocks->_pvt = l_cs_blocks_pvt;
     pthread_rwlock_init(&l_cs_blocks_pvt->rwlock,NULL);
-    pthread_rwlock_init(&l_cs_blocks_pvt->datums_lock, NULL);
+    pthread_rwlock_init(&l_cs_blocks_pvt->datums_rwlock, NULL);
 
     const char * l_genesis_blocks_hash_str = dap_config_get_item_str_default(a_chain_config,"blocks","genesis_block",NULL);
     if ( l_genesis_blocks_hash_str ){
@@ -460,8 +453,9 @@ static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply)
             pthread_rwlock_wrlock( &PVT(l_blocks)->rwlock );
             if ( l_blocks->block_new )
                 DAP_DELETE( l_blocks->block_new );
-            l_blocks->block_new = dap_chain_block_new(PVT(l_blocks)->block_cache_last ?
-                                                      &PVT(l_blocks)->block_cache_last->block_hash : NULL,
+            dap_chain_block_cache_t *l_bcache_last = PVT(l_blocks)->blocks ? PVT(l_blocks)->blocks->hh.tbl->tail->prev : NULL;
+            l_bcache_last = l_bcache_last ? l_bcache_last->hh.next : PVT(l_blocks)->blocks;
+            l_blocks->block_new = dap_chain_block_new(l_bcache_last ? &l_bcache_last->block_hash : NULL,
                                                       &l_blocks->block_new_size);
             pthread_rwlock_unlock( &PVT(l_blocks)->rwlock );
         } break;
@@ -867,7 +861,8 @@ static void s_callback_delete(dap_chain_t * a_chain)
         l_blocks->callback_delete(l_blocks);
     pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
     pthread_rwlock_destroy(&PVT(l_blocks)->rwlock);
-    pthread_rwlock_destroy(&PVT(l_blocks)->datums_lock);
+    pthread_rwlock_destroy(&PVT(l_blocks)->datums_rwlock);
+    dap_chain_block_chunks_delete(PVT(l_blocks)->chunks);
     DAP_DEL_Z(l_blocks->_inheritor);
     DAP_DEL_Z(l_blocks->_pvt);
     log_it(L_INFO, "Block destructed");
@@ -883,6 +878,7 @@ static void s_callback_cs_blocks_purge(dap_chain_t *a_chain)
         DAP_DELETE(l_block->block);
         dap_chain_block_cache_delete(l_block);
     }
+    PVT(l_blocks)->blocks_count = 0;
     pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
     
     dap_chain_block_datum_index_t *l_datum_index = NULL, *l_datum_index_tmp = NULL;
@@ -893,11 +889,8 @@ static void s_callback_cs_blocks_purge(dap_chain_t *a_chain)
         l_datum_index = NULL;
     }
     pthread_rwlock_unlock(&PVT(l_blocks)->datums_rwlock);
-    PVT(l_blocks)->blocks_count = 0;
 
     dap_chain_block_chunks_delete(PVT(l_blocks)->chunks);
-    PVT(l_blocks)->block_cache_last = NULL;
-    PVT(l_blocks)->block_cache_first = NULL;
     dap_chain_cell_delete_all(a_chain);
     PVT(l_blocks)->chunks = dap_chain_block_chunks_create(l_blocks);
 }
@@ -960,22 +953,15 @@ static int s_add_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_ca
 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;
-    pthread_rwlock_wrlock( &PVT(a_blocks)->rwlock );
+    //pthread_rwlock_wrlock( &PVT(a_blocks)->rwlock ); // do lock in calling context!
     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");
-    //All correct, no matter for result    
-    HASH_ADD(hh, PVT(a_blocks)->blocks,block_hash,sizeof (a_block_cache->block_hash), a_block_cache);
-    PVT(a_blocks)->blocks_count++;
-    if (! (PVT(a_blocks)->block_cache_first ) )
-            PVT(a_blocks)->block_cache_first = a_block_cache;
-    if (PVT(a_blocks)->block_cache_last)
-        PVT(a_blocks)->block_cache_last->next = a_block_cache;
-    a_block_cache->prev = PVT(a_blocks)->block_cache_last;
-    PVT(a_blocks)->block_cache_last = a_block_cache;
-    pthread_rwlock_unlock( &PVT(a_blocks)->rwlock );
-    return 1;
+             l_res == (int)a_block_cache->datum_count ? "all correct" : "but ledger declined");
+    // Ignore addition result for now
+    HASH_ADD(hh, PVT(a_blocks)->blocks, block_hash, sizeof (a_block_cache->block_hash), a_block_cache);
+    ++PVT(a_blocks)->blocks_count;
+    //pthread_rwlock_unlock( &PVT(a_blocks)->rwlock ); // do unlock in calling context!
+    return /* l_res */ 0;
 }
 
 
@@ -987,7 +973,7 @@ static void s_bft_consensus_setup(dap_chain_cs_blocks_t * a_blocks)
 {
     bool l_was_chunks_changed = false;
     // Compare all chunks with chain's tail
-    for(dap_chain_block_chunk_t * l_chunk = PVT(a_blocks)->chunks->chunks_last ; l_chunk; l_chunk=l_chunk->prev ){
+    for (dap_chain_block_chunk_t *l_chunk = PVT(a_blocks)->chunks->chunks_last ; l_chunk; l_chunk=l_chunk->prev ){
         size_t l_chunk_length = HASH_COUNT(l_chunk->block_cache_hash);
         dap_chain_block_cache_t * l_block_cache_chunk_top_prev = dap_chain_block_cs_cache_get_by_hash(a_blocks,&l_chunk->block_cache_top->prev_hash);
         dap_chain_block_cache_t * l_block_cache= l_block_cache_chunk_top_prev;
@@ -1014,7 +1000,7 @@ static void s_bft_consensus_setup(dap_chain_cs_blocks_t * a_blocks)
                     if(l_block_cache->next)
                         l_block_cache->next->prev = l_block_cache->prev;
                     HASH_DEL(PVT(a_blocks)->blocks,l_block_cache);
-                    PVT(a_blocks)->blocks_count--;
+                    --PVT(a_blocks)->blocks_count;
                     pthread_rwlock_unlock(& PVT(a_blocks)->rwlock);
                     dap_chain_block_chunks_add(PVT(a_blocks)->chunks,l_block_cache);
                 }
@@ -1058,61 +1044,49 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
     dap_chain_block_t * l_block = (dap_chain_block_t *) a_atom;
     size_t l_block_size = a_atom_size;
 
-    pthread_rwlock_wrlock(&PVT(l_blocks)->datums_lock);
     dap_chain_hash_fast_t l_block_hash;
     dap_hash_fast(l_block, l_block_size, &l_block_hash);
-    dap_chain_block_cache_t * l_block_cache = dap_chain_block_cs_cache_get_by_hash(l_blocks, &l_block_hash);
-    if (l_block_cache ){
-        debug_if(s_debug_more, L_DEBUG, "... already present in blocks %s", l_block_cache->block_hash_str);
-        pthread_rwlock_unlock(&PVT(l_blocks)->datums_lock);
+
+    dap_chain_block_cache_t * l_block_cache = NULL;
+    pthread_rwlock_wrlock(& PVT(l_blocks)->rwlock);
+    HASH_FIND(hh, PVT(l_blocks)->blocks, &l_block_hash, sizeof(l_block_hash), l_block_cache);
+    if (l_block_cache) {
+        debug_if(s_debug_more, L_DEBUG, "... %s is already present", l_block_cache->block_hash_str);
+        pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
         return ATOM_PASS;
     } else {
         l_block_cache = dap_chain_block_cache_new(l_blocks, &l_block_hash, l_block, l_block_size);
         if (!l_block_cache) {
             log_it(L_DEBUG, "... corrupted block");
-            pthread_rwlock_unlock(&PVT(l_blocks)->datums_lock);
+            pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
             return ATOM_REJECT;
         }
         debug_if(s_debug_more, L_DEBUG, "... new block %s", l_block_cache->block_hash_str);
     }
-    pthread_rwlock_unlock(&PVT(l_blocks)->datums_lock);
 
-    // verify hashes and consensus
-    dap_chain_atom_verify_res_t ret = s_callback_atom_verify (a_chain, a_atom, a_atom_size);
-
-    if (ret == ATOM_MOVE_TO_THRESHOLD) {
-        //log_it(L_ATT, "Booo!");
-        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, 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){
-            pthread_rwlock_wrlock( &PVT(l_blocks)->rwlock );
-            HASH_ADD(hh, PVT(l_blocks)->blocks_tx_treshold, block_hash, sizeof(l_block_cache->block_hash), l_block_cache);
-            pthread_rwlock_unlock( &PVT(l_blocks)->rwlock );
-            debug_if(s_debug_more, L_DEBUG, "... tresholded for tx ledger");
-        }else{
-             debug_if(s_debug_more, L_WARNING, "... error adding (code %d)", l_consensus_check);
-             ret = ATOM_REJECT;
-        }
-         // !TODO make chunks add to blocks
-    }else if(ret == ATOM_MOVE_TO_THRESHOLD){
-        if (dap_chain_block_cs_cache_get_by_hash(l_blocks, &l_block_hash)) {
-            // if it was concurrent atom processed before
-            dap_chain_block_cache_delete(l_block_cache);
-            return ATOM_PASS;
+    dap_chain_atom_verify_res_t ret = s_callback_atom_verify(a_chain, a_atom, a_atom_size);
+    switch (ret) {
+    case ATOM_ACCEPT:
+        s_add_atom_to_blocks(l_blocks, l_block_cache);
+        debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", a_atom);
+        break;
+    case ATOM_MOVE_TO_THRESHOLD:
+        // TODO: reimplement and enable threshold for blocks
+/*      {
+            debug_if(s_debug_more, L_DEBUG, "Verified atom %p: THRESHOLDED", a_atom);
+            break;
         }
-        dap_chain_block_chunks_add( PVT(l_blocks)->chunks,l_block_cache);
-        //dap_chain_block_chunks_sort(PVT(l_blocks)->chunks);
-    }else if (ret == ATOM_REJECT ){
+*/
+        ret = ATOM_REJECT;
+    case ATOM_REJECT:
         dap_chain_block_cache_delete(l_block_cache);
+        debug_if(s_debug_more, L_DEBUG, "Verified atom %p: REJECTED", a_atom);
+        break;
+    default:
+        debug_if(s_debug_more, L_DEBUG, "Unknown verification ret code %d", ret);
+        break;
     }
-    debug_if(s_debug_more, L_DEBUG, "Verified atom %p: %s", a_atom, ret == ATOM_ACCEPT ? "accepted" :
-                                                   (ret == ATOM_REJECT ? "rejected" : "thresholded"));
-    //s_bft_consensus_setup(l_blocks);
+    pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
     return ret;
 }
 
@@ -1192,9 +1166,12 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain,
             log_it(L_WARNING,"Cant accept genesis block: already present data in blockchain");
             return ATOM_REJECT;
         }
-    } else if (!PVT(l_blocks)->block_cache_last ||
-                !dap_hash_fast_compare(&PVT(l_blocks)->block_cache_last->block_hash, &l_block_prev_hash))
-        return ATOM_MOVE_TO_THRESHOLD;
+    } else {
+        dap_chain_block_cache_t *l_bcache_last = PVT(l_blocks)->blocks ? PVT(l_blocks)->blocks->hh.tbl->tail->prev : NULL;
+        l_bcache_last = l_bcache_last ? l_bcache_last->hh.next : PVT(l_blocks)->blocks;
+        if (!l_bcache_last || !dap_hash_fast_compare(&l_bcache_last->block_hash, &l_block_prev_hash))
+            return ATOM_MOVE_TO_THRESHOLD;
+    }
     return ATOM_ACCEPT;
 }
 
@@ -1346,20 +1323,28 @@ static dap_chain_datum_t** s_callback_atom_get_datums(dap_chain_atom_ptr_t a_ato
  */
 static dap_chain_atom_ptr_t s_callback_atom_iter_get_first( dap_chain_atom_iter_t * a_atom_iter, size_t *a_atom_size )
 {
-    if(! a_atom_iter){
-        log_it(L_ERROR, "NULL iterator on input for atom_iter_get_first function");
+    if(!a_atom_iter) {
+        log_it(L_CRITICAL, "Invalid argument");
         return NULL;
     }
     dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS(a_atom_iter->chain);
     dap_chain_cs_blocks_pvt_t *l_blocks_pvt = l_blocks ? PVT(l_blocks) : NULL;
     assert(l_blocks_pvt);
-    a_atom_iter->cur_item = l_blocks_pvt->block_cache_first;
-    a_atom_iter->cur = l_blocks_pvt->block_cache_first ?  l_blocks_pvt->block_cache_first->block : NULL;
-    a_atom_iter->cur_size = l_blocks_pvt->block_cache_first ? l_blocks_pvt->block_cache_first->block_size : 0;
-    a_atom_iter->cur_hash = l_blocks_pvt->block_cache_first ? &l_blocks_pvt->block_cache_first->block_hash : NULL;
-
+    //pthread_rwlock_rdlock(&l_blocks_pvt->rwlock);
+    a_atom_iter->cur_item       = l_blocks_pvt->blocks;
+    if (a_atom_iter->cur_item) {
+        a_atom_iter->cur        = l_blocks_pvt->blocks->block;
+        a_atom_iter->cur_size   = l_blocks_pvt->blocks->block_size;
+        a_atom_iter->cur_hash   = &l_blocks_pvt->blocks->block_hash;
+    } else {
+        a_atom_iter->cur        = NULL;
+        a_atom_iter->cur_size   = 0;
+        a_atom_iter->cur_hash   = NULL;
+    }
+    //pthread_rwlock_unlock(&l_blocks_pvt->rwlock);
     if (a_atom_size)
         *a_atom_size = a_atom_iter->cur_size;
+
     return a_atom_iter->cur;
 }
 
@@ -1369,27 +1354,26 @@ static dap_chain_atom_ptr_t s_callback_atom_iter_get_first( dap_chain_atom_iter_
  * @param a_atom_size
  * @return
  */
-static dap_chain_atom_ptr_t s_callback_atom_iter_get_next( dap_chain_atom_iter_t * a_atom_iter,size_t *a_atom_size )
+static dap_chain_atom_ptr_t s_callback_atom_iter_get_next(dap_chain_atom_iter_t * a_atom_iter,size_t *a_atom_size )
 {
     assert(a_atom_iter);
     assert(a_atom_iter->cur_item);
 
-    dap_chain_block_cache_t * l_cur_cache =(dap_chain_block_cache_t *) a_atom_iter->cur_item;
-    a_atom_iter->cur_item = l_cur_cache = l_cur_cache->next;
-    if (l_cur_cache){
-        a_atom_iter->cur = l_cur_cache->block;
-        a_atom_iter->cur_size = l_cur_cache->block_size;
-        a_atom_iter->cur_hash = &l_cur_cache->block_hash;
-        if(a_atom_size)
-            *a_atom_size = l_cur_cache->block_size;
-        return l_cur_cache->block;
+    dap_chain_block_cache_t *l_next_item = ((dap_chain_block_cache_t*)a_atom_iter->cur_item)->hh.next;
+    a_atom_iter->cur_item = l_next_item;
+    if (a_atom_iter->cur_item) {
+        a_atom_iter->cur        = l_next_item->block;
+        a_atom_iter->cur_size   = l_next_item->block_size;
+        a_atom_iter->cur_hash   = &l_next_item->block_hash;
+    } else {
+        a_atom_iter->cur        = NULL;
+        a_atom_iter->cur_size   = 0;
+        a_atom_iter->cur_hash   = NULL;
     }
-    a_atom_iter->cur = NULL;
-    a_atom_iter->cur_size = 0;
-    a_atom_iter->cur_hash = NULL;
-    if (a_atom_size)
-        *a_atom_size = 0;
-    return NULL;
+    if(a_atom_size)
+        *a_atom_size = a_atom_iter->cur_size;
+
+    return a_atom_iter->cur;
 }
 
 /**
@@ -1399,29 +1383,29 @@ static dap_chain_atom_ptr_t s_callback_atom_iter_get_next( dap_chain_atom_iter_t
  * @param a_links_size_ptr
  * @return
  */
-static dap_chain_atom_ptr_t *s_callback_atom_iter_get_links( dap_chain_atom_iter_t * a_atom_iter , size_t *a_links_size, size_t ** a_links_size_ptr )
+static dap_chain_atom_ptr_t *s_callback_atom_iter_get_links(dap_chain_atom_iter_t *a_atom_iter , size_t *a_links_size, size_t **a_links_size_ptr)
 {
     assert(a_atom_iter);
     assert(a_links_size);
     assert(a_links_size_ptr);
-    if (a_atom_iter->cur_item){
-        dap_chain_block_cache_t * l_block_cache =(dap_chain_block_cache_t *) a_atom_iter->cur_item;
-        if (l_block_cache->links_hash_count){
-            *a_links_size_ptr = DAP_NEW_Z_SIZE( size_t, l_block_cache->links_hash_count*sizeof (size_t));
-            *a_links_size = l_block_cache->links_hash_count;
-            dap_chain_atom_ptr_t * l_ret = DAP_NEW_Z_SIZE(dap_chain_atom_ptr_t, l_block_cache->links_hash_count *sizeof (dap_chain_atom_ptr_t) );
-            for (size_t i = 0; i< l_block_cache->links_hash_count; i ++){
-                dap_chain_cs_blocks_t *l_cs_blocks = (dap_chain_cs_blocks_t *)l_block_cache->_inheritor;
-                dap_chain_block_cache_t *l_link = dap_chain_block_cs_cache_get_by_hash(l_cs_blocks, &l_block_cache->links_hash[i]);
-                assert(l_link);
-                (*a_links_size_ptr)[i] = l_link->block_size;
-                l_ret[i] = l_link->block;
-            }
-            return l_ret;
-        }else
-            return NULL;
-    }else
+    if (!a_atom_iter->cur_item) {
         return NULL;
+    }
+    dap_chain_block_cache_t * l_block_cache =(dap_chain_block_cache_t *) a_atom_iter->cur_item;
+    if (!l_block_cache->links_hash_count) {
+        return NULL;
+    }
+    *a_links_size_ptr = DAP_NEW_Z_SIZE(size_t, l_block_cache->links_hash_count * sizeof(size_t));
+    *a_links_size = l_block_cache->links_hash_count;
+    dap_chain_atom_ptr_t *l_ret = DAP_NEW_Z_SIZE(dap_chain_atom_ptr_t, l_block_cache->links_hash_count * sizeof(dap_chain_atom_ptr_t));
+    for (size_t i = 0; i < l_block_cache->links_hash_count; ++i){
+        dap_chain_cs_blocks_t *l_cs_blocks = (dap_chain_cs_blocks_t *)l_block_cache->_inheritor;
+        dap_chain_block_cache_t *l_link = dap_chain_block_cs_cache_get_by_hash(l_cs_blocks, &l_block_cache->links_hash[i]);
+        assert(l_link);
+        (*a_links_size_ptr)[i] = l_link->block_size;
+        l_ret[i] = l_link->block;
+    }
+    return l_ret;
 }
 
 /**
@@ -1433,15 +1417,18 @@ static dap_chain_atom_ptr_t *s_callback_atom_iter_get_links( dap_chain_atom_iter
  */
 static dap_chain_atom_ptr_t *s_callback_atom_iter_get_lasts( dap_chain_atom_iter_t *a_atom_iter, size_t *a_links_size, size_t **a_lasts_size_ptr)
 {
-    assert(a_atom_iter);
+    if(!a_atom_iter) {
+        log_it(L_CRITICAL, "Invalid argument");
+        return NULL;
+    }
+    dap_chain_block_cache_t *l_blocks = PVT(DAP_CHAIN_CS_BLOCKS(a_atom_iter->chain))->blocks;
+    dap_chain_block_cache_t *l_block_cache_last = l_blocks ? l_blocks->hh.tbl->tail->prev : NULL;
+    l_block_cache_last = l_block_cache_last ? l_block_cache_last->hh.next : l_blocks;
 
-    dap_chain_block_cache_t *l_block_cache_last = PVT(DAP_CHAIN_CS_BLOCKS(a_atom_iter->chain))->block_cache_last;
     if (l_block_cache_last) {
         a_atom_iter->cur = l_block_cache_last->block;
         a_atom_iter->cur_size = l_block_cache_last->block_size;
         a_atom_iter->cur_hash = &l_block_cache_last->block_hash;
-        if (a_links_size)
-            *a_links_size = 1;
         if (a_lasts_size_ptr) {
             *a_lasts_size_ptr = DAP_NEW_Z(size_t);
             if (!a_lasts_size_ptr) {
@@ -1450,22 +1437,27 @@ static dap_chain_atom_ptr_t *s_callback_atom_iter_get_lasts( dap_chain_atom_iter
             }
             (*a_lasts_size_ptr)[0] = l_block_cache_last->block_size;
         }
+        if (a_links_size)
+            *a_links_size = 1;
         dap_chain_atom_ptr_t *l_ret = DAP_NEW_Z(dap_chain_atom_ptr_t);
         if (!l_ret) {
-                log_it(L_CRITICAL, "Memory allocation error");
+            log_it(L_CRITICAL, "Memory allocation error");
+            if (a_lasts_size_ptr)
+                DAP_DEL_Z(*a_lasts_size_ptr);
             return NULL;
         }
         l_ret[0] = l_block_cache_last->block;
         return l_ret;
+    } else {
+        a_atom_iter->cur = NULL;
+        a_atom_iter->cur_size = 0;
+        a_atom_iter->cur_hash = NULL;
+        if (a_links_size)
+            *a_links_size = 0;
+        if (a_lasts_size_ptr)
+            *a_lasts_size_ptr = NULL;
+        return NULL;
     }
-    a_atom_iter->cur = NULL;
-    a_atom_iter->cur_size = 0;
-    a_atom_iter->cur_hash = NULL;
-    if (a_links_size)
-        *a_links_size = 0;
-    if (a_lasts_size_ptr)
-        *a_lasts_size_ptr = NULL;
-    return NULL;
 }
 
 /**
@@ -1543,14 +1535,14 @@ static dap_chain_block_t *s_new_block_move(dap_chain_cs_blocks_t *a_blocks, size
     size_t l_ret_size = 0;
     dap_chain_block_t *l_ret = NULL;
     dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(a_blocks);
-    pthread_rwlock_wrlock(&l_blocks_pvt->datums_lock);
+    pthread_rwlock_wrlock(&l_blocks_pvt->rwlock);
     if ( a_blocks->block_new ) {
         l_ret = a_blocks->block_new;
         l_ret_size = a_blocks->block_new_size;
         a_blocks->block_new = NULL;
         a_blocks->block_new_size = 0;
     }
-    pthread_rwlock_unlock(&l_blocks_pvt->datums_lock);
+    pthread_rwlock_unlock(&l_blocks_pvt->rwlock);
     if (a_new_block_size)
         *a_new_block_size = l_ret_size;
     return l_ret;
@@ -1569,7 +1561,7 @@ static size_t s_callback_add_datums(dap_chain_t *a_chain, dap_chain_datum_t **a_
     dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(l_blocks);
 
     size_t l_datum_processed = 0;
-    pthread_rwlock_wrlock(&l_blocks_pvt->datums_lock);
+    pthread_rwlock_wrlock(&l_blocks_pvt->rwlock);
     for (size_t i = 0; i < a_datums_count; ++i) {
         dap_chain_datum_t *l_datum = a_datums[i];
         size_t l_datum_size = dap_chain_datum_size(l_datum);
@@ -1582,7 +1574,9 @@ static size_t s_callback_add_datums(dap_chain_t *a_chain, dap_chain_datum_t **a_
             break;
         }
         if (!l_blocks->block_new) {
-            l_blocks->block_new = dap_chain_block_new(&l_blocks_pvt->block_cache_last->block_hash, &l_blocks->block_new_size);
+            dap_chain_block_cache_t *l_bcache_last = l_blocks_pvt->blocks ? l_blocks_pvt->blocks->hh.tbl->tail->prev : NULL;
+            l_bcache_last = l_bcache_last ? l_bcache_last->hh.next : l_blocks_pvt->blocks;
+            l_blocks->block_new = dap_chain_block_new(&l_bcache_last->block_hash, &l_blocks->block_new_size);
             l_blocks->block_new->hdr.cell_id.uint64 = a_chain->cells->id.uint64;
             l_blocks->block_new->hdr.chain_id.uint64 = l_blocks->chain->id.uint64;
         }
@@ -1590,7 +1584,7 @@ static size_t s_callback_add_datums(dap_chain_t *a_chain, dap_chain_datum_t **a_
         l_blocks->block_new_size = dap_chain_block_datum_add(&l_blocks->block_new, l_blocks->block_new_size, l_datum, l_datum_size);
         l_datum_processed++;
     }
-    pthread_rwlock_unlock(&l_blocks_pvt->datums_lock);
+    pthread_rwlock_unlock(&l_blocks_pvt->rwlock);
     return l_datum_processed;
 }
 
@@ -1602,8 +1596,11 @@ static size_t s_callback_add_datums(dap_chain_t *a_chain, dap_chain_datum_t **a_
 static size_t s_callback_count_atom(dap_chain_t *a_chain)
 {
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
-    dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(l_blocks);
-    return l_blocks_pvt->blocks_count;
+    size_t l_ret = 0;
+    pthread_rwlock_rdlock(&PVT(l_blocks)->rwlock);
+    l_ret = PVT(l_blocks)->blocks_count;
+    pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
+    return l_ret;
 }
 
 /**
@@ -1618,7 +1615,9 @@ static dap_list_t *s_callback_get_atoms(dap_chain_t *a_chain, size_t a_count, si
 {
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
     dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(l_blocks);
+    pthread_rwlock_rdlock(&PVT(l_blocks)->rwlock);
     if (!l_blocks_pvt->blocks) {
+        pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
         return NULL;
     }
     size_t l_offset = a_count * (a_page - 1);
@@ -1626,6 +1625,7 @@ static dap_list_t *s_callback_get_atoms(dap_chain_t *a_chain, size_t a_count, si
     if (a_page < 2)
         l_offset = 0;
     if (l_offset > l_count){
+        pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
         return NULL;
     }
     dap_list_t *l_list = NULL;
@@ -1661,5 +1661,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_blocks)->rwlock);
     return l_list;
 }
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index 69afdc5ea7..dc5a5215d5 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -138,8 +138,7 @@ static dap_list_t *s_dap_chain_callback_get_txs(dap_chain_t *a_chain, size_t a_c
 static size_t s_dap_chain_callback_get_count_atom(dap_chain_t *a_chain);
 static dap_list_t *s_callback_get_atoms(dap_chain_t *a_chain, size_t a_count, size_t a_page, bool a_reverse);
 
-static bool s_seed_mode = false;
-static bool s_debug_more = false;
+static bool s_seed_mode = false, s_debug_more = false, s_threshold_enabled = false;
 
 /**
  * @brief dap_chain_cs_dag_init
@@ -149,9 +148,10 @@ int dap_chain_cs_dag_init()
 {
     srand((unsigned int) time(NULL));
     dap_chain_cs_type_add( "dag", dap_chain_cs_dag_new );
-    s_seed_mode = dap_config_get_item_bool_default(g_config,"general","seed_mode",false);
-    s_debug_more = dap_config_get_item_bool_default(g_config,"dag","debug_more",false);
-
+    s_seed_mode         = dap_config_get_item_bool_default(g_config, "general", "seed_mode",        false);
+    s_debug_more        = dap_config_get_item_bool_default(g_config, "dag",     "debug_more",       false);
+    s_threshold_enabled = dap_config_get_item_bool_default(g_config, "dag",     "threshold_enabled",false);
+    debug_if(s_debug_more, L_DEBUG, "Thresholding %s", s_threshold_enabled ? "enabled" : "disabled");
     dap_cli_server_cmd_add ("dag", s_cli_dag, "DAG commands",
         "dag event create -net <net_name> -chain <chain_name> -datum <datum_hash> [-H {hex | base58(default)}]\n"
             "\tCreate event from datum mempool element\n\n"
@@ -425,7 +425,7 @@ void dap_chain_cs_dag_delete(dap_chain_t * a_chain)
 }
 
 
-static int s_dap_chain_add_datum(dap_chain_cs_dag_t *a_dag, 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)
 {
     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) ){
@@ -455,20 +455,13 @@ static int s_dap_chain_add_datum(dap_chain_cs_dag_t *a_dag, dap_chain_cs_dag_eve
         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_chain_cs_dag_event_item_t *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[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);
+        log_it(L_INFO, "Dag event %s checked, ret code %d : %s", l_buf_hash, l_ret,
+               l_ret ? dap_chain_net_verify_datum_err_code_to_str(l_datum, l_ret) : "Ok");
     }
-    return l_ledger_res;
+    return l_ret;
 }
 
 static bool s_dap_chain_check_if_event_is_present(dap_chain_cs_dag_event_item_t * a_hash_table, const dap_chain_hash_fast_t * hash) {
@@ -521,71 +514,59 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
     // 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_mutex_unlock(l_events_mutex);
 
     // verify hashes and consensus
     switch (ret) {
     case ATOM_ACCEPT:
         ret = s_chain_callback_atom_verify(a_chain, a_atom, a_atom_size);
-        if (ret == ATOM_MOVE_TO_THRESHOLD && !dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id)))
-            ret = ATOM_REJECT; /* TODO: A temporary fix for memory consumption */
-        if(s_debug_more)
-            log_it(L_DEBUG, "Verified atom %p: %s", a_atom, ret == ATOM_ACCEPT ? "accepted" :
-                                                           (ret == ATOM_REJECT ? "rejected" : "thresholded"));
+        if (ret == ATOM_MOVE_TO_THRESHOLD) {
+            if (!s_threshold_enabled && !dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id)))
+                ret = ATOM_REJECT;
+        }
+        debug_if(s_debug_more, L_DEBUG, "Verified atom %p: %s", a_atom, dap_chain_atom_verify_res_str[ret]);
         break;
     case ATOM_PASS:
-        if(s_debug_more) {
-            log_it(L_DEBUG, "Atom already present");
-        }
+        debug_if(s_debug_more, L_DEBUG, "Atom already present");
         DAP_DELETE(l_event_item);
+        pthread_mutex_unlock(l_events_mutex);
         return ret;
     default:
         break;
     }
 
     switch (ret) {
-    case ATOM_MOVE_TO_THRESHOLD:
-        pthread_mutex_lock(l_events_mutex);
+    case ATOM_MOVE_TO_THRESHOLD: {
         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) {
             HASH_ADD(hh, PVT(l_dag)->events_treshold, hash, sizeof(l_event_item->hash), l_event_item);
-
-            if (s_debug_more)
-                log_it(L_DEBUG, "... added to threshold");
+            debug_if(s_debug_more, L_DEBUG, "... added to threshold");
         } else {
             ret = ATOM_REJECT;
-            if (s_debug_more)
-                log_it(L_DEBUG, "... rejected because the atom was removed from the threshold.");
+            debug_if(s_debug_more, L_DEBUG, "... rejected because the atom was removed from the threshold.");
         }
-        pthread_mutex_unlock(l_events_mutex);
         break;
+    }
     case ATOM_ACCEPT: {
         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)
-                log_it(L_DEBUG, "... added");
+            debug_if(s_debug_more, L_DEBUG, "... added");
             break;
         case DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS:
         case DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION:
-            if(s_debug_more)
-                log_it(L_DEBUG, "... ledger tresholded");
+            debug_if(s_debug_more, L_DEBUG, "... ledger tresholded");
             break;
         case DAP_CHAIN_DATUM_CA:
-            if(s_debug_more)
-                log_it(L_DEBUG, "... DATUM_CA");
+            debug_if(s_debug_more, L_DEBUG, "... DATUM_CA");
             break;
         case DAP_CHAIN_DATUM_CUSTOM:
-            if(s_debug_more)
-                log_it(L_DEBUG, "... DATUM_CUSTOM");
+            debug_if(s_debug_more, L_DEBUG, "... DATUM_CUSTOM");
             break;
         default:
-            if (s_debug_more)
-                log_it(L_WARNING, "... added with ledger code %d", l_consensus_check);
+            debug_if(s_debug_more, L_WARNING, "... added with ledger code %d", l_consensus_check);
             break;
         }
-        pthread_mutex_lock(l_events_mutex);
         dap_chain_cs_dag_event_item_t *l_tail = PVT(l_dag)->events ? PVT(l_dag)->events->hh.tbl->tail->prev : NULL;
         if (!l_tail)
             l_tail = PVT(l_dag)->events;
@@ -598,12 +579,12 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
         else
             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_mutex_unlock(l_events_mutex);
     } break;
     default:
         DAP_DELETE(l_event_item); // Neither added, nor freed
         break;
     }
+    pthread_mutex_unlock(l_events_mutex);
     return ret;
 }
 
@@ -808,13 +789,11 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_
     dap_chain_atom_verify_res_t res = ATOM_ACCEPT;
     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");
+        debug_if(s_debug_more, L_WARNING, "Unsupported event version, possible corrupted event");
         return ATOM_REJECT;
     }
     if (l_event->header.chain_id.uint64 != a_chain->id.uint64) {
-        if (s_debug_more)
-            log_it(L_WARNING, "Event from another chain, possible corrupted event");
+        debug_if(s_debug_more, L_WARNING, "Event from another chain, possible corrupted event");
         return ATOM_REJECT;
     }
 
@@ -831,8 +810,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_
         }
     }
     if (!s_event_verify_size(l_event, a_atom_size)) {
-        if (s_debug_more)
-            log_it(L_WARNING,"Event size not equal to expected");
+        debug_if(s_debug_more, L_WARNING,"Event size not equal to expected");
         return  ATOM_REJECT;
     }
 
-- 
GitLab