From 3cc804a71e23482b6db72707b42a2a8545ee3d17 Mon Sep 17 00:00:00 2001
From: "Constantin P." <papizh.konstantin@demlabs.net>
Date: Mon, 9 Dec 2024 12:46:15 +0700
Subject: [PATCH 01/11] v1

---
 modules/chain/dap_chain.c                     |   3 +-
 modules/chain/dap_chain_cell.c                |  12 +-
 modules/ledger/dap_chain_ledger.c             |  88 +++++-------
 modules/ledger/dap_chain_ledger_token.c       |   8 +-
 modules/ledger/dap_chain_ledger_tx.c          |  28 ++--
 modules/ledger/include/dap_chain_ledger_pvt.h |  12 +-
 modules/net/dap_chain_net.c                   | 130 +++++++-----------
 .../node-cli/dap_chain_node_cli_cmd_token.c   |  39 +++---
 modules/node-cli/dap_chain_node_cli_cmd_tx.c  |  28 +---
 9 files changed, 144 insertions(+), 204 deletions(-)

diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index bf407fea20..dd1ed571c4 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -546,8 +546,7 @@ int dap_chain_load_all(dap_chain_t *a_chain)
         return -3;
     }
     for (struct dirent *l_dir_entry = readdir(l_dir); l_dir_entry != NULL; l_dir_entry = readdir(l_dir)) {
-        const char * l_filename = l_dir_entry->d_name;
-        const char l_suffix[] = ".dchaincell";
+        const char *l_filename = l_dir_entry->d_name, l_suffix[] = ".dchaincell";
         size_t l_suffix_len = strlen(l_suffix);
         if (!strncmp(l_filename + strlen(l_filename) - l_suffix_len, l_suffix, l_suffix_len)) {
             uint64_t l_cell_id_uint64 = 0;
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index 86f8a43330..4319d582a0 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -103,8 +103,7 @@ int dap_chain_cell_init(void)
     }
     
 #endif
-    //s_cells_path = dap_config_get_item_str(g_config,"resources","cells_storage");
-    return  0;
+    return 0;
 }
 
 #ifndef DAP_OS_WINDOWS
@@ -147,7 +146,8 @@ DAP_STATIC_INLINE int s_cell_map_new_volume(dap_chain_cell_t *a_cell, size_t a_f
         NTSTATUS err = pfnNtCreateSection(&hSection, SECTION_MAP_READ|SECTION_EXTEND_SIZE|SECTION_MAP_WRITE,
                                           NULL, &SectionSize, PAGE_READWRITE, SEC_RESERVE, (HANDLE)_get_osfhandle(fileno(a_cell->file_storage)));
         if ( !NT_SUCCESS(err) )
-            return log_it(L_ERROR, "NtCreateSection() failed, status %lx", err), -1;
+            return log_it(L_ERROR, "NtCreateSection() failed, status %lx: \"%s\"",
+                                   err, dap_str_ntstatus(err) ), -1;
         a_cell->map_range_bounds = dap_list_append(a_cell->map_range_bounds, hSection);
     }
 #endif
@@ -168,7 +168,8 @@ DAP_STATIC_INLINE int s_cell_map_new_volume(dap_chain_cell_t *a_cell, size_t a_f
     err = pfnNtMapViewOfSection(hSection, GetCurrentProcess(), (HANDLE)&a_cell->map, 0, 0, 
                                 &Offset, &l_map_size, ViewUnmap, MEM_RESERVE, PAGE_WRITECOPY);
     if ( !NT_SUCCESS(err) )
-        return NtClose(hSection), log_it(L_ERROR, "NtMapViewOfSection() failed, status %lx", err), -1;
+        return NtClose(hSection), log_it(L_ERROR, "NtMapViewOfSection() failed, status %lx: \"%s\"",
+                                                  err, dap_str_ntstatus(err) ), -1;
 #else
     if (a_load)
         s_cell_reclaim_cur_volume(a_cell);
@@ -658,7 +659,8 @@ ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom,
                 HANDLE hSection = (HANDLE)a_cell->map_range_bounds->data;
                 NTSTATUS err = pfnNtExtendSection(hSection, &SectionSize);
                 if ( !NT_SUCCESS(err) ) {
-                    log_it(L_ERROR, "NtExtendSection() failed, status %lx", err);
+                    log_it(L_ERROR, "NtExtendSection() failed, status %lx: \"%s\"",
+                                    err, dap_str_ntstatus(err) );
                     l_err = true;
                 }
             }
diff --git a/modules/ledger/dap_chain_ledger.c b/modules/ledger/dap_chain_ledger.c
index 3c81df968e..e6224f2f5d 100644
--- a/modules/ledger/dap_chain_ledger.c
+++ b/modules/ledger/dap_chain_ledger.c
@@ -244,25 +244,12 @@ void dap_ledger_deinit()
  */
 static dap_ledger_t *dap_ledger_handle_new(void)
 {
-    dap_ledger_t *l_ledger = DAP_NEW_Z(dap_ledger_t);
-    if ( !l_ledger ) {
-        log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-        return NULL;
-    }
-    dap_ledger_private_t * l_ledger_pvt;
-    l_ledger->_internal = l_ledger_pvt = DAP_NEW_Z(dap_ledger_private_t);
-    if ( !l_ledger_pvt ) {
-        log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-        DAP_DELETE(l_ledger);
-        return NULL;
-    }
-    // Initialize Read/Write Lock Attribute
-    pthread_rwlock_init(&l_ledger_pvt->ledger_rwlock, NULL);
-    pthread_rwlock_init(&l_ledger_pvt->tokens_rwlock, NULL);
-    pthread_rwlock_init(&l_ledger_pvt->threshold_txs_rwlock , NULL);
-    pthread_rwlock_init(&l_ledger_pvt->balance_accounts_rwlock , NULL);
-    pthread_rwlock_init(&l_ledger_pvt->stake_lock_rwlock, NULL);
-    pthread_rwlock_init(&l_ledger_pvt->rewards_rwlock, NULL);
+    dap_ledger_t *l_ledger = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_ledger_t, NULL);
+    dap_ledger_private_t *l_ledger_pvt = l_ledger->_internal = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_ledger_private_t, NULL, l_ledger);
+
+    l_ledger_pvt->ledger_rwlock = l_ledger_pvt->tokens_rwlock = l_ledger_pvt->threshold_txs_rwlock
+        = l_ledger_pvt->balance_accounts_rwlock = l_ledger_pvt->stake_lock_rwlock = l_ledger_pvt->rewards_rwlock
+        = PTHREAD_RWLOCK_INITIALIZER;
     return l_ledger;
 }
 
@@ -275,7 +262,6 @@ void dap_ledger_handle_free(dap_ledger_t *a_ledger)
 {
     if(!a_ledger)
         return;
-    log_it(L_INFO,"Ledger for network %s destroyed", a_ledger->net->pub.name);
     // Destroy Read/Write Lock
     pthread_rwlock_destroy(&PVT(a_ledger)->ledger_rwlock);
     pthread_rwlock_destroy(&PVT(a_ledger)->tokens_rwlock);
@@ -283,8 +269,8 @@ void dap_ledger_handle_free(dap_ledger_t *a_ledger)
     pthread_rwlock_destroy(&PVT(a_ledger)->balance_accounts_rwlock);
     pthread_rwlock_destroy(&PVT(a_ledger)->stake_lock_rwlock);
     pthread_rwlock_destroy(&PVT(a_ledger)->rewards_rwlock);
-    DAP_DELETE(PVT(a_ledger));
-    DAP_DELETE(a_ledger);
+    DAP_DEL_MULTY(PVT(a_ledger), a_ledger);
+    log_it(L_INFO,"Ledger for network %s destroyed", a_ledger->net->pub.name);
 
 }
 
@@ -606,34 +592,36 @@ json_object *dap_ledger_balance_info(dap_ledger_t *a_ledger, size_t a_limit, siz
 
 int dap_ledger_pvt_threshold_txs_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_hash_fast_t *a_tx_hash)
 {
-    dap_ledger_tx_item_t *l_item_tmp = NULL;
+    dap_ledger_tx_item_t *l_item = NULL;
     dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
     unsigned l_hash_value = 0;
     HASH_VALUE(a_tx_hash, sizeof(*a_tx_hash), l_hash_value);
-    pthread_rwlock_rdlock(&l_ledger_pvt->threshold_txs_rwlock);
-    HASH_FIND_BYHASHVALUE(hh, l_ledger_pvt->threshold_txs, a_tx_hash, sizeof(*a_tx_hash), l_hash_value, l_item_tmp);
+    pthread_rwlock_wrlock(&l_ledger_pvt->threshold_txs_rwlock);
+    HASH_FIND_BYHASHVALUE(hh, l_ledger_pvt->threshold_txs, a_tx_hash, sizeof(*a_tx_hash), l_hash_value, l_item);
     unsigned long long l_threshold_txs_count = HASH_COUNT(l_ledger_pvt->threshold_txs);
-    if (!l_item_tmp) {
+    if (!l_item) {
         if (l_threshold_txs_count >= s_threshold_txs_max) {
+            pthread_rwlock_unlock(&l_ledger_pvt->threshold_txs_rwlock);
             debug_if(g_debug_ledger, L_WARNING, "Threshold for transactions is overfulled (%zu max), dropping down tx %s, added nothing",
                                                 s_threshold_txs_max, dap_hash_fast_to_str_static(a_tx_hash));
             return -2;
         }
-        l_item_tmp = DAP_NEW_Z(dap_ledger_tx_item_t);
-        if ( !l_item_tmp ) {
+        if (!( l_item = DAP_NEW_Z(dap_ledger_tx_item_t) )) {
+            pthread_rwlock_unlock(&l_ledger_pvt->threshold_txs_rwlock);
             log_it(L_CRITICAL, "%s", c_error_memory_alloc);
             return -1;
         }
-        l_item_tmp->tx_hash_fast = *a_tx_hash;
-        l_item_tmp->tx = l_ledger_pvt->mapped ? a_tx : DAP_DUP_SIZE(a_tx, dap_chain_datum_tx_get_size(a_tx));
-        if ( !l_item_tmp->tx ) {
-            DAP_DELETE(l_item_tmp);
+        l_item->tx_hash_fast = *a_tx_hash;
+        l_item->tx = is_ledger_mapped(l_ledger_pvt) ? a_tx : DAP_DUP_SIZE(a_tx, dap_chain_datum_tx_get_size(a_tx));
+        if ( !l_item->tx ) {
+            DAP_DELETE(l_item);
+            pthread_rwlock_unlock(&l_ledger_pvt->threshold_txs_rwlock);
             log_it(L_CRITICAL, "%s", c_error_memory_alloc);
             return -1;
         }
-        l_item_tmp->ts_added = dap_nanotime_now();
-        l_item_tmp->cache_data.ts_created = a_tx->header.ts_created;
-        HASH_ADD_BYHASHVALUE(hh, l_ledger_pvt->threshold_txs, tx_hash_fast, sizeof(dap_chain_hash_fast_t), l_hash_value, l_item_tmp);
+        l_item->ts_added = dap_nanotime_now();
+        l_item->cache_data.ts_created = a_tx->header.ts_created;
+        HASH_ADD_BYHASHVALUE(hh, l_ledger_pvt->threshold_txs, tx_hash_fast, sizeof(dap_chain_hash_fast_t), l_hash_value, l_item);
         debug_if(g_debug_ledger, L_DEBUG, "Tx %s added to threshold", dap_hash_fast_to_str_static(a_tx_hash));
     }
     pthread_rwlock_unlock(&l_ledger_pvt->threshold_txs_rwlock);
@@ -653,7 +641,7 @@ void dap_ledger_pvt_threshold_txs_proc(dap_ledger_t *a_ledger)
             if (l_res != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION &&
                     l_res != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS) {
                 HASH_DEL(l_ledger_pvt->threshold_txs, l_tx_item);
-                if ( !l_ledger_pvt->mapped )
+                if ( !is_ledger_mapped(l_ledger_pvt) )
                     DAP_DELETE(l_tx_item->tx);
                 DAP_DELETE(l_tx_item);
                 l_success = true;
@@ -679,7 +667,7 @@ static void s_threshold_txs_free(dap_ledger_t *a_ledger)
             HASH_DEL(l_pvt->threshold_txs, l_current);
             char l_tx_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
             dap_chain_hash_fast_to_str(&l_current->tx_hash_fast, l_tx_hash_str, sizeof(l_tx_hash_str));
-            if ( !l_pvt->mapped )
+            if ( !is_ledger_mapped(l_pvt) )
                 DAP_DELETE(l_current->tx);
             DAP_DELETE(l_current);
             log_it(L_NOTICE, "Removed transaction %s form threshold ledger", l_tx_hash_str);
@@ -757,28 +745,18 @@ void dap_ledger_load_cache(dap_ledger_t *a_ledger)
  * create ledger for specific net
  * load ledger cache
  * @param a_check_flags checking flags
- *          DAP_LEDGER_CHECK_TOKEN_EMISSION
- *          DAP_LEDGER_CHECK_CELLS_DS
- *          DAP_LEDGER_CHECK_CELLS_DS
  * @param a_net_name char * network name, for example "kelvin-testnet"
  * @return dap_ledger_t*
  */
 dap_ledger_t *dap_ledger_create(dap_chain_net_t *a_net, uint16_t a_flags)
 {
     dap_ledger_t *l_ledger = dap_ledger_handle_new();
-    if (!l_ledger) {
-        log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-        return NULL;
-    }
+    dap_return_val_if_fail(l_ledger, NULL);
+
     l_ledger->net = a_net;
     dap_ledger_private_t *l_ledger_pvt = PVT(l_ledger);
-    l_ledger_pvt->check_ds = a_flags & DAP_LEDGER_CHECK_LOCAL_DS;
-    l_ledger_pvt->check_cells_ds = a_flags & DAP_LEDGER_CHECK_CELLS_DS;
-    l_ledger_pvt->check_token_emission = a_flags & DAP_LEDGER_CHECK_TOKEN_EMISSION;
-    l_ledger_pvt->cached = a_flags & DAP_LEDGER_CACHE_ENABLED;
-    l_ledger_pvt->mapped = a_flags & DAP_LEDGER_MAPPED;
-    l_ledger_pvt->threshold_enabled = a_flags & DAP_LEDGER_THRESHOLD_ENABLED;
-    if (l_ledger_pvt->threshold_enabled)
+    l_ledger_pvt->flags = a_flags;
+    if ( is_ledger_threshld(l_ledger_pvt) )
         l_ledger_pvt->threshold_txs_free_timer = dap_interval_timer_create(s_threshold_free_timer_tick,
                                                                       (dap_timer_callback_t)s_threshold_txs_free, l_ledger);
     pthread_cond_init(&l_ledger_pvt->load_cond, NULL);
@@ -801,7 +779,7 @@ dap_ledger_t *dap_ledger_create(dap_chain_net_t *a_net, uint16_t a_flags)
         }
         log_it(L_DEBUG, "Chain %s.%s has %d datums in HAL and %d datums in HRL", a_net->pub.name, l_chain->name, l_whitelist_size, l_blacklist_size);
     }
-    if ( l_ledger_pvt->cached )
+    if ( is_ledger_cached(l_ledger_pvt) )
         // load ledger cache from GDB
         dap_ledger_load_cache(l_ledger);
 #endif
@@ -973,7 +951,7 @@ void dap_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
     char *l_gdb_group;
     HASH_ITER(hh, l_ledger_pvt->ledger_items , l_item_current, l_item_tmp) {
         HASH_DEL(l_ledger_pvt->ledger_items, l_item_current);
-        if (!l_ledger_pvt->mapped)
+        if (!is_ledger_mapped(l_ledger_pvt))
             DAP_DELETE(l_item_current->tx);
         DAP_DEL_Z(l_item_current);
     }
@@ -1042,7 +1020,7 @@ void dap_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
     /* Delete threshold transactions */
     HASH_ITER(hh, l_ledger_pvt->threshold_txs, l_item_current, l_item_tmp) {
         HASH_DEL(l_ledger_pvt->threshold_txs, l_item_current);
-        if (!l_ledger_pvt->mapped)
+        if (!is_ledger_mapped(l_ledger_pvt))
             DAP_DELETE(l_item_current->tx);
         DAP_DEL_Z(l_item_current);
     }
@@ -1531,5 +1509,5 @@ dap_list_t *dap_ledger_get_list_tx_cond_outs(dap_ledger_t *a_ledger, const dap_c
 
 bool dap_ledger_cache_enabled(dap_ledger_t *a_ledger)
 {
-    return PVT(a_ledger)->cached;
+    return is_ledger_cached(PVT(a_ledger));
 }
diff --git a/modules/ledger/dap_chain_ledger_token.c b/modules/ledger/dap_chain_ledger_token.c
index a624cd3c90..6c7982a231 100644
--- a/modules/ledger/dap_chain_ledger_token.c
+++ b/modules/ledger/dap_chain_ledger_token.c
@@ -1075,7 +1075,7 @@ dap_chain_datum_token_t *dap_ledger_token_ticker_check(dap_ledger_t *a_ledger, c
  */
 void s_ledger_token_cache_update(dap_ledger_t *a_ledger, dap_ledger_token_item_t *l_token_item)
 {
-    if (!PVT(a_ledger)->cached)
+    if (! is_ledger_cached(PVT(a_ledger)) )
         return;
     char *l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_TOKENS_STR);
     size_t l_cache_size = l_token_item->datum_token_size + sizeof(uint256_t);
@@ -1389,7 +1389,7 @@ int s_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_
         return DAP_LEDGER_CHECK_ALREADY_CACHED;
     }
 
-    if (!PVT(a_ledger)->check_token_emission)
+    if (! is_ledger_ems_chk(PVT(a_ledger)) )
         goto ret_success;
 
     // Check emission correctness
@@ -1511,7 +1511,7 @@ int dap_ledger_token_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_token_
 
 void dap_ledger_pvt_emission_cache_update(dap_ledger_t *a_ledger, dap_ledger_token_emission_item_t *a_emission_item)
 {
-    if (!PVT(a_ledger)->cached)
+    if (! is_ledger_cached(PVT(a_ledger)) )
         return;
     char *l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_EMISSIONS_STR);
     size_t l_cache_size = a_emission_item->datum_token_emission_size + sizeof(dap_hash_fast_t);
@@ -1578,7 +1578,7 @@ int dap_ledger_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_emissi
                        l_balance, l_emission->hdr.ticker,
                        dap_chain_addr_to_str_static(&(l_emission->hdr.address)));
     }
-    if (PVT(a_ledger)->threshold_enabled)
+    if ( is_ledger_threshld(PVT(a_ledger)) )
         dap_ledger_pvt_threshold_txs_proc(a_ledger);
     return DAP_LEDGER_CHECK_OK;
 }
diff --git a/modules/ledger/dap_chain_ledger_tx.c b/modules/ledger/dap_chain_ledger_tx.c
index 89ffbf2cae..2e99264a79 100644
--- a/modules/ledger/dap_chain_ledger_tx.c
+++ b/modules/ledger/dap_chain_ledger_tx.c
@@ -1144,7 +1144,7 @@ static struct json_object *s_wallet_info_json_collect(dap_ledger_t *a_ledger, da
  */
 static int s_balance_cache_update(dap_ledger_t *a_ledger, dap_ledger_wallet_balance_t *a_balance)
 {
-    if (PVT(a_ledger)->cached) {
+    if ( is_ledger_cached(PVT(a_ledger)) ) {
         char *l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_BALANCES_STR);
         if (dap_global_db_set(l_gdb_group, a_balance->key, &a_balance->balance, sizeof(uint256_t), false, NULL, NULL)) {
             debug_if(g_debug_ledger, L_WARNING, "Ledger cache mismatch");
@@ -1234,7 +1234,7 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
                                                        l_main_token_ticker, &l_tag, &l_action, false))) {
         if ((l_ret_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS ||
                 l_ret_check == DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION) &&
-                l_ledger_pvt->threshold_enabled && !dap_chain_net_get_load_mode(a_ledger->net)) {
+                is_ledger_threshld(l_ledger_pvt) && !dap_chain_net_get_load_mode(a_ledger->net)) {
             if (!l_from_threshold)
                 dap_ledger_pvt_threshold_txs_add(a_ledger, a_tx, a_tx_hash);
         } else {
@@ -1259,7 +1259,7 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
     dap_list_t *l_trackers_mover = NULL;
     dap_store_obj_t *l_cache_used_outs = NULL;
     char *l_ledger_cache_group = NULL;
-    if (PVT(a_ledger)->cached) {
+    if ( is_ledger_cached(l_ledger_pvt) ) {
         l_cache_used_outs = DAP_NEW_Z_SIZE(dap_store_obj_t, sizeof(dap_store_obj_t) * (l_outs_used + 1));
         if ( !l_cache_used_outs ) {
             log_it(L_CRITICAL, "%s", c_error_memory_alloc);
@@ -1367,7 +1367,7 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
                                                   l_prev_item_out->out_metadata[l_bound_item->prev_out_idx].trackers, a_tx->header.ts_created);
         // add a used output
         l_prev_item_out->cache_data.n_outs_used++;
-        if (PVT(a_ledger)->cached) {
+        if ( is_ledger_cached(l_ledger_pvt) ) {
             // mirror it in the cache
             size_t l_cache_size = sizeof(l_prev_item_out->cache_data) + l_prev_item_out->cache_data.n_outs * sizeof(dap_chain_hash_fast_t);
             size_t l_tx_size = dap_chain_datum_tx_get_size(l_prev_item_out->tx);
@@ -1511,11 +1511,11 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
     }
     l_tx_item->tx_hash_fast = *a_tx_hash;
     size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
-    l_tx_item->tx = l_ledger_pvt->mapped ? a_tx : DAP_DUP_SIZE(a_tx, l_tx_size);
+    l_tx_item->tx = is_ledger_mapped(l_ledger_pvt) ? a_tx : DAP_DUP_SIZE(a_tx, l_tx_size);
     l_tx_item->cache_data.n_outs = l_outs_count;
     l_tx_item->cache_data.tag = l_tag;
     l_tx_item->cache_data.action = l_action;
-    dap_stpcpy(l_tx_item->cache_data.token_ticker, l_main_token_ticker);
+    dap_strncpy(l_tx_item->cache_data.token_ticker, l_main_token_ticker, sizeof(l_tx_item->cache_data.token_ticker));
 
     // Moving colour to new outputs
     size_t i = 0;
@@ -1597,7 +1597,7 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
             l_notify->callback(a_ledger, a_tx, a_tx_hash, l_notify->arg, DAP_LEDGER_NOTIFY_OPCODE_ADDED);
         }
     }
-    if (PVT(a_ledger)->cached) {
+    if ( is_ledger_cached(l_ledger_pvt) ) {
         // Add it to cache
         size_t l_cache_size = sizeof(l_tx_item->cache_data) + l_tx_item->cache_data.n_outs * sizeof(dap_chain_hash_fast_t);
         size_t l_tx_cache_sz = l_tx_size + l_cache_size + sizeof(dap_ledger_cache_gdb_record_t);
@@ -1616,7 +1616,7 @@ int dap_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_ha
         if (dap_global_db_set_raw(l_cache_used_outs, l_outs_used + 1, NULL, NULL))
             debug_if(g_debug_ledger, L_WARNING, "Ledger cache mismatch");
     }
-    if (!a_from_threshold && l_ledger_pvt->threshold_enabled)
+    if (!a_from_threshold && is_ledger_threshld(l_ledger_pvt))
         dap_ledger_pvt_threshold_txs_proc(a_ledger);
 FIN:
     if (l_trackers_mover)
@@ -1625,7 +1625,7 @@ FIN:
         dap_list_free_full(l_list_bound_items, NULL);
     if (l_list_tx_out)
         dap_list_free(l_list_tx_out);
-    if (PVT(a_ledger)->cached) {
+    if ( is_ledger_cached(l_ledger_pvt) ) {
         if (l_cache_used_outs) {
             for (size_t i = 1; i < l_outs_used; ++i) {
                 DAP_DEL_MULTY(l_cache_used_outs[i].key, l_cache_used_outs[i].value);
@@ -1680,7 +1680,7 @@ int dap_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap
 
     dap_store_obj_t *l_cache_used_outs = NULL;
     char *l_ledger_cache_group = NULL;
-    if (PVT(a_ledger)->cached) {
+    if ( is_ledger_cached(l_ledger_pvt) ) {
         l_cache_used_outs = DAP_NEW_Z_COUNT(dap_store_obj_t, l_outs_used);
         if ( !l_cache_used_outs ) {
             log_it(L_CRITICAL, "Memory allocation error");
@@ -1770,7 +1770,7 @@ int dap_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap
         dap_ledger_tx_item_t *l_prev_item_out = l_bound_item->prev_item;
         l_prev_item_out->out_metadata[l_bound_item->prev_out_idx].tx_spent_hash_fast = (dap_hash_fast_t){ };
         l_prev_item_out->cache_data.n_outs_used--;
-        if (PVT(a_ledger)->cached) {
+        if ( is_ledger_cached(l_ledger_pvt) ) {
             // mirror it in the cache
             size_t l_tx_size = dap_chain_datum_tx_get_size(l_prev_item_out->tx);
             size_t l_cache_size = sizeof(l_prev_item_out->cache_data) + l_prev_item_out->cache_data.n_outs * sizeof(dap_chain_hash_fast_t);
@@ -1906,7 +1906,7 @@ int dap_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap
         dap_list_free_full(l_tx_item->out_metadata[i].trackers, NULL);
     DAP_DELETE(l_tx_item);
 
-    if (PVT(a_ledger)->cached) {
+    if ( is_ledger_cached(l_ledger_pvt) ) {
         // Add it to cache
         dap_global_db_del_sync(l_ledger_cache_group, l_tx_hash_str);
         // Apply it with single DB transaction
@@ -1918,7 +1918,7 @@ FIN:
         dap_list_free_full(l_list_bound_items, NULL);
     if (l_list_tx_out)
         dap_list_free(l_list_tx_out);
-    if (PVT(a_ledger)->cached) {
+    if ( is_ledger_cached(l_ledger_pvt) ) {
         if (l_cache_used_outs) {
             for (size_t i = 1; i < l_outs_used; i++) {
                 DAP_DELETE(l_cache_used_outs[i].key);
@@ -1954,7 +1954,7 @@ int dap_ledger_tx_load(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx, dap_c
 
 static void s_ledger_stake_lock_cache_update(dap_ledger_t *a_ledger, dap_ledger_stake_lock_item_t *a_stake_lock_item)
 {
-    if (!PVT(a_ledger)->cached)
+    if (!is_ledger_cached(PVT(a_ledger)))
         return;
     char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
     dap_chain_hash_fast_to_str(&a_stake_lock_item->tx_for_stake_lock_hash, l_hash_str, sizeof(l_hash_str));
diff --git a/modules/ledger/include/dap_chain_ledger_pvt.h b/modules/ledger/include/dap_chain_ledger_pvt.h
index 62eb273e50..b94a9fb3ac 100644
--- a/modules/ledger/include/dap_chain_ledger_pvt.h
+++ b/modules/ledger/include/dap_chain_ledger_pvt.h
@@ -186,12 +186,13 @@ typedef struct dap_ledger_private {
     dap_ledger_decree_item_t *decrees;
     dap_ledger_anchor_item_t *anchors;
 
-    // Save/load operations condition
+    // Save/load cache operations condition
     pthread_mutex_t load_mutex;
     pthread_cond_t load_cond;
     bool load_end;
     // Ledger flags
-    bool check_ds, check_cells_ds, check_token_emission, cached, mapped, threshold_enabled;
+    //bool check_ds, check_cells_ds, check_token_emission, cached, mapped, threshold_enabled;
+    uint16_t flags;
     //notifiers
     dap_list_t *bridged_tx_notifiers;
     dap_list_t *tx_add_notifiers;
@@ -202,6 +203,13 @@ typedef struct dap_ledger_private {
 
 #define PVT(a) ( (dap_ledger_private_t *) a->_internal )
 
+#define is_ledger_ds_chk(l)         ( l->flags & DAP_LEDGER_CHECK_LOCAL_DS )
+#define is_ledger_cells_ds_chk(l)   ( l->flags & DAP_LEDGER_CHECK_CELLS_DS )
+#define is_ledger_ems_chk(l)        ( l->flags & DAP_LEDGER_CHECK_TOKEN_EMISSION )
+#define is_ledger_mapped(l)         ( l->flags & DAP_LEDGER_MAPPED )
+#define is_ledger_cached(l)         ( l->flags & DAP_LEDGER_CACHE_ENABLED )
+#define is_ledger_threshld(l)       ( l->flags & DAP_LEDGER_THRESHOLD_ENABLED )
+
 extern bool g_debug_ledger;
 
 bool dap_ledger_pvt_cache_gdb_load_tokens_callback(dap_global_db_instance_t *a_dbi,
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index f20f69afa4..5e8774bfba 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -541,7 +541,7 @@ int s_link_manager_fill_net_info(dap_link_t *a_link)
         }
     }
     dap_chain_node_info_t *l_node_info = NULL;
-    if (!l_host || !l_host[0] || !l_port) {
+    if (!l_host || !*l_host || !l_port) {
         for (dap_chain_net_t *net = s_nets_by_name; net; net = net->hh.next) {
             if (( l_node_info = dap_chain_node_info_read(net, &a_link->addr) ))
                 break;
@@ -697,10 +697,7 @@ static dap_chain_net_t *s_net_new(const char *a_net_name, dap_config_t *a_cfg)
                 *a_native_ticker= dap_config_get_item_str(a_cfg, "general", "native_ticker");
     dap_chain_net_id_t l_net_id;
 
-    if(!a_node_role)
-        return log_it(L_ERROR, "Can't create l_net, can't read node role config"), NULL;
-
-    if(!l_net_name_str || !l_net_id_str || dap_chain_net_id_parse(l_net_id_str, &l_net_id))
+    if (!l_net_name_str || !*l_net_name_str || !l_net_id_str || dap_chain_net_id_parse(l_net_id_str, &l_net_id))
         return log_it(L_ERROR, "Can't create l_net, can't read name or ID config"), NULL;
 
     dap_chain_net_t *l_net_sought = NULL;
@@ -715,38 +712,38 @@ static dap_chain_net_t *s_net_new(const char *a_net_name, dap_config_t *a_cfg)
                         l_net_sought->pub.id.uint64);
         return NULL;
     }
+
+    if (!a_native_ticker)
+        return log_it(L_ERROR, "Invalid native ticker, check [general] \"native_ticker\" in %s.cfg", l_net_name_str), NULL;
+
+    uint32_t l_role;
+    if (!a_node_role)
+        l_role = NODE_ROLE_FULL;
+    else if ( !strcmp(a_node_role, "root_master") )
+        l_role = NODE_ROLE_ROOT_MASTER;
+    else if ( !strcmp(a_node_role,"root") )
+        l_role = NODE_ROLE_ROOT;
+    else if ( !strcmp(a_node_role,"archive") )
+        l_role = NODE_ROLE_ARCHIVE;
+    else if ( !strcmp(a_node_role,"cell_master") )
+        l_role = NODE_ROLE_CELL_MASTER;
+    else if ( !strcmp(a_node_role,"master") )
+        l_role = NODE_ROLE_MASTER;
+    else if ( !strcmp(a_node_role,"full") )
+        l_role = NODE_ROLE_FULL;
+    else if ( !strcmp(a_node_role,"light") )
+        l_role = NODE_ROLE_LIGHT;
+    else
+        return log_it(L_ERROR,"Unknown node role \"%s\" for network '%s'", a_node_role, l_net_name_str), NULL;
+
     dap_chain_net_t *l_ret = DAP_NEW_Z_SIZE_RET_VAL_IF_FAIL(dap_chain_net_t, sizeof(dap_chain_net_t) + sizeof(dap_chain_net_pvt_t), NULL);
     PVT(l_ret)->node_info = DAP_NEW_Z_SIZE_RET_VAL_IF_FAIL(dap_chain_node_info_t, sizeof(dap_chain_node_info_t) + DAP_HOSTADDR_STRLEN + 1, NULL, l_ret);
 
     l_ret->pub.id = l_net_id;
-    if (strcmp (a_node_role, "root_master")==0){
-        PVT(l_ret)->node_role.enums = NODE_ROLE_ROOT_MASTER;
-    } else if (strcmp( a_node_role,"root") == 0){
-        PVT(l_ret)->node_role.enums = NODE_ROLE_ROOT;
-    } else if (strcmp( a_node_role,"archive") == 0){
-        PVT(l_ret)->node_role.enums = NODE_ROLE_ARCHIVE;
-    } else if (strcmp( a_node_role,"cell_master") == 0){
-        PVT(l_ret)->node_role.enums = NODE_ROLE_CELL_MASTER;
-    }else if (strcmp( a_node_role,"master") == 0){
-        PVT(l_ret)->node_role.enums = NODE_ROLE_MASTER;
-    }else if (strcmp( a_node_role,"full") == 0){
-        PVT(l_ret)->node_role.enums = NODE_ROLE_FULL;
-    }else if (strcmp( a_node_role,"light") == 0){
-        PVT(l_ret)->node_role.enums = NODE_ROLE_LIGHT;
-    }else{
-        log_it(L_ERROR,"Unknown node role \"%s\" for network '%s'", a_node_role, l_net_name_str);
-        DAP_DELETE(l_ret);
-        return NULL;
-    }
-    if (!( l_net_name_str ))
-        return DAP_DELETE(l_ret), log_it(L_ERROR, "Invalid net name, check [general] \"name\" in netconfig"), NULL;
-    dap_strncpy(l_ret->pub.name, l_net_name_str, sizeof(l_ret->pub.name));
-    if (!( l_ret->pub.native_ticker = a_native_ticker ))
-        return DAP_DEL_MULTY(l_ret->pub.name, l_ret),
-               log_it(L_ERROR, "Invalid native ticker, check [general] \"native_ticker\" in %s.cfg",
-                                l_net_name_str),
-                NULL;
+    PVT(l_ret)->node_role.enums = l_role;
     log_it (L_NOTICE, "Node role \"%s\" selected for network '%s'", a_node_role, l_net_name_str);
+    dap_strncpy(l_ret->pub.name, l_net_name_str, sizeof(l_ret->pub.name));
+    l_ret->pub.native_ticker = a_native_ticker;
     l_ret->pub.config = a_cfg;
     l_ret->pub.gdb_groups_prefix
         = dap_config_get_item_str_default( a_cfg, "general", "gdb_groups_prefix", dap_config_get_item_str(a_cfg, "general", "name") );
@@ -784,35 +781,21 @@ bool s_net_disk_load_notify_callback(UNUSED_ARG void *a_arg)
  */
 void dap_chain_net_load_all()
 {
-    if ( dap_config_get_item_bool_default(g_config, "server", "enabled", false) ) {
-        char l_local_ip[INET6_ADDRSTRLEN] = { '\0' };
-        uint16_t l_in_port = 0;
-        const char **l_listening = dap_config_get_array_str(g_config, "server", DAP_CFG_PARAM_LISTEN_ADDRS, NULL);
-        if ( l_listening ) {
-            if ( dap_net_parse_config_address(*l_listening, l_local_ip, &l_in_port, NULL, NULL) < 0 )
-                log_it(L_ERROR, "Invalid server IP address, check [server] section in cellframe-node.cfg");
-            else {
-                // power of short-circuit
-                if ( l_in_port || ( l_in_port = dap_config_get_item_int16_default(g_config, "server", DAP_CFG_PARAM_LEGACY_PORT, 8079 ))) {
-                    s_server_enabled = true;
-                    log_it(L_INFO, "Server is enabled on [%s : %u]", l_local_ip, l_in_port);
-                }
-            }
-        }
-    }
-    uint16_t l_nets_count = HASH_COUNT(s_nets_by_name);
+    int l_nets_count = HASH_COUNT(s_nets_by_name), i = 0, l_err;
     if (!l_nets_count)
         return log_it(L_ERROR, "No networks initialized!");
     pthread_t l_tids[l_nets_count];
-    dap_chain_net_t *l_net = s_nets_by_name;
     dap_timerfd_t *l_load_notify_timer = dap_timerfd_start(5000, (dap_timerfd_callback_t)s_net_disk_load_notify_callback, NULL);
-    for (int i = 0; i < l_nets_count; ++i) {
-        pthread_create(&l_tids[i], NULL, s_net_load, l_net);
-        l_net = l_net->hh.next;
-    }
-    for (int i = 0; i < l_nets_count; ++i) {
-        pthread_join(l_tids[i], NULL);
-    }
+    for ( dap_chain_net_t *l_net = s_nets_by_name; l_net && !( l_err = pthread_create(&l_tids[i], NULL, s_net_load, l_net) ); l_net = l_net->hh.next, ++i );
+    if ( i < l_nets_count ) {
+        log_it(L_ERROR, "%s%d of %d nets are loading! Thread creation error %d: \"%s\"",
+                        i ? "Only " : "", i, l_nets_count, l_err, dap_strerror(l_err));
+        l_nets_count = i;
+    }
+    for ( i = 0; i < l_nets_count; ++i ) {
+        if (( l_err = pthread_join(l_tids[i], NULL) ))
+            log_it(L_ERROR, "Thread %d join error %d: \"%s\"", l_err, dap_strerror(l_err));
+     }
     dap_timerfd_delete(l_load_notify_timer->worker, l_load_notify_timer->esocket_uuid);
 }
 
@@ -1862,15 +1845,17 @@ int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx)
         }
         l_net->pub.bridged_networks_count = j;
         if (j < i)
-            l_net->pub.bridged_networks = DAP_REALLOC_COUNT(l_net->pub.bridged_networks, j); // Can be NULL, it's ok
+            l_net->pub.bridged_networks = j
+                ? DAP_REALLOC_COUNT(l_net->pub.bridged_networks, j)
+                : ( DAP_DELETE(l_net->pub.bridged_networks), NULL ); // No bridged nets is OK
     }
 
     // read nodes addrs and hosts
     if (
-        dap_config_stream_addrs_parse(l_cfg, "general", "permanent_nodes_addrs", &l_net_pvt->permanent_links_addrs, &l_net_pvt->permanent_links_addrs_count) ||
-        s_nodes_hosts_init(l_net, l_cfg, "permanent_nodes_hosts", &l_net_pvt->permanent_links_hosts, &l_net_pvt->permanent_links_hosts_count) ||
-        s_nodes_hosts_init(l_net, l_cfg, "seed_nodes_hosts", &l_net_pvt->seed_nodes_hosts, &l_net_pvt->seed_nodes_count) ||
-        (!l_net_pvt->seed_nodes_count && s_nodes_hosts_init(l_net, l_cfg, "bootstrap_hosts", &l_net_pvt->seed_nodes_hosts, &l_net_pvt->seed_nodes_count) )
+        dap_config_stream_addrs_parse(l_cfg, "general", "permanent_nodes_addrs", &l_net_pvt->permanent_links_addrs, &l_net_pvt->permanent_links_addrs_count)
+     || s_nodes_hosts_init(l_net, l_cfg, "permanent_nodes_hosts", &l_net_pvt->permanent_links_hosts, &l_net_pvt->permanent_links_hosts_count)
+     || s_nodes_hosts_init(l_net, l_cfg, "seed_nodes_hosts", &l_net_pvt->seed_nodes_hosts, &l_net_pvt->seed_nodes_count)
+     || ( !l_net_pvt->seed_nodes_count && s_nodes_hosts_init(l_net, l_cfg, "bootstrap_hosts", &l_net_pvt->seed_nodes_hosts, &l_net_pvt->seed_nodes_count) )
     ) {
         dap_chain_net_delete(l_net);
         dap_config_close(l_cfg);
@@ -1882,6 +1867,9 @@ int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx)
     // Get list chains name for enabled debug mode
     bool is_esbocs_debug = dap_config_get_item_bool_default(l_cfg, "esbocs", "consensus_debug", false);
 
+    if ( dap_server_enabled() && ( l_net_pvt->node_info->ext_port = dap_config_get_item_uint16(g_config, "server", "ext_port") ))
+        log_it(L_INFO, "Set external port %u for adding in node list", l_net_pvt->node_info->ext_port);
+
     struct dirent *l_dir_entry;
     // Services register & configure
     dap_chain_srv_start(l_net->pub.id, DAP_CHAIN_NET_SRV_XCHANGE_LITERAL, NULL);        // Harcoded core service starting for exchange capability
@@ -1950,8 +1938,7 @@ int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx)
             for ( ; i < k; ++i) {
                 if ( l_occupied_default_types[l_types_arr[i]] ) {
                     if ( i < k - 1 )
-                        l_types_arr[i] =
-                            l_types_arr[k - 1];
+                        l_types_arr[i] = l_types_arr[k - 1];
                     --i;
                     --k;
                 } else
@@ -2021,18 +2008,10 @@ static void *s_net_load(void *a_arg)
     }
 
     dap_chain_net_pvt_t *l_net_pvt = PVT(l_net);
-
-    // reload ledger cache at once
-    if (s_chain_net_reload_ledger_cache_once(l_net)) {
-        log_it(L_WARNING,"Start one time ledger cache reloading");
-        dap_ledger_purge(l_net->pub.ledger, false);
-        dap_chain_srv_purge_all(l_net->pub.id);
-    }
     //else dap_chain_net_srv_stake_load_cache(l_net); // TODO rework ledger and staking caches
     // load chains
     dap_chain_t *l_chain = l_net->pub.chains;
-    clock_t l_chain_load_start_time; 
-    l_chain_load_start_time = clock(); 
+    clock_t l_chain_load_start_time = clock(); 
     while (l_chain) {
         l_net->pub.fee_value = uint256_0;
         l_net->pub.fee_addr = c_dap_chain_addr_blank;
@@ -2193,11 +2172,6 @@ static void *s_net_load(void *a_arg)
     DL_FOREACH(l_net->pub.chains, l_chain)
         dap_chain_cs_load(l_chain, l_net->pub.config);
 
-    if ( s_server_enabled ) {
-        if (( l_net_pvt->node_info->ext_port = dap_config_get_item_uint16(g_config, "server", "ext_port") ))
-            log_it(L_INFO, "Set external port %u for adding in node list", l_net_pvt->node_info->ext_port);
-    }
-
     l_net_pvt->node_info->address.uint64 = g_node_addr.uint64;
 
     log_it(L_NOTICE, "Net load information: node_addr " NODE_ADDR_FP_STR ", seed links %u, cell_id 0x%016"DAP_UINT64_FORMAT_X,
diff --git a/modules/node-cli/dap_chain_node_cli_cmd_token.c b/modules/node-cli/dap_chain_node_cli_cmd_token.c
index 0ea06e1d4b..985ad2d800 100644
--- a/modules/node-cli/dap_chain_node_cli_cmd_token.c
+++ b/modules/node-cli/dap_chain_node_cli_cmd_token.c
@@ -426,31 +426,24 @@ static int s_parse_common_token_decl_arg(int a_argc, char ** a_argv, void **a_st
  */
 dap_list_t* s_parse_wallet_addresses(const char *a_tx_address, dap_list_t *l_tsd_list, size_t *l_tsd_total_size, uint32_t flag)
 {
-    if (!a_tx_address){
-       log_it(L_DEBUG,"a_tx_address is null");
-       return l_tsd_list;
-    }
-
-    char ** l_str_wallet_addr = NULL;
-    l_str_wallet_addr = dap_strsplit(a_tx_address,",",0xffff);
+    dap_return_val_if_fail(a_tx_address, l_tsd_list);
 
-    if (!l_str_wallet_addr){
-       log_it(L_DEBUG,"Error in wallet addresses array parsing in tx_receiver_allowed parameter");
-       return l_tsd_list;
-    }
+    char **l_str_wallet_addr = dap_strsplit(a_tx_address,",",0xffff);
+    if (!l_str_wallet_addr)
+       return log_it(L_ERROR, "Can't split \"%s\" by commas!", a_tx_address), l_tsd_list;
 
-    while (l_str_wallet_addr && *l_str_wallet_addr){
-        log_it(L_DEBUG,"Processing wallet address: %s", *l_str_wallet_addr);
-        dap_chain_addr_t *addr_to = dap_chain_addr_from_str(*l_str_wallet_addr);
+    for (char **l_cur = l_str_wallet_addr; l_cur && *l_cur; ++l_cur) {
+        log_it(L_DEBUG, "Processing wallet address: %s", *l_cur);
+        dap_chain_addr_t *addr_to = dap_chain_addr_from_str(*l_cur);
         if (addr_to){
-            dap_tsd_t * l_tsd = dap_tsd_create(flag, addr_to, sizeof(dap_chain_addr_t));
+            dap_tsd_t *l_tsd = dap_tsd_create(flag, addr_to, sizeof(dap_chain_addr_t));
             l_tsd_list = dap_list_append(l_tsd_list, l_tsd);
             *l_tsd_total_size += dap_tsd_size(l_tsd);
-        }else{
-            log_it(L_DEBUG,"Error in wallet address parsing");
-        }
-        l_str_wallet_addr++;
+            DAP_DELETE(addr_to);
+        } else
+            log_it(L_ERROR, "Can't convert it to address!");
     }
+    dap_strfreev(l_str_wallet_addr);
     return l_tsd_list;
 }
 
@@ -479,15 +472,15 @@ static int s_parse_additional_token_decl_arg(int a_argc, char ** a_argv, void **
     if (!a_update_token) {
         if (a_params->ext.flags){   // Flags
             l_str_flags = dap_strsplit(a_params->ext.flags,",",0xffff );
-            while (l_str_flags && *l_str_flags){
-                uint16_t l_flag = dap_chain_datum_token_flag_from_str(*l_str_flags);
+            for (char **l_cur = l_str_flags; l_cur && *l_cur; ++l_cur) {
+                uint16_t l_flag = dap_chain_datum_token_flag_from_str(*l_cur);
                 if (l_flag == DAP_CHAIN_DATUM_TOKEN_FLAG_UNDEFINED ){
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Flag can't be \"%s\"",*l_str_flags);
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Flag can't be \"%s\"",*l_cur);
                     return -20;
                 }
                 l_flags |= l_flag; // if we have multiple flags
-                l_str_flags++;
             }
+            dap_strfreev(l_str_flags);
         }
     } else {
         const char *l_set_flags = NULL;
diff --git a/modules/node-cli/dap_chain_node_cli_cmd_tx.c b/modules/node-cli/dap_chain_node_cli_cmd_tx.c
index c3f84f37ca..440cd4ef1c 100644
--- a/modules/node-cli/dap_chain_node_cli_cmd_tx.c
+++ b/modules/node-cli/dap_chain_node_cli_cmd_tx.c
@@ -2882,9 +2882,7 @@ int com_tx_create(int a_argc, char **a_argv, void **a_json_arr_reply)
         for (size_t i = 0; i < l_addr_el_count; ++i) {
             l_addr_to[i] = dap_chain_addr_from_str(l_addr_base58_to_array[i]);
             if(!l_addr_to[i]) {
-                for (size_t j = 0; j < i; ++j) {
-                    DAP_DELETE(l_addr_to[j]);
-                }
+                DAP_DEL_ARRAY(l_addr_to, i);
                 DAP_DEL_MULTY(l_addr_to, l_addr_base58_to_array, l_value);
                 dap_json_rpc_error_add(*a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_TX_CREATE_DESTINATION_ADDRESS_INVALID, "destination address is invalid");
                 return DAP_CHAIN_NODE_CLI_COM_TX_CREATE_DESTINATION_ADDRESS_INVALID;
@@ -2921,9 +2919,7 @@ int com_tx_create(int a_argc, char **a_argv, void **a_json_arr_reply)
             l_ret = DAP_CHAIN_NODE_CLI_COM_TX_CREATE_CAN_NOT_ADD_DATUM_IN_MEMPOOL;
         }
         json_object_array_add(*a_json_arr_reply, l_jobj_emission);
-        for (size_t i = 0; i < l_addr_el_count; ++i) {
-                DAP_DELETE(l_addr_to[i]);
-            }
+        DAP_DEL_ARRAY(l_addr_to, l_addr_el_count);
         DAP_DEL_MULTY(l_addr_to, l_value);
         if (l_wallet_fee) {
             dap_chain_wallet_close(l_wallet_fee);
@@ -2938,9 +2934,7 @@ int com_tx_create(int a_argc, char **a_argv, void **a_json_arr_reply)
     if(!l_wallet) {
         dap_json_rpc_error_add(*a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_TX_CREATE_WALLET_DOES_NOT_EXIST,
                                "wallet %s does not exist", l_from_wallet_name);
-        for (size_t i = 0; i < l_addr_el_count; ++i) {
-                DAP_DELETE(l_addr_to[i]);
-        }
+        DAP_DEL_ARRAY(l_addr_to, l_addr_el_count);
         DAP_DEL_MULTY(l_addr_to, l_value);
         return DAP_CHAIN_NODE_CLI_COM_TX_CREATE_WALLET_DOES_NOT_EXIST;
     } else {
@@ -2957,9 +2951,7 @@ int com_tx_create(int a_argc, char **a_argv, void **a_json_arr_reply)
         dap_enc_key_delete(l_priv_key);
         dap_json_rpc_error_add(*a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_TX_CREATE_SOURCE_ADDRESS_INVALID, "source address is invalid");
         json_object_put(l_jobj_result);
-        for (size_t i = 0; i < l_addr_el_count; ++i) {
-            DAP_DELETE(l_addr_to[i]);
-        }
+        DAP_DEL_ARRAY(l_addr_to, l_addr_el_count);
         DAP_DEL_MULTY(l_addr_to, l_value);
         return DAP_CHAIN_NODE_CLI_COM_TX_CREATE_SOURCE_ADDRESS_INVALID;
     }
@@ -2970,9 +2962,7 @@ int com_tx_create(int a_argc, char **a_argv, void **a_json_arr_reply)
             dap_enc_key_delete(l_priv_key);
             dap_json_rpc_error_add(*a_json_arr_reply, DAP_CHAIN_NODE_CLI_COM_TX_CREATE_EQ_SOURCE_DESTINATION_ADDRESS, "The transaction cannot be directed to the same address as the source.");
             json_object_put(l_jobj_result);
-            for (size_t j = 0; j < l_addr_el_count; ++j) {
-                    DAP_DELETE(l_addr_to[j]);
-            }
+            DAP_DEL_ARRAY(l_addr_to, l_addr_el_count);
             DAP_DEL_MULTY(l_addr_to, l_value);
             return DAP_CHAIN_NODE_CLI_COM_TX_CREATE_EQ_SOURCE_DESTINATION_ADDRESS;
         }
@@ -3000,9 +2990,7 @@ int com_tx_create(int a_argc, char **a_argv, void **a_json_arr_reply)
                 dap_string_free(l_allowed_list, true);
                 json_object_put(l_jobj_result);
 
-                for (size_t j = 0; j < l_addr_el_count; ++j) {
-                    DAP_DELETE(l_addr_to[j]);
-                }
+                DAP_DEL_ARRAY(l_addr_to, l_addr_el_count);
                 DAP_DEL_MULTY(l_addr_to, l_value);
                 return DAP_CHAIN_NODE_CLI_COM_TX_CREATE_DESTINATION_NETWORK_IS_UNREACHEBLE;
             }
@@ -3036,9 +3024,7 @@ int com_tx_create(int a_argc, char **a_argv, void **a_json_arr_reply)
     json_object_array_add(*a_json_arr_reply, l_jobj_result);
 
     
-    for (size_t i = 0; i < l_addr_el_count; ++i) {
-        DAP_DELETE(l_addr_to[i]);
-    }
+    DAP_DEL_ARRAY(l_addr_to, l_addr_el_count);
     DAP_DEL_MULTY(l_addr_to, l_value);
     dap_chain_wallet_close(l_wallet);
     dap_enc_key_delete(l_priv_key);
-- 
GitLab


From 25d1e6122065e4825d12b82a062b0a48ee0944f9 Mon Sep 17 00:00:00 2001
From: "Constantin P." <papizh.konstantin@demlabs.net>
Date: Wed, 11 Dec 2024 14:45:07 +0700
Subject: [PATCH 02/11] ...

---
 modules/net/dap_chain_net.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 5e8774bfba..c49e31116e 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -792,10 +792,9 @@ void dap_chain_net_load_all()
                         i ? "Only " : "", i, l_nets_count, l_err, dap_strerror(l_err));
         l_nets_count = i;
     }
-    for ( i = 0; i < l_nets_count; ++i ) {
-        if (( l_err = pthread_join(l_tids[i], NULL) ))
-            log_it(L_ERROR, "Thread %d join error %d: \"%s\"", l_err, dap_strerror(l_err));
-     }
+    for ( i = 0; i < l_nets_count; l_err = pthread_join(l_tids[i++], NULL) ) {
+        debug_if(l_err, L_ERROR, "Thread %d join error %d: \"%s\"", l_err, dap_strerror(l_err));
+    }
     dap_timerfd_delete(l_load_notify_timer->worker, l_load_notify_timer->esocket_uuid);
 }
 
-- 
GitLab


From 4a358b8b2eac701ced2a4cee74b582443b5d8831 Mon Sep 17 00:00:00 2001
From: "Constantin P." <papizh.konstantin@demlabs.net>
Date: Sat, 28 Dec 2024 11:17:57 +0700
Subject: [PATCH 03/11] proceeding....

---
 dap-sdk                                       |   2 +-
 modules/chain/tests/dap_chain_ledger_tests.c  |   2 +-
 .../consensus/dag-poa/dap_chain_cs_dag_poa.c  |  12 +-
 modules/ledger/dap_chain_ledger.c             |   3 +-
 modules/ledger/dap_chain_ledger_decree.c      |  29 +--
 modules/ledger/include/dap_chain_ledger.h     |   3 +-
 modules/net/dap_chain_net.c                   | 190 +++++++++---------
 modules/net/include/dap_chain_net.h           |   3 +
 8 files changed, 110 insertions(+), 134 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index 3b666f271d..ff4ff670a8 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 3b666f271d3f3ecceebcabc091370fbff270e4f6
+Subproject commit ff4ff670a8b221e11dbf9e83d4dee499ada5e5eb
diff --git a/modules/chain/tests/dap_chain_ledger_tests.c b/modules/chain/tests/dap_chain_ledger_tests.c
index 0d095b8844..1ac7c8d084 100644
--- a/modules/chain/tests/dap_chain_ledger_tests.c
+++ b/modules/chain/tests/dap_chain_ledger_tests.c
@@ -1027,7 +1027,7 @@ void dap_ledger_test_run(void){
     dap_assert_PIF(dap_chain_cs_create(l_chain_main, &l_cfg) == 0, "Chain esbocs cs creating: ");
     DL_APPEND(l_net->pub.chains, l_chain_main);
 
-    dap_assert_PIF(!dap_ledger_decree_create(l_net->pub.ledger), "Decree initialization:");
+    dap_assert_PIF(!dap_ledger_decree_init(l_net->pub.ledger), "Decree initialization:");
 
     char *l_seed_ph = "H58i9GJKbn91238937^#$t6cjdf";
     size_t l_seed_ph_size = strlen(l_seed_ph);
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 409a5ccf59..9ca644a02f 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -379,11 +379,7 @@ static int s_callback_new(dap_chain_t *a_chain, dap_config_t * a_chain_cfg)
         l_poa_pvt->auth_certs_count = dap_config_get_item_uint16_default(a_chain_cfg,"dag-poa","auth_certs_number",0);
         l_poa_pvt->auth_certs_count_verify = dap_config_get_item_uint16_default(a_chain_cfg,"dag-poa","auth_certs_number_verify",0);
         if (l_poa_pvt->auth_certs_count && l_poa_pvt->auth_certs_count_verify) {
-            l_poa_pvt->auth_certs = DAP_NEW_Z_SIZE ( dap_cert_t *, l_poa_pvt->auth_certs_count * sizeof(dap_cert_t *));
-            if (!l_poa_pvt->auth_certs) {
-                log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-                return -1;
-            }
+            l_poa_pvt->auth_certs = DAP_NEW_Z_COUNT_RET_VAL_IF_FAIL(dap_cert_t*, l_poa_pvt->auth_certs_count, -1);
             char l_cert_name[MAX_PATH + 1];
             int l_pos;
             for (uint16_t i = 0; i < l_poa_pvt->auth_certs_count ; ++i) {
@@ -910,11 +906,9 @@ dap_list_t *dap_chain_cs_dag_poa_get_auth_certs(dap_chain_t *a_chain, size_t *a_
         *a_count_verify = l_poa_pvt->auth_certs_count_verify;
 
     dap_list_t *l_keys_list = NULL;
-    for(size_t i = 0; i < l_poa_pvt->auth_certs_count; i++)
+    for (size_t i = 0; i < l_poa_pvt->auth_certs_count; ++i)
     {
-        dap_pkey_t *l_pkey = dap_cert_to_pkey(l_poa_pvt->auth_certs[i]);
-        l_keys_list = dap_list_append(l_keys_list, l_pkey);
+        l_keys_list = dap_list_append(l_keys_list, dap_cert_to_pkey(l_poa_pvt->auth_certs[i]));
     }
-
     return l_keys_list;
 }
diff --git a/modules/ledger/dap_chain_ledger.c b/modules/ledger/dap_chain_ledger.c
index e6224f2f5d..ede85c407c 100644
--- a/modules/ledger/dap_chain_ledger.c
+++ b/modules/ledger/dap_chain_ledger.c
@@ -784,8 +784,7 @@ dap_ledger_t *dap_ledger_create(dap_chain_net_t *a_net, uint16_t a_flags)
         dap_ledger_load_cache(l_ledger);
 #endif
     // Decrees initializing
-    dap_ledger_decree_create(l_ledger);
-
+    dap_ledger_decree_init(l_ledger);
     return l_ledger;
 }
 
diff --git a/modules/ledger/dap_chain_ledger_decree.c b/modules/ledger/dap_chain_ledger_decree.c
index 3ecfd2f963..1795c3a26b 100644
--- a/modules/ledger/dap_chain_ledger_decree.c
+++ b/modules/ledger/dap_chain_ledger_decree.c
@@ -42,31 +42,14 @@ static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain
 static int s_service_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain_net_t *a_net, bool a_apply);
 
 // Public functions
-int dap_ledger_decree_create(dap_ledger_t *a_ledger)
-{
-    dap_return_val_if_fail(a_ledger, -106);
-
-    size_t l_auth_certs_count = 0;
-    dap_list_t *l_net_keys = NULL;
-    uint16_t l_count_verify = 0;
-    for (dap_chain_t *l_chain = a_ledger->net->pub.chains; l_chain; l_chain = l_chain->next) {
-        if (!l_chain->callback_get_poa_certs)
-            continue;
-        l_net_keys = l_chain->callback_get_poa_certs(l_chain, &l_auth_certs_count, &l_count_verify);
-        if (l_net_keys)
-            break;
-    }
 
-    if (!l_net_keys || !l_auth_certs_count) {
-        log_it(L_WARNING, "Certificates for net %s not found.", a_ledger->net->pub.name);
-        return -1;
-    }
+void dap_ledger_decree_init(dap_ledger_t *a_ledger) {
     dap_ledger_private_t *l_ledger_pvt = PVT(a_ledger);
-    l_ledger_pvt->decree_min_num_of_signers = l_count_verify;
-    l_ledger_pvt->decree_num_of_owners = l_auth_certs_count;
-    l_ledger_pvt->decree_owners_pkeys = l_net_keys;
-
-    return 0;
+    l_ledger_pvt->decree_min_num_of_signers = a_ledger->net->pub.keys_min_count;
+    l_ledger_pvt->decree_num_of_owners = dap_list_length(a_ledger->net->pub.keys);
+    l_ledger_pvt->decree_owners_pkeys = a_ledger->net->pub.keys;
+    if ( !l_ledger_pvt->decree_owners_pkeys )
+        log_it(L_WARNING, "PoA certificates for net %s not found", a_ledger->net->pub.name);
 }
 
 static int s_decree_clear(dap_ledger_t *a_ledger)
diff --git a/modules/ledger/include/dap_chain_ledger.h b/modules/ledger/include/dap_chain_ledger.h
index 66be425d77..4055bf5130 100644
--- a/modules/ledger/include/dap_chain_ledger.h
+++ b/modules/ledger/include/dap_chain_ledger.h
@@ -482,7 +482,8 @@ void dap_ledger_set_cache_tx_check_callback(dap_ledger_t *a_ledger, dap_ledger_c
 dap_chain_tx_out_cond_t* dap_chain_ledger_get_tx_out_cond_linked_to_tx_in_cond(dap_ledger_t *a_ledger, dap_chain_tx_in_cond_t *a_in_cond);
 void dap_ledger_load_end(dap_ledger_t *a_ledger);
 
-int dap_ledger_decree_create(dap_ledger_t *a_ledger);
+//int dap_ledger_decree_create(dap_ledger_t *a_ledger);
+void dap_ledger_decree_init(dap_ledger_t *a_ledger);
 void dap_ledger_decree_purge(dap_ledger_t *a_ledger);
 
 uint16_t dap_ledger_decree_get_min_num_of_signers(dap_ledger_t *a_ledger);
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index c49e31116e..334bea8d8d 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -217,6 +217,7 @@ static bool s_net_states_proc(void *a_arg);
 static void s_net_states_notify(dap_chain_net_t * l_net);
 static void s_nodelist_change_notify(dap_store_obj_t *a_obj, void *a_arg);
 //static void s_net_proc_kill( dap_chain_net_t * a_net );
+static int s_chains_init_all(const char *a_netname, const char *a_path, int *a_ledger_flags);
 static int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx);
 static void *s_net_load(void *a_arg);
 static int s_net_try_online(dap_chain_net_t *a_net);
@@ -1809,6 +1810,77 @@ static int s_nodes_hosts_init(dap_chain_net_t *a_net, dap_config_t *a_cfg, const
     return 0;
 }
 
+static int s_chains_init_all(dap_chain_net_t *a_net, const char *a_path, int *a_ledger_flags) {
+    DIR *l_chains_dir = opendir(a_path);
+    if (!l_chains_dir)
+        return log_it(L_ERROR, "Can't find any chains for network %s", a_net->pub.name), -1;
+    bool is_esbocs_debug = dap_config_get_item_bool_default(a_net->pub.config, "esbocs", "consensus_debug", false);
+    dap_config_t *l_chain_config, *l_all_chain_configs = NULL, *l_tmp_cfg;
+    char l_chain_cfg_path[MAX_PATH + 1] = { '\0' };
+    int l_pos = snprintf(l_chain_cfg_path, MAX_PATH, "network/%s/", a_net->pub.name);
+    for ( struct dirent *l_dir_entry; ( l_dir_entry = readdir(l_chains_dir) ); ) {
+        unsigned short l_len = strlen(l_dir_entry->d_name);
+        if ( l_len > 4 && !dap_strncmp(l_dir_entry->d_name + l_len - 4, ".cfg", 4) ) {
+            *(l_dir_entry->d_name + l_len - 4) = '\0';
+            log_it(L_DEBUG, "Opening chain config \"%s.%s\"", a_net->pub.name, l_dir_entry->d_name);
+            dap_strncpy(l_chain_cfg_path + l_pos, l_dir_entry->d_name, MAX_PATH - l_pos);
+            if (!( l_chain_config = dap_config_open(l_chain_cfg_path) )) {
+                log_it(L_ERROR, "Can't open chain config %s, skip it", l_dir_entry->d_name);
+                continue;
+            }
+            HASH_ADD_KEYPTR(hh, l_all_chain_configs, l_chain_config->path, strlen(l_chain_config->path), l_chain_config);
+        }
+    }
+    closedir(l_chains_dir);
+    if (!l_all_chain_configs)
+        return log_it(L_ERROR, "Can't find any chains for network %s", a_net->pub.name), -2;
+
+    HASH_SORT(l_all_chain_configs, s_cmp_cfg_pri);
+    dap_chain_t *l_chain;
+    dap_chain_type_t *l_types_arr;
+    char l_occupied_default_types[CHAIN_TYPE_MAX] = { 0 };
+    int l_poa_signers = 0, l_poa_signers_min = 0;
+    HASH_ITER(hh, l_all_chain_configs, l_chain_config, l_tmp_cfg) {
+        if (( l_chain = dap_chain_load_from_cfg(a_net->pub.name, a_net->pub.id, l_chain_config) )) {
+            DL_APPEND(a_net->pub.chains, l_chain);
+            l_types_arr = l_chain->default_datum_types;
+            uint16_t
+                i = 0,
+                k = l_chain->default_datum_types_count;
+            for ( ; i < k; ++i) {
+                if ( l_occupied_default_types[l_types_arr[i]] ) {
+                    if ( i < k - 1 )
+                        l_types_arr[i] = l_types_arr[k - 1];
+                    --i;
+                    --k;
+                } else
+                    l_occupied_default_types[l_types_arr[i]] = 1;
+            }
+            if ( k < l_chain->default_datum_types_count ) {
+                l_chain->default_datum_types_count = k;
+                l_chain->default_datum_types = DAP_REALLOC_COUNT(l_chain->default_datum_types, k);
+            }
+            if ( !dap_strcmp(DAP_CHAIN_PVT(l_chain)->cs_name, "esbocs") && is_esbocs_debug )
+                dap_chain_esbocs_change_debug_mode(l_chain, true);
+            if (l_chain->callback_load_from_gdb && a_ledger_flags) {
+                *a_ledger_flags &= ~DAP_LEDGER_MAPPED;
+                *a_ledger_flags |= DAP_LEDGER_THRESHOLD_ENABLED;
+            }
+            if ( l_chain->callback_get_poa_certs ) {
+                uint16_t l_min_count = 0;
+                a_net->pub.keys = dap_list_append(a_net->pub.keys, l_chain->callback_get_poa_certs(l_chain, NULL, &l_min_count));
+                a_net->pub.keys_min_count += l_min_count;
+            }
+        } else {
+            HASH_DEL(l_all_chain_configs, l_chain_config);
+            dap_config_close(l_chain_config);
+            return -3;
+        }
+    }
+    HASH_CLEAR(hh, l_all_chain_configs);
+    return 0;
+}
+
 /**
  * @brief load network config settings from cellframe-node.cfg file
  *
@@ -1864,107 +1936,42 @@ int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx)
         log_it(L_WARNING, "Can't read seed nodes addresses, work with local balancer only");
 
     // Get list chains name for enabled debug mode
-    bool is_esbocs_debug = dap_config_get_item_bool_default(l_cfg, "esbocs", "consensus_debug", false);
 
     if ( dap_server_enabled() && ( l_net_pvt->node_info->ext_port = dap_config_get_item_uint16(g_config, "server", "ext_port") ))
         log_it(L_INFO, "Set external port %u for adding in node list", l_net_pvt->node_info->ext_port);
 
-    struct dirent *l_dir_entry;
     // Services register & configure
     dap_chain_srv_start(l_net->pub.id, DAP_CHAIN_NET_SRV_XCHANGE_LITERAL, NULL);        // Harcoded core service starting for exchange capability
     dap_chain_srv_start(l_net->pub.id, DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_LITERAL, NULL);    // Harcoded core service starting for delegated keys storage
     char *l_services_path = dap_strdup_printf("%s/network/%s/services", dap_config_path(), l_net->pub.name);
     DIR *l_service_cfg_dir = opendir(l_services_path);
     DAP_DELETE(l_services_path);
-    while (l_service_cfg_dir && (l_dir_entry = readdir(l_service_cfg_dir)) != NULL) {
-        if (l_dir_entry->d_name[0] == '\0')
-            continue;
-        const char *l_entry_name = l_dir_entry->d_name;
-        size_t l_entry_len = strlen(l_entry_name);
-        if (l_entry_len < 4 || // It has non zero name excluding file extension
-                strncmp(l_entry_name + l_entry_len - 4, ".cfg", 4) != 0) // its not a .cfg file
-            continue;
-        log_it(L_DEBUG, "Opening service config \"%s\"...", l_entry_name);
-        char *l_service_cfg_path = dap_strdup_printf("network/%s/services/%s", l_net->pub.name, l_entry_name);
-        dap_config_t *l_cfg_new = dap_config_open(l_service_cfg_path);
-        if (l_cfg_new) {
-            char *l_service_name = DAP_DUP_SIZE((char *)l_entry_name, l_entry_len - 3);
-            l_service_name[l_entry_len - 4] = 0;
-            dap_chain_srv_start(l_net->pub.id, l_service_name, l_cfg_new);
-            dap_config_close(l_cfg_new);
-            DAP_DELETE(l_service_name);
-        }
-        DAP_DELETE(l_service_cfg_path);
-    }
-    closedir(l_service_cfg_dir);
-
-    /* *** Chains init by configs *** */
-    DIR *l_chains_dir = opendir(a_path);
-    if (!l_chains_dir)
-        return log_it(L_ERROR, "Can't find any chains for network %s", l_net->pub.name), dap_chain_net_delete(l_net), -7;
-
-    dap_config_t *l_chain_config, *l_all_chain_configs = NULL, *l_tmp_cfg;
-    char l_chain_cfg_path[MAX_PATH + 1] = { '\0' };
-    int l_pos = snprintf(l_chain_cfg_path, MAX_PATH, "network/%s/", a_net_name);
-    while (( l_dir_entry = readdir(l_chains_dir) )) {
-        unsigned short l_len = strlen(l_dir_entry->d_name);
-        if ( l_len > 4 && !dap_strncmp(l_dir_entry->d_name + l_len - 4, ".cfg", 4) ) {
-            *(l_dir_entry->d_name + l_len - 4) = '\0';
-            log_it(L_DEBUG, "Opening chain config \"%s.%s\"", a_net_name, l_dir_entry->d_name);
-            dap_strncpy(l_chain_cfg_path + l_pos, l_dir_entry->d_name, MAX_PATH - l_pos);
-            if (!( l_chain_config = dap_config_open(l_chain_cfg_path) )) {
-                log_it(L_ERROR, "Can't open chain config %s, skip it", l_dir_entry->d_name);
+    if (l_service_cfg_dir) {
+        for ( struct dirent *l_dir_entry; ( l_dir_entry = readdir(l_service_cfg_dir) ); ) {
+            const char *l_entry_name = l_dir_entry->d_name;
+            size_t l_entry_len = strlen(l_entry_name);
+            if (l_entry_len < 4 || // It has non zero name excluding file extension
+                    strncmp(l_entry_name + l_entry_len - 4, ".cfg", 4) != 0) // its not a .cfg file
                 continue;
+            log_it(L_DEBUG, "Opening service config \"%s\"...", l_entry_name);
+            char *l_service_cfg_path = dap_strdup_printf("network/%s/services/%s", l_net->pub.name, l_entry_name);
+            dap_config_t *l_cfg_new = dap_config_open(l_service_cfg_path);
+            if (l_cfg_new) {
+                char *l_service_name = DAP_DUP_SIZE((char *)l_entry_name, l_entry_len - 3);
+                l_service_name[l_entry_len - 4] = 0;
+                dap_chain_srv_start(l_net->pub.id, l_service_name, l_cfg_new);
+                dap_config_close(l_cfg_new);
+                DAP_DELETE(l_service_name);
             }
-            HASH_ADD_KEYPTR(hh, l_all_chain_configs, l_chain_config->path, strlen(l_chain_config->path), l_chain_config);
-        }
-    }
-    closedir(l_chains_dir);
-    if (!l_all_chain_configs)
-        return log_it(L_ERROR, "Can't find any chains for network %s", l_net->pub.name), dap_chain_net_delete(l_net), -8;
-
-    HASH_SORT(l_all_chain_configs, s_cmp_cfg_pri);
-    dap_chain_t *l_chain;
-    dap_chain_type_t *l_types_arr;
-    char l_occupied_default_types[CHAIN_TYPE_MAX] = { 0 };
-    HASH_ITER(hh, l_all_chain_configs, l_chain_config, l_tmp_cfg) {
-        if (( l_chain = dap_chain_load_from_cfg(l_net->pub.name, l_net->pub.id, l_chain_config) )) {
-            DL_APPEND(l_net->pub.chains, l_chain);
-            l_types_arr = l_chain->default_datum_types;
-            uint16_t
-                i = 0,
-                k = l_chain->default_datum_types_count;
-            for ( ; i < k; ++i) {
-                if ( l_occupied_default_types[l_types_arr[i]] ) {
-                    if ( i < k - 1 )
-                        l_types_arr[i] = l_types_arr[k - 1];
-                    --i;
-                    --k;
-                } else
-                    l_occupied_default_types[l_types_arr[i]] = 1;
-            }
-            if ( k < l_chain->default_datum_types_count ) {
-                l_chain->default_datum_types_count = k;
-                l_chain->default_datum_types = DAP_REALLOC_COUNT(l_chain->default_datum_types, k);
-            }
-            if (!dap_strcmp(DAP_CHAIN_PVT(l_chain)->cs_name, "esbocs") && is_esbocs_debug) {
-                dap_chain_esbocs_change_debug_mode(l_chain, true);
-            }
-        } else {
-            HASH_DEL(l_all_chain_configs, l_chain_config);
-            dap_config_close(l_chain_config);
-            dap_chain_net_delete(l_net);
-            return -5;
+            DAP_DELETE(l_service_cfg_path);
         }
+        closedir(l_service_cfg_dir);
     }
-    HASH_CLEAR(hh, l_all_chain_configs);
-
-    // LEDGER model
     uint16_t l_ledger_flags = 0;
     switch ( PVT( l_net )->node_role.enums ) {
     case NODE_ROLE_LIGHT:
         //break;
-        PVT( l_net )->node_role.enums = NODE_ROLE_FULL; // TODO: implement light mode
+        PVT( a_net )->node_role.enums = NODE_ROLE_FULL; // TODO: implement light mode
     case NODE_ROLE_FULL:
         l_ledger_flags |= DAP_LEDGER_CHECK_LOCAL_DS;
         if (dap_config_get_item_bool_default(g_config, "ledger", "cache_enabled", false))
@@ -1975,23 +1982,12 @@ int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx)
     if (dap_config_get_item_bool_default(g_config, "ledger", "mapped", true))
         l_ledger_flags |= DAP_LEDGER_MAPPED;
 
-    for (dap_chain_t *l_chain = l_net->pub.chains; l_chain; l_chain = l_chain->next) {
-        if (l_chain->callback_load_from_gdb) {
-            l_ledger_flags &= ~DAP_LEDGER_MAPPED;
-            l_ledger_flags |= DAP_LEDGER_THRESHOLD_ENABLED;
-            continue;
-        }
-        if (!l_chain->callback_get_poa_certs)
-            continue;
-        if (!l_net->pub.keys)
-            l_net->pub.keys = l_chain->callback_get_poa_certs(l_chain, NULL, NULL);
-    }
-    if (!l_net->pub.keys)
-        log_it(L_WARNING, "PoA certificates for net %s not found", l_net->pub.name);
+    int l_res = s_chains_init_all(l_net, a_path, &l_ledger_flags);
+    if ( l_res )
+        return dap_chain_net_delete(l_net), l_res;
 
     // init LEDGER model
     l_net->pub.ledger = dap_ledger_create(l_net, l_ledger_flags);
-
     return 0;
 }
 
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index b438c77cad..6f56bf9cc1 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -62,7 +62,10 @@ typedef struct dap_chain_net {
         dap_chain_net_id_t id;
         char name[DAP_CHAIN_NET_NAME_MAX + 1], gdb_nodes[DAP_CHAIN_NET_NAME_MAX + sizeof(s_gdb_nodes_postfix) + 1];
         const char *gdb_groups_prefix, *native_ticker;
+        // PoA section
         dap_list_t *keys;               // List of PoA certs for net
+        uint16_t keys_min_count;        // PoA minimum required number
+        //
         dap_chain_t *chains;            // double-linked list of chains
         dap_ledger_t *ledger;
         uint256_t fee_value;            // Net fee
-- 
GitLab


From db28812600a04836bf4b8cadaf14ceef32be2815 Mon Sep 17 00:00:00 2001
From: "P. Constantin" <papizh.konstantin@demlabs.net>
Date: Wed, 5 Feb 2025 01:05:50 +0700
Subject: [PATCH 04/11] ...

---
 modules/chain/dap_chain.c                     |  93 ++--
 modules/chain/dap_chain_cell.c                | 437 ++++++++++--------
 modules/chain/dap_chain_cs.c                  |   9 +-
 modules/chain/include/dap_chain.h             |  13 +-
 modules/chain/include/dap_chain_cell.h        |  34 +-
 modules/chain/include/dap_chain_common.h      |  16 +-
 .../consensus/dag-poa/dap_chain_cs_dag_poa.c  |  30 +-
 modules/net/dap_chain_net.c                   | 159 ++-----
 modules/type/blocks/dap_chain_cs_blocks.c     |  19 +-
 modules/type/dag/dap_chain_cs_dag.c           |   2 +-
 10 files changed, 421 insertions(+), 391 deletions(-)

diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index af633b7822..4084a05703 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -385,10 +385,11 @@ dap_chain_t *dap_chain_load_from_cfg(const char *a_chain_net_name, dap_chain_net
         if (!dap_dir_test(DAP_CHAIN_PVT(l_chain)->file_storage_dir))
             dap_mkdir_with_parents(DAP_CHAIN_PVT(l_chain)->file_storage_dir);
     } else
-        log_it (L_INFO, "Not set file storage path, will not stored in files");
+        log_it (L_INFO, "Not set file storage path, will not be stored in files"); // TODO
 
-    if (!l_chain->cells)
-        dap_chain_cell_create_fill( l_chain, (dap_chain_cell_id_t){ .uint64 = 0 } );
+    /*if (!l_chain->cells)
+        dap_chain_cell_create_fill( l_chain, (dap_chain_cell_id_t){ .uint64 = 0 } );*/
+    
     l_chain->config = a_cfg;
     l_chain->load_priority = dap_config_get_item_uint16_default(a_cfg, "chain", "load_priority", 100);
 
@@ -495,7 +496,7 @@ const char *dap_chain_get_cs_type(dap_chain_t *l_chain)
  * @param l_chain
  * @return
  */
-int dap_chain_save_all(dap_chain_t *l_chain)
+int dap_chain_save_all(dap_chain_t *l_chain) // TODO - move to cell.c
 {
     int l_ret = 0;
     pthread_rwlock_rdlock(&l_chain->cell_rwlock);
@@ -509,7 +510,7 @@ int dap_chain_save_all(dap_chain_t *l_chain)
 }
 
 //send chain load_progress data to notify socket
-bool download_notify_callback(dap_chain_t* a_chain) {
+static bool s_load_notify_callback(dap_chain_t* a_chain) {
     json_object* l_chain_info = json_object_new_object();
     json_object_object_add(l_chain_info, "class", json_object_new_string("chain_init"));
     json_object_object_add(l_chain_info, "net", json_object_new_string(a_chain->net_name));
@@ -529,55 +530,67 @@ bool download_notify_callback(dap_chain_t* a_chain) {
  */
 int dap_chain_load_all(dap_chain_t *a_chain)
 {
-    int l_ret = 0;
-    if (!a_chain)
-        return -2;
+    dap_return_val_if_fail(a_chain, -2);
     if (a_chain->callback_load_from_gdb) {
         a_chain->is_mapped = false;
         a_chain->callback_load_from_gdb(a_chain);
         return 0;
     }
     char *l_storage_dir = DAP_CHAIN_PVT(a_chain)->file_storage_dir;
-    if (!l_storage_dir)
-        return 0;
+    dap_return_val_if_fail_err(l_storage_dir, 0, "No path set for chains files in net %s", a_chain->net_name); // TODO: light mode?
+
     DIR *l_dir = opendir(l_storage_dir);
-    if (!l_dir) {
-        log_it(L_ERROR, "Cannot open directory %s", DAP_CHAIN_PVT(a_chain)->file_storage_dir);
-        return -3;
-    }
-    for (struct dirent *l_dir_entry = readdir(l_dir); l_dir_entry != NULL; l_dir_entry = readdir(l_dir)) {
-        const char *l_filename = l_dir_entry->d_name, l_suffix[] = ".dchaincell";
-        size_t l_suffix_len = strlen(l_suffix);
-        if (!strncmp(l_filename + strlen(l_filename) - l_suffix_len, l_suffix, l_suffix_len)) {
-            uint64_t l_cell_id_uint64 = 0;
-            sscanf(l_filename, "%"DAP_UINT64_FORMAT_x".dchaincell", &l_cell_id_uint64);
-            dap_chain_cell_t *l_cell = dap_chain_cell_create_fill(a_chain, (dap_chain_cell_id_t){ .uint64 = l_cell_id_uint64 });
-            dap_timerfd_t* l_download_notify_timer = dap_timerfd_start(5000, (dap_timerfd_callback_t)download_notify_callback, a_chain);
-            l_ret += dap_chain_cell_load(a_chain, l_cell);
+    dap_return_val_if_fail_err(l_dir, -3, "Cannot open directory %s, error %d: \"%s\"",
+                                          DAP_CHAIN_PVT(a_chain)->file_storage_dir, errno, dap_strerror(errno));
+    int l_err = -1;
+    const char l_suffix[] = ".dchaincell", *l_filename;
+    struct dirent *l_dir_entry = NULL;
+    dap_time_t l_ts_start = dap_time_now();
+    while (( l_dir_entry = readdir(l_dir) )) {
+        l_filename = l_dir_entry->d_name;
+        size_t l_namelen = strlen(l_filename);
+        if ( l_namelen >= sizeof(l_suffix) && !strncmp(l_filename + l_namelen - sizeof(l_suffix) - 1, l_suffix, sizeof(l_suffix) - 1) ) {
+            dap_timerfd_t* l_load_notify_timer = dap_timerfd_start(5000, (dap_timerfd_callback_t)s_load_notify_callback, a_chain);
+            l_err = dap_chain_cell_open(a_chain, l_filename, 'a');
+            dap_timerfd_delete(l_load_notify_timer->worker, l_load_notify_timer->esocket_uuid);
+            s_load_notify_callback(a_chain);
+            if (l_err)
+                break;
             if ( DAP_CHAIN_PVT(a_chain)->need_reorder ) {
 #ifdef DAP_OS_WINDOWS
-                strcat(l_cell->file_storage_path, ".new");
-                if (remove(l_cell->file_storage_path) == -1) {
-                    log_it(L_ERROR, "File %s doesn't exist", l_cell->file_storage_path);
-                }
-                *(l_cell->file_storage_path + strlen(l_cell->file_storage_path) - 4) = '\0';
+                char *l_new_path = dap_strdup_printf("%s/%s.new", DAP_CHAIN_PVT(a_chain)->file_storage_dir, l_filename);
+                if ( remove(l_new_path) == -1 )
+                    log_it(L_ERROR, "File \"%s\" doesn't exist", l_new_path);
+                DAP_DELETE(l_new_path);
 #else
-                const char *l_filename_backup = dap_strdup_printf("%s.unsorted", l_cell->file_storage_path);
-                if (remove(l_filename_backup) == -1) {
+                char *l_old_name = dap_strdup_printf("%s/%s", DAP_CHAIN_PVT(a_chain)->file_storage_dir, l_filename),
+                     *l_filename_backup = dap_strdup_printf("%s.unsorted", l_old_name);
+                     
+                if (remove(l_filename_backup) == -1)
                     log_it(L_ERROR, "File %s doesn't exist", l_filename_backup);
+                if (rename(l_old_name, l_filename_backup)) {
+                    log_it(L_ERROR, "Couldn't rename %s to %s", l_old_name, l_filename_backup);
                 }
-                if (rename(l_cell->file_storage_path, l_filename_backup)) {
-                    log_it(L_ERROR, "Couldn't rename %s to %s", l_cell->file_storage_path, l_filename_backup);
-                }
-                DAP_DELETE(l_filename_backup);
+                DAP_DEL_MULTY(l_old_name, l_filename_backup);
 #endif
             }
-            dap_timerfd_delete(l_download_notify_timer->worker, l_download_notify_timer->esocket_uuid);
-            download_notify_callback(a_chain);
         }
     }
     closedir(l_dir);
-    return l_ret;
+    
+    switch (l_err) {
+    case 0:
+        log_it(L_INFO, "Loaded all chain \"%s : %s\" cells in %lf s",
+                        a_chain->net_name, a_chain->name, difftime((time_t)dap_time_now(), l_ts_start));
+        break;
+    case -1:
+        if (!( l_err = dap_chain_cell_open_file(a_chain, "0.dchaincell", 'w') ))
+            log_it(L_INFO, "Initialized chain \"%s : %s\" cell 0", a_chain->net_name, a_chain->name);
+        break;
+    default:
+        log_it(L_ERROR, "Chain \"%s : %s\" cell was not loaded, error %d", a_chain->net_name, a_chain->name, l_err)
+    }
+    return l_err;
 }
 
 /**
@@ -904,11 +917,7 @@ void dap_chain_datum_notify(dap_chain_cell_t *a_chain_cell,  dap_hash_fast_t *a_
     dap_list_t *l_iter;
     DL_FOREACH(a_chain_cell->chain->datum_notifiers, l_iter) {
         dap_chain_datum_notifier_t *l_notifier = (dap_chain_datum_notifier_t*)l_iter->data;
-        struct chain_thread_datum_notifier *l_arg = DAP_NEW_Z(struct chain_thread_datum_notifier);
-        if (!l_arg) {
-            log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-            continue;
-        }
+        struct chain_thread_datum_notifier *l_arg = DAP_NEW_Z_RET_IF_FAIL(struct chain_thread_datum_notifier);
         *l_arg = (struct chain_thread_datum_notifier) {
             .callback = l_notifier->callback, .callback_arg = l_notifier->arg,
             .chain = a_chain_cell->chain,     .cell_id = a_chain_cell->id,
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index 2f81640f4c..cf26c6514d 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -42,6 +42,9 @@
 #define DAP_CHAIN_CELL_FILE_TYPE_RAW 0
 #define DAP_CHAIN_CELL_FILE_TYPE_COMPRESSED 1
 #define DAP_MAPPED_VOLUME_LIMIT ( 1 << 28 ) // 256 MB for now, may be should be configurable?
+
+#define CELL_FILE_EXT "dchaincell"
+
 /**
   * @struct dap_chain_cell_file_header
   */
@@ -117,6 +120,7 @@ DAP_STATIC_INLINE void s_cell_reclaim_cur_volume(dap_chain_cell_t *a_cell) {
 }
 #endif
 
+#if 0
 DAP_STATIC_INLINE int s_cell_file_write_header(dap_chain_cell_t *a_cell)
 {
     dap_chain_cell_file_header_t l_hdr = {
@@ -129,8 +133,9 @@ DAP_STATIC_INLINE int s_cell_file_write_header(dap_chain_cell_t *a_cell)
     };
     return fwrite(&l_hdr, sizeof(l_hdr), 1, a_cell->file_storage) ? fflush(a_cell->file_storage) : -1;
 }
+#endif
 
-DAP_STATIC_INLINE int s_cell_map_new_volume(dap_chain_cell_t *a_cell, size_t a_fpos, bool a_load) {
+DAP_STATIC_INLINE int s_cell_map_new_volume(dap_chain_cell_mmap_data_t *a_cell_map_data, size_t a_fpos, bool a_load) {
 #ifdef DAP_OS_WINDOWS
     HANDLE hSection = NULL;
     if ( !a_fpos ) {
@@ -144,7 +149,8 @@ DAP_STATIC_INLINE int s_cell_map_new_volume(dap_chain_cell_t *a_cell, size_t a_f
         };
         
         NTSTATUS err = pfnNtCreateSection(&hSection, SECTION_MAP_READ | SECTION_EXTEND_SIZE,
-                                          NULL, &SectionSize, PAGE_READWRITE, SEC_RESERVE, (HANDLE)_get_osfhandle(fileno(a_cell->file_storage)));
+                                          NULL, &SectionSize, PAGE_READWRITE, SEC_RESERVE,
+                                          (HANDLE)_get_osfhandle(fileno(a_cell->file_storage)));
         if ( !NT_SUCCESS(err) )
             return log_it(L_ERROR, "NtCreateSection() failed, status %lx: \"%s\"",
                                    err, dap_str_ntstatus(err) ), -1;
@@ -191,24 +197,7 @@ DAP_STATIC_INLINE int s_cell_map_new_volume(dap_chain_cell_t *a_cell, size_t a_f
     return 0;
 }
 
-/**
- * @brief dap_chain_cell_find_by_id
- * get dap_chain_cell_t object by cell (shard) id
- * @param a_chain dap_chain_t object
- * @param a_cell_id dap_chain_cell_id_t cell (shard) id
- * @return dap_chain_cell_t* 
- */
-dap_chain_cell_t * dap_chain_cell_find_by_id(dap_chain_t * a_chain, dap_chain_cell_id_t a_cell_id)
-{
-    if (!a_chain->cells)
-        return NULL;
-    dap_chain_cell_t *l_cell = NULL;
-    pthread_rwlock_rdlock(&a_chain->cell_rwlock);
-    HASH_FIND(hh, a_chain->cells, &a_cell_id, sizeof(dap_chain_cell_id_t), l_cell);
-    pthread_rwlock_unlock(&a_chain->cell_rwlock);
-    return l_cell;
-}
-
+#if 0
 /**
  * @brief 
  * a_cell_id if < 0 then not used
@@ -216,7 +205,7 @@ dap_chain_cell_t * dap_chain_cell_find_by_id(dap_chain_t * a_chain, dap_chain_ce
  * @param a_cell_id dap_chain_cell_id_t cell (shard) id
  * @return dap_chain_cell_t* 
  */
-dap_chain_cell_t * dap_chain_cell_create_fill(dap_chain_t * a_chain, dap_chain_cell_id_t a_cell_id)
+dap_chain_cell_t * dap_chain_cell_create_fill(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id)
 {
     dap_chain_cell_t * l_cell = NULL;
     pthread_rwlock_wrlock(&a_chain->cell_rwlock);
@@ -233,6 +222,7 @@ dap_chain_cell_t * dap_chain_cell_create_fill(dap_chain_t * a_chain, dap_chain_c
     DAP_DELETE(l_cell); \
     pthread_rwlock_unlock(&a_chain->cell_rwlock); \
     NULL; })
+
     if ( !(l_file = fopen(file_storage_path, "a+b")) ) {
         log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be opened, error %d",
                         file_storage_path, a_cell_id.uint64, errno);
@@ -263,6 +253,7 @@ dap_chain_cell_t * dap_chain_cell_create_fill(dap_chain_t * a_chain, dap_chain_c
         log_it(L_NOTICE, "Initialized file storage for cell 0x%016"DAP_UINT64_FORMAT_X" \"%s\"",
                           a_cell_id.uint64, file_storage_path);
         fflush(l_file);
+        l_file = freopen(file_storage_path, "a+b", l_file);
     }
 
     if ( a_chain->is_mapped && s_cell_map_new_volume(l_cell, 0, true) ) {
@@ -276,15 +267,10 @@ dap_chain_cell_t * dap_chain_cell_create_fill(dap_chain_t * a_chain, dap_chain_c
     return l_cell;
 }
 
-/**
- * @brief
- * close a_cell->file_storage file object
- * @param a_cell dap_chain_cell_t object
- */
-void dap_chain_cell_close(dap_chain_cell_t *a_cell)
-{
-    if(!a_cell)
-        return;
+#endif
+
+DAP_STATIC_INLINE int s_cell_close(dap_chain_cell_t *a_cell) {
+    pthread_rwlock_wrlock(&a_cell->storage_rwlock);
     if(a_cell->file_storage) {
         fclose(a_cell->file_storage);
         a_cell->file_storage = NULL;
@@ -320,8 +306,31 @@ void dap_chain_cell_close(dap_chain_cell_t *a_cell)
         DAP_DELETE(l_orig);
     }
 #endif
+    pthread_rwlock_unlock(&a_cell->storage_rwlock);
+    pthread_rwlock_destroy(&a_cell->storage_rwlock);
+}
+
+/**
+ * @brief
+ * close a_cell->file_storage file object
+ * @param a_cell dap_chain_cell_t object
+ */
+void dap_chain_cell_close(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id)
+{
+    dap_return_if_fail(a_chain);
+    dap_chain_cell_t *l_cell = NULL;
+    HASH_FIND(hh, a_chain->cells, &a_cell_id, sizeof(dap_chain_cell_id_t), l_cell);
+    if (l_cell) {
+        s_cell_close(l_cell);
+        HASH_DEL(a_chain->cells, l_cell);
+        DAP_DELETE(l_cell);
+    } else
+        log_it(L_ERROR, "Cell 0x%016"DAP_UINT64_FORMAT_X" not found in chain \"%s : %s\"",
+                a_cell_id.uint64, a_chain->net_name, a_chain->name);
+    pthread_rwlock_unlock(&a_chain->cell_rwlock);
 }
 
+#if 0
 /**
  * @brief 
  * free chain cell objects
@@ -387,15 +396,16 @@ void dap_chain_cell_delete_all_and_free_file(dap_chain_t *a_chain) {
     pthread_rwlock_unlock(&a_chain->cell_rwlock);
 }
 
-void dap_chain_cell_delete_all(dap_chain_t *a_chain) {
+#endif
+
+void dap_chain_cell_close_all(dap_chain_t *a_chain) {
     if (!a_chain)
         return;
     pthread_rwlock_wrlock(&a_chain->cell_rwlock);
     dap_chain_cell_t *l_cell, *l_tmp;
     HASH_ITER(hh, a_chain->cells, l_cell, l_tmp) {
-        dap_chain_cell_close(l_cell);
+        s_cell_close(l_cell);
         HASH_DEL(a_chain->cells, l_cell);
-        pthread_rwlock_destroy(&l_cell->storage_rwlock);
         DAP_DELETE(l_cell);
     }
     pthread_rwlock_unlock(&a_chain->cell_rwlock);
@@ -408,107 +418,90 @@ void dap_chain_cell_delete_all(dap_chain_t *a_chain) {
  * @param a_cell_file_path contains name of chain, for example "0.dchaincell" 
  * @return
  */
-int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell)
+DAP_STATIC_INLINE int s_cell_load_from_file(dap_chain_cell_t *a_cell)
 {
-    if (!a_cell)
-        return -1;
-    off_t l_full_size = !fseeko(a_cell->file_storage, 0, SEEK_END) ? ftello(a_cell->file_storage) : -1;
-    if (l_full_size < 0)
-        return log_it(L_ERROR, "Can't get chain size, error %d: \"%s\"", errno, dap_strerror(errno)), -1;
-    if ( l_full_size < (off_t)sizeof(dap_chain_cell_file_header_t) ) {
-        log_it(L_ERROR, "Chain cell \"%s\" is corrupt, create new file", a_cell->file_storage_path);
-        return -1;
-    }
-    dap_chain_cell_file_header_t *l_hdr = NULL;
-    if (a_chain->is_mapped) {
-        l_hdr = (dap_chain_cell_file_header_t*)a_cell->map;
-    } else {
-        fseeko(a_cell->file_storage, 0, SEEK_SET);
-        l_hdr = DAP_NEW(dap_chain_cell_file_header_t);
-        if ( fread(l_hdr, 1, sizeof(*l_hdr), a_cell->file_storage) != sizeof(*l_hdr) ) {
-            log_it(L_ERROR,"Can't read chain header \"%s\"", a_cell->file_storage_path);
-            fclose(a_cell->file_storage);
-            DAP_DELETE(l_hdr);
-            return -2;
+    off_t l_pos, l_full_size = !fseeko(a_cell->file_storage, 0, SEEK_END) ? ftello(a_cell->file_storage) : -1;
+    dap_return_val_if_fail_err(l_full_size < 0, 1, "Can't get chain size, error %d: \"%s\"", errno, dap_strerror(errno));
+    dap_return_val_if_fail_err(l_full_size < (off_t)sizeof(dap_chain_cell_file_header_t), 2, "Chain cell \"%s\" is corrupt, create new file", a_cell->file_storage_path);
+
+    /* Load header */
+    {
+        dap_chain_cell_file_header_t *l_hdr = DAP_NEW_STACK(dap_chain_cell_file_header_t);
+        if (a_cell->chain->is_mapped) {
+            dap_return_val_if_pass_err( s_cell_map_new_volume(a_cell, 0, false), -3, "Error on mapping the first volume" );
+            l_hdr = (dap_chain_cell_file_header_t*)a_cell->map;
+        } else {
+            fseeko(a_cell->file_storage, 0, SEEK_SET);
+            dap_return_val_if_fail_err( fread(l_hdr, 1, sizeof(*l_hdr), a_cell->file_storage) != sizeof(*l_hdr), -4,
+                                        "Can't read chain header \"%s\"", a_cell->file_storage_path );
         }
-    }
-    if (l_hdr->signature != DAP_CHAIN_CELL_FILE_SIGNATURE) {
-        log_it(L_ERROR, "Wrong signature in chain \"%s\", possible file corrupt", a_cell->file_storage_path);
-        fclose(a_cell->file_storage);
-        if (!a_chain->is_mapped) DAP_DELETE(l_hdr);
-        return -3;
-    }
-    if (l_hdr->version < DAP_CHAIN_CELL_FILE_VERSION ){
-        log_it(L_ERROR, "Too low chain version, backup files");
-        fclose(a_cell->file_storage);
-        if (!a_chain->is_mapped) DAP_DELETE(l_hdr);
-        return -4;
-    }
-    off_t l_pos = sizeof(*l_hdr);
-    if (a_chain->is_mapped)
-        a_cell->map_pos = a_cell->map + l_pos;
-    if (l_full_size == l_pos) {
-        return fseeko(a_cell->file_storage, l_pos, SEEK_SET);
+        dap_return_val_if_fail_err( l_hdr->cell_id.uint64 == a_cell->id.uint64, 5,
+                                    "Wrong cell id, %lu != %lu", l_hdr->cell_id.uint64, a_cell->id.uint64);
+        dap_return_val_if_fail_err( l_hdr->signature == DAP_CHAIN_CELL_FILE_SIGNATURE, 5,
+                                    "Wrong signature in chain \"%s\", possible file corrupt", a_cell->file_storage_path );
+        dap_return_val_if_fail_err( l_hdr->version >= DAP_CHAIN_CELL_FILE_VERSION, -6,
+                                    "Too low chain version %d < %d, create a backup", l_hdr->version, DAP_CHAIN_CELL_FILE_VERSION );
+        l_pos = sizeof(*l_hdr);
+        if (a_cell->chain->is_mapped)
+            a_cell->map_pos = a_cell->map + l_pos;
+        if (l_full_size == l_pos)
+            return 0; // fseeko(a_cell->file_storage, l_pos, SEEK_SET);
     }
 
+    /* Load atoms */
     int l_ret = 0;    
     uint64_t l_el_size = 0, q = 0;
-    if (a_chain->is_mapped) {
+    if (a_cell->chain->is_mapped) {
         dap_hash_fast_t l_atom_hash;
         for ( off_t l_vol_rest = 0; l_pos + sizeof(uint64_t) < (size_t)l_full_size; ++q, l_pos += l_el_size + sizeof(uint64_t) ) {
             l_vol_rest = (off_t)(a_cell->map_end - a_cell->map_pos) - sizeof(uint64_t);
             if ( l_vol_rest <= 0 || (uint64_t)l_vol_rest < *(uint64_t*)a_cell->map_pos )
-                if ( s_cell_map_new_volume(a_cell, l_pos, true) ) {
-                    l_ret = -2;
-                    break;
-                }
+                dap_return_val_if_pass_err( s_cell_map_new_volume(a_cell, l_pos, true), -7, "Error on mapping a new volume" );
             l_el_size = *(uint64_t*)a_cell->map_pos;
             if ( !l_el_size || l_el_size > (size_t)(l_full_size - l_pos) )
                 break;
             a_cell->map_pos += sizeof(uint64_t);
             dap_chain_atom_ptr_t l_atom = (dap_chain_atom_ptr_t)(a_cell->map_pos);
             dap_hash_fast(l_atom, l_el_size, &l_atom_hash);
-            a_chain->callback_atom_add(a_chain, l_atom, l_el_size, &l_atom_hash, false);
+            a_cell->chain->callback_atom_add(a_cell->chain, l_atom, l_el_size, &l_atom_hash, false);
             a_cell->map_pos += l_el_size;
-            a_chain->load_progress = (int)((float)l_pos/l_full_size * 100 + 0.5);
+            a_cell->chain->load_progress = (int)((float)l_pos/l_full_size * 100 + 0.5);
         }
 #ifndef DAP_OS_WINDOWS
         s_cell_reclaim_cur_volume(a_cell);
 #endif
     } else { 
-        DAP_DELETE(l_hdr);
         size_t l_read = 0;
         while ((l_read = fread(&l_el_size, 1, sizeof(l_el_size), a_cell->file_storage)) && !feof(a_cell->file_storage)) {
             if (l_read != sizeof(l_el_size) || l_el_size == 0) {
                 log_it(L_ERROR, "Corrupted element size %zu, chain %s is damaged", l_el_size, a_cell->file_storage_path);
-                l_ret = -4;
+                l_ret = 8;
                 break;
             }
             dap_chain_atom_ptr_t l_element = DAP_NEW_SIZE(dap_chain_atom_ptr_t, l_el_size);
             if (!l_element) {
                 log_it(L_CRITICAL, "Memory allocation error");
-                l_ret = -5;
+                l_ret = -9;
                 break;
             }
             l_read = fread((void*)l_element, 1, l_el_size, a_cell->file_storage);
             if (l_read != l_el_size) {
                 log_it(L_ERROR, "Read only %lu of %zu bytes, stop cell loading", l_read, l_el_size);
                 DAP_DELETE(l_element);
-                l_ret = -6;
+                l_ret = 10;
                 break;
             }
             l_pos += sizeof(uint64_t) + l_read;
-            a_chain->load_progress = (int)((float)l_pos/l_full_size * 100 + 0.5);
+            a_cell->chain->load_progress = (int)((float)l_pos/l_full_size * 100 + 0.5);
             dap_hash_fast_t l_atom_hash = {};
             dap_hash_fast(l_element, l_el_size, &l_atom_hash);
-            dap_chain_atom_verify_res_t l_res = a_chain->callback_atom_add(a_chain, l_element, l_el_size, &l_atom_hash, false);
-            if (l_res != ATOM_ACCEPT && l_res != ATOM_FORK) {
+            dap_chain_atom_verify_res_t l_res = a_cell->chain->callback_atom_add(a_cell->chain, l_element, l_el_size, &l_atom_hash, false);
+            if (l_res != ATOM_ACCEPT && l_res != ATOM_FORK)
                 DAP_DELETE(l_element);
-            }
             ++q;
         }
     }
-    if ( l_pos < l_full_size ) {
+    if ( l_pos < l_full_size && l_ret > 0 ) {
         log_it(L_ERROR, "Chain \"%s\" has incomplete tail, truncating %zu bytes",
                         a_cell->file_storage_path, l_full_size - l_pos );
 #ifdef DAP_OS_WINDOWS
@@ -516,9 +509,8 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell)
             LARGE_INTEGER SectionSize = (LARGE_INTEGER) { .QuadPart = l_pos };
             HANDLE hSection = (HANDLE)a_cell->map_range_bounds->data;
             NTSTATUS err = pfnNtExtendSection(hSection, &SectionSize);
-            if ( !NT_SUCCESS(err) ) {
+            if ( !NT_SUCCESS(err) )
                 log_it(L_ERROR, "NtExtendSection() failed, status %lx", err);
-            }
         } else
 #endif
             ftruncate(fileno(a_cell->file_storage), l_pos);
@@ -528,38 +520,125 @@ int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell)
     return l_ret;
 }
 
+DAP_STATIC_INLINE int s_cell_open(dap_chain_t *a_chain, const char *a_filename, const char a_mode) {
+    dap_chain_cell_id_t l_cell_id = { };
+    { /* Check filename */
+        char l_fmt[20] = "", l_ext[ sizeof(CELL_FILE_EXT) ] = "", l_ext2 = '\0';
+        snprintf(l_fmt, sizeof(l_fmt), "%s%d%s", "%"DAP_UINT64_FORMAT_x".%", sizeof(CELL_FILE_EXT) - 1, "[^.].%c");
+
+        switch ( sscanf(a_filename, l_fmt, &l_cell_id.uint64, l_ext, &l_ext2) ) {
+        case 3:
+        case 2:
+            if ( !dap_strncmp(l_ext, CELL_FILE_EXT) )
+                break;
+        default:
+            return log_it(L_ERROR, "Invalid cell file name \"%s\"", a_filename), EINVAL;
+        }
+    }
+
+    const char file_storage_path[MAX_PATH], mode[] = { a_mode, '+', 'b', '\0' };
+    snprintf(file_storage_path, MAX_PATH, "%s/%s", DAP_CHAIN_PVT(a_chain)->file_storage_dir, a_filename);
+    dap_chain_cell_t *l_cell = NULL;
+
+#define m_ret_err(err, ...) return ({ if (l_cell->file_storage) fclose(l_cell->file_storage); \
+                                      DAP_DELETE(l_cell); log_it(L_ERROR, ##__VA_ARGS__), err })
+
+    dap_chain_cell_mmap_data_t l_cell_map_data = { };
+    HASH_FIND(hh, a_chain->cells, &l_cell_id, sizeof(dap_chain_cell_id_t), l_cell);
+    if (l_cell) {
+        if (a_mode == 'w') {
+            s_cell_close(l_cell);
+            HASH_DEL(a_chain->cells, l_cell);
+            DAP_DELETE(l_cell);
+        } else
+            m_ret_err(EEXIST, "Cell \"%s\" is already loaded in chain \"%s : %s\"",
+                              a_filename, a_chain->net_name, a_chain->name);
+    }
+    FILE *l_file = fopen(file_storage_path, mode);
+    if ( !l_file )
+        m_ret_err(errno, "Cell \"%s : %s / \"%s\" cannot be opened, error %d",
+                         a_chain->net_name, a_chain->name, a_filename, errno);
+
+    l_cell = DAP_NEW_Z(dap_chain_cell_t);
+    *l_cell = (dap_chain_cell_t) {
+        .id             = l_cell_id,
+        .chain          = a_chain,
+        .file_storage   = l_file,
+        .storage_rwlock = PTHREAD_RWLOCK_INITIALIZER
+    };
+    dap_strncpy(l_cell->file_storage_path, file_storage_path, MAX_PATH);
+
+    switch (a_mode) {
+    case 'a': {
+        int l_load_res = s_cell_load_from_file(l_cell);
+        if (!l_load_res)
+            break;
+        else if (l_load_res < 0)
+            m_ret_err(errno, "Cell \"%s : %s / \"%s\" cannot be loaded, code %d",
+                             a_chain->net_name, a_chain->name, a_filename, l_load_res);
+        // Otherwise, rewrite the file from scratch
+    }
+    case 'w': {
+        dap_chain_cell_file_header_t l_hdr = {
+            .signature      = DAP_CHAIN_CELL_FILE_SIGNATURE,
+            .version        = DAP_CHAIN_CELL_FILE_VERSION,
+            .type           = DAP_CHAIN_CELL_FILE_TYPE_RAW,
+            .chain_id       = a_chain->id,
+            .chain_net_id   = a_chain->net_id,
+            .cell_id        = l_cell_id
+        };
+        if ( !fwrite(&l_hdr, sizeof(l_hdr), 1, l_cell->file_storage) )
+            m_ret_err(errno, "fwrite() error %d", errno);
+        fflush(l_cell->file_storage);
+        l_cell->file_storage = freopen(file_storage_path, "a+b", l_cell->file_storage);
+        if ( a_chain->is_mapped && s_cell_map_new_volume(l_cell, 0, false) )
+            m_ret_err(EINVAL, "Error on mapping the first volume");
+    }
+    default:
+        break;
+    }
+    HASH_ADD(hh, a_chain->cells, id, sizeof(dap_chain_cell_id_t), l_cell);
+    log_it(L_INFO, "Cell storage \"%s\" is %s for chain \"%s : %s\"",
+                    a_filename, a_mode == 'w' ? "created" : "opened" a_chain->net_name, a_chain->name);
+    return 0;
+}
+
+int dap_chain_cell_open(dap_chain_t *a_chain, const char *a_filename, const char a_mode) {
+    pthread_rwlock_wrlock(&a_chain->cell_rwlock);
+    int l_ret = s_cell_open(a_chain, a_filename, a_mode);
+    pthread_rwlock_unlock(&a_chain->cell_rwlock);
+    return l_ret;
+#undef m_ret_err
+}
+
 static int s_cell_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a_atom, uint64_t a_atom_size)
 {
-    if (!a_atom || !a_atom_size) {
-        log_it(L_CRITICAL, "Invalid arguments");
-        return -1;
-    }
+    dap_return_val_if_fail(a_atom && a_atom_size, -1);
+
     if (a_cell->chain->is_mapped) {
         off_t l_pos = !fseeko(a_cell->file_storage, 0, SEEK_END) ? ftello(a_cell->file_storage) : -1;
-        if (l_pos < 0)
-            return log_it(L_ERROR, "Can't get chain size, error %d: \"%s\"", errno, dap_strerror(errno)), -1;
+        dap_return_val_if_pass_err(l_pos < 0, -1, "Can't get \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X" size, error %d",
+                                                     a_cell->chain->net_name, a_cell->chain->name, a_cell->id, errno);
         debug_if (s_debug_more, L_DEBUG, "Before filling volume for atom size %ld, stream pos of %s is %lu, map pos is %lu, space left in map %lu",
-                      a_atom_size, a_cell->file_storage_path, l_pos, (size_t)(a_cell->map_pos - a_cell->map), (size_t)(a_cell->map_end - a_cell->map_pos));
+                    a_atom_size, a_cell->file_storage_path, l_pos, (size_t)(a_cell->map_pos - a_cell->map), (size_t)(a_cell->map_end - a_cell->map_pos));
         if ( a_atom_size + sizeof(uint64_t) > (size_t)(a_cell->map_end - a_cell->map_pos) )
-            if ( s_cell_map_new_volume(a_cell, (size_t)l_pos, false) )
-                return -2;
+            dap_return_val_if_pass_err(
+                s_cell_map_new_volume(a_cell, (size_t)l_pos, false), 
+                -2, "Failed to create new map volume for \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
+                a_cell->chain->net_name, a_cell->chain->name, a_cell->id
+            );
     }
     
     debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG, "Before writing an atom of size %lu, stream pos of %s is %ld and pos is %lu, space left in map %lu", 
                                             a_atom_size, a_cell->file_storage_path, ftello(a_cell->file_storage),
                                             (size_t)(a_cell->map_pos - a_cell->map), (size_t)(a_cell->map_end - a_cell->map_pos));
+    dap_return_val_if_fail_err(
+        fwrite(&a_atom_size, sizeof(a_atom_size), 1, a_cell->file_storage) == 1 &&
+        fwrite(a_atom,       a_atom_size,         1, a_cell->file_storage) == 1,
+        -3, "Can't write atom (%zu b) to \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X", error %d: \"%s\"",
+            a_atom_size, a_cell->chain->net_name, a_cell->chain->name, a_cell->id, errno, dap_strerror(errno)
+    );
 
-    if (fwrite(&a_atom_size, sizeof(a_atom_size), 1, a_cell->file_storage) != 1) {
-        log_it (L_ERROR, "Can't write atom data size from cell 0x%016"DAP_UINT64_FORMAT_X" in \"%s\"",
-                a_cell->id.uint64,
-                a_cell->file_storage_path);
-        return -2;
-    }
-    if (fwrite(a_atom, a_atom_size, 1, a_cell->file_storage) != 1) {
-        log_it(L_ERROR, "Can't write atom (%zu b) to file \"%s\", err %d: \"%s\"",
-                        a_atom_size, a_cell->file_storage_path, errno, dap_strerror(errno) );
-        return -3;
-    }
     debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG, "After writing an atom of size %lu, stream pos of %s is %lu and map shift is %lu", 
                                             a_atom_size, a_cell->file_storage_path, ftello(a_cell->file_storage),
                                             (size_t)(a_cell->map_pos - a_cell->map));
@@ -570,7 +649,7 @@ static int s_cell_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a
                                             MAP_PRIVATE|MAP_FIXED, fileno(a_cell->file_storage), a_cell->cur_vol_start)) ) {
             log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be remapped, errno %d",
                             a_cell->file_storage_path, a_cell->id.uint64, errno);
-            return -1;
+            return -2;
         }
     }
 #endif
@@ -582,110 +661,100 @@ static int s_cell_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a
  * add atoms to selected chain
  * @param a_cell - cell object. Contains file path to cell storage data, for example - "0.dchaincell"
  * a_cell->chain contains 
- *  name - "zerochain"
- *  net_name - "kelvin-testnet"
- *  filepath - "C:\\Users\\Public\\Documents\\cellframe-node\\var\\lib\\network\\kelvin-testnet\\zerochain\\/0.dchaincell"
+ *  name
+ *  net_name
+ *  filepath
  * @param a_atom
  * @param a_atom_size
  * @return
  */
 ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom, size_t a_atom_size)
 {
-    if(!a_cell)
-        return -1;
-    if (!a_atom && !a_cell->chain) {
-        log_it(L_WARNING,"Chain not found for cell 0x%016"DAP_UINT64_FORMAT_X" ( %s )",
-                               a_cell->id.uint64, a_cell->file_storage_path);
-        return -1;
-    }
-    size_t l_total_res = 0, l_count = 0;
-    bool l_err = false;
+    dap_return_val_if_fail(a_cell, -1);
+    dap_return_val_if_pass_err(!a_atom && !a_cell->chain, -2, "Chain not found for cell 0x%016"DAP_UINT64_FORMAT_X" %s ",
+                                                              a_cell->id.uint64, a_cell->file_storage_path);
+    size_t l_size = 0, l_count = 0;
+    int l_err = -1;
     pthread_rwlock_wrlock(&a_cell->storage_rwlock);
-    if (!a_atom || !a_atom_size) {
+    if ( a_atom && a_atom_size ) {
+        //pthread_rwlock_wrlock(a_cell->chain->cell_rwlock);
+        debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG, "Before appending an atom of size %lu, stream pos of %s is %lu, map pos is %lu",
+                      a_atom_size, a_cell->file_storage_path, ftello(a_cell->file_storage),
+                      (size_t)(a_cell->map_pos - a_cell->map));
+        
+        if ( !s_cell_file_atom_add(a_cell, a_atom, a_atom_size) ) {
+            ++l_count;
+            l_size = a_atom_size + sizeof(uint64_t);
+            debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG,"After appending an atom of size %lu, stream pos of %s is %lu, map pos is %lu",
+                                                a_atom_size, a_cell->file_storage_path, ftello(a_cell->file_storage),
+                                                (size_t)(a_cell->map_end - a_cell->map_pos));
 #ifdef DAP_OS_WINDOWS
-        strcat(a_cell->file_storage_path, ".new");
+            if (a_cell->chain->is_mapped) {
+                off_t l_off = ftello(a_cell->file_storage);
+                LARGE_INTEGER SectionSize = (LARGE_INTEGER) { .QuadPart = l_off };
+                HANDLE hSection = (HANDLE)a_cell->map_range_bounds->data;
+                NTSTATUS err = pfnNtExtendSection(hSection, &SectionSize);
+                if ( !NT_SUCCESS(err) ) {
+                    log_it(L_ERROR, "NtExtendSection() failed, status %lx: \"%s\"",
+                                    err, dap_str_ntstatus(err) );
+                    l_err = -2;
+                }
+            }
 #endif
-        a_cell->file_storage = freopen(a_cell->file_storage_path, "w+b", a_cell->file_storage);
-        debug_if (s_debug_more,L_DEBUG, "Rewinding file %s", a_cell->file_storage_path);
+        }
+        //pthread_rwlock_unlock(a_cell->chain->cell_rwlock);
+    } else {
+        if (a_cell->chain->is_mapped) {
+            log_it(L_ERROR, "Unable to rewrite memory-mapped chain");
+            // TODO: do we actually need it besides zerochain reordering issue?
+            pthread_rwlock_unlock(&a_cell->storage_rwlock);
+            return -3;
+        }
+        const char *l_fname = dap_strdup_printf("%"DAP_UINT64_FORMAT_x "." CELL_FILE_EXT
+#ifdef DAP_OS_WINDOWS
+            ".new"
+#endif
+            , a_cell->id.uint64);
         bool was_mapped = a_cell->chain->is_mapped;
         a_cell->chain->is_mapped = false;
-        if ( s_cell_file_write_header(a_cell) < 0 ) {
-            log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X": can't fill header",
-                            a_cell->file_storage_path, a_cell->id.uint64);
-            a_cell->chain->is_mapped = was_mapped;
+        l_err = dap_chain_cell_open(a_cell->chain, l_fname, 'w');
+        DAP_DELETE(l_fname);
+        if (l_err) {
+            log_it(L_ERROR, "Can't open chain \"%s : %s\" cell, code %d", a_cell->chain->net_name, a_cell->chain->name, l_err);
             pthread_rwlock_unlock(&a_cell->storage_rwlock);
-            return -2;
+            return -3;
         }
-        l_total_res += sizeof(dap_chain_cell_file_header_t);
+        l_size += sizeof(dap_chain_cell_file_header_t);
         dap_chain_atom_iter_t *l_atom_iter = a_cell->chain->callback_atom_iter_create(a_cell->chain, a_cell->id, NULL);
         dap_chain_atom_ptr_t l_atom;
         uint64_t l_atom_size = 0;
+        //pthread_rwlock_wrlock(a_cell->chain->cell_rwlock);
         for (l_atom = a_cell->chain->callback_atom_iter_get(l_atom_iter, DAP_CHAIN_ITER_OP_FIRST, &l_atom_size);
-             l_atom && l_atom_size;
+             l_atom && l_atom_size && !( l_err = s_cell_file_atom_add(a_cell, l_atom, l_atom_size) );
              l_atom = a_cell->chain->callback_atom_iter_get(l_atom_iter, DAP_CHAIN_ITER_OP_NEXT, &l_atom_size))
         {
-            if ( s_cell_file_atom_add(a_cell, l_atom, l_atom_size) ) {
-                l_err = true;
-                break;
-            } else {
-                l_total_res += sizeof(uint64_t) + l_atom_size;
-                ++l_count;
-            }
+            l_size += sizeof(uint64_t) + l_atom_size;
+            ++l_count;
         }
-        a_cell->chain->is_mapped = was_mapped;
         a_cell->chain->callback_atom_iter_delete(l_atom_iter);
+        a_cell->chain->is_mapped = was_mapped;
         debug_if (s_debug_more && a_cell->chain->is_mapped,L_DEBUG, "After rewriting file %s, stream pos is %lu and map pos is %lu",
                       a_cell->file_storage_path, ftello(a_cell->file_storage),
                       (size_t)(a_cell->map_pos - a_cell->map));
-    } else {
-        debug_if (s_debug_more && a_cell->chain->is_mapped,L_DEBUG, "Before appending an atom of size %lu, stream pos of %s is %lu, map pos is %lu",
-                      a_atom_size, a_cell->file_storage_path, ftello(a_cell->file_storage),
-                      (size_t)(a_cell->map_pos - a_cell->map));
-        if ( s_cell_file_atom_add(a_cell, a_atom, a_atom_size) ) {
-            log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X": can't save atom!",
-                   a_cell->file_storage_path, a_cell->id.uint64);
-            pthread_rwlock_unlock(&a_cell->storage_rwlock);
-            return -4;
-        }
-        debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG,"After appending an atom of size %lu, stream pos of %s is %lu, map pos is %lu",
-                                                a_atom_size, a_cell->file_storage_path, ftello(a_cell->file_storage),
-                                                (size_t)(a_cell->map_end - a_cell->map_pos));
-        ++l_count;
-        l_total_res = a_atom_size + sizeof(uint64_t);
+        //pthread_rwlock_unlock(a_cell->chain->cell_rwlock);
     }
-    
-    if (l_total_res) {
+
+    if (l_size) {
 #ifndef DAP_OS_DARWIN
         fflush(a_cell->file_storage);
 #endif
-#ifdef DAP_OS_WINDOWS
-        if (a_cell->chain->is_mapped) {
-            off_t l_off = ftello(a_cell->file_storage);
-            if (l_off < 0) {
-                log_it(L_ERROR, "Can't get chain size!");
-                l_err = true;
-            } else {
-                LARGE_INTEGER SectionSize = (LARGE_INTEGER) { .QuadPart = l_off };
-                HANDLE hSection = (HANDLE)a_cell->map_range_bounds->data;
-                NTSTATUS err = pfnNtExtendSection(hSection, &SectionSize);
-                if ( !NT_SUCCESS(err) ) {
-                    log_it(L_ERROR, "NtExtendSection() failed, status %lx: \"%s\"",
-                                    err, dap_str_ntstatus(err) );
-                    l_err = true;
-                }
-            }
-        }
-#endif
-        log_it(L_DEBUG, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X": saved %zu atoms (%zu bytes)",
-               a_cell->file_storage_path, a_cell->id.uint64, l_count, l_total_res);
-        if (l_err) {
-            log_it(L_WARNING, "Not all data was saved due to writing error!");
-        }
+        log_it(L_DEBUG, "Saved %zu atom%s (%zu bytes) to chain \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
+               l_count, l_count > 1 ? "s" : "", l_size, a_cell->chain->net_name, a_cell->chain->name, a_cell->id.uint64);
+        debug_if(l_err, L_WARNING, "Not all data was saved due to writing error %d!", l_err);
     } else {
         log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X": nothing saved!",
                a_cell->file_storage_path, a_cell->id.uint64);
     }
     pthread_rwlock_unlock(&a_cell->storage_rwlock);
-    return l_total_res;
+    return l_size;
 }
-
diff --git a/modules/chain/dap_chain_cs.c b/modules/chain/dap_chain_cs.c
index 124f0af805..d2e296b577 100644
--- a/modules/chain/dap_chain_cs.c
+++ b/modules/chain/dap_chain_cs.c
@@ -95,8 +95,7 @@ int dap_chain_cs_load(dap_chain_t *a_chain, dap_config_t *a_chain_cfg)
 {
     dap_chain_cs_callbacks_item_t *l_item = NULL;
     HASH_FIND_STR(s_cs_callbacks, DAP_CHAIN_PVT(a_chain)->cs_name, l_item);
-    if (!l_item)
-        return log_it(L_ERROR, "Callbacks for cs %s not found!", DAP_CHAIN_PVT(a_chain)->cs_name), -1;
+    dap_return_val_if_fail_err(l_item, -1, "Callbacks for cs %s not found!", DAP_CHAIN_PVT(a_chain)->cs_name);
     return l_item->callbacks.callback_load
         ? l_item->callbacks.callback_load(a_chain, a_chain_cfg)
         : 0;
@@ -106,8 +105,7 @@ int dap_chain_cs_class_delete(dap_chain_t *a_chain)
 {
     dap_chain_cs_class_callbacks_item_t *l_item = NULL;
     HASH_FIND_STR(s_class_callbacks, DAP_CHAIN_PVT(a_chain)->cs_type, l_item);
-    if (!l_item)
-        return log_it(L_ERROR, "Callbacks for cs %s not found!", DAP_CHAIN_PVT(a_chain)->cs_name), -1;
+    dap_return_val_if_fail_err(l_item, -1, "Callbacks for cs %s not found!", DAP_CHAIN_PVT(a_chain)->cs_name);
     return l_item->callbacks.callback_delete
         ? l_item->callbacks.callback_delete(a_chain)
         : 0;
@@ -117,8 +115,7 @@ int dap_chain_cs_class_purge(dap_chain_t *a_chain)
 {
     dap_chain_cs_class_callbacks_item_t *l_item = NULL;
     HASH_FIND_STR(s_class_callbacks, DAP_CHAIN_PVT(a_chain)->cs_type, l_item);
-    if (!l_item)
-        return log_it(L_ERROR, "Callbacks for cs %s not found!", DAP_CHAIN_PVT(a_chain)->cs_name), -1;
+    dap_return_val_if_fail_err(l_item, -1, "Callbacks for cs %s not found!", DAP_CHAIN_PVT(a_chain)->cs_name);
     return l_item->callbacks.callback_purge
         ? l_item->callbacks.callback_purge(a_chain)
         : 0;
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index 467e1b01bb..5d26c66bb3 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -71,15 +71,16 @@ typedef struct dap_chain_datum_iter {
 } dap_chain_datum_iter_t;
 
 typedef enum dap_chain_atom_verify_res{
-    ATOM_ACCEPT = 0, ATOM_PASS, ATOM_REJECT, ATOM_MOVE_TO_THRESHOLD, ATOM_FORK
+    ATOM_ACCEPT = 0, ATOM_PASS, ATOM_REJECT, ATOM_MOVE_TO_THRESHOLD, ATOM_FORK, ATOM_CORRUPTED
 } dap_chain_atom_verify_res_t;
 
 static const char* const dap_chain_atom_verify_res_str[] = {
-    [ATOM_ACCEPT]   = "accepted",
-    [ATOM_PASS]     = "skipped",
-    [ATOM_REJECT]   = "rejected",
-    [ATOM_MOVE_TO_THRESHOLD] = "thresholded",
-    [ATOM_FORK] = "forked"
+    [ATOM_ACCEPT]           = "accepted",
+    [ATOM_PASS]             = "skipped",
+    [ATOM_REJECT]           = "rejected",
+    [ATOM_MOVE_TO_THRESHOLD]= "thresholded",
+    [ATOM_FORK]             = "forked",
+    [ATOM_CORRUPTED]        = "corrupted"
 };
 
 typedef enum dap_chain_iter_op {
diff --git a/modules/chain/include/dap_chain_cell.h b/modules/chain/include/dap_chain_cell.h
index db47d0150a..6ed59c9ca3 100644
--- a/modules/chain/include/dap_chain_cell.h
+++ b/modules/chain/include/dap_chain_cell.h
@@ -29,6 +29,11 @@
 #include "dap_chain.h"
 #include "dap_chain_common.h"
 
+typedef struct dap_chain_cell_mmap_data {
+    off_t vol_size;
+    char *map, *map_pos, **maps;
+} dap_chain_cell_mmap_data_t;
+
 typedef struct dap_chain_cell {
     dap_chain_cell_id_t id;
     dap_chain_t * chain;
@@ -76,14 +81,23 @@ typedef struct dap_chain_cell_decl{
 
 
 int dap_chain_cell_init(void);
-dap_chain_cell_t *dap_chain_cell_create_fill(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id);
-dap_chain_cell_t *dap_chain_cell_find_by_id(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id);
-void dap_chain_cell_close(dap_chain_cell_t *a_cell);
-void dap_chain_cell_delete(dap_chain_cell_t *a_cell);
-void dap_chain_cell_delete_all_and_free_file(dap_chain_t *a_chain);
-void dap_chain_cell_delete_all(dap_chain_t *a_chain);
-int dap_chain_cell_load(dap_chain_t *a_chain, dap_chain_cell_t *a_cell);
-ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell,const void *a_atom, size_t a_atom_size);
-DAP_STATIC_INLINE ssize_t dap_chain_cell_file_update(dap_chain_cell_t *a_cell) {
-    return dap_chain_cell_file_append(a_cell, NULL, 0);
+int dap_chain_cell_open(dap_chain_t *a_chain, const char *a_filename, const char a_mode);
+
+DAP_INLINE dap_chain_cell_t *dap_chain_cell_find_by_id(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id) {
+    dap_chain_cell_t *l_cell = NULL;
+    HASH_FIND(hh, a_chain->cells, &a_cell_id, sizeof(dap_chain_cell_id_t), l_cell);
+    return l_cell;
+}
+DAP_INLINE dap_chain_cell_t *dap_chain_cell_capture_by_id(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id) {
+    pthread_rwlock_rdlock(&a_chain->cell_rwlock);
+    return dap_chain_cell_find_by_id(a_chain, a_cell_id);
 }
+DAP_INLINE void dap_chain_cell_remit(const dap_chain_cell_t *a_cell) {
+    pthread_rwlock_unlock(&a_cell->chain->cell_rwlock);
+}
+
+void dap_chain_cell_close(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id);
+void dap_chain_cell_close_all(dap_chain_t *a_chain);
+ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom, size_t a_atom_size);
+#define dap_chain_cell_file_update(a_cell) dap_chain_cell_file_append(a_cell, NULL, 0);
+
diff --git a/modules/chain/include/dap_chain_common.h b/modules/chain/include/dap_chain_common.h
index 5de3ac83a0..74706f6d1b 100644
--- a/modules/chain/include/dap_chain_common.h
+++ b/modules/chain/include/dap_chain_common.h
@@ -80,14 +80,14 @@ typedef union dap_chain_node_role{
 DAP_STATIC_INLINE const char *dap_chain_node_role_to_str(dap_chain_node_role_t a_node_role)
 {
     switch (a_node_role.enums) {
-        case NODE_ROLE_ROOT_MASTER: return "NODE_ROLE_ROOT_MASTER";
-        case NODE_ROLE_ROOT: return "NODE_ROLE_ROOT";
-        case NODE_ROLE_ARCHIVE: return "NODE_ROLE_ARCHIVE";
-        case NODE_ROLE_CELL_MASTER: return "NODE_ROLE_CELL_MASTER";
-        case NODE_ROLE_MASTER: return "NODE_ROLE_MASTER";
-        case NODE_ROLE_FULL: return "NODE_ROLE_FULL";
-        case NODE_ROLE_LIGHT: return "NODE_ROLE_LIGHT";
-        default: return "UNDEFINED";
+        case NODE_ROLE_ROOT_MASTER: return "root master";
+        case NODE_ROLE_ROOT: return "root";
+        case NODE_ROLE_ARCHIVE: return "archive";
+        case NODE_ROLE_CELL_MASTER: return "cell master";
+        case NODE_ROLE_MASTER: return "master";
+        case NODE_ROLE_FULL: return "full";
+        case NODE_ROLE_LIGHT: return "liht";
+        default: return "none";
     }
 }
 
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 a5e6e8cf31..68677baf8d 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -687,35 +687,33 @@ static int s_callback_created(dap_chain_t * a_chain, dap_config_t *a_chain_net_c
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG ( a_chain );
     dap_chain_cs_dag_poa_t * l_poa = DAP_CHAIN_CS_DAG_POA( l_dag );
 
-    const char * l_events_sign_cert = NULL;
-    if ( ( l_events_sign_cert = dap_config_get_item_str(a_chain_net_cfg,"dag-poa","events-sign-cert") ) != NULL ) {
-        if ( ( PVT(l_poa)->events_sign_cert = dap_cert_find_by_name(l_events_sign_cert)) == NULL ){
-            log_it(L_ERROR,"Can't load events sign certificate, name \"%s\" is wrong",l_events_sign_cert);
-        }else
-            log_it(L_NOTICE,"Loaded \"%s\" certificate to sign poa event", l_events_sign_cert);
-
+    const char *l_events_sign_cert = = dap_config_get_item_str(a_chain_net_cfg,"dag-poa","events-sign-cert");
+    if ( l_events_sign_cert ) {
+        if (!( PVT(l_poa)->events_sign_cert = dap_cert_find_by_name(l_events_sign_cert) ))
+            log_it(L_ERROR,"Can't load events sign certificate, name \"%s\" is wrong", l_events_sign_cert);
+        else
+            log_it(L_NOTICE, "Loaded \"%s\" certificate to sign poa events", l_events_sign_cert);
     }
+
     dap_chain_net_t *l_net = dap_chain_net_by_name(a_chain->net_name);
     assert(l_net);
     dap_global_db_cluster_t *l_dag_cluster = dap_global_db_cluster_add(dap_global_db_instance_get_default(), NULL,
                                                                        dap_guuid_compose(l_net->pub.id.uint64, DAP_CHAIN_CLUSTER_ID_DAG),
                                                                        l_dag->gdb_group_events_round_new, DAG_ROUND_NEW_TTL, true,
                                                                        DAP_GDB_MEMBER_ROLE_NOBODY, DAP_CLUSTER_TYPE_AUTONOMIC);
-    if (!l_dag_cluster) {
-        log_it(L_ERROR, "Can't create cluster for consensus communication. Can't start the DAG consensus");
-        return -1;
-    }
+    dap_return_val_if_fail_err(l_dag_cluster, -1, "Can't create cluster for consensus communication. Can't start the DAG consensus");
+
     dap_global_db_cluster_add_notify_callback(l_dag_cluster, s_round_changes_notify, l_dag);
     dap_chain_net_add_auth_nodes_to_cluster(l_net, l_dag_cluster);
     dap_link_manager_add_net_associate(l_net->pub.id.uint64, l_dag_cluster->links_cluster);
     PVT(l_poa)->mempool_timer = dap_interval_timer_create(15000, s_timer_process_callback, a_chain);
 
     switch ( dap_chain_net_get_role(l_net).enums ) {
-        case NODE_ROLE_ROOT_MASTER:
-        case NODE_ROLE_ROOT:
-            dap_global_db_get_all(l_dag->gdb_group_events_round_new, 0, s_callback_sync_all_on_start, l_dag);
-        default:
-            break;
+    case NODE_ROLE_ROOT_MASTER:
+    case NODE_ROLE_ROOT:
+        dap_global_db_get_all(l_dag->gdb_group_events_round_new, 0, s_callback_sync_all_on_start, l_dag);
+    default:
+        break;
     }
     return 0;
 }
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 93d253d1e5..7406a88203 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -1839,7 +1839,8 @@ static int s_chains_init_all(dap_chain_net_t *a_net, const char *a_path, int *a_
     dap_config_t *l_chain_config, *l_all_chain_configs = NULL, *l_tmp_cfg;
     char l_chain_cfg_path[MAX_PATH + 1] = { '\0' };
     int l_pos = snprintf(l_chain_cfg_path, MAX_PATH, "network/%s/", a_net->pub.name);
-    for ( struct dirent *l_dir_entry; ( l_dir_entry = readdir(l_chains_dir) ); ) {
+    struct dirent *l_dir_entry = NULL;
+    while (( l_dir_entry = readdir(l_chains_dir) )) {
         unsigned short l_len = strlen(l_dir_entry->d_name);
         if ( l_len > 4 && !dap_strncmp(l_dir_entry->d_name + l_len - 4, ".cfg", 4) ) {
             *(l_dir_entry->d_name + l_len - 4) = '\0';
@@ -1978,11 +1979,10 @@ int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx)
             char *l_service_cfg_path = dap_strdup_printf("network/%s/services/%s", l_net->pub.name, l_entry_name);
             dap_config_t *l_cfg_new = dap_config_open(l_service_cfg_path);
             if (l_cfg_new) {
-                char *l_service_name = DAP_DUP_SIZE((char *)l_entry_name, l_entry_len - 3);
-                l_service_name[l_entry_len - 4] = 0;
+                char l_service_name[l_entry_len - 3];
+                dap_strncpy(l_service_name, l_entry_name, l_entry_len - 4);
                 dap_chain_srv_start(l_net->pub.id, l_service_name, l_cfg_new);
                 dap_config_close(l_cfg_new);
-                DAP_DELETE(l_service_name);
             }
             DAP_DELETE(l_service_cfg_path);
         }
@@ -2015,24 +2015,16 @@ int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx)
 static void *s_net_load(void *a_arg)
 {
     dap_chain_net_t *l_net = a_arg;
-    int l_err_code = 0;
-
-    if (!l_net->pub.config) {
-        log_it(L_ERROR,"Can't open default network config");
-        l_err_code = -1;
-        goto ret;
-    }
+    dap_return_val_if_fail_err(l_net->pub.config, NULL, "Can't open network %s config", l_net->pub.name);
 
     dap_chain_net_pvt_t *l_net_pvt = PVT(l_net);
-    //else dap_chain_net_srv_stake_load_cache(l_net); // TODO rework ledger and staking caches
-    // load chains
-    dap_chain_t *l_chain = l_net->pub.chains;
-    clock_t l_chain_load_start_time = clock(); 
-    while (l_chain) {
+    l_net_pvt->balancer_type = dap_config_get_item_bool_default(l_net->pub.config, "general", "use_dns_links", false);
+    char l_gdb_groups_mask[DAP_GLOBAL_DB_GROUP_NAME_SIZE_MAX];
+    dap_chain_t *l_chain;
+    DL_FOREACH(l_net->pub.chains, l_chain) {
         l_net->pub.fee_value = uint256_0;
         l_net->pub.fee_addr = c_dap_chain_addr_blank;
-        if (!dap_chain_load_all(l_chain)) {
-            log_it (L_NOTICE, "Loaded chain files");
+        if ( !dap_chain_load_all(l_chain) ) {
             if ( DAP_CHAIN_PVT(l_chain)->need_reorder ) // # unsafe crutch, need to escape reorder usage
             {
                 log_it(L_DAP, "Reordering chain files for chain %s", l_chain->name);
@@ -2053,117 +2045,76 @@ static void *s_net_load(void *a_arg)
                 while (l_chain->callback_atom_add_from_treshold(l_chain, NULL))
                     log_it(L_DEBUG, "Added atom from treshold");
             }
-        } else {
-            //dap_chain_save_all( l_chain );
-            log_it (L_NOTICE, "Initialized chain files");
         }
         l_chain->atom_num_last = 0;
-        time_t l_chain_load_time_taken = clock() - l_chain_load_start_time; 
-        double time_taken = ((double)l_chain_load_time_taken)/CLOCKS_PER_SEC; // in seconds 
-        log_it(L_NOTICE, "[%s] Chain [%s] processing took %f seconds", l_chain->net_name, l_chain->name, time_taken);
-        l_chain = l_chain->next;
-    }
-    dap_ledger_load_end(l_net->pub.ledger);
-
-    // Do specific role actions post-chain created
-    l_net_pvt->state_target = NET_STATE_OFFLINE;
-    switch ( l_net_pvt->node_role.enums ) {
-        case NODE_ROLE_ROOT_MASTER:{
-            // Set to process everything in datum pool
-            dap_chain_t * l_chain = NULL;
-            DL_FOREACH(l_net->pub.chains, l_chain)
-                l_chain->is_datum_pool_proc = true;
-            log_it(L_INFO,"Root master node role established");
-        } // Master root includes root
-        case NODE_ROLE_ROOT:{
-            // Set to process only zerochain
-            dap_chain_id_t l_chain_id = {{0}};
-            dap_chain_t *l_chain = dap_chain_find_by_id(l_net->pub.id, l_chain_id);
-            if (l_chain)
-                l_chain->is_datum_pool_proc = true;
-            log_it(L_INFO,"Root node role established");
-        } break;
+        switch ( l_net_pvt->node_role.enums ) {
+        case NODE_ROLE_ROOT_MASTER:
+        /* Processes everything in mempool*/
+            l_chain->is_datum_pool_proc = true;
+            break;
+        case NODE_ROLE_ROOT:
+        /* Processes zerochain only */
+            l_chain->is_datum_pool_proc = !l_chain->id.uint64;
+            break;
         case NODE_ROLE_CELL_MASTER:
-        case NODE_ROLE_MASTER:{
-            uint16_t l_proc_chains_count=0;
-            const char **l_proc_chains = dap_config_get_array_str(l_net->pub.config, "role-master", "proc_chains", &l_proc_chains_count);
-            for (size_t i = 0; i< l_proc_chains_count ; i++) {
-                dap_chain_id_t l_chain_id = {};
-                if (dap_chain_id_parse(l_proc_chains[i], &l_chain_id) == 0) {
-                    dap_chain_t *l_chain = dap_chain_find_by_id(l_net->pub.id, l_chain_id );
-                    if (l_chain)
-                        l_chain->is_datum_pool_proc = true;
-                    else
-                        log_it(L_WARNING, "Can't find chain id 0x%016" DAP_UINT64_FORMAT_X, l_chain_id.uint64);
-                }
-            }
-            log_it(L_INFO,"Master node role established");
-        } break;
-        case NODE_ROLE_FULL:{
-            log_it(L_INFO,"Full node role established");
+        case NODE_ROLE_MASTER: {
+        /* Processes specified chains only */
+            uint16_t k = 0;
+            dap_chain_id_t l_chain_id;
+            const char **l_proc_chains = dap_config_get_array_str(l_net->pub.config, "role-master", "proc_chains", &k);
+            while (k--)
+                l_chain->is_datum_pool_proc = ( !dap_chain_id_parse(l_proc_chains[k], &l_chain_id) && (l_chain->id.uint64 == l_chain_id.uint64) );
         } break;
-        case NODE_ROLE_LIGHT:
-        default:
-            log_it(L_INFO,"Light node role established");
-
-    }
-
-    l_net_pvt->balancer_type = dap_config_get_item_bool_default(l_net->pub.config, "general", "use_dns_links", false);
+        default: break;
 
-    // Init GlobalDB clusters for mempool, service and nodes (with aliases)
-    char *l_gdb_groups_mask = NULL;
-    DL_FOREACH(l_net->pub.chains, l_chain) {
         // Personal chain mempool cluster for each chain
-        l_gdb_groups_mask = dap_strdup_printf("%s.chain-%s.mempool", l_net->pub.gdb_groups_prefix, l_chain->name);
+        snprintf(l_gdb_groups_mask, sizeof(l_gdb_groups_mask), "%s.chain-%s.mempool",
+                                                               l_net->pub.gdb_groups_prefix, l_chain->name);
         dap_global_db_cluster_t *l_cluster = dap_global_db_cluster_add(
                                                 dap_global_db_instance_get_default(), l_net->pub.name,
                                                 dap_guuid_compose(l_net->pub.id.uint64, 0), l_gdb_groups_mask,
                                                 dap_config_get_item_int32_default(l_net->pub.config, "global_db", "mempool_ttl", DAP_CHAIN_NET_MEMPOOL_TTL),
                                                 true, DAP_GDB_MEMBER_ROLE_USER, DAP_CLUSTER_TYPE_EMBEDDED);
-        if (!l_cluster) {
-            log_it(L_ERROR, "Can't initialize mempool cluster for network %s", l_net->pub.name);
-            l_err_code = -2;
-            goto ret;
-        }
+        dap_return_val_if_fail_err(l_cluster, NULL, "Net \"%s\" loading error %d: can't initialize mempool cluster",
+                                                    l_net->pub.name, -2);
         dap_chain_net_add_auth_nodes_to_cluster(l_net, l_cluster);
-        DAP_DELETE(l_gdb_groups_mask);
         if (l_net->pub.chains == l_chain)   // Pointer for first mempool cluster in global double-linked list of clusters
             l_net_pvt->mempool_clusters = l_cluster;
     }
+    dap_ledger_load_end(l_net->pub.ledger);
+    log_it(L_INFO, "Node role \"%s\" established in net %s", dap_chain_node_role_to_str(l_net_pvt->node_role.enums), l_net->pub.name);
+    l_net_pvt->state_target = NET_STATE_OFFLINE;
+
+    // Init GlobalDB clusters for service and nodes (with aliases)
     // Service orders cluster
-    l_gdb_groups_mask = dap_strdup_printf("%s.service.orders", l_net->pub.gdb_groups_prefix);
+    snprintf(l_gdb_groups_mask, sizeof(l_gdb_groups_mask), "%s.service.orders", l_net->pub.gdb_groups_prefix);
     l_net_pvt->orders_cluster = dap_global_db_cluster_add(dap_global_db_instance_get_default(),
                                                           l_net->pub.name, dap_guuid_compose(l_net->pub.id.uint64, 0),
                                                           l_gdb_groups_mask, 0, true,
                                                           DAP_GDB_MEMBER_ROLE_GUEST,
                                                           DAP_CLUSTER_TYPE_EMBEDDED);
-    if (!l_net_pvt->orders_cluster) {
-        log_it(L_ERROR, "Can't initialize orders cluster for network %s", l_net->pub.name);
-        goto ret;
-    }
+    dap_return_val_if_fail_err(l_net_pvt->orders_cluster, NULL, "Net \"%s\" loading error %d: can't initialize orders cluster",
+                                                                l_net->pub.name, -3);
     dap_chain_net_add_auth_nodes_to_cluster(l_net, l_net_pvt->orders_cluster);
-    DAP_DELETE(l_gdb_groups_mask);
     // Common orders cluster
-    l_gdb_groups_mask = dap_strdup_printf("%s.orders", l_net->pub.gdb_groups_prefix);
+    snprintf(l_gdb_groups_mask, sizeof(l_gdb_groups_mask), "%s.orders", l_net->pub.gdb_groups_prefix);
     l_net_pvt->common_orders = dap_global_db_cluster_add(dap_global_db_instance_get_default(),
                                                           l_net->pub.name, dap_guuid_compose(l_net->pub.id.uint64, 0),
                                                           l_gdb_groups_mask, 0, true,
                                                           DAP_GDB_MEMBER_ROLE_USER,
                                                           DAP_CLUSTER_TYPE_EMBEDDED);
-    if (!l_net_pvt->common_orders) {
-        log_it(L_ERROR, "Can't initialize orders cluster for network %s", l_net->pub.name);
-        goto ret;
-    }
+    dap_return_val_if_fail_err(l_net_pvt->common_orders, NULL, "Net \"%s\" loading error %d: can't initialize common orders cluster"
+                                                               l_net->pub.name, -4);
     dap_chain_net_add_auth_nodes_to_cluster(l_net, l_net_pvt->common_orders);
-    DAP_DELETE(l_gdb_groups_mask);
     // Node states cluster
-    l_gdb_groups_mask = dap_strdup_printf("%s.nodes.states", l_net->pub.gdb_groups_prefix);
+    snprintf(l_gdb_groups_mask, sizeof(l_gdb_groups_mask), "%s.nodes.states", l_net->pub.gdb_groups_prefix);
     l_net_pvt->nodes_states = dap_global_db_cluster_add(dap_global_db_instance_get_default(),
                                                         l_net->pub.name, dap_guuid_compose(l_net->pub.id.uint64, 0),
                                                         l_gdb_groups_mask, DAP_CHAIN_NET_NODES_TTL, true,
                                                         DAP_GDB_MEMBER_ROLE_USER,
                                                         DAP_CLUSTER_TYPE_EMBEDDED);
-    DAP_DELETE(l_gdb_groups_mask);
+    dap_return_val_if_fail_err(l_net_pvt->nodes_states, NULL, "Net \"%s\" loading error %d: can't initialize node states cluster"
+                                                               l_net->pub.name, -5);
     // Nodes and its aliases cluster
     snprintf(l_net->pub.gdb_nodes, sizeof(l_net->pub.gdb_nodes), "%s.%s", l_net->pub.gdb_groups_prefix, s_gdb_nodes_postfix);
     l_net_pvt->nodes_cluster = dap_global_db_cluster_add(dap_global_db_instance_get_default(),
@@ -2171,19 +2122,14 @@ static void *s_net_load(void *a_arg)
                                                          l_net->pub.gdb_nodes, 7200, true,
                                                          DAP_GDB_MEMBER_ROLE_GUEST,
                                                          DAP_CLUSTER_TYPE_EMBEDDED);
-    if (!l_net_pvt->nodes_cluster) {
-        log_it(L_ERROR, "Can't initialize nodes cluster for network %s", l_net->pub.name);
-        l_err_code = -3;
-        goto ret;
-    }
+    dap_return_val_if_fail_err(l_net_pvt->nodes_cluster, NULL, "Net \"%s\" loading error %d: can't initialize nodes cluster"
+                                                               l_net->pub.name, -6);
     dap_chain_net_add_auth_nodes_to_cluster(l_net, l_net_pvt->nodes_cluster);
     dap_chain_net_add_nodelist_notify_callback(l_net, s_nodelist_change_notify, l_net);
 
-    if (dap_link_manager_add_net(l_net->pub.id.uint64, l_net_pvt->nodes_cluster->links_cluster,
-                                dap_config_get_item_uint16_default(l_net->pub.config,
-                                                                   "general", "links_required", 3))) {
+    if ( dap_link_manager_add_net(l_net->pub.id.uint64, l_net_pvt->nodes_cluster->links_cluster,
+                                  dap_config_get_item_uint16_default(l_net->pub.config, "general", "links_required", 3)) )
         log_it(L_WARNING, "Can't add net %s to link manager", l_net->pub.name);
-    }
 
     DL_FOREACH(l_net->pub.chains, l_chain)
         dap_chain_cs_load(l_chain, l_net->pub.config);
@@ -2215,12 +2161,9 @@ static void *s_net_load(void *a_arg)
     l_net_pvt->sync_context.sync_idle_time = dap_config_get_item_uint32_default(g_config, "chain", "sync_idle_time", 60);
     dap_proc_thread_timer_add(NULL, s_sync_timer_callback, l_net, c_sync_timer_period);
 
-    log_it(L_INFO, "Chain network \"%s\" initialized", l_net->pub.name);
+    log_it(L_INFO, "Network \"%s\" initialized", l_net->pub.name);
     l_net_pvt->state = NET_STATE_OFFLINE;
-ret:
-    if (l_err_code)
-        log_it(L_ERROR, "Loading chains of net %s finished with (%d) error code.", l_net->pub.name, l_err_code);
-    return NULL;
+    return l_net;
 }
 
 dap_global_db_cluster_t *dap_chain_net_get_mempool_cluster(dap_chain_t *a_chain)
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 19609ca5cb..8c67acdacd 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -279,11 +279,7 @@ void dap_chain_cs_blocks_deinit()
 
 static int s_chain_cs_blocks_new(dap_chain_t *a_chain, dap_config_t *a_chain_config)
 {
-    dap_chain_cs_blocks_t * l_cs_blocks = DAP_NEW_Z(dap_chain_cs_blocks_t);
-    if (!l_cs_blocks) {
-        log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-        return -1;
-    }
+    dap_chain_cs_blocks_t * l_cs_blocks = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_cs_blocks_t, -1);
     a_chain->_inheritor = l_cs_blocks;
     l_cs_blocks->chain = a_chain;
 
@@ -1506,7 +1502,7 @@ static int s_callback_cs_blocks_purge(dap_chain_t *a_chain)
         l_datum_index = NULL;
     }
     pthread_rwlock_unlock(&PVT(l_blocks)->datums_rwlock);
-    dap_chain_cell_delete_all(a_chain);
+    dap_chain_cell_close_all(a_chain);
     return 0;
 }
 
@@ -1564,8 +1560,9 @@ static int s_add_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_ca
             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);
-            dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_blocks->chain, a_blocks->chain->active_cell_id);
+            dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_blocks->chain, a_blocks->chain->active_cell_id);
             dap_chain_datum_notify(l_cell, l_datum_hash, &l_datum_index->block_cache->block_hash, (byte_t *)l_datum, l_datum_size, l_res, l_datum_index_data.action, l_datum_index_data.uid);
+            dap_chain_cell_remit(l_cell);
         }
     }
     debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str,
@@ -1598,8 +1595,9 @@ static int s_delete_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block
             l_ret++;
             HASH_DEL(PVT(a_blocks)->datum_index, l_datum_index);
             // notify datum removed
-            dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_blocks->chain, a_blocks->chain->active_cell_id);
+            dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_blocks->chain, a_blocks->chain->active_cell_id);
             dap_chain_datum_removed_notify(l_cell, l_datum_hash);
+            dap_chain_cell_remit(l_cell);
         }
     }
     debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str,
@@ -1720,7 +1718,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
     case ATOM_ACCEPT:{
         dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
         assert(l_net);
-        dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_chain, l_block->hdr.cell_id);
+        dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_chain, l_block->hdr.cell_id);
 #ifndef DAP_CHAIN_BLOCKS_TEST
         if ( !dap_chain_net_get_load_mode(l_net) ) {
             if ( (ret = dap_chain_atom_save(l_cell, a_atom, a_atom_size, a_atom_new ? &l_block_hash : NULL)) < 0 ) {
@@ -1843,9 +1841,9 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
         debug_if(s_debug_more, L_DEBUG, "Verified atom %p with hash %s: REJECTED", a_atom, dap_chain_hash_fast_to_str_static(&l_block_hash));
         break;
     case ATOM_FORK:{
-        dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_chain, l_block->hdr.cell_id);
 #ifndef DAP_CHAIN_BLOCKS_TEST
         if ( !dap_chain_net_get_load_mode( dap_chain_net_by_id(a_chain->net_id)) ) {
+            dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_chain, l_block->hdr.cell_id);
             if ( (ret = dap_chain_atom_save(l_cell, a_atom, a_atom_size, a_atom_new ? &l_block_hash : NULL)) < 0 ) {
                 log_it(L_ERROR, "Can't save atom to file, code %d", ret);
                 return ATOM_REJECT;
@@ -1853,6 +1851,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
                 l_block = (dap_chain_block_t*)( l_cell->map_pos += sizeof(uint64_t) );  // Switching to mapped area
                 l_cell->map_pos += a_atom_size;
             }
+            dap_chain_cell_remit(l_cell);
             ret = ATOM_FORK;
         }
 #endif
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index bef0bb74de..431f3f0b90 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -372,7 +372,7 @@ static int s_chain_cs_dag_purge(dap_chain_t *a_chain)
         DAP_DELETE(l_event_current);
     }
     pthread_mutex_unlock(&l_dag_pvt->events_mutex);
-    dap_chain_cell_delete_all(a_chain);
+    dap_chain_cell_close_all(a_chain);
     return 0;
 }
 
-- 
GitLab


From 83bc572bd90e5ed0e706184ef075554cfa105206 Mon Sep 17 00:00:00 2001
From: "P. Constantin" <papizh.konstantin@demlabs.net>
Date: Thu, 6 Feb 2025 21:45:46 +0700
Subject: [PATCH 05/11] ...

---
 dap-sdk                                |   2 +-
 modules/chain/dap_chain.c              |  49 +++++-----
 modules/chain/dap_chain_cell.c         | 130 +++++++------------------
 modules/chain/include/dap_chain.h      |   8 +-
 modules/chain/include/dap_chain_cell.h |   3 +-
 5 files changed, 65 insertions(+), 127 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index b6ead51e41..e4ffa996e2 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit b6ead51e413671d2416f98796b8ac7d397e2e0ed
+Subproject commit e4ffa996e2df6a6f454ba8110bc49b8f1c533741
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 4084a05703..6070d8e8c6 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -821,17 +821,16 @@ static bool s_notify_datum_removed_on_thread(void *a_arg)
     return false;
 }
 
-ssize_t dap_chain_atom_save(dap_chain_cell_t *a_chain_cell, const uint8_t *a_atom, size_t a_atom_size, dap_hash_fast_t *a_new_atom_hash)
+ssize_t dap_chain_atom_save(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id,
+                            const uint8_t *a_atom, size_t a_atom_size,
+                            dap_hash_fast_t *a_new_atom_hash, char **a_atom_map)
 {
-    dap_return_val_if_fail(a_chain_cell && a_chain_cell->chain, -1);
-    dap_chain_t *l_chain = a_chain_cell->chain;
-
     if (a_new_atom_hash) { // Atom is new and need to be distributed for the net
-        dap_cluster_t *l_net_cluster = dap_cluster_find(dap_guuid_compose(l_chain->net_id.uint64, 0));
+        dap_cluster_t *l_net_cluster = dap_cluster_find(dap_guuid_compose(a_chain->net_id.uint64, 0));
         if (l_net_cluster) {
             size_t l_pkt_size = a_atom_size + sizeof(dap_chain_ch_pkt_t);
-            dap_chain_ch_pkt_t *l_pkt = dap_chain_ch_pkt_new(l_chain->net_id, l_chain->id,
-                                                             a_chain_cell->id, a_atom, a_atom_size,
+            dap_chain_ch_pkt_t *l_pkt = dap_chain_ch_pkt_new(a_chain->net_id, a_chain->id,
+                                                             a_cell_id, a_atom, a_atom_size,
                                                              DAP_CHAIN_CH_PKT_VERSION_CURRENT);
             if (l_pkt) {
                 dap_gossip_msg_issue(l_net_cluster, DAP_CHAIN_CH_ID, l_pkt, l_pkt_size, a_new_atom_hash);
@@ -839,7 +838,7 @@ ssize_t dap_chain_atom_save(dap_chain_cell_t *a_chain_cell, const uint8_t *a_ato
             }
         }
     }
-    return dap_chain_cell_file_append(a_chain_cell, a_atom, a_atom_size);
+    return dap_chain_cell_file_append(a_chain, a_cell_id, a_atom, a_atom_size, a_atom_map);
 }
 
 /**
@@ -882,47 +881,43 @@ const char* dap_chain_get_path(dap_chain_t *a_chain)
     return DAP_CHAIN_PVT(a_chain)->file_storage_dir;
 }
 
-void dap_chain_atom_notify(dap_chain_cell_t *a_chain_cell, dap_hash_fast_t *a_hash, const uint8_t *a_atom, size_t a_atom_size) {
+void dap_chain_atom_notify(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_hash, const uint8_t *a_atom, size_t a_atom_size) {
 #ifdef DAP_CHAIN_BLOCKS_TEST
     return;
 #endif
 
-    if ( !a_chain_cell->chain->atom_notifiers )
+    if ( !a_chain->atom_notifiers )
         return;
     dap_list_t *l_iter;
-    DL_FOREACH(a_chain_cell->chain->atom_notifiers, l_iter) {
+    DL_FOREACH(a_chain->atom_notifiers, l_iter) {
         dap_chain_atom_notifier_t *l_notifier = (dap_chain_atom_notifier_t*)l_iter->data;
-        struct chain_thread_notifier *l_arg = DAP_NEW_Z(struct chain_thread_notifier);
-        if (!l_arg) {
-            log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-            continue;
-        }
+        struct chain_thread_notifier *l_arg = DAP_NEW_Z_RET_IF_FAIL(struct chain_thread_notifier);
         *l_arg = (struct chain_thread_notifier) {
             .callback = l_notifier->callback, .callback_arg = l_notifier->arg,
-            .chain = a_chain_cell->chain,     .cell_id = a_chain_cell->id,
+            .chain = a_chain,     .cell_id = a_cell_id,
             .hash = *a_hash,
-            .atom = a_chain_cell->chain->is_mapped ? (byte_t*)a_atom : DAP_DUP_SIZE((byte_t*)a_atom, a_atom_size),
+            .atom = a_chain->is_mapped ? (byte_t*)a_atom : DAP_DUP_SIZE((byte_t*)a_atom, a_atom_size),
             .atom_size = a_atom_size };
         dap_proc_thread_callback_add_pri(l_notifier->proc_thread, s_notify_atom_on_thread, l_arg, DAP_QUEUE_MSG_PRIORITY_LOW);
     }
 }
 
-void dap_chain_datum_notify(dap_chain_cell_t *a_chain_cell,  dap_hash_fast_t *a_hash, dap_hash_fast_t *a_atom_hash, const uint8_t *a_datum, size_t a_datum_size, int a_ret_code, uint32_t a_action, dap_chain_srv_uid_t a_uid) {
+void dap_chain_datum_notify(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_hash, dap_hash_fast_t *a_atom_hash, const uint8_t *a_datum, size_t a_datum_size, int a_ret_code, uint32_t a_action, dap_chain_srv_uid_t a_uid) {
 #ifdef DAP_CHAIN_BLOCKS_TEST
     return;
 #endif
 
-    if ( !a_chain_cell->chain->datum_notifiers )
+    if ( !a_chain->datum_notifiers )
         return;
     dap_list_t *l_iter;
-    DL_FOREACH(a_chain_cell->chain->datum_notifiers, l_iter) {
+    DL_FOREACH(a_chain->datum_notifiers, l_iter) {
         dap_chain_datum_notifier_t *l_notifier = (dap_chain_datum_notifier_t*)l_iter->data;
         struct chain_thread_datum_notifier *l_arg = DAP_NEW_Z_RET_IF_FAIL(struct chain_thread_datum_notifier);
         *l_arg = (struct chain_thread_datum_notifier) {
             .callback = l_notifier->callback, .callback_arg = l_notifier->arg,
-            .chain = a_chain_cell->chain,     .cell_id = a_chain_cell->id,
+            .chain = a_chain,     .cell_id = a_cell_id,
             .hash = *a_hash,
-            .datum = a_chain_cell->chain->is_mapped ? (byte_t*)a_datum : DAP_DUP_SIZE((byte_t*)a_datum, a_datum_size),
+            .datum = a_chain->is_mapped ? (byte_t*)a_datum : DAP_DUP_SIZE((byte_t*)a_datum, a_datum_size),
             .datum_size = a_datum_size,
             .ret_code = a_ret_code,
             .action = a_action,
@@ -931,15 +926,15 @@ void dap_chain_datum_notify(dap_chain_cell_t *a_chain_cell,  dap_hash_fast_t *a_
     }
 }
 
-void dap_chain_datum_removed_notify(dap_chain_cell_t *a_chain_cell,  dap_hash_fast_t *a_hash) {
+void dap_chain_datum_removed_notify(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_hash) {
 #ifdef DAP_CHAIN_BLOCKS_TEST
     return;
 #endif
 
-    if ( !a_chain_cell->chain->datum_removed_notifiers )
+    if ( !a_chain->datum_removed_notifiers )
         return;
     dap_list_t *l_iter;
-    DL_FOREACH(a_chain_cell->chain->datum_removed_notifiers, l_iter) {
+    DL_FOREACH(a_chain->datum_removed_notifiers, l_iter) {
         dap_chain_datum_removed_notifier_t *l_notifier = (dap_chain_datum_removed_notifier_t*)l_iter->data;
         struct chain_thread_datum_removed_notifier *l_arg = DAP_NEW_Z(struct chain_thread_datum_removed_notifier);
         if (!l_arg) {
@@ -948,7 +943,7 @@ void dap_chain_datum_removed_notify(dap_chain_cell_t *a_chain_cell,  dap_hash_fa
         }
         *l_arg = (struct chain_thread_datum_removed_notifier) {
             .callback = l_notifier->callback, .callback_arg = l_notifier->arg,
-            .chain = a_chain_cell->chain,     .cell_id = a_chain_cell->id,
+            .chain = a_chain,     .cell_id = a_cell_id,
             .hash = *a_hash};
         dap_proc_thread_callback_add_pri(l_notifier->proc_thread, s_notify_datum_removed_on_thread, l_arg, DAP_QUEUE_MSG_PRIORITY_LOW);
     }
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index cf26c6514d..f7b8580bfd 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -611,10 +611,8 @@ int dap_chain_cell_open(dap_chain_t *a_chain, const char *a_filename, const char
 #undef m_ret_err
 }
 
-static int s_cell_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a_atom, uint64_t a_atom_size)
+static int s_cell_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a_atom, uint64_t a_atom_size, char **a_atom_map)
 {
-    dap_return_val_if_fail(a_atom && a_atom_size, -1);
-
     if (a_cell->chain->is_mapped) {
         off_t l_pos = !fseeko(a_cell->file_storage, 0, SEEK_END) ? ftello(a_cell->file_storage) : -1;
         dap_return_val_if_pass_err(l_pos < 0, -1, "Can't get \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X" size, error %d",
@@ -635,24 +633,40 @@ static int s_cell_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a
     dap_return_val_if_fail_err(
         fwrite(&a_atom_size, sizeof(a_atom_size), 1, a_cell->file_storage) == 1 &&
         fwrite(a_atom,       a_atom_size,         1, a_cell->file_storage) == 1,
-        -3, "Can't write atom (%zu b) to \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X", error %d: \"%s\"",
+        -3, "Can't write atom [%zu b] to \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X", error %d: \"%s\"",
             a_atom_size, a_cell->chain->net_name, a_cell->chain->name, a_cell->id, errno, dap_strerror(errno)
     );
 
     debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG, "After writing an atom of size %lu, stream pos of %s is %lu and map shift is %lu", 
                                             a_atom_size, a_cell->file_storage_path, ftello(a_cell->file_storage),
                                             (size_t)(a_cell->map_pos - a_cell->map));
-#ifdef DAP_OS_DARWIN
     fflush(a_cell->file_storage);
+
     if (a_cell->chain->is_mapped) {
+#ifdef DAP_OS_DARWIN 
         if ( MAP_FAILED == (a_cell->map = mmap(a_cell->map, dap_page_roundup(DAP_MAPPED_VOLUME_LIMIT), PROT_READ,
                                             MAP_PRIVATE|MAP_FIXED, fileno(a_cell->file_storage), a_cell->cur_vol_start)) ) {
             log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be remapped, errno %d",
                             a_cell->file_storage_path, a_cell->id.uint64, errno);
             return -2;
         }
-    }
+#elif defined DAP_OS_WINDOWS
+        off_t l_off = ftello(a_cell->file_storage);
+        LARGE_INTEGER SectionSize = (LARGE_INTEGER) { .QuadPart = l_off };
+        HANDLE hSection = (HANDLE)a_cell->map_range_bounds->data;
+        NTSTATUS err = pfnNtExtendSection(hSection, &SectionSize);
+        if ( !NT_SUCCESS(err) ) {
+            log_it(L_ERROR, "NtExtendSection() failed, status %lx: \"%s\"",
+                            err, dap_str_ntstatus(err) );
+            return -2;
+        }
 #endif
+        /* Pass ptr to mapped area */
+        if (a_atom_map) {
+            *a_atom_map = a_cell->map_pos += sizeof(uint64_t);
+            a_cell->map_pos += a_atom_size;
+        }
+    }
     return 0;
 }
 
@@ -668,93 +682,21 @@ static int s_cell_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a
  * @param a_atom_size
  * @return
  */
-ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom, size_t a_atom_size)
+int dap_chain_cell_file_append(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, const void *a_atom, size_t a_atom_size, char **a_atom_map)
 {
-    dap_return_val_if_fail(a_cell, -1);
-    dap_return_val_if_pass_err(!a_atom && !a_cell->chain, -2, "Chain not found for cell 0x%016"DAP_UINT64_FORMAT_X" %s ",
-                                                              a_cell->id.uint64, a_cell->file_storage_path);
-    size_t l_size = 0, l_count = 0;
-    int l_err = -1;
-    pthread_rwlock_wrlock(&a_cell->storage_rwlock);
-    if ( a_atom && a_atom_size ) {
-        //pthread_rwlock_wrlock(a_cell->chain->cell_rwlock);
-        debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG, "Before appending an atom of size %lu, stream pos of %s is %lu, map pos is %lu",
-                      a_atom_size, a_cell->file_storage_path, ftello(a_cell->file_storage),
-                      (size_t)(a_cell->map_pos - a_cell->map));
-        
-        if ( !s_cell_file_atom_add(a_cell, a_atom, a_atom_size) ) {
-            ++l_count;
-            l_size = a_atom_size + sizeof(uint64_t);
-            debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG,"After appending an atom of size %lu, stream pos of %s is %lu, map pos is %lu",
-                                                a_atom_size, a_cell->file_storage_path, ftello(a_cell->file_storage),
-                                                (size_t)(a_cell->map_end - a_cell->map_pos));
-#ifdef DAP_OS_WINDOWS
-            if (a_cell->chain->is_mapped) {
-                off_t l_off = ftello(a_cell->file_storage);
-                LARGE_INTEGER SectionSize = (LARGE_INTEGER) { .QuadPart = l_off };
-                HANDLE hSection = (HANDLE)a_cell->map_range_bounds->data;
-                NTSTATUS err = pfnNtExtendSection(hSection, &SectionSize);
-                if ( !NT_SUCCESS(err) ) {
-                    log_it(L_ERROR, "NtExtendSection() failed, status %lx: \"%s\"",
-                                    err, dap_str_ntstatus(err) );
-                    l_err = -2;
-                }
-            }
-#endif
-        }
-        //pthread_rwlock_unlock(a_cell->chain->cell_rwlock);
-    } else {
-        if (a_cell->chain->is_mapped) {
-            log_it(L_ERROR, "Unable to rewrite memory-mapped chain");
-            // TODO: do we actually need it besides zerochain reordering issue?
-            pthread_rwlock_unlock(&a_cell->storage_rwlock);
-            return -3;
-        }
-        const char *l_fname = dap_strdup_printf("%"DAP_UINT64_FORMAT_x "." CELL_FILE_EXT
-#ifdef DAP_OS_WINDOWS
-            ".new"
-#endif
-            , a_cell->id.uint64);
-        bool was_mapped = a_cell->chain->is_mapped;
-        a_cell->chain->is_mapped = false;
-        l_err = dap_chain_cell_open(a_cell->chain, l_fname, 'w');
-        DAP_DELETE(l_fname);
-        if (l_err) {
-            log_it(L_ERROR, "Can't open chain \"%s : %s\" cell, code %d", a_cell->chain->net_name, a_cell->chain->name, l_err);
-            pthread_rwlock_unlock(&a_cell->storage_rwlock);
-            return -3;
-        }
-        l_size += sizeof(dap_chain_cell_file_header_t);
-        dap_chain_atom_iter_t *l_atom_iter = a_cell->chain->callback_atom_iter_create(a_cell->chain, a_cell->id, NULL);
-        dap_chain_atom_ptr_t l_atom;
-        uint64_t l_atom_size = 0;
-        //pthread_rwlock_wrlock(a_cell->chain->cell_rwlock);
-        for (l_atom = a_cell->chain->callback_atom_iter_get(l_atom_iter, DAP_CHAIN_ITER_OP_FIRST, &l_atom_size);
-             l_atom && l_atom_size && !( l_err = s_cell_file_atom_add(a_cell, l_atom, l_atom_size) );
-             l_atom = a_cell->chain->callback_atom_iter_get(l_atom_iter, DAP_CHAIN_ITER_OP_NEXT, &l_atom_size))
-        {
-            l_size += sizeof(uint64_t) + l_atom_size;
-            ++l_count;
-        }
-        a_cell->chain->callback_atom_iter_delete(l_atom_iter);
-        a_cell->chain->is_mapped = was_mapped;
-        debug_if (s_debug_more && a_cell->chain->is_mapped,L_DEBUG, "After rewriting file %s, stream pos is %lu and map pos is %lu",
-                      a_cell->file_storage_path, ftello(a_cell->file_storage),
-                      (size_t)(a_cell->map_pos - a_cell->map));
-        //pthread_rwlock_unlock(a_cell->chain->cell_rwlock);
-    }
-
-    if (l_size) {
-#ifndef DAP_OS_DARWIN
-        fflush(a_cell->file_storage);
-#endif
-        log_it(L_DEBUG, "Saved %zu atom%s (%zu bytes) to chain \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
-               l_count, l_count > 1 ? "s" : "", l_size, a_cell->chain->net_name, a_cell->chain->name, a_cell->id.uint64);
-        debug_if(l_err, L_WARNING, "Not all data was saved due to writing error %d!", l_err);
-    } else {
-        log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X": nothing saved!",
-               a_cell->file_storage_path, a_cell->id.uint64);
-    }
-    pthread_rwlock_unlock(&a_cell->storage_rwlock);
-    return l_size;
+    dap_return_val_if_fail(a_atom && a_atom_size && a_chain, -1);
+    dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_chain, a_cell_id);
+    dap_return_val_if_fail_err(l_cell, -2, "Cell #%"DAP_UINT64_FORMAT_x" not found in chain \"%s : %s\"",
+                                            a_cell_id, a_chain->net_name, a_chain->name);
+    pthread_rwlock_wrlock(&l_cell->storage_rwlock);
+    int l_err = s_cell_file_atom_add(l_cell, a_atom, a_atom_size, a_atom_map);
+    if (l_err)
+        log_it(L_DEBUG, "Saved atom of size %zu bytes to chain \"%s : %s\", cell 0x%016"DAP_UINT64_FORMAT_X"",
+                        a_atom_size, a_chain->net_name, a_chain->name, a_cell_id.uint64);
+    else
+        log_it(L_ERROR, "Noting saved to chain \"%s : %s\", cell 0x%016"DAP_UINT64_FORMAT_X", error %d",
+                        a_chain->net_name, a_chain->name, a_cell_id.uint64, l_err);
+    pthread_rwlock_unlock(&l_cell->storage_rwlock);
+    dap_chain_cell_remit(l_cell);
+    return 0;
 }
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index 5d26c66bb3..767b46442b 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -313,9 +313,9 @@ void dap_chain_add_callback_notify(dap_chain_t *a_chain, dap_chain_callback_noti
 void dap_chain_add_callback_datum_index_notify(dap_chain_t *a_chain, dap_chain_callback_datum_notify_t a_callback, dap_proc_thread_t *a_thread, void *a_callback_arg);
 void dap_chain_add_callback_datum_removed_from_index_notify(dap_chain_t *a_chain, dap_chain_callback_datum_removed_notify_t a_callback, dap_proc_thread_t *a_thread, void *a_callback_arg);
 void dap_chain_atom_confirmed_notify_add(dap_chain_t *a_chain, dap_chain_callback_notify_t a_callback, void *a_arg, uint64_t a_conf_cnt);
-void dap_chain_atom_notify(dap_chain_cell_t *a_chain_cell,  dap_hash_fast_t *a_hash, const uint8_t *a_atom, size_t a_atom_size);
-void dap_chain_datum_notify(dap_chain_cell_t *a_chain_cell,  dap_hash_fast_t *a_hash, dap_chain_hash_fast_t *a_atom_hash, const uint8_t *a_datum, size_t a_datum_size, int a_ret_code, uint32_t a_action, dap_chain_srv_uid_t a_uid);
-void dap_chain_datum_removed_notify(dap_chain_cell_t *a_chain_cell,  dap_hash_fast_t *a_hash);
+void dap_chain_atom_notify(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_hash, const uint8_t *a_atom, size_t a_atom_size);
+void dap_chain_datum_notify(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id,  dap_hash_fast_t *a_hash, dap_chain_hash_fast_t *a_atom_hash, const uint8_t *a_datum, size_t a_datum_size, int a_ret_code, uint32_t a_action, dap_chain_srv_uid_t a_uid);
+void dap_chain_datum_removed_notify(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_hash);
 void dap_chain_atom_add_from_threshold(dap_chain_t *a_chain);
 dap_chain_atom_ptr_t dap_chain_get_atom_by_hash(dap_chain_t * a_chain, dap_chain_hash_fast_t * a_atom_hash, size_t * a_atom_size);
 bool dap_chain_get_atom_last_hash_num_ts(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, dap_hash_fast_t *a_atom_hash, uint64_t *a_atom_num, dap_time_t *a_atom_timestamp);
@@ -323,7 +323,7 @@ DAP_STATIC_INLINE bool dap_chain_get_atom_last_hash(dap_chain_t *a_chain, dap_ch
 {
     return dap_chain_get_atom_last_hash_num_ts(a_chain, a_cell_id, a_atom_hash, NULL, NULL);
 }
-ssize_t dap_chain_atom_save(dap_chain_cell_t *a_chain_cell, const uint8_t *a_atom, size_t a_atom_size, dap_hash_fast_t *a_new_atom_hash);
+ssize_t dap_chain_atom_save(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, const uint8_t *a_atom, size_t a_atom_size, dap_hash_fast_t *a_new_atom_hash);
 int dap_cert_chain_file_save(dap_chain_datum_t *datum, char *net_name);
 
 const char *dap_chain_type_to_str(dap_chain_type_t a_chain_type);
diff --git a/modules/chain/include/dap_chain_cell.h b/modules/chain/include/dap_chain_cell.h
index 6ed59c9ca3..618def9cc6 100644
--- a/modules/chain/include/dap_chain_cell.h
+++ b/modules/chain/include/dap_chain_cell.h
@@ -98,6 +98,7 @@ DAP_INLINE void dap_chain_cell_remit(const dap_chain_cell_t *a_cell) {
 
 void dap_chain_cell_close(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id);
 void dap_chain_cell_close_all(dap_chain_t *a_chain);
-ssize_t dap_chain_cell_file_append(dap_chain_cell_t *a_cell, const void *a_atom, size_t a_atom_size);
+int dap_chain_cell_file_append(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id,
+                                   const void *a_atom, size_t a_atom_size, char **a_atom_map);
 #define dap_chain_cell_file_update(a_cell) dap_chain_cell_file_append(a_cell, NULL, 0);
 
-- 
GitLab


From 223dca189c0c49737545551f44a40b88f95455d5 Mon Sep 17 00:00:00 2001
From: "P. Constantin" <papizh.konstantin@demlabs.net>
Date: Mon, 17 Feb 2025 20:41:15 +0700
Subject: [PATCH 06/11] ....

---
 dap-sdk                                       |   2 +-
 modules/chain/dap_chain.c                     |  57 +--
 modules/chain/dap_chain_cell.c                | 465 ++++++------------
 modules/chain/include/dap_chain.h             |  14 +-
 modules/chain/include/dap_chain_cell.h        |  12 +-
 .../consensus/dag-poa/dap_chain_cs_dag_poa.c  |   8 +-
 modules/ledger/dap_chain_ledger.c             |  20 +-
 modules/ledger/dap_chain_ledger_decree.c      |   2 +-
 modules/net/dap_chain_net.c                   | 244 ++++-----
 .../service/datum/dap_chain_net_srv_datum.c   |   2 +-
 modules/type/blocks/dap_chain_cs_blocks.c     |  63 +--
 modules/type/dag/dap_chain_cs_dag.c           | 278 ++++++-----
 12 files changed, 456 insertions(+), 711 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index e4ffa996e2..64b2cd4990 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit e4ffa996e2df6a6f454ba8110bc49b8f1c533741
+Subproject commit 64b2cd4990a59c3af91e8f1402d4cfd468bd90bc
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 6070d8e8c6..20b2e15e7d 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -83,11 +83,11 @@ int dap_chain_init(void)
  */
 void dap_chain_deinit(void)
 {
-    dap_chain_item_t * l_item = NULL, *l_tmp = NULL;
+    /*dap_chain_item_t * l_item = NULL, *l_tmp = NULL;
     HASH_ITER(hh, s_chain_items, l_item, l_tmp) {
           dap_chain_delete(l_item->chain);
           DAP_DELETE(l_item);
-    }
+    }*/ // TODO!
     dap_chain_srv_deinit();
 }
 
@@ -144,12 +144,6 @@ void dap_chain_set_cs_type(dap_chain_t *a_chain, const char *a_cs_type)
     DAP_CHAIN_PVT(a_chain)->cs_type = dap_strdup(a_cs_type);
 }
 
-int dap_chain_purge(dap_chain_t *a_chain)
-{
-    int ret = dap_chain_cs_class_purge(a_chain);
-    return ret + dap_chain_cs_purge(a_chain);
-}
-
 /**
  * @brief
  * delete dap chain object
@@ -216,6 +210,7 @@ dap_chain_atom_ptr_t dap_chain_get_atom_by_hash(dap_chain_t * a_chain, dap_chain
  */
 dap_chain_t * dap_chain_find_by_id(dap_chain_net_id_t a_chain_net_id,dap_chain_id_t a_chain_id)
 {
+    // TODO! Reconsider lock mechanics
     dap_chain_item_id_t l_chain_item_id = {
         .id = a_chain_id,
         .net_id = a_chain_net_id,
@@ -491,24 +486,6 @@ const char *dap_chain_get_cs_type(dap_chain_t *l_chain)
     return (const char *)DAP_CHAIN_PVT(l_chain)->cs_name;
 }
 
-/**
- * @brief dap_chain_save_all
- * @param l_chain
- * @return
- */
-int dap_chain_save_all(dap_chain_t *l_chain) // TODO - move to cell.c
-{
-    int l_ret = 0;
-    pthread_rwlock_rdlock(&l_chain->cell_rwlock);
-    dap_chain_cell_t *l_item = NULL, *l_item_tmp = NULL;
-    HASH_ITER(hh,l_chain->cells,l_item,l_item_tmp){
-        if(dap_chain_cell_file_update(l_item) <= 0)
-            l_ret++;
-    }
-    pthread_rwlock_unlock(&l_chain->cell_rwlock);
-    return l_ret;
-}
-
 //send chain load_progress data to notify socket
 static bool s_load_notify_callback(dap_chain_t* a_chain) {
     json_object* l_chain_info = json_object_new_object();
@@ -546,7 +523,7 @@ int dap_chain_load_all(dap_chain_t *a_chain)
     const char l_suffix[] = ".dchaincell", *l_filename;
     struct dirent *l_dir_entry = NULL;
     dap_time_t l_ts_start = dap_time_now();
-    while (( l_dir_entry = readdir(l_dir) )) {
+    while (( l_dir_entry = readdir(l_dir) ) && !l_err ) {
         l_filename = l_dir_entry->d_name;
         size_t l_namelen = strlen(l_filename);
         if ( l_namelen >= sizeof(l_suffix) && !strncmp(l_filename + l_namelen - sizeof(l_suffix) - 1, l_suffix, sizeof(l_suffix) - 1) ) {
@@ -554,26 +531,6 @@ int dap_chain_load_all(dap_chain_t *a_chain)
             l_err = dap_chain_cell_open(a_chain, l_filename, 'a');
             dap_timerfd_delete(l_load_notify_timer->worker, l_load_notify_timer->esocket_uuid);
             s_load_notify_callback(a_chain);
-            if (l_err)
-                break;
-            if ( DAP_CHAIN_PVT(a_chain)->need_reorder ) {
-#ifdef DAP_OS_WINDOWS
-                char *l_new_path = dap_strdup_printf("%s/%s.new", DAP_CHAIN_PVT(a_chain)->file_storage_dir, l_filename);
-                if ( remove(l_new_path) == -1 )
-                    log_it(L_ERROR, "File \"%s\" doesn't exist", l_new_path);
-                DAP_DELETE(l_new_path);
-#else
-                char *l_old_name = dap_strdup_printf("%s/%s", DAP_CHAIN_PVT(a_chain)->file_storage_dir, l_filename),
-                     *l_filename_backup = dap_strdup_printf("%s.unsorted", l_old_name);
-                     
-                if (remove(l_filename_backup) == -1)
-                    log_it(L_ERROR, "File %s doesn't exist", l_filename_backup);
-                if (rename(l_old_name, l_filename_backup)) {
-                    log_it(L_ERROR, "Couldn't rename %s to %s", l_old_name, l_filename_backup);
-                }
-                DAP_DEL_MULTY(l_old_name, l_filename_backup);
-#endif
-            }
         }
     }
     closedir(l_dir);
@@ -584,11 +541,11 @@ int dap_chain_load_all(dap_chain_t *a_chain)
                         a_chain->net_name, a_chain->name, difftime((time_t)dap_time_now(), l_ts_start));
         break;
     case -1:
-        if (!( l_err = dap_chain_cell_open_file(a_chain, "0.dchaincell", 'w') ))
+        if (!( l_err = dap_chain_cell_open(a_chain, "0.dchaincell", 'w') ))
             log_it(L_INFO, "Initialized chain \"%s : %s\" cell 0", a_chain->net_name, a_chain->name);
         break;
     default:
-        log_it(L_ERROR, "Chain \"%s : %s\" cell was not loaded, error %d", a_chain->net_name, a_chain->name, l_err)
+        log_it(L_ERROR, "Chain \"%s : %s\" cell was not loaded, error %d", a_chain->net_name, a_chain->name, l_err);
     }
     return l_err;
 }
@@ -821,7 +778,7 @@ static bool s_notify_datum_removed_on_thread(void *a_arg)
     return false;
 }
 
-ssize_t dap_chain_atom_save(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id,
+int dap_chain_atom_save(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id,
                             const uint8_t *a_atom, size_t a_atom_size,
                             dap_hash_fast_t *a_new_atom_hash, char **a_atom_map)
 {
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index f7b8580bfd..7df6254238 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -58,6 +58,23 @@ typedef struct dap_chain_cell_file_header
     dap_chain_cell_id_t cell_id;
 } DAP_ALIGN_PACKED dap_chain_cell_file_header_t;
 
+typedef struct dap_chain_cell_mmap_volume {
+#ifdef DAP_OS_DARWIN
+    off_t offset;
+#endif
+    off_t size;
+    char *base;
+    struct dap_chain_cell_mmap_volume *prev, *next;
+} dap_chain_cell_mmap_volume_t;
+
+typedef struct dap_chain_cell_mmap_data {
+#ifdef DAP_OS_WINDOWS
+    HANDLE section;
+#endif
+    dap_chain_cell_mmap_volume_t *volume;
+    char *cursor;
+} dap_chain_cell_mmap_data_t;
+
 #ifdef DAP_OS_WINDOWS
 typedef NTSTATUS (*pfn_NtCreateSection)(
     OUT PHANDLE SectionHandle, IN ACCESS_MASK DesiredAccess,
@@ -110,204 +127,100 @@ int dap_chain_cell_init(void)
 }
 
 #ifndef DAP_OS_WINDOWS
-DAP_STATIC_INLINE void s_cell_reclaim_cur_volume(dap_chain_cell_t *a_cell) {
+DAP_STATIC_INLINE void s_cell_reclaim_cur_volume(dap_chain_cell_mmap_volume_t *a_vol) {
     if (
 #ifdef MADV_PAGEOUT
-    //madvise(a_cell->map, (size_t)(a_cell->map_end - a_cell->map), MADV_PAGEOUT) &&
+    //madvise(a_vol->base, a_vol->size, MADV_PAGEOUT) &&
 #endif
-    madvise(a_cell->map, (size_t)(a_cell->map_end - a_cell->map), MADV_DONTNEED) )
+    madvise(a_vol->base, a_vol->size, MADV_DONTNEED) )
         log_it(L_ERROR, "Unable to reclaim the previous volume, errno %d: \"%s\"", errno, dap_strerror(errno));
 }
 #endif
 
-#if 0
-DAP_STATIC_INLINE int s_cell_file_write_header(dap_chain_cell_t *a_cell)
-{
-    dap_chain_cell_file_header_t l_hdr = {
-        .signature      = DAP_CHAIN_CELL_FILE_SIGNATURE,
-        .version        = DAP_CHAIN_CELL_FILE_VERSION,
-        .type           = DAP_CHAIN_CELL_FILE_TYPE_RAW,
-        .chain_id       = a_cell->chain->id,
-        .chain_net_id   = a_cell->chain->net_id,
-        .cell_id        = a_cell->id
-    };
-    return fwrite(&l_hdr, sizeof(l_hdr), 1, a_cell->file_storage) ? fflush(a_cell->file_storage) : -1;
-}
-#endif
-
-DAP_STATIC_INLINE int s_cell_map_new_volume(dap_chain_cell_mmap_data_t *a_cell_map_data, size_t a_fpos, bool a_load) {
+DAP_STATIC_INLINE int s_cell_map_new_volume(dap_chain_cell_t *a_cell, off_t a_fpos, bool a_load) {
 #ifdef DAP_OS_WINDOWS
-    HANDLE hSection = NULL;
     if ( !a_fpos ) {
-        //if (a_cell->map_range_bounds)
-        //    NtClose( (HANDLE)a_cell->map_range_bounds->data );
-        off_t l_ssize = !fseeko(a_cell->file_storage, 0, SEEK_END) ? ftello(a_cell->file_storage) : -1;
-        if (l_ssize < 0)
-            return log_it(L_ERROR, "Can't get chain size, error %d: \"%s\"", errno, dap_strerror(errno)), -1;
-        LARGE_INTEGER SectionSize = { 
-            .QuadPart = l_ssize 
-        };
-        
-        NTSTATUS err = pfnNtCreateSection(&hSection, SECTION_MAP_READ | SECTION_EXTEND_SIZE,
-                                          NULL, &SectionSize, PAGE_READWRITE, SEC_RESERVE,
-                                          (HANDLE)_get_osfhandle(fileno(a_cell->file_storage)));
+        LARGE_INTEGER SectionSize = { .QuadPart = !fseeko(a_cell->file_storage, 0, SEEK_END) ? ftello(a_cell->file_storage) : -1 };
+        dap_return_val_if_pass_err(SectionSize.QuadPart < 0, -1, "Can't get chain size, error %d: \"%s\"", errno, dap_strerror(errno));
+        NTSTATUS err = pfnNtCreateSection( &a_cell->mapping->section, SECTION_MAP_READ | SECTION_EXTEND_SIZE,
+                                           NULL, &SectionSize, PAGE_READWRITE, SEC_RESERVE,
+                                           (HANDLE)_get_osfhandle(fileno(a_cell->file_storage)) );
         if ( !NT_SUCCESS(err) )
             return log_it(L_ERROR, "NtCreateSection() failed, status %lx: \"%s\"",
                                    err, dap_str_ntstatus(err) ), -1;
-        a_cell->map_range_bounds = dap_list_append(a_cell->map_range_bounds, hSection);
     }
 #endif
-    size_t  l_map_size      = dap_page_roundup(DAP_MAPPED_VOLUME_LIMIT),
+    dap_chain_cell_mmap_volume_t *l_new_vol = DAP_NEW_Z(dap_chain_cell_mmap_volume_t);
+    l_new_vol->size = dap_page_roundup(DAP_MAPPED_VOLUME_LIMIT);
+    off_t l_volume_offset = a_fpos ?
 #ifdef DAP_OS_WINDOWS
-            l_volume_start  = a_fpos ? dap_64k_rounddown(a_fpos)    : 0,
+            dap_64k_rounddown(a_fpos)
 #else               
-            l_volume_start  = a_fpos ? dap_page_rounddown(a_fpos)   : 0,
-#endif                  
-            l_offset        = a_fpos - l_volume_start;
+            dap_page_rounddown(a_fpos)
+#endif
+            : 0,
+        l_offset = a_fpos - l_volume_offset;
 #ifdef DAP_OS_WINDOWS
-    hSection = (HANDLE)a_cell->map_range_bounds->data;
-    a_cell->map = NULL;
     int err = 0;
-    LARGE_INTEGER Offset = {
-        .QuadPart = l_volume_start
-    };
-    err = pfnNtMapViewOfSection(hSection, GetCurrentProcess(), (HANDLE)&a_cell->map, 0, 0, 
-                                &Offset, &l_map_size, ViewUnmap, MEM_RESERVE, PAGE_READONLY);
-    if ( !NT_SUCCESS(err) )
-        return NtClose(hSection), log_it(L_ERROR, "NtMapViewOfSection() failed, status %lx: \"%s\"",
-                                                  err, dap_str_ntstatus(err) ), -1;
+    LARGE_INTEGER Offset = { .QuadPart = l_volume_offset };
+    err = pfnNtMapViewOfSection(a_cell->mapping->section, GetCurrentProcess(), (HANDLE)&l_new_vol->base, 0, 0, 
+                                &Offset, &l_new_vol->size, ViewUnmap, MEM_RESERVE, PAGE_READONLY);
+    if ( !NT_SUCCESS(err) ) {
+        NtClose(a_cell->mapping->section);
+        log_it(L_ERROR, "NtMapViewOfSection() failed, status %lx: \"%s\"", err, dap_str_ntstatus(err) );
+        DAP_DELETE(l_new_vol);
+        return -1;
+    }
 #else
     if (a_load)
-        s_cell_reclaim_cur_volume(a_cell);
-    if (( a_cell->map = mmap(NULL, l_map_size, PROT_READ, MAP_PRIVATE,
-                             fileno(a_cell->file_storage), l_volume_start) ) == MAP_FAILED )
-        return log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be mapped, errno %d",
-                                a_cell->file_storage_path, a_cell->id.uint64, errno), -1;
+        s_cell_reclaim_cur_volume(a_cell->mapping->volume);
+    l_new_vol->base = mmap( NULL, l_new_vol->size, PROT_READ, MAP_PRIVATE,
+                            fileno(a_cell->file_storage), l_volume_offset );
+    if ( l_new_vol->base == MAP_FAILED ) {
+        log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be mapped, errno %d",
+                        a_cell->file_storage_path, a_cell->id.uint64, errno);
+        DAP_DELETE(l_new_vol);
+        return -1;
+    }
 #ifdef DAP_OS_DARWIN
-    a_cell->cur_vol_start = l_volume_start;
+    l_new_vol->offset = l_volume_offset;
 #endif
 #endif
-    a_cell->map_pos = a_cell->map + l_offset;
-    a_cell->map_range_bounds = dap_list_append(a_cell->map_range_bounds, a_cell->map);
-    a_cell->map_range_bounds = dap_list_append(a_cell->map_range_bounds, a_cell->map_end = a_cell->map + l_map_size);
+    a_cell->mapping->cursor = l_new_vol->base + l_offset;
 #ifndef DAP_OS_WINDOWS    
     if (a_load)
-        madvise(a_cell->map, l_map_size, MADV_SEQUENTIAL);
+        madvise(l_new_vol->base, l_new_vol->size, MADV_SEQUENTIAL);
 #endif
+    DL_PREPEND(a_cell->mapping->volume, l_new_vol);
     return 0;
 }
 
-#if 0
-/**
- * @brief 
- * a_cell_id if < 0 then not used
- * @param a_chain dap_chain_t object
- * @param a_cell_id dap_chain_cell_id_t cell (shard) id
- * @return dap_chain_cell_t* 
- */
-dap_chain_cell_t * dap_chain_cell_create_fill(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id)
-{
-    dap_chain_cell_t * l_cell = NULL;
-    pthread_rwlock_wrlock(&a_chain->cell_rwlock);
-    HASH_FIND(hh, a_chain->cells, &a_cell_id, sizeof(dap_chain_cell_id_t), l_cell);
-    if (l_cell) {
-        pthread_rwlock_unlock(&a_chain->cell_rwlock);
-        return l_cell;
-    }
-    char file_storage_path[MAX_PATH];
-    snprintf(file_storage_path, MAX_PATH, "%s/%0"DAP_UINT64_FORMAT_x".dchaincell",
-             DAP_CHAIN_PVT(a_chain)->file_storage_dir, a_cell_id.uint64);
-    FILE *l_file = NULL;
-#define CLEANUP_AND_RET return ({ if (l_file) fclose(l_file); \
-    DAP_DELETE(l_cell); \
-    pthread_rwlock_unlock(&a_chain->cell_rwlock); \
-    NULL; })
-
-    if ( !(l_file = fopen(file_storage_path, "a+b")) ) {
-        log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be opened, error %d",
-                        file_storage_path, a_cell_id.uint64, errno);
-        CLEANUP_AND_RET;
-    }
-    if ( !(l_cell = DAP_NEW_Z(dap_chain_cell_t)) )
-        CLEANUP_AND_RET;
-    *l_cell = (dap_chain_cell_t) {
-        .id             = a_cell_id,
-        .chain          = a_chain,
-        .file_storage   = l_file,
-        .storage_rwlock = PTHREAD_RWLOCK_INITIALIZER
-    };
-    off_t l_size = !fseeko(l_file, 0, SEEK_END) ? ftello(l_file) : -1;
-    if (l_size < 0)
-        CLEANUP_AND_RET;
-    else if ( (size_t)l_size < sizeof(dap_chain_cell_file_header_t) ) {
-        if ( l_size ) {
-            log_it(L_INFO, "Possibly corrupt cell storage 0x%016"DAP_UINT64_FORMAT_X" \"%s\", rewriting it",
-                            a_cell_id.uint64, file_storage_path);
-            l_file = freopen(file_storage_path, "w+b", l_file);
-        }
-        if ( s_cell_file_write_header(l_cell) < 0 ) {
-            log_it(L_ERROR, "Can't init file storage for cell 0x%016"DAP_UINT64_FORMAT_X" \"%s\", errno %d",
-                             a_cell_id.uint64, file_storage_path, errno);
-            CLEANUP_AND_RET;
-        }
-        log_it(L_NOTICE, "Initialized file storage for cell 0x%016"DAP_UINT64_FORMAT_X" \"%s\"",
-                          a_cell_id.uint64, file_storage_path);
-        fflush(l_file);
-        l_file = freopen(file_storage_path, "a+b", l_file);
-    }
-
-    if ( a_chain->is_mapped && s_cell_map_new_volume(l_cell, 0, true) ) {
-        CLEANUP_AND_RET;
-    }
-#undef CLEANUP_AND_RET
-    memcpy(l_cell->file_storage_path, file_storage_path, sizeof(file_storage_path));
-    debug_if (s_debug_more && a_chain->is_mapped, L_DEBUG, "Mapped volume size is %lu", (size_t)(l_cell->map_end - l_cell->map));
-    HASH_ADD(hh, a_chain->cells, id, sizeof(dap_chain_cell_id_t), l_cell);
-    pthread_rwlock_unlock(&a_chain->cell_rwlock);
-    return l_cell;
-}
-
-#endif
-
 DAP_STATIC_INLINE int s_cell_close(dap_chain_cell_t *a_cell) {
-    pthread_rwlock_wrlock(&a_cell->storage_rwlock);
+    //pthread_rwlock_wrlock(&a_cell->storage_rwlock);
     if(a_cell->file_storage) {
         fclose(a_cell->file_storage);
         a_cell->file_storage = NULL;
     }
     if (a_cell->chain->is_mapped) {
-        dap_list_t *l_iter = a_cell->map_range_bounds;
+        a_cell->mapping->cursor = NULL;
+        int i = 0;
+        dap_chain_cell_mmap_volume_t *l_vol, *l_tmp;
+        DL_FOREACH_SAFE(a_cell->mapping->volume, l_vol, l_tmp) {
+            debug_if(s_debug_more, L_DEBUG, "Unmap volume #%d, %lu bytes", i++, l_vol->size);
 #ifdef DAP_OS_WINDOWS
-        l_iter = l_iter->next;
-#endif
-        for (; l_iter; l_iter = l_iter->next) {
-            if (l_iter->next) {
-                debug_if(s_debug_more, L_DEBUG, "Unmap volume %p (%lu bytes)", l_iter->data, (size_t)(l_iter->next->data - l_iter->data));
-#ifdef DAP_OS_WINDOWS
-                pfnNtUnmapViewOfSection(GetCurrentProcess(), l_iter->data);
+            pfnNtUnmapViewOfSection(GetCurrentProcess(), l_vol->base);
 #else
-                munmap(l_iter->data, (size_t)(l_iter->next->data - l_iter->data));
+            munmap(l_vol->base, l_vol->size);
 #endif
-                l_iter = l_iter->next;
-            }
+            DL_DELETE(a_cell->mapping->volume, l_vol);
+            DAP_DELETE(l_vol);
         }
 #ifdef DAP_OS_WINDOWS
-        NtClose(a_cell->map_range_bounds->data);
+        NtClose(a_cell->mapping->section);
 #endif
-        dap_list_free(a_cell->map_range_bounds);
     }
-#ifdef DAP_OS_WINDOWS
-    char *l_new = strstr(a_cell->file_storage_path, ".new");
-    if (l_new) {
-        char *l_orig = dap_strdup(a_cell->file_storage_path);
-        *l_new = '\0';
-        remove(a_cell->file_storage_path);
-        rename(l_orig, a_cell->file_storage_path);
-        DAP_DELETE(l_orig);
-    }
-#endif
-    pthread_rwlock_unlock(&a_cell->storage_rwlock);
-    pthread_rwlock_destroy(&a_cell->storage_rwlock);
+    //pthread_rwlock_unlock(&a_cell->storage_rwlock);
+    //pthread_rwlock_destroy(&a_cell->storage_rwlock);
 }
 
 /**
@@ -318,89 +231,17 @@ DAP_STATIC_INLINE int s_cell_close(dap_chain_cell_t *a_cell) {
 void dap_chain_cell_close(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id)
 {
     dap_return_if_fail(a_chain);
-    dap_chain_cell_t *l_cell = NULL;
-    HASH_FIND(hh, a_chain->cells, &a_cell_id, sizeof(dap_chain_cell_id_t), l_cell);
-    if (l_cell) {
-        s_cell_close(l_cell);
-        HASH_DEL(a_chain->cells, l_cell);
-        DAP_DELETE(l_cell);
-    } else
-        log_it(L_ERROR, "Cell 0x%016"DAP_UINT64_FORMAT_X" not found in chain \"%s : %s\"",
-                a_cell_id.uint64, a_chain->net_name, a_chain->name);
-    pthread_rwlock_unlock(&a_chain->cell_rwlock);
-}
-
-#if 0
-/**
- * @brief 
- * free chain cell objects
- * @param a_cell dap_chain_cell_t object
- */
-void dap_chain_cell_delete(dap_chain_cell_t *a_cell)
-{
-    if(!a_cell)
-        return;
-    dap_chain_cell_close(a_cell);
-    if (a_cell->chain->cells) {
-        dap_chain_cell_t *l_cell = NULL;
-        dap_chain_cell_id_t l_cell_id = {
-            .uint64 = a_cell->id.uint64
-        };
-        pthread_rwlock_wrlock(&a_cell->chain->cell_rwlock);
-        HASH_FIND(hh, a_cell->chain->cells, &l_cell_id, sizeof(dap_chain_cell_id_t), l_cell);
-        if (l_cell)
-            HASH_DEL(a_cell->chain->cells, l_cell);
-        pthread_rwlock_unlock(&a_cell->chain->cell_rwlock);
-    }
-    a_cell->chain = NULL;
-    a_cell->file_storage_path[0] = '\0';
-    pthread_rwlock_destroy(&a_cell->storage_rwlock);
-    DAP_DELETE(a_cell);
-}
-
-void dap_chain_cell_delete_all_and_free_file(dap_chain_t *a_chain) {
-    if (!a_chain)
-        return;
-    pthread_rwlock_wrlock(&a_chain->cell_rwlock);
-    dap_chain_cell_t *l_cell, *l_tmp;
-    HASH_ITER(hh, a_chain->cells, l_cell, l_tmp) {
-        char *l_fsp = dap_strdup(l_cell->file_storage_path);
-        dap_chain_cell_id_t l_cell_id = l_cell->id;
-        dap_chain_cell_close(l_cell);
-
-        dap_chain_cell_t * l_cell_nh = DAP_NEW_Z(dap_chain_cell_t);
-        FILE *l_file = fopen(l_fsp, "w+b");
-        if ( !l_file ) {
-            log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be opened, error %d",
-                   l_fsp, l_cell_id.uint64, errno);
-        }
-        *l_cell_nh = (dap_chain_cell_t) {
-                .id             = l_cell_id,
-                .chain          = a_chain,
-                .file_storage   = l_file
-        };
-        if ( s_cell_file_write_header(l_cell_nh) < 0 ) {
-            log_it(L_ERROR, "Can't init file storage for cell 0x%016"DAP_UINT64_FORMAT_X" \"%s\", errno %d",
-                   l_cell_id.uint64, l_fsp, errno);
-        } else {
-            log_it(L_NOTICE, "Reinitialized file storage for cell 0x%016"DAP_UINT64_FORMAT_X" \"%s\"",
-                   l_cell_id.uint64, l_fsp);
-        }
-        dap_chain_cell_close(l_cell_nh);
-
-        DAP_DELETE(l_fsp);
-        HASH_DEL(a_chain->cells, l_cell);
-        pthread_rwlock_destroy(&l_cell->storage_rwlock);
-        DAP_DELETE(l_cell);
-    }
-    pthread_rwlock_unlock(&a_chain->cell_rwlock);
+    dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_chain, a_cell_id);
+    dap_return_if_fail_err(l_cell, "Cell 0x%016"DAP_UINT64_FORMAT_X" not found in chain \"%s : %s\"",
+                                    a_cell_id.uint64, a_chain->net_name, a_chain->name);
+    s_cell_close(l_cell);
+    HASH_DEL(a_chain->cells, l_cell);
+    DAP_DELETE(l_cell);
+    dap_chain_cell_remit(l_cell);
 }
 
-#endif
-
 void dap_chain_cell_close_all(dap_chain_t *a_chain) {
-    if (!a_chain)
-        return;
+    dap_return_if_fail(a_chain);
     pthread_rwlock_wrlock(&a_chain->cell_rwlock);
     dap_chain_cell_t *l_cell, *l_tmp;
     HASH_ITER(hh, a_chain->cells, l_cell, l_tmp) {
@@ -429,7 +270,7 @@ DAP_STATIC_INLINE int s_cell_load_from_file(dap_chain_cell_t *a_cell)
         dap_chain_cell_file_header_t *l_hdr = DAP_NEW_STACK(dap_chain_cell_file_header_t);
         if (a_cell->chain->is_mapped) {
             dap_return_val_if_pass_err( s_cell_map_new_volume(a_cell, 0, false), -3, "Error on mapping the first volume" );
-            l_hdr = (dap_chain_cell_file_header_t*)a_cell->map;
+            l_hdr = (dap_chain_cell_file_header_t*)a_cell->mapping->volume->base;
         } else {
             fseeko(a_cell->file_storage, 0, SEEK_SET);
             dap_return_val_if_fail_err( fread(l_hdr, 1, sizeof(*l_hdr), a_cell->file_storage) != sizeof(*l_hdr), -4,
@@ -443,62 +284,78 @@ DAP_STATIC_INLINE int s_cell_load_from_file(dap_chain_cell_t *a_cell)
                                     "Too low chain version %d < %d, create a backup", l_hdr->version, DAP_CHAIN_CELL_FILE_VERSION );
         l_pos = sizeof(*l_hdr);
         if (a_cell->chain->is_mapped)
-            a_cell->map_pos = a_cell->map + l_pos;
+            a_cell->mapping->cursor = a_cell->mapping->volume->base + l_pos;
         if (l_full_size == l_pos)
-            return 0; // fseeko(a_cell->file_storage, l_pos, SEEK_SET);
+            return 0;
     }
 
     /* Load atoms */
     int l_ret = 0;    
-    uint64_t l_el_size = 0, q = 0;
+    off_t l_el_size = 0, q = 0;
+    dap_chain_atom_ptr_t l_atom;
+    dap_hash_fast_t l_atom_hash;
     if (a_cell->chain->is_mapped) {
-        dap_hash_fast_t l_atom_hash;
-        for ( off_t l_vol_rest = 0; l_pos + sizeof(uint64_t) < (size_t)l_full_size; ++q, l_pos += l_el_size + sizeof(uint64_t) ) {
-            l_vol_rest = (off_t)(a_cell->map_end - a_cell->map_pos) - sizeof(uint64_t);
-            if ( l_vol_rest <= 0 || (uint64_t)l_vol_rest < *(uint64_t*)a_cell->map_pos )
+        for ( off_t l_vol_rest = 0; l_pos + sizeof(uint64_t) < l_full_size; ++q, l_pos += sizeof(uint64_t) + l_el_size ) {
+            l_vol_rest = (off_t)( a_cell->mapping->volume->base + a_cell->mapping->volume->size - a_cell->mapping->cursor - sizeof(uint64_t) );
+            if ( l_vol_rest <= 0 || (uint64_t)l_vol_rest < ( l_el_size = *(uint64_t*)a_cell->mapping->cursor ) )
                 dap_return_val_if_pass_err( s_cell_map_new_volume(a_cell, l_pos, true), -7, "Error on mapping a new volume" );
-            l_el_size = *(uint64_t*)a_cell->map_pos;
             if ( !l_el_size || l_el_size > (size_t)(l_full_size - l_pos) )
                 break;
-            a_cell->map_pos += sizeof(uint64_t);
-            dap_chain_atom_ptr_t l_atom = (dap_chain_atom_ptr_t)(a_cell->map_pos);
+            l_atom = (dap_chain_atom_ptr_t)(a_cell->mapping->cursor + sizeof(uint64_t));
             dap_hash_fast(l_atom, l_el_size, &l_atom_hash);
-            a_cell->chain->callback_atom_add(a_cell->chain, l_atom, l_el_size, &l_atom_hash, false);
-            a_cell->map_pos += l_el_size;
-            a_cell->chain->load_progress = (int)((float)l_pos/l_full_size * 100 + 0.5);
+            dap_chain_atom_verify_res_t l_verif = a_cell->chain->callback_atom_prefetch
+                ? a_cell->chain->callback_atom_prefetch(a_cell->chain, l_atom, l_el_size, &l_atom_hash)
+                : a_cell->chain->callback_atom_add(a_cell->chain, l_atom, l_el_size, &l_atom_hash, false);
+            if ( l_verif == ATOM_CORRUPTED ) {
+                log_it(L_ERROR, "Atom #%d is corrupted, can't proceed with loading chain \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
+                                q, a_cell->chain->net_name, a_cell->chain->name, a_cell->id.uint64);
+                l_ret = 8;
+                break;
+            }
+            a_cell->mapping->cursor += sizeof(uint64_t) + l_el_size;
+            if ( !a_cell->chain->callback_atom_prefetch )
+                a_cell->chain->load_progress = (int)((float)l_pos/l_full_size * 100 + 0.5);
         }
 #ifndef DAP_OS_WINDOWS
-        s_cell_reclaim_cur_volume(a_cell);
+        /* Reclaim the last volume */
+        s_cell_reclaim_cur_volume(a_cell->mapping->volume);
 #endif
     } else { 
         size_t l_read = 0;
-        while ((l_read = fread(&l_el_size, 1, sizeof(l_el_size), a_cell->file_storage)) && !feof(a_cell->file_storage)) {
-            if (l_read != sizeof(l_el_size) || l_el_size == 0) {
+        while (( l_read = fread(&l_el_size, 1, sizeof(l_el_size), a_cell->file_storage) ) && !feof(a_cell->file_storage) ) {
+            if ( !l_el_size || l_read != sizeof(l_el_size) ) {
                 log_it(L_ERROR, "Corrupted element size %zu, chain %s is damaged", l_el_size, a_cell->file_storage_path);
                 l_ret = 8;
                 break;
             }
-            dap_chain_atom_ptr_t l_element = DAP_NEW_SIZE(dap_chain_atom_ptr_t, l_el_size);
-            if (!l_element) {
+            l_atom = DAP_NEW_SIZE(dap_chain_atom_ptr_t, l_el_size);
+            if (!l_atom) {
                 log_it(L_CRITICAL, "Memory allocation error");
                 l_ret = -9;
                 break;
             }
-            l_read = fread((void*)l_element, 1, l_el_size, a_cell->file_storage);
+            l_read = fread((void*)l_atom, 1, l_el_size, a_cell->file_storage);
             if (l_read != l_el_size) {
                 log_it(L_ERROR, "Read only %lu of %zu bytes, stop cell loading", l_read, l_el_size);
-                DAP_DELETE(l_element);
+                DAP_DELETE(l_atom);
                 l_ret = 10;
                 break;
             }
-            l_pos += sizeof(uint64_t) + l_read;
-            a_cell->chain->load_progress = (int)((float)l_pos/l_full_size * 100 + 0.5);
-            dap_hash_fast_t l_atom_hash = {};
-            dap_hash_fast(l_element, l_el_size, &l_atom_hash);
-            dap_chain_atom_verify_res_t l_res = a_cell->chain->callback_atom_add(a_cell->chain, l_element, l_el_size, &l_atom_hash, false);
-            if (l_res != ATOM_ACCEPT && l_res != ATOM_FORK)
-                DAP_DELETE(l_element);
+            dap_hash_fast(l_atom, l_el_size, &l_atom_hash);
+            dap_chain_atom_verify_res_t l_verif = a_cell->chain->callback_atom_prefetch
+                ? a_cell->chain->callback_atom_prefetch(a_cell->chain, l_atom, l_el_size, &l_atom_hash)
+                : a_cell->chain->callback_atom_add(a_cell->chain, l_atom, l_el_size, &l_atom_hash, false);
+            DAP_DELETE(l_atom);
+            if ( l_verif == ATOM_CORRUPTED ) {
+                log_it(L_ERROR, "Atom #%d is corrupted, can't proceed with loading chain \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
+                                q, a_cell->chain->net_name, a_cell->chain->name, a_cell->id.uint64);
+                l_ret = 11;
+                break;
+            }
             ++q;
+            l_pos += sizeof(uint64_t) + l_read;
+            if ( !a_cell->chain->callback_atom_prefetch )
+                a_cell->chain->load_progress = (int)((float)l_pos/l_full_size * 100 + 0.5);
         }
     }
     if ( l_pos < l_full_size && l_ret > 0 ) {
@@ -507,8 +364,7 @@ DAP_STATIC_INLINE int s_cell_load_from_file(dap_chain_cell_t *a_cell)
 #ifdef DAP_OS_WINDOWS
         if (a_cell->chain->is_mapped) {
             LARGE_INTEGER SectionSize = (LARGE_INTEGER) { .QuadPart = l_pos };
-            HANDLE hSection = (HANDLE)a_cell->map_range_bounds->data;
-            NTSTATUS err = pfnNtExtendSection(hSection, &SectionSize);
+            NTSTATUS err = pfnNtExtendSection(a_cell->mapping->section, &SectionSize);
             if ( !NT_SUCCESS(err) )
                 log_it(L_ERROR, "NtExtendSection() failed, status %lx", err);
         } else
@@ -516,7 +372,10 @@ DAP_STATIC_INLINE int s_cell_load_from_file(dap_chain_cell_t *a_cell)
             ftruncate(fileno(a_cell->file_storage), l_pos);
     }
     fseeko(a_cell->file_storage, l_pos, SEEK_SET);
-    log_it(L_INFO, "Loaded %lu atoms in cell %s", q, a_cell->file_storage_path);
+    if ( a_cell->chain->callback_atoms_prefetched_add )
+        a_cell->chain->callback_atoms_prefetched_add(a_cell->chain);
+    log_it(L_INFO, "Loaded %lu atoms in chain \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
+                    q, a_cell->chain->net_name, a_cell->chain->name, a_cell->id.uint64);
     return l_ret;
 }
 
@@ -528,25 +387,26 @@ DAP_STATIC_INLINE int s_cell_open(dap_chain_t *a_chain, const char *a_filename,
 
         switch ( sscanf(a_filename, l_fmt, &l_cell_id.uint64, l_ext, &l_ext2) ) {
         case 3:
+            // TODO: X.dchaincell.*
         case 2:
-            if ( !dap_strncmp(l_ext, CELL_FILE_EXT) )
+            if ( !dap_strncmp(l_ext, CELL_FILE_EXT, sizeof(l_ext)) )
                 break;
         default:
             return log_it(L_ERROR, "Invalid cell file name \"%s\"", a_filename), EINVAL;
         }
     }
-
-    const char file_storage_path[MAX_PATH], mode[] = { a_mode, '+', 'b', '\0' };
+    char file_storage_path[MAX_PATH], mode[] = { a_mode, '+', 'b', '\0' };
     snprintf(file_storage_path, MAX_PATH, "%s/%s", DAP_CHAIN_PVT(a_chain)->file_storage_dir, a_filename);
     dap_chain_cell_t *l_cell = NULL;
 
 #define m_ret_err(err, ...) return ({ if (l_cell->file_storage) fclose(l_cell->file_storage); \
-                                      DAP_DELETE(l_cell); log_it(L_ERROR, ##__VA_ARGS__), err })
+                                      DAP_DELETE(l_cell); log_it(L_ERROR, ##__VA_ARGS__), err; })
 
     dap_chain_cell_mmap_data_t l_cell_map_data = { };
     HASH_FIND(hh, a_chain->cells, &l_cell_id, sizeof(dap_chain_cell_id_t), l_cell);
     if (l_cell) {
         if (a_mode == 'w') {
+            /* Attention! File rewriting requires that ledger was already purged */
             s_cell_close(l_cell);
             HASH_DEL(a_chain->cells, l_cell);
             DAP_DELETE(l_cell);
@@ -564,19 +424,21 @@ DAP_STATIC_INLINE int s_cell_open(dap_chain_t *a_chain, const char *a_filename,
         .id             = l_cell_id,
         .chain          = a_chain,
         .file_storage   = l_file,
-        .storage_rwlock = PTHREAD_RWLOCK_INITIALIZER
+        //.storage_rwlock = PTHREAD_RWLOCK_INITIALIZER
     };
     dap_strncpy(l_cell->file_storage_path, file_storage_path, MAX_PATH);
 
-    switch (a_mode) {
+    switch (*mode) {
     case 'a': {
         int l_load_res = s_cell_load_from_file(l_cell);
-        if (!l_load_res)
+        if ( !l_load_res )
             break;
         else if (l_load_res < 0)
             m_ret_err(errno, "Cell \"%s : %s / \"%s\" cannot be loaded, code %d",
                              a_chain->net_name, a_chain->name, a_filename, l_load_res);
         // Otherwise, rewrite the file from scratch
+        ftruncate(fileno(l_cell->file_storage), 0);
+        *mode = 'w';
     }
     case 'w': {
         dap_chain_cell_file_header_t l_hdr = {
@@ -599,8 +461,9 @@ DAP_STATIC_INLINE int s_cell_open(dap_chain_t *a_chain, const char *a_filename,
     }
     HASH_ADD(hh, a_chain->cells, id, sizeof(dap_chain_cell_id_t), l_cell);
     log_it(L_INFO, "Cell storage \"%s\" is %s for chain \"%s : %s\"",
-                    a_filename, a_mode == 'w' ? "created" : "opened" a_chain->net_name, a_chain->name);
+                    a_filename, *mode == 'w' ? "created" : "opened", a_chain->net_name, a_chain->name);
     return 0;
+#undef m_ret_err
 }
 
 int dap_chain_cell_open(dap_chain_t *a_chain, const char *a_filename, const char a_mode) {
@@ -608,7 +471,6 @@ int dap_chain_cell_open(dap_chain_t *a_chain, const char *a_filename, const char
     int l_ret = s_cell_open(a_chain, a_filename, a_mode);
     pthread_rwlock_unlock(&a_chain->cell_rwlock);
     return l_ret;
-#undef m_ret_err
 }
 
 static int s_cell_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a_atom, uint64_t a_atom_size, char **a_atom_map)
@@ -617,55 +479,38 @@ static int s_cell_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a
         off_t l_pos = !fseeko(a_cell->file_storage, 0, SEEK_END) ? ftello(a_cell->file_storage) : -1;
         dap_return_val_if_pass_err(l_pos < 0, -1, "Can't get \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X" size, error %d",
                                                      a_cell->chain->net_name, a_cell->chain->name, a_cell->id, errno);
-        debug_if (s_debug_more, L_DEBUG, "Before filling volume for atom size %ld, stream pos of %s is %lu, map pos is %lu, space left in map %lu",
-                    a_atom_size, a_cell->file_storage_path, l_pos, (size_t)(a_cell->map_pos - a_cell->map), (size_t)(a_cell->map_end - a_cell->map_pos));
-        if ( a_atom_size + sizeof(uint64_t) > (size_t)(a_cell->map_end - a_cell->map_pos) )
+        if ( a_atom_size + sizeof(uint64_t) > (size_t)(a_cell->mapping->volume->base + a_cell->mapping->volume->size - a_cell->mapping->cursor) )
             dap_return_val_if_pass_err(
-                s_cell_map_new_volume(a_cell, (size_t)l_pos, false), 
+                s_cell_map_new_volume(a_cell, l_pos, false), 
                 -2, "Failed to create new map volume for \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
                 a_cell->chain->net_name, a_cell->chain->name, a_cell->id
             );
     }
-    
-    debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG, "Before writing an atom of size %lu, stream pos of %s is %ld and pos is %lu, space left in map %lu", 
-                                            a_atom_size, a_cell->file_storage_path, ftello(a_cell->file_storage),
-                                            (size_t)(a_cell->map_pos - a_cell->map), (size_t)(a_cell->map_end - a_cell->map_pos));
     dap_return_val_if_fail_err(
         fwrite(&a_atom_size, sizeof(a_atom_size), 1, a_cell->file_storage) == 1 &&
         fwrite(a_atom,       a_atom_size,         1, a_cell->file_storage) == 1,
         -3, "Can't write atom [%zu b] to \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X", error %d: \"%s\"",
             a_atom_size, a_cell->chain->net_name, a_cell->chain->name, a_cell->id, errno, dap_strerror(errno)
     );
-
-    debug_if (s_debug_more && a_cell->chain->is_mapped, L_DEBUG, "After writing an atom of size %lu, stream pos of %s is %lu and map shift is %lu", 
-                                            a_atom_size, a_cell->file_storage_path, ftello(a_cell->file_storage),
-                                            (size_t)(a_cell->map_pos - a_cell->map));
     fflush(a_cell->file_storage);
 
     if (a_cell->chain->is_mapped) {
-#ifdef DAP_OS_DARWIN 
-        if ( MAP_FAILED == (a_cell->map = mmap(a_cell->map, dap_page_roundup(DAP_MAPPED_VOLUME_LIMIT), PROT_READ,
-                                            MAP_PRIVATE|MAP_FIXED, fileno(a_cell->file_storage), a_cell->cur_vol_start)) ) {
-            log_it(L_ERROR, "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be remapped, errno %d",
-                            a_cell->file_storage_path, a_cell->id.uint64, errno);
-            return -2;
-        }
+#ifdef DAP_OS_DARWIN
+        a_cell->mapping->volume->base = mmap( a_cell->mapping->volume->base, a_cell->mapping->volume->size,
+                                              PROT_READ, MAP_PRIVATE | MAP_FIXED, fileno(a_cell->file_storage),
+                                              a_cell->mapping->volume->offset );
+        dap_return_val_if_pass_err( a_cell->mapping->volume->base == MAP_FAILED, -2,
+            "Chain cell \"%s\" 0x%016"DAP_UINT64_FORMAT_X" cannot be remapped, errno %d",
+            a_cell->file_storage_path, a_cell->id.uint64, errno );
 #elif defined DAP_OS_WINDOWS
-        off_t l_off = ftello(a_cell->file_storage);
-        LARGE_INTEGER SectionSize = (LARGE_INTEGER) { .QuadPart = l_off };
-        HANDLE hSection = (HANDLE)a_cell->map_range_bounds->data;
-        NTSTATUS err = pfnNtExtendSection(hSection, &SectionSize);
-        if ( !NT_SUCCESS(err) ) {
-            log_it(L_ERROR, "NtExtendSection() failed, status %lx: \"%s\"",
-                            err, dap_str_ntstatus(err) );
-            return -2;
-        }
+        LARGE_INTEGER SectionSize = (LARGE_INTEGER) { .QuadPart = ftello(a_cell->file_storage) };
+        NTSTATUS err = pfnNtExtendSection(a_cell->mapping->section, &SectionSize);
+        dap_return_val_if_fail_err( NT_SUCCESS(err), -2, "NtExtendSection() failed, status %lx: \"%s\"", err, dap_str_ntstatus(err) );
 #endif
         /* Pass ptr to mapped area */
-        if (a_atom_map) {
-            *a_atom_map = a_cell->map_pos += sizeof(uint64_t);
-            a_cell->map_pos += a_atom_size;
-        }
+        if (a_atom_map)
+            *a_atom_map = a_cell->mapping->cursor + sizeof(uint64_t);
+        a_cell->mapping->cursor += sizeof(uint64_t) + a_atom_size;
     }
     return 0;
 }
@@ -688,7 +533,7 @@ int dap_chain_cell_file_append(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_
     dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_chain, a_cell_id);
     dap_return_val_if_fail_err(l_cell, -2, "Cell #%"DAP_UINT64_FORMAT_x" not found in chain \"%s : %s\"",
                                             a_cell_id, a_chain->net_name, a_chain->name);
-    pthread_rwlock_wrlock(&l_cell->storage_rwlock);
+    //pthread_rwlock_wrlock(&l_cell->storage_rwlock);
     int l_err = s_cell_file_atom_add(l_cell, a_atom, a_atom_size, a_atom_map);
     if (l_err)
         log_it(L_DEBUG, "Saved atom of size %zu bytes to chain \"%s : %s\", cell 0x%016"DAP_UINT64_FORMAT_X"",
@@ -696,7 +541,7 @@ int dap_chain_cell_file_append(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_
     else
         log_it(L_ERROR, "Noting saved to chain \"%s : %s\", cell 0x%016"DAP_UINT64_FORMAT_X", error %d",
                         a_chain->net_name, a_chain->name, a_cell_id.uint64, l_err);
-    pthread_rwlock_unlock(&l_cell->storage_rwlock);
+    //pthread_rwlock_unlock(&l_cell->storage_rwlock);
     dap_chain_cell_remit(l_cell);
     return 0;
 }
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index 767b46442b..310fce8b26 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -97,6 +97,7 @@ typedef int (*dap_chain_callback_new_cfg_t)(dap_chain_t *, dap_config_t *);
 typedef void (*dap_chain_callback_ptr_t)(dap_chain_t *, void * );
 
 typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_t)(dap_chain_t *a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_hash_fast_t *a_atom_hash, bool a_atom_new);
+typedef unsigned (*dap_chain_callback_atoms_t)(dap_chain_t*);
 typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_form_treshold_t)(dap_chain_t *, size_t *);
 typedef json_object *(*dap_chain_callback_atom_to_json)(json_object **a_arr_out, dap_chain_t *a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, const char *a_hex_out_type);
 typedef dap_chain_atom_verify_res_t (*dap_chain_callback_atom_verify_t)(dap_chain_t *, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t*);
@@ -192,6 +193,8 @@ typedef struct dap_chain {
 
     pthread_rwlock_t cell_rwlock;
 
+    dap_chain_callback_atom_verify_t callback_atom_prefetch;
+    dap_chain_callback_atoms_t callback_atoms_prefetched_add;
     dap_chain_callback_atom_t callback_atom_add;
     dap_chain_callback_atom_form_treshold_t callback_atom_add_from_treshold;
     dap_chain_callback_atom_verify_t callback_atom_verify;
@@ -273,11 +276,8 @@ typedef struct dap_chain_atom_confirmed_notifier {
 
 typedef struct dap_chain_pvt {
     char *file_storage_dir;
-    char *cs_name;
-    char *cs_type;
+    char *cs_name, *cs_type;
     bool cs_started;
-    bool need_reorder;
-
 } dap_chain_pvt_t;
 
 #define DAP_CHAIN_PVT(a) ((dap_chain_pvt_t *)a->_pvt)
@@ -298,17 +298,15 @@ void dap_chain_deinit(void);
 
 dap_chain_t *dap_chain_create(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);
 void dap_chain_set_cs_type(dap_chain_t *a_chain, const char *a_cs_type);
-int dap_chain_purge(dap_chain_t *a_chain);
 
 int dap_chain_load_all(dap_chain_t *a_chain);
-int dap_chain_save_all(dap_chain_t *a_chain);
 bool dap_chain_has_file_store(dap_chain_t *a_chain);
 
 dap_chain_t *dap_chain_find_by_id(dap_chain_net_id_t a_chain_net_id,dap_chain_id_t a_chain_id);
 dap_chain_t *dap_chain_load_from_cfg(const char *a_chain_net_name, dap_chain_net_id_t a_chain_net_id, dap_config_t *a_cfg);
 void dap_chain_info_dump_log(dap_chain_t *a_chain);
 
-void dap_chain_delete(dap_chain_t * a_chain);
+void dap_chain_delete(dap_chain_t *a_chain);
 void dap_chain_add_callback_notify(dap_chain_t *a_chain, dap_chain_callback_notify_t a_callback, dap_proc_thread_t *a_thread, void *a_arg);
 void dap_chain_add_callback_datum_index_notify(dap_chain_t *a_chain, dap_chain_callback_datum_notify_t a_callback, dap_proc_thread_t *a_thread, void *a_callback_arg);
 void dap_chain_add_callback_datum_removed_from_index_notify(dap_chain_t *a_chain, dap_chain_callback_datum_removed_notify_t a_callback, dap_proc_thread_t *a_thread, void *a_callback_arg);
@@ -323,7 +321,7 @@ DAP_STATIC_INLINE bool dap_chain_get_atom_last_hash(dap_chain_t *a_chain, dap_ch
 {
     return dap_chain_get_atom_last_hash_num_ts(a_chain, a_cell_id, a_atom_hash, NULL, NULL);
 }
-ssize_t dap_chain_atom_save(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, const uint8_t *a_atom, size_t a_atom_size, dap_hash_fast_t *a_new_atom_hash);
+int dap_chain_atom_save(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id, const uint8_t *a_atom, size_t a_atom_size, dap_hash_fast_t *a_new_atom_hash, char **a_atom_map);
 int dap_cert_chain_file_save(dap_chain_datum_t *datum, char *net_name);
 
 const char *dap_chain_type_to_str(dap_chain_type_t a_chain_type);
diff --git a/modules/chain/include/dap_chain_cell.h b/modules/chain/include/dap_chain_cell.h
index 618def9cc6..74efe15fdb 100644
--- a/modules/chain/include/dap_chain_cell.h
+++ b/modules/chain/include/dap_chain_cell.h
@@ -29,20 +29,15 @@
 #include "dap_chain.h"
 #include "dap_chain_common.h"
 
-typedef struct dap_chain_cell_mmap_data {
-    off_t vol_size;
-    char *map, *map_pos, **maps;
-} dap_chain_cell_mmap_data_t;
+typedef struct dap_chain_cell_mmap_data dap_chain_cell_mmap_data_t;
 
 typedef struct dap_chain_cell {
     dap_chain_cell_id_t id;
-    dap_chain_t * chain;
-
+    dap_chain_t *chain;
     char file_storage_path[MAX_PATH];
-    char *map, *map_pos, *map_end;
+    dap_chain_cell_mmap_data_t *mapping;
     FILE *file_storage;
     uint8_t file_storage_type;
-    dap_list_t *map_range_bounds;
 #ifdef DAP_OS_DARWIN
     size_t cur_vol_start;
 #endif
@@ -100,5 +95,4 @@ void dap_chain_cell_close(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id);
 void dap_chain_cell_close_all(dap_chain_t *a_chain);
 int dap_chain_cell_file_append(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id,
                                    const void *a_atom, size_t a_atom_size, char **a_atom_map);
-#define dap_chain_cell_file_update(a_cell) dap_chain_cell_file_append(a_cell, NULL, 0);
 
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 68677baf8d..a026bc1dc1 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -351,11 +351,7 @@ static int s_callback_new(dap_chain_t *a_chain, dap_config_t * a_chain_cfg)
         return -1;
     }
     dap_chain_cs_dag_t *l_dag = DAP_CHAIN_CS_DAG(a_chain);
-    dap_chain_cs_dag_poa_t *l_poa = DAP_NEW_Z(dap_chain_cs_dag_poa_t);
-    if (!l_poa) {
-        log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-        return -1;
-    }
+    dap_chain_cs_dag_poa_t *l_poa = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_chain_cs_dag_poa_t, -1);
     l_dag->_inheritor = l_poa;
     l_dag->callback_delete = s_callback_delete;
     l_dag->callback_cs_verify = s_callback_event_verify;
@@ -687,7 +683,7 @@ static int s_callback_created(dap_chain_t * a_chain, dap_config_t *a_chain_net_c
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG ( a_chain );
     dap_chain_cs_dag_poa_t * l_poa = DAP_CHAIN_CS_DAG_POA( l_dag );
 
-    const char *l_events_sign_cert = = dap_config_get_item_str(a_chain_net_cfg,"dag-poa","events-sign-cert");
+    const char *l_events_sign_cert = dap_config_get_item_str(a_chain_net_cfg,"dag-poa","events-sign-cert");
     if ( l_events_sign_cert ) {
         if (!( PVT(l_poa)->events_sign_cert = dap_cert_find_by_name(l_events_sign_cert) ))
             log_it(L_ERROR,"Can't load events sign certificate, name \"%s\" is wrong", l_events_sign_cert);
diff --git a/modules/ledger/dap_chain_ledger.c b/modules/ledger/dap_chain_ledger.c
index 23414a6063..2b6b213fb9 100644
--- a/modules/ledger/dap_chain_ledger.c
+++ b/modules/ledger/dap_chain_ledger.c
@@ -971,7 +971,7 @@ void dap_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
         HASH_DEL(l_ledger_pvt->ledger_items, l_item_current);
         if (!is_ledger_mapped(l_ledger_pvt))
             DAP_DELETE(l_item_current->tx);
-        DAP_DEL_Z(l_item_current);
+        DAP_DELETE(l_item_current);
     }
     if (!a_preserve_db) {
         l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_TXS_STR);
@@ -983,8 +983,7 @@ void dap_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
     dap_ledger_wallet_balance_t *l_balance_current, *l_balance_tmp;
     HASH_ITER(hh, l_ledger_pvt->balance_accounts, l_balance_current, l_balance_tmp) {
         HASH_DEL(l_ledger_pvt->balance_accounts, l_balance_current);
-        DAP_DELETE(l_balance_current->key);
-        DAP_DELETE(l_balance_current);
+        DAP_DEL_MULTY(l_balance_current->key, l_balance_current);
     }
     if (!a_preserve_db) {
         l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_BALANCES_STR);
@@ -1000,19 +999,12 @@ void dap_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
         pthread_rwlock_wrlock(&l_token_current->token_emissions_rwlock);
         HASH_ITER(hh, l_token_current->token_emissions, l_emission_current, l_emission_tmp) {
             HASH_DEL(l_token_current->token_emissions, l_emission_current);
-            DAP_DELETE(l_emission_current->datum_token_emission);
-            DAP_DEL_Z(l_emission_current);
+            DAP_DEL_MULTY(l_emission_current->datum_token_emission, l_emission_current);
         }
         pthread_rwlock_unlock(&l_token_current->token_emissions_rwlock);
-        DAP_DELETE(l_token_current->datum_token);
-        DAP_DELETE(l_token_current->auth_pkeys);
-        DAP_DELETE(l_token_current->auth_pkey_hashes);
-        DAP_DEL_Z(l_token_current->tx_recv_allow);
-        DAP_DEL_Z(l_token_current->tx_recv_block);
-        DAP_DEL_Z(l_token_current->tx_send_allow);
-        DAP_DEL_Z(l_token_current->tx_send_block);
         pthread_rwlock_destroy(&l_token_current->token_emissions_rwlock);
-        DAP_DELETE(l_token_current);
+        DAP_DEL_MULTY(l_token_current->datum_token, l_token_current->datum_token, l_token_current->auth_pkeys, l_token_current->auth_pkey_hashes,
+            l_token_current->tx_recv_allow, l_token_current->tx_recv_block, l_token_current->tx_send_allow, l_token_current->tx_send_block, l_token_current);
     }
     if (!a_preserve_db) {
         l_gdb_group = dap_ledger_get_gdb_group(a_ledger, DAP_LEDGER_TOKENS_STR);
@@ -1040,7 +1032,7 @@ void dap_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
         HASH_DEL(l_ledger_pvt->threshold_txs, l_item_current);
         if (!is_ledger_mapped(l_ledger_pvt))
             DAP_DELETE(l_item_current->tx);
-        DAP_DEL_Z(l_item_current);
+        DAP_DELETE(l_item_current);
     }
 
     l_ledger_pvt->ledger_items         = NULL;
diff --git a/modules/ledger/dap_chain_ledger_decree.c b/modules/ledger/dap_chain_ledger_decree.c
index 94a51110c5..000b8e67e5 100644
--- a/modules/ledger/dap_chain_ledger_decree.c
+++ b/modules/ledger/dap_chain_ledger_decree.c
@@ -71,7 +71,7 @@ static int s_decree_clear(dap_ledger_t *a_ledger)
 void dap_ledger_decree_purge(dap_ledger_t *a_ledger)
 {
     s_decree_clear(a_ledger);
-    dap_ledger_decree_create(a_ledger);
+    //dap_ledger_decree_create(a_ledger);
 }
 
 static int s_decree_verify(dap_chain_net_t *a_net, dap_chain_datum_decree_t *a_decree, size_t a_data_size, dap_chain_hash_fast_t *a_decree_hash, bool a_anchored)
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 7406a88203..72ea0e13f2 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -220,7 +220,7 @@ static bool s_net_states_proc(void *a_arg);
 static void s_net_states_notify(dap_chain_net_t * l_net);
 static void s_nodelist_change_notify(dap_store_obj_t *a_obj, void *a_arg);
 //static void s_net_proc_kill( dap_chain_net_t * a_net );
-static int s_chains_init_all(const char *a_netname, const char *a_path, int *a_ledger_flags);
+static int s_chains_init_all(dap_chain_net_t *a_net, const char *a_path, uint16_t *a_ledger_flags);
 static int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx);
 static void *s_net_load(void *a_arg);
 static int s_net_try_online(dap_chain_net_t *a_net);
@@ -904,21 +904,34 @@ void s_set_reply_text_node_status(void **a_str_reply, dap_chain_net_t * a_net){
  * @return true
  * @return false
  */
-void dap_chain_net_purge(dap_chain_net_t *l_net)
+void dap_chain_net_purge(dap_chain_net_t *a_net)
 {
-    dap_chain_srv_purge_all(l_net->pub.id);
-    dap_ledger_purge(l_net->pub.ledger, false);
-    dap_chain_t *l_chain = NULL;
-    DL_FOREACH(l_net->pub.chains, l_chain) {
-        dap_chain_purge(l_chain);
-        dap_chain_load_all(l_chain);
-        l_net->pub.fee_value = uint256_0;
-        l_net->pub.fee_addr = c_dap_chain_addr_blank;
+    dap_chain_net_pvt_t *l_pvt = PVT(a_net);
+    dap_global_db_cluster_t *l_mempool = l_pvt->mempool_clusters;
+    while (l_mempool) {
+        dap_global_db_cluster_t *l_next = l_mempool->next;
+        dap_global_db_cluster_delete(l_mempool);
+        l_mempool = l_next;
     }
-    DL_FOREACH(l_net->pub.chains, l_chain) {
-        if (l_chain->callback_atom_add_from_treshold) {
-            while (l_chain->callback_atom_add_from_treshold(l_chain, NULL))
-                debug_if(s_debug_more, L_DEBUG, "Added atom from treshold");
+    dap_global_db_cluster_delete(l_pvt->orders_cluster);
+    dap_global_db_cluster_delete(l_pvt->nodes_cluster);
+    dap_global_db_cluster_delete(l_pvt->nodes_states);
+    dap_global_db_cluster_delete(l_pvt->common_orders);
+    struct block_reward *l_reward, *l_tmp;
+    DL_FOREACH_SAFE(l_pvt->rewards, l_reward, l_tmp) {
+        DL_DELETE(l_pvt->rewards, l_reward);
+        DAP_DELETE(l_reward);
+    }
+    dap_chain_srv_purge_all(a_net->pub.id);
+    if (a_net->pub.ledger) {
+        dap_ledger_purge(a_net->pub.ledger, false);
+        dap_ledger_handle_free(a_net->pub.ledger);
+    }
+    if (a_net->pub.chains) {
+        dap_chain_t *l_chain = NULL, *l_tmp = NULL;
+        DL_FOREACH_SAFE(a_net->pub.chains, l_chain, l_tmp) {
+            DL_DELETE(a_net->pub.chains, l_chain);
+            dap_chain_delete(l_chain);
         }
     }
 }
@@ -1753,36 +1766,15 @@ void dap_chain_net_deinit()
  */
 void dap_chain_net_delete(dap_chain_net_t *a_net)
 {
-    // Synchronously going to offline state
-    PVT(a_net)->state = PVT(a_net)->state_target = NET_STATE_OFFLINE;
-    s_net_states_proc(a_net);
-    dap_global_db_cluster_t *l_mempool = PVT(a_net)->mempool_clusters;
-    while (l_mempool) {
-        dap_global_db_cluster_t *l_next = l_mempool->next;
-        dap_global_db_cluster_delete(l_mempool);
-        l_mempool = l_next;
-    }
-    dap_global_db_cluster_delete(PVT(a_net)->orders_cluster);
-    dap_global_db_cluster_delete(PVT(a_net)->nodes_cluster);
-    dap_global_db_cluster_delete(PVT(a_net)->nodes_states);
-    dap_global_db_cluster_delete(PVT(a_net)->common_orders);
-
-    DAP_DELETE(PVT(a_net)->node_info);
-    if (a_net->pub.ledger) {
-        dap_ledger_purge(a_net->pub.ledger, true);
-        dap_ledger_handle_free(a_net->pub.ledger);
-    }
-    if (a_net->pub.chains) {
-        dap_chain_t
-            *l_cur = NULL,
-            *l_tmp = NULL;
-        DL_FOREACH_SAFE(a_net->pub.chains, l_cur, l_tmp) {
-            DL_DELETE(a_net->pub.chains, l_cur);
-            dap_chain_delete(l_cur);
-        }
-    }
+    dap_chain_net_pvt_t *l_pvt = PVT(a_net);
+    dap_chain_net_purge(a_net);
+    DAP_DEL_ARRAY(l_pvt->permanent_links_hosts, l_pvt->permanent_links_hosts_count);
+    DAP_DEL_ARRAY(l_pvt->seed_nodes_hosts, l_pvt->seed_nodes_count);
+    DAP_DEL_MULTY(l_pvt->permanent_links_hosts, l_pvt->seed_nodes_hosts, l_pvt->permanent_links_addrs, l_pvt->node_info);
+    // TODO: delete sync_timer and whatever else is initialized AFTER chains load
     HASH_DEL(s_nets_by_name, a_net);
     HASH_DELETE(hh2, s_nets_by_id, a_net);
+    dap_config_close(a_net->pub.config);
     DAP_DELETE(a_net);
 }
 
@@ -1831,7 +1823,7 @@ static int s_nodes_hosts_init(dap_chain_net_t *a_net, dap_config_t *a_cfg, const
     return 0;
 }
 
-static int s_chains_init_all(dap_chain_net_t *a_net, const char *a_path, int *a_ledger_flags) {
+static int s_chains_init_all(dap_chain_net_t *a_net, const char *a_path, uint16_t *a_ledger_flags) {
     DIR *l_chains_dir = opendir(a_path);
     if (!l_chains_dir)
         return log_it(L_ERROR, "Can't find any chains for network %s", a_net->pub.name), -1;
@@ -1903,6 +1895,56 @@ static int s_chains_init_all(dap_chain_net_t *a_net, const char *a_path, int *a_
     return 0;
 }
 
+int s_chain_net_preload(dap_chain_net_t *a_net) {
+    // Services register & configure
+    dap_chain_srv_start(a_net->pub.id, DAP_CHAIN_NET_SRV_XCHANGE_LITERAL, NULL);        // Harcoded core service starting for exchange capability
+    dap_chain_srv_start(a_net->pub.id, DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_LITERAL, NULL);    // Harcoded core service starting for delegated keys storage
+    char *l_services_path = dap_strdup_printf("%s/network/%s/services", dap_config_path(), a_net->pub.name);
+    DIR *l_service_cfg_dir = opendir(l_services_path);
+    DAP_DELETE(l_services_path);
+    if (l_service_cfg_dir) {
+        for ( struct dirent *l_dir_entry; ( l_dir_entry = readdir(l_service_cfg_dir) ); ) {
+            const char *l_entry_name = l_dir_entry->d_name;
+            size_t l_entry_len = strlen(l_entry_name);
+            if (l_entry_len < 4 || // It has non zero name excluding file extension
+                    strncmp(l_entry_name + l_entry_len - 4, ".cfg", 4) != 0) // its not a .cfg file
+                continue;
+            log_it(L_DEBUG, "Opening service config \"%s\"...", l_entry_name);
+            char *l_service_cfg_path = dap_strdup_printf("network/%s/services/%s", a_net->pub.name, l_entry_name);
+            dap_config_t *l_cfg_new = dap_config_open(l_service_cfg_path);
+            if (l_cfg_new) {
+                char l_service_name[l_entry_len - 3];
+                dap_strncpy(l_service_name, l_entry_name, l_entry_len - 4);
+                dap_chain_srv_start(a_net->pub.id, l_service_name, l_cfg_new);
+                dap_config_close(l_cfg_new);
+            }
+            DAP_DELETE(l_service_cfg_path);
+        }
+        closedir(l_service_cfg_dir);
+    }
+    uint16_t l_ledger_flags = 0;
+    switch ( PVT( a_net )->node_role.enums ) {
+    case NODE_ROLE_LIGHT:
+        //break;
+        PVT( a_net )->node_role.enums = NODE_ROLE_FULL; // TODO: implement light mode
+    case NODE_ROLE_FULL:
+        l_ledger_flags |= DAP_LEDGER_CHECK_LOCAL_DS;
+        if (dap_config_get_item_bool_default(g_config, "ledger", "cache_enabled", false))
+            l_ledger_flags |= DAP_LEDGER_CACHE_ENABLED;
+    default:
+        l_ledger_flags |= DAP_LEDGER_CHECK_CELLS_DS | DAP_LEDGER_CHECK_TOKEN_EMISSION;
+    }
+    if (dap_config_get_item_bool_default(g_config, "ledger", "mapped", true))
+        l_ledger_flags |= DAP_LEDGER_MAPPED;
+
+    int l_res = s_chains_init_all(a_net, a_net->pub.config->path, &l_ledger_flags);
+    if (!l_res)
+        a_net->pub.ledger = dap_ledger_create(a_net, l_ledger_flags);
+    
+    return l_res;
+    
+}
+
 /**
  * @brief load network config settings from cellframe-node.cfg file
  *
@@ -1913,8 +1955,7 @@ static int s_chains_init_all(dap_chain_net_t *a_net, const char *a_path, int *a_
 int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx)
 {
     dap_config_t *l_cfg = dap_config_open(a_path);
-    if (!l_cfg)
-        return log_it(L_ERROR,"Can't open default network config %s", a_path), -1;
+    dap_return_val_if_fail_err(l_cfg, -1, "Can't open default network config %s", a_path);
 
     dap_chain_net_t *l_net = s_net_new(a_net_name, l_cfg);
     if ( !l_net )
@@ -1951,65 +1992,17 @@ int s_net_init(const char *a_net_name, const char *a_path, uint16_t a_acl_idx)
      || ( !l_net_pvt->seed_nodes_count && s_nodes_hosts_init(l_net, l_cfg, "bootstrap_hosts", &l_net_pvt->seed_nodes_hosts, &l_net_pvt->seed_nodes_count) )
     ) {
         dap_chain_net_delete(l_net);
-        dap_config_close(l_cfg);
         return -4;
     }
-    if (!l_net_pvt->seed_nodes_count)
+    if ( !l_net_pvt->seed_nodes_count )
         log_it(L_WARNING, "Can't read seed nodes addresses, work with local balancer only");
 
-    // Get list chains name for enabled debug mode
-
     if ( dap_server_enabled() && ( l_net_pvt->node_info->ext_port = dap_config_get_item_uint16(g_config, "server", "ext_port") ))
         log_it(L_INFO, "Set external port %u for adding in node list", l_net_pvt->node_info->ext_port);
 
-    // Services register & configure
-    dap_chain_srv_start(l_net->pub.id, DAP_CHAIN_NET_SRV_XCHANGE_LITERAL, NULL);        // Harcoded core service starting for exchange capability
-    dap_chain_srv_start(l_net->pub.id, DAP_CHAIN_NET_SRV_STAKE_POS_DELEGATE_LITERAL, NULL);    // Harcoded core service starting for delegated keys storage
-    char *l_services_path = dap_strdup_printf("%s/network/%s/services", dap_config_path(), l_net->pub.name);
-    DIR *l_service_cfg_dir = opendir(l_services_path);
-    DAP_DELETE(l_services_path);
-    if (l_service_cfg_dir) {
-        for ( struct dirent *l_dir_entry; ( l_dir_entry = readdir(l_service_cfg_dir) ); ) {
-            const char *l_entry_name = l_dir_entry->d_name;
-            size_t l_entry_len = strlen(l_entry_name);
-            if (l_entry_len < 4 || // It has non zero name excluding file extension
-                    strncmp(l_entry_name + l_entry_len - 4, ".cfg", 4) != 0) // its not a .cfg file
-                continue;
-            log_it(L_DEBUG, "Opening service config \"%s\"...", l_entry_name);
-            char *l_service_cfg_path = dap_strdup_printf("network/%s/services/%s", l_net->pub.name, l_entry_name);
-            dap_config_t *l_cfg_new = dap_config_open(l_service_cfg_path);
-            if (l_cfg_new) {
-                char l_service_name[l_entry_len - 3];
-                dap_strncpy(l_service_name, l_entry_name, l_entry_len - 4);
-                dap_chain_srv_start(l_net->pub.id, l_service_name, l_cfg_new);
-                dap_config_close(l_cfg_new);
-            }
-            DAP_DELETE(l_service_cfg_path);
-        }
-        closedir(l_service_cfg_dir);
-    }
-    uint16_t l_ledger_flags = 0;
-    switch ( PVT( l_net )->node_role.enums ) {
-    case NODE_ROLE_LIGHT:
-        //break;
-        PVT( a_net )->node_role.enums = NODE_ROLE_FULL; // TODO: implement light mode
-    case NODE_ROLE_FULL:
-        l_ledger_flags |= DAP_LEDGER_CHECK_LOCAL_DS;
-        if (dap_config_get_item_bool_default(g_config, "ledger", "cache_enabled", false))
-            l_ledger_flags |= DAP_LEDGER_CACHE_ENABLED;
-    default:
-        l_ledger_flags |= DAP_LEDGER_CHECK_CELLS_DS | DAP_LEDGER_CHECK_TOKEN_EMISSION;
-    }
-    if (dap_config_get_item_bool_default(g_config, "ledger", "mapped", true))
-        l_ledger_flags |= DAP_LEDGER_MAPPED;
+    int l_ret = s_chain_net_preload(l_net);
+    return l_ret ? dap_chain_net_delete(l_net), l_ret : 0;
 
-    int l_res = s_chains_init_all(l_net, a_path, &l_ledger_flags);
-    if ( l_res )
-        return dap_chain_net_delete(l_net), l_res;
-
-    // init LEDGER model
-    l_net->pub.ledger = dap_ledger_create(l_net, l_ledger_flags);
-    return 0;
 }
 
 static void *s_net_load(void *a_arg)
@@ -2024,28 +2017,7 @@ static void *s_net_load(void *a_arg)
     DL_FOREACH(l_net->pub.chains, l_chain) {
         l_net->pub.fee_value = uint256_0;
         l_net->pub.fee_addr = c_dap_chain_addr_blank;
-        if ( !dap_chain_load_all(l_chain) ) {
-            if ( DAP_CHAIN_PVT(l_chain)->need_reorder ) // # unsafe crutch, need to escape reorder usage
-            {
-                log_it(L_DAP, "Reordering chain files for chain %s", l_chain->name);
-                if (l_chain->callback_atom_add_from_treshold) {
-                    while (l_chain->callback_atom_add_from_treshold(l_chain, NULL))
-                        log_it(L_DEBUG, "Added atom from treshold");
-                }
-                dap_chain_save_all(l_chain);
-                
-                DAP_CHAIN_PVT(l_chain)->need_reorder = false;
-                dap_chain_purge(l_chain);
-                dap_ledger_purge(l_net->pub.ledger, false);
-                l_net->pub.fee_value = uint256_0;
-                l_net->pub.fee_addr = c_dap_chain_addr_blank;
-                dap_chain_load_all(l_chain);
-            }
-            if (l_chain->callback_atom_add_from_treshold) {
-                while (l_chain->callback_atom_add_from_treshold(l_chain, NULL))
-                    log_it(L_DEBUG, "Added atom from treshold");
-            }
-        }
+        int l_ret = dap_chain_load_all(l_chain);
         l_chain->atom_num_last = 0;
         switch ( l_net_pvt->node_role.enums ) {
         case NODE_ROLE_ROOT_MASTER:
@@ -2066,7 +2038,7 @@ static void *s_net_load(void *a_arg)
                 l_chain->is_datum_pool_proc = ( !dap_chain_id_parse(l_proc_chains[k], &l_chain_id) && (l_chain->id.uint64 == l_chain_id.uint64) );
         } break;
         default: break;
-
+        }
         // Personal chain mempool cluster for each chain
         snprintf(l_gdb_groups_mask, sizeof(l_gdb_groups_mask), "%s.chain-%s.mempool",
                                                                l_net->pub.gdb_groups_prefix, l_chain->name);
@@ -2082,7 +2054,7 @@ static void *s_net_load(void *a_arg)
             l_net_pvt->mempool_clusters = l_cluster;
     }
     dap_ledger_load_end(l_net->pub.ledger);
-    log_it(L_INFO, "Node role \"%s\" established in net %s", dap_chain_node_role_to_str(l_net_pvt->node_role.enums), l_net->pub.name);
+    log_it(L_INFO, "Node role \"%s\" established in net %s", dap_chain_node_role_to_str(l_net_pvt->node_role), l_net->pub.name);
     l_net_pvt->state_target = NET_STATE_OFFLINE;
 
     // Init GlobalDB clusters for service and nodes (with aliases)
@@ -2103,7 +2075,7 @@ static void *s_net_load(void *a_arg)
                                                           l_gdb_groups_mask, 0, true,
                                                           DAP_GDB_MEMBER_ROLE_USER,
                                                           DAP_CLUSTER_TYPE_EMBEDDED);
-    dap_return_val_if_fail_err(l_net_pvt->common_orders, NULL, "Net \"%s\" loading error %d: can't initialize common orders cluster"
+    dap_return_val_if_fail_err(l_net_pvt->common_orders, NULL, "Net \"%s\" loading error %d: can't initialize common orders cluster",
                                                                l_net->pub.name, -4);
     dap_chain_net_add_auth_nodes_to_cluster(l_net, l_net_pvt->common_orders);
     // Node states cluster
@@ -2113,7 +2085,7 @@ static void *s_net_load(void *a_arg)
                                                         l_gdb_groups_mask, DAP_CHAIN_NET_NODES_TTL, true,
                                                         DAP_GDB_MEMBER_ROLE_USER,
                                                         DAP_CLUSTER_TYPE_EMBEDDED);
-    dap_return_val_if_fail_err(l_net_pvt->nodes_states, NULL, "Net \"%s\" loading error %d: can't initialize node states cluster"
+    dap_return_val_if_fail_err(l_net_pvt->nodes_states, NULL, "Net \"%s\" loading error %d: can't initialize node states cluster",
                                                                l_net->pub.name, -5);
     // Nodes and its aliases cluster
     snprintf(l_net->pub.gdb_nodes, sizeof(l_net->pub.gdb_nodes), "%s.%s", l_net->pub.gdb_groups_prefix, s_gdb_nodes_postfix);
@@ -2122,7 +2094,7 @@ static void *s_net_load(void *a_arg)
                                                          l_net->pub.gdb_nodes, 7200, true,
                                                          DAP_GDB_MEMBER_ROLE_GUEST,
                                                          DAP_CLUSTER_TYPE_EMBEDDED);
-    dap_return_val_if_fail_err(l_net_pvt->nodes_cluster, NULL, "Net \"%s\" loading error %d: can't initialize nodes cluster"
+    dap_return_val_if_fail_err(l_net_pvt->nodes_cluster, NULL, "Net \"%s\" loading error %d: can't initialize nodes cluster",
                                                                l_net->pub.name, -6);
     dap_chain_net_add_auth_nodes_to_cluster(l_net, l_net_pvt->nodes_cluster);
     dap_chain_net_add_nodelist_notify_callback(l_net, s_nodelist_change_notify, l_net);
@@ -2144,7 +2116,7 @@ static void *s_net_load(void *a_arg)
     // TODO rework alias concept
     const char * l_node_addr_type = dap_config_get_item_str_default(l_net->pub.config ,
                                                                     "general", "node_addr_type", "auto");
-    if (!dap_strcmp(l_node_addr_type, "static")) {
+    if ( !dap_strcmp(l_node_addr_type, "static") ) {
         const char *l_node_alias_str = dap_config_get_item_str_default(l_net->pub.config, "general", "node-addr",
                                                                        dap_config_get_item_str(l_net->pub.config,
                                                                                                "general", "node-alias"));
@@ -2160,7 +2132,7 @@ static void *s_net_load(void *a_arg)
 
     l_net_pvt->sync_context.sync_idle_time = dap_config_get_item_uint32_default(g_config, "chain", "sync_idle_time", 60);
     dap_proc_thread_timer_add(NULL, s_sync_timer_callback, l_net, c_sync_timer_period);
-
+    // TODO! Delete the timer in "purge()"
     log_it(L_INFO, "Network \"%s\" initialized", l_net->pub.name);
     l_net_pvt->state = NET_STATE_OFFLINE;
     return l_net;
@@ -2802,11 +2774,7 @@ int dap_chain_net_add_reward(dap_chain_net_t *a_net, uint256_t a_reward, uint64_
         log_it(L_ERROR, "Can't add retrospective reward for block");
         return -2;
     }
-    struct block_reward *l_new_reward = DAP_NEW_Z(struct block_reward);
-    if (!l_new_reward) {
-        log_it(L_CRITICAL, "Out of memory");
-        return -3;
-    }
+    struct block_reward *l_new_reward = DAP_NEW_Z_RET_VAL_IF_FAIL(struct block_reward, -3);
     l_new_reward->block_number = a_block_num;
     l_new_reward->reward = a_reward;
     // Place new reward at begining
@@ -3279,18 +3247,14 @@ DAP_INLINE dap_chain_net_state_t dap_chain_net_get_target_state(dap_chain_net_t
 bool dap_chain_net_stop(dap_chain_net_t *a_net)
 {
     int l_attempts_count = 0;
-    bool l_ret = false;
-    if (dap_chain_net_get_target_state(a_net) == NET_STATE_ONLINE) {
-        dap_chain_net_state_go_to(a_net, NET_STATE_OFFLINE);
-        l_ret = true;
-    } else if (dap_chain_net_get_state(a_net) != NET_STATE_OFFLINE) {
+    if ( dap_chain_net_get_target_state(a_net) == NET_STATE_ONLINE || dap_chain_net_get_state(a_net) != NET_STATE_OFFLINE )
         dap_chain_net_state_go_to(a_net, NET_STATE_OFFLINE);
+
+    while (dap_chain_net_get_state(a_net) != NET_STATE_OFFLINE && l_attempts_count++ < 5) {
+        sched_yield();
+        sleep(1);
     }
-    while (dap_chain_net_get_state(a_net) != NET_STATE_OFFLINE && l_attempts_count++ < 5) { sleep(1); }
-    if (dap_chain_net_get_state(a_net) != NET_STATE_OFFLINE) {
-        log_it(L_ERROR, "Can't stop net %s", a_net->pub.name);
-    }
-    return l_ret;
+    return dap_chain_net_get_state(a_net) == NET_STATE_OFFLINE;
 }
 
 /*------------------------------------State machine block end---------------------------------*/
diff --git a/modules/service/datum/dap_chain_net_srv_datum.c b/modules/service/datum/dap_chain_net_srv_datum.c
index 768e158fb1..25eb125b06 100644
--- a/modules/service/datum/dap_chain_net_srv_datum.c
+++ b/modules/service/datum/dap_chain_net_srv_datum.c
@@ -221,7 +221,7 @@ void s_order_notficator(dap_store_obj_t *a_obj, void *a_arg)
     dap_chain_net_srv_price_t *l_price = NULL;
 
     if ((l_order->price_unit.uint32 != SERV_UNIT_PCS) || (l_order->direction != SERV_DIR_BUY) ||
-            (strncmp(l_order->price_ticker, l_price->token, DAP_CHAIN_TICKER_SIZE_MAX)) ||
+            (dap_strncmp(l_order->price_ticker, l_price->token, DAP_CHAIN_TICKER_SIZE_MAX)) ||
             (!compare256(l_order->price, l_price->value_datoshi))) {
         char *l_balance_order = dap_chain_balance_coins_print(l_order->price);
         char *l_balance_service = dap_chain_balance_coins_print(l_price->value_datoshi);
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 8c67acdacd..9bd233b211 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -1560,9 +1560,8 @@ static int s_add_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_ca
             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);
-            dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_blocks->chain, a_blocks->chain->active_cell_id);
-            dap_chain_datum_notify(l_cell, l_datum_hash, &l_datum_index->block_cache->block_hash, (byte_t *)l_datum, l_datum_size, l_res, l_datum_index_data.action, l_datum_index_data.uid);
-            dap_chain_cell_remit(l_cell);
+            dap_chain_datum_notify(a_blocks->chain, a_block_cache->block->hdr.cell_id, l_datum_hash, &l_datum_index->block_cache->block_hash,
+                                   (byte_t*)l_datum, l_datum_size, l_res, l_datum_index_data.action, l_datum_index_data.uid);
         }
     }
     debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str,
@@ -1595,9 +1594,7 @@ static int s_delete_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block
             l_ret++;
             HASH_DEL(PVT(a_blocks)->datum_index, l_datum_index);
             // notify datum removed
-            dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_blocks->chain, a_blocks->chain->active_cell_id);
-            dap_chain_datum_removed_notify(l_cell, l_datum_hash);
-            dap_chain_cell_remit(l_cell);
+            dap_chain_datum_removed_notify(a_blocks->chain, a_block_cache->block->hdr.cell_id, l_datum_hash);
         }
     }
     debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str,
@@ -1618,7 +1615,7 @@ static void s_add_atom_to_blocks(dap_chain_cs_blocks_t *a_blocks, dap_chain_bloc
 }
 
 
-static bool s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_block_cache_t * a_bcache, uint64_t a_main_branch_length, dap_chain_cell_t *a_cell)
+static bool s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_block_cache_t * a_bcache, uint64_t a_main_branch_length)
 {
     dap_chain_cs_blocks_t * l_blocks = a_blocks;
     if (!a_blocks){
@@ -1683,7 +1680,7 @@ static bool s_select_longest_branch(dap_chain_cs_blocks_t * a_blocks, dap_chain_
             HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_curr_atom->block_hash), l_curr_atom);
             debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", l_curr_atom);
             s_add_atom_datums(l_blocks, l_curr_atom);
-            dap_chain_atom_notify(a_cell, &l_curr_atom->block_hash, (byte_t*)l_curr_atom->block, l_curr_atom->block_size);
+            dap_chain_atom_notify(a_blocks->chain, l_curr_atom->block->hdr.cell_id, &l_curr_atom->block_hash, (byte_t*)l_curr_atom->block, l_curr_atom->block_size);
             HASH_DEL(new_main_branch, l_item);
         }
         // Next we save pointer to new forked branch (former main branch) instead of it
@@ -1718,24 +1715,15 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
     case ATOM_ACCEPT:{
         dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
         assert(l_net);
-        dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_chain, l_block->hdr.cell_id);
 #ifndef DAP_CHAIN_BLOCKS_TEST
         if ( !dap_chain_net_get_load_mode(l_net) ) {
-            if ( (ret = dap_chain_atom_save(l_cell, a_atom, a_atom_size, a_atom_new ? &l_block_hash : NULL)) < 0 ) {
-                log_it(L_ERROR, "Can't save atom to file, code %d", ret);
-                return ATOM_REJECT;
-            } else if (a_chain->is_mapped) {
-                l_block = (dap_chain_block_t*)( l_cell->map_pos += sizeof(uint64_t) );  // Switching to mapped area
-                l_cell->map_pos += a_atom_size;
-            }
-            ret = ATOM_ACCEPT;
+            int l_err = dap_chain_atom_save(a_chain, l_block->hdr.cell_id, a_atom, a_atom_size, a_atom_new ? &l_block_hash : NULL, (char**)&l_block);
+            dap_return_val_if_pass_err(l_err, ATOM_REJECT, "Can't save atom to file, code %d", l_err);
         }
 #endif
         l_block_cache = dap_chain_block_cache_new(&l_block_hash, l_block, a_atom_size, PVT(l_blocks)->blocks_count + 1, !a_chain->is_mapped);
-        if (!l_block_cache) {
-            log_it(L_DEBUG, "%s", "... corrupted block");
-            return ATOM_REJECT;
-        }
+        dap_return_val_if_fail_err(l_block_cache, dap_chain_net_get_load_mode(l_net) ? ATOM_CORRUPTED : ATOM_REJECT,
+                                   "Block %s is corrupted!", l_block_cache->block_hash_str);
         debug_if(s_debug_more, L_DEBUG, "... new block %s", l_block_cache->block_hash_str);
 
         pthread_rwlock_wrlock(& PVT(l_blocks)->rwlock);
@@ -1746,7 +1734,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
                 HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_block_cache->block_hash), l_block_cache);
                 debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", a_atom);
                 s_add_atom_datums(l_blocks, l_block_cache);
-                dap_chain_atom_notify(l_cell, &l_block_cache->block_hash, (byte_t*)l_block, a_atom_size);
+                dap_chain_atom_notify(a_chain, l_block->hdr.cell_id, &l_block_cache->block_hash, (byte_t*)l_block, a_atom_size);
                 dap_chain_atom_add_from_threshold(a_chain);
                 pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
 
@@ -1772,8 +1760,6 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
 #endif
                 return ATOM_ACCEPT;
             }
-
-
             for (size_t i = 0; i < PVT(l_blocks)->forked_br_cnt; i++){
                 dap_chain_block_forked_branch_t *l_cur_branch = PVT(l_blocks)->forked_branches[i];
                 dap_chain_block_forked_branch_atoms_table_t *l_last = HASH_LAST(l_cur_branch->forked_branch_atoms);
@@ -1788,7 +1774,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
                     l_block_cache->block_number = l_last->block_cache->block_number + 1;
                     HASH_ADD(hh, l_cur_branch->forked_branch_atoms, block_hash, sizeof(dap_hash_fast_t), l_new_item);
                     uint64_t l_main_branch_length = PVT(l_blocks)->blocks_count - l_cur_branch->connected_block->block_number;
-                    if (s_select_longest_branch(l_blocks, l_cur_branch->connected_block, l_main_branch_length, l_cell)){
+                    if ( s_select_longest_branch(l_blocks, l_cur_branch->connected_block, l_main_branch_length) ) {
                         dap_chain_block_cache_t *l_bcache_last = HASH_LAST(PVT(l_blocks)->blocks);
                         // Send it to notificator listeners
 #ifndef DAP_CHAIN_BLOCKS_TEST
@@ -1818,7 +1804,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
             ++PVT(l_blocks)->blocks_count;
             debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", a_atom);
             s_add_atom_datums(l_blocks, l_block_cache);
-            dap_chain_atom_notify(l_cell, &l_block_cache->block_hash, (byte_t*)l_block, a_atom_size);
+            dap_chain_atom_notify(a_chain, l_block->hdr.cell_id, &l_block_cache->block_hash, (byte_t*)l_block, a_atom_size);
             dap_chain_atom_add_from_threshold(a_chain);
             pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
             return ret;
@@ -1843,15 +1829,8 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
     case ATOM_FORK:{
 #ifndef DAP_CHAIN_BLOCKS_TEST
         if ( !dap_chain_net_get_load_mode( dap_chain_net_by_id(a_chain->net_id)) ) {
-            dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_chain, l_block->hdr.cell_id);
-            if ( (ret = dap_chain_atom_save(l_cell, a_atom, a_atom_size, a_atom_new ? &l_block_hash : NULL)) < 0 ) {
-                log_it(L_ERROR, "Can't save atom to file, code %d", ret);
-                return ATOM_REJECT;
-            } else if (a_chain->is_mapped) {
-                l_block = (dap_chain_block_t*)( l_cell->map_pos += sizeof(uint64_t) );  // Switching to mapped area
-                l_cell->map_pos += a_atom_size;
-            }
-            dap_chain_cell_remit(l_cell);
+            int l_err = dap_chain_atom_save(a_chain, l_block->hdr.cell_id, a_atom, a_atom_size, a_atom_new ? &l_block_hash : NULL, (char**)&l_block);
+            dap_return_val_if_pass_err(l_err, ATOM_REJECT, "Can't save atom to file, code %d", l_err);
             ret = ATOM_FORK;
         }
 #endif
@@ -1892,6 +1871,9 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
     case ATOM_PASS:
         debug_if(s_debug_more, L_DEBUG, "... %s is already present", dap_chain_hash_fast_to_str_static(&l_block_hash));
         break;
+    case ATOM_CORRUPTED:
+        debug_if(s_debug_more, L_DEBUG, "... atom is corrupted.%s", dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id))
+            ? " The file will be truncated!" : "");
     default:
         debug_if(s_debug_more, L_DEBUG, "Unknown verification ret code %d", ret);
         break;
@@ -1909,6 +1891,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
 static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t *a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_chain_hash_fast_t *a_atom_hash)
 {
     dap_return_val_if_fail(a_chain && a_atom && a_atom_size && a_atom_hash, ATOM_REJECT);
+    bool l_load_mode = dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id));
     dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
     assert(l_blocks);
     dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(l_blocks);
@@ -1917,14 +1900,14 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t *a_chain,
     dap_chain_hash_fast_t l_block_hash = *a_atom_hash;
 
     if (sizeof(l_block->hdr) >= a_atom_size) {
-        log_it(L_WARNING, "Size of block %s is %zd that is equal or less then block's header size %zd",
+        log_it(L_WARNING, "Block %s size %zd <= block header size %zd",
                                 dap_hash_fast_to_str_static(a_atom_hash), a_atom_size, sizeof(l_block->hdr));
-        return ATOM_REJECT;
+        return l_load_mode ? ATOM_CORRUPTED : ATOM_REJECT;
     }
     size_t l_offset = dap_chain_block_get_sign_offset(l_block, a_atom_size);
     if (!l_offset) {
         log_it(L_WARNING, "Block %s with size %zu parsing error", dap_hash_fast_to_str_static(a_atom_hash), a_atom_size);
-        return ATOM_REJECT;
+        return l_load_mode ? ATOM_CORRUPTED : ATOM_REJECT;
     }
     if ((l_block->hdr.version >= 2 || /* Old bug, crutch for it */ l_block->hdr.meta_n_datum_n_signs_size != l_offset) &&
             l_block->hdr.meta_n_datum_n_signs_size + sizeof(l_block->hdr) != a_atom_size) {
@@ -1934,7 +1917,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t *a_chain,
         if (!l_hash_found) {
             log_it(L_WARNING, "Incorrect size %zu of block %s, expected %zu", l_block->hdr.meta_n_datum_n_signs_size + sizeof(l_block->hdr),
                                                                     dap_hash_fast_to_str_static(a_atom_hash), a_atom_size);
-            return ATOM_REJECT;
+            return l_load_mode ? ATOM_CORRUPTED : ATOM_REJECT;
         }
     }
     while (sizeof(l_block->hdr) + l_offset + sizeof(dap_sign_t) < a_atom_size) {
@@ -1951,7 +1934,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t *a_chain,
         if (!l_hash_found) {
             log_it(L_WARNING, "Incorrect size %zu of block %s, expected %zu", l_offset + sizeof(l_block->hdr),
                                                                     dap_hash_fast_to_str_static(a_atom_hash), a_atom_size);
-            return ATOM_REJECT;
+            return l_load_mode ? ATOM_CORRUPTED : ATOM_REJECT;
         }
     }
 
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index 431f3f0b90..e52d88fd87 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -78,14 +78,11 @@ typedef struct dap_chain_cs_dag_blocked {
 
 typedef struct dap_chain_cs_dag_pvt {
     pthread_mutex_t events_mutex;
-    dap_chain_cs_dag_event_item_t * 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_event_item_t *events_prefetched, *events, *events_treshold, *events_treshold_conflicted, *events_lasts_unlinked, *datums;
     dap_chain_cs_dag_blocked_t *removed_events_from_treshold;
     dap_interval_timer_t treshold_free_timer;
     uint64_t tx_count;
+    bool need_reorder;
 } dap_chain_cs_dag_pvt_t;
 
 #define PVT(a) ((dap_chain_cs_dag_pvt_t *) a->_pvt )
@@ -97,7 +94,9 @@ static void s_threshold_free(dap_chain_cs_dag_t *a_dag);
 static dap_chain_cs_dag_event_item_t *s_dag_proc_treshold(dap_chain_cs_dag_t *a_dag);
 
 // Atomic element organization callbacks
-static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t *a_atom_hash, bool a_atom_new);                      //    Accept new event in dag
+static dap_chain_atom_verify_res_t s_chain_callback_atom_read(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t *a_atom_hash);
+static unsigned s_chain_callback_prefetched_atoms_add(dap_chain_t *a_chain);
+static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t *a_atom_hash, bool a_atom_new); //    Accept new event in dag
 static dap_chain_atom_ptr_t s_chain_callback_atom_add_from_treshold(dap_chain_t * a_chain, size_t *a_event_size_out);                    //    Accept new event in dag from treshold
 static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t * a_chain, dap_chain_atom_ptr_t , size_t, dap_hash_fast_t *a_atom_hash);                   //    Verify new event in dag
 static size_t s_chain_callback_atom_get_static_hdr_size(void);                               //    Get dag event header size
@@ -213,7 +212,10 @@ static int s_chain_cs_dag_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     pthread_mutexattr_destroy(&l_mutex_attr);
 
     // Atom element callbacks
+
+    a_chain->callback_atom_prefetch = s_chain_callback_atom_read; // Prefetching
     a_chain->callback_atom_add = s_chain_callback_atom_add ;  // Accept new element in chain
+    a_chain->callback_atoms_prefetched_add = s_chain_callback_prefetched_atoms_add;
     a_chain->callback_atom_add_from_treshold = s_chain_callback_atom_add_from_treshold;  // Accept new elements in chain from treshold
     a_chain->callback_atom_verify = s_chain_callback_atom_verify ;  // Verify new element in chain
     a_chain->callback_atom_get_hdr_static_size = s_chain_callback_atom_get_static_hdr_size; // Get dag event hdr size
@@ -400,20 +402,11 @@ static int s_chain_cs_dag_delete(dap_chain_t * a_chain)
 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 (!l_datum) {
-        log_it(L_WARNING, "Corrupted event, failed to extract datum from event.");
-        return -2;
-    }
-    if(a_event_item->event_size < sizeof(l_datum->header) ){
-        log_it(L_WARNING, "Corrupted event, too small to fit datum in it");
-        return -1;
-    }
-    size_t l_datum_size = dap_chain_datum_size(l_datum);
-    size_t l_datum_size_max = dap_chain_cs_dag_event_get_datum_size_maximum(a_event_item->event, a_event_item->event_size);
-    if(l_datum_size >l_datum_size_max ){
-        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_return_val_if_fail_err( l_datum, -2, "Corrupted event, failed to extract datum" );
+    dap_return_val_if_pass_err( a_event_item->event_size < sizeof(l_datum->header), -1, "Corrupted event, size too small");
+    size_t l_datum_size = dap_chain_datum_size(l_datum),
+        l_datum_size_max = dap_chain_cs_dag_event_get_datum_size_maximum(a_event_item->event, a_event_item->event_size);
+    dap_return_val_if_pass_err( l_datum_size > l_datum_size_max, -1, "Event size exeeds max size permitted, %zd > %zd", l_datum_size, l_datum_size_max );
     dap_hash_fast_t l_datum_hash;
     dap_chain_datum_calc_hash(l_datum, &l_datum_hash);
     int l_ret = dap_chain_datum_add(a_dag->chain, l_datum, l_datum_size, &l_datum_hash, NULL);
@@ -432,12 +425,9 @@ static int s_dap_chain_add_atom_to_events_table(dap_chain_cs_dag_t *a_dag, dap_c
         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);
-    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_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");
-    }
+    debug_if(s_debug_more, L_INFO, "Dag event %s checked, ret code %d : %s",
+             dap_chain_hash_fast_to_str_static(&a_event_item->hash), l_ret,
+             l_ret ? dap_chain_net_verify_datum_err_code_to_str(l_datum, l_ret) : "Ok");
     return l_ret;
 }
 
@@ -454,6 +444,71 @@ static int s_sort_event_item(dap_chain_cs_dag_event_item_t* a, dap_chain_cs_dag_
     return a->ts_created < b->ts_created ? -1 : a->ts_created == b->ts_created ? 0 : 1;
 }
 
+static dap_chain_atom_verify_res_t s_dag_event_integrity_check(dap_chain_cs_dag_t *a_dag, uint64_t a_chain_id, dap_chain_cs_dag_event_t *a_event,
+                                                               size_t a_event_size, dap_chain_hash_fast_t *a_atom_hash)
+{
+    dap_return_val_if_pass_err( a_event_size < sizeof(dap_chain_cs_dag_event_t), ATOM_CORRUPTED,
+                                "Too small event size %zu", a_event_size );
+    dap_return_val_if_pass_err( a_event->header.version, ATOM_CORRUPTED,
+                                "Unsupported event version %u", a_event->header.version );
+    dap_return_val_if_fail_err( a_event->header.chain_id.uint64 == a_chain_id, ATOM_CORRUPTED,
+                                "Wrong chain id %zu", a_event->header.chain_id.uint64 );
+    if ( a_dag->hal ) {
+        dap_chain_cs_dag_hal_item_t *l_hash_search = NULL;
+        HASH_FIND(hh, a_dag->hal, a_atom_hash, sizeof(*a_atom_hash), l_hash_search);
+        if (l_hash_search)
+            return ATOM_ACCEPT;
+    }
+    size_t l_atom_size = dap_chain_cs_dag_event_calc_size(a_event, a_event_size);
+    dap_return_val_if_fail_err( l_atom_size == a_event_size, ATOM_CORRUPTED,
+                                "Invalid event size, %zu != %zu", l_atom_size, a_event_size );
+    return ATOM_PASS;
+}
+
+static dap_chain_atom_verify_res_t s_chain_callback_atom_read(dap_chain_t *a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_chain_hash_fast_t *a_atom_hash)
+{
+    dap_chain_cs_dag_t *l_dag = DAP_CHAIN_CS_DAG(a_chain);
+    dap_chain_cs_dag_event_t *l_event = (dap_chain_cs_dag_event_t*)a_atom, *l_tmp;
+    dap_chain_atom_verify_res_t l_verif = s_dag_event_integrity_check(l_dag, a_chain->id.uint64, l_event, a_atom_size, a_atom_hash);
+    dap_return_val_if_pass_err( l_verif == ATOM_CORRUPTED, l_verif, "Event %s is corrupted", dap_hash_fast_to_str_static(a_atom_hash) );
+
+    dap_chain_cs_dag_event_item_t *l_event_item = NULL;
+    unsigned hashval = 0;
+    static dap_time_t l_last_ts = 0;
+    HASH_VALUE(a_atom_hash, sizeof(*a_atom_hash), hashval);
+    HASH_FIND_BYHASHVALUE(hh, PVT(l_dag)->events_prefetched, a_atom_hash, sizeof(*a_atom_hash), hashval, l_event_item);
+    if (!l_event_item) {
+        l_event_item = DAP_NEW(dap_chain_cs_dag_event_item_t);
+        *l_event_item = (dap_chain_cs_dag_event_item_t) {
+            .hash       = *a_atom_hash,
+            .event      = a_chain->is_mapped ? l_event : DAP_DUP_SIZE(l_event, a_atom_size),
+            .event_size = a_atom_size,
+            .ts_created = l_event->header.ts_created
+        };
+        HASH_ADD_BYHASHVALUE(hh, PVT(l_dag)->events_prefetched, hash, sizeof(*a_atom_hash), hashval, l_event_item);
+        if ( l_last_ts > l_event_item->ts_created )
+            PVT(l_dag)->need_reorder = true;
+        l_last_ts = l_event_item->ts_created;
+    }
+    return ATOM_ACCEPT;
+}
+
+static unsigned s_chain_callback_prefetched_atoms_add(dap_chain_t *a_chain) {
+    dap_chain_cs_dag_t *l_dag = DAP_CHAIN_CS_DAG(a_chain);
+    if ( PVT(l_dag)->need_reorder ) {
+        HASH_SORT( PVT(l_dag)->events_prefetched, s_sort_event_item );
+        PVT(l_dag)->need_reorder = false;
+    }
+    unsigned i = 0, q = HASH_COUNT(PVT(l_dag)->events_prefetched);
+    dap_chain_cs_dag_event_item_t *l_event_item, *l_tmp;
+    HASH_ITER(hh, PVT(l_dag)->events_prefetched, l_event_item, l_tmp) {
+        HASH_DEL(PVT(l_dag)->events_prefetched, l_event_item);
+        s_chain_callback_atom_add(a_chain, l_event_item->event, l_event_item->event_size, &l_event_item->datum_hash, false);
+        a_chain->load_progress = (int)((float)++i/q * 100 + 0.5);
+    }
+    return i;
+}
+
 /**
  * @brief s_chain_callback_atom_add Accept new event in dag
  * @param a_chain DAG object
@@ -463,20 +518,19 @@ static int s_sort_event_item(dap_chain_cs_dag_event_item_t* a, dap_chain_cs_dag_
  */
 static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_hash_fast_t *a_atom_hash, bool a_atom_new)
 {
-    dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG(a_chain);
-    dap_chain_cs_dag_event_t * l_event = (dap_chain_cs_dag_event_t *) a_atom;
+    dap_chain_cs_dag_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_hash_fast_t l_event_hash = *a_atom_hash;
-    debug_if(s_debug_more, L_DEBUG, "Processing event: %s ... (size %zd)",  dap_chain_hash_fast_to_str_static(&l_event_hash), a_atom_size);
+    debug_if(s_debug_more, L_DEBUG, "Processing event: %s ... (size %zd)",  dap_chain_hash_fast_to_str_static(a_atom_hash), a_atom_size);
     pthread_mutex_lock(&PVT(l_dag)->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_hash) ||
-            s_dap_chain_check_if_event_is_present(PVT(l_dag)->events_treshold, &l_event_hash) ? ATOM_PASS : ATOM_ACCEPT;
+    dap_chain_atom_verify_res_t ret = s_dap_chain_check_if_event_is_present(PVT(l_dag)->events, a_atom_hash) ||
+            s_dap_chain_check_if_event_is_present(PVT(l_dag)->events_treshold, a_atom_hash) ? ATOM_PASS : ATOM_ACCEPT;
 
     // verify hashes and consensus
     switch (ret) {
     case ATOM_ACCEPT:
-        ret = s_chain_callback_atom_verify(a_chain, a_atom, a_atom_size, &l_event_hash);
+        ret = s_chain_callback_atom_verify(a_chain, a_atom, a_atom_size, a_atom_hash);
         if (ret == ATOM_MOVE_TO_THRESHOLD) {
             if (!s_threshold_enabled /*&& !dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id))*/)
                 ret = ATOM_REJECT;
@@ -490,28 +544,30 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
     default:
         break;
     }
-    dap_chain_cs_dag_event_item_t *l_event_item = DAP_NEW_Z(dap_chain_cs_dag_event_item_t);
-    if ( !l_event_item ) {
-        log_it(L_CRITICAL, "%s", c_error_memory_alloc);
-        pthread_mutex_unlock(&PVT(l_dag)->events_mutex);
-        return ATOM_REJECT;
+    bool l_load_mode = dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id));
+    dap_chain_cs_dag_event_item_t *l_event_item;
+    if (l_load_mode) {
+        l_event_item = (dap_chain_cs_dag_event_item_t*)(a_atom_hash); // Guaranteed by C1x §6.7.2.1.13
+        l_event_item->ts_added = dap_time_now();
+    } else {
+        l_event_item = DAP_NEW(dap_chain_cs_dag_event_item_t);
+        *l_event_item = (dap_chain_cs_dag_event_item_t) {
+            .hash       = *a_atom_hash,
+            .ts_added   = dap_time_now(),
+            .event      = a_chain->is_mapped ? l_event : DAP_DUP_SIZE(l_event, a_atom_size),
+            .event_size = a_atom_size,
+            .ts_created = l_event->header.ts_created
+        };
     }
-    *l_event_item = (dap_chain_cs_dag_event_item_t) {
-        .hash       = l_event_hash,
-        .ts_added   = dap_time_now(),
-        .event      = a_chain->is_mapped ? l_event : DAP_DUP_SIZE(l_event, a_atom_size),
-        .event_size = a_atom_size,
-        .ts_created = l_event->header.ts_created
-    };
 
     switch (ret) {
     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_hash, sizeof(dap_chain_hash_fast_t), el);
+        HASH_FIND(hh, PVT(l_dag)->removed_events_from_treshold, a_atom_hash, sizeof(dap_chain_hash_fast_t), el);
         if (!el) {
-            if ( a_chain->is_mapped && dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id)) )
+            if ( a_chain->is_mapped && l_load_mode )
                 l_event_item->mapped_region = (char*)l_event;
-            HASH_ADD(hh, PVT(l_dag)->events_treshold, hash, sizeof(l_event_hash), l_event_item);
+            HASH_ADD(hh, PVT(l_dag)->events_treshold, hash, sizeof(*a_atom_hash), l_event_item);
             debug_if(s_debug_more, L_DEBUG, "... added to threshold");
         } else {
             ret = ATOM_REJECT;
@@ -520,15 +576,12 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
         break;
     }
     case ATOM_ACCEPT: {
-        dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_chain, l_event->header.cell_id);
-        if ( !dap_chain_net_get_load_mode( dap_chain_net_by_id(a_chain->net_id)) ) {
-            if ( dap_chain_atom_save(l_cell, a_atom, a_atom_size, a_atom_new ? &l_event_hash : NULL) < 0 ) {
-                log_it(L_ERROR, "Can't save atom to file");
+        if ( !l_load_mode ) {
+            int l_err = dap_chain_atom_save(a_chain, l_event->header.cell_id, a_atom, a_atom_size, a_atom_new ? a_atom_hash : NULL, (char**)&l_event_item->event);
+            if (l_err) {
+                log_it(L_ERROR, "Can't save atom to file, code %d", l_err);
                 ret = ATOM_REJECT;
                 break;
-            } else if (a_chain->is_mapped) {
-                l_event_item->event = (dap_chain_cs_dag_event_t*)( l_cell->map_pos += sizeof(uint64_t) );
-                l_cell->map_pos += a_atom_size;
             }
         }
         int l_consensus_check = s_dap_chain_add_atom_to_events_table(l_dag, l_event_item);
@@ -546,19 +599,9 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
             debug_if(s_debug_more, L_WARNING, "... added with ledger code %d", l_consensus_check);
             break;
         }
-        
-        dap_chain_cs_dag_event_item_t *l_tail = HASH_LAST(PVT(l_dag)->events);
-        if (l_tail && l_tail->ts_created > l_event->header.ts_created) {
-            DAP_CHAIN_PVT(a_chain)->need_reorder = true;
-        
-            HASH_ADD_INORDER(hh, PVT(l_dag)->events, hash, sizeof(l_event_item->hash), l_event_item, s_sort_event_item);
-            dap_chain_cs_dag_event_item_t *it = PVT(l_dag)->events;
-            for (uint64_t i = 0; it; it = it->hh.next)  // renumber chain events
-                it->event_number = ++i;
-        } 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);
-        dap_chain_atom_notify(l_cell, &l_event_item->hash, (const byte_t*)l_event_item->event, l_event_item->event_size);
+        dap_chain_atom_notify(l_dag->chain, l_event_item->event->header.cell_id, &l_event_item->hash, (const byte_t*)l_event_item->event, l_event_item->event_size);
         dap_chain_atom_add_from_threshold(a_chain);
     } break;
     default:
@@ -745,60 +788,39 @@ dap_chain_cs_dag_event_t* dap_chain_cs_dag_find_event_by_hash(dap_chain_cs_dag_t
  */
 static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t *a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_chain_hash_fast_t *a_atom_hash)
 {
-    dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG(a_chain);
-    dap_chain_cs_dag_event_t * l_event = (dap_chain_cs_dag_event_t *) a_atom;
-    dap_chain_atom_verify_res_t res = ATOM_ACCEPT;
-    pthread_mutex_t *l_events_mutex = &PVT(l_dag)->events_mutex;
-    if (a_atom_size < sizeof(dap_chain_cs_dag_event_t)) {
-        log_it(L_WARNING, "Too small event size %zu, less than event header", a_atom_size);
-        return ATOM_REJECT;
-    }
-    if (l_event->header.version) {
-        log_it(L_WARNING, "Unsupported event version, possible corrupted event");
-        return ATOM_REJECT;
-    }
-    if (l_event->header.chain_id.uint64 != a_chain->id.uint64) {
-        log_it(L_WARNING, "Event from another chain, possible corrupted event");
-        return ATOM_REJECT;
-    }
-    dap_chain_hash_fast_t l_event_hash = *a_atom_hash;
-    // Hard accept list
-    if (l_dag->hal) {
-        dap_chain_cs_dag_hal_item_t *l_hash_found = NULL;
-        pthread_mutex_lock(l_events_mutex);
-        HASH_FIND(hh, l_dag->hal, &l_event_hash, sizeof(l_event_hash), l_hash_found);
-        pthread_mutex_unlock(l_events_mutex);
-        if (l_hash_found) {
+    dap_chain_cs_dag_event_t *l_event = (dap_chain_cs_dag_event_t*)a_atom;
+    dap_chain_cs_dag_t *l_dag = DAP_CHAIN_CS_DAG(a_chain);
+    if ( dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id)) ) {
+        if ( l_dag->hal ) {
+            /* We should check HAL twice, because we can't tell HAL'ed event from passed after prefetching */
+            dap_chain_cs_dag_hal_item_t *l_hash_search = NULL;
+            HASH_FIND(hh, l_dag->hal, a_atom_hash, sizeof(*a_atom_hash), l_hash_search);
+            if (l_hash_search)
+                return ATOM_ACCEPT;
+        }
+    } else
+        switch ( s_dag_event_integrity_check(l_dag, a_chain->id.uint64, l_event, a_atom_size, a_atom_hash) ) {
+        case ATOM_ACCEPT:
             return ATOM_ACCEPT;
+        case ATOM_CORRUPTED:
+            return ATOM_REJECT;
+        default:
+            break;
         }
-    }
-    size_t l_atom_size = dap_chain_cs_dag_event_calc_size(l_event, a_atom_size);
-    if (l_atom_size != a_atom_size) {
-        log_it(L_WARNING, "Event size %zu not equal to expected %zu", l_atom_size, a_atom_size);
-        return  ATOM_REJECT;
-    }
-
+    dap_chain_atom_verify_res_t res = ATOM_ACCEPT;
+    pthread_mutex_t *l_events_mutex = &PVT(l_dag)->events_mutex;
     // genesis or seed mode
-    if (l_event->header.hash_count == 0){
-        if(s_seed_mode && !PVT(l_dag)->events){
-            log_it(L_NOTICE,"Accepting genesis event");
+    if ( !l_event->header.hash_count ) {
+        if ( s_seed_mode ) /* TODO: lock with mutex too. Is this yet used?...*/
+            return PVT(l_dag)->events
+                ? log_it(L_NOTICE,"Treating event %s as genesis. Time to turn seed mode off!", dap_hash_fast_to_str_static(a_atom_hash)), ATOM_ACCEPT
+                : ( log_it(L_ERROR, "Genesis event is already present! Turn off seed mode and try again!"), ATOM_REJECT );
+        if ( l_dag->is_static_genesis_event ) {
+            dap_return_val_if_pass_err( memcmp( a_atom_hash, &l_dag->static_genesis_event_hash, sizeof(*a_atom_hash) ),
+                                        /* l_load_mode ? ATOM_CORRUPTED : */ ATOM_REJECT, "Wrong genesis event: preconfigured \"%s\" != \"%s\"",
+                                        dap_hash_fast_to_str_static(&l_dag->static_genesis_event_hash), dap_hash_fast_to_str_static(a_atom_hash) );
+            debug_if(s_debug_more, L_INFO, "Accepting static genesis event \"%s\"", dap_hash_fast_to_str_static(a_atom_hash));
             return ATOM_ACCEPT;
-        }else if(s_seed_mode){
-            log_it(L_WARNING,"Cant accept genesis event: already present data in DAG, ->events is not NULL");
-            return  ATOM_REJECT;
-        }
-
-        if (l_dag->is_static_genesis_event ){
-            if ( memcmp( &l_event_hash, &l_dag->static_genesis_event_hash, sizeof(l_event_hash) ) != 0 ){
-                char l_event_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE], l_genesis_event_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
-                dap_chain_hash_fast_to_str(&l_event_hash, l_event_hash_str, sizeof(l_event_hash_str));
-                dap_chain_hash_fast_to_str(&l_dag->static_genesis_event_hash, l_genesis_event_hash_str, sizeof(l_genesis_event_hash_str));
-                log_it(L_WARNING, "Wrong genesis event %s (staticly predefined %s)",l_event_hash_str, l_genesis_event_hash_str);
-                return ATOM_REJECT;
-            } else {
-                debug_if(s_debug_more, L_INFO, "Accepting static genesis event");
-                return ATOM_ACCEPT;
-            }
         }
     }
 
@@ -821,10 +843,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_verify(dap_chain_t *a_c
     }
 
     //consensus
-    if (res == ATOM_ACCEPT && l_dag->callback_cs_verify(l_dag, l_event, a_atom_hash))
-        res = ATOM_REJECT;
-
-    return res;
+    return res == ATOM_ACCEPT && l_dag->callback_cs_verify(l_dag, l_event, a_atom_hash) ? ATOM_REJECT : res;
 }
 
 /**
@@ -937,16 +956,13 @@ dap_chain_cs_dag_event_item_t* s_dag_proc_treshold(dap_chain_cs_dag_t * a_dag)
         if (ret == DAP_THRESHOLD_OK) {
             debug_if(s_debug_more, L_DEBUG, "Processing event (threshold): %s...",
                     dap_chain_hash_fast_to_str_static(&l_event_item->hash));
-            dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(a_dag->chain, l_event_item->event->header.cell_id);
             if ( !l_event_item->mapped_region ) {
-                if ( dap_chain_atom_save(l_cell, (const byte_t*)l_event_item->event, l_event_item->event_size, NULL) < 0 ) {
-                    log_it(L_CRITICAL, "Can't move atom from threshold to file");
+                int l_err = dap_chain_atom_save(a_dag->chain, l_event_item->event->header.cell_id, (const byte_t*)l_event_item->event,
+                                                l_event_item->event_size, NULL, (char**)&l_event_item->event);
+                if (l_err)
+                    log_it(L_CRITICAL, "Can't move atom from threshold to file, code %d", l_err);
                     res = false;
                     break;
-                } else if (a_dag->chain->is_mapped) {
-                    l_event_item->event = (dap_chain_cs_dag_event_t*)( l_cell->map_pos += sizeof(uint64_t) );
-                    l_cell->map_pos += l_event_item->event_size;
-                }
             }
             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);
@@ -954,7 +970,7 @@ dap_chain_cs_dag_event_item_t* s_dag_proc_treshold(dap_chain_cs_dag_t * a_dag)
                 HASH_ADD(hh, PVT(a_dag)->events, hash, sizeof(l_event_item->hash), l_event_item);
                 s_dag_events_lasts_process_new_last_event(a_dag, l_event_item);
                 debug_if(s_debug_more, L_INFO, "... moved from threshold to chain");
-                dap_chain_atom_notify(l_cell, &l_event_item->hash, (byte_t*)l_event_item->event, l_event_item->event_size);
+                dap_chain_atom_notify(a_dag->chain, l_event_item->event->header.cell_id, &l_event_item->hash, (byte_t*)l_event_item->event, l_event_item->event_size);
                 res = true;
             } else {
                 // TODO clear other threshold items linked with this one
@@ -1428,7 +1444,7 @@ static int s_cli_dag(int argc, char ** argv, void **a_str_reply)
                 }
             }
             // write events to file and delete events from db
-            if(l_list_to_del) {
+            /* if(l_list_to_del) {
                 if (dap_chain_cell_file_update(l_chain->cells) > 0) {
                     // delete events from db
                     dap_list_t *l_el;
@@ -1438,7 +1454,7 @@ static int s_cli_dag(int argc, char ** argv, void **a_str_reply)
                 }
                 dap_chain_cell_close(l_chain->cells);
                 dap_list_free(l_list_to_del);
-            }
+            } */ // TODO!
 
             // Cleaning up
             dap_global_db_objs_delete(l_objs, l_objs_size);
-- 
GitLab


From 9db9eff68591179b8886e5d92d8be9ec23a08f7c Mon Sep 17 00:00:00 2001
From: "Constantin P." <papizh.konstantin@demlabs.net>
Date: Tue, 18 Feb 2025 12:52:20 +0700
Subject: [PATCH 07/11] Build fix

---
 dap-sdk                                       |  2 +-
 modules/chain/dap_chain_cell.c                | 25 ++++++++++---------
 .../consensus/esbocs/dap_chain_cs_esbocs.c    |  2 +-
 modules/ledger/dap_chain_ledger.c             | 10 +++++---
 modules/net/dap_chain_net.c                   |  2 +-
 .../dap_chain_net_srv_emit_delegate.c         |  2 +-
 modules/type/dag/dap_chain_cs_dag.c           |  3 ++-
 7 files changed, 25 insertions(+), 21 deletions(-)

diff --git a/dap-sdk b/dap-sdk
index 64b2cd4990..825fe16538 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 64b2cd4990a59c3af91e8f1402d4cfd468bd90bc
+Subproject commit 825fe16538c62b1c4732b16a415c9cb966ff6085
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index 7df6254238..46236b6d1b 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -221,6 +221,7 @@ DAP_STATIC_INLINE int s_cell_close(dap_chain_cell_t *a_cell) {
     }
     //pthread_rwlock_unlock(&a_cell->storage_rwlock);
     //pthread_rwlock_destroy(&a_cell->storage_rwlock);
+    return 0;
 }
 
 /**
@@ -236,8 +237,8 @@ void dap_chain_cell_close(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_id)
                                     a_cell_id.uint64, a_chain->net_name, a_chain->name);
     s_cell_close(l_cell);
     HASH_DEL(a_chain->cells, l_cell);
-    DAP_DELETE(l_cell);
     dap_chain_cell_remit(l_cell);
+    DAP_DELETE(l_cell);
 }
 
 void dap_chain_cell_close_all(dap_chain_t *a_chain) {
@@ -295,11 +296,11 @@ DAP_STATIC_INLINE int s_cell_load_from_file(dap_chain_cell_t *a_cell)
     dap_chain_atom_ptr_t l_atom;
     dap_hash_fast_t l_atom_hash;
     if (a_cell->chain->is_mapped) {
-        for ( off_t l_vol_rest = 0; l_pos + sizeof(uint64_t) < l_full_size; ++q, l_pos += sizeof(uint64_t) + l_el_size ) {
+        for ( off_t l_vol_rest = 0; l_pos + sizeof(uint64_t) < (size_t)l_full_size; ++q, l_pos += sizeof(uint64_t) + l_el_size ) {
             l_vol_rest = (off_t)( a_cell->mapping->volume->base + a_cell->mapping->volume->size - a_cell->mapping->cursor - sizeof(uint64_t) );
-            if ( l_vol_rest <= 0 || (uint64_t)l_vol_rest < ( l_el_size = *(uint64_t*)a_cell->mapping->cursor ) )
+            if ( l_vol_rest <= 0 || l_vol_rest < ( l_el_size = *(uint64_t*)a_cell->mapping->cursor ) )
                 dap_return_val_if_pass_err( s_cell_map_new_volume(a_cell, l_pos, true), -7, "Error on mapping a new volume" );
-            if ( !l_el_size || l_el_size > (size_t)(l_full_size - l_pos) )
+            if ( !l_el_size || l_el_size > l_full_size - l_pos )
                 break;
             l_atom = (dap_chain_atom_ptr_t)(a_cell->mapping->cursor + sizeof(uint64_t));
             dap_hash_fast(l_atom, l_el_size, &l_atom_hash);
@@ -307,7 +308,7 @@ DAP_STATIC_INLINE int s_cell_load_from_file(dap_chain_cell_t *a_cell)
                 ? a_cell->chain->callback_atom_prefetch(a_cell->chain, l_atom, l_el_size, &l_atom_hash)
                 : a_cell->chain->callback_atom_add(a_cell->chain, l_atom, l_el_size, &l_atom_hash, false);
             if ( l_verif == ATOM_CORRUPTED ) {
-                log_it(L_ERROR, "Atom #%d is corrupted, can't proceed with loading chain \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
+                log_it(L_ERROR, "Atom #%ld is corrupted, can't proceed with loading chain \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
                                 q, a_cell->chain->net_name, a_cell->chain->name, a_cell->id.uint64);
                 l_ret = 8;
                 break;
@@ -335,7 +336,7 @@ DAP_STATIC_INLINE int s_cell_load_from_file(dap_chain_cell_t *a_cell)
                 break;
             }
             l_read = fread((void*)l_atom, 1, l_el_size, a_cell->file_storage);
-            if (l_read != l_el_size) {
+            if (l_read != (size_t)l_el_size) {
                 log_it(L_ERROR, "Read only %lu of %zu bytes, stop cell loading", l_read, l_el_size);
                 DAP_DELETE(l_atom);
                 l_ret = 10;
@@ -347,7 +348,7 @@ DAP_STATIC_INLINE int s_cell_load_from_file(dap_chain_cell_t *a_cell)
                 : a_cell->chain->callback_atom_add(a_cell->chain, l_atom, l_el_size, &l_atom_hash, false);
             DAP_DELETE(l_atom);
             if ( l_verif == ATOM_CORRUPTED ) {
-                log_it(L_ERROR, "Atom #%d is corrupted, can't proceed with loading chain \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
+                log_it(L_ERROR, "Atom #%ld is corrupted, can't proceed with loading chain \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
                                 q, a_cell->chain->net_name, a_cell->chain->name, a_cell->id.uint64);
                 l_ret = 11;
                 break;
@@ -383,7 +384,7 @@ DAP_STATIC_INLINE int s_cell_open(dap_chain_t *a_chain, const char *a_filename,
     dap_chain_cell_id_t l_cell_id = { };
     { /* Check filename */
         char l_fmt[20] = "", l_ext[ sizeof(CELL_FILE_EXT) ] = "", l_ext2 = '\0';
-        snprintf(l_fmt, sizeof(l_fmt), "%s%d%s", "%"DAP_UINT64_FORMAT_x".%", sizeof(CELL_FILE_EXT) - 1, "[^.].%c");
+        snprintf(l_fmt, sizeof(l_fmt), "%s%lu%s", "%"DAP_UINT64_FORMAT_x".%", sizeof(CELL_FILE_EXT) - 1, "[^.].%c");
 
         switch ( sscanf(a_filename, l_fmt, &l_cell_id.uint64, l_ext, &l_ext2) ) {
         case 3:
@@ -478,19 +479,19 @@ static int s_cell_file_atom_add(dap_chain_cell_t *a_cell, dap_chain_atom_ptr_t a
     if (a_cell->chain->is_mapped) {
         off_t l_pos = !fseeko(a_cell->file_storage, 0, SEEK_END) ? ftello(a_cell->file_storage) : -1;
         dap_return_val_if_pass_err(l_pos < 0, -1, "Can't get \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X" size, error %d",
-                                                     a_cell->chain->net_name, a_cell->chain->name, a_cell->id, errno);
+                                                     a_cell->chain->net_name, a_cell->chain->name, a_cell->id.uint64, errno);
         if ( a_atom_size + sizeof(uint64_t) > (size_t)(a_cell->mapping->volume->base + a_cell->mapping->volume->size - a_cell->mapping->cursor) )
             dap_return_val_if_pass_err(
                 s_cell_map_new_volume(a_cell, l_pos, false), 
                 -2, "Failed to create new map volume for \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X"",
-                a_cell->chain->net_name, a_cell->chain->name, a_cell->id
+                a_cell->chain->net_name, a_cell->chain->name, a_cell->id.uint64
             );
     }
     dap_return_val_if_fail_err(
         fwrite(&a_atom_size, sizeof(a_atom_size), 1, a_cell->file_storage) == 1 &&
         fwrite(a_atom,       a_atom_size,         1, a_cell->file_storage) == 1,
         -3, "Can't write atom [%zu b] to \"%s : %s\" cell 0x%016"DAP_UINT64_FORMAT_X", error %d: \"%s\"",
-            a_atom_size, a_cell->chain->net_name, a_cell->chain->name, a_cell->id, errno, dap_strerror(errno)
+            a_atom_size, a_cell->chain->net_name, a_cell->chain->name, a_cell->id.uint64, errno, dap_strerror(errno)
     );
     fflush(a_cell->file_storage);
 
@@ -532,7 +533,7 @@ int dap_chain_cell_file_append(dap_chain_t *a_chain, dap_chain_cell_id_t a_cell_
     dap_return_val_if_fail(a_atom && a_atom_size && a_chain, -1);
     dap_chain_cell_t *l_cell = dap_chain_cell_capture_by_id(a_chain, a_cell_id);
     dap_return_val_if_fail_err(l_cell, -2, "Cell #%"DAP_UINT64_FORMAT_x" not found in chain \"%s : %s\"",
-                                            a_cell_id, a_chain->net_name, a_chain->name);
+                                            a_cell_id.uint64, a_chain->net_name, a_chain->name);
     //pthread_rwlock_wrlock(&l_cell->storage_rwlock);
     int l_err = s_cell_file_atom_add(l_cell, a_atom, a_atom_size, a_atom_map);
     if (l_err)
diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index 0c0668acb6..b642862d4d 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -264,7 +264,7 @@ static int s_callback_new(dap_chain_t *a_chain, dap_config_t *a_chain_cfg)
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
     int l_dot_pos = strlen(l_auth_certs_prefix), l_len = l_dot_pos + 16, l_pos2 = 0;
     char l_cert_name[l_len];
-    strncpy(l_cert_name, l_auth_certs_prefix, l_dot_pos);
+    dap_strncpy(l_cert_name, l_auth_certs_prefix, l_dot_pos);
     for (i = 0; i < l_auth_certs_count; ++i) {
         dap_cert_t *l_cert_cur;
         l_pos2 = snprintf(l_cert_name + l_dot_pos, 16, ".%u", i);
diff --git a/modules/ledger/dap_chain_ledger.c b/modules/ledger/dap_chain_ledger.c
index 2b6b213fb9..b4a8535db7 100644
--- a/modules/ledger/dap_chain_ledger.c
+++ b/modules/ledger/dap_chain_ledger.c
@@ -246,10 +246,12 @@ static dap_ledger_t *dap_ledger_handle_new(void)
 {
     dap_ledger_t *l_ledger = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_ledger_t, NULL);
     dap_ledger_private_t *l_ledger_pvt = l_ledger->_internal = DAP_NEW_Z_RET_VAL_IF_FAIL(dap_ledger_private_t, NULL, l_ledger);
-
-    l_ledger_pvt->ledger_rwlock = l_ledger_pvt->tokens_rwlock = l_ledger_pvt->threshold_txs_rwlock
-        = l_ledger_pvt->balance_accounts_rwlock = l_ledger_pvt->stake_lock_rwlock = l_ledger_pvt->rewards_rwlock
-        = PTHREAD_RWLOCK_INITIALIZER;
+    pthread_rwlock_init(&l_ledger_pvt->ledger_rwlock, NULL);
+    pthread_rwlock_init(&l_ledger_pvt->tokens_rwlock, NULL);
+    pthread_rwlock_init(&l_ledger_pvt->threshold_txs_rwlock, NULL);
+    pthread_rwlock_init(&l_ledger_pvt->balance_accounts_rwlock, NULL);
+    pthread_rwlock_init(&l_ledger_pvt->stake_lock_rwlock, NULL);
+    pthread_rwlock_init(&l_ledger_pvt->rewards_rwlock, NULL);
     return l_ledger;
 }
 
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 72ea0e13f2..3cf22a25ad 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -815,7 +815,7 @@ void dap_chain_net_load_all()
         l_nets_count = i;
     }
     for ( i = 0; i < l_nets_count; l_err = pthread_join(l_tids[i++], NULL) ) {
-        debug_if(l_err, L_ERROR, "Thread %d join error %d: \"%s\"", l_err, dap_strerror(l_err));
+        debug_if(l_err, L_ERROR, "Thread %d join error %d: \"%s\"", i, l_err, dap_strerror(l_err));
     }
     dap_timerfd_delete(l_load_notify_timer->worker, l_load_notify_timer->esocket_uuid);
 }
diff --git a/modules/service/emit-delegate/dap_chain_net_srv_emit_delegate.c b/modules/service/emit-delegate/dap_chain_net_srv_emit_delegate.c
index a10cf022ac..4b2e0769f3 100644
--- a/modules/service/emit-delegate/dap_chain_net_srv_emit_delegate.c
+++ b/modules/service/emit-delegate/dap_chain_net_srv_emit_delegate.c
@@ -415,7 +415,7 @@ static dap_chain_datum_tx_t *s_taking_tx_sign(json_object *a_json_arr_reply, dap
         m_sign_fail(ERROR_TX_MISMATCH, "Requested conditional transaction restrict provided sign key");
     size_t l_my_pkey_size = 0;
     byte_t *l_my_pkey = dap_enc_key_serialize_pub_key(a_enc_key, &l_my_pkey_size);
-    if (l_my_pkey)
+    if (!l_my_pkey)
         m_sign_fail(ERROR_COMPOSE, "Can't serialize sign public key");
     size_t l_tsd_hashes_count = l_cond->tsd_size / (sizeof(dap_tsd_t) + sizeof(dap_hash_fast_t));
     size_t l_signs_limit = l_tsd_hashes_count * 2;
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index e52d88fd87..c4421022f9 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -959,10 +959,11 @@ dap_chain_cs_dag_event_item_t* s_dag_proc_treshold(dap_chain_cs_dag_t * a_dag)
             if ( !l_event_item->mapped_region ) {
                 int l_err = dap_chain_atom_save(a_dag->chain, l_event_item->event->header.cell_id, (const byte_t*)l_event_item->event,
                                                 l_event_item->event_size, NULL, (char**)&l_event_item->event);
-                if (l_err)
+                if (l_err) {
                     log_it(L_CRITICAL, "Can't move atom from threshold to file, code %d", l_err);
                     res = false;
                     break;
+                }
             }
             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);
-- 
GitLab


From 982ef4ef7568490ce36e068b1a22ccbe5134b3e0 Mon Sep 17 00:00:00 2001
From: "Constantin P." <papizh.konstantin@demlabs.net>
Date: Tue, 18 Feb 2025 13:56:54 +0700
Subject: [PATCH 08/11] ...

---
 modules/type/blocks/dap_chain_cs_blocks.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index ccf9d057f6..684248faa7 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -1728,8 +1728,6 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
         dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
         assert(l_net);
 #ifndef DAP_CHAIN_BLOCKS_TEST
-        dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
-        assert(l_net);
         if ( !dap_chain_net_get_load_mode(l_net) ) {
             int l_err = dap_chain_atom_save(a_chain, l_block->hdr.cell_id, a_atom, a_atom_size, a_atom_new ? &l_block_hash : NULL, (char**)&l_block);
             if (l_err) {
-- 
GitLab


From b7b5f520c79ff700de02adec6648ce8f8d3a5450 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Tue, 18 Feb 2025 15:31:05 +0700
Subject: [PATCH 09/11] [*] Sub update

---
 dap-sdk | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dap-sdk b/dap-sdk
index 825fe16538..e85a4e785c 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 825fe16538c62b1c4732b16a415c9cb966ff6085
+Subproject commit e85a4e785cd64395685ecbb9df24830a1ccb4dcf
-- 
GitLab


From b29b40f33a23954d0da07580225dbf013b4d19ca Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Tue, 18 Feb 2025 16:04:33 +0700
Subject: [PATCH 10/11] [*] Test repair

---
 modules/chain/tests/dap_chain_ledger_tests.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/modules/chain/tests/dap_chain_ledger_tests.c b/modules/chain/tests/dap_chain_ledger_tests.c
index 18f949b6b7..6c284f7f95 100644
--- a/modules/chain/tests/dap_chain_ledger_tests.c
+++ b/modules/chain/tests/dap_chain_ledger_tests.c
@@ -1025,7 +1025,7 @@ void dap_ledger_test_run(void){
     dap_assert_PIF(dap_chain_cs_create(l_chain_main, &l_cfg) == 0, "Chain esbocs cs creating: ");
     DL_APPEND(l_net->pub.chains, l_chain_main);
 
-    dap_assert_PIF(!dap_ledger_decree_init(l_net->pub.ledger), "Decree initialization:");
+    dap_ledger_decree_init(l_net->pub.ledger);
 
     char *l_seed_ph = "H58i9GJKbn91238937^#$t6cjdf";
     size_t l_seed_ph_size = strlen(l_seed_ph);
-- 
GitLab


From de4d0e3522e1abf77d8c7a68613d63516802f1ed Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Tue, 18 Feb 2025 16:12:01 +0700
Subject: [PATCH 11/11] [*] Blocks test repair

---
 modules/type/blocks/dap_chain_cs_blocks.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 684248faa7..253c1ad2dd 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -1726,8 +1726,8 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
     switch (ret) {
     case ATOM_ACCEPT:{
         dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
-        assert(l_net);
 #ifndef DAP_CHAIN_BLOCKS_TEST
+        assert(l_net);
         if ( !dap_chain_net_get_load_mode(l_net) ) {
             int l_err = dap_chain_atom_save(a_chain, l_block->hdr.cell_id, a_atom, a_atom_size, a_atom_new ? &l_block_hash : NULL, (char**)&l_block);
             if (l_err) {
@@ -1924,7 +1924,8 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
 static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t *a_chain, dap_chain_atom_ptr_t a_atom, size_t a_atom_size, dap_chain_hash_fast_t *a_atom_hash)
 {
     dap_return_val_if_fail(a_chain && a_atom && a_atom_size && a_atom_hash, ATOM_REJECT);
-    bool l_load_mode = dap_chain_net_get_load_mode(dap_chain_net_by_id(a_chain->net_id));
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
+    bool l_load_mode = l_net ? dap_chain_net_get_load_mode(l_net) : false;
     dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
     assert(l_blocks);
     dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(l_blocks);
-- 
GitLab