From c18ca2a457e9fd9dcc388511a18cd0600616f752 Mon Sep 17 00:00:00 2001
From: Roman Khlopkov <roman.khlopkov@demlabs.net>
Date: Mon, 24 Jan 2022 12:13:47 +0000
Subject: [PATCH] bugs-5489

---
 modules/chain/dap_chain_ledger.c              | 185 +++++++++---------
 modules/channel/chain/dap_stream_ch_chain.c   |   8 +-
 modules/common/dap_chain_datum_tx_items.c     |   3 +-
 .../common/include/dap_chain_datum_tx_items.h |   2 +-
 modules/global-db/dap_chain_global_db.c       |  24 +--
 .../global-db/dap_chain_global_db_driver.c    |   2 +-
 .../dap_chain_global_db_driver_cdb.c          |   8 +-
 modules/net/dap_chain_net.c                   |   6 +
 modules/net/dap_chain_node_cli_cmd.c          |  11 +-
 9 files changed, 125 insertions(+), 124 deletions(-)

diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index 5f64beb19e..9bfd287bca 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -199,11 +199,8 @@ typedef struct dap_ledger_private {
     bool check_cells_ds;
     bool check_token_emission;
     dap_chain_cell_id_t local_cell_id;
-    /* Cache section */
-    dap_ledger_cache_item_t last_tx;
-    dap_ledger_cache_item_t last_spent_tx;
-    dap_ledger_cache_item_t last_emit;
-    dap_ledger_cache_str_item_t last_ticker;
+
+    bool load_mode;
 } dap_ledger_private_t;
 #define PVT(a) ( (dap_ledger_private_t* ) a->_internal )
 
@@ -287,10 +284,7 @@ void dap_chain_ledger_handle_free(dap_ledger_t *a_ledger)
 
 void dap_chain_ledger_load_end(dap_ledger_t *a_ledger)
 {
-    PVT(a_ledger)->last_tx.found = true;
-    PVT(a_ledger)->last_spent_tx.found = true;
-    PVT(a_ledger)->last_emit.found = true;
-    PVT(a_ledger)->last_ticker.found = true;
+    PVT(a_ledger)->load_mode = false;
 }
 
 
@@ -903,12 +897,15 @@ static int s_token_tsd_parse(dap_ledger_t * a_ledger, dap_chain_ledger_token_ite
 
 int dap_chain_ledger_token_load(dap_ledger_t *a_ledger, dap_chain_datum_token_t *a_token, size_t a_token_size)
 {
-    if (PVT(a_ledger)->last_ticker.found) {
-        return dap_chain_ledger_token_add(a_ledger, a_token, a_token_size);
-    } else if (!strncmp(PVT(a_ledger)->last_ticker.key, a_token->ticker, DAP_CHAIN_TICKER_SIZE_MAX)) {
-        PVT(a_ledger)->last_ticker.found = true;
-    }
-    return 0;
+    if (PVT(a_ledger)->load_mode) {
+        dap_chain_ledger_token_item_t *l_token_item;
+        pthread_rwlock_rdlock(&PVT(a_ledger)->tokens_rwlock);
+        HASH_FIND_STR(PVT(a_ledger)->tokens, a_token->ticker, l_token_item);
+        pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
+        if (l_token_item)
+            return 0;
+    }
+    return dap_chain_ledger_token_add(a_ledger, a_token, a_token_size);
 }
 
 dap_list_t *dap_chain_ledger_token_info(dap_ledger_t *a_ledger)
@@ -1044,15 +1041,9 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger)
             }
         }
         HASH_ADD_STR(l_ledger_pvt->tokens, ticker, l_token_item);
-        if (i == l_objs_count - 1) {
-            l_ledger_pvt->last_ticker.key = l_token_item->ticker;
-        }
     }
     dap_chain_global_db_objs_delete(l_objs, l_objs_count);
     DAP_DELETE(l_gdb_group);
-    if (l_objs_count == 0 || l_ledger_pvt->last_ticker.key == NULL) {
-        l_ledger_pvt->last_ticker.found = true;
-    }
 
     l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_EMISSIONS_STR);
     l_objs_count = 0;
@@ -1078,15 +1069,9 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger)
             HASH_ADD(hh, l_ledger_pvt->treshold_emissions, datum_token_emission_hash,
                      sizeof(dap_chain_hash_fast_t), l_emission_item);
         }
-        if (i == l_objs_count - 1) {
-            l_ledger_pvt->last_emit.hash = &l_emission_item->datum_token_emission_hash;
-        }
     }
     dap_chain_global_db_objs_delete(l_objs, l_objs_count);
     DAP_DELETE(l_gdb_group);
-    if (l_objs_count == 0 || l_ledger_pvt->last_emit.hash == NULL) {
-        l_ledger_pvt->last_emit.found = true;
-    }
 
     l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TXS_STR);
     l_objs_count = 0;
@@ -1098,15 +1083,9 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger)
         memcpy(l_tx_item->tx, l_objs[i].value + sizeof(l_tx_item->cache_data), l_objs[i].value_len - sizeof(l_tx_item->cache_data));
         memcpy(&l_tx_item->cache_data, l_objs[i].value, sizeof(l_tx_item->cache_data));
         HASH_ADD(hh, l_ledger_pvt->ledger_items, tx_hash_fast, sizeof(dap_chain_hash_fast_t), l_tx_item);
-        if (i == l_objs_count - 1) {
-            l_ledger_pvt->last_tx.hash = &l_tx_item->tx_hash_fast;
-        }
     }
     dap_chain_global_db_objs_delete(l_objs, l_objs_count);
     DAP_DELETE(l_gdb_group);
-    if (l_objs_count == 0 || l_ledger_pvt->last_tx.hash == NULL) {
-        l_ledger_pvt->last_tx.found = true;
-    }
 
     l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_SPENT_TXS_STR);
     l_objs_count = 0;
@@ -1116,15 +1095,9 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger)
         dap_chain_hash_fast_from_str(l_objs[i].key, &l_tx_spent_item->tx_hash_fast);
         strncpy(l_tx_spent_item->token_ticker, (char *)l_objs[i].value, DAP_CHAIN_TICKER_SIZE_MAX);
         HASH_ADD(hh, l_ledger_pvt->spent_items, tx_hash_fast, sizeof(dap_chain_hash_fast_t), l_tx_spent_item);
-        if (i == l_objs_count - 1) {
-            l_ledger_pvt->last_spent_tx.hash = &l_tx_spent_item->tx_hash_fast;
-        }
     }
     dap_chain_global_db_objs_delete(l_objs, l_objs_count);
     DAP_DELETE(l_gdb_group);
-    if (l_objs_count == 0 || l_ledger_pvt->last_spent_tx.hash == NULL) {
-        l_ledger_pvt->last_spent_tx.found = true;
-    }
 
     l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_BALANCES_STR);
     l_objs_count = 0;
@@ -1174,8 +1147,11 @@ dap_ledger_t* dap_chain_ledger_create(uint16_t a_check_flags, char *a_net_name)
     l_ledger_priv->net = dap_chain_net_by_name(a_net_name);
 
     log_it(L_DEBUG,"Created ledger \"%s\"",a_net_name);
-    // load ledger cache from GDB
-    dap_chain_ledger_load_cache(l_ledger);
+    l_ledger_priv->load_mode = true;
+    if (dap_config_get_item_bool_default(g_config, "ledger", "cached", true)) {
+        // load ledger cache from GDB
+        dap_chain_ledger_load_cache(l_ledger);
+    }
     return l_ledger;
 }
 
@@ -1382,16 +1358,32 @@ int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_
 
 int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size)
 {
-    if (PVT(a_ledger)->last_emit.found) {
-        return dap_chain_ledger_token_emission_add(a_ledger, a_token_emission, a_token_emission_size);
-    } else {
+    if (PVT(a_ledger)->load_mode) {
         dap_chain_hash_fast_t l_token_emission_hash = {};
         dap_hash_fast(a_token_emission, a_token_emission_size, &l_token_emission_hash);
-        if (!memcmp(PVT(a_ledger)->last_emit.hash, &l_token_emission_hash, sizeof(dap_chain_hash_fast_t))) {
-            PVT(a_ledger)->last_emit.found = true;
+        dap_chain_ledger_token_emission_item_t *l_token_emission_item;
+        dap_chain_ledger_token_item_t *l_token_item, *l_item_tmp;
+        pthread_rwlock_rdlock(&PVT(a_ledger)->tokens_rwlock);
+        HASH_ITER(hh, PVT(a_ledger)->tokens, l_token_item, l_item_tmp) {
+            pthread_rwlock_rdlock(&l_token_item->token_emissions_rwlock);
+            HASH_FIND(hh, l_token_item->token_emissions, &l_token_emission_hash, sizeof(l_token_emission_hash),
+                    l_token_emission_item);
+            pthread_rwlock_unlock(&l_token_item->token_emissions_rwlock);
+            if (l_token_emission_item) {
+                pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
+                return 0;
+            }
+        }
+        pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
+        pthread_rwlock_rdlock(&PVT(a_ledger)->treshold_emissions_rwlock);
+        HASH_FIND(hh, PVT(a_ledger)->treshold_emissions, &l_token_emission_hash, sizeof(l_token_emission_hash),
+                l_token_emission_item);
+        pthread_rwlock_unlock(&PVT(a_ledger)->treshold_emissions_rwlock);
+        if (l_token_emission_item) {
+            return DAP_CHAIN_CS_VERIFY_CODE_TX_NO_TOKEN;
         }
     }
-    return 0;
+    return dap_chain_ledger_token_emission_add(a_ledger, a_token_emission, a_token_emission_size);
 }
 
 /**
@@ -2600,21 +2592,28 @@ FIN:
 
 int dap_chain_ledger_tx_load(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx)
 {
-    if (PVT(a_ledger)->last_tx.found && PVT(a_ledger)->last_spent_tx.found) {
-        return dap_chain_ledger_tx_add(a_ledger, a_tx, false);
-    } else {
+    if (PVT(a_ledger)->load_mode) {
         dap_chain_hash_fast_t l_tx_hash = {};
         dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_tx_hash);
-        if (!PVT(a_ledger)->last_tx.found &&
-                !memcmp(PVT(a_ledger)->last_tx.hash, &l_tx_hash, sizeof(dap_chain_hash_fast_t))) {
-            PVT(a_ledger)->last_tx.found = true;
-        }
-        if (!PVT(a_ledger)->last_spent_tx.found &&
-                !memcmp(PVT(a_ledger)->last_spent_tx.hash, &l_tx_hash, sizeof(dap_chain_hash_fast_t))) {
-            PVT(a_ledger)->last_spent_tx.found = true;
-        }
-    }
-    return 1;
+        dap_chain_ledger_tx_item_t *l_tx_item;
+        pthread_rwlock_rdlock(&PVT(a_ledger)->ledger_rwlock);
+        HASH_FIND(hh, PVT(a_ledger)->ledger_items, &l_tx_hash, sizeof(dap_chain_hash_fast_t), l_tx_item);
+        if (l_tx_item) {
+            pthread_rwlock_unlock(&PVT(a_ledger)->ledger_rwlock);
+            return 1;
+        }
+        HASH_FIND(hh, PVT(a_ledger)->treshold_txs, &l_tx_hash, sizeof(dap_chain_hash_fast_t), l_tx_item);
+        if (l_tx_item) {
+            pthread_rwlock_unlock(&PVT(a_ledger)->ledger_rwlock);
+            return DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS;
+        }
+        dap_chain_ledger_tx_spent_item_t *l_tx_spent_item;
+        HASH_FIND(hh, PVT(a_ledger)->spent_items, &l_tx_hash, sizeof(dap_chain_hash_fast_t), l_tx_spent_item);
+        pthread_rwlock_unlock(&PVT(a_ledger)->ledger_rwlock);
+        if (l_tx_spent_item)
+            return 1;
+    }
+    return dap_chain_ledger_tx_add(a_ledger, a_tx, false);
 }
 
 /**
@@ -2648,10 +2647,12 @@ int dap_chain_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_
             char *l_cache_data = DAP_NEW_Z_SIZE(char, DAP_CHAIN_TICKER_SIZE_MAX);
             strncpy(l_cache_data, l_item_used->token_ticker, DAP_CHAIN_TICKER_SIZE_MAX);
             l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_SPENT_TXS_STR);
-            if (!dap_chain_global_db_gr_set(dap_hash_fast_to_str_new(a_tx_hash), l_cache_data, -1, l_gdb_group)) {
+            char *l_tx_hash_str = dap_hash_fast_to_str_new(a_tx_hash);
+            if (!dap_chain_global_db_gr_set(l_tx_hash_str, l_cache_data, -1, l_gdb_group)) {
                 if(s_debug_more)
                     log_it(L_WARNING, "Ledger cache mismatch");
                 DAP_DELETE(l_cache_data);
+                DAP_DELETE(l_tx_hash_str);
             }
             DAP_DELETE(l_gdb_group);
         }
@@ -2672,7 +2673,6 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
 {
     dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
     const int l_hash_str_size = DAP_CHAIN_HASH_FAST_SIZE * 2 + 2;
-    char l_hash_str[l_hash_str_size];
     pthread_rwlock_wrlock(&l_ledger_priv->ledger_rwlock);
     pthread_rwlock_wrlock(&l_ledger_priv->tokens_rwlock);
     pthread_rwlock_wrlock(&l_ledger_priv->treshold_emissions_rwlock);
@@ -2681,68 +2681,67 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
 
     // delete transactions
     dap_chain_ledger_tx_item_t *l_item_current, *l_item_tmp;
-    char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TXS_STR);
-    HASH_ITER(hh, l_ledger_priv->ledger_items , l_item_current, l_item_tmp) {
-        DAP_DELETE(l_item_current->tx);
+    char *l_gdb_group;
+    HASH_ITER(hh, l_ledger_priv->ledger_items , l_item_current, l_item_tmp) {    
         HASH_DEL(l_ledger_priv->ledger_items, l_item_current);
-        if (!a_preserve_db) {
-            dap_chain_hash_fast_to_str(&l_item_current->tx_hash_fast, l_hash_str, l_hash_str_size);
-            dap_chain_global_db_gr_del(dap_strdup(l_hash_str), l_gdb_group);
-        }
+        DAP_DELETE(l_item_current->tx);
         DAP_DELETE(l_item_current);
     }
-    DAP_DELETE(l_gdb_group);
+    if (!a_preserve_db) {
+        l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TXS_STR);
+        dap_chain_global_db_gr_del(NULL, l_gdb_group);
+        DAP_DELETE(l_gdb_group);
+    }
 
     // delete spent transactions
     dap_chain_ledger_tx_spent_item_t *l_spent_item_current, *l_spent_item_tmp;
-    l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_SPENT_TXS_STR);
     HASH_ITER(hh, l_ledger_priv->spent_items, l_spent_item_current, l_spent_item_tmp) {
         HASH_DEL(l_ledger_priv->spent_items, l_spent_item_current);
-        if (!a_preserve_db) {
-            dap_chain_hash_fast_to_str(&l_spent_item_current->tx_hash_fast, l_hash_str, l_hash_str_size);
-            dap_chain_global_db_gr_del(dap_strdup(l_hash_str), l_gdb_group);
-        }
         DAP_DELETE(l_item_current);
     }
-    DAP_DELETE(l_gdb_group);
+    if (!a_preserve_db) {
+        l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_SPENT_TXS_STR);
+        dap_chain_global_db_gr_del(NULL, l_gdb_group);
+        DAP_DELETE(l_gdb_group);
+    }
 
     // delete balances
     dap_ledger_wallet_balance_t *l_balance_current, *l_balance_tmp;
-    l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_BALANCES_STR);
     HASH_ITER(hh, l_ledger_priv->balance_accounts, l_balance_current, l_balance_tmp) {
         HASH_DEL(l_ledger_priv->balance_accounts, l_balance_current);
-        if (!a_preserve_db)
-            dap_chain_global_db_gr_del(l_balance_current->key, l_gdb_group);
         DAP_DELETE(l_balance_current);
     }
-    DAP_DELETE(l_gdb_group);
+    if (!a_preserve_db) {
+        l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_BALANCES_STR);
+        dap_chain_global_db_gr_del(NULL, l_gdb_group);
+        DAP_DELETE(l_gdb_group);
+    }
 
     // delete tokens & its emissions
     dap_chain_ledger_token_item_t *l_token_current, *l_token_tmp;
     dap_chain_ledger_token_emission_item_t *l_emission_current, *l_emission_tmp;
-    l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TOKENS_STR);
-    char *l_emissions_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_EMISSIONS_STR);
     HASH_ITER(hh, l_ledger_priv->tokens, l_token_current, l_token_tmp) {
         HASH_DEL(l_ledger_priv->tokens, l_token_current);
         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);
-            if (!a_preserve_db) {
-                dap_chain_hash_fast_to_str(&l_emission_current->datum_token_emission_hash, l_hash_str, l_hash_str_size);
-                dap_chain_global_db_gr_del(dap_strdup(l_hash_str), l_emissions_gdb_group);
-            }
             DAP_DELETE(l_emission_current->datum_token_emission);
             DAP_DELETE(l_emission_current);
         }
         pthread_rwlock_unlock(&l_token_current->token_emissions_rwlock);
-        if (!a_preserve_db)
-            dap_chain_global_db_gr_del(dap_strdup(l_token_current->ticker), l_gdb_group);
         DAP_DELETE(l_token_current->datum_token);
         pthread_rwlock_destroy(&l_token_current->token_emissions_rwlock);
         DAP_DELETE(l_token_current);
     }
-    DAP_DELETE(l_gdb_group);
-    DAP_DELETE(l_emissions_gdb_group);
+    if (!a_preserve_db) {
+        l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TOKENS_STR);
+        dap_chain_global_db_gr_del(NULL, l_gdb_group);
+        DAP_DELETE(l_gdb_group);
+        l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_EMISSIONS_STR);
+        dap_chain_global_db_gr_del(NULL, l_gdb_group);
+        DAP_DELETE(l_gdb_group);
+    }
+
 
 
     // delete threshold emissions
@@ -2758,12 +2757,6 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
         DAP_DELETE(l_item_current);
     }
 
-
-    l_ledger_priv->last_tx.found = true;
-    l_ledger_priv->last_spent_tx.found = true;
-    l_ledger_priv->last_emit.found = true;
-    l_ledger_priv->last_ticker.found = true;
-
     pthread_rwlock_unlock(&l_ledger_priv->ledger_rwlock);
     pthread_rwlock_unlock(&l_ledger_priv->tokens_rwlock);
     pthread_rwlock_unlock(&l_ledger_priv->treshold_emissions_rwlock);
diff --git a/modules/channel/chain/dap_stream_ch_chain.c b/modules/channel/chain/dap_stream_ch_chain.c
index 16322cf602..ec45ff56e9 100644
--- a/modules/channel/chain/dap_stream_ch_chain.c
+++ b/modules/channel/chain/dap_stream_ch_chain.c
@@ -109,6 +109,7 @@ static bool s_sync_in_chains_callback(dap_proc_thread_t *a_thread, void *a_arg);
 
 static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg);
 static void s_gdb_in_pkt_error_worker_callback(dap_worker_t *a_thread, void *a_arg);
+static void s_free_log_list_gdb ( dap_stream_ch_chain_t * a_ch_chain);
 
 static bool s_debug_more=false;
 static uint_fast16_t s_update_pack_size=100; // Number of hashes packed into the one packet
@@ -398,7 +399,7 @@ static bool s_sync_out_gdb_proc_callback(dap_proc_thread_t *a_thread, void *a_ar
 	if (l_ch == NULL) {
 		log_it(L_INFO, "Client disconnected before we sent the reply");
 		s_sync_request_delete(l_sync_request);
-		return;
+        return true;
 	}
 	dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch);
 
@@ -528,7 +529,8 @@ static bool s_sync_in_chains_callback(dap_proc_thread_t *a_thread, void *a_arg)
         if (s_debug_more) {
             char l_atom_hash_str[72]={'\0'};
             dap_chain_hash_fast_to_str(&l_atom_hash,l_atom_hash_str,sizeof (l_atom_hash_str)-1 );
-            log_it(L_INFO,"Accepted atom with hash %s for %s:%s", l_atom_hash_str, l_chain->net_name, l_chain->name);
+            log_it(L_INFO, "%s atom with hash %s for %s:%s", l_atom_add_res == ATOM_ACCEPT ? "Accepted" : "Thresholded",
+                            l_atom_hash_str, l_chain->net_name, l_chain->name);
         }
         dap_chain_cell_t *l_cell = dap_chain_cell_find_by_id(l_chain, l_sync_request->request_hdr.cell_id);
         if (!l_cell) {
@@ -1425,7 +1427,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
  * @brief dap_stream_ch_chain_go_idle_and_free_log_list
  * @param a_ch_chain
  */
-void s_free_log_list_gdb ( dap_stream_ch_chain_t * a_ch_chain)
+static void s_free_log_list_gdb ( dap_stream_ch_chain_t * a_ch_chain)
 {
     // free log list
     dap_db_log_list_delete(a_ch_chain->request_db_log);
diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c
index bf418dedec..36a08dabdf 100644
--- a/modules/common/dap_chain_datum_tx_items.c
+++ b/modules/common/dap_chain_datum_tx_items.c
@@ -163,12 +163,13 @@ size_t dap_chain_datum_item_tx_get_size(const uint8_t *a_item)
  *
  * return item, NULL Error
  */
-dap_chain_tx_token_t* dap_chain_datum_tx_item_token_create(dap_chain_hash_fast_t * a_datum_token_hash,const char * a_ticker)
+dap_chain_tx_token_t *dap_chain_datum_tx_item_token_create(dap_chain_id_t a_id, dap_chain_hash_fast_t *a_datum_token_hash, const char *a_ticker)
 {
     if(!a_ticker)
         return NULL;
     dap_chain_tx_token_t *l_item = DAP_NEW_Z(dap_chain_tx_token_t);
     l_item->header.type = TX_ITEM_TYPE_TOKEN;
+    l_item->header.token_emission_chain_id.uint64 = a_id.uint64;
     memcpy (& l_item->header.token_emission_hash, a_datum_token_hash, sizeof ( *a_datum_token_hash ) );
     strncpy(l_item->header.ticker, a_ticker, sizeof(l_item->header.ticker) - 1);
     return l_item;
diff --git a/modules/common/include/dap_chain_datum_tx_items.h b/modules/common/include/dap_chain_datum_tx_items.h
index c06d9abd9e..4fedf64b46 100644
--- a/modules/common/include/dap_chain_datum_tx_items.h
+++ b/modules/common/include/dap_chain_datum_tx_items.h
@@ -80,7 +80,7 @@ size_t dap_chain_datum_item_tx_get_size(const uint8_t *a_item);
  *
  * return item, NULL Error
  */
-dap_chain_tx_token_t* dap_chain_datum_tx_item_token_create(dap_chain_hash_fast_t * a_datum_token_hash,const char * a_ticker);
+dap_chain_tx_token_t *dap_chain_datum_tx_item_token_create(dap_chain_id_t a_id, dap_chain_hash_fast_t *a_datum_token_hash, const char *a_ticker);
 
 /**
  * Create item dap_chain_tx_out_t
diff --git a/modules/global-db/dap_chain_global_db.c b/modules/global-db/dap_chain_global_db.c
index 7d714677cb..35665007b9 100644
--- a/modules/global-db/dap_chain_global_db.c
+++ b/modules/global-db/dap_chain_global_db.c
@@ -606,8 +606,6 @@ bool dap_chain_global_db_set( char *a_key,  void *a_value, size_t a_value_len)
  */
 bool dap_chain_global_db_gr_del(char *a_key,const char *a_group)
 {
-    if(!a_key)
-        return NULL;
     dap_store_obj_t store_data;
     memset(&store_data, 0, sizeof(dap_store_obj_t));
     store_data.key = dap_strdup(a_key);
@@ -615,16 +613,18 @@ bool dap_chain_global_db_gr_del(char *a_key,const char *a_group)
     lock();
     int l_res = dap_chain_global_db_driver_delete(&store_data, 1);
     unlock();
-    if(l_res >= 0) {
-        // add to Del group
-        global_db_gr_del_add(dap_strdup(a_key), store_data.group, time(NULL));
-    }
-    // do not add to history if l_res=1 (already deleted)
-    if (!l_res) {
-        store_data.key = a_key;
-        dap_global_db_obj_track_history(&store_data);
-    } else {
-        DAP_DELETE(a_key);
+    if (a_key) {
+        if (l_res >= 0) {
+            // add to Del group
+            global_db_gr_del_add(dap_strdup(a_key), store_data.group, time(NULL));
+        }
+        // do not add to history if l_res=1 (already deleted)
+        if (!l_res) {
+            store_data.key = a_key;
+            dap_global_db_obj_track_history(&store_data);
+        } else {
+            DAP_DELETE(a_key);
+        }
     }
     return !l_res;
 }
diff --git a/modules/global-db/dap_chain_global_db_driver.c b/modules/global-db/dap_chain_global_db_driver.c
index 3e3176a1af..98e9e26cac 100644
--- a/modules/global-db/dap_chain_global_db_driver.c
+++ b/modules/global-db/dap_chain_global_db_driver.c
@@ -458,7 +458,7 @@ int dap_chain_global_db_driver_appy(pdap_store_obj_t a_store_obj, size_t a_store
                 log_it(L_ERROR, "Can't write item %s/%s (code %d)\n", l_store_obj_cur->group, l_cur_key, l_ret_tmp);
                 l_ret -= 1;
             }
-            DAP_DELETE(l_cur_key);
+            DAP_DEL_Z(l_cur_key);
             if (l_ret)
                 break;
         }
diff --git a/modules/global-db/dap_chain_global_db_driver_cdb.c b/modules/global-db/dap_chain_global_db_driver_cdb.c
index d3a6d25208..f41b91f6b5 100644
--- a/modules/global-db/dap_chain_global_db_driver_cdb.c
+++ b/modules/global-db/dap_chain_global_db_driver_cdb.c
@@ -172,8 +172,10 @@ pcdb_instance dap_cdb_init_group(char *a_group, int a_flags) {
     pthread_mutex_lock(&cdb_mutex);
     char l_cdb_path[strlen(s_cdb_path) + strlen(a_group) + 2];
     HASH_FIND_STR(s_cdb, a_group, l_cdb_i);
-    if (l_cdb_i && !(a_flags & CDB_TRUNC)) {
-        goto FIN;
+    if (!(a_flags & CDB_TRUNC)) {
+        if (l_cdb_i)
+            goto FIN;
+        l_cdb_i = DAP_NEW(cdb_instance);
     }
     l_cdb_i = DAP_NEW(cdb_instance);
     l_cdb_i->local_group = dap_strdup(a_group);
@@ -618,13 +620,13 @@ int dap_db_driver_cdb_apply_store_obj(pdap_store_obj_t a_store_obj) {
         if(a_store_obj->key) {
             if(cdb_del(l_cdb_i->cdb, a_store_obj->key, (int) strlen(a_store_obj->key)) == -3)
                 ret = 1;
+            DAP_DELETE(a_store_obj->key);
         } else {
             cdb_destroy(l_cdb_i->cdb);
             if (!dap_cdb_init_group(a_store_obj->group, CDB_TRUNC | CDB_PAGEWARMUP)) {
                 ret = -1;
             }
         }
-        DAP_DELETE(a_store_obj->key);
     }
     return ret;
 }
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index b643ccfb08..19a710b2d7 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -1783,6 +1783,12 @@ static int s_cli_net(int argc, char **argv, char **a_str_reply)
                     dap_chain_gdb_ledger_load((char *)dap_chain_gdb_get_group(l_chain), l_chain);
                 } else {
                     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");
+                        }
+                    }
+
                 }
             }
         } else {
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index d797a5abaa..be8be7a104 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -3281,13 +3281,10 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
     // Create emission datum
     // then create datum in memory
     if (!l_emission) {
-        char * l_gdb_group_mempool_emission;
-        if(l_chain_emission) {
-            l_gdb_group_mempool_emission = dap_chain_net_get_gdb_group_mempool(l_chain_emission);
-        }
-        else {
-            l_gdb_group_mempool_emission = dap_chain_net_get_gdb_group_mempool_by_chain_type(l_net, CHAIN_TYPE_EMISSION);
+        if (!l_chain_emission) {
+            l_chain_emission = dap_chain_net_get_chain_by_chain_type(l_net, CHAIN_TYPE_EMISSION);
         }
+        char *l_gdb_group_mempool_emission = dap_chain_net_get_gdb_group_mempool(l_chain_emission);
         size_t l_emission_size = sizeof(l_emission->hdr) +
                 sizeof(l_emission->data.type_auth.signs_count);
 
@@ -3349,7 +3346,7 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
     l_tx->header.ts_created = time(NULL);
     dap_chain_hash_fast_t l_tx_prev_hash = { 0 };
     // create items
-    dap_chain_tx_token_t *l_tx_token = dap_chain_datum_tx_item_token_create(&l_emission_hash, l_ticker);
+    dap_chain_tx_token_t *l_tx_token = dap_chain_datum_tx_item_token_create(l_chain_emission->id, &l_emission_hash, l_ticker);
     dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(&l_tx_prev_hash, 0);
     dap_chain_256_tx_out_t *l_out = dap_chain_datum_tx_item_out_create(l_addr, l_emission_value);
 
-- 
GitLab