diff --git a/3rdparty/cuttdb/src/cdb_bgtask.c b/3rdparty/cuttdb/src/cdb_bgtask.c
index 1d16c81a95ec1a5b83b64283150fe97e86f83d64..d12bd26e6c3b35e61e97aab1f2be49b10ea9cd80 100644
--- a/3rdparty/cuttdb/src/cdb_bgtask.c
+++ b/3rdparty/cuttdb/src/cdb_bgtask.c
@@ -16,14 +16,7 @@
 #include "cdb_bgtask.h"
 #include <stdlib.h>
 #include <errno.h>
-#if defined(DAP_OS_DARWIN)
 #include <signal.h>
-#elif defined(_WIN32)
-#include <sys/signal.h>
-#else
-#include <signal.h>
-#endif
-
 
 /* where thread begins */
 static void *_cdb_bgtask_func(void *arg);
diff --git a/dap-sdk/core/include/dap_common.h b/dap-sdk/core/include/dap_common.h
index 7baa879248bd5fb824dfcaaf99ee5521e7dc1698..46b5578d90139ce055ded6108faaea8cfcd70461 100755
--- a/dap-sdk/core/include/dap_common.h
+++ b/dap-sdk/core/include/dap_common.h
@@ -122,8 +122,8 @@ typedef uint8_t byte_t;
   #define DAP_NEW_Z_SIZE(a, b)  DAP_CAST_REINT(a, rpcalloc(1,b))
   #define DAP_REALLOC(a, b)     rprealloc(a,b)
   #define DAP_DELETE(a)         rpfree(a)
-  #define DAP_DUP(a)            ( __typeof(a) ret = memcpy(ret,a,sizeof(*a)) )
-  #define DAP_DUP_SIZE(a,b)       ( __typeof(a) ret = memcpy(ret,a,b) )
+  #define DAP_DUP(a, b)         memcpy(a, b, sizeof(*b))
+  #define DAP_DUP_SIZE(a, b, s) memcpy(a, b, s)
 #else
   #define DAP_MALLOC(a)         malloc(a)
   #define DAP_FREE(a)           free(a)
@@ -139,8 +139,8 @@ typedef uint8_t byte_t;
   #define DAP_NEW_Z_SIZE(a, b)  DAP_CAST_REINT(a, calloc(1,b))
   #define DAP_REALLOC(a, b)     realloc(a,b)
   #define DAP_DELETE(a)         free(a)
-  #define DAP_DUP(a)            ( __typeof(a) ret = memcpy(ret,a,sizeof(*a)) )
-  #define DAP_DUP_SIZE(a,b)       ( __typeof(a) memcpy(ret,a,b) )
+  #define DAP_DUP(a, b)         memcpy(a, b, sizeof(*b))
+  #define DAP_DUP_SIZE(a, b, s) memcpy(a, b, s)
 #endif
 
 #define DAP_DEL_Z(a)          if(a) { DAP_DELETE(a); a=NULL;}
diff --git a/dap-sdk/core/src/dap_common.c b/dap-sdk/core/src/dap_common.c
index 0a7aa08e40deba922de8896e0a0a13b1f330d6a5..d36d88e4575a670ce1774896f706fbe4436932a1 100755
--- a/dap-sdk/core/src/dap_common.c
+++ b/dap-sdk/core/src/dap_common.c
@@ -190,7 +190,7 @@ const char * dap_get_appname()
 }
 
 /**
- * @brief dap_set_appname
+ * @brief dap_set_appname set application name in global s_appname variable
  * @param a_appname
  * @return
  */
@@ -222,6 +222,16 @@ void dap_set_log_tag_width(size_t a_width) {
  * @param[in] a_log_file
  * @return
  */
+
+/**
+ * @brief dap_common_init call this function before using dap sdk modules
+ * 
+ * @param a_console_title set console title. Can be result of dap_get_appname()
+ * @param a_log_file_path path to log file. Saved in s_log_file_path variable
+ * @param a_log_dirpath path to log directory. Saved in s_log_dir_path variable
+ * @return int (0 if succcess, -1 if error)
+ */
+
 int dap_common_init( const char *a_console_title, const char *a_log_file_path, const char *a_log_dirpath) {
 
     // init randomer
diff --git a/dap-sdk/core/src/dap_file_utils.c b/dap-sdk/core/src/dap_file_utils.c
index 5844fcf3d712beaa08b1c617d4c8da43dfdebce3..30b3f7dc98effc0e4a69c5e6a0de728dcf81386f 100755
--- a/dap-sdk/core/src/dap_file_utils.c
+++ b/dap-sdk/core/src/dap_file_utils.c
@@ -114,12 +114,14 @@ bool dap_dir_test(const char * a_dir_path)
     return false;
 }
 
+
 /**
- * Create a new directory with intermediate sub-directories
- *
- * @dir_path new directory pathname
- * @return 0, if the directory was created or already exist, else -1
+ * @brief dap_mkdir_with_parents Create a new directory with intermediate sub-directories
+ * 
+ * @param a_dir_path new directory pathname
+ * @return int 0, if the directory was created or already exist, else -1
  */
+
 int dap_mkdir_with_parents(const char *a_dir_path)
 {
     // validation of a pointer
diff --git a/dap-sdk/core/src/dap_strfuncs.c b/dap-sdk/core/src/dap_strfuncs.c
index 118c040d0c300e38f7914faf20ca40bd923d5f15..f8944b88b34ef8fb956dfcb35036a7c188b07211 100755
--- a/dap-sdk/core/src/dap_strfuncs.c
+++ b/dap-sdk/core/src/dap_strfuncs.c
@@ -185,6 +185,14 @@ char *dap_itoa128(char *a_str, int128_t a_value, int a_base)
  *
  * Returns: length of the string
  */
+
+/**
+ * @brief dap_strlen get length of the string
+ * 
+ * @param a_str pointer to string
+ * @return size_t 
+ */
+
 size_t dap_strlen(const char *a_str)
 {
     size_t l_length = 0;
@@ -196,12 +204,13 @@ size_t dap_strlen(const char *a_str)
 }
 
 /**
- * dap_strcmp:
- * @a_str1: (nullable): the string
- * @a_str2: (nullable): the string
- *
- * Compare a_str1 and a_str2
+ * @brief dap_strcmp a_str1 and a_str2
+ * 
+ * @param a_str1 (nullable): the string
+ * @param a_str2 (nullable): the string
+ * @return int 
  */
+
 int dap_strcmp(const char *a_str1, const char *a_str2)
 {
     if(a_str1 && a_str2) {
@@ -211,12 +220,14 @@ int dap_strcmp(const char *a_str1, const char *a_str2)
 }
 
 /**
- * dap_strcmp:
- * @a_str1: (nullable): the string
- * @a_str2: (nullable): the string
- *
- * Compare a_n characters of a_str1 and a_str2
+ * @brief dap_strcmp
+ * 
+ * @param a_str1  (nullable): the string
+ * @param a_str2  (nullable): the string
+ * @param a_n Compare a_n characters of a_str1 and a_str2
+ * @return int 
  */
+
 int dap_strncmp(const char *a_str1, const char *a_str2, size_t a_n)
 {
     if(a_str1 && a_str2) {
@@ -225,16 +236,17 @@ int dap_strncmp(const char *a_str1, const char *a_str2, size_t a_n)
     return -1;
 }
 
+
 /**
- * dap_strdup:
- * @a_str: (nullable): the string to duplicate
- *
+ * @brief dap_strdup:
  * Duplicates a string. If @a_str is %NULL it returns %NULL.
  * The returned string should be freed
  * when no longer needed.
  *
- * Returns: a newly-allocated copy of @a_str
+ * @param a_str (nullable): the string to duplicate
+ * @return char* duplicated string
  */
+
 char* dap_strdup(const char *a_str)
 {
     char *l_new_str;
@@ -255,18 +267,21 @@ char* dap_strdup(const char *a_str)
 }
 
 /**
- * dap_strdup_vprintf:
- * @a_format: a standard printf() format string, but notice
- *     [string precision pitfalls][string-precision]
- * @a_args: the list of parameters to insert into the format string
- *
+ * @brief dap_strdup_vprintf
+ * 
  * Similar to the standard C vsprintf() function but safer, since it
  * calculates the maximum space required and allocates memory to hold
  * the result. The returned string should be freed with DAP_DELETE()
  * when no longer needed.
  *
  * Returns: a newly-allocated string holding the result
+ * 
+ * @param a_format  a standard printf() format string, but notice
+ *     [string precision pitfalls][string-precision]
+ * @param a_args the list of parameters to insert into the format string
+ * @return char* 
  */
+
 char* dap_strdup_vprintf(const char *a_format, va_list a_args)
 {
     char *l_string = NULL;
@@ -277,16 +292,18 @@ char* dap_strdup_vprintf(const char *a_format, va_list a_args)
 }
 
 /**
- * dap_strdup_printf:
- * @a_format: a standard printf() format string
- *
- * Similar to the standard C sprintf() function but safer, since it
+ * @brief dap_strdup_printf:
+ * 
+ *  * Similar to the standard C sprintf() function but safer, since it
  * calculates the maximum space required and allocates memory to hold
  * the result. The returned string should be freed with DAP_DELETE()
  * when no longer needed.
- *
- * Returns: a newly-allocated string holding the result
+ * 
+ * @param a_format a standard printf() format string
+ * @param ... 
+ * @return char* a newly-allocated string holding the result
  */
+
 char* dap_strdup_printf(const char *a_format, ...)
 {
     char *l_buffer;
@@ -630,6 +647,13 @@ char** dap_strsplit(const char *a_string, const char *a_delimiter, int a_max_tok
     return l_str_array;
 }
 
+/**
+ * @brief  dap_str_countv
+ * 
+ * @param a_str_array 
+ * @return size_t 
+ */
+
 size_t dap_str_countv(char **a_str_array)
 {
     size_t l_i = 0;
@@ -642,16 +666,19 @@ size_t dap_str_countv(char **a_str_array)
 }
 
 /**
- * dap_strdupv:
- * @a_str_array: (nullable): a %NULL-terminated array of strings
- *
+ * @brief  dap_strdupv:
+ * 
+ * @param a_str_array (nullable): a %NULL-terminated array of strings
  * Copies %NULL-terminated array of strings. The copy is a deep copy;
  * the new array should be freed by first freeing each string, then
  * the array itself. g_strfreev() does this for you. If called
  * on a %NULL value, g_strdupv() simply returns %NULL.
  *
  * Returns: (nullable): a new %NULL-terminated array of strings.
+ *
+ * @return char** 
  */
+
 char** dap_strdupv(const char **a_str_array)
 {
     if(a_str_array)
@@ -680,14 +707,16 @@ char** dap_strdupv(const char **a_str_array)
 }
 
 /**
- * dap_strfreev:
- * @a_str_array: (nullable): a %NULL-terminated array of strings to free
- *
+ * @brief dap_strfreev:
+ * 
  * Frees a %NULL-terminated array of strings, as well as each
  * string it contains.
  *
  * If @a_str_array is %NULL, this function simply returns.
+ *
+ * @param a_str_array (nullable): a %NULL-terminated array of strings to free
  */
+
 void dap_strfreev(char **a_str_array)
 {
     if(a_str_array)
@@ -701,9 +730,8 @@ void dap_strfreev(char **a_str_array)
 }
 
 /**
- * dap_strchug:
- * @a_string: a string to remove the leading whitespace from
- *
+ * @brief dap_strchug:
+ * 
  * Removes leading whitespace from a string, by moving the rest
  * of the characters forward.
  *
@@ -713,7 +741,11 @@ void dap_strfreev(char **a_str_array)
  *
  * The pointer to @a_string is returned to allow the nesting of functions.
  * Returns: @a_string
+ * 
+ * @param a_string a string to remove the leading whitespace from
+ * @return char* 
  */
+
 char* dap_strchug(char *a_string)
 {
     unsigned char *l_start;
@@ -760,15 +792,18 @@ char* dap_strchomp(char *a_string)
 }
 
 /**
- * dap_strup:
- * @a_str: a string
- * @a_len: length of @a_str in bytes, or -1 if @a_str is nul-terminated
- *
+ * @brief dap_strup
+ * 
  * Converts all lower case ASCII letters to upper case ASCII letters.
  *
  * Returns: a newly allocated string, with all the lower case
  *     characters in @a_str converted to upper case
+ * 
+ * @param a_str a string
+ * @param a_len  length of @a_str in bytes, or -1 if @a_str is nul-terminated
+ * @return char* 
  */
+
 char* dap_strup(const char *a_str, ssize_t a_len)
 {
     char *l_result, *l_s;
@@ -786,15 +821,17 @@ char* dap_strup(const char *a_str, ssize_t a_len)
 }
 
 /**
- * dap_strdown:
- * @a_str: a string
- * @a_len: length of @a_str in bytes, or -1 if @a_str is nul-terminated
- *
- * Converts all upper case ASCII letters to lower case ASCII letters.
+ * @brief  dap_strdown
+ *  Converts all upper case ASCII letters to lower case ASCII letters.
  *
  * Returns: a newly-allocated string, with all the upper case
  *     characters in @a_str converted to lower case
+ * 
+ * @param a_str a string
+ * @param a_len length of @a_str in bytes, or -1 if @a_str is nul-terminated
+ * @return char* 
  */
+
 char* dap_strdown(const char *a_str, ssize_t a_len)
 {
     char *l_result, *l_s;
@@ -811,10 +848,9 @@ char* dap_strdown(const char *a_str, ssize_t a_len)
     return l_result;
 }
 
+
 /**
- * dap_strreverse:
- * @a_string: the string to reverse
- *
+ * @brief dap_strreverse
  * Reverses all of the bytes in a string. For example,
  * `dap_strreverse("abcdef")` will result in "fedcba".
  *
@@ -822,7 +858,11 @@ char* dap_strdown(const char *a_str, ssize_t a_len)
  * containing multibyte characters.
  *
  * Returns: the same pointer passed in as @a_string
+ *
+ * @param a_string  the string to reverse
+ * @return char* 
  */
+
 char* dap_strreverse(char *a_string)
 {
     dap_return_val_if_fail(a_string != NULL, NULL);
@@ -857,6 +897,14 @@ char *strptime( char *buff, const char *fmt, struct tm *tm ) {
   return buff + len;
 }
 
+/**
+ * @brief _strndup
+ * 
+ * @param str 
+ * @param len 
+ * @return char* 
+ */
+
 char *_strndup(const char *str, unsigned long len) {
     char *buf = (char*)memchr(str, '\0', len);
     if (buf)
diff --git a/dap-sdk/crypto/src/dap_cert.c b/dap-sdk/crypto/src/dap_cert.c
index 920e16678ad35a37c074412ef3e620b6850ffceb..131b7415c5a152a088c75a78f4715d181bbb83d9 100755
--- a/dap-sdk/crypto/src/dap_cert.c
+++ b/dap-sdk/crypto/src/dap_cert.c
@@ -73,7 +73,7 @@ static dap_cert_item_t * s_certs = NULL;
 static dap_cert_folder_t * s_cert_folders = NULL;
 
 /**
- * @brief dap_cert_init
+ * @brief dap_cert_init empty stub for certificate init
  * @return
  */
 int dap_cert_init()
diff --git a/dap-sdk/crypto/src/dap_enc.c b/dap-sdk/crypto/src/dap_enc.c
index bb388202b73abac4f794c96408768490c7ad4102..507d62b52553d8e6e0eaab3ff8147b3bf351037d 100755
--- a/dap-sdk/crypto/src/dap_enc.c
+++ b/dap-sdk/crypto/src/dap_enc.c
@@ -35,9 +35,11 @@
 #define LOG_TAG "dap_enc"
 
 /**
- * @brief enc_init
- * @return
+ * @brief dap_enc_init if you want to use crypto functions from dap-sdk call that function
+ * 
+ * @return int 
  */
+
 int dap_enc_init()
 {
     srand(time(NULL));
diff --git a/dap-sdk/crypto/src/dap_enc_base58.c b/dap-sdk/crypto/src/dap_enc_base58.c
index 84282f26f97c1b9da2101a7b8274f93091f89f06..ad6c897a31beddb1ee04489d91bdbc19c10e389f 100755
--- a/dap-sdk/crypto/src/dap_enc_base58.c
+++ b/dap-sdk/crypto/src/dap_enc_base58.c
@@ -46,10 +46,10 @@ const int8_t c_b58digits_map[] = {
 };
 
 /**
- * @brief dap_enc_base58_decode
- * @param a_in
- * @param a_out
- * @return
+ * @brief dap_enc_base58_decode decode string using base58 alghoritm
+ * @param a_in - encoded string
+ * @param a_out - output buffer
+ * @return size_t output buffer size
  */
 size_t dap_enc_base58_decode(const char * a_in, void * a_out)
 {
@@ -152,8 +152,14 @@ size_t dap_enc_base58_decode(const char * a_in, void * a_out)
 }
 
 
-
-//bool b58enc(char *a_out, size_t *l_out_size, const void *a_in, size_t a_in_size)
+/**
+ * @brief dap_enc_base58_encode encode string in Base58 alghorithm
+ * 
+ * @param a_in - input buffer
+ * @param a_in_size - buffer size
+ * @param a_out - string with results
+ * @return size_t - returned string size (in bytes)
+ */
 size_t dap_enc_base58_encode(const void * a_in, size_t a_in_size, char * a_out)
 {
     const uint8_t *l_in_u8 = a_in;
diff --git a/dap-sdk/crypto/src/dap_enc_key.c b/dap-sdk/crypto/src/dap_enc_key.c
index 580127163d885d223b3d0857a501dde984c170f7..8d4c458ae07f8f42cae459bfb52610cc448de940 100755
--- a/dap-sdk/crypto/src/dap_enc_key.c
+++ b/dap-sdk/crypto/src/dap_enc_key.c
@@ -351,7 +351,7 @@ struct dap_enc_key_callbacks{
 
 const size_t c_callbacks_size = sizeof(s_callbacks) / sizeof(s_callbacks[0]);
 /**
- * @brief dap_enc_key_init
+ * @brief dap_enc_key_init empty stub
  * @return
  */
 int dap_enc_key_init()
diff --git a/modules/chain/dap_chain_cell.c b/modules/chain/dap_chain_cell.c
index 238e97a4a69df20aafab2d60b05c1d165f0dfa1c..8e44c836749ef016857260637011c9092096f604 100644
--- a/modules/chain/dap_chain_cell.c
+++ b/modules/chain/dap_chain_cell.c
@@ -115,14 +115,13 @@ void dap_chain_cell_delete(dap_chain_cell_t *a_cell)
 int dap_chain_cell_load(dap_chain_t * a_chain, const char * a_cell_file_path)
 {
     dap_chain_cell_t * l_cell = dap_chain_cell_create();
-
     l_cell->file_storage_path = dap_strdup( a_cell_file_path );
-
-    char *l_file_path = dap_strdup_printf("%s/%s", DAP_CHAIN_PVT (a_chain)->file_storage_dir,
-            l_cell->file_storage_path);
-
-    l_cell->file_storage = fopen(l_file_path,"rb");
-    DAP_DELETE(l_file_path);
+    {
+        char l_file_path[MAX_PATH] = {'\0'};
+        dap_snprintf(l_file_path, MAX_PATH, "%s/%s", DAP_CHAIN_PVT(a_chain)->file_storage_dir,
+                     l_cell->file_storage_path);
+        l_cell->file_storage = fopen(l_file_path,"rb");
+    }
     if ( l_cell->file_storage ){
         dap_chain_cell_file_header_t l_hdr = {0};
         if ( fread( &l_hdr,1,sizeof(l_hdr),l_cell->file_storage ) == sizeof (l_hdr) ) {
@@ -186,12 +185,12 @@ int dap_chain_cell_file_append( dap_chain_cell_t * a_cell, const void* a_atom, s
     size_t l_total_wrote_bytes = 0;
     // file need to be opened or created
     if(a_cell->file_storage == NULL) {
-        char *l_file_path = dap_strdup_printf("%s/%s", DAP_CHAIN_PVT ( a_cell->chain)->file_storage_dir,
-                a_cell->file_storage_path);
+        char l_file_path[MAX_PATH] = {'\0'};
+        dap_snprintf(l_file_path, MAX_PATH, "%s/%s", DAP_CHAIN_PVT(a_cell->chain)->file_storage_dir,
+                     a_cell->file_storage_path);
         a_cell->file_storage = fopen(l_file_path, "ab");
         if(a_cell->file_storage == NULL)
             a_cell->file_storage = fopen(l_file_path, "wb");
-        DAP_DELETE(l_file_path);
     }
     if(!a_cell->file_storage) {
         log_it(L_ERROR, "File \"%s\" not opened  for write cell 0x%016X",
@@ -255,10 +254,10 @@ int dap_chain_cell_file_update( dap_chain_cell_t * a_cell)
         return -1;
     }
     if(a_cell->file_storage == NULL ){ // File need to be created
-        char *l_file_path = dap_strdup_printf("%s/%s", DAP_CHAIN_PVT ( a_cell->chain)->file_storage_dir,
-                a_cell->file_storage_path);
+        char l_file_path[MAX_PATH] = {'\0'};
+        dap_snprintf(l_file_path, MAX_PATH, "%s/%s", DAP_CHAIN_PVT(a_cell->chain)->file_storage_dir,
+                     a_cell->file_storage_path);
         a_cell->file_storage = fopen(l_file_path, "wb");
-        DAP_DELETE(l_file_path);
         if(a_cell->file_storage) {
             dap_chain_cell_file_header_t l_hdr = {
                 .signature = DAP_CHAIN_CELL_FILE_SIGNATURE,
diff --git a/modules/channel/chain/dap_stream_ch_chain.c b/modules/channel/chain/dap_stream_ch_chain.c
index 7e6fd0b55d3e1de16eb2430203d544a720c1daa4..86a353e7ec4526bdfec864dab5b2ab82b325b934 100644
--- a/modules/channel/chain/dap_stream_ch_chain.c
+++ b/modules/channel/chain/dap_stream_ch_chain.c
@@ -77,8 +77,6 @@ struct sync_request
     dap_stream_ch_chain_pkt_hdr_t request_hdr;
     dap_chain_pkt_item_t pkt;
 
-    dap_stream_ch_chain_update_element_t *local_gdbs;
-    uint64_t local_gdbs_count;
     dap_stream_ch_chain_hash_item_t *remote_atoms; // Remote atoms
     dap_stream_ch_chain_hash_item_t *remote_gdbs; // Remote gdbs
 
@@ -331,8 +329,7 @@ static void s_sync_out_gdb_first_worker_callback(dap_worker_t *a_worker, void *a
     dap_chain_net_t *l_net = dap_chain_net_by_id(l_ch_chain->request_hdr.net_id);
 
     // Add it to outgoing list
-    l_ch_chain->request_global_db_trs = l_sync_request->gdb.db_log;
-    l_ch_chain->request_db_iter = NULL;
+    l_ch_chain->request_db_log = l_sync_request->gdb.db_log;
     l_ch_chain->state = CHAIN_STATE_SYNC_GLOBAL_DB;
     dap_chain_node_addr_t l_node_addr = { 0 };
     l_node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
@@ -347,7 +344,6 @@ static void s_sync_out_gdb_first_worker_callback(dap_worker_t *a_worker, void *a
 
     if( a_worker){ // We send NULL to prevent delete
         s_sync_request_delete(l_sync_request);
-        l_ch_chain->is_on_request = false;
     }
 }
 
@@ -369,19 +365,16 @@ static void s_sync_out_gdb_last_worker_callback(dap_worker_t *a_worker, void *a_
     dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN( l_ch );
     s_sync_out_gdb_first_worker_callback(NULL,a_arg); // NULL to say callback not to delete request
 
-    dap_stream_ch_chain_sync_request_t l_request = {0};
     if (s_debug_more )
         log_it(L_INFO,"Out: DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB");
     dap_stream_ch_chain_pkt_write_unsafe(l_ch_chain->ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
                                          l_ch_chain->request_hdr.net_id.uint64, l_ch_chain->request_hdr.chain_id.uint64,
-                                         l_ch_chain->request_hdr.cell_id.uint64, &l_request, sizeof(l_request));
+                                         l_ch_chain->request_hdr.cell_id.uint64, NULL, 0);
     l_ch_chain->state = CHAIN_STATE_IDLE;
     if(l_ch_chain->callback_notify_packet_out)
         l_ch_chain->callback_notify_packet_out(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
                                                 NULL, 0, l_ch_chain->callback_notify_arg);
-    l_ch_chain->is_on_request = false;
     s_sync_request_delete(l_sync_request);
-
 }
 
 /**
@@ -392,27 +385,23 @@ static void s_sync_out_gdb_last_worker_callback(dap_worker_t *a_worker, void *a_
  */
 static bool s_sync_out_gdb_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
 {
-    struct sync_request *l_sync_request = (struct sync_request *) a_arg;
-
-    // Get log diff
-    uint64_t l_local_last_id = dap_db_log_get_last_id();
-    if (s_debug_more)
-        log_it(L_DEBUG, "Sync out gdb proc, requested transactions %"DAP_UINT64_FORMAT_u":%"DAP_UINT64_FORMAT_u" from address "NODE_ADDR_FP_STR,
-                            l_sync_request->request.id_start, l_local_last_id, NODE_ADDR_FP_ARGS_S(l_sync_request->request.node_addr));
-    uint64_t l_start_item = l_sync_request->request.id_start;
-    // If the current global_db has been truncated, but the remote node has not known this
-    if(l_sync_request->request.id_start > l_local_last_id) {
-        l_start_item = 0;
-    }
+    struct sync_request *l_sync_request = (struct sync_request *)a_arg;
     dap_chain_net_t *l_net = dap_chain_net_by_id(l_sync_request->request_hdr.net_id);
-    dap_list_t *l_add_groups = dap_chain_net_get_add_gdb_group(l_net, l_sync_request->request.node_addr);
-    dap_db_log_list_t *l_db_log = dap_db_log_list_start(l_start_item + 1, l_add_groups);
+    int l_flags = 0;
+    if (dap_chain_net_get_add_gdb_group(l_net, l_sync_request->request.node_addr))
+        l_flags |= F_DB_LOG_ADD_EXTRA_GROUPS;
+    if (!l_sync_request->request.id_start)
+        l_flags |= F_DB_LOG_SYNC_FROM_ZERO;
+    dap_db_log_list_t *l_db_log = dap_db_log_list_start(l_sync_request->request.node_addr, l_flags);
 
     if(l_db_log) {
+        if (s_debug_more)
+            log_it(L_DEBUG, "Sync out gdb proc, requested %"DAP_UINT64_FORMAT_u" transactions from address "NODE_ADDR_FP_STR,
+                             l_db_log->items_number, NODE_ADDR_FP_ARGS_S(l_sync_request->request.node_addr));
         l_sync_request->gdb.db_log = l_db_log;
-        dap_proc_thread_worker_exec_callback(a_thread, l_sync_request->worker->id, s_sync_out_gdb_first_worker_callback,l_sync_request );
+        dap_proc_thread_worker_exec_callback(a_thread, l_sync_request->worker->id, s_sync_out_gdb_first_worker_callback, l_sync_request );
     } else {
-        dap_proc_thread_worker_exec_callback(a_thread, l_sync_request->worker->id, s_sync_out_gdb_last_worker_callback,l_sync_request );
+        dap_proc_thread_worker_exec_callback(a_thread, l_sync_request->worker->id, s_sync_out_gdb_last_worker_callback, l_sync_request );
     }
     return true;
 }
@@ -427,7 +416,6 @@ static void s_sync_update_gdb_start_worker_callback(dap_worker_t *a_worker, void
         s_sync_request_delete(l_sync_request);
         return;
     }
-
     dap_stream_ch_chain_pkt_write_unsafe(l_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_START,
                                          l_sync_request->request_hdr.net_id.uint64, l_sync_request->request_hdr.chain_id.uint64,
                                          l_sync_request->request_hdr.cell_id.uint64, NULL, 0);
@@ -438,21 +426,24 @@ static void s_sync_update_gdb_start_worker_callback(dap_worker_t *a_worker, void
     DAP_DELETE(l_sync_request);
 }
 
-static void s_sync_update_gdb_proc_callback(dap_worker_t  *a_worker, void *a_arg)
+static bool s_sync_update_gdb_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
 {
-    struct sync_request *l_sync_request = (struct sync_request *) a_arg;
-
-    dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(DAP_STREAM_WORKER(a_worker), l_sync_request->ch_uuid);
-    if( l_ch == NULL ){
-        log_it(L_INFO,"Client disconnected before we sent the reply");
-        s_sync_request_delete(l_sync_request);
-        return ;
-    }
-    // TODO make a local_gdbs hash table
+    struct sync_request *l_sync_request = (struct sync_request *)a_arg;
+    log_it(L_DEBUG, "Prepare request to gdb sync from %s", l_sync_request->request.id_start ? "last sync" : "zero");
+    dap_chain_net_t *l_net = dap_chain_net_by_id(l_sync_request->request_hdr.net_id);
+    dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(DAP_STREAM_WORKER(l_sync_request->worker), l_sync_request->ch_uuid);
     dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch);
-    l_ch_chain->local_gdbs = l_sync_request->local_gdbs;
-    l_ch_chain->local_gdbs_count = l_sync_request->local_gdbs_count;
-    dap_worker_exec_callback_on( l_sync_request->worker, s_sync_update_gdb_start_worker_callback, l_sync_request);
+    int l_flags = 0;
+    if (dap_chain_net_get_add_gdb_group(l_net, l_sync_request->request.node_addr))
+        l_flags |= F_DB_LOG_ADD_EXTRA_GROUPS;
+    if (!l_sync_request->request.id_start)
+        l_flags |= F_DB_LOG_SYNC_FROM_ZERO;
+    dap_db_log_list_t *l_db_log = dap_db_log_list_start(l_sync_request->request.node_addr, l_flags);
+    l_ch_chain->request_db_log = l_db_log;
+    l_ch_chain->state = CHAIN_STATE_UPDATE_GLOBAL_DB;
+    l_sync_request->request.node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
+    dap_proc_thread_worker_exec_callback(a_thread, l_sync_request->worker->id, s_sync_update_gdb_start_worker_callback, l_sync_request);
+    return true;
 }
 
 /**
@@ -583,7 +574,7 @@ static void s_gdb_in_pkt_error_worker_callback(dap_worker_t *a_worker, void *a_a
     dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(DAP_STREAM_WORKER(a_worker), l_sync_request->ch_uuid);
     if( l_ch == NULL ){
         log_it(L_INFO,"Client disconnected before we sent the reply");
-        s_sync_request_delete(l_sync_request);
+        DAP_DELETE(l_sync_request);
         return;
     }
 
@@ -609,7 +600,7 @@ static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
     if (l_pkt_item->pkt_data_size) {
         size_t l_data_obj_count = 0;
         // deserialize data & Parse data from dap_db_log_pack()
-        dap_store_obj_t *l_store_obj = dap_db_log_unpack(l_pkt_item->pkt_data, l_pkt_item->pkt_data_size, &l_data_obj_count);
+        dap_store_obj_t *l_store_obj = dap_store_unpacket_multiple((dap_store_obj_pkt_t *)l_pkt_item->pkt_data, &l_data_obj_count);
         if (s_debug_more){
             if (l_data_obj_count)
                 log_it(L_INFO, "In: GLOBAL_DB parse: pkt_data_size=%zd, l_data_obj_count = %d",l_pkt_item->pkt_data_size, l_data_obj_count );
@@ -619,46 +610,25 @@ static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
                  log_it(L_WARNING, "In: GLOBAL_DB parse: packet in list with NULL data(pkt_data_size:%zd)", l_pkt_item->pkt_data_size);
         }
 
-        for(size_t i = 0; i < l_data_obj_count; i++) {
-            // timestamp for exist obj
-            time_t l_timestamp_cur = 0;
+        for (size_t i = 0; i < l_data_obj_count; i++) {
             // obj to add
-            dap_store_obj_t* l_obj = l_store_obj + i;
-            // read item from base;
-            size_t l_count_read = 0;
-            dap_store_obj_t *l_read_obj = dap_chain_global_db_driver_read(l_obj->group,
-                    l_obj->key, &l_count_read);
-            // get timestamp for the exist entry
-            if(l_read_obj)
-                l_timestamp_cur = l_read_obj->timestamp;
-            // get timestamp for the deleted entry
-            else
-            {
-                l_timestamp_cur = global_db_gr_del_get_timestamp(l_obj->group, l_obj->key);
-            }
-
+            dap_store_obj_t *l_obj = l_store_obj + i;
             //check whether to apply the received data into the database
-            bool l_apply = true;
-            if(l_obj->timestamp < l_timestamp_cur)
-                l_apply = false;
-            else if(l_obj->type == 'd') {
-                // already deleted
-                if(!l_read_obj)
-                    l_apply = false;
+            bool l_apply = false;
+            // timestamp for exist obj
+            time_t l_timestamp_cur = 0;
+            if (dap_chain_global_db_driver_is(l_obj->group, l_obj->key)) {
+                dap_store_obj_t *l_read_obj = dap_chain_global_db_driver_read(l_obj->group, l_obj->key, NULL);
+                if (l_read_obj) {
+                    l_timestamp_cur = l_read_obj->timestamp;
+                    dap_store_obj_free(l_read_obj, 1);
+                }
             }
-            else if(l_obj->type == 'a') {
-                bool l_is_the_same_present = false;
-                if(l_read_obj &&
-                        l_read_obj->value_len == l_obj->value_len &&
-                        !memcmp(l_read_obj->value, l_obj->value, l_obj->value_len))
-                    l_is_the_same_present = true;
-                // this data already present in global_db and not obsolete (out of date)
-                if(l_read_obj && (l_is_the_same_present || l_read_obj->timestamp >= l_store_obj->timestamp))
-                    l_apply = false;
+            // check the applied object newer that we have stored or erased
+            if (l_obj->timestamp > global_db_gr_del_get_timestamp(l_obj->group, l_obj->key) &&
+                    l_obj->timestamp > l_timestamp_cur) {
+                l_apply = true;
             }
-            if(l_read_obj)
-                dap_store_obj_free(l_read_obj, l_count_read);
-
             if (s_debug_more){
                 char l_ts_str[50];
                 dap_time_to_str_rfc822(l_ts_str, sizeof(l_ts_str), l_store_obj[i].timestamp);
@@ -667,12 +637,7 @@ static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
                         (char ) l_store_obj[i].type, l_store_obj[i].type, l_store_obj[i].group,
                         l_store_obj[i].key, l_ts_str, l_store_obj[i].value_len);
             }
-
-            if(!l_apply) {
-                // If request was from defined node_addr we update its state
-                if(l_sync_request->request.node_addr.uint64) {
-                    dap_db_set_last_id_remote(l_sync_request->request.node_addr.uint64, l_obj->id);
-                }
+            if (!l_apply) {
                 continue;
             }
 
@@ -680,7 +645,7 @@ static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
             dap_chain_t *l_chain = dap_chain_find_by_id(l_sync_request->request_hdr.net_id, l_sync_request->request_hdr.chain_id);
             if(l_chain) {
                 if(l_chain->callback_add_datums_with_group){
-                    void * restrict l_store_obj_value = l_store_obj->value;
+                    void * restrict l_store_obj_value = l_store_obj[i].value;
                     l_chain->callback_add_datums_with_group(l_chain,
                             (dap_chain_datum_t** restrict) l_store_obj_value, 1,
                             l_store_obj[i].group);
@@ -688,17 +653,13 @@ static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
             }
             // save data to global_db
             if(!dap_chain_global_db_obj_save(l_obj, 1)) {
-                if(l_store_obj)
-                    dap_store_obj_free(l_store_obj, l_data_obj_count);
-                dap_proc_thread_worker_exec_callback(a_thread, l_sync_request->worker->id, s_gdb_in_pkt_error_worker_callback, l_sync_request);
-                return true;
+                struct sync_request *l_sync_req_err = DAP_NEW_Z(struct sync_request);
+                memcpy(l_sync_req_err, l_sync_request, sizeof(struct sync_request));
+                dap_proc_thread_worker_exec_callback(a_thread, l_sync_request->worker->id,
+                                                  s_gdb_in_pkt_error_worker_callback, l_sync_req_err);
             } else {
-                // If request was from defined node_addr we update its state
-                if(l_sync_request->request.node_addr.uint64) {
-                    dap_db_set_last_id_remote(l_sync_request->request.node_addr.uint64, l_obj->id);
-                }
                 if (s_debug_more)
-                    log_it(L_DEBUG, "Added new GLOBAL_DB history pack");
+                    log_it(L_DEBUG, "Added new GLOBAL_DB synchronization record");
             }
         }
         if(l_store_obj)
@@ -721,7 +682,6 @@ static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
 struct sync_request *dap_stream_ch_chain_create_sync_request(dap_stream_ch_chain_pkt_t *a_chain_pkt, dap_stream_ch_t* a_ch)
 {
     dap_stream_ch_chain_t * l_ch_chain = DAP_STREAM_CH_CHAIN(a_ch);
-    memcpy(&l_ch_chain->request, a_chain_pkt->data, sizeof(l_ch_chain->request));
     memcpy(&l_ch_chain->request_hdr, &a_chain_pkt->hdr, sizeof(l_ch_chain->request_hdr));
     struct sync_request *l_sync_request = DAP_NEW_Z(struct sync_request);
     l_sync_request->ch_uuid = a_ch->uuid;
@@ -749,11 +709,13 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
 {
     dap_stream_ch_chain_t * l_ch_chain = DAP_STREAM_CH_CHAIN(a_ch);
     if (!l_ch_chain) {
+        log_it(L_ERROR, "No chain in channel, returning");
         return;
     }
     dap_stream_ch_pkt_t * l_ch_pkt = (dap_stream_ch_pkt_t *) a_arg;
     dap_stream_ch_chain_pkt_t * l_chain_pkt = (dap_stream_ch_chain_pkt_t *) l_ch_pkt->data;
     if (!l_chain_pkt) {
+        log_it(L_ERROR, "No chain packet in channel packet, returning");
         return;
     }
     if (l_ch_pkt->hdr.size< sizeof (l_chain_pkt->hdr) ){
@@ -807,21 +769,30 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
             if(s_debug_more)
                 log_it(L_INFO, "In:  UPDATE_GLOBAL_DB_REQ pkt: net 0x%016x chain 0x%016x cell 0x%016x", l_chain_pkt->hdr.net_id.uint64 ,
                                     l_chain_pkt->hdr.chain_id.uint64, l_chain_pkt->hdr.cell_id.uint64);
-            l_ch_chain->state = CHAIN_STATE_UPDATE_GLOBAL_DB;
+            if (l_chain_pkt_data_size == sizeof(dap_stream_ch_chain_sync_request_t))
+                memcpy(&l_ch_chain->request, l_chain_pkt->data, sizeof(dap_stream_ch_chain_sync_request_t));
+            dap_chain_node_client_t *l_client = (dap_chain_node_client_t *)l_ch_chain->callback_notify_arg;
+            if (l_client && l_client->resync_gdb)
+                l_ch_chain->request.id_start = 0;
+            else
+                l_ch_chain->request.id_start = 1;   // incremental sync by default
             struct sync_request *l_sync_request = dap_stream_ch_chain_create_sync_request(l_chain_pkt, a_ch);
             l_ch_chain->stats_request_gdb_processed = 0;
-            dap_worker_exec_callback_on( a_ch->stream_worker->worker, s_sync_update_gdb_proc_callback, l_sync_request);
-        }break;
+            dap_proc_queue_add_callback_inter(a_ch->stream_worker->worker->proc_queue_input, s_sync_update_gdb_proc_callback, l_sync_request);
+        } break;
+
         // Response with metadata organized in TSD
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_TSD:{
+            if (s_debug_more)
+                log_it(L_DEBUG, "Global DB TSD packet detected");
+        } break;
 
-        }break;
         // If requested - begin to recieve record's hashes
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_START:{
             if (s_debug_more)
                 log_it(L_INFO, "In:  UPDATE_GLOBAL_DB_START pkt net 0x%016x chain 0x%016x cell 0x%016x", l_chain_pkt->hdr.net_id.uint64 ,
                        l_chain_pkt->hdr.chain_id.uint64, l_chain_pkt->hdr.cell_id.uint64);
-            if(l_ch_chain->state != CHAIN_STATE_IDLE){
+            if (l_ch_chain->state != CHAIN_STATE_IDLE){
                 log_it(L_WARNING, "Can't process UPDATE_GLOBAL_DB_START request because its already busy with syncronization");
                 s_stream_ch_write_error_unsafe(a_ch, l_chain_pkt->hdr.net_id.uint64,
                         l_chain_pkt->hdr.chain_id.uint64, l_chain_pkt->hdr.cell_id.uint64,
@@ -830,12 +801,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
             }
             memcpy(&l_ch_chain->request_hdr, &l_chain_pkt->hdr, sizeof(dap_stream_ch_chain_pkt_t));
             l_ch_chain->state = CHAIN_STATE_UPDATE_GLOBAL_DB_REMOTE;
-            dap_stream_ch_chain_hash_item_t *l_hash_item = NULL, *l_tmp = NULL;
-            HASH_ITER(hh, l_ch_chain->remote_gdbs, l_hash_item, l_tmp) {
-                HASH_DEL(l_ch_chain->remote_gdbs, l_hash_item);
-                DAP_DELETE(l_hash_item);
-            }
-        }break;
+        } break;
         // Response with gdb element hashes and sizes
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB:{
             if(s_debug_more)
@@ -858,14 +824,14 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                     memcpy(&l_hash_item->hash, &l_element->hash, sizeof (l_element->hash));
                     l_hash_item->size = l_element->size;
                     HASH_ADD(hh, l_ch_chain->remote_gdbs, hash, sizeof (l_hash_item->hash), l_hash_item);
-                    if (s_debug_more){
+                    /*if (s_debug_more){
                         char l_hash_str[72]={ [0]='\0'};
                         dap_chain_hash_fast_to_str(&l_hash_item->hash,l_hash_str,sizeof (l_hash_str));
-                        log_it(L_INFO,"In: Updated remote hash gdb list with %s ", l_hash_str);
-                    }
+                        log_it(L_DEBUG,"In: Updated remote hash gdb list with %s ", l_hash_str);
+                    }*/
                 }
             }
-        }break;
+        } break;
         // End of response with starting of DB sync
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB:
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_END: {
@@ -893,8 +859,9 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                     else
                         log_it(L_INFO, "In: SYNC_GLOBAL_DB pkt");
                 }
+                if (l_chain_pkt_data_size == sizeof(dap_stream_ch_chain_sync_request_t))
+                    memcpy(&l_ch_chain->request, l_chain_pkt->data, sizeof(dap_stream_ch_chain_sync_request_t));
                 struct sync_request *l_sync_request = dap_stream_ch_chain_create_sync_request(l_chain_pkt, a_ch);
-                l_ch_chain->state = CHAIN_STATE_SYNC_GLOBAL_DB;
                 dap_proc_queue_add_callback_inter(a_ch->stream_worker->worker->proc_queue_input, s_sync_out_gdb_proc_callback, l_sync_request);
             }else{
                 log_it(L_WARNING, "DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB: Wrong chain packet size %zd when expected %zd", l_chain_pkt_data_size, sizeof(l_ch_chain->request));
@@ -943,7 +910,6 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                        l_chain_pkt->hdr.chain_id.uint64, l_chain_pkt->hdr.cell_id.uint64);
                 if (!l_ch_chain->callback_notify_packet_in) { // we haven't node client waitng, so reply to other side
                     dap_stream_ch_chain_sync_request_t l_sync_gdb = {};
-                    l_sync_gdb.id_start = dap_db_get_last_id_remote(l_sync_gdb.node_addr.uint64);
                     dap_chain_net_t *l_net = dap_chain_net_by_id(l_chain_pkt->hdr.net_id);
                     l_sync_gdb.node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
                     dap_stream_ch_chain_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_REQ, l_chain_pkt->hdr.net_id.uint64,
@@ -953,7 +919,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
 
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_GLOBAL_DB_RVRS: {
             dap_stream_ch_chain_sync_request_t l_sync_gdb = {};
-            l_sync_gdb.id_start = dap_db_get_last_id_remote(l_sync_gdb.node_addr.uint64);
+            l_sync_gdb.id_start = 1;
             dap_chain_net_t *l_net = dap_chain_net_by_id(l_chain_pkt->hdr.net_id);
             l_sync_gdb.node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
             log_it(L_INFO, "In:  SYNC_GLOBAL_DB_RVRS pkt: net 0x%016x chain 0x%016x cell 0x%016x, request gdb sync from %u", l_chain_pkt->hdr.net_id.uint64 ,
@@ -969,7 +935,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
         } break;
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_GLOBAL_DB_GROUP: {
             if (s_debug_more)
-                log_it(L_INFO, "In:  SYNCED_GLOBAL_DB_GROUP pkt net 0x%016x chain 0x%016x cell 0x%016x", l_chain_pkt->hdr.net_id.uint64 ,
+                log_it(L_INFO, "In:  FIRST_GLOBAL_DB_GROUP pkt net 0x%016x chain 0x%016x cell 0x%016x", l_chain_pkt->hdr.net_id.uint64 ,
                        l_chain_pkt->hdr.chain_id.uint64, l_chain_pkt->hdr.cell_id.uint64);
         } break;
 
@@ -999,11 +965,12 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                                                      l_chain_pkt->hdr.net_id.uint64,l_chain_pkt->hdr.chain_id.uint64,
                                                      l_chain_pkt->hdr.cell_id.uint64, NULL, 0);
             }
-        }break;
+        } break;
         // Response with metadata organized in TSD
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_CHAINS_TSD :{
-
-        }break;
+            if (s_debug_more)
+                log_it(L_DEBUG, "Chain TSD packet detected");
+        } break;
 
         // If requested - begin to send atom hashes
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_CHAINS_START:{
@@ -1029,19 +996,14 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
             }
             l_ch_chain->state = CHAIN_STATE_UPDATE_CHAINS_REMOTE;
             memcpy(&l_ch_chain->request_hdr, &l_chain_pkt->hdr, sizeof(dap_stream_ch_chain_pkt_hdr_t));
-            dap_stream_ch_chain_hash_item_t *l_hash_item = NULL, *l_tmp = NULL;
-            HASH_ITER(hh, l_ch_chain->remote_atoms, l_hash_item, l_tmp) {
-                HASH_DEL(l_ch_chain->remote_atoms, l_hash_item);
-                DAP_DELETE(l_hash_item);
-            }
             if(s_debug_more)
                 log_it(L_INFO,"In: UPDATE_CHAINS_START pkt");
         } break;
 
         // Response with atom hashes and sizes
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_CHAINS :{
-            uint l_count_added=0;
-            uint l_count_total=0;
+            unsigned int l_count_added=0;
+            unsigned int l_count_total=0;
 
             dap_chain_t * l_chain = dap_chain_find_by_id(l_chain_pkt->hdr.net_id, l_chain_pkt->hdr.chain_id);
             if (! l_chain){
@@ -1119,13 +1081,16 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                 }
                 struct sync_request *l_sync_request = dap_stream_ch_chain_create_sync_request(l_chain_pkt, a_ch);
                 l_ch_chain->state = CHAIN_STATE_SYNC_CHAINS;
-                char *l_hash_from_str = dap_chain_hash_fast_to_str_new(&l_ch_chain->request.hash_from);
-                char *l_hash_to_str = dap_chain_hash_fast_to_str_new(&l_ch_chain->request.hash_to);
-                log_it(L_INFO, "In:  SYNC_CHAINS pkt: net 0x%016x chain 0x%016x cell 0x%016x between %s and %s", l_ch_chain->request_hdr.net_id.uint64 ,
-                       l_ch_chain->request_hdr.chain_id.uint64, l_ch_chain->request_hdr.cell_id.uint64,
-                       l_hash_from_str? l_hash_from_str: "(null)", l_hash_to_str?l_hash_to_str:"(null)");
-                DAP_DELETE(l_hash_from_str);
-                DAP_DELETE(l_hash_to_str);
+                l_ch_chain->stats_request_atoms_processed = 0;
+                if (l_ch_pkt->hdr.type == DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS) {
+                    char *l_hash_from_str = dap_chain_hash_fast_to_str_new(&l_ch_chain->request.hash_from);
+                    char *l_hash_to_str = dap_chain_hash_fast_to_str_new(&l_ch_chain->request.hash_to);
+                    log_it(L_INFO, "In:  SYNC_CHAINS pkt: net 0x%016x chain 0x%016x cell 0x%016x between %s and %s", l_ch_chain->request_hdr.net_id.uint64 ,
+                           l_ch_chain->request_hdr.chain_id.uint64, l_ch_chain->request_hdr.cell_id.uint64,
+                           l_hash_from_str? l_hash_from_str: "(null)", l_hash_to_str?l_hash_to_str:"(null)");
+                    DAP_DELETE(l_hash_from_str);
+                    DAP_DELETE(l_hash_to_str);
+                }
                 dap_proc_queue_add_callback_inter(a_ch->stream_worker->worker->proc_queue_input, s_sync_out_chains_proc_callback, l_sync_request);
             } else {
                 log_it(L_WARNING, "DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNC_CHAINS: Wrong chain packet size %zd when expected %zd",
@@ -1144,7 +1109,6 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                        NODE_ADDR_FP_ARGS_S(l_ch_chain->request.node_addr),
                        l_chain_pkt_data_size,      l_ch_chain->request_hdr.net_id.uint64 ,
                        l_ch_chain->request_hdr.chain_id.uint64, l_ch_chain->request_hdr.cell_id.uint64);
-                l_ch_chain->stats_request_atoms_processed = 0;
             }else{
                 log_it(L_WARNING,"Incorrect data size %zd in packet DAP_STREAM_CH_CHAIN_PKT_TYPE_FIRST_CHAIN", l_chain_pkt_data_size);
                 s_stream_ch_write_error_unsafe(a_ch, l_chain_pkt->hdr.net_id.uint64,
@@ -1205,6 +1169,9 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                                                         "ERROR_NET_INVALID_ID");
                     break;
                 }
+                if (s_debug_more) {
+                    log_it(L_INFO, "Out: UPDATE_CHAINS_REQ pkt");
+                }
                 dap_stream_ch_chain_sync_request_t l_request= {};
                 dap_stream_ch_chain_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_CHAINS_REQ, l_chain_pkt->hdr.net_id.uint64,
                                               l_chain_pkt->hdr.chain_id.uint64, l_chain_pkt->hdr.cell_id.uint64, &l_request, sizeof(l_request));
@@ -1241,14 +1208,13 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                 l_error_str[l_chain_pkt_data_size-1]='\0'; // To be sure that nobody sends us garbage
                                                            // without trailing zero
             log_it(L_WARNING,"In from remote addr %s chain id 0x%016x got error on his side: '%s'",
-                   l_ch_chain->ch->stream->esocket->remote_addr_str?
-                                                                                    l_ch_chain->ch->stream->esocket->remote_addr_str: "<no addr>",
-                   l_chain_pkt->hdr.chain_id.uint64, l_chain_pkt_data_size>1? l_error_str:"<empty>");
+                   l_ch_chain->ch->stream->esocket->remote_addr_str ? l_ch_chain->ch->stream->esocket->remote_addr_str: "<no addr>",
+                   l_chain_pkt->hdr.chain_id.uint64, l_chain_pkt_data_size > 1 ? l_error_str:"<empty>");
         } break;
 
         case DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_ALL: {
             log_it(L_INFO, "In from "NODE_ADDR_FP_STR":  SYNCED_ALL net 0x%016x chain 0x%016x cell 0x%016x",NODE_ADDR_FP_ARGS_S(l_ch_chain->node_client->remote_node_addr), l_chain_pkt->hdr.net_id.uint64 ,
-                   l_chain_pkt->hdr.chain_id.uint64, l_chain_pkt->hdr.cell_id.uint64);
+                           l_chain_pkt->hdr.chain_id.uint64, l_chain_pkt->hdr.cell_id.uint64);
         } break;
 
         default: {
@@ -1285,29 +1251,17 @@ void dap_stream_ch_chain_go_idle ( dap_stream_ch_chain_t * a_ch_chain)
             }
         DAP_DEL_Z(a_ch_chain->request_atom_iter);
     }
-}
-
-static void s_process_gdb_iter(dap_stream_ch_t *a_ch)
-{
-    dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(a_ch);
-    dap_db_log_list_t *l_db_list = l_ch_chain->request_global_db_trs;
-    dap_store_obj_pkt_t *l_pkt = (dap_store_obj_pkt_t *)l_ch_chain->request_db_iter->data;
-    uint32_t l_pkt_size = sizeof(dap_store_obj_pkt_t) + l_pkt->data_size;
-    // TODO find current record hash and compare it with hash table
-    if( s_debug_more)
-        log_it(L_INFO, "Send one global_db record packet len=%d (rest=%d/%d items)", l_pkt_size,
-           dap_db_log_list_get_count_rest(l_db_list), dap_db_log_list_get_count(l_db_list));
-    dap_stream_ch_chain_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_GLOBAL_DB,
-                                         l_ch_chain->request_hdr.net_id.uint64, l_ch_chain->request_hdr.chain_id.uint64,
-                                         l_ch_chain->request_hdr.cell_id.uint64, l_pkt, l_pkt_size);
-    dap_list_t *l_iter = dap_list_next(l_ch_chain->request_db_iter);
-    if (l_iter) {
-        l_ch_chain->request_db_iter = l_iter;
-    } else {
-        l_ch_chain->stats_request_gdb_processed++;
-        l_ch_chain->request_db_iter = dap_list_first(l_ch_chain->request_db_iter);
-        dap_list_free_full(l_ch_chain->request_db_iter, free);
-        l_ch_chain->request_db_iter = NULL;
+    // free log list
+    dap_db_log_list_delete(a_ch_chain->request_db_log);
+    a_ch_chain->request_db_log = NULL;
+    dap_stream_ch_chain_hash_item_t *l_hash_item = NULL, *l_tmp = NULL;
+    HASH_ITER(hh, a_ch_chain->remote_gdbs, l_hash_item, l_tmp) {
+        HASH_DEL(a_ch_chain->remote_gdbs, l_hash_item);
+        DAP_DELETE(l_hash_item);
+    }
+    HASH_ITER(hh, a_ch_chain->remote_atoms, l_hash_item, l_tmp) {
+        HASH_DEL(a_ch_chain->remote_atoms, l_hash_item);
+        DAP_DELETE(l_hash_item);
     }
 }
 
@@ -1325,69 +1279,104 @@ void s_stream_ch_packet_out(dap_stream_ch_t* a_ch, void* a_arg)
     dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(a_ch);
 
     switch (l_ch_chain->state) {
-
         // Update list of global DB records to remote
         case CHAIN_STATE_UPDATE_GLOBAL_DB: {
-            if (l_ch_chain->stats_request_gdb_processed == l_ch_chain->local_gdbs_count) {
-                dap_stream_ch_chain_sync_request_t l_sync_gdb = {};
-                l_sync_gdb.id_start = dap_db_get_last_id_remote(l_ch_chain->request.node_addr.uint64);
-                dap_chain_net_t *l_net = dap_chain_net_by_id(l_ch_chain->request_hdr.net_id);
-                l_sync_gdb.node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
-                dap_stream_ch_chain_pkt_write_unsafe(l_ch_chain->ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_END,
-                                                     l_ch_chain->request_hdr.net_id.uint64, l_ch_chain->request_hdr.chain_id.uint64,
-                                                     l_ch_chain->request_hdr.cell_id.uint64, &l_sync_gdb, sizeof(dap_stream_ch_chain_sync_request_t));
-                if (s_debug_more )
-                    log_it(L_INFO, "Out: DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_END");
-                dap_stream_ch_chain_go_idle(l_ch_chain);
-            } else {
-                uint_fast16_t l_count = l_ch_chain->local_gdbs_count - l_ch_chain->stats_request_gdb_processed;
-                if (l_count > s_update_pack_size)
-                    l_count = s_update_pack_size;
+            dap_stream_ch_chain_update_element_t l_data[s_update_pack_size];
+            uint_fast16_t i;
+            for (i = 0; i < s_update_pack_size; i++) {
+                dap_db_log_list_obj_t *l_obj = dap_db_log_list_get(l_ch_chain->request_db_log);
+                if (!l_obj)
+                    break;
+                memcpy(&l_data[i].hash, &l_obj->hash, sizeof(dap_chain_hash_fast_t));
+                l_data[i].size = l_obj->pkt->data_size;
+            }
+            if (i) {
                 dap_stream_ch_chain_pkt_write_unsafe(l_ch_chain->ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB,
                                                      l_ch_chain->request_hdr.net_id.uint64, l_ch_chain->request_hdr.chain_id.uint64,
                                                      l_ch_chain->request_hdr.cell_id.uint64,
-                                                     &l_ch_chain->local_gdbs[l_ch_chain->stats_request_gdb_processed],
-                                                     l_count * sizeof(dap_stream_ch_chain_update_element_t));
-                l_ch_chain->stats_request_gdb_processed += l_count;
+                                                     l_data, i * sizeof(dap_stream_ch_chain_update_element_t));
+                l_ch_chain->stats_request_gdb_processed += i;
                 if (s_debug_more)
                     log_it(L_INFO, "Out: DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB");
+            } else {
+                l_ch_chain->request.node_addr.uint64 = dap_chain_net_get_cur_addr_int(dap_chain_net_by_id(
+                                                                                          l_ch_chain->request_hdr.net_id));
+                dap_stream_ch_chain_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_END,
+                                                     l_ch_chain->request_hdr.net_id.uint64,
+                                                     l_ch_chain->request_hdr.chain_id.uint64,
+                                                     l_ch_chain->request_hdr.cell_id.uint64,
+                                                     &l_ch_chain->request, sizeof(dap_stream_ch_chain_sync_request_t));
+                if (s_debug_more )
+                    log_it(L_INFO, "Out: DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_END");
+                dap_stream_ch_chain_go_idle(l_ch_chain);
             }
         } break;
 
         // Synchronize GDB
         case CHAIN_STATE_SYNC_GLOBAL_DB: {
-            if (l_ch_chain->request_db_iter) {
-                s_process_gdb_iter(a_ch);
-            } else {
-                dap_global_db_obj_t *l_obj;
-                do { // Get log diff
-                    size_t l_item_size_out = 0;
-                    l_obj = dap_db_log_list_get(l_ch_chain->request_global_db_trs);
-                    l_ch_chain->request_db_iter = dap_db_log_pack(l_obj, &l_item_size_out);
-                    if (l_ch_chain->request_db_iter && l_item_size_out) {
-                        break;
-                    }
-                    // Item not found, maybe it has deleted? Then go to the next item
-                } while (l_obj);
-                if (l_ch_chain->request_db_iter) {
-                    s_process_gdb_iter(a_ch);
+            // Get global DB record
+            dap_store_obj_pkt_t *l_pkt = NULL;
+            dap_db_log_list_obj_t *l_obj = NULL;
+            size_t l_pkt_size = 0;
+            for (uint_fast16_t l_skip_count = 0; l_skip_count < s_skip_in_reactor_count; ) {
+                l_obj = dap_db_log_list_get(l_ch_chain->request_db_log);
+                if (!l_obj)
+                    break;
+                dap_stream_ch_chain_hash_item_t *l_hash_item = NULL;
+                HASH_FIND(hh, l_ch_chain->remote_gdbs, &l_obj->hash, sizeof(dap_hash_fast_t), l_hash_item);
+                if (l_hash_item) { // If found - skip it
+                    /*if (s_debug_more) {
+                        char l_request_atom_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
+                        dap_chain_hash_fast_to_str(&l_obj->hash, l_request_atom_hash_str, DAP_CHAIN_HASH_FAST_STR_SIZE);
+                        log_it(L_DEBUG, "Out CHAIN: skip GDB hash %s because its already present in remote GDB hash table",
+                                        l_request_atom_hash_str);
+                    }*/
+                    l_skip_count++;
                 } else {
-                    // free log list
-                    dap_db_log_list_delete(l_ch_chain->request_global_db_trs);
-                    l_ch_chain->request_global_db_trs = NULL;
-                    log_it( L_INFO,"Syncronized database:  last id %"DAP_UINT64_FORMAT_U", items syncronyzed %"DAP_UINT64_FORMAT_U" ", dap_db_log_get_last_id(),
-                        l_ch_chain->stats_request_gdb_processed );
-                    // last message
-                    dap_stream_ch_chain_sync_request_t l_request = {};
-                    dap_stream_ch_chain_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
-                                                         l_ch_chain->request_hdr.net_id.uint64, l_ch_chain->request_hdr.chain_id.uint64,
-                                                         l_ch_chain->request_hdr.cell_id.uint64, &l_request, sizeof(l_request));
-                    dap_stream_ch_chain_go_idle(l_ch_chain);
-                    if (l_ch_chain->callback_notify_packet_out)
-                        l_ch_chain->callback_notify_packet_out(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
-                                                               NULL, 0, l_ch_chain->callback_notify_arg);
+                    if (l_ch_chain->request.node_addr.uint64) {
+                        dap_db_set_last_id_remote(l_ch_chain->request.node_addr.uint64,
+                                                  dap_store_packet_get_id(l_obj->pkt),
+                                                  dap_store_packet_get_group(l_obj->pkt));
+                    }
+                    l_hash_item = DAP_NEW(dap_stream_ch_chain_hash_item_t);
+                    memcpy(&l_hash_item->hash, &l_obj->hash, sizeof(dap_chain_hash_fast_t));
+                    l_hash_item->size = l_obj->pkt->data_size;
+                    HASH_ADD(hh, l_ch_chain->remote_gdbs, hash, sizeof(dap_chain_hash_fast_t), l_hash_item);
+                    l_pkt = dap_store_packet_multiple(l_pkt, l_obj->pkt);
+                    l_ch_chain->stats_request_gdb_processed++;
+                    l_pkt_size = sizeof(dap_store_obj_pkt_t) + l_pkt->data_size;
+                    if (l_pkt_size >= DAP_CHAIN_PKT_EXPECT_SIZE)
+                        break;
                 }
             }
+            if (l_pkt_size) {
+                // If request was from defined node_addr we update its state
+                if( s_debug_more)
+                    log_it(L_INFO, "Send one global_db packet len=%d (rest=%d/%d items)", l_pkt_size,
+                                    dap_db_log_list_get_count_rest(l_ch_chain->request_db_log),
+                                    dap_db_log_list_get_count(l_ch_chain->request_db_log));
+                dap_stream_ch_chain_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_GLOBAL_DB,
+                                                     l_ch_chain->request_hdr.net_id.uint64, l_ch_chain->request_hdr.chain_id.uint64,
+                                                     l_ch_chain->request_hdr.cell_id.uint64, l_pkt, l_pkt_size);
+                DAP_DELETE(l_pkt);
+            } else if (l_obj) {
+                // Sending dumb packet with nothing to inform remote thats we're just skiping GDBs, nothing freezed
+                dap_stream_ch_chain_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_TSD,
+                                                     l_ch_chain->request_hdr.net_id.uint64, l_ch_chain->request_hdr.chain_id.uint64,
+                                                     l_ch_chain->request_hdr.cell_id.uint64, NULL, 0);
+            } else {
+                log_it( L_INFO,"Syncronized database: items syncronyzed %"DAP_UINT64_FORMAT_u" from %"DAP_UINT64_FORMAT_u"",
+                        l_ch_chain->stats_request_gdb_processed, dap_db_log_list_get_count(l_ch_chain->request_db_log));
+                // last message
+                dap_stream_ch_chain_sync_request_t l_request = {};
+                dap_stream_ch_chain_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
+                                                     l_ch_chain->request_hdr.net_id.uint64, l_ch_chain->request_hdr.chain_id.uint64,
+                                                     l_ch_chain->request_hdr.cell_id.uint64, &l_request, sizeof(l_request));
+                dap_stream_ch_chain_go_idle(l_ch_chain);
+                if (l_ch_chain->callback_notify_packet_out)
+                    l_ch_chain->callback_notify_packet_out(l_ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_SYNCED_GLOBAL_DB,
+                                                           NULL, 0, l_ch_chain->callback_notify_arg);
+            }
         } break;
 
         // Update list of atoms to remote
@@ -1478,6 +1467,8 @@ void s_stream_ch_packet_out(dap_stream_ch_t* a_ch, void* a_arg)
                 }
                 // Then get next atom and populate new last
                 l_ch_chain->request_atom_iter->chain->callback_atom_iter_get_next(l_ch_chain->request_atom_iter, NULL);
+                if (l_was_sent_smth)
+                    break;
             }
             if(!l_ch_chain->request_atom_iter || !l_ch_chain->request_atom_iter->cur)  { // All chains synced
                 dap_stream_ch_chain_sync_request_t l_request = {0};
diff --git a/modules/channel/chain/include/dap_stream_ch_chain.h b/modules/channel/chain/include/dap_stream_ch_chain.h
index 07cd345916bd4ac0b1567405d083743aa4539418..5fd46f5c682158bb1b8c4b9323297161383170e6 100644
--- a/modules/channel/chain/include/dap_stream_ch_chain.h
+++ b/modules/channel/chain/include/dap_stream_ch_chain.h
@@ -65,31 +65,23 @@ typedef struct dap_stream_ch_chain {
     uint64_t stats_request_atoms_processed;
     uint64_t stats_request_gdb_processed;
 
-
-    dap_stream_ch_chain_update_element_t *local_gdbs;
-    uint64_t local_gdbs_count;
     dap_stream_ch_chain_hash_item_t * remote_atoms; // Remote atoms
     dap_stream_ch_chain_hash_item_t * remote_gdbs; // Remote gdbs
 
     // request section
     dap_chain_atom_iter_t *request_atom_iter;
-    dap_db_log_list_t *request_global_db_trs; // list of global db records
+    dap_db_log_list_t *request_db_log; // list of global db records
     dap_stream_ch_chain_sync_request_t request;
     dap_stream_ch_chain_pkt_hdr_t request_hdr;
     dap_list_t *request_db_iter;
 
-    bool request_updates_complete;
-
-    bool is_on_request; // Protects request section
-    bool is_on_reverse_request;
-
     dap_stream_ch_chain_callback_packet_t callback_notify_packet_out;
     dap_stream_ch_chain_callback_packet_t callback_notify_packet_in;
     void *callback_notify_arg;
 } dap_stream_ch_chain_t;
 
 #define DAP_STREAM_CH_CHAIN(a) ((dap_stream_ch_chain_t *) ((a)->internal) )
-
+#define DAP_CHAIN_PKT_EXPECT_SIZE 7168
 
 int dap_stream_ch_chain_init(void);
 void dap_stream_ch_chain_deinit(void);
diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c
index 7af1ea5a5130319edef32298a345619a4b11366e..96f0ae56df8970dd701729f088e9d0bcc0607efa 100644
--- a/modules/common/dap_chain_datum_tx_items.c
+++ b/modules/common/dap_chain_datum_tx_items.c
@@ -156,7 +156,6 @@ dap_chain_tx_token_t* dap_chain_datum_tx_item_token_create(dap_chain_hash_fast_t
     l_item->header.type = TX_ITEM_TYPE_TOKEN;
     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/consensus/none/dap_chain_cs_none.c b/modules/consensus/none/dap_chain_cs_none.c
index 707465f28882e1a2f4fbd0d152680aa410c1972d..b3bae67c29784c400075212ca7816f8bb8fcb6a5 100644
--- a/modules/consensus/none/dap_chain_cs_none.c
+++ b/modules/consensus/none/dap_chain_cs_none.c
@@ -128,7 +128,7 @@ int dap_chain_gdb_init(void)
  * @param a_value
  * @param a_value_len
  */
-static void s_history_callback_notify(void * a_arg, const char a_op_code, const char * a_prefix, const char * a_group,
+static void s_history_callback_notify(void * a_arg, const char a_op_code, const char * a_group,
         const char * a_key, const void * a_value, const size_t a_value_size)
 {
     if (a_arg){
@@ -136,8 +136,8 @@ static void s_history_callback_notify(void * a_arg, const char a_op_code, const
         dap_chain_net_t *l_net = dap_chain_net_by_id( l_gdb->chain->net_id);
         log_it(L_DEBUG,"%s.%s: op_code='%c' group=\"%s\" key=\"%s\" value_size=%u",l_net->pub.name,
                l_gdb->chain->name, a_op_code, a_group, a_key, a_value_size);
-        dap_chain_node_mempool_autoproc_notify((void *)l_net, a_op_code, a_prefix, a_group, a_key, a_value, a_value_size);
-        dap_chain_net_sync_gdb_broadcast((void *)l_net, a_op_code, a_prefix, a_group, a_key, a_value, a_value_size);
+        dap_chain_node_mempool_autoproc_notify((void *)l_net, a_op_code, a_group, a_key, a_value, a_value_size);
+        dap_chain_net_sync_gdb_broadcast((void *)l_net, a_op_code, a_group, a_key, a_value, a_value_size);
     }
 }
 
@@ -174,9 +174,7 @@ int dap_chain_gdb_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     }
 
     // Add group prefix that will be tracking all changes
-    dap_chain_global_db_add_history_group_prefix("chain-gdb", GROUP_LOCAL_HISTORY);
-
-    dap_chain_global_db_add_history_callback_notify("chain-gdb", s_history_callback_notify,l_gdb);
+    dap_chain_global_db_add_sync_group("chain-gdb", s_history_callback_notify, l_gdb);
 
     // load ledger
     l_gdb_priv->is_load_mode = true;
diff --git a/modules/global-db/dap_chain_global_db.c b/modules/global-db/dap_chain_global_db.c
index 4a6ca4f938b1284b2f59c8845c23d91e8948505a..829c573e043ad52c2c514062ad86dadc3243d31b 100644
--- a/modules/global-db/dap_chain_global_db.c
+++ b/modules/global-db/dap_chain_global_db.c
@@ -62,135 +62,68 @@ static inline void unlock()
 }
 
 // Callback table item
-typedef struct history_group_item
+typedef struct sync_group_item
 {
-    char prefix[32];
-    uint8_t padding[7];
-    bool auto_track; // Track history actions automaticly
-    dap_global_db_obj_callback_notify_t callback_notify;
-    void * callback_arg;
-    char *group_name_for_history;
-    UT_hash_handle hh;
-} history_group_item_t;
-
-// Callback table item
-typedef struct history_extra_group_item
-{
-    char *group_name;
+    char *group_mask;
     char *group_name_for_history;
     dap_global_db_obj_callback_notify_t callback_notify;
     void * callback_arg;
     UT_hash_handle hh;
-} history_extra_group_item_t;
+} sync_group_item_t;
 
 // Tacked group callbacks
-static history_group_item_t * s_history_group_items = NULL;
-static history_extra_group_item_t * s_history_extra_group_items = NULL;
-char * extract_group_prefix(const char * a_group);
+static sync_group_item_t *s_sync_group_items = NULL;
+static sync_group_item_t *s_sync_group_extra_items = NULL;
+static bool s_track_history = false;
 
 /**
- * @brief extract_group_prefix
- * @param a_group
- * @return
- */
-char * extract_group_prefix(const char* a_group)
-{
-    char * l_group_prefix = NULL, *l_delimeter;
-    size_t l_group_prefix_size;
-
-//    l_delimeter = index(a_group, '.');
-    l_delimeter = strchr(a_group, '.');
-
-    if(l_delimeter == NULL) {
-        l_group_prefix = dap_strdup(a_group);
-        l_group_prefix_size = dap_strlen(l_group_prefix) + 1;
-    } else {
-        l_group_prefix_size = (size_t) l_delimeter - (size_t) a_group;
-        if(l_group_prefix_size > 1)
-            l_group_prefix = strndup(a_group, l_group_prefix_size);
-    }
-    return l_group_prefix;
-}
-
-
-/*
- * Get history group by group name
+ * @brief dap_chain_global_db_add_sync_group
+ * @details Add group name for synchronization
+ * @param a_group_prefix
  */
-char* dap_chain_global_db_get_history_group_by_group_name(const char * a_group_name)
+void dap_chain_global_db_add_sync_group(const char *a_group_prefix, dap_global_db_obj_callback_notify_t a_callback, void *a_arg)
 {
-    if(!s_history_extra_group_items || !a_group_name)
-        return NULL;
-    history_extra_group_item_t * l_history_extra_group_item = NULL;
-    HASH_FIND_STR(s_history_extra_group_items, a_group_name, l_history_extra_group_item);
-    if(l_history_extra_group_item) {
-        return dap_strdup(l_history_extra_group_item->group_name_for_history);
-    }else
-        return NULL;
+    sync_group_item_t * l_item = DAP_NEW_Z(sync_group_item_t);
+    l_item->group_mask = dap_strdup_printf("%s.*", a_group_prefix);
+    l_item->group_name_for_history = dap_strdup(GROUP_LOCAL_HISTORY);
+    l_item->callback_notify = a_callback;
+    l_item->callback_arg = a_arg;
+    HASH_ADD_STR(s_sync_group_items, group_mask, l_item);
 }
 
 /**
- * @brief dap_chain_global_db_add_history_group_prefix
- * @details Add group prefix that will be tracking all changes
+ * @brief dap_chain_global_db_add_sync_extra_group
+ * @details Add group name for synchronization with especially node addresses
  * @param a_group_prefix
- * @param a_group_name_for_history
  */
-void dap_chain_global_db_add_history_group_prefix(const char * a_group_prefix, const char * a_group_name_for_history)
+void dap_chain_global_db_add_sync_extra_group(const char *a_group_mask, dap_global_db_obj_callback_notify_t a_callback, void *a_arg)
 {
-    history_group_item_t * l_item = DAP_NEW_Z(history_group_item_t);
-    snprintf(l_item->prefix, sizeof(l_item->prefix), "%s", a_group_prefix);
-    l_item->group_name_for_history = dap_strdup(a_group_name_for_history);//GROUP_LOCAL_HISTORY
-    l_item->auto_track = true;
-    HASH_ADD_STR(s_history_group_items, prefix, l_item);
+    sync_group_item_t* l_item = DAP_NEW_Z(sync_group_item_t);
+    l_item->group_mask = dap_strdup(a_group_mask);
+    l_item->group_name_for_history = dap_strdup(GROUP_LOCAL_HISTORY".extra");
+    l_item->callback_notify = a_callback;
+    l_item->callback_arg = a_arg;
+    HASH_ADD_STR(s_sync_group_extra_items, group_mask, l_item);
 }
 
-/**
- * @brief dap_chain_global_db_add_history_callback_notify
- * @param a_group_prefix
- * @param a_callback
- */
-void dap_chain_global_db_add_history_callback_notify(const char * a_group_prefix,
-        dap_global_db_obj_callback_notify_t a_callback, void * a_arg)
+dap_list_t *dap_chain_db_get_sync_groups_internal(sync_group_item_t *a_table)
 {
-    history_group_item_t * l_item = NULL;
-    HASH_FIND_STR(s_history_group_items, a_group_prefix, l_item);
-    if(l_item) {
-        l_item->callback_notify = a_callback;
-        l_item->callback_arg = a_arg;
-    } else
-        log_it(L_WARNING, "Can't setup notify callback for groups with prefix %s. Possible not in history track state",
-                a_group_prefix);
+    dap_list_t *l_ret = NULL;
+    sync_group_item_t *l_item = NULL, *l_item_tmp = NULL;
+    HASH_ITER(hh, a_table, l_item, l_item_tmp) {
+        l_ret = dap_list_append(l_ret, l_item->group_mask);
+    }
+    return l_ret;
 }
 
-/**
- * @brief dap_chain_global_db_add_history_extra_group
- * @details Add group prefix that will be tracking all changes
- * @param a_group_prefix
- */
-const char* dap_chain_global_db_add_history_extra_group(const char * a_group_name, dap_chain_node_addr_t *a_nodes, uint16_t *a_nodes_count)
+dap_list_t *dap_chain_db_get_sync_groups()
 {
-    history_extra_group_item_t* l_item = DAP_NEW_Z(history_extra_group_item_t);
-    l_item->group_name = dap_strdup(a_group_name);
-    l_item->group_name_for_history = dap_strdup_printf("local.history.%s", a_group_name);
-    HASH_ADD_STR(s_history_extra_group_items, group_name, l_item);
-    return (const char*)l_item->group_name_for_history;
+    return dap_chain_db_get_sync_groups_internal(s_sync_group_items);
 }
 
-/**
- * @brief dap_chain_global_db_add_history_extra_group_callback_notify
- * @param a_group_prefix
- * @param a_callback
- */
-void dap_chain_global_db_add_history_extra_group_callback_notify(const char * a_group_prefix,
-        dap_global_db_obj_callback_notify_t a_callback, void * a_arg)
+dap_list_t *dap_chain_db_get_sync_extra_groups()
 {
-    history_extra_group_item_t * l_item = NULL;
-    HASH_FIND_STR(s_history_extra_group_items, a_group_prefix, l_item);
-    if(l_item) {
-        l_item->callback_notify = a_callback;
-        l_item->callback_arg = a_arg;
-    } else
-        log_it(L_WARNING, "Can't setup notify callback for extra groups with prefix %s. Possible not in history track state",
-                a_group_prefix);
+    return dap_chain_db_get_sync_groups_internal(s_sync_group_extra_items);
 }
 
 /**
@@ -220,13 +153,8 @@ void dap_chain_global_db_obj_delete(dap_global_db_obj_t *obj)
  */
 void dap_chain_global_db_objs_delete(dap_global_db_obj_t *objs, size_t a_count)
 {
-    //int i = 0;
-    //while(objs) {
     for(size_t i = 0; i < a_count; i++) {
-        //if(!(objs[i]))
-        //    break;
         dap_chain_global_db_obj_clean(objs + i);
-        //i++;
     }
     DAP_DELETE(objs);
 }
@@ -239,8 +167,9 @@ void dap_chain_global_db_objs_delete(dap_global_db_obj_t *objs, size_t a_count)
 int dap_chain_global_db_init(dap_config_t * g_config)
 {
     const char *l_storage_path = dap_config_get_item_str(g_config, "resources", "dap_global_db_path");
-    //const char *l_driver_name = dap_config_get_item_str_default(g_config, "resources", "dap_global_db_driver", "sqlite");
-    const char *l_driver_name = dap_config_get_item_str_default(g_config, "resources", "dap_global_db_driver", "cdb");
+    const char *l_driver_name = dap_config_get_item_str_default(g_config, "resources", "dap_global_db_driver", "sqlite");
+    //const char *l_driver_name = dap_config_get_item_str_default(g_config, "resources", "dap_global_db_driver", "cdb");
+    s_track_history = dap_config_get_item_bool_default(g_config, "resources", "dap_global_db_track_history", s_track_history);
     lock();
     int res = dap_db_driver_init(l_driver_name, l_storage_path);
     unlock();
@@ -260,20 +189,20 @@ void dap_chain_global_db_deinit(void)
     dap_db_driver_deinit();
     //dap_db_deinit();
     unlock();
-    history_group_item_t * l_item = NULL, *l_item_tmp = NULL;
-    HASH_ITER(hh, s_history_group_items, l_item, l_item_tmp)
+    sync_group_item_t * l_item = NULL, *l_item_tmp = NULL;
+    HASH_ITER(hh, s_sync_group_items, l_item, l_item_tmp)
     {
         DAP_DELETE(l_item->group_name_for_history);
         DAP_DELETE(l_item);
     }
-    history_extra_group_item_t * l_add_item = NULL, *l_add_item_tmp = NULL;
-    HASH_ITER(hh, s_history_extra_group_items, l_add_item, l_add_item_tmp)
+    sync_group_item_t * l_add_item = NULL, *l_add_item_tmp = NULL;
+    HASH_ITER(hh, s_sync_group_extra_items, l_add_item, l_add_item_tmp)
     {
-        DAP_DELETE(l_add_item->group_name);
+        DAP_DELETE(l_add_item->group_mask);
         DAP_DELETE(l_add_item->group_name_for_history);
         DAP_DELETE(l_add_item);
     }
-    s_history_group_items = NULL;
+    s_sync_group_items = NULL;
 
 }
 
@@ -299,19 +228,6 @@ void* dap_chain_global_db_obj_get(const char *a_key, const char *a_group)
     // read one item
     dap_store_obj_t *l_store_data = dap_chain_global_db_driver_read(a_group, a_key, &l_count);
     return l_store_data;
-
-    /*    size_t count = 0;
-     if(!a_key)
-     return NULL;
-     size_t query_len = (size_t) snprintf(NULL, 0, "(&(cn=%s)(objectClass=%s))", a_key, a_group);
-     char *query = DAP_NEW_Z_SIZE(char, query_len + 1); //char query[32 + strlen(a_key)];
-     snprintf(query, query_len + 1, "(&(cn=%s)(objectClass=%s))", a_key, a_group); // objectClass != ou
-     lock();
-     dap_store_obj_t *store_data = dap_db_read_data(query, &count);
-     unlock();
-     assert(count <= 1);
-     DAP_DELETE(query);
-     return store_data;*/
 }
 
 /**
@@ -323,18 +239,14 @@ void* dap_chain_global_db_obj_get(const char *a_key, const char *a_group)
  */
 dap_store_obj_t* dap_chain_global_db_obj_gr_get(const char *a_key, size_t *a_data_len_out, const char *a_group)
 {
-    //uint8_t *l_ret_value = NULL;
     // read several items, 0 - no limits
     size_t l_data_len_out = 0;
     if(a_data_len_out)
         l_data_len_out = *a_data_len_out;
     dap_store_obj_t *l_store_data = dap_chain_global_db_driver_read(a_group, a_key, &l_data_len_out);
     if(l_store_data) {
-        //l_ret_value = (l_store_data->value) ? DAP_NEW_SIZE(uint8_t, l_store_data->value_len) : NULL; //ret_value = (store_data->value) ? strdup(store_data->value) : NULL;
-        //memcpy(l_ret_value, l_store_data->value, l_store_data->value_len);
         if(a_data_len_out)
-            *a_data_len_out = l_data_len_out;//l_store_data->value_len;
-        //dap_store_obj_free(l_store_data, l_data_len_out);
+            *a_data_len_out = l_data_len_out;
     }
     return l_store_data;
 }
@@ -363,28 +275,6 @@ uint8_t * dap_chain_global_db_gr_get(const char *a_key, size_t *a_data_len_out,
         dap_store_obj_free(l_store_data, l_data_len_out);
     }
     return l_ret_value;
-
-    /*ldb
-     *     uint8_t *l_ret_value = NULL;
-     size_t l_count = 0;
-     if(!a_key)
-     return NULL;
-     size_t l_query_len =(size_t) snprintf(NULL, 0, "(&(cn=%s)(objectClass=%s))", a_key, a_group);
-
-     char *l_query = DAP_NEW_Z_SIZE(char, l_query_len + 1); //char query[32 + strlen(a_key)];
-     snprintf(l_query, l_query_len + 1, "(&(cn=%s)(objectClass=%s))", a_key, a_group); // objectClass != ou
-     lock();
-     pdap_store_obj_t store_data = dap_db_read_data(l_query, &l_count);
-     unlock();
-     if(l_count == 1 && store_data && !strcmp(store_data->key, a_key)) {
-     l_ret_value = (store_data->value) ? DAP_NEW_SIZE(uint8_t, store_data->value_len) : NULL; //ret_value = (store_data->value) ? strdup(store_data->value) : NULL;
-     memcpy(l_ret_value, store_data->value, store_data->value_len);
-     if(a_data_out)
-     *a_data_out = store_data->value_len;
-     }
-     dap_store_obj_free(store_data, l_count);
-     DAP_DELETE(l_query);
-     return l_ret_value;*/
 }
 
 uint8_t * dap_chain_global_db_get(const char *a_key, size_t *a_data_out)
@@ -398,18 +288,20 @@ uint8_t * dap_chain_global_db_get(const char *a_key, size_t *a_data_out)
  */
 static bool global_db_gr_del_add(char *a_key,const char *a_group, time_t a_timestamp)
 {
-    dap_store_obj_t store_data;// = DAP_NEW_Z_SIZE(dap_store_obj_t, sizeof(struct dap_store_obj));
+    dap_store_obj_t store_data;
     memset(&store_data, 0, sizeof(dap_store_obj_t));
     store_data.type = 'a';
-    store_data.key = a_key;//dap_strdup(a_key);
+    store_data.key = a_key;
     // no data
     store_data.value = NULL;
     store_data.value_len = 0;
     // group = parent group + '.del'
     store_data.group = dap_strdup_printf("%s.del", a_group);
-    store_data.timestamp = a_timestamp;//time(NULL);
+    store_data.timestamp = a_timestamp;
     lock();
-    int l_res = dap_chain_global_db_driver_add(&store_data, 1);
+    int l_res = 0;
+    if (!dap_chain_global_db_driver_is(store_data.group, store_data.key))
+        l_res = dap_chain_global_db_driver_add(&store_data, 1);
     unlock();
     DAP_DELETE(store_data.group);
     if(l_res>=0)
@@ -420,11 +312,11 @@ static bool global_db_gr_del_add(char *a_key,const char *a_group, time_t a_times
 /**
  * Delete info about the deleted entry from the base
  */
-static bool global_db_gr_del_del(char *a_key,const char *a_group)
+static bool global_db_gr_del_del(char *a_key, const char *a_group)
 {
     if(!a_key)
         return NULL;
-    dap_store_obj_t store_data;// = DAP_NEW_Z_SIZE(dap_store_obj_t, sizeof(struct dap_store_obj));
+    dap_store_obj_t store_data;
     memset(&store_data, 0, sizeof(dap_store_obj_t));
     store_data.key = a_key;
    // store_data->c_key = a_key;
@@ -456,7 +348,7 @@ time_t global_db_gr_del_get_timestamp(const char *a_group, char *a_key)
     store_data.group = dap_strdup_printf("%s.del", a_group);
     //store_data->c_group = a_group;
     lock();
-    if(dap_chain_global_db_driver_is(store_data.group, store_data.key)) {
+    if (dap_chain_global_db_driver_is(store_data.group, store_data.key)) {
         size_t l_count_out = 0;
         dap_store_obj_t *l_obj = dap_chain_global_db_driver_read(store_data.group, store_data.key, &l_count_out);
         assert(l_count_out <= 1);
@@ -468,155 +360,7 @@ time_t global_db_gr_del_get_timestamp(const char *a_group, char *a_key)
     return l_timestamp;
 }
 
-/**
- *
- */
-
-/**
- * @brief dap_chain_global_db_gr_set
- * @param a_key
- * @param a_value
- * @param a_value_len
- * @param a_group
- * @details Set one entry to base. IMPORTANT: a_key and a_value should be passed without free after (it will be released by gdb itself)
- * @return
- */
-bool dap_chain_global_db_gr_set(char *a_key, void *a_value, size_t a_value_len, const char *a_group)
-{
-    dap_store_obj_t store_data;// = DAP_NEW_Z_SIZE(dap_store_obj_t, sizeof(struct dap_store_obj));
-    memset(&store_data, 0, sizeof(dap_store_obj_t));
-    store_data.type = 'a';
-    store_data.key = a_key;//dap_strdup(a_key);
-    store_data.value = a_value;//DAP_NEW_Z_SIZE(uint8_t, a_value_len);
 
-    //memcpy(store_data.value, a_value, a_value_len);
-
-    store_data.value_len = (a_value_len == (size_t) -1) ? dap_strlen((const char*) a_value) : a_value_len;
-    store_data.group = (char*)a_group;//dap_strdup(a_group);
-    store_data.timestamp = time(NULL);
-    lock();
-    int l_res = dap_chain_global_db_driver_add(&store_data, 1);
-    unlock();
-
-    // Extract prefix if added successfuly, add history log and call notify callback if present
-    if(!l_res) {
-        // Delete info about the deleted entry from the base if one present
-        global_db_gr_del_del(a_key, a_group);
-
-        char * l_group_prefix = extract_group_prefix(a_group);
-        history_group_item_t * l_history_group_item = NULL;
-        if(l_group_prefix)
-            HASH_FIND_STR(s_history_group_items, l_group_prefix, l_history_group_item);
-
-        if(l_history_group_item) {
-            if(l_history_group_item->auto_track) {
-                lock();
-                dap_db_history_add('a', &store_data, 1, l_history_group_item->group_name_for_history);
-                unlock();
-            }
-            if(l_history_group_item->callback_notify)
-                l_history_group_item->callback_notify(l_history_group_item->callback_arg, 'a', l_group_prefix, a_group,
-                        a_key, a_value, a_value_len);
-        }
-        // looking for extra group
-        else {
-            history_extra_group_item_t * l_history_extra_group_item = NULL;
-            HASH_FIND_STR(s_history_extra_group_items, a_group, l_history_extra_group_item);
-
-            if(l_history_extra_group_item) {
-                lock();
-                dap_db_history_add('a', &store_data, 1, l_history_extra_group_item->group_name_for_history);
-                unlock();
-                if(l_history_extra_group_item->callback_notify)
-                    l_history_extra_group_item->callback_notify(l_history_extra_group_item->callback_arg, 'a',
-                            l_group_prefix,
-                            a_group,
-                            a_key, a_value, a_value_len);
-            }
-        }
-        if(l_group_prefix)
-            DAP_DELETE(l_group_prefix);
-    } else {
-        log_it(L_ERROR, "Save error: %d", l_res);
-    }
-    //DAP_DELETE(store_data);
-
-    return !l_res;
-}
-
-bool dap_chain_global_db_set( char *a_key,  void *a_value, size_t a_value_len)
-{
-    return dap_chain_global_db_gr_set(a_key, a_value, a_value_len, GROUP_LOCAL_GENERAL);
-}
-
-/**
- * Delete entry from base
- */
-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;// = DAP_NEW_Z_SIZE(dap_store_obj_t, sizeof(struct dap_store_obj));
-    memset(&store_data, 0, sizeof(dap_store_obj_t));
-    store_data.key = a_key;
-    store_data.group = (char*)a_group;
-    lock();
-    int l_res = dap_chain_global_db_driver_delete(&store_data, 1);
-    unlock();
-    // do not add to history if l_res=1 (already deleted)
-    if(!l_res) {
-        // added to Del group
-        global_db_gr_del_add(a_key, a_group, time(NULL));
-        // Extract prefix
-        char * l_group_prefix = extract_group_prefix(a_group);
-        history_group_item_t * l_history_group_item = NULL;
-        if(l_group_prefix)
-            HASH_FIND_STR(s_history_group_items, l_group_prefix, l_history_group_item);
-        if(l_history_group_item) {
-            if(l_history_group_item->auto_track) {
-                lock();
-                dap_db_history_add('d', &store_data, 1, l_history_group_item->group_name_for_history);
-                unlock();
-            }
-            if(l_history_group_item->callback_notify)
-                l_history_group_item->callback_notify(l_history_group_item->callback_arg, 'd', l_group_prefix, a_group,
-                        a_key, NULL, 0);
-        }
-        // looking for extra group
-        else {
-            history_extra_group_item_t * l_history_extra_group_item = NULL;
-            HASH_FIND_STR(s_history_extra_group_items, a_group, l_history_extra_group_item);
-
-            if(l_history_extra_group_item) {
-                lock();
-                dap_db_history_add('d', &store_data, 1, l_history_extra_group_item->group_name_for_history);
-                unlock();
-                if(l_history_extra_group_item->callback_notify)
-                    l_history_extra_group_item->callback_notify(l_history_extra_group_item->callback_arg, 'd',
-                            l_group_prefix, a_group, a_key, NULL, 0);
-            }
-        }
-        if(l_group_prefix)
-            DAP_DELETE(l_group_prefix);
-    }
-    //DAP_DELETE(store_data);
-    if(l_res>=0){
-        // added to Del group
-        global_db_gr_del_add(a_key, a_group, time(NULL));
-        /*/ read del info
-        char *l_group = dap_strdup_printf("%s.del", a_group);
-        size_t l_data_size_out = 0;
-        dap_store_obj_t *l_objs = dap_chain_global_db_obj_gr_get(a_key, &l_data_size_out,l_group);
-        // update timestamp
-        if(l_objs){
-            if(l_objs->timestamp<time(NULL))
-        dap_store_obj_free(l_objs, l_data_size_out);
-        }
-        DAP_DELETE(l_group);*/
-        return true;
-    }
-    return false;
-}
 bool dap_chain_global_db_del(char *a_key)
 {
     return dap_chain_global_db_gr_del(a_key, GROUP_LOCAL_GENERAL);
@@ -687,6 +431,120 @@ dap_global_db_obj_t* dap_chain_global_db_load(size_t *a_data_size_out)
 {
     return dap_chain_global_db_gr_load(GROUP_LOCAL_GENERAL, a_data_size_out);
 }
+
+/**
+ * @brief extract_group_mask
+ * @param a_group
+ * @return
+ */
+static sync_group_item_t *find_item_by_mask(sync_group_item_t *a_items, const char *a_group)
+{
+    sync_group_item_t * l_item = NULL, *l_item_tmp = NULL;
+    HASH_ITER(hh, a_items, l_item, l_item_tmp) {
+        if (!dap_fnmatch(l_item->group_mask, a_group, 0))
+            return l_item;
+    }
+    return NULL;
+}
+
+
+void dap_global_db_obj_track_history(void* a_store_data)
+{
+    if (!s_track_history)
+        return;
+    dap_store_obj_t *l_obj = (dap_store_obj_t *)a_store_data;
+    sync_group_item_t *l_sync_group_item = find_item_by_mask(s_sync_group_items, l_obj->group);
+    if(l_sync_group_item) {
+        lock();
+        dap_db_history_add((char)l_obj->type, l_obj, 1, l_sync_group_item->group_name_for_history);
+        unlock();
+        if(l_sync_group_item->callback_notify) {
+            if(l_obj) {
+                l_sync_group_item->callback_notify(l_sync_group_item->callback_arg,
+                        (const char)l_obj->type,
+                        l_obj->group, l_obj->key,
+                        l_obj->value, l_obj->value_len);
+            }
+        }
+    } else { // looking for extra group
+        sync_group_item_t *l_sync_extra_group_item = find_item_by_mask(s_sync_group_extra_items, l_obj->group);
+        if(l_sync_extra_group_item) {
+            lock();
+            dap_db_history_add((char)l_obj->type, l_obj, 1, l_sync_extra_group_item->group_name_for_history);
+            unlock();
+            if(l_sync_extra_group_item->callback_notify)
+                l_sync_extra_group_item->callback_notify(l_sync_extra_group_item->callback_arg,
+                        (const char)l_obj->type, l_obj->group, l_obj->key,
+                        l_obj->value, l_obj->value_len);
+        }
+    }
+}
+
+
+/**
+ * @brief dap_chain_global_db_gr_set
+ * @param a_key
+ * @param a_value
+ * @param a_value_len
+ * @param a_group
+ * @details Set one entry to base. IMPORTANT: a_key and a_value should be passed without free after (it will be released by gdb itself)
+ * @return
+ */
+bool dap_chain_global_db_gr_set(char *a_key, void *a_value, size_t a_value_len, const char *a_group)
+{
+    dap_store_obj_t store_data;
+    memset(&store_data, 0, sizeof(dap_store_obj_t));
+    store_data.key = a_key;
+    store_data.value = a_value;
+    store_data.value_len = (a_value_len == (size_t) -1) ? dap_strlen((const char*) a_value) : a_value_len;
+    store_data.group = (char*)a_group;
+    store_data.timestamp = time(NULL);
+    lock();
+    int l_res = dap_chain_global_db_driver_add(&store_data, 1);
+    unlock();
+
+    // Extract prefix if added successfuly, add history log and call notify callback if present
+    if(!l_res) {
+        // delete info about the deleted entry from the base if one present
+        global_db_gr_del_del(store_data.key, store_data.group);
+        dap_global_db_obj_track_history(&store_data);
+    } else {
+        log_it(L_ERROR, "Save error: %d", l_res);
+    }
+
+    return !l_res;
+}
+
+bool dap_chain_global_db_set( char *a_key,  void *a_value, size_t a_value_len)
+{
+    return dap_chain_global_db_gr_set(a_key, a_value, a_value_len, GROUP_LOCAL_GENERAL);
+}
+
+/**
+ * Delete entry from base
+ */
+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 = a_key;
+    store_data.group = (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(store_data.key, store_data.group, store_data.timestamp);
+    }
+    // do not add to history if l_res=1 (already deleted)
+    if (!l_res) {
+        dap_global_db_obj_track_history(&store_data);
+    }
+    return !l_res;
+}
+
 /**
  * Write to the database from an array of data_size bytes
  *
@@ -702,67 +560,19 @@ bool dap_chain_global_db_obj_save(void* a_store_data, size_t a_objs_count)
     int l_res = dap_chain_global_db_driver_appy(a_store_data, a_objs_count);
     unlock();
 
-    // Extract prefix if added successfuly, add history log and call notify callback if present
-    if(!l_res) {
-        for(size_t i = 0; i < a_objs_count; i++) {
-
-            dap_store_obj_t *a_store_obj = a_store_data + i;
-            if(a_store_obj->type == 'a')
-                // delete info about the deleted entry from the base if one present
-                global_db_gr_del_del(a_store_obj->key, a_store_obj->group);
-            else if(a_store_obj->type == 'd')
-                // add to Del group
-                global_db_gr_del_add(a_store_obj->key, a_store_obj->group, a_store_obj->timestamp);
-
-
-            history_group_item_t * l_history_group_item = NULL;
-            dap_store_obj_t* l_obj = (dap_store_obj_t*)a_store_data + i;
-            char * l_group_prefix = extract_group_prefix(l_obj->group);
-            if(l_group_prefix)
-                HASH_FIND_STR(s_history_group_items, l_group_prefix, l_history_group_item);
-
-            if(l_history_group_item) {
-                if(l_history_group_item->auto_track) {
-                    lock();
-                    dap_db_history_add((char)l_obj->type, l_obj, 1, l_history_group_item->group_name_for_history);
-                    unlock();
-                }
-                if(l_history_group_item->callback_notify) {
-                    if(l_obj) {
-                        l_history_group_item->callback_notify(l_history_group_item->callback_arg,
-                                (const char)l_obj->type,
-                                l_group_prefix, l_obj->group, l_obj->key,
-                                l_obj->value, l_obj->value_len);
-                    } else {
-                        break;
-                    }
-                }
-            }
-            // looking for extra group
-            else {
-                history_extra_group_item_t * l_history_extra_group_item = NULL;
-                HASH_FIND_STR(s_history_extra_group_items, l_obj->group, l_history_extra_group_item);
-
-                if(l_history_extra_group_item) {
-                    lock();
-                    dap_db_history_add((char)l_obj->type, l_obj, 1, l_history_extra_group_item->group_name_for_history);
-                    unlock();
-                    if(l_history_extra_group_item->callback_notify)
-                        l_history_extra_group_item->callback_notify(l_history_extra_group_item->callback_arg,
-                                (const char)l_obj->type,
-                                l_group_prefix, l_obj->group, l_obj->key,
-                                l_obj->value, l_obj->value_len);
-                }
-            }
-
-            DAP_DELETE(l_group_prefix);
-        }
-
-    }
-    if(l_res >= 0) {
-        return true;
+    for(size_t i = 0; i < a_objs_count; i++) {
+        dap_store_obj_t *a_store_obj = (dap_store_obj_t *)a_store_data + i;
+        if (a_store_obj->type == 'a' && !l_res)
+            // delete info about the deleted entry from the base if one present
+            global_db_gr_del_del(a_store_obj->key, a_store_obj->group);
+        else if (a_store_obj->type == 'd' && l_res >= 0)
+            // add to Del group
+            global_db_gr_del_add(a_store_obj->key, a_store_obj->group, a_store_obj->timestamp);
+        if (!l_res)
+        // Extract prefix if added successfuly, add history log and call notify callback if present
+        dap_global_db_obj_track_history(a_store_obj);
     }
-    return false;
+    return !l_res;
 }
 
 bool dap_chain_global_db_gr_save(dap_global_db_obj_t* a_objs, size_t a_objs_count, const char *a_group)
@@ -783,39 +593,13 @@ bool dap_chain_global_db_gr_save(dap_global_db_obj_t* a_objs, size_t a_objs_coun
         //log_it(L_DEBUG,"Added %u objects", a_objs_count);
         int l_res = dap_chain_global_db_driver_add(l_store_data, a_objs_count);
         unlock();
-        if(!l_res) {
+        if(!l_res) {    
             for(size_t i = 0; i < a_objs_count; i++) {
-                history_group_item_t * l_history_group_item = NULL;
-                dap_store_obj_t *l_obj = l_store_data + i;
-
-                char * l_group_prefix = extract_group_prefix(l_obj->group);
-                if(l_group_prefix)
-                    HASH_FIND_STR(s_history_group_items, l_group_prefix, l_history_group_item);
-
-                if(l_history_group_item) {
-                    if(l_history_group_item->auto_track) {
-                        lock();
-                        dap_db_history_add('a', l_store_data, 1, l_history_group_item->group_name_for_history);
-                        unlock();
-                    }
-                    if(l_history_group_item->callback_notify) {
-                        if(l_obj) {
-                            l_history_group_item->callback_notify(l_history_group_item->callback_arg, 'a',
-                                    l_group_prefix, l_obj->group, l_obj->key,
-                                    l_obj->value, l_obj->value_len);
-                        } else {
-                            break;
-                        }
-                    }
-                }
-                DAP_DELETE(l_group_prefix);
+                dap_global_db_obj_track_history(l_store_data + i);
             }
-
-        }
-        DAP_DELETE(l_store_data); //dap_store_obj_free(store_data, a_objs_count);
-        if(!l_res) {
-            return true;
         }
+        DAP_DELETE(l_store_data);
+        return !l_res;
     }
     return false;
 }
@@ -834,66 +618,3 @@ char* dap_chain_global_db_hash(const uint8_t *data, size_t data_size)
 {
     return dap_chain_global_db_driver_hash(data, data_size);
 }
-
-/**
- * Parse data from dap_db_log_pack()
- *
- * return dap_store_obj_t*
- */
-void* dap_db_log_unpack(const void *a_data, size_t a_data_size, size_t *a_store_obj_count)
-{
-    const dap_store_obj_pkt_t *l_pkt = (const dap_store_obj_pkt_t*) a_data;
-    if (! l_pkt || ! a_data_size)
-        return NULL;
-    if( (l_pkt->data_size+ sizeof(dap_store_obj_pkt_t)) != ((size_t) a_data_size ))
-        return NULL;
-
-    size_t l_store_obj_count = 0;
-    dap_store_obj_t *l_obj = dap_store_unpacket_multiple(l_pkt, &l_store_obj_count);
-    if(a_store_obj_count)
-        *a_store_obj_count = l_store_obj_count;
-
-    return l_obj;
-}
-
-/**
- * Get timestamp from dap_db_log_pack()
- */
-time_t dap_db_log_unpack_get_timestamp(uint8_t *a_data, size_t a_data_size)
-{
-    dap_store_obj_pkt_t *l_pkt = (dap_store_obj_pkt_t*) a_data;
-    if(!l_pkt || l_pkt->data_size != (a_data_size - sizeof(dap_store_obj_pkt_t)))
-        return 0;
-    return l_pkt->timestamp;
-}
-
-/**
- * Get log diff as string
- */
-char* dap_db_log_get_diff(size_t *a_data_size_out)
-{
-    //DapList *l_group_list = dap_list_append(l_group_list,GROUP_HISTORY);
-    size_t l_data_size_out = 0;
-    dap_global_db_obj_t *l_objs = dap_chain_global_db_gr_load(GROUP_LOCAL_HISTORY, &l_data_size_out);
-    // make keys & val vector
-    char **l_keys_vals0 = DAP_NEW_SIZE(char*, sizeof(char*) * (l_data_size_out * 2 + 2));
-    char **l_keys_vals = l_keys_vals0 + 1;
-    size_t i;
-    // first element - number of records
-    l_keys_vals0[0] = dap_strdup_printf("%d", l_data_size_out);
-    for(i = 0; i < l_data_size_out; i++) {
-        dap_global_db_obj_t *l_obj_cur = l_objs + i;
-        l_keys_vals[i] = l_obj_cur->key;
-        l_keys_vals[i + l_data_size_out] = (char*) l_obj_cur->value;
-    }
-    if(a_data_size_out)
-        *a_data_size_out = l_data_size_out;
-    // last element - NULL (marker)
-    l_keys_vals[l_data_size_out * 2] = NULL;
-    char *l_keys_vals_flat = dap_strjoinv(GLOBAL_DB_HIST_KEY_SEPARATOR, l_keys_vals0);
-    DAP_DELETE(l_keys_vals0[0]);
-    DAP_DELETE(l_keys_vals0);
-    //dap_strfreev(l_keys_vals0);
-    dap_chain_global_db_objs_delete(l_objs, l_data_size_out);
-    return l_keys_vals_flat;
-}
diff --git a/modules/global-db/dap_chain_global_db_driver.c b/modules/global-db/dap_chain_global_db_driver.c
index 542d5758af4b53788311cf2a6543c897cca5ef88..ed6511d71dedcdef65effcee2f5bb9d908adeaa1 100644
--- a/modules/global-db/dap_chain_global_db_driver.c
+++ b/modules/global-db/dap_chain_global_db_driver.c
@@ -198,148 +198,6 @@ void dap_store_obj_free(dap_store_obj_t *a_store_obj, size_t a_store_count)
     DAP_DELETE(a_store_obj);
 }
 
-static size_t dap_db_get_size_pdap_store_obj_t(pdap_store_obj_t store_obj)
-{
-    size_t size = sizeof(uint32_t) + 2 * sizeof(uint16_t) + sizeof(size_t) + sizeof(time_t)
-            + sizeof(uint64_t) + dap_strlen(store_obj->group) +
-            dap_strlen(store_obj->key) + store_obj->value_len;
-    return size;
-}
-
-/**
- * serialization
- * @param a_store_obj_count count of structures store_obj
- * @param a_timestamp create data time
- * @param a_size_out[out] size of output structure
- * @return NULL in case of an error
- */
-dap_list_t *dap_store_packet_multiple(pdap_store_obj_t a_store_obj, time_t a_timestamp,
-        size_t a_store_obj_count)
-{
-    if (!a_store_obj || a_store_obj_count < 1)
-        return NULL;
-
-    // calculate output structure size
-    dap_list_t *l_ret = NULL;
-    dap_store_obj_pkt_t *l_pkt;
-    uint32_t l_obj_count = 0, l_data_size_out = 0;
-    for (size_t l_q = 0; l_q < a_store_obj_count; ++l_q) {
-        l_data_size_out += dap_db_get_size_pdap_store_obj_t(&a_store_obj[l_q]);
-        if (l_data_size_out > DAP_CHAIN_PKT_EXPECT_SIZE || (l_q == a_store_obj_count - 1 && l_data_size_out)) {
-            l_pkt = DAP_NEW_Z_SIZE(dap_store_obj_pkt_t, sizeof(dap_store_obj_pkt_t) + l_data_size_out);
-            l_pkt->data_size = l_data_size_out;
-            l_pkt->timestamp = a_timestamp;
-            l_pkt->obj_count = l_q + 1 - l_obj_count;
-            l_ret = dap_list_append(l_ret, l_pkt);
-            l_data_size_out = 0;
-            l_obj_count = l_q + 1;
-        }
-    }
-    l_obj_count = 0;
-    for (dap_list_t *l_iter = l_ret; l_iter; l_iter = dap_list_next(l_iter)) {
-        l_pkt = (dap_store_obj_pkt_t *)l_iter->data;
-        uint64_t l_offset = 0;
-        for(size_t l_q = 0; l_q < l_pkt->obj_count; ++l_q) {
-            dap_store_obj_t obj = a_store_obj[l_obj_count + l_q];
-            //uint16_t section_size = (uint16_t) dap_strlen(obj.section);
-            uint16_t group_size = (uint16_t) dap_strlen(obj.group);
-            uint16_t key_size = (uint16_t) dap_strlen(obj.key);
-            memcpy(l_pkt->data + l_offset, &obj.type, sizeof(int));
-            l_offset += sizeof(int);
-            //memcpy(l_pkt->data + l_offset, &section_size, sizeof(uint16_t));
-            //l_offset += sizeof(uint16_t);
-            //memcpy(l_pkt->data + l_offset, obj.section, section_size);
-            //l_offset += section_size;
-            memcpy(l_pkt->data + l_offset, &group_size, sizeof(uint16_t));
-            l_offset += sizeof(uint16_t);
-            memcpy(l_pkt->data + l_offset, obj.group, group_size);
-            l_offset += group_size;
-            memcpy(l_pkt->data + l_offset, &obj.id, sizeof(uint64_t));
-            l_offset += sizeof(uint64_t);
-            memcpy(l_pkt->data + l_offset, &obj.timestamp, sizeof(time_t));
-            l_offset += sizeof(time_t);
-            memcpy(l_pkt->data + l_offset, &key_size, sizeof(uint16_t));
-            l_offset += sizeof(uint16_t);
-            memcpy(l_pkt->data + l_offset, obj.key, key_size);
-            l_offset += key_size;
-            memcpy(l_pkt->data + l_offset, &obj.value_len, sizeof(size_t));
-            l_offset += sizeof(size_t);
-            memcpy(l_pkt->data + l_offset, obj.value, obj.value_len);
-            l_offset += obj.value_len;
-        }
-        l_obj_count += l_pkt->obj_count;
-        assert(l_pkt->data_size == l_offset);
-    }
-    return l_ret;
-}
-/**
- * deserialization
- * @param store_obj_count[out] count of the output structures store_obj
- * @return NULL in case of an error*
- */
-
-dap_store_obj_t *dap_store_unpacket_multiple(const dap_store_obj_pkt_t *pkt, size_t *store_obj_count)
-{
-    if(!pkt || pkt->data_size < 1)
-        return NULL;
-    uint64_t offset = 0;
-    uint32_t count = pkt->obj_count;
-    dap_store_obj_t *store_obj = DAP_NEW_Z_SIZE(dap_store_obj_t, count * sizeof(struct dap_store_obj));
-    for(size_t q = 0; q < count; ++q) {
-        dap_store_obj_t *obj = store_obj + q;
-        uint16_t str_length;
-
-        if (offset+sizeof (int)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'type' field"); break;} // Check for buffer boundries
-        memcpy(&obj->type, pkt->data + offset, sizeof(int));
-        offset += sizeof(int);
-
-        //memcpy(&str_size, pkt->data + offset, sizeof(uint16_t));
-        //offset += sizeof(uint16_t);
-        //obj->section = DAP_NEW_Z_SIZE(char, str_size + 1);
-        //memcpy(obj->section, pkt->data + offset, str_size);
-        //offset += str_size;
-
-        if (offset+sizeof (uint16_t)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'group_length' field"); break;} // Check for buffer boundries
-        memcpy(&str_length, pkt->data + offset, sizeof(uint16_t));
-        offset += sizeof(uint16_t);
-
-        if (offset+str_length> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'group' field"); break;} // Check for buffer boundries
-        obj->group = DAP_NEW_Z_SIZE(char, str_length + 1);
-        memcpy(obj->group, pkt->data + offset, str_length);
-        offset += str_length;
-
-        if (offset+sizeof (uint64_t)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'id' field"); break;} // Check for buffer boundries
-        memcpy(&obj->id, pkt->data + offset, sizeof(uint64_t));
-        offset += sizeof(uint64_t);
-
-        if (offset+sizeof (time_t)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'timestamp' field"); break;} // Check for buffer boundries
-        memcpy(&obj->timestamp, pkt->data + offset, sizeof(time_t));
-        offset += sizeof(time_t);
-
-        if (offset+sizeof (uint16_t)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'key_length' field"); break;} // Check for buffer boundries
-        memcpy(&str_length, pkt->data + offset, sizeof(uint16_t));
-        offset += sizeof(uint16_t);
-
-        if (offset+ str_length > pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'key' field"); break;} // Check for buffer boundries
-        obj->key = DAP_NEW_Z_SIZE(char, str_length + 1);
-        memcpy(obj->key, pkt->data + offset, str_length);
-        offset += str_length;
-
-        if (offset+sizeof (size_t)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'value_length' field"); break;} // Check for buffer boundries
-        memcpy(&obj->value_len, pkt->data + offset, sizeof(size_t));
-        offset += sizeof(size_t);
-
-        if (offset+obj->value_len> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'value' field"); break;} // Check for buffer boundries
-        obj->value = DAP_NEW_Z_SIZE(uint8_t, obj->value_len + 1);
-        memcpy(obj->value, pkt->data + offset, obj->value_len);
-        offset += obj->value_len;
-    }
-    //assert(pkt->data_size == offset);
-    if(store_obj_count)
-        *store_obj_count = count;
-    return store_obj;
-}
-
 /**
  * Calc hash for data
  *
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 d22d8759a303932481e88db1010ff67f36f8b02c..1aeba149aaf31a97e43ef8511a2c7ccf1a0c0b20 100644
--- a/modules/global-db/dap_chain_global_db_driver_cdb.c
+++ b/modules/global-db/dap_chain_global_db_driver_cdb.c
@@ -121,6 +121,23 @@ bool dap_cdb_get_cond_obj_iter_callback(void *arg, const char *key, int ksize, c
     return true;
 }
 
+bool dap_cdb_get_count_iter_callback(void *arg, const char *key, int ksize, const char *val, int vsize, uint32_t expire, uint64_t oid) {
+    UNUSED(ksize);
+    UNUSED(val);
+    UNUSED(vsize);
+    UNUSED(expire);
+    UNUSED(oid);
+    UNUSED(key);
+
+    if (dap_hex_to_uint(val, sizeof(uint64_t)) < ((pobj_arg)arg)->id) {
+        return true;
+    }
+    if (--((pobj_arg)arg)->q == 0) {
+        return false;
+    }
+    return true;
+}
+
 pcdb_instance dap_cdb_init_group(char *a_group, int a_flags) {
     pcdb_instance l_cdb_i = NULL;
     pthread_mutex_lock(&cdb_mutex);
@@ -421,19 +438,23 @@ dap_store_obj_t* dap_db_driver_cdb_read_cond_store_obj(const char *a_group, uint
 
 size_t dap_db_driver_cdb_read_count_store(const char *a_group, uint64_t a_id)
 {
-    if(!a_group) {
+    if (!a_group) {
         return 0;
     }
     pcdb_instance l_cdb_i = dap_cdb_get_db_by_group(a_group);
-    if(!l_cdb_i) {
+    if (!l_cdb_i) {
         return 0;
     }
     CDB *l_cdb = l_cdb_i->cdb;
     CDBSTAT l_cdb_stat;
     cdb_stat(l_cdb, &l_cdb_stat);
-    if(a_id > l_cdb_stat.rnum)
-        return 0;
-    return (size_t) l_cdb_stat.rnum - a_id + 1;
+    obj_arg l_arg;
+    l_arg.q = l_cdb_stat.rnum;
+    l_arg.id = a_id;
+    void *l_iter = cdb_iterate_new(l_cdb, 0);
+    cdb_iterate(l_cdb, dap_cdb_get_count_iter_callback, (void*)&l_arg, l_iter);
+    cdb_iterate_destroy(l_cdb, l_iter);
+    return l_cdb_stat.rnum - l_arg.q;
 }
 
 /**
@@ -446,11 +467,10 @@ dap_list_t* dap_db_driver_cdb_get_groups_by_mask(const char *a_group_mask)
         return NULL;
     cdb_instance *cur_cdb, *tmp;
     pthread_rwlock_rdlock(&cdb_rwlock);
-    HASH_ITER(hh, s_cdb, cur_cdb, tmp)
-    {
-        if(!dap_fnmatch(a_group_mask, cur_cdb->local_group, 0))
-            if(dap_fnmatch("*.del", cur_cdb->local_group, 0))
-                l_ret_list = dap_list_prepend(l_ret_list, dap_strdup(cur_cdb->local_group));
+    HASH_ITER(hh, s_cdb, cur_cdb, tmp) {
+        char *l_table_name = cur_cdb->local_group;
+        if(!dap_fnmatch(a_group_mask, l_table_name, 0))
+            l_ret_list = dap_list_prepend(l_ret_list, dap_strdup(l_table_name));
     }
     pthread_rwlock_unlock(&cdb_rwlock);
     return l_ret_list;
diff --git a/modules/global-db/dap_chain_global_db_driver_sqlite.c b/modules/global-db/dap_chain_global_db_driver_sqlite.c
index 7f8a9ba6a720a5e675681e9b30aefdc34d24f2b7..9b90abff137a177a9727ab6da13d1a65a2bdc5c9 100644
--- a/modules/global-db/dap_chain_global_db_driver_sqlite.c
+++ b/modules/global-db/dap_chain_global_db_driver_sqlite.c
@@ -36,6 +36,7 @@
 #include "dap_hash.h"
 #include "dap_file_utils.h"
 #include "dap_strfuncs.h"
+#include "dap_file_utils.h"
 #include "dap_chain_global_db_driver_sqlite.h"
 
 #define LOG_TAG "db_sqlite"
@@ -90,6 +91,7 @@ int dap_db_driver_sqlite_init(const char *a_filename_db, dap_db_driver_callbacks
         log_it(L_ERROR, "Can't init sqlite err=%d (%s)", l_ret, sqlite3_errstr(l_ret));
         return -2;
     }
+    // Check paths and create them if nessesary
     char * l_filename_dir = dap_path_get_dirname(a_filename_db);
     if(!dap_dir_test(l_filename_dir)){
         log_it(L_NOTICE, "No directory %s, trying to create...",l_filename_dir);
@@ -106,7 +108,7 @@ int dap_db_driver_sqlite_init(const char *a_filename_db, dap_db_driver_callbacks
             log_it(L_NOTICE,"Directory created");
     }
     DAP_DEL_Z(l_filename_dir);
-
+    // Open Sqlite file, create if nessesary
     char *l_error_message = NULL;
     s_db = dap_db_driver_sqlite_open(a_filename_db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, &l_error_message);
     if(!s_db) {
@@ -131,6 +133,9 @@ int dap_db_driver_sqlite_init(const char *a_filename_db, dap_db_driver_callbacks
         a_drv_callback->read_last_store_obj = dap_db_driver_sqlite_read_last_store_obj;
         a_drv_callback->transaction_start = dap_db_driver_sqlite_start_transaction;
         a_drv_callback->transaction_end = dap_db_driver_sqlite_end_transaction;
+        a_drv_callback->get_groups_by_mask  = dap_db_driver_sqlite_get_groups_by_mask;
+        a_drv_callback->read_count_store = dap_db_driver_sqlite_read_count_store;
+        a_drv_callback->is_obj = dap_db_driver_sqlite_is_obj;
         a_drv_callback->deinit = dap_db_driver_sqlite_deinit;
         a_drv_callback->flush = dap_db_driver_sqlite_flush;
         s_filename_db = strdup(a_filename_db);
@@ -415,7 +420,6 @@ static int dap_db_driver_sqlite_fetch_array(sqlite3_stmt *l_res, SQLITE_ROW_VALU
                 if(cur_val->type == SQLITE_INTEGER)
                 {
                     cur_val->val.val_int64 = sqlite3_column_int64(l_res, l_iCol);
-                    cur_val->val.val_int = sqlite3_column_int(l_res, l_iCol);
                 }
                 else if(cur_val->type == SQLITE_FLOAT)
                     cur_val->val.val_float = sqlite3_column_double(l_res, l_iCol);
@@ -518,6 +522,22 @@ int dap_db_driver_sqlite_end_transaction(void)
     }
 }
 
+char *dap_db_driver_sqlite_make_group_name(const char *a_table_name)
+{
+    char *l_table_name = dap_strdup(a_table_name);
+    ssize_t l_table_name_len = (ssize_t)dap_strlen(l_table_name);
+    const char *l_needle = "_";
+    // replace '_' to '.'
+    while(1){
+    char *l_str = dap_strstr_len(l_table_name, l_table_name_len, l_needle);
+    if(l_str)
+        *l_str = '.';
+    else
+        break;
+    }
+    return l_table_name;
+}
+
 char *dap_db_driver_sqlite_make_table_name(const char *a_group_name)
 {
     char *l_group_name = dap_strdup(a_group_name);
@@ -726,10 +746,10 @@ dap_store_obj_t* dap_db_driver_sqlite_read_cond_store_obj(const char *a_group, u
         l_count_out = (int)*a_count_out;
     char *l_str_query;
     if(l_count_out)
-        l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE id>'%lld' ORDER BY id ASC LIMIT %d",
+        l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE id>='%lld' ORDER BY id ASC LIMIT %d",
                 l_table_name, a_id, l_count_out);
     else
-        l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE id>'%lld' ORDER BY id ASC",
+        l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' WHERE id>='%lld' ORDER BY id ASC",
                 l_table_name, a_id);
     pthread_rwlock_wrlock(&s_db_rwlock);
     if(!s_db){
@@ -790,12 +810,10 @@ dap_store_obj_t* dap_db_driver_sqlite_read_cond_store_obj(const char *a_group, u
  */
 dap_store_obj_t* dap_db_driver_sqlite_read_store_obj(const char *a_group, const char *a_key, size_t *a_count_out)
 {
+    if(!a_group || !s_db)
+        return NULL;
     dap_store_obj_t *l_obj = NULL;
-    char *l_error_message = NULL;
     sqlite3_stmt *l_res;
-    if(!a_group)
-        return NULL;
-
     char * l_table_name = dap_db_driver_sqlite_make_table_name(a_group);
     // no limit
     uint64_t l_count_out = 0;
@@ -818,18 +836,13 @@ dap_store_obj_t* dap_db_driver_sqlite_read_store_obj(const char *a_group, const
             l_str_query = sqlite3_mprintf("SELECT id,ts,key,value FROM '%s' ORDER BY id ASC", l_table_name);
     }
     pthread_rwlock_wrlock(&s_db_rwlock);
-    if(!s_db){
-        pthread_rwlock_unlock(&s_db_rwlock);
-        return NULL;
-    }
-
-    int l_ret = dap_db_driver_sqlite_query(s_db, l_str_query, &l_res, &l_error_message);
+    int l_ret = dap_db_driver_sqlite_query(s_db, l_str_query, &l_res, NULL);
     pthread_rwlock_unlock(&s_db_rwlock);
+
     sqlite3_free(l_str_query);
     DAP_DEL_Z(l_table_name);
     if(l_ret != SQLITE_OK) {
         //log_it(L_ERROR, "read l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
-        dap_db_driver_sqlite_free(l_error_message);
         return NULL;
     }
 
@@ -864,3 +877,85 @@ dap_store_obj_t* dap_db_driver_sqlite_read_store_obj(const char *a_group, const
         *a_count_out = l_count_out;
     return l_obj;
 }
+
+dap_list_t* dap_db_driver_sqlite_get_groups_by_mask(const char *a_group_mask)
+{
+    if(!a_group_mask || !s_db)
+        return NULL;
+    sqlite3_stmt *l_res;
+    const char *l_str_query = "SELECT name FROM sqlite_master WHERE type ='table' AND name NOT LIKE 'sqlite_%'";
+    dap_list_t *l_ret_list = NULL;
+    pthread_rwlock_wrlock(&s_db_rwlock);
+    int l_ret = dap_db_driver_sqlite_query(s_db, (char *)l_str_query, &l_res, NULL);
+    pthread_rwlock_unlock(&s_db_rwlock);
+    if(l_ret != SQLITE_OK) {
+        //log_it(L_ERROR, "Get tables l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
+        return NULL;
+    }
+    char * l_mask = dap_db_driver_sqlite_make_table_name(a_group_mask);
+    SQLITE_ROW_VALUE *l_row = NULL;
+    while (dap_db_driver_sqlite_fetch_array(l_res, &l_row) == SQLITE_ROW && l_row) {
+        char *l_table_name = (char *)l_row->val->val.val_str;
+        if(!dap_fnmatch(l_mask, l_table_name, 0))
+            l_ret_list = dap_list_prepend(l_ret_list, dap_db_driver_sqlite_make_group_name(l_table_name));
+        dap_db_driver_sqlite_row_free(l_row);
+    }
+    dap_db_driver_sqlite_query_free(l_res);
+    return l_ret_list;
+}
+
+size_t dap_db_driver_sqlite_read_count_store(const char *a_group, uint64_t a_id)
+{
+    sqlite3_stmt *l_res;
+    if(!a_group || ! s_db)
+        return 0;
+
+    char * l_table_name = dap_db_driver_sqlite_make_table_name(a_group);
+    char *l_str_query = sqlite3_mprintf("SELECT COUNT(*) FROM '%s' WHERE id>='%lld'", l_table_name, a_id);
+    pthread_rwlock_wrlock(&s_db_rwlock);
+    int l_ret = dap_db_driver_sqlite_query(s_db, l_str_query, &l_res, NULL);
+    pthread_rwlock_unlock(&s_db_rwlock);
+    sqlite3_free(l_str_query);
+    DAP_DEL_Z(l_table_name);
+
+    if(l_ret != SQLITE_OK) {
+        //log_it(L_ERROR, "Count l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
+        return 0;
+    }
+    size_t l_ret_val;
+    SQLITE_ROW_VALUE *l_row = NULL;
+    if (dap_db_driver_sqlite_fetch_array(l_res, &l_row) == SQLITE_ROW && l_row) {
+        l_ret_val = (size_t)l_row->val->val.val_int64;
+        dap_db_driver_sqlite_row_free(l_row);
+    }
+    dap_db_driver_sqlite_query_free(l_res);
+    return l_ret_val;
+}
+
+bool dap_db_driver_sqlite_is_obj(const char *a_group, const char *a_key)
+{
+    sqlite3_stmt *l_res;
+    if(!a_group || ! s_db)
+        return false;
+
+    char * l_table_name = dap_db_driver_sqlite_make_table_name(a_group);
+    char *l_str_query = sqlite3_mprintf("SELECT EXISTS(SELECT * FROM '%s' WHERE key='%s')", l_table_name, a_key);
+    pthread_rwlock_wrlock(&s_db_rwlock);
+    int l_ret = dap_db_driver_sqlite_query(s_db, l_str_query, &l_res, NULL);
+    pthread_rwlock_unlock(&s_db_rwlock);
+    sqlite3_free(l_str_query);
+    DAP_DEL_Z(l_table_name);
+
+    if(l_ret != SQLITE_OK) {
+        //log_it(L_ERROR, "Exists l_ret=%d, %s\n", sqlite3_errcode(s_db), sqlite3_errmsg(s_db));
+        return false;
+    }
+    bool l_ret_val;
+    SQLITE_ROW_VALUE *l_row = NULL;
+    if (dap_db_driver_sqlite_fetch_array(l_res, &l_row) == SQLITE_ROW && l_row) {
+        l_ret_val = (size_t)l_row->val->val.val_int64;
+        dap_db_driver_sqlite_row_free(l_row);
+    }
+    dap_db_driver_sqlite_query_free(l_res);
+    return l_ret_val;
+}
diff --git a/modules/global-db/dap_chain_global_db_hist.c b/modules/global-db/dap_chain_global_db_hist.c
index 05950ebc8ca0c32765d3777cfd685931a263351f..2fea00e1c06b8e2360a4746a9c70179f5051fe2a 100644
--- a/modules/global-db/dap_chain_global_db_hist.c
+++ b/modules/global-db/dap_chain_global_db_hist.c
@@ -8,7 +8,7 @@
 #include <dap_string.h>
 #include <dap_hash.h>
 #include "dap_chain_datum_tx_items.h"
-
+#include "dap_chain_global_db_remote.h"
 #include "dap_chain_global_db_hist.h"
 
 #include "uthash.h"
@@ -72,1006 +72,6 @@ static char* dap_db_new_history_timestamp()
     return l_str;
 }
 
-/**
- * Get data according the history log
- *
- * return dap_store_obj_pkt_t*
- */
-dap_list_t* dap_db_log_pack(dap_global_db_obj_t *a_obj, size_t *a_data_size_out)
-{
-    if(!a_obj)
-        return NULL;
-    dap_global_db_hist_t l_rec;
-    if(dap_db_history_unpack_hist((char*) a_obj->value, &l_rec) == -1)
-        return NULL;
-    time_t l_timestamp = strtoll(a_obj->key, NULL, 10);
-
-    // parse global_db records in a history record
-    char **l_keys = dap_strsplit(l_rec.keys, GLOBAL_DB_HIST_KEY_SEPARATOR, -1);
-    size_t l_count = dap_str_countv(l_keys);
-    // read records from global_db
-    int i = 0;
-    dap_store_obj_t *l_store_obj = DAP_NEW_Z_SIZE(dap_store_obj_t, l_count * sizeof(dap_store_obj_t));
-    while(l_keys[i]) {
-        dap_store_obj_t *l_obj = NULL;
-        // add record - read record
-        if(l_rec.type == 'a'){
-            l_obj = (dap_store_obj_t*) dap_chain_global_db_obj_get(l_keys[i], l_rec.group);
-            // l_obj may be NULL, if this record has been deleted but it is present in history
-            if(l_obj)
-                l_obj->id = a_obj->id;
-        }
-        // delete record - save only key for record
-        else if(l_rec.type == 'd') { // //section=strdup("kelvin_nodes");
-            l_obj = (dap_store_obj_t*) DAP_NEW_Z(dap_store_obj_t);
-            l_obj->id = a_obj->id;
-            l_obj->group = dap_strdup(l_rec.group);
-            l_obj->key = dap_strdup(l_keys[i]);
-            l_obj->timestamp = global_db_gr_del_get_timestamp(l_obj->group, l_obj->key);
-        }
-        if(l_obj == NULL) {
-            dap_store_obj_free(l_store_obj, l_count);
-            dap_strfreev(l_keys);
-            return NULL;
-        }
-        // save record type: 'a' or 'd'
-        l_obj->type = (uint8_t)l_rec.type;
-
-        memcpy(l_store_obj + i, l_obj, sizeof(dap_store_obj_t));
-        DAP_DELETE(l_obj);
-        i++;
-    }
-    // serialize data
-    dap_list_t *l_data_out = dap_store_packet_multiple(l_store_obj, l_timestamp, l_count);
-
-    dap_store_obj_free(l_store_obj, l_count);
-    dap_strfreev(l_keys);
-
-    if(l_data_out && a_data_size_out) {
-        *a_data_size_out = 0;
-        for (dap_list_t *l_iter = l_data_out; l_iter; l_iter = dap_list_next(l_iter)) {
-            *a_data_size_out += sizeof(dap_store_obj_pkt_t) + ((dap_store_obj_pkt_t *)l_data_out)->data_size;
-        }
-    }
-    return l_data_out;
-
-}
-
-
-// for dap_db_history()
-static dap_store_obj_t* get_prev_tx(dap_global_db_obj_t *a_objs, dap_tx_data_t *a_tx_data)
-{
-    if(!a_objs || !a_tx_data)
-        return NULL;
-    dap_global_db_obj_t *l_obj_cur = a_objs + a_tx_data->obj_num;
-    dap_global_db_hist_t l_rec;
-    if(dap_db_history_unpack_hist((char*) l_obj_cur->value, &l_rec) == -1)
-        return NULL;
-    char **l_keys = dap_strsplit(l_rec.keys, GLOBAL_DB_HIST_KEY_SEPARATOR, -1);
-    size_t l_count = dap_str_countv(l_keys);
-    if(a_tx_data->pos_num >= l_count) {
-        dap_strfreev(l_keys);
-        return NULL;
-    }
-    dap_store_obj_t *l_obj =
-            (dap_store_obj_t*) l_keys ? dap_chain_global_db_obj_get(l_keys[a_tx_data->pos_num], l_rec.group) : NULL;
-    dap_strfreev(l_keys);
-    return l_obj;
-}
-
-/**
- * Get data according the history log
- *
- * return history string
- */
-#if 0
-char* dap_db_history_tx(dap_chain_hash_fast_t* a_tx_hash, const char *a_group_mempool)
-{
-    dap_string_t *l_str_out = dap_string_new(NULL);
-    // load history
-    size_t l_data_size_out = 0;
-    dap_global_db_obj_t *l_objs = dap_chain_global_db_gr_load(GROUP_LOCAL_HISTORY, &l_data_size_out);
-    size_t i, j;
-    bool l_tx_hash_found = false;
-    dap_tx_data_t *l_tx_data_hash = NULL;
-    for(i = 0; i < l_data_size_out; i++) {
-        dap_global_db_obj_t *l_obj_cur = l_objs + i;
-
-        // parse global_db records in a history record
-        dap_global_db_hist_t l_rec;
-        if(dap_db_history_unpack_hist((char*) l_obj_cur->value, &l_rec) == -1)
-            continue;
-        // use only groups with datums
-        if(dap_strcmp(a_group_mempool, l_rec.group))
-            continue;
-
-        char **l_keys = dap_strsplit(l_rec.keys, GLOBAL_DB_HIST_KEY_SEPARATOR, -1);
-        size_t l_count = dap_str_countv(l_keys);
-        dap_store_obj_t *l_obj = NULL;
-        // all objs in one history records
-        for(j = 0; j < l_count; j++) {
-
-            if(l_rec.type != 'a')
-                continue;
-            l_obj = (dap_store_obj_t*) dap_chain_global_db_obj_get(l_keys[j], l_rec.group);
-            if(!l_obj)
-                continue;
-            // datum
-            dap_chain_datum_t *l_datum = (dap_chain_datum_t*) l_obj->value;
-            if(!l_datum && l_datum->header.type_id != DAP_CHAIN_DATUM_TX)
-                continue;
-
-            dap_tx_data_t *l_tx_data = NULL;
-
-            // transaction
-            dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data;
-
-            // find Token items - present in emit transaction
-            dap_list_t *l_list_tx_token = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_TOKEN, NULL);
-
-            // find OUT items
-            dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL);
-            dap_list_t *l_list_tmp = l_list_out_items;
-            while(l_list_tmp) {
-                const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data;
-                // save OUT item l_tx_out
-                if(!l_tx_data)
-                {
-                    // save tx hash
-                    l_tx_data = DAP_NEW_Z(dap_tx_data_t);
-                    dap_chain_hash_fast_t l_tx_hash;
-                    dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
-                    memcpy(&l_tx_data->tx_hash, &l_tx_hash, sizeof(dap_chain_hash_fast_t));
-                    memcpy(&l_tx_data->addr, &l_tx_out->addr, sizeof(dap_chain_addr_t));
-                    dap_chain_hash_fast_to_str(&l_tx_data->tx_hash, l_tx_data->tx_hash_str,
-                            sizeof(l_tx_data->tx_hash_str));
-                    l_tx_data->obj_num = i;
-                    l_tx_data->pos_num = j;
-                    // save token name
-                    if(l_list_tx_token) {
-                        dap_chain_tx_token_t *tk = l_list_tx_token->data;
-                        int d = sizeof(l_tx_data->token_ticker);
-                        memcpy(l_tx_data->token_ticker, tk->header.ticker, sizeof(l_tx_data->token_ticker));
-                    }
-                    // take token from prev out item
-                    else {
-
-                        // find IN items
-                        dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
-                        dap_list_t *l_list_tmp_in = l_list_in_items;
-                        // find token_ticker in prev OUT items
-                        while(l_list_tmp_in) {
-                            const dap_chain_tx_in_t *l_tx_in =
-                                    (const dap_chain_tx_in_t*) l_list_tmp_in->data;
-                            dap_chain_hash_fast_t tx_prev_hash = l_tx_in->header.tx_prev_hash;
-
-                            //find prev OUT item
-                            dap_tx_data_t *l_tx_data_prev = NULL;
-                            HASH_FIND(hh, l_tx_data_hash, &tx_prev_hash, sizeof(dap_chain_hash_fast_t),
-                                    l_tx_data_prev);
-                            if(l_tx_data_prev != NULL) {
-                                // fill token in l_tx_data from prev transaction
-                                if(l_tx_data) {
-                                    // get token from prev tx
-                                    memcpy(l_tx_data->token_ticker, l_tx_data_prev->token_ticker,
-                                            sizeof(l_tx_data->token_ticker));
-                                    break;
-                                }
-                                l_list_tmp_in = dap_list_next(l_list_tmp_in);
-                            }
-                        }
-                        if(l_list_in_items)
-                            dap_list_free(l_list_in_items);
-                    }
-                    HASH_ADD(hh, l_tx_data_hash, tx_hash, sizeof(dap_chain_hash_fast_t), l_tx_data);
-                }
-                l_list_tmp = dap_list_next(l_list_tmp);
-            }
-            if(l_list_out_items)
-                dap_list_free(l_list_out_items);
-
-            // calc hash
-            dap_chain_hash_fast_t l_tx_hash;
-            dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
-            // search tx with a_tx_hash
-            if(!dap_hash_fast_compare(a_tx_hash, &l_tx_hash))
-                continue;
-            // found a_tx_hash now
-
-            // transaction time
-            char *l_time_str = NULL;
-            if(l_tx->header.ts_created > 0) {
-                time_t rawtime = (time_t) l_tx->header.ts_created;
-                struct tm * timeinfo;
-                timeinfo = localtime(&rawtime);
-                if(timeinfo) {
-                    dap_string_append_printf(l_str_out, " %s", asctime(timeinfo));
-                }
-            }
-
-            // find all OUT items in transaction
-            l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL);
-            l_list_tmp = l_list_out_items;
-            while(l_list_tmp) {
-                const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data;
-                dap_tx_data_t *l_tx_data_prev = NULL;
-
-                const char *l_token_str = NULL;
-                if(l_tx_data)
-                    l_token_str = l_tx_data->token_ticker;
-                char *l_dst_to_str =
-                        (l_tx_out) ? dap_chain_addr_to_str(&l_tx_out->addr) :
-                        NULL;
-                dap_string_append_printf(l_str_out, " OUT item %lld %s to %s\n",
-                        l_tx_out->header.value,
-                        dap_strlen(l_token_str) > 0 ? l_token_str : "?",
-                        l_dst_to_str ? l_dst_to_str : "?"
-                                       );
-                DAP_DELETE(l_dst_to_str);
-                l_list_tmp = dap_list_next(l_list_tmp);
-            }
-            // find all IN items in transaction
-            dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
-            l_list_tmp = l_list_in_items;
-            // find cur addr in prev OUT items
-            while(l_list_tmp) {
-                const dap_chain_tx_in_t *l_tx_in = (const dap_chain_tx_in_t*) l_list_tmp->data;
-                dap_chain_hash_fast_t tx_prev_hash = l_tx_in->header.tx_prev_hash;
-                char l_tx_hash_str[70];
-                if(!dap_hash_fast_is_blank(&tx_prev_hash))
-                    dap_chain_hash_fast_to_str(&tx_prev_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
-                else
-                    strcpy(l_tx_hash_str,"Null");
-                dap_string_append_printf(l_str_out, " IN item \n  prev tx_hash %s\n", l_tx_hash_str);
-
-                //find prev OUT item
-                dap_tx_data_t *l_tx_data_prev = NULL;
-                HASH_FIND(hh, l_tx_data_hash, &tx_prev_hash, sizeof(dap_chain_hash_fast_t), l_tx_data_prev);
-                if(l_tx_data_prev != NULL) {
-
-                    dap_store_obj_t *l_obj_prev = get_prev_tx(l_objs, l_tx_data_prev);
-                    dap_chain_datum_t *l_datum_prev =
-                            l_obj_prev ? (dap_chain_datum_t*) l_obj_prev->value : NULL;
-                    dap_chain_datum_tx_t *l_tx_prev =
-                            l_datum_prev ? (dap_chain_datum_tx_t*) l_datum_prev->data : NULL;
-
-                    // find OUT items in prev datum
-                    dap_list_t *l_list_out_prev_items = dap_chain_datum_tx_items_get(l_tx_prev,
-                            TX_ITEM_TYPE_OUT, NULL);
-                    // find OUT item for IN item;
-                    dap_list_t *l_list_out_prev_item = dap_list_nth(l_list_out_prev_items,
-                            l_tx_in->header.tx_out_prev_idx);
-                    dap_chain_tx_out_t *l_tx_prev_out =
-                            l_list_out_prev_item ?
-                                                   (dap_chain_tx_out_t*) l_list_out_prev_item->data :
-                                                   NULL;
-                    // print value from prev out item
-                    dap_string_append_printf(l_str_out, "  prev OUT item value=%lld",
-                            l_tx_prev_out->header.value
-                            );
-                }
-                dap_string_append_printf(l_str_out, "\n");
-                l_list_tmp = dap_list_next(l_list_tmp);
-            }
-
-            if(l_list_tx_token)
-                dap_list_free(l_list_tx_token);
-            if(l_list_out_items)
-                dap_list_free(l_list_out_items);
-            if(l_list_in_items)
-                dap_list_free(l_list_in_items);
-            l_tx_hash_found = true;
-            break;
-        }
-        dap_list_t *l_records_out = NULL;
-
-        DAP_DELETE(l_obj);
-        dap_strfreev(l_keys);
-        // transaction was found -> exit
-        if(l_tx_hash_found)
-            break;
-    }
-    dap_chain_global_db_objs_delete(l_objs, l_data_size_out);
-    // if no history
-    if(!l_str_out->len)
-        dap_string_append(l_str_out, "empty");
-    char *l_ret_str = l_str_out ? dap_string_free(l_str_out, false) : NULL;
-    return l_ret_str;
-}
-#endif
-
-/**
- * Get data according the history log
- *
- * return history string
- */
-#if 0
-char* dap_db_history_addr(dap_chain_addr_t * a_addr, const char *a_group_mempool)
-{
-    dap_string_t *l_str_out = dap_string_new(NULL);
-    // load history
-    size_t l_data_size_out = 0;
-    dap_global_db_obj_t *l_objs = dap_chain_global_db_gr_load(GROUP_LOCAL_HISTORY, &l_data_size_out);
-    size_t i, j;
-    dap_tx_data_t *l_tx_data_hash = NULL;
-    for(i = 0; i < l_data_size_out; i++) {
-        dap_global_db_obj_t *l_obj_cur = l_objs + i;
-        // parse global_db records in a history record
-        dap_global_db_hist_t l_rec;
-        if(dap_db_history_unpack_hist((char*) l_obj_cur->value, &l_rec) == -1)
-            continue;
-        // use only groups with datums
-        if(dap_strcmp(a_group_mempool, l_rec.group))
-            continue;
-
-        char **l_keys = dap_strsplit(l_rec.keys, GLOBAL_DB_HIST_KEY_SEPARATOR, -1);
-        size_t l_count = dap_str_countv(l_keys);
-        dap_store_obj_t *l_obj = NULL;
-        // all objs in one history records
-        for(j = 0; j < l_count; j++) {
-            if(l_rec.type != 'a')
-                continue;
-            l_obj = (dap_store_obj_t*) dap_chain_global_db_obj_get(l_keys[j], l_rec.group);
-            if(!l_obj)
-                continue;
-            // datum
-            dap_chain_datum_t *l_datum = (dap_chain_datum_t*) l_obj->value;
-            if(!l_datum && l_datum->header.type_id != DAP_CHAIN_DATUM_TX)
-                continue;
-
-            // transaction
-            dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data;
-            dap_list_t *l_records_out = NULL;
-            // transaction time
-            char *l_time_str = NULL;
-            {
-                if(l_tx->header.ts_created > 0) {
-                    time_t rawtime = (time_t) l_tx->header.ts_created;
-                    struct tm * timeinfo;
-                    timeinfo = localtime(&rawtime);
-                    if(timeinfo)
-                        l_time_str = dap_strdup(asctime(timeinfo));
-                }
-                else
-                    l_time_str = dap_strdup(" ");
-            }
-
-            // transaction
-            dap_tx_data_t *l_tx_data = NULL;
-
-            // find Token items - present in emit transaction
-            dap_list_t *l_list_tx_token = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_TOKEN, NULL);
-
-            // find OUT items
-            dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL);
-            dap_list_t *l_list_tmp = l_list_out_items;
-            while(l_list_tmp) {
-                const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data;
-                // save OUT item l_tx_out
-                {
-                    // save tx hash
-                    l_tx_data = DAP_NEW_Z(dap_tx_data_t);
-                    dap_chain_hash_fast_t l_tx_hash;
-                    dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
-                    memcpy(&l_tx_data->tx_hash, &l_tx_hash, sizeof(dap_chain_hash_fast_t));
-                    memcpy(&l_tx_data->addr, &l_tx_out->addr, sizeof(dap_chain_addr_t));
-                    dap_chain_hash_fast_to_str(&l_tx_data->tx_hash, l_tx_data->tx_hash_str,
-                                                                sizeof(l_tx_data->tx_hash_str));
-                    l_tx_data->obj_num = i;
-                    l_tx_data->pos_num = j;
-                    // save token name
-                    if(l_tx_data && l_list_tx_token) {
-                        dap_chain_tx_token_t *tk = l_list_tx_token->data;
-                        int d = sizeof(l_tx_data->token_ticker);
-                        memcpy(l_tx_data->token_ticker, tk->header.ticker, sizeof(l_tx_data->token_ticker));
-                    }
-                    HASH_ADD(hh, l_tx_data_hash, tx_hash, sizeof(dap_chain_hash_fast_t), l_tx_data);
-
-                    // save OUT items to list
-                    {
-                        l_records_out = dap_list_append(l_records_out, (void*) l_tx_out);
-                    }
-                }
-                l_list_tmp = dap_list_next(l_list_tmp);
-            }
-
-            // find IN items
-            l_count = 0;
-            dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
-            l_list_tmp = l_list_in_items;
-            // find cur addr in prev OUT items
-            bool l_is_use_all_cur_out = false;
-            {
-                while(l_list_tmp) {
-                    const dap_chain_tx_in_t *l_tx_in = (const dap_chain_tx_in_t*) l_list_tmp->data;
-                    dap_chain_hash_fast_t tx_prev_hash = l_tx_in->header.tx_prev_hash;
-
-                    //find prev OUT item
-                    dap_tx_data_t *l_tx_data_prev = NULL;
-                    HASH_FIND(hh, l_tx_data_hash, &tx_prev_hash, sizeof(dap_chain_hash_fast_t), l_tx_data_prev);
-                    if(l_tx_data_prev != NULL) {
-                        // fill token in l_tx_data from prev transaction
-                        if(l_tx_data) {
-                            // get token from prev tx
-                            memcpy(l_tx_data->token_ticker, l_tx_data_prev->token_ticker,
-                                    sizeof(l_tx_data->token_ticker));
-                            dap_store_obj_t *l_obj_prev = get_prev_tx(l_objs, l_tx_data_prev);
-                            dap_chain_datum_t *l_datum_prev =
-                                    l_obj_prev ? (dap_chain_datum_t*) l_obj_prev->value : NULL;
-                            dap_chain_datum_tx_t *l_tx_prev =
-                                    l_datum_prev ? (dap_chain_datum_tx_t*) l_datum_prev->data : NULL;
-
-                            // find OUT items in prev datum
-                            dap_list_t *l_list_out_prev_items = dap_chain_datum_tx_items_get(l_tx_prev,
-                                    TX_ITEM_TYPE_OUT, NULL);
-                            // find OUT item for IN item;
-                            dap_list_t *l_list_out_prev_item = dap_list_nth(l_list_out_prev_items,
-                                    l_tx_in->header.tx_out_prev_idx);
-                            dap_chain_tx_out_t *l_tx_prev_out =
-                                    l_list_out_prev_item ?
-                                                           (dap_chain_tx_out_t*) l_list_out_prev_item->data :
-                                                           NULL;
-                            if(l_tx_prev_out && !memcmp(&l_tx_prev_out->addr, a_addr, sizeof(dap_chain_addr_t)))
-                                l_is_use_all_cur_out = true;
-
-                        }
-                    }
-
-                    // find prev OUT items for IN items
-                    l_list_tmp = l_list_in_items;
-                    while(l_list_tmp) {
-                        const dap_chain_tx_in_t *l_tx_in = (const dap_chain_tx_in_t*) l_list_tmp->data;
-                        dap_chain_hash_fast_t tx_prev_hash = l_tx_in->header.tx_prev_hash;
-                        // if first transaction - empty prev OUT item
-                        if(dap_hash_fast_is_blank(&tx_prev_hash)) {
-                            // add emit info to ret string
-                            if(!memcmp(&l_tx_data->addr, a_addr, sizeof(dap_chain_addr_t)))
-                                    {
-                                dap_list_t *l_records_tmp = l_records_out;
-                                while(l_records_tmp) {
-
-                                    const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_records_tmp->data;
-                                    dap_string_append_printf(l_str_out, "tx hash %s \n emit %lld %s\n",
-                                            l_tx_data->tx_hash_str,
-                                            l_tx_out->header.value,
-                                            l_tx_data->token_ticker);
-                                    l_records_tmp = dap_list_next(l_records_tmp);
-                                }
-                            }
-                            dap_list_free(l_records_out);
-                        }
-                        // in other transactions except first one
-                        else {
-                            //find prev OUT item
-                            dap_tx_data_t *l_tx_data_prev = NULL;
-                            HASH_FIND(hh, l_tx_data_hash, &tx_prev_hash, sizeof(dap_chain_hash_fast_t), l_tx_data_prev);
-                            if(l_tx_data_prev != NULL) {
-                                char *l_src_str = NULL;
-                                bool l_src_str_is_cur = false;
-                                if(l_tx_data) {
-                                    // get token from prev tx
-                                    memcpy(l_tx_data->token_ticker, l_tx_data_prev->token_ticker,
-                                            sizeof(l_tx_data->token_ticker));
-
-                                    dap_store_obj_t *l_obj_prev = get_prev_tx(l_objs, l_tx_data_prev);
-                                    dap_chain_datum_t *l_datum_prev =
-                                            l_obj_prev ? (dap_chain_datum_t*) l_obj_prev->value : NULL;
-                                    dap_chain_datum_tx_t *l_tx_prev =
-                                            l_datum_prev ? (dap_chain_datum_tx_t*) l_datum_prev->data : NULL;
-
-                                    // find OUT items in prev datum
-                                    dap_list_t *l_list_out_prev_items = dap_chain_datum_tx_items_get(l_tx_prev,
-                                            TX_ITEM_TYPE_OUT, NULL);
-                                    // find OUT item for IN item;
-                                    dap_list_t *l_list_out_prev_item = dap_list_nth(l_list_out_prev_items,
-                                            l_tx_in->header.tx_out_prev_idx);
-                                    dap_chain_tx_out_t *l_tx_prev_out =
-                                            l_list_out_prev_item ?
-                                                                   (dap_chain_tx_out_t*) l_list_out_prev_item->data :
-                                                                   NULL;
-                                    // if use src addr
-                                    bool l_is_use_src_addr = false;
-                                    // find source addrs
-                                    dap_string_t *l_src_addr = dap_string_new(NULL);
-                                    {
-                                        // find IN items in prev datum - for get destination addr
-                                        dap_list_t *l_list_in_prev_items = dap_chain_datum_tx_items_get(l_tx_prev,
-                                                TX_ITEM_TYPE_IN, NULL);
-                                        dap_list_t *l_list_tmp = l_list_in_prev_items;
-                                        while(l_list_tmp) {
-                                            dap_chain_tx_in_t *l_tx_prev_in = l_list_tmp->data;
-                                            dap_chain_hash_fast_t l_tx_prev_prev_hash =
-                                                    l_tx_prev_in->header.tx_prev_hash;
-                                            //find prev OUT item
-                                            dap_tx_data_t *l_tx_data_prev_prev = NULL;
-                                            HASH_FIND(hh, l_tx_data_hash, &l_tx_prev_prev_hash,
-                                                    sizeof(dap_chain_hash_fast_t), l_tx_data_prev_prev);
-                                            if(l_tx_data_prev_prev) {
-                                                // if use src addr
-                                                if(!memcmp(&l_tx_data_prev_prev->addr, a_addr,
-                                                        sizeof(dap_chain_addr_t)))
-                                                    l_is_use_src_addr = true;
-                                                char *l_str = dap_chain_addr_to_str(&l_tx_data_prev_prev->addr);
-                                                if(l_src_addr->len > 0)
-                                                    dap_string_append_printf(l_src_addr, "\n   %s", l_str);
-                                                else
-                                                    dap_string_append_printf(l_src_addr, "%s", l_str); // first record
-                                                DAP_DELETE(l_str);
-                                            }
-                                            l_list_tmp = dap_list_next(l_list_tmp);
-                                        }
-                                    }
-
-                                    char *l_dst_to_str =
-                                            (l_tx_prev_out) ? dap_chain_addr_to_str(&l_tx_prev_out->addr) :
-                                            NULL;
-                                    // if use dst addr
-                                    bool l_is_use_dst_addr = false;
-                                    if(!memcmp(&l_tx_prev_out->addr, a_addr, sizeof(dap_chain_addr_t)))
-                                        l_is_use_dst_addr = true;
-
-                                    l_src_str_is_cur = l_is_use_src_addr;
-                                    if(l_src_addr->len <= 1) {
-                                        l_src_str =
-                                                (l_tx_data) ? dap_chain_addr_to_str(&l_tx_data->addr) :
-                                                NULL;
-                                        if(!memcmp(&l_tx_prev_out->addr, a_addr, sizeof(dap_chain_addr_t)))
-                                            l_src_str_is_cur = true;
-                                        dap_string_free(l_src_addr, true);
-                                    }
-                                    else
-                                        l_src_str = dap_string_free(l_src_addr, false);
-                                    if(l_is_use_src_addr && !l_is_use_dst_addr) {
-                                        dap_string_append_printf(l_str_out,
-                                                "tx hash %s \n %s in send  %lld %s from %s\n to %s\n",
-                                                l_tx_data->tx_hash_str,
-                                                l_time_str ? l_time_str : "",
-                                                l_tx_prev_out->header.value,
-                                                l_tx_data->token_ticker,
-                                                l_src_str ? l_src_str : "",
-                                                l_dst_to_str);
-                                    } else if(l_is_use_dst_addr && !l_is_use_src_addr) {
-                                        if(!l_src_str_is_cur)
-                                            dap_string_append_printf(l_str_out,
-                                                    "tx hash %s \n %s in recv %lld %s from %s\n",
-                                                    l_tx_data->tx_hash_str,
-                                                    l_time_str ? l_time_str : "",
-                                                    l_tx_prev_out->header.value,
-                                                    l_tx_data->token_ticker,
-                                                    l_src_str ? l_src_str : "");
-                                    }
-
-                                    DAP_DELETE(l_dst_to_str);
-                                    dap_list_free(l_list_out_prev_items);
-                                    DAP_DELETE(l_obj_prev);
-                                }
-
-                                // OUT items
-                                dap_list_t *l_records_tmp = l_records_out;
-                                while(l_records_tmp) {
-
-                                    const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_records_tmp->data;
-
-                                    if(l_is_use_all_cur_out
-                                            || !memcmp(&l_tx_out->addr, a_addr, sizeof(dap_chain_addr_t))) {
-
-                                        char *l_addr_str = (l_tx_out) ? dap_chain_addr_to_str(&l_tx_out->addr) : NULL;
-
-                                        if(!memcmp(&l_tx_out->addr, a_addr, sizeof(dap_chain_addr_t))) {
-                                            if(!l_src_str_is_cur)
-                                                dap_string_append_printf(l_str_out, "tx hash %s \n %s recv %lld %s from %s\n",
-                                                        l_tx_data->tx_hash_str,
-                                                        l_time_str ? l_time_str : "",
-                                                        l_tx_out->header.value,
-                                                        l_tx_data_prev->token_ticker,
-                                                        l_src_str ? l_src_str : "?");
-                                        }
-                                        else {
-                                            dap_string_append_printf(l_str_out, "tx hash %s \n %s send %lld %s to %sd\n",
-                                                    l_tx_data->tx_hash_str,
-                                                    l_time_str ? l_time_str : "",
-                                                    l_tx_out->header.value,
-                                                    l_tx_data_prev->token_ticker,
-                                                    l_addr_str ? l_addr_str : "");
-                                        }
-                                        DAP_DELETE(l_addr_str);
-                                    }
-                                    l_records_tmp = dap_list_next(l_records_tmp);
-                                }
-                                dap_list_free(l_records_out);
-                                DAP_DELETE(l_src_str);
-
-                            }
-                        }
-                        l_list_tmp = dap_list_next(l_list_tmp);
-                    }
-                    l_list_tmp = dap_list_next(l_list_tmp);
-                }
-            }
-
-
-
-            if(l_list_tx_token)
-                dap_list_free(l_list_tx_token);
-            if(l_list_out_items)
-                dap_list_free(l_list_out_items);
-            if(l_list_in_items)
-                dap_list_free(l_list_in_items);
-
-            DAP_DELETE(l_time_str);
-        }
-        DAP_DELETE(l_obj);
-        dap_strfreev(l_keys);
-
-    }
-    // delete hashes
-    dap_tx_data_t *l_iter_current, *l_item_tmp;
-    HASH_ITER(hh, l_tx_data_hash , l_iter_current, l_item_tmp)
-    {
-        // delete struct
-        DAP_DELETE(l_iter_current);
-        HASH_DEL(l_tx_data_hash, l_iter_current);
-    }
-    dap_chain_global_db_objs_delete(l_objs, l_data_size_out);
-    // if no history
-    if(!l_str_out->len)
-        dap_string_append(l_str_out, " empty");
-    char *l_ret_str = l_str_out ? dap_string_free(l_str_out, false) : NULL;
-    return l_ret_str;
-}
-#endif
-
-
-/**
- * Get data according the history log
- *
- * return history string
- */
-char* dap_db_history(dap_chain_addr_t * a_addr, const char *a_group_mempool)
-{
-    dap_string_t *l_str_out = dap_string_new(NULL);
-    // load history
-    size_t l_data_size_out = 0;
-    dap_global_db_obj_t *l_objs = dap_chain_global_db_gr_load(GROUP_LOCAL_HISTORY, &l_data_size_out);
-    size_t i, j;
-    dap_tx_data_t *l_tx_data_hash = NULL;
-    for(i = 0; i < l_data_size_out; i++) {
-        dap_global_db_obj_t *l_obj_cur = l_objs + i;
-
-        // parse global_db records in a history record
-        dap_global_db_hist_t l_rec;
-        if(dap_db_history_unpack_hist((char*) l_obj_cur->value, &l_rec) == -1)
-            continue;
-        // use only groups with datums
-        if(dap_strcmp(a_group_mempool, l_rec.group))
-            continue;
-
-        char **l_keys = dap_strsplit(l_rec.keys, GLOBAL_DB_HIST_KEY_SEPARATOR, -1);
-        size_t l_count = dap_str_countv(l_keys);
-        dap_store_obj_t *l_obj = NULL;
-        // all objs in one history records
-        for(j = 0; j < l_count; j++) {
-            // add record
-            if(l_rec.type == 'a') {
-                l_obj = (dap_store_obj_t*) dap_chain_global_db_obj_get(l_keys[j], l_rec.group);
-                if(!l_obj)
-                    continue;
-                dap_chain_datum_t *l_datum = (dap_chain_datum_t*) l_obj->value;
-                if(!l_datum)
-                    continue;
-                switch (l_datum->header.type_id) {
-                /*                case DAP_CHAIN_DATUM_TOKEN_DECL: {
-                 dap_chain_datum_token_t *l_token = (dap_chain_datum_token_t*) l_datum->data;
-                 }
-                 break;
-                 case DAP_CHAIN_DATUM_TOKEN_EMISSION: {
-                 dap_chain_datum_token_emission_t *l_token_emission =
-                 (dap_chain_datum_token_emission_t*) l_datum->data;
-                 }
-                 break;*/
-                // find transaction
-                case DAP_CHAIN_DATUM_TX: {
-                    dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data;
-                    dap_list_t *l_records_out = NULL;
-
-                    // transaction time
-                    char *l_time_str = NULL;
-                    if(l_tx->header.ts_created > 0) {
-                        time_t rawtime = (time_t) l_tx->header.ts_created;
-                        struct tm * timeinfo;
-                        timeinfo = localtime(&rawtime);
-                        if(timeinfo)
-                            l_time_str = dap_strdup(asctime(timeinfo));
-                    }
-                    else
-                        l_time_str = dap_strdup(" ");
-
-                    int l_count = 0;
-                    dap_tx_data_t *l_tx_data = NULL;
-                    // find Token items - present in emit transaction
-                    l_count = 0;
-                    dap_list_t *l_list_tx_token = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_TOKEN, &l_count);
-
-                    // find OUT items
-                    dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, &l_count);
-                    dap_list_t *l_list_tmp = l_list_out_items;
-                    while(l_list_tmp) {
-                        dap_chain_tx_out_t *l_tx_out = (dap_chain_tx_out_t*) l_list_tmp->data;
-                        // save OUT item l_tx_out
-                        {
-                            // save tx hash
-                            l_tx_data = DAP_NEW_Z(dap_tx_data_t);
-                            dap_chain_hash_fast_t l_tx_hash;
-                            dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
-                            memcpy(&l_tx_data->tx_hash, &l_tx_hash, sizeof(dap_chain_hash_fast_t));
-                            memcpy(&l_tx_data->addr, &l_tx_out->addr, sizeof(dap_chain_addr_t));
-                            l_tx_data->obj_num = i;
-                            l_tx_data->pos_num = j;
-                            // save token name
-                            if(l_tx_data && l_list_tx_token) {
-                                dap_chain_tx_token_t *tk = l_list_tx_token->data;
-//                                int d = sizeof(l_tx_data->token_ticker);
-                                memcpy(l_tx_data->token_ticker, tk->header.ticker, sizeof(l_tx_data->token_ticker));
-                            }
-                            HASH_ADD(hh, l_tx_data_hash, tx_hash, sizeof(dap_chain_hash_fast_t), l_tx_data);
-
-                            // save OUT items to list
-                            {
-                                l_records_out = dap_list_append(l_records_out, (void*) l_tx_out);
-                            }
-                        }
-                        l_list_tmp = dap_list_next(l_list_tmp);
-                    }
-
-                    // find IN items
-                    l_count = 0;
-                    dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, &l_count);
-                    l_list_tmp = l_list_in_items;
-
-                    // find cur addr in prev OUT items
-                    bool l_is_use_all_cur_out = false;
-                    {
-                        while(l_list_tmp) {
-                            const dap_chain_tx_in_t *l_tx_in = (const dap_chain_tx_in_t*) l_list_tmp->data;
-                            dap_chain_hash_fast_t tx_prev_hash = l_tx_in->header.tx_prev_hash;
-
-                            //find prev OUT item
-                            dap_tx_data_t *l_tx_data_prev = NULL;
-                            HASH_FIND(hh, l_tx_data_hash, &tx_prev_hash, sizeof(dap_chain_hash_fast_t), l_tx_data_prev);
-                            if(l_tx_data_prev != NULL) {
-                                // fill token in l_tx_data from prev transaction
-                                if(l_tx_data) {
-                                    // get token from prev tx
-                                    memcpy(l_tx_data->token_ticker, l_tx_data_prev->token_ticker,
-                                            sizeof(l_tx_data->token_ticker));
-                                    dap_store_obj_t *l_obj_prev = get_prev_tx(l_objs, l_tx_data_prev);
-                                    dap_chain_datum_t *l_datum_prev =
-                                            l_obj_prev ? (dap_chain_datum_t*) l_obj_prev->value : NULL;
-                                    dap_chain_datum_tx_t *l_tx_prev =
-                                            l_datum_prev ? (dap_chain_datum_tx_t*) l_datum_prev->data : NULL;
-
-                                    // find OUT items in prev datum
-                                    dap_list_t *l_list_out_prev_items = dap_chain_datum_tx_items_get(l_tx_prev,
-                                            TX_ITEM_TYPE_OUT, &l_count);
-                                    // find OUT item for IN item;
-                                    dap_list_t *l_list_out_prev_item = dap_list_nth(l_list_out_prev_items,
-                                            l_tx_in->header.tx_out_prev_idx);
-                                    dap_chain_tx_out_t *l_tx_prev_out =
-                                            l_list_out_prev_item ?
-                                                                   (dap_chain_tx_out_t*) l_list_out_prev_item->data :
-                                                                   NULL;
-                                    if(l_tx_prev_out && !memcmp(&l_tx_prev_out->addr, a_addr, sizeof(dap_chain_addr_t)))
-                                        l_is_use_all_cur_out = true;
-
-                                }
-                            }
-                            l_list_tmp = dap_list_next(l_list_tmp);
-                        }
-                    }
-
-                    // find prev OUT items for IN items
-                    l_list_tmp = l_list_in_items;
-                    while(l_list_tmp) {
-                        const dap_chain_tx_in_t *l_tx_in = (const dap_chain_tx_in_t*) l_list_tmp->data;
-                        dap_chain_hash_fast_t tx_prev_hash = l_tx_in->header.tx_prev_hash;
-                        // if first transaction - empty prev OUT item
-                        if(dap_hash_fast_is_blank(&tx_prev_hash)) {
-                            // add emit info to ret string
-                            if(l_tx_data && a_addr &&
-                                    ( memcmp(&l_tx_data->addr, a_addr, sizeof(dap_chain_addr_t) ) == 0 )
-                                ) {
-                                dap_list_t *l_records_tmp = l_records_out;
-                                while(l_records_tmp) {
-                                    const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_records_tmp->data;
-                                    dap_string_append_printf(l_str_out, "emit %lld %s\n",
-                                            l_tx_out->header.value,
-                                            l_tx_data->token_ticker);
-                                    l_records_tmp = dap_list_next(l_records_tmp);
-                                }
-                            }
-                            dap_list_free(l_records_out);
-                        }
-                        // in other transactions except first one
-                        else {
-                            //find prev OUT item
-                            dap_tx_data_t *l_tx_data_prev = NULL;
-                            HASH_FIND(hh, l_tx_data_hash, &tx_prev_hash, sizeof(dap_chain_hash_fast_t), l_tx_data_prev);
-                            if(l_tx_data_prev != NULL) {
-                                char *l_src_str = NULL;
-                                bool l_src_str_is_cur = false;
-                                if(l_tx_data) {
-                                    // get token from prev tx
-                                    memcpy(l_tx_data->token_ticker, l_tx_data_prev->token_ticker,
-                                            sizeof(l_tx_data->token_ticker));
-
-                                    dap_store_obj_t *l_obj_prev = get_prev_tx(l_objs, l_tx_data_prev);
-                                    dap_chain_datum_t *l_datum_prev =
-                                            l_obj_prev ? (dap_chain_datum_t*) l_obj_prev->value : NULL;
-                                    dap_chain_datum_tx_t *l_tx_prev =
-                                            l_datum_prev ? (dap_chain_datum_tx_t*) l_datum_prev->data : NULL;
-
-                                    // find OUT items in prev datum
-                                    dap_list_t *l_list_out_prev_items = dap_chain_datum_tx_items_get(l_tx_prev,
-                                            TX_ITEM_TYPE_OUT, &l_count);
-                                    // find OUT item for IN item;
-                                    dap_list_t *l_list_out_prev_item = dap_list_nth(l_list_out_prev_items,
-                                            l_tx_in->header.tx_out_prev_idx);
-                                    dap_chain_tx_out_t *l_tx_prev_out =
-                                            l_list_out_prev_item ?
-                                                                   (dap_chain_tx_out_t*) l_list_out_prev_item->data :
-                                                                   NULL;
-                                    // if use src addr
-                                    bool l_is_use_src_addr = false;
-                                    // find source addrs
-                                    dap_string_t *l_src_addr = dap_string_new(NULL);
-                                    {
-                                        // find IN items in prev datum - for get destination addr
-                                        dap_list_t *l_list_in_prev_items = dap_chain_datum_tx_items_get(l_tx_prev,
-                                                TX_ITEM_TYPE_IN, &l_count);
-                                        dap_list_t *l_list_tmp = l_list_in_prev_items;
-                                        while(l_list_tmp) {
-                                            dap_chain_tx_in_t *l_tx_prev_in = l_list_tmp->data;
-                                            dap_chain_hash_fast_t l_tx_prev_prev_hash =
-                                                    l_tx_prev_in->header.tx_prev_hash;
-                                            //find prev OUT item
-                                            dap_tx_data_t *l_tx_data_prev_prev = NULL;
-                                            HASH_FIND(hh, l_tx_data_hash, &l_tx_prev_prev_hash,
-                                                    sizeof(dap_chain_hash_fast_t), l_tx_data_prev_prev);
-                                            if(l_tx_data_prev_prev) {
-                                                // if use src addr
-                                                if(!memcmp(&l_tx_data_prev_prev->addr, a_addr,
-                                                        sizeof(dap_chain_addr_t)))
-                                                    l_is_use_src_addr = true;
-                                                char *l_str = dap_chain_addr_to_str(&l_tx_data_prev_prev->addr);
-                                                if(l_src_addr->len > 0)
-                                                    dap_string_append_printf(l_src_addr, "\n   %s", l_str);
-                                                else
-                                                    dap_string_append_printf(l_src_addr, "%s", l_str); // first record
-                                                DAP_DELETE(l_str);
-                                            }
-                                            l_list_tmp = dap_list_next(l_list_tmp);
-                                        }
-                                    }
-
-                                    char *l_dst_to_str =
-                                            (l_tx_prev_out) ? dap_chain_addr_to_str(&l_tx_prev_out->addr) :
-                                            NULL;
-                                    // if use dst addr
-                                    bool l_is_use_dst_addr = false;
-                                    if(l_tx_prev_out &&  a_addr &&
-                                            ( memcmp(&l_tx_prev_out->addr, a_addr, sizeof(dap_chain_addr_t) ) == 0 )){
-                                        l_is_use_dst_addr = true;
-                                    }
-
-                                    l_src_str_is_cur = l_is_use_src_addr;
-                                    if(l_src_addr->len <= 1) {
-                                        l_src_str =
-                                                (l_tx_data) ? dap_chain_addr_to_str(&l_tx_data->addr) :
-                                                NULL;
-                                        if(!memcmp(&l_tx_prev_out->addr, a_addr, sizeof(dap_chain_addr_t)))
-                                            l_src_str_is_cur = true;
-                                        dap_string_free(l_src_addr, true);
-                                    }
-                                    else
-                                        l_src_str = dap_string_free(l_src_addr, false);
-                                    if(l_is_use_src_addr && !l_is_use_dst_addr) {
-                                        dap_string_append_printf(l_str_out,
-                                                "%s in send  %lld %s from %s\n to %s\n",
-                                                l_time_str ? l_time_str : "",
-                                                l_tx_prev_out?l_tx_prev_out->header.value:0,
-                                                l_tx_data->token_ticker,
-                                                l_src_str ? l_src_str : "",
-                                                l_dst_to_str);
-                                    } else if(l_is_use_dst_addr && !l_is_use_src_addr) {
-                                        if(!l_src_str_is_cur)
-                                            dap_string_append_printf(l_str_out,
-                                                    "%s in recv %lld %s from %s\n",
-                                                    l_time_str ? l_time_str : "",
-                                                    l_tx_prev_out->header.value,
-                                                    l_tx_data->token_ticker,
-                                                    l_src_str ? l_src_str : "");
-                                    }
-
-                                    DAP_DELETE(l_dst_to_str);
-                                    dap_list_free(l_list_out_prev_items);
-                                    DAP_DELETE(l_obj_prev);
-                                }
-
-                                // OUT items
-                                dap_list_t *l_records_tmp = l_records_out;
-                                while(l_records_tmp) {
-
-                                    const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_records_tmp->data;
-
-                                    if(l_is_use_all_cur_out
-                                            || !memcmp(&l_tx_out->addr, a_addr, sizeof(dap_chain_addr_t))) {
-
-                                        char *l_addr_str = (l_tx_out) ? dap_chain_addr_to_str(&l_tx_out->addr) : NULL;
-
-                                        if(!memcmp(&l_tx_out->addr, a_addr, sizeof(dap_chain_addr_t))) {
-                                            if(!l_src_str_is_cur)
-                                                dap_string_append_printf(l_str_out, "%s recv %lld %s from %s\n",
-                                                        l_time_str ? l_time_str : "",
-                                                        l_tx_out->header.value,
-                                                        l_tx_data_prev->token_ticker,
-                                                        l_src_str ? l_src_str : "?");
-                                        }
-                                        else {
-                                            dap_string_append_printf(l_str_out, "%s send %lld %s to %sd\n",
-                                                    l_time_str ? l_time_str : "",
-                                                    l_tx_out->header.value,
-                                                    l_tx_data_prev->token_ticker,
-                                                    l_addr_str ? l_addr_str : "");
-                                        }
-                                        DAP_DELETE(l_addr_str);
-                                    }
-                                    l_records_tmp = dap_list_next(l_records_tmp);
-                                }
-                                dap_list_free(l_records_out);
-                                DAP_DELETE(l_src_str);
-
-                            }
-                        }
-                        l_list_tmp = dap_list_next(l_list_tmp);
-                    }
-                    if(l_list_tx_token)
-                        dap_list_free(l_list_tx_token);
-                    if(l_list_out_items)
-                        dap_list_free(l_list_out_items);
-                    if(l_list_in_items)
-                        dap_list_free(l_list_in_items);
-
-                    DAP_DELETE(l_time_str);
-                }
-                    break;
-                default:
-                    continue;
-                }
-            }
-            // delete record
-            else if(l_rec.type == 'd') {
-                //printf("del_gr%d_%d=%s\n", i, j, l_rec.group);
-            }
-        }
-        DAP_DELETE(l_obj);
-        dap_strfreev(l_keys);
-    }
-    // delete hashes
-    dap_tx_data_t *l_iter_current, *l_item_tmp;
-    HASH_ITER(hh, l_tx_data_hash , l_iter_current, l_item_tmp)
-    {
-        // delete struct
-        DAP_DELETE(l_iter_current);
-        HASH_DEL(l_tx_data_hash, l_iter_current);
-    }
-    dap_chain_global_db_objs_delete(l_objs, l_data_size_out);
-    // if no history
-    if(!l_str_out->len)
-        dap_string_append(l_str_out, "empty");
-    char *l_ret_str = l_str_out ? dap_string_free(l_str_out, false) : NULL;
-    return l_ret_str;
-}
-
 /**
  * Add data to the history log
  */
@@ -1121,22 +121,13 @@ bool dap_db_history_add(char a_type, pdap_store_obj_t a_store_obj, size_t a_dap_
     return false;
 }
 
-/**
- * Truncate the history log
- */
-bool dap_db_history_truncate(void)
-{
-    // TODO
-    return true;
-}
-
 /**
  * Get last id in log
  */
-uint64_t dap_db_log_get_group_history_last_id(const char *a_history_group_name)
+uint64_t dap_db_log_get_group_last_id(const char *a_group_name)
 {
     uint64_t result = 0;
-    dap_store_obj_t *l_last_obj = dap_chain_global_db_get_last(a_history_group_name);
+    dap_store_obj_t *l_last_obj = dap_chain_global_db_get_last(a_group_name);
     if(l_last_obj) {
         result = l_last_obj->id;
         dap_store_obj_free(l_last_obj, 1);
@@ -1149,170 +140,69 @@ uint64_t dap_db_log_get_group_history_last_id(const char *a_history_group_name)
  */
 uint64_t dap_db_log_get_last_id(void)
 {
-    return dap_db_log_get_group_history_last_id(GROUP_LOCAL_HISTORY);
-}
-
-/*static int compare_items(const void * l_a, const void * l_b)
-{
-    const dap_global_db_obj_t *l_item_a = (const dap_global_db_obj_t*) l_a;
-    const dap_global_db_obj_t *l_item_b = (const dap_global_db_obj_t*) l_b;
-    int l_ret = strcmp(l_item_a->key, l_item_b->key);
-    return l_ret;
-}*/
-
-/**
- * Get log diff as list
- */
-dap_list_t* dap_db_log_get_list(uint64_t first_id)
-{
-    dap_list_t *l_list = NULL;
-    size_t l_data_size_out = 0;
-    //log_it(L_DEBUG,"loading db list...");
-    dap_store_obj_t *l_objs = dap_chain_global_db_cond_load(GROUP_LOCAL_HISTORY, first_id, &l_data_size_out);
-    //dap_global_db_obj_t *l_objs = dap_chain_global_db_gr_load(GROUP_LOCAL_HISTORY, first_timestamp, &l_data_size_out);
-    for(size_t i = 0; i < l_data_size_out; i++) {
-        dap_store_obj_t *l_obj_cur = l_objs + i;
-        dap_global_db_obj_t *l_item = DAP_NEW(dap_global_db_obj_t);
-        l_item->id = l_obj_cur->id;
-        l_item->key = dap_strdup(l_obj_cur->key);
-        l_item->value = (uint8_t*) dap_strdup((char*) l_obj_cur->value);
-        l_list = dap_list_append(l_list, l_item);
-    }
-    //log_it(L_DEBUG,"loaded db list n=%d", l_data_size_out);
-    dap_store_obj_free(l_objs, l_data_size_out);
-
-    return l_list;
-    /*
-     size_t l_list_count = 0;
-     char *l_first_key_str = dap_strdup_printf("%lld", (int64_t) first_timestamp);
-     size_t l_data_size_out = 0;
-
-     for(size_t i = 0; i < l_data_size_out; i++) {
-     dap_global_db_obj_t *l_obj_cur = l_objs[i];
-     //        log_it(L_DEBUG,"%lld and %lld tr",strtoll(l_obj_cur->key,NULL,10), first_timestamp );
-     if( strtoll(l_obj_cur->key,NULL,10) > (long long) first_timestamp  ) {
-     dap_global_db_obj_t *l_item = DAP_NEW(dap_global_db_obj_t);
-     l_item->key = dap_strdup(l_obj_cur->key);
-     l_item->value =(uint8_t*) dap_strdup((char*) l_obj_cur->value);
-     l_list = dap_list_append(l_list, l_item);
-     l_list_count++;
-     }
-     }
-     // sort list by key (time str)
-     //dap_list_sort(l_list, (dap_callback_compare_t) compare_items);
-     log_it(L_DEBUG,"Prepared %u items (list size %u)", l_list_count, dap_list_length(l_list));
-     DAP_DELETE(l_first_key_str);
-     dap_chain_global_db_objs_delete(l_objs);
-     */
-    /*/ dbg - sort result
-     l_data_size_out = dap_list_length(l_list);
-     for(size_t i = 0; i < l_data_size_out; i++) {
-     dap_list_t *l_list_tmp = dap_list_nth(l_list, i);
-     dap_global_db_obj_t *l_item = l_list_tmp->data;
-     printf("2 %d %s\n", i, l_item->key);
-     }*/
-
-}
-
-/**
- * Free list getting from dap_db_log_get_list()
- */
-void dap_db_log_del_list(dap_list_t *a_list)
-{
-    dap_list_free_full(a_list, (dap_callback_destroyed_t) dap_chain_global_db_obj_delete);
+    return dap_db_log_get_group_last_id(GROUP_LOCAL_HISTORY);
 }
 
-
-
-
 /**
  * Thread for reading log list
  * instead dap_db_log_get_list()
  */
 static void *s_list_thread_proc(void *arg)
 {
-    dap_db_log_list_t *l_dap_db_log_list = (dap_db_log_list_t*) arg;
-    size_t l_items_number = 0;
-    while(1) {
-        bool is_process;
-        char *l_group_cur_name = NULL;
-        // check for break process
-        pthread_mutex_lock(&l_dap_db_log_list->list_mutex);
-        is_process = l_dap_db_log_list->is_process;
-        size_t l_item_start = l_dap_db_log_list->item_start;
-        size_t l_item_last = l_dap_db_log_list->item_last;
-        if(l_dap_db_log_list->group_cur == -1)
-            l_group_cur_name = GROUP_LOCAL_HISTORY;
-        else
-            l_group_cur_name = l_dap_db_log_list->group_names[l_dap_db_log_list->group_cur];
-        pthread_mutex_unlock(&l_dap_db_log_list->list_mutex);
-        if(!is_process)
-            break;
-        // calculating how many items required to read
-        size_t l_item_count =(uint64_t) min(10, (int64_t)l_item_last - (int64_t)l_item_start + 1);
-        dap_store_obj_t *l_objs = NULL;
-        // read next 1...10 items
-        if(l_item_count > 0)
-            l_objs = dap_chain_global_db_cond_load(l_group_cur_name, l_item_start, &l_item_count);
-        // go to next group
-        if(!l_objs) {
-            pthread_mutex_lock(&l_dap_db_log_list->list_mutex);
-            while(l_dap_db_log_list->group_cur < l_dap_db_log_list->group_number) {
-                l_dap_db_log_list->group_cur++;
-                // check for empty group
-                if( !(l_dap_db_log_list->group_number) || (l_dap_db_log_list->group_number_items[l_dap_db_log_list->group_cur] < 1)) {
-                    continue;
-                }
-                break;
-            }
-            // end of all groups
-            if(l_dap_db_log_list->group_cur >= l_dap_db_log_list->group_number) {
-                pthread_mutex_unlock(&l_dap_db_log_list->list_mutex);
+    dap_db_log_list_t *l_dap_db_log_list = (dap_db_log_list_t *)arg;
+    for (dap_list_t *l_groups = l_dap_db_log_list->groups; l_groups && l_dap_db_log_list->is_process; l_groups = dap_list_next(l_groups)) {
+        dap_db_log_list_group_t *l_group_cur = (dap_db_log_list_group_t *)l_groups->data;
+        char *l_del_group_name_replace = NULL;
+        char l_obj_type;
+        if (!dap_fnmatch("*.del", l_group_cur->name, 0)) {
+            l_obj_type = 'd';
+            size_t l_del_name_len = strlen(l_group_cur->name) - 4; //strlen(".del");
+            l_del_group_name_replace = DAP_NEW_SIZE(char, l_del_name_len + 1);
+            memcpy(l_del_group_name_replace, l_group_cur->name, l_del_name_len);
+            l_del_group_name_replace[l_del_name_len] = '\0';
+        } else {
+            l_obj_type = 'a';
+        }
+        uint64_t l_item_start = l_group_cur->last_id_synced + 1;
+        while (l_group_cur->count && l_dap_db_log_list->is_process) { // Number of records to be synchronized
+            size_t l_item_count = min(32, l_group_cur->count);
+            dap_store_obj_t *l_objs = dap_chain_global_db_cond_load(l_group_cur->name, l_item_start, &l_item_count);
+            // go to next group
+            if (!l_objs)
                 break;
+            // set new start pos = lastitem pos + 1
+            l_item_start = l_objs[l_item_count - 1].id + 1;
+            l_group_cur->count -= l_item_count;
+            dap_list_t *l_list = NULL;
+            for (size_t i = 0; i < l_item_count; i++) {
+                dap_store_obj_t *l_obj_cur = l_objs + i;
+                l_obj_cur->type = l_obj_type;
+                if (l_obj_type == 'd') {
+                    DAP_DELETE(l_obj_cur->group);
+                    l_obj_cur->group = dap_strdup(l_del_group_name_replace);
+                }
+                dap_db_log_list_obj_t *l_list_obj = DAP_NEW_Z(dap_db_log_list_obj_t);
+                uint64_t l_cur_id = l_obj_cur->id;
+                l_obj_cur->id = 0;
+                dap_store_obj_pkt_t *l_pkt = dap_store_packet_single(l_obj_cur);
+                dap_hash_fast(l_pkt->data, l_pkt->data_size, &l_list_obj->hash);
+                dap_store_packet_change_id(l_pkt, l_cur_id);
+                l_list_obj->pkt = l_pkt;
+                l_list = dap_list_append(l_list, l_list_obj);
+                if (!l_dap_db_log_list->is_process)
+                    break;
             }
-            l_dap_db_log_list->item_start = 0;
-            l_dap_db_log_list->item_last = l_dap_db_log_list->group_last_id[l_dap_db_log_list->group_cur];
-            l_item_start = l_dap_db_log_list->item_start;
-            l_item_last = l_dap_db_log_list->item_last;
-            if(l_dap_db_log_list->group_cur == -1)
-                l_group_cur_name = GROUP_LOCAL_HISTORY;
-            else
-                l_group_cur_name = l_dap_db_log_list->group_names[l_dap_db_log_list->group_cur];
+            dap_store_obj_free(l_objs, l_item_count);
+            pthread_mutex_lock(&l_dap_db_log_list->list_mutex);
+            // add l_list to list_write
+            l_dap_db_log_list->list_write = dap_list_concat(l_dap_db_log_list->list_write, l_list);
+            // init read list if it ended already
+            if(!l_dap_db_log_list->list_read)
+                l_dap_db_log_list->list_read = l_list;
             pthread_mutex_unlock(&l_dap_db_log_list->list_mutex);
-
-            //l_item_count = min(10, (int64_t)l_item_last - (int64_t)l_item_start + 1);
-            //if(l_item_count<=0)
-            //    continue;
-            // read next 1...10 items
-            //l_objs = dap_chain_global_db_cond_load(l_group_cur_name, l_item_start, &l_item_count);
-            continue;
-        }
-        //if(!l_objs)
-            //continue;
-        dap_list_t *l_list = NULL;
-        for(size_t i = 0; i < l_item_count; i++) {
-            dap_store_obj_t *l_obj_cur = l_objs + i;
-            dap_global_db_obj_t *l_item = DAP_NEW(dap_global_db_obj_t);
-            l_item->id = l_obj_cur->id;
-            l_item->key = dap_strdup(l_obj_cur->key);
-            l_item->value = (uint8_t*) dap_strdup((char*) l_obj_cur->value);
-            l_list = dap_list_append(l_list, l_item);
         }
-        pthread_mutex_lock(&l_dap_db_log_list->list_mutex);
-        // add l_list to list_write
-        l_dap_db_log_list->list_write = dap_list_concat(l_dap_db_log_list->list_write, l_list);
-        // init read list if it ended already
-        if(!l_dap_db_log_list->list_read)
-            l_dap_db_log_list->list_read = l_list;
-        // set new start pos = lastitem pos + 1
-        if(l_item_count > 0)
-            l_dap_db_log_list->item_start = l_objs[l_item_count - 1].id + 1;
-        //else
-        //    l_dap_db_log_list->item_start += l_data_size_out;
-        pthread_mutex_unlock(&l_dap_db_log_list->list_mutex);
-        l_items_number += l_item_count;
-        //log_it(L_DEBUG, "loaded items n=%u/%u", l_data_size_out, l_items_number);
-        dap_store_obj_free(l_objs, l_item_count);
+        if (l_del_group_name_replace)
+            DAP_DELETE(l_del_group_name_replace);
     }
 
     pthread_mutex_lock(&l_dap_db_log_list->list_mutex);
@@ -1324,70 +214,39 @@ static void *s_list_thread_proc(void *arg)
 /**
  * instead dap_db_log_get_list()
  */
-dap_db_log_list_t* dap_db_log_list_start(uint64_t first_id, dap_list_t *a_add_groups_mask)
+dap_db_log_list_t* dap_db_log_list_start(dap_chain_node_addr_t a_addr, int a_flags)
 {
-
+#ifdef GDB_SYNC_ALWAYS_FROM_ZERO
+    a_flags |= F_DB_LOG_SYNC_FROM_ZERO;
+#endif
     //log_it(L_DEBUG, "Start loading db list_write...");
-
-    size_t l_add_groups_num = 0;// number of group
-    dap_list_t *l_add_groups_mask = a_add_groups_mask;
-    // calc l_add_groups_num
-    while(l_add_groups_mask) {
-        // не считать группы del
-        dap_list_t *l_groups = dap_chain_global_db_driver_get_groups_by_mask(l_add_groups_mask->data);
-        l_add_groups_num += dap_list_length(l_groups);
-        dap_list_free_full(l_groups, (dap_callback_destroyed_t) free);
-        l_add_groups_mask = dap_list_next(l_add_groups_mask);
+    dap_db_log_list_t *l_dap_db_log_list = DAP_NEW_Z(dap_db_log_list_t);
+    dap_list_t *l_groups_masks = dap_chain_db_get_sync_groups();
+    if (a_flags & F_DB_LOG_ADD_EXTRA_GROUPS) {
+        l_groups_masks = dap_list_concat(l_groups_masks, dap_chain_db_get_sync_extra_groups());
     }
-    if(l_add_groups_num == 0)
-        return NULL;
+    for (dap_list_t *l_cur_mask = l_groups_masks; l_cur_mask; l_cur_mask = dap_list_next(l_cur_mask)) {
+        l_dap_db_log_list->groups = dap_list_concat(l_dap_db_log_list->groups,
+                                                    dap_chain_global_db_driver_get_groups_by_mask(l_cur_mask->data));
+    }
+    dap_list_free(l_groups_masks);
 
-    size_t l_data_size_out_main = dap_db_log_get_last_id() - first_id + 1;
-            //dap_chain_global_db_driver_count(GROUP_LOCAL_HISTORY, first_id); - not working for sqlite
-    size_t *l_data_size_out_add_items = DAP_NEW_Z_SIZE(size_t, sizeof(size_t) * l_add_groups_num);
-    uint64_t *l_group_last_id = DAP_NEW_Z_SIZE(uint64_t, sizeof(uint64_t) * l_add_groups_num);
-    char **l_group_names = DAP_NEW_Z_SIZE(char*, sizeof(char*) * l_add_groups_num);
-    size_t l_data_size_out_add_items_count = 0;
-    l_add_groups_mask = a_add_groups_mask;
-    while(l_add_groups_mask){
-        dap_list_t *l_groups0 = dap_chain_global_db_driver_get_groups_by_mask(l_add_groups_mask->data);
-        dap_list_t *l_groups = l_groups0;
-        size_t l_group_cur = 0;
-        while(l_groups){
-            const char *l_group_name = (const char *) l_groups->data;
-            l_group_names[l_group_cur] = dap_strdup(dap_chain_global_db_get_history_group_by_group_name(l_group_name));
-            dap_store_obj_t *l_obj = dap_chain_global_db_driver_read_last(l_group_names[l_group_cur]);
-            if(l_obj) {
-                l_group_last_id[l_group_cur] = l_obj->id;
-                dap_store_obj_free(l_obj, 1);
-            }
-            l_data_size_out_add_items[l_group_cur] = dap_chain_global_db_driver_count(l_group_names[l_group_cur], 1);
-            l_data_size_out_add_items_count += l_data_size_out_add_items[l_group_cur];
-            l_group_cur++;
-            l_groups = dap_list_next(l_groups);
-        }
-        dap_list_free_full(l_groups0, (dap_callback_destroyed_t) free);
-        l_add_groups_mask = dap_list_next(l_add_groups_mask);
+    for (dap_list_t *l_groups = l_dap_db_log_list->groups; l_groups; l_groups = dap_list_next(l_groups)) {
+        dap_db_log_list_group_t *l_replace = DAP_NEW_Z(dap_db_log_list_group_t);
+        l_replace->name = (char *)l_groups->data;
+        if (a_flags & F_DB_LOG_SYNC_FROM_ZERO)
+            l_replace->last_id_synced = 0;
+        else
+            l_replace->last_id_synced = dap_db_get_last_id_remote(a_addr.uint64, l_replace->name);
+        l_replace->count = dap_chain_global_db_driver_count(l_replace->name, l_replace->last_id_synced + 1);
+        l_dap_db_log_list->items_number += l_replace->count;
+        l_groups->data = (void *)l_replace;
     }
-    if(!(l_data_size_out_main + l_data_size_out_add_items_count)){
-        DAP_DELETE(l_data_size_out_add_items);
-        DAP_DELETE(l_group_last_id);
-        DAP_DELETE(l_group_names);
+    l_dap_db_log_list->items_rest = l_dap_db_log_list->items_number;
+    if (!l_dap_db_log_list->items_number) {
+        DAP_DELETE(l_dap_db_log_list);
         return NULL;
     }
-    dap_db_log_list_t *l_dap_db_log_list = DAP_NEW_Z(dap_db_log_list_t);
-    l_dap_db_log_list->item_start = first_id;
-    l_dap_db_log_list->item_last = first_id + l_data_size_out_main;
-    l_dap_db_log_list->items_number_main = l_data_size_out_main;
-    l_dap_db_log_list->items_number_add = l_data_size_out_add_items_count;
-    l_dap_db_log_list->items_number = l_data_size_out_main + l_data_size_out_add_items_count;
-    l_dap_db_log_list->items_rest = l_dap_db_log_list->items_number;
-    l_dap_db_log_list->group_number = (int64_t)l_add_groups_num;
-    l_dap_db_log_list->group_number_items = l_data_size_out_add_items;
-    l_dap_db_log_list->group_last_id = l_group_last_id;
-    l_dap_db_log_list->group_names = l_group_names;
-    l_dap_db_log_list->group_cur = -1;
-    l_dap_db_log_list->add_groups = a_add_groups_mask;
     l_dap_db_log_list->is_process = true;
     pthread_mutex_init(&l_dap_db_log_list->list_mutex, NULL);
     pthread_create(&l_dap_db_log_list->thread, NULL, s_list_thread_proc, l_dap_db_log_list);
@@ -1421,7 +280,7 @@ size_t dap_db_log_list_get_count_rest(dap_db_log_list_t *a_db_log_list)
 /**
  * Get one item from log_list
  */
-dap_global_db_obj_t* dap_db_log_list_get(dap_db_log_list_t *a_db_log_list)
+dap_db_log_list_obj_t* dap_db_log_list_get(dap_db_log_list_t *a_db_log_list)
 {
     if(!a_db_log_list)
         return NULL;
@@ -1449,10 +308,17 @@ dap_global_db_obj_t* dap_db_log_list_get(dap_db_log_list_t *a_db_log_list)
             break;
     }
     //log_it(L_DEBUG, "get item n=%d", a_db_log_list->items_number - a_db_log_list->items_rest);
-    return (dap_global_db_obj_t*) l_list ? l_list->data : NULL;
+    return l_list ? (dap_db_log_list_obj_t *)l_list->data : NULL;
     //return l_list;
 }
 
+void dap_db_log_list_delete_item(void *a_item)
+{
+    dap_db_log_list_obj_t *l_list_item = (dap_db_log_list_obj_t *)a_item;
+    DAP_DELETE(l_list_item->pkt);
+    DAP_DELETE(l_list_item);
+}
+
 /**
  * Get log diff as list_write
  */
@@ -1467,13 +333,8 @@ void dap_db_log_list_delete(dap_db_log_list_t *a_db_log_list)
         pthread_mutex_unlock(&a_db_log_list->list_mutex);
         pthread_join(a_db_log_list->thread, NULL);
     }
-    for(int64_t i = 0; i < a_db_log_list->group_number; i++)
-        DAP_DELETE(a_db_log_list->group_names[i]);
-    DAP_DELETE(a_db_log_list->group_names);
-    DAP_DELETE(a_db_log_list->group_last_id);
-    DAP_DELETE(a_db_log_list->group_number_items);
-    dap_list_free(a_db_log_list->add_groups);
-    dap_list_free_full(a_db_log_list->list_write, (dap_callback_destroyed_t) dap_chain_global_db_obj_delete);
+    dap_list_free_full(a_db_log_list->groups, free);
+    dap_list_free_full(a_db_log_list->list_write, (dap_callback_destroyed_t)dap_db_log_list_delete_item);
     pthread_mutex_destroy(&a_db_log_list->list_mutex);
     DAP_DELETE(a_db_log_list);
 }
diff --git a/modules/global-db/dap_chain_global_db_remote.c b/modules/global-db/dap_chain_global_db_remote.c
index e0b3650be62a68a18ea1de4104c3a2dd06f46a5a..8075026a12d0dd7fc54ecb491d1a546d9b1b0f3d 100644
--- a/modules/global-db/dap_chain_global_db_remote.c
+++ b/modules/global-db/dap_chain_global_db_remote.c
@@ -90,7 +90,6 @@ uint64_t dap_db_get_cur_node_addr(char *a_net_name)
     time_t l_dt = time(NULL) - l_node_time;
     //NODE_TIME_EXPIRED
     if(l_node_time && l_dt > addr_time_expired) {
-        //log_it(L_NOTICE, "Node 0x%016X set last synced timestamp %"DAP_UINT64_FORMAT_U"", a_id);
         l_node_addr_ret = 0;
     }
     DAP_DELETE(l_key);
@@ -103,31 +102,33 @@ uint64_t dap_db_get_cur_node_addr(char *a_net_name)
 /**
  * Set last id for remote node
  */
-bool dap_db_set_last_id_remote(uint64_t a_node_addr, uint64_t a_id)
+bool dap_db_set_last_id_remote(uint64_t a_node_addr, uint64_t a_id, char *a_group)
 {
-    //log_it( L_DEBUG, "Node 0x%016X set last synced timestamp %"DAP_UINT64_FORMAT_U"", a_node_addr, a_id);
-    uint64_t *l_id = DAP_NEW(uint64_t);
-    *l_id = a_id;
-    return dap_chain_global_db_gr_set(dap_strdup_printf("%ju", a_node_addr),
-                                      l_id, sizeof(uint64_t),
-                                      GROUP_LOCAL_NODE_LAST_ID);
+    //log_it( L_DEBUG, "Node 0x%016X set last synced id %"DAP_UINT64_FORMAT_u"", a_node_addr, a_id);
+    char *l_node_addr_str = dap_strdup_printf("%ju%s", a_node_addr, a_group);
+    bool l_ret = dap_chain_global_db_gr_set(l_node_addr_str, &a_id, sizeof(uint64_t),
+                                            GROUP_LOCAL_NODE_LAST_ID);
+    DAP_DELETE(l_node_addr_str);
+    return l_ret;
 }
 
 /**
  * Get last id for remote node
  */
-uint64_t dap_db_get_last_id_remote(uint64_t a_node_addr)
+uint64_t dap_db_get_last_id_remote(uint64_t a_node_addr, char *a_group)
 {
-    char *l_node_addr_str = dap_strdup_printf("%ju", a_node_addr);
-    size_t l_timestamp_len = 0;
-    uint8_t *l_timestamp = dap_chain_global_db_gr_get((const char*) l_node_addr_str, &l_timestamp_len,
-    GROUP_LOCAL_NODE_LAST_ID);
-    uint64_t l_ret_timestamp = 0;
-    if(l_timestamp && l_timestamp_len == sizeof(uint64_t))
-        memcpy(&l_ret_timestamp, l_timestamp, l_timestamp_len);
+    char *l_node_addr_str = dap_strdup_printf("%ju%s", a_node_addr, a_group);
+    size_t l_id_len = 0;
+    uint8_t *l_id = dap_chain_global_db_gr_get((const char*) l_node_addr_str, &l_id_len,
+                                                GROUP_LOCAL_NODE_LAST_ID);
+    uint64_t l_ret_id = 0;
+    if (l_id) {
+        if (l_id_len == sizeof(uint64_t))
+            memcpy(&l_ret_id, l_id, l_id_len);
+        DAP_DELETE(l_id);
+    }
     DAP_DELETE(l_node_addr_str);
-    DAP_DELETE(l_timestamp);
-    return l_ret_timestamp;
+    return l_ret_id;
 }
 
 /**
@@ -152,3 +153,166 @@ dap_chain_hash_fast_t *dap_db_get_last_hash_remote(uint64_t a_node_addr, dap_cha
     DAP_DELETE(l_node_chain_str);
     return (dap_chain_hash_fast_t *)l_hash;
 }
+
+static size_t dap_db_get_size_pdap_store_obj_t(pdap_store_obj_t store_obj)
+{
+    size_t size = sizeof(uint32_t) + 2 * sizeof(uint16_t) + sizeof(time_t)
+            + 2 * sizeof(uint64_t) + dap_strlen(store_obj->group) +
+            dap_strlen(store_obj->key) + store_obj->value_len;
+    return size;
+}
+
+/**
+ * serialization
+ * @param a_old_pkt an object for multiplexation
+ * @param a_new_pkt an object for multiplexation
+ * @return NULL in case of an error
+ */
+dap_store_obj_pkt_t *dap_store_packet_multiple(dap_store_obj_pkt_t *a_old_pkt, dap_store_obj_pkt_t *a_new_pkt)
+{
+    if (!a_new_pkt)
+        return a_old_pkt;
+    if (a_old_pkt)
+        a_old_pkt = (dap_store_obj_pkt_t *)DAP_REALLOC(a_old_pkt,
+                                                       a_old_pkt->data_size + a_new_pkt->data_size + sizeof(dap_store_obj_pkt_t));
+    else
+        a_old_pkt = DAP_NEW_Z_SIZE(dap_store_obj_pkt_t, a_new_pkt->data_size + sizeof(dap_store_obj_pkt_t));
+    memcpy(a_old_pkt->data + a_old_pkt->data_size, a_new_pkt->data, a_new_pkt->data_size);
+    a_old_pkt->data_size += a_new_pkt->data_size;
+    a_old_pkt->obj_count++;
+    return a_old_pkt;
+}
+
+char *dap_store_packet_get_group(dap_store_obj_pkt_t *a_pkt)
+{
+    uint16_t l_gr_len;
+    memcpy(&l_gr_len, a_pkt->data + sizeof(uint32_t), sizeof(uint16_t));
+    char *l_ret_str = DAP_NEW_SIZE(char, l_gr_len + 1);
+    size_t l_gr_offset = sizeof(uint32_t) + sizeof(uint16_t);
+    memcpy(l_ret_str, a_pkt->data + l_gr_offset, l_gr_len);
+    l_ret_str[l_gr_len] = '\0';
+    return l_ret_str;
+}
+
+uint64_t dap_store_packet_get_id(dap_store_obj_pkt_t *a_pkt)
+{
+    uint16_t l_gr_len;
+    memcpy(&l_gr_len, a_pkt->data + sizeof(uint32_t), sizeof(uint16_t));
+    size_t l_id_offset = sizeof(uint32_t) + sizeof(uint16_t) + l_gr_len;
+    uint64_t l_ret_id;
+    memcpy(&l_ret_id, a_pkt->data + l_id_offset, sizeof(uint64_t));
+    return l_ret_id;
+}
+
+void dap_store_packet_change_id(dap_store_obj_pkt_t *a_pkt, uint64_t a_id)
+{
+    uint16_t l_gr_len;
+    memcpy(&l_gr_len, a_pkt->data + sizeof(uint32_t), sizeof(uint16_t));
+    size_t l_id_offset = sizeof(uint32_t) + sizeof(uint16_t) + l_gr_len;
+    memcpy(a_pkt->data + l_id_offset, &a_id, sizeof(uint64_t));
+}
+
+/**
+ * serialization
+ * @param a_store_obj an object for serialization
+ * @return NULL in case of an error
+ */
+dap_store_obj_pkt_t *dap_store_packet_single(pdap_store_obj_t a_store_obj)
+{
+    if (!a_store_obj)
+        return NULL;
+
+    uint32_t l_data_size_out = dap_db_get_size_pdap_store_obj_t(a_store_obj);
+    dap_store_obj_pkt_t *l_pkt = DAP_NEW_SIZE(dap_store_obj_pkt_t, l_data_size_out + sizeof(dap_store_obj_pkt_t));
+    l_pkt->data_size = l_data_size_out;
+    l_pkt->obj_count = 1;
+    l_pkt->timestamp = 0;
+    uint32_t l_type = a_store_obj->type;
+    memcpy(l_pkt->data, &l_type, sizeof(uint32_t));
+    uint64_t l_offset = sizeof(uint32_t);
+    uint16_t group_size = (uint16_t) dap_strlen(a_store_obj->group);
+    memcpy(l_pkt->data + l_offset, &group_size, sizeof(uint16_t));
+    l_offset += sizeof(uint16_t);
+    memcpy(l_pkt->data + l_offset, a_store_obj->group, group_size);
+    l_offset += group_size;
+    memcpy(l_pkt->data + l_offset, &a_store_obj->id, sizeof(uint64_t));
+    l_offset += sizeof(uint64_t);
+    memcpy(l_pkt->data + l_offset, &a_store_obj->timestamp, sizeof(time_t));
+    l_offset += sizeof(time_t);
+    uint16_t key_size = (uint16_t) dap_strlen(a_store_obj->key);
+    memcpy(l_pkt->data + l_offset, &key_size, sizeof(uint16_t));
+    l_offset += sizeof(uint16_t);
+    memcpy(l_pkt->data + l_offset, a_store_obj->key, key_size);
+    l_offset += key_size;
+    memcpy(l_pkt->data + l_offset, &a_store_obj->value_len, sizeof(uint64_t));
+    l_offset += sizeof(uint64_t);
+    memcpy(l_pkt->data + l_offset, a_store_obj->value, a_store_obj->value_len);
+    l_offset += a_store_obj->value_len;
+    assert(l_offset == l_data_size_out);
+    return l_pkt;
+}
+/**
+ * deserialization
+ * @param store_obj_count[out] count of the output structures store_obj
+ * @return NULL in case of an error*
+ */
+
+dap_store_obj_t *dap_store_unpacket_multiple(const dap_store_obj_pkt_t *pkt, size_t *store_obj_count)
+{
+    if(!pkt || pkt->data_size < 1)
+        return NULL;
+    uint64_t offset = 0;
+    uint32_t count = pkt->obj_count;
+    dap_store_obj_t *store_obj = DAP_NEW_SIZE(dap_store_obj_t, count * sizeof(struct dap_store_obj));
+    for(size_t q = 0; q < count; ++q) {
+        dap_store_obj_t *obj = store_obj + q;
+        uint16_t str_length;
+
+        uint32_t l_type;
+        if (offset+sizeof (uint32_t)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'type' field"); break;} // Check for buffer boundries
+        memcpy(&l_type, pkt->data + offset, sizeof(uint32_t));
+        obj->type = l_type;
+        offset += sizeof(uint32_t);
+
+        if (offset+sizeof (uint16_t)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'group_length' field"); break;} // Check for buffer boundries
+        memcpy(&str_length, pkt->data + offset, sizeof(uint16_t));
+        offset += sizeof(uint16_t);
+
+        if (offset+str_length> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'group' field"); break;} // Check for buffer boundries
+        obj->group = DAP_NEW_SIZE(char, str_length + 1);
+        memcpy(obj->group, pkt->data + offset, str_length);
+        obj->group[str_length] = '\0';
+        offset += str_length;
+
+        if (offset+sizeof (uint64_t)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'id' field"); break;} // Check for buffer boundries
+        memcpy(&obj->id, pkt->data + offset, sizeof(uint64_t));
+        offset += sizeof(uint64_t);
+
+        if (offset+sizeof (time_t)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'timestamp' field"); break;} // Check for buffer boundries
+        memcpy(&obj->timestamp, pkt->data + offset, sizeof(time_t));
+        offset += sizeof(time_t);
+
+        if (offset+sizeof (uint16_t)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'key_length' field"); break;} // Check for buffer boundries
+        memcpy(&str_length, pkt->data + offset, sizeof(uint16_t));
+        offset += sizeof(uint16_t);
+
+        if (offset+ str_length > pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'key' field"); break;} // Check for buffer boundries
+        obj->key = DAP_NEW_SIZE(char, str_length + 1);
+        memcpy(obj->key, pkt->data + offset, str_length);
+        obj->key[str_length] = '\0';
+        offset += str_length;
+
+        if (offset+sizeof (uint64_t)> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'value_length' field"); break;} // Check for buffer boundries
+        memcpy(&obj->value_len, pkt->data + offset, sizeof(uint64_t));
+        offset += sizeof(uint64_t);
+
+        if (offset+obj->value_len> pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'value' field"); break;} // Check for buffer boundries
+        obj->value = DAP_NEW_SIZE(uint8_t, obj->value_len);
+        memcpy(obj->value, pkt->data + offset, obj->value_len);
+        offset += obj->value_len;
+    }
+    //assert(pkt->data_size == offset);
+    if(store_obj_count)
+        *store_obj_count = count;
+    return store_obj;
+}
diff --git a/modules/global-db/include/dap_chain_global_db.h b/modules/global-db/include/dap_chain_global_db.h
index 807ca35db612f1bbdbd069b07574d06efa6e11b7..0cefa57fac338ecbf91aceb9e88f51814dd23091 100644
--- a/modules/global-db/include/dap_chain_global_db.h
+++ b/modules/global-db/include/dap_chain_global_db.h
@@ -23,9 +23,8 @@ typedef struct dap_global_db_obj {
     size_t value_len;
 }DAP_ALIGN_PACKED dap_global_db_obj_t, *pdap_global_db_obj_t;
 
-typedef void (*dap_global_db_obj_callback_notify_t) (void * a_arg, const char a_op_code, const char * a_prefix, const char * a_group,
-                                                     const char * a_key, const void * a_value,
-                                                     const size_t a_value_len);
+typedef void (*dap_global_db_obj_callback_notify_t) (void * a_arg, const char a_op_code, const char * a_group,
+                                                     const char * a_key, const void * a_value, const size_t a_value_len);
 
 /**
  * Flush DB
@@ -49,22 +48,15 @@ void dap_chain_global_db_objs_delete(dap_global_db_obj_t *objs, size_t a_count);
 int dap_chain_global_db_init(dap_config_t * a_config);
 
 void dap_chain_global_db_deinit(void);
-
-/*
- * Get history group by group name
- */
-char* dap_chain_global_db_get_history_group_by_group_name(const char * a_group_name);
-
 /**
  * Setup callbacks and filters
  */
-// Add group prefix that will be tracking all changes
-void dap_chain_global_db_add_history_group_prefix(const char * a_group_prefix, const char * a_group_name_for_history);
-void dap_chain_global_db_add_history_callback_notify(const char * a_group_prefix,
-                                                     dap_global_db_obj_callback_notify_t a_callback, void * a_arg);
-const char* dap_chain_global_db_add_history_extra_group(const char * a_group_name, dap_chain_node_addr_t *a_nodes, uint16_t *a_nodes_count);
-void dap_chain_global_db_add_history_extra_group_callback_notify(const char * a_group_prefix,
-        dap_global_db_obj_callback_notify_t a_callback, void * a_arg);
+// Add group name that will be synchronized
+void dap_chain_global_db_add_sync_group(const char *a_group_prefix, dap_global_db_obj_callback_notify_t a_callback, void *a_arg);
+void dap_chain_global_db_add_sync_extra_group(const char *a_group_mask, dap_global_db_obj_callback_notify_t a_callback, void *a_arg);
+dap_list_t *dap_chain_db_get_sync_groups();
+dap_list_t *dap_chain_db_get_sync_extra_groups();
+void dap_global_db_obj_track_history(void* a_store_data);
 /**
  * Get entry from base
  */
@@ -116,26 +108,3 @@ bool dap_chain_global_db_save(dap_global_db_obj_t* a_objs, size_t a_objs_count);
  */
 char* dap_chain_global_db_hash(const uint8_t *data, size_t data_size);
 char* dap_chain_global_db_hash_fast(const uint8_t *data, size_t data_size);
-
-// Get data according the history log
-dap_list_t* dap_db_log_pack(dap_global_db_obj_t *a_obj, size_t *a_data_size_out);
-
-// Get data according the history log
-//char* dap_db_history_tx(dap_chain_hash_fast_t * a_tx_hash, const char *a_group_mempool);
-//char* dap_db_history_addr(dap_chain_addr_t * a_addr, const char *a_group_mempool);
-//char* dap_db_history(dap_chain_addr_t * a_addr, const char *a_group_mempool);
-
-// Parse data from dap_db_log_pack()
-void* dap_db_log_unpack(const void *a_data, size_t a_data_size, size_t *a_store_obj_count);
-// Get timestamp from dap_db_log_pack()
-//time_t dap_db_log_unpack_get_timestamp(uint8_t *a_data, size_t a_data_size);
-
-// Get last id in log
-uint64_t dap_db_log_get_group_history_last_id(const char *a_history_group_name);
-uint64_t dap_db_log_get_last_id(void);
-// Get log diff as list
-dap_list_t* dap_db_log_get_list(uint64_t first_id);
-// Free list getting from dap_db_log_get_list()
-void dap_db_log_del_list(dap_list_t *a_list);
-// Get log diff as string
-char* dap_db_log_get_diff(size_t *a_data_size_out);
diff --git a/modules/global-db/include/dap_chain_global_db_driver.h b/modules/global-db/include/dap_chain_global_db_driver.h
index 4bccdc9e0905fa1ee4423aca3459065b331c29de..ecf75715ecb4423ec15d2d0cc05776b0a7b97c70 100644
--- a/modules/global-db/include/dap_chain_global_db_driver.h
+++ b/modules/global-db/include/dap_chain_global_db_driver.h
@@ -29,15 +29,12 @@
 #include "dap_common.h"
 #include "dap_list.h"
 
-#define DAP_CHAIN_PKT_EXPECT_SIZE 7168
-
 typedef struct dap_store_obj {
 	uint64_t id;
     time_t timestamp;
 	uint8_t type;
     char *group;
     char *key;
-    //const char *c_group;
     const char *c_key;
     uint8_t *value;
 	size_t value_len;
@@ -92,8 +89,3 @@ dap_store_obj_t* dap_chain_global_db_driver_read(const char *a_group, const char
 bool dap_chain_global_db_driver_is(const char *a_group, const char *a_key);
 size_t dap_chain_global_db_driver_count(const char *a_group, uint64_t id);
 dap_list_t* dap_chain_global_db_driver_get_groups_by_mask(const char *a_group_mask);
-
-dap_list_t *dap_store_packet_multiple(pdap_store_obj_t a_store_obj,
-		time_t a_timestamp, size_t a_store_obj_count);
-dap_store_obj_t *dap_store_unpacket_multiple(const dap_store_obj_pkt_t *a_pkt,
-		size_t *a_store_obj_count);
diff --git a/modules/global-db/include/dap_chain_global_db_driver_sqlite.h b/modules/global-db/include/dap_chain_global_db_driver_sqlite.h
index 2d1175df09dee149211876af69383abed045162f..7c05f5fd33c4dcb73aaae0b62baf8e06c9296202 100644
--- a/modules/global-db/include/dap_chain_global_db_driver_sqlite.h
+++ b/modules/global-db/include/dap_chain_global_db_driver_sqlite.h
@@ -50,3 +50,6 @@ int dap_db_driver_sqlite_apply_store_obj(dap_store_obj_t *a_store_obj);
 dap_store_obj_t* dap_db_driver_sqlite_read_last_store_obj(const char *a_group);
 dap_store_obj_t* dap_db_driver_sqlite_read_cond_store_obj(const char *a_group, uint64_t a_id, size_t *a_count_out);
 dap_store_obj_t* dap_db_driver_sqlite_read_store_obj(const char *a_group, const char *a_key, size_t *a_count_out);
+dap_list_t* dap_db_driver_sqlite_get_groups_by_mask(const char *a_group_mask);
+size_t dap_db_driver_sqlite_read_count_store(const char *a_group, uint64_t a_id);
+bool dap_db_driver_sqlite_is_obj(const char *a_group, const char *a_key);
diff --git a/modules/global-db/include/dap_chain_global_db_hist.h b/modules/global-db/include/dap_chain_global_db_hist.h
index f50e902c1310e08ca1eea3b87873cf6a30eea7cb..a74fe304f15609d822c33b0bdca6aff353f94339 100644
--- a/modules/global-db/include/dap_chain_global_db_hist.h
+++ b/modules/global-db/include/dap_chain_global_db_hist.h
@@ -8,6 +8,9 @@
 #define GLOBAL_DB_HIST_REC_SEPARATOR "\r;"
 #define GLOBAL_DB_HIST_KEY_SEPARATOR "\a;"
 
+#define F_DB_LOG_ADD_EXTRA_GROUPS   1
+#define F_DB_LOG_SYNC_FROM_ZERO     2
+
 typedef struct dap_global_db_hist {
     char type;// 'a' add or 'd' delete
     const char *group;
@@ -18,34 +21,36 @@ typedef struct dap_global_db_hist {
 //Add data to the history log
 bool dap_db_history_add(char a_type, pdap_store_obj_t a_store_obj, size_t a_dap_store_count, const char *a_group);
 
-// Truncate the history log
-bool dap_db_history_truncate(void);
+// for dap_db_log_list_xxx()
+
+typedef struct dap_db_log_list_group {
+    char *name;
+    uint64_t last_id_synced;
+    uint64_t count;
+} dap_db_log_list_group_t;
 
+typedef struct dap_db_log_list_obj {
+    dap_store_obj_pkt_t *pkt;
+    dap_hash_fast_t hash;
+} dap_db_log_list_obj_t;
 
-// for dap_db_log_list_xxx()
 typedef struct dap_db_log_list {
     dap_list_t *list_write; // writed list
     dap_list_t *list_read; // readed list (inside list_write)
     bool is_process;
-    size_t item_start; // first item to read from db
-    size_t item_last; // last item to read from db
     size_t items_rest; // rest items to read from list_read
-    size_t items_number_main;
-    size_t items_number_add;
-    size_t items_number; // remaining items in list_write after reading from db
-    char **group_names;
-    int64_t group_number; // number of group
-    int64_t group_cur; // current group number, -1 for the main group, 0 ... group_count for the additional group
-    size_t *group_number_items; // number of items for each group
-    uint64_t *group_last_id;
-    dap_list_t *add_groups; // additional group for sync
+    size_t items_number; // total items in list_write after reading from db
+    dap_list_t *groups;
     pthread_t thread;
     pthread_mutex_t list_mutex;
 } dap_db_log_list_t;
 
-dap_db_log_list_t* dap_db_log_list_start(uint64_t first_id, dap_list_t *a_add_groups);
+dap_db_log_list_t* dap_db_log_list_start(dap_chain_node_addr_t a_addr, int flags);
 size_t dap_db_log_list_get_count(dap_db_log_list_t *a_db_log_list);
 size_t dap_db_log_list_get_count_rest(dap_db_log_list_t *a_db_log_list);
-dap_global_db_obj_t* dap_db_log_list_get(dap_db_log_list_t *a_db_log_list);
+dap_db_log_list_obj_t *dap_db_log_list_get(dap_db_log_list_t *a_db_log_list);
 void dap_db_log_list_delete(dap_db_log_list_t *a_db_log_list);
+// Get last id in log
+uint64_t dap_db_log_get_group_last_id(const char *a_group_name);
+uint64_t dap_db_log_get_last_id(void);
 
diff --git a/modules/global-db/include/dap_chain_global_db_remote.h b/modules/global-db/include/dap_chain_global_db_remote.h
index 7a58f3b1e4a56b2c1eeac90ef15335a0de8c0c59..7e63ac02b733e85c6f07e49433e403065908a176 100644
--- a/modules/global-db/include/dap_chain_global_db_remote.h
+++ b/modules/global-db/include/dap_chain_global_db_remote.h
@@ -4,16 +4,24 @@
 #include <time.h>
 #include "dap_chain.h"
 #include "dap_chain_common.h"
+#include "dap_chain_global_db_driver.h"
 // Set addr for current node
 bool dap_db_set_cur_node_addr(uint64_t a_address, char *a_net_name);
 bool dap_db_set_cur_node_addr_exp(uint64_t a_address, char *a_net_name );
 uint64_t dap_db_get_cur_node_addr(char *a_net_name);
 
 // Set last id for remote node
-bool dap_db_set_last_id_remote(uint64_t a_node_addr, uint64_t a_id);
+bool dap_db_set_last_id_remote(uint64_t a_node_addr, uint64_t a_id, char *a_group);
 // Get last id for remote node
-uint64_t dap_db_get_last_id_remote(uint64_t a_node_addr);
+uint64_t dap_db_get_last_id_remote(uint64_t a_node_addr, char *a_group);
 // Set last hash for chain for remote node
 bool dap_db_set_last_hash_remote(uint64_t a_node_addr, dap_chain_t *a_chain, dap_chain_hash_fast_t *a_hash);
 // Get last hash for chain for remote node
 dap_chain_hash_fast_t *dap_db_get_last_hash_remote(uint64_t a_node_addr, dap_chain_t *a_chain);
+
+dap_store_obj_pkt_t *dap_store_packet_single(pdap_store_obj_t a_store_obj);
+dap_store_obj_pkt_t *dap_store_packet_multiple(dap_store_obj_pkt_t *a_old_pkt, dap_store_obj_pkt_t *a_new_pkt);
+dap_store_obj_t *dap_store_unpacket_multiple(const dap_store_obj_pkt_t *a_pkt, size_t *a_store_obj_count);
+char *dap_store_packet_get_group(dap_store_obj_pkt_t *a_pkt);
+uint64_t dap_store_packet_get_id(dap_store_obj_pkt_t *a_pkt);
+void dap_store_packet_change_id(dap_store_obj_pkt_t *a_pkt, uint64_t a_id);
diff --git a/modules/net/CMakeLists.txt b/modules/net/CMakeLists.txt
index 4085114464c3c8402f4581a3bc27ad5551eb0b02..4c05cea61e5af5c5a8710ee0c20c5a9904af0c74 100644
--- a/modules/net/CMakeLists.txt
+++ b/modules/net/CMakeLists.txt
@@ -37,7 +37,7 @@ endif()
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRCS} ${DAP_CHAIN_NET_HEADERS} ${IPUTILS_SRCS} ${IPUTILS_HEADERS})
 
 if(WIN32)
-  target_link_libraries(dap_core dap_chain_net dap_crypto dap_client dap_server_core dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_chain dap_chain_wallet dap_chain_net_srv
+  target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_client dap_server_core dap_notify_srv dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_chain dap_chain_wallet dap_chain_net_srv
                             dap_chain_mempool dap_chain_global_db dap_chain_cs_none)
 endif()
 
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 90e3433e548957359715adaf185a5c7bdb97b80a..1d26565b6d0d7327d4b3f1e2271dbcfbcf744842 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -241,7 +241,7 @@ static void s_net_proc_kill( dap_chain_net_t * a_net );
 int s_net_load(const char * a_net_name, uint16_t a_acl_idx);
 
 // Notify callback for GlobalDB changes
-static void s_gbd_history_callback_notify (void * a_arg,const char a_op_code, const char * a_prefix, const char * a_group,
+static void s_gbd_history_callback_notify (void * a_arg, const char a_op_code, const char * a_group,
                                                      const char * a_key, const void * a_value,
                                                      const size_t a_value_len);
 static void s_chain_callback_notify(void * a_arg, dap_chain_t *a_chain, dap_chain_cell_id_t a_id, void *a_atom, size_t a_atom_size);
@@ -296,6 +296,7 @@ int dap_chain_net_state_go_to(dap_chain_net_t * a_net, dap_chain_net_state_t a_n
     pthread_mutex_lock( &PVT(a_net)->state_mutex_cond); // Preventing call of state_go_to before wait cond will be armed
     // set flag for sync
     PVT(a_net)->flags |= F_DAP_CHAIN_NET_GO_SYNC;
+    //PVT(a_net)->flags |= F_DAP_CHAIN_NET_SYNC_FROM_ZERO;
 #ifndef _WIN32
     pthread_cond_signal( &PVT(a_net)->state_proc_cond );
 #else
@@ -312,10 +313,10 @@ void dap_chain_net_set_srv_callback_notify(dap_global_db_obj_callback_notify_t a
     s_srv_callback_notify = a_callback;
 }
 
-void dap_chain_net_sync_gdb_broadcast(void *a_arg, const char a_op_code, const char *a_prefix, const char *a_group,
+void dap_chain_net_sync_gdb_broadcast(void *a_arg, const char a_op_code, const char *a_group,
                                       const char *a_key, const void *a_value, const size_t a_value_len)
 {
-    UNUSED(a_prefix);
+    UNUSED(a_value);
     UNUSED(a_value_len);
     dap_chain_net_t *l_net = (dap_chain_net_t *)a_arg;
     if (PVT(l_net)->state == NET_STATE_ONLINE) {
@@ -336,9 +337,7 @@ void dap_chain_net_sync_gdb_broadcast(void *a_arg, const char a_op_code, const c
         l_obj->type = (uint8_t)a_op_code;
         DAP_DELETE(l_obj->group);
         l_obj->group = dap_strdup(a_group);
-        dap_list_t *l_list_out = dap_store_packet_multiple(l_obj, l_obj->timestamp, 1);
-        // Expect only one element in list
-        dap_store_obj_pkt_t *l_data_out = (dap_store_obj_pkt_t *)l_list_out->data;
+        dap_store_obj_pkt_t *l_data_out = dap_store_packet_single(l_obj);
         dap_store_obj_free(l_obj, 1);
         dap_chain_t *l_chain = dap_chain_net_get_chain_by_name(l_net, "gdb");
         dap_chain_id_t l_chain_id = l_chain ? l_chain->id : (dap_chain_id_t) {};
@@ -350,7 +349,7 @@ void dap_chain_net_sync_gdb_broadcast(void *a_arg, const char a_op_code, const c
                                                  sizeof(dap_store_obj_pkt_t) + l_data_out->data_size);
         }
         pthread_rwlock_unlock(&PVT(l_net)->rwlock);
-        dap_list_free_full(l_list_out, free);
+        DAP_DELETE(l_data_out);
     }
 }
 
@@ -364,16 +363,16 @@ void dap_chain_net_sync_gdb_broadcast(void *a_arg, const char a_op_code, const c
  * @param a_value
  * @param a_value_len
  */
-static void s_gbd_history_callback_notify (void * a_arg, const char a_op_code, const char * a_prefix, const char * a_group,
+static void s_gbd_history_callback_notify (void * a_arg, const char a_op_code, const char * a_group,
                                                      const char * a_key, const void * a_value, const size_t a_value_len)
 {
     if (!a_arg) {
         return;
     }
-    dap_chain_node_mempool_autoproc_notify(a_arg, a_op_code, a_prefix, a_group, a_key, a_value, a_value_len);
-    dap_chain_net_sync_gdb_broadcast(a_arg, a_op_code, a_prefix, a_group, a_key, a_value, a_value_len);
+    dap_chain_node_mempool_autoproc_notify(a_arg, a_op_code, a_group, a_key, a_value, a_value_len);
+    dap_chain_net_sync_gdb_broadcast(a_arg, a_op_code, a_group, a_key, a_value, a_value_len);
     if (s_srv_callback_notify) {
-        s_srv_callback_notify(a_arg, a_op_code, a_prefix, a_group, a_key, a_value, a_value_len);
+        s_srv_callback_notify(a_arg, a_op_code, a_group, a_key, a_value, a_value_len);
     }
 }
 
@@ -445,9 +444,6 @@ static void s_node_link_callback_connected(dap_chain_node_client_t * a_node_clie
 {
     dap_chain_net_t * l_net = (dap_chain_net_t *) a_arg;
     dap_chain_net_pvt_t * l_net_pvt = PVT(l_net);
-    dap_chain_node_info_t * l_link_info = a_node_client->info;
-
-
 
     a_node_client->stream_worker = dap_client_get_stream_worker(a_node_client->client);
     if(a_node_client->stream_worker == NULL){
@@ -456,8 +452,7 @@ static void s_node_link_callback_connected(dap_chain_node_client_t * a_node_clie
         return;
     }
 
-    a_node_client->state = NODE_CLIENT_STATE_ESTABLISHED;
-
+    a_node_client->resync_gdb = l_net_pvt->flags & F_DAP_CHAIN_NET_SYNC_FROM_ZERO;
     if( !a_node_client->is_reconnecting || s_debug_more )
         log_it(L_NOTICE, "Established connection with %s."NODE_ADDR_FP_STR,l_net->pub.name,
                NODE_ADDR_FP_ARGS_S(a_node_client->remote_node_addr));
@@ -466,32 +461,6 @@ static void s_node_link_callback_connected(dap_chain_node_client_t * a_node_clie
     l_net_pvt->links_connected_count++;
     s_net_links_notify(l_net);
 
-    // If we're fist time here - initiate the GDB sync
-    if (! a_node_client->is_reconnecting){
-        dap_stream_ch_chain_sync_request_t l_sync_gdb = {};
-        // Get last timestamp in log if wasn't SYNC_FROM_ZERO flag
-        if (! (l_net_pvt->flags & F_DAP_CHAIN_NET_SYNC_FROM_ZERO) )
-            l_sync_gdb.id_start = (uint64_t) dap_db_get_last_id_remote(a_node_client->remote_node_addr.uint64);
-        l_sync_gdb.node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
-        log_it(L_DEBUG, "Prepared request to gdb sync from %"DAP_UINT64_FORMAT_U" to %"DAP_UINT64_FORMAT_U"", l_sync_gdb.id_start, l_sync_gdb.id_end?l_sync_gdb.id_end:-1 );
-        // find dap_chain_id_t
-        dap_chain_t *l_chain = l_net->pub.chains;
-        dap_chain_id_t l_chain_id = l_chain ? l_chain->id : (dap_chain_id_t ) {0};
-
-        a_node_client->ch_chain = dap_client_get_stream_ch_unsafe(a_node_client->client,dap_stream_ch_chain_get_id() );
-        if (a_node_client->ch_chain)
-            a_node_client->ch_chain_uuid = a_node_client->ch_chain->uuid;
-
-        a_node_client->ch_chain_net = dap_client_get_stream_ch_unsafe(a_node_client->client,dap_stream_ch_chain_get_id() );
-        if(a_node_client->ch_chain_net)
-            a_node_client->ch_chain_net_uuid = a_node_client->ch_chain_net->uuid;
-
-        dap_stream_ch_chain_pkt_write_unsafe( a_node_client->ch_chain ,
-                                                           DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_REQ, l_net->pub.id.uint64,
-                                                        l_chain_id.uint64, l_net->pub.cell_id.uint64, &l_sync_gdb, sizeof(l_sync_gdb));
-    }
-    a_node_client->is_reconnecting = false;
-
     if(l_net_pvt->state == NET_STATE_LINKS_CONNECTING ){
         l_net_pvt->state = NET_STATE_LINKS_ESTABLISHED;
         dap_proc_queue_add_callback_inter(a_node_client->stream_worker->worker->proc_queue_input,s_net_states_proc,l_net );
@@ -1106,9 +1075,6 @@ int dap_chain_net_init()
         "net -net <chain net name> ledger reload\n"
             "\tPurge the cache of chain net ledger and recalculate it from chain file\n"                                        );
     s_seed_mode = dap_config_get_item_bool_default(g_config,"general","seed_mode",false);
-    dap_chain_global_db_add_history_group_prefix("global", GROUP_LOCAL_HISTORY);
-
-    dap_chain_global_db_add_history_callback_notify("global", s_gbd_history_callback_notify, NULL );
 
     // maximum number of connections to other nodes
     s_max_links_count = dap_config_get_item_int32_default(g_config, "general", "max_links", s_max_links_count);
@@ -1216,7 +1182,7 @@ static int s_cli_net( int argc, char **argv, void *arg_func, char **a_str_reply)
     // command 'list'
     const char * l_list_cmd = NULL;
 
-    if(dap_chain_node_cli_find_option_val(argv, arg_index, argc, "list", &l_list_cmd) != 0) {
+    if(dap_chain_node_cli_find_option_val(argv, arg_index, argc, "list", &l_list_cmd) != 0 ) {
         dap_string_t *l_string_ret = dap_string_new("");
         if (dap_strcmp(l_list_cmd,"chains")==0){
             const char * l_net_str = NULL;
@@ -1630,13 +1596,13 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
         l_net->pub.gdb_groups_prefix = dap_strdup (
                     dap_config_get_item_str_default(l_cfg , "general" , "gdb_groups_prefix",
                                                     dap_config_get_item_str(l_cfg , "general" , "name" ) ) );
-        dap_chain_global_db_add_history_group_prefix( l_net->pub.gdb_groups_prefix, GROUP_LOCAL_HISTORY);
-        dap_chain_global_db_add_history_callback_notify(l_net->pub.gdb_groups_prefix, s_gbd_history_callback_notify, l_net );
+        dap_chain_global_db_add_sync_group("global", s_gbd_history_callback_notify, l_net);
+        dap_chain_global_db_add_sync_group(l_net->pub.gdb_groups_prefix, s_gbd_history_callback_notify, l_net);
 
         l_net->pub.gdb_nodes = dap_strdup_printf("%s.nodes",l_net->pub.gdb_groups_prefix);
         l_net->pub.gdb_nodes_aliases = dap_strdup_printf("%s.nodes.aliases",l_net->pub.gdb_groups_prefix);
 
-        // for sync special groups - nodes
+        // nodes for special sync
         char **l_gdb_sync_nodes_addrs = dap_config_get_array_str(l_cfg, "general", "gdb_sync_nodes_addrs",
                 &l_net_pvt->gdb_sync_nodes_addrs_count);
         if(l_gdb_sync_nodes_addrs && l_net_pvt->gdb_sync_nodes_addrs_count > 0) {
@@ -1646,37 +1612,13 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
                 dap_chain_node_addr_from_str(l_net_pvt->gdb_sync_nodes_addrs + i, l_gdb_sync_nodes_addrs[i]);
             }
         }
-        // for sync special groups - groups
-        char **l_gdb_sync_groups = dap_config_get_array_str(l_cfg, "general", "gdb_sync_groups", &l_net_pvt->gdb_sync_groups_count);
-        if(l_gdb_sync_groups && l_net_pvt->gdb_sync_groups_count > 0) {
-            l_net_pvt->gdb_sync_groups = (char **) DAP_NEW_SIZE(char**, sizeof(char*)*l_net_pvt->gdb_sync_groups_count);
-            for(uint16_t i = 0; i < l_net_pvt->gdb_sync_groups_count; i++) {
-                l_net_pvt->gdb_sync_groups[i] = dap_strdup(l_gdb_sync_groups[i]);
-                // added group to history log
-                dap_list_t *l_groups0 = dap_chain_global_db_driver_get_groups_by_mask(l_net_pvt->gdb_sync_groups[i]);
-                dap_list_t *l_groups = l_groups0;
-                while(l_groups) {
-                    char *l_group_name = l_groups->data;
-                    // do not use groups with names like *.del
-                    if(dap_fnmatch("*.del", l_group_name, 0)) {
-                        const char *l_history_group = dap_chain_global_db_add_history_extra_group(l_group_name,
-                                                        l_net_pvt->gdb_sync_nodes_addrs,
-                                                        &l_net_pvt->gdb_sync_nodes_addrs_count);
-                        dap_chain_global_db_add_history_extra_group_callback_notify(l_group_name,
-                                s_gbd_history_callback_notify, l_net);
-                        // create history for group
-                        if(dap_db_log_get_group_history_last_id(l_history_group) <= 0) {
-                            size_t l_data_size_out = 0;
-                            dap_store_obj_t *l_obj = dap_chain_global_db_obj_gr_get(NULL, &l_data_size_out, l_group_name);
-                            if(l_obj && l_data_size_out > 0) {
-                                dap_db_history_add('a', l_obj, l_data_size_out, l_history_group);
-                                dap_store_obj_free(l_obj, l_data_size_out);
-                            }
-                        }
-                    }
-                    l_groups = dap_list_next(l_groups);
-                }
-                dap_list_free_full(l_groups0, (dap_callback_destroyed_t)free);
+        // groups for special sync
+        uint16_t l_gdb_sync_groups_count;
+        char **l_gdb_sync_groups = dap_config_get_array_str(l_cfg, "general", "gdb_sync_groups", &l_gdb_sync_groups_count);
+        if (l_gdb_sync_groups && l_gdb_sync_groups_count > 0) {
+            for(uint16_t i = 0; i < l_gdb_sync_groups_count; i++) {
+                // add group to special sync
+                dap_chain_global_db_add_sync_extra_group(l_gdb_sync_groups[i], s_gbd_history_callback_notify, l_net);
             }
         }
 
@@ -2383,7 +2325,7 @@ dap_list_t* dap_chain_net_get_node_list(dap_chain_net_t * l_net)
  * @param a_net
  * @param a_flag_sync_from_zero
  */
-void dap_chain_net_set_flag_sync_from_zero( dap_chain_net_t * a_net, bool a_flag_sync_from_zero)
+void dap_chain_net_set_flag_sync_from_zero(dap_chain_net_t * a_net, bool a_flag_sync_from_zero)
 {
     if( a_flag_sync_from_zero)
         PVT(a_net)->flags |= F_DAP_CHAIN_NET_SYNC_FROM_ZERO;
@@ -2519,18 +2461,16 @@ dap_chain_datum_tx_t * dap_chain_net_get_tx_by_hash(dap_chain_net_t * a_net, dap
  * @param a_node_addr
  * @return
  */
-dap_list_t * dap_chain_net_get_add_gdb_group(dap_chain_net_t * a_net, dap_chain_node_addr_t a_node_addr)
+bool dap_chain_net_get_add_gdb_group(dap_chain_net_t *a_net, dap_chain_node_addr_t a_node_addr)
 {
-    dap_list_t *l_list_groups = NULL;
     if(!a_net || !PVT(a_net) || !PVT(a_net)->gdb_sync_nodes_addrs)
-        return NULL;
+        return false;
     for(uint16_t i = 0; i < PVT(a_net)->gdb_sync_nodes_addrs_count; i++) {
         if(a_node_addr.uint64 == PVT(a_net)->gdb_sync_nodes_addrs[i].uint64) {
-            for(uint16_t j = 0; j < PVT(a_net)->gdb_sync_groups_count; j++)
-                l_list_groups = dap_list_append(l_list_groups, PVT(a_net)->gdb_sync_groups[j]);
+            return true;
         }
     }
-    return l_list_groups;
+    return false;
 }
 
 /**
diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c
index 5f9ac6fcd097343d087d8fd996dec54b8d70977a..817455ff9e922ce73b65281a17ff5d93668e425a 100644
--- a/modules/net/dap_chain_node.c
+++ b/modules/net/dap_chain_node.c
@@ -323,10 +323,9 @@ void dap_chain_node_mempool_autoproc_deinit()
     s_mempool_auto = false;
 }
 
-void dap_chain_node_mempool_autoproc_notify(void *a_arg, const char a_op_code, const char *a_prefix, const char *a_group,
+void dap_chain_node_mempool_autoproc_notify(void *a_arg, const char a_op_code, const char *a_group,
                                              const char *a_key, const void *a_value, const size_t a_value_len)
 {
-    UNUSED(a_prefix);
     UNUSED(a_value_len);
     if (!a_arg || !a_value || !s_mempool_auto || a_op_code != 'a') {
         return;
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 4453a28d30dd2c478a551d7d2d64653ec8b9dd0a..bdb5a2e59ddebf06ae084f86fdf55b2d4cbc4339 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -1053,7 +1053,7 @@ int com_node(int a_argc, char ** a_argv, void *arg_func, char **a_str_reply)
         dap_stream_ch_chain_sync_request_t l_sync_request = { { 0 } };
          dap_stream_ch_t * l_ch_chain = dap_client_get_stream_ch_unsafe(l_node_client->client, dap_stream_ch_chain_get_id());
          // fill begin id
-         l_sync_request.id_start = dap_db_get_last_id_remote(l_remote_node_info->hdr.address.uint64);
+         l_sync_request.id_start = 1;
          // fill current node address
          l_sync_request.node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
 
diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c
index 85116dd2e4034a69dc1c5a91613b736b0b4eac21..59e71bf6363bbf1319e2c8cdc7c6cdf70aa150e7 100644
--- a/modules/net/dap_chain_node_client.c
+++ b/modules/net/dap_chain_node_client.c
@@ -84,11 +84,10 @@ typedef struct dap_chain_node_client_handle {
 
 static dap_chain_node_client_handle_t * s_clients = NULL;
 
-
 //static int listen_port_tcp = 8079;
 
 static void s_stage_connected_callback(dap_client_t *a_client, void *a_arg);
-static bool s_timer_update_states_callback(void * a_arg );
+static bool s_timer_update_states_callback(void *a_arg);
 
 static void s_ch_chain_callback_notify_packet_out(dap_stream_ch_chain_t*, uint8_t a_pkt_type,
         dap_stream_ch_chain_pkt_t *a_pkt, size_t a_pkt_data_size,
@@ -165,7 +164,9 @@ static void s_stage_status_error_callback(dap_client_t *a_client, void *a_arg)
         pthread_mutex_unlock(&l_node_client->wait_mutex);
         l_node_client->esocket_uuid = 0;
 
-        if (l_node_client->keep_connection) {
+        if (l_node_client->callbacks.disconnected) {
+            l_node_client->callbacks.disconnected(l_node_client, l_node_client->callbacks_arg);
+        } else if (l_node_client->keep_connection) {
             dap_events_socket_uuid_t *l_uuid = DAP_NEW(dap_events_socket_uuid_t);
             memcpy(l_uuid, &l_node_client->uuid, sizeof(dap_events_socket_uuid_t));
             dap_timerfd_start_on_worker(l_node_client->stream_worker? l_node_client->stream_worker->worker: dap_events_worker_get_auto(),s_timer_update_states*1000,s_timer_update_states_callback, l_uuid);
@@ -177,12 +178,19 @@ static void s_stage_status_error_callback(dap_client_t *a_client, void *a_arg)
         l_node_client->callbacks.error(l_node_client, EINVAL,l_node_client->callbacks_arg );
 }
 
+static void s_node_client_connected_synchro_start_callback(dap_worker_t *a_worker, void *a_arg)
+{
+    UNUSED(a_worker);
+    if (s_timer_update_states_callback(a_arg))
+        DAP_DELETE(a_arg);
+}
+
 /**
  * @brief s_timer_update_states_callback
  * @param a_arg
  * @return
  */
-static bool s_timer_update_states_callback(void * a_arg )
+static bool s_timer_update_states_callback(void *a_arg)
 {
     dap_chain_node_client_handle_t *l_client_found = NULL;
     dap_events_socket_uuid_t *l_uuid = (dap_events_socket_uuid_t *)a_arg;
@@ -201,7 +209,7 @@ static bool s_timer_update_states_callback(void * a_arg )
     dap_events_socket_t * l_es = NULL;
     dap_events_socket_uuid_t l_es_uuid = l_me->esocket_uuid;
     // check if esocket still in worker
-    if( (l_es = dap_worker_esocket_find_uuid(l_worker, l_es_uuid)) != NULL ){
+    if( (l_es = dap_worker_esocket_find_uuid(l_worker, l_es_uuid)) != NULL ) {
         dap_client_t * l_client = dap_client_from_esocket(l_es);
         if (l_client ) {
             dap_chain_node_client_t * l_node_client = (dap_chain_node_client_t*) l_client->_inheritor;
@@ -212,27 +220,21 @@ static bool s_timer_update_states_callback(void * a_arg )
                     assert(l_ch_chain);
                     dap_chain_net_t * l_net = l_node_client->net;
                     assert(l_net);
-
                     // If we do nothing - init sync process
                     if (l_ch_chain->state == CHAIN_STATE_IDLE ||l_ch_chain->state == CHAIN_STATE_SYNC_ALL ){
+                        log_it(L_INFO, "Start synchronization process with "NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(l_node_client->remote_node_addr));
                         dap_stream_ch_chain_sync_request_t l_sync_gdb = {};
-                        l_sync_gdb.id_start = (uint64_t) dap_db_get_last_id_remote(l_node_client->remote_node_addr.uint64);
                         l_sync_gdb.node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
-                        log_it(L_DEBUG, "Prepared request to gdb sync from %"DAP_UINT64_FORMAT_U" to %"DAP_UINT64_FORMAT_U"", l_sync_gdb.id_start,
-                               l_sync_gdb.id_end?l_sync_gdb.id_end:-1 );
-                        // find dap_chain_id_t
-                        dap_chain_t *l_chain = l_net->pub.chains;
-                        dap_chain_id_t l_chain_id = l_chain ? l_chain->id : (dap_chain_id_t ) {0};
-                        dap_stream_ch_chain_pkt_write_unsafe( l_node_client->ch_chain ,
-                                                          DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_REQ, l_net->pub.id.uint64,
-                                                                        l_chain_id.uint64, l_net->pub.cell_id.uint64,
-                                                              &l_sync_gdb, sizeof(l_sync_gdb));
+                        dap_stream_ch_chain_pkt_write_unsafe(l_node_client->ch_chain, DAP_STREAM_CH_CHAIN_PKT_TYPE_UPDATE_GLOBAL_DB_REQ,
+                                                             l_net->pub.id.uint64, 0, l_net->pub.cell_id.uint64,
+                                                             &l_sync_gdb, sizeof(l_sync_gdb));
                     }
                     return true;
                 }
             }
         }
     }
+
     // if we not returned yet
     l_me->state = NODE_CLIENT_STATE_DISCONNECTED;
     if (l_me->keep_connection) {
@@ -277,8 +279,11 @@ static void s_stage_connected_callback(dap_client_t *a_client, void *a_arg)
             l_node_client->stream_worker = l_stream->stream_worker;
             if (l_node_client->keep_connection) {
                 dap_events_socket_uuid_t *l_uuid = DAP_NEW(dap_events_socket_uuid_t);
-                memcpy(l_uuid, &l_node_client->uuid, sizeof(dap_events_socket_uuid_t));
-                dap_timerfd_start_on_worker(l_stream->esocket->worker,s_timer_update_states*1000,s_timer_update_states_callback, l_uuid);
+                DAP_DUP(l_uuid, &l_node_client->uuid);
+                dap_worker_exec_callback_on(l_stream->esocket->worker, s_node_client_connected_synchro_start_callback, l_uuid);
+                dap_events_socket_uuid_t *l_uuid_timer = DAP_NEW(dap_events_socket_uuid_t);
+                DAP_DUP(l_uuid_timer, &l_node_client->uuid);
+                dap_timerfd_start_on_worker(l_stream->esocket->worker, s_timer_update_states * 1000, s_timer_update_states_callback, l_uuid_timer);
             }
         }
 #ifndef _WIN32
@@ -595,13 +600,14 @@ dap_chain_node_client_t* dap_chain_node_client_create_n_connect(dap_chain_net_t
         return NULL;
     }
     dap_chain_node_client_t *l_node_client = DAP_NEW_Z(dap_chain_node_client_t);
+
     l_node_client->state = NODE_CLIENT_STATE_DISCONNECTED;
     l_node_client->callbacks_arg = a_callback_arg;
     if(a_callbacks)
         memcpy(&l_node_client->callbacks,a_callbacks,sizeof (*a_callbacks));
     l_node_client->info = a_node_info;
+    l_node_client->uuid = dap_uuid_generate_uint64();
     l_node_client->net = a_net;
-    l_node_client->uuid = dap_uuid_generate_uint128();
     dap_chain_node_client_handle_t * l_client_handle = DAP_NEW_Z(dap_chain_node_client_handle_t);
     l_client_handle->uuid = l_node_client->uuid;
     l_client_handle->client = l_node_client;
@@ -655,9 +661,6 @@ static bool dap_chain_node_client_connect_internal(dap_chain_node_client_t *a_no
         return false;
     }
     dap_client_set_uplink_unsafe(a_node_client->client, strdup(host), a_node_client->info->hdr.ext_port);
-//    dap_client_stage_t a_stage_target = STAGE_ENC_INIT;
-//    dap_client_stage_t l_stage_target = STAGE_STREAM_STREAMING;
-
     a_node_client->state = NODE_CLIENT_STATE_CONNECTING ;
     // ref pvt client
     //dap_client_pvt_ref(DAP_CLIENT_PVT(a_node_client->client));
@@ -832,6 +835,7 @@ int dap_chain_node_client_set_callbacks(dap_client_t *a_client, uint8_t a_ch_id)
                 l_ch_chain->callback_notify_packet_out = s_ch_chain_callback_notify_packet_out;
                 l_ch_chain->callback_notify_packet_in = s_ch_chain_callback_notify_packet_in;
                 l_ch_chain->callback_notify_arg = l_node_client;
+                l_node_client->ch_chain = l_ch;
                 memcpy(&l_node_client->ch_chain_uuid, &l_ch->uuid, sizeof(dap_stream_ch_uuid_t));
             }
             // N
@@ -839,6 +843,7 @@ int dap_chain_node_client_set_callbacks(dap_client_t *a_client, uint8_t a_ch_id)
                 dap_stream_ch_chain_net_t *l_ch_chain = DAP_STREAM_CH_CHAIN_NET(l_ch);
                 l_ch_chain->notify_callback = s_ch_chain_callback_notify_packet_in2;
                 l_ch_chain->notify_callback_arg = l_node_client;
+                l_node_client->ch_chain_net = l_ch;
                 memcpy(&l_node_client->ch_chain_net_uuid, &l_ch->uuid, sizeof(dap_stream_ch_uuid_t));
             }
             // R
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index 7f59409edf8f0064568b68497f8dcbe2d7fa4d68..ad6475656fd92064aedf39b4d6575657eeec38b8 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -115,7 +115,7 @@ static inline const char * dap_chain_net_state_to_str(dap_chain_net_state_t a_st
 
 void dap_chain_net_delete( dap_chain_net_t * a_net);
 void dap_chain_net_proc_mempool (dap_chain_net_t * a_net);
-void dap_chain_net_set_flag_sync_from_zero( dap_chain_net_t * a_net, bool a_flag_sync_from_zero);
+void dap_chain_net_set_flag_sync_from_zero(dap_chain_net_t * a_net, bool a_flag_sync_from_zero);
 bool dap_chain_net_get_flag_sync_from_zero( dap_chain_net_t * a_net);
 
 
@@ -170,12 +170,12 @@ DAP_STATIC_INLINE char * dap_chain_net_get_gdb_group_mempool(dap_chain_t * l_cha
 dap_chain_t * dap_chain_net_get_chain_by_chain_type(dap_chain_net_t * l_net, dap_chain_type_t a_datum_type);
 char * dap_chain_net_get_gdb_group_mempool_by_chain_type(dap_chain_net_t * l_net, dap_chain_type_t a_datum_type);
 dap_chain_net_t **dap_chain_net_list(uint16_t *a_size);
-dap_list_t * dap_chain_net_get_add_gdb_group(dap_chain_net_t * a_net, dap_chain_node_addr_t a_node_addr);
+bool dap_chain_net_get_add_gdb_group(dap_chain_net_t *a_net, dap_chain_node_addr_t a_node_addr);
 
 int dap_chain_net_verify_datum_for_add(dap_chain_net_t *a_net, dap_chain_datum_t * a_datum );
 void dap_chain_net_dump_datum(dap_string_t * a_str_out, dap_chain_datum_t * a_datum, const char *a_hash_out_type);
 void dap_chain_net_set_srv_callback_notify(dap_global_db_obj_callback_notify_t a_callback);
-void dap_chain_net_sync_gdb_broadcast(void *a_arg, const char a_op_code, const char *a_prefix, const char *a_group,
+void dap_chain_net_sync_gdb_broadcast(void *a_arg, const char a_op_code, const char *a_group,
                                       const char *a_key, const void *a_value, const size_t a_value_len);
 
 struct dap_chain_node_client * dap_chain_net_client_create_n_connect( dap_chain_net_t * a_net, struct dap_chain_node_info *a_link_info);
diff --git a/modules/net/include/dap_chain_node.h b/modules/net/include/dap_chain_node.h
index 4bfc7f23c1f150d29d4afb76aaa283bb2131f1f9..9d84beabcc2a289a3024f185ffea98de15c43d8a 100644
--- a/modules/net/include/dap_chain_node.h
+++ b/modules/net/include/dap_chain_node.h
@@ -147,6 +147,6 @@ inline static char* dap_chain_node_addr_to_hash_str(dap_chain_node_addr_t *addre
 bool dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_node_role_t a_role, dap_chain_datum_t *a_datum);
 bool dap_chain_node_mempool_autoproc_init();
 void dap_chain_node_mempool_autoproc_deinit();
-void dap_chain_node_mempool_autoproc_notify(void *a_arg, const char a_op_code, const char *a_prefix, const char *a_group,
+void dap_chain_node_mempool_autoproc_notify(void *a_arg, const char a_op_code, const char *a_group,
                                              const char *a_key, const void *a_value, const size_t a_value_len);
 
diff --git a/modules/net/include/dap_chain_node_client.h b/modules/net/include/dap_chain_node_client.h
index ca18108812d5b57e3f4f9e0f030ea68b80273ea2..92a7ba56d3479fbf01a31fe3d3ea3f0b78142ec2 100644
--- a/modules/net/include/dap_chain_node_client.h
+++ b/modules/net/include/dap_chain_node_client.h
@@ -66,10 +66,10 @@ typedef struct dap_chain_node_client_callbacks{
 // state for a client connection
 typedef struct dap_chain_node_client {
     dap_chain_node_client_state_t state;
-    uint64_t uuid;
 
-    bool sync_gdb;
-    bool sync_chains;
+    dap_events_socket_uuid_t uuid;
+    bool resync_gdb;
+    bool resync_chains;
 
     dap_chain_cell_id_t cell_id;
 
@@ -119,6 +119,7 @@ typedef struct dap_chain_node_client {
     dap_chain_node_client_callbacks_t callbacks;
     void * callbacks_arg;
 } dap_chain_node_client_t;
+
 #define DAP_CHAIN_NODE_CLIENT(a) (a ? (dap_chain_node_client_t *) (a)->_inheritor : NULL)
 
 int dap_chain_node_client_init(void);
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index 1c06eaf7e86da81d408533b846161ed6fb4c7c30..9e1f98e2e0ee816778c967e791ac86dd599eefd2 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -63,7 +63,7 @@ char *s_server_continents[]={
 		"Antarctica"
  };
 
-static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const char *a_prefix, const char *a_group,
+static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const char *a_group,
                                    const char *a_key, const void *a_value, const size_t a_value_len);
 
 /**
@@ -520,10 +520,9 @@ void dap_chain_net_srv_order_dump_to_string(dap_chain_net_srv_order_t *a_order,d
     }
 }
 
-static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const char *a_prefix, const char *a_group,
+static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const char *a_group,
                                    const char *a_key, const void *a_value, const size_t a_value_len)
 {
-    UNUSED(a_prefix);
     UNUSED(a_value_len);
     if (!a_arg || !a_value || a_op_code != 'a' || !dap_config_get_item_bool_default(g_config, "srv", "order_signed_only", false)) {
         return;