From eab6b4aba661880d0293802e8eff3f4cde0e999b Mon Sep 17 00:00:00 2001
From: Alexander Lysikov <alexander.lysikov@demlabs.net>
Date: Mon, 18 Apr 2022 15:52:30 +0500
Subject: [PATCH 1/3] feature-5654: Pin and Unpin records in the Global Db

---
 modules/channel/chain/dap_stream_ch_chain.c   |   7 ++
 modules/global-db/dap_chain_global_db.c       |  67 ++++++++---
 .../dap_chain_global_db_driver_cdb.c          |  12 +-
 .../global-db/dap_chain_global_db_remote.c    |   8 +-
 .../global-db/include/dap_chain_global_db.h   |   5 +-
 .../include/dap_chain_global_db_driver.h      |   5 +
 modules/net/dap_chain_node_cli_cmd.c          | 105 +++++++++++++++++-
 7 files changed, 185 insertions(+), 24 deletions(-)

diff --git a/modules/channel/chain/dap_stream_ch_chain.c b/modules/channel/chain/dap_stream_ch_chain.c
index 8b9dce49d..0b1110799 100644
--- a/modules/channel/chain/dap_stream_ch_chain.c
+++ b/modules/channel/chain/dap_stream_ch_chain.c
@@ -753,13 +753,20 @@ static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
             bool l_apply = false;
             // timestamp for exist obj
             time_t l_timestamp_cur = 0;
+            // Record is pinned or not
+            bool l_is_pinned_cur = false;
             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;
+                    l_is_pinned_cur = l_read_obj->flags | RECORD_PINNED;
                     dap_store_obj_free(l_read_obj, 1);
                 }
             }
+            // Do not overwrite pinned records
+            if(l_is_pinned_cur) {
+                continue;
+            }
             time_t l_timestamp_del = global_db_gr_del_get_timestamp(l_obj->group, l_obj->key);
             // check the applied object newer that we have stored or erased
             if (l_obj->timestamp > (uint64_t)l_timestamp_del &&
diff --git a/modules/global-db/dap_chain_global_db.c b/modules/global-db/dap_chain_global_db.c
index 5768111d6..dfc00fedc 100644
--- a/modules/global-db/dap_chain_global_db.c
+++ b/modules/global-db/dap_chain_global_db.c
@@ -313,35 +313,50 @@ dap_store_obj_t* dap_chain_global_db_obj_gr_get(const char *a_key, size_t *a_dat
     return l_store_data;
 }
 
-
 /**
- * @brief Gets an object value from database by a_key and a_group.
+ * @brief Gets an object value with parameters from database by a_key and a_group.
  *
  * @param a_key an object key string
  * @param a_data_len_out a length of values that were gotten
+ * @param a_flags_out record flags that were gotten
  * @param a_group a group name string
  * @return If successful, returns a pointer to the object value.
  */
-uint8_t * dap_chain_global_db_gr_get(const char *a_key, size_t *a_data_len_out, const char *a_group)
+uint8_t* dap_chain_global_db_flags_gr_get(const char *a_key, size_t *a_data_len_out, uint8_t *a_flags_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)
-        a_data_len_out = &l_data_len_out;
-    dap_store_obj_t *l_store_data = dap_chain_global_db_driver_read(a_group, a_key, a_data_len_out);
-    if (!l_store_data) {
+    size_t l_count_records = 0;
+    dap_store_obj_t *l_store_data = dap_chain_global_db_driver_read(a_group, a_key, &l_count_records);
+    if(!l_store_data || l_count_records < 1) {
         return NULL;
     }
     l_ret_value = l_store_data->value && l_store_data->value_len
             ? DAP_DUP_SIZE(l_store_data->value, l_store_data->value_len)
             : NULL;
-    l_data_len_out = l_store_data->value_len;
-    dap_store_obj_free(l_store_data, 1);
-    *a_data_len_out = l_data_len_out;
+    // set length of output buffer
+    if(a_data_len_out)
+        *a_data_len_out = l_store_data->value_len;
+    // set flag of record
+    if(a_flags_out)
+        *a_flags_out = l_store_data->flags;
+    dap_store_obj_free(l_store_data, l_count_records);
     return l_ret_value;
 }
 
+/**
+ * @brief Gets an object value from database by a_key and a_group.
+ *
+ * @param a_key an object key string
+ * @param a_data_len_out a length of values that were gotten
+ * @param a_group a group name string
+ * @return If successful, returns a pointer to the object value.
+ */
+uint8_t * dap_chain_global_db_gr_get(const char *a_key, size_t *a_data_len_out, const char *a_group)
+{
+    return dap_chain_global_db_flags_gr_get(a_key, a_data_len_out, NULL, a_group);
+}
+
 /**
  * @brief Gets an object value from database by a_key for the "local.general" group.
  * @param a_key an object key string
@@ -556,19 +571,21 @@ void dap_global_db_change_notify(dap_store_obj_t *a_store_data)
 }
 
 /**
- * @brief Adds a value to a database.
+ * @brief Adds a value with parameters to a database.
  * @param a_key a object key string
  * @param a_value a value to be added
  * @param a_value_len length of value. If a_value_len=-1, the function calculates length.
  * @param a_group a group name string
+ * @param a_flags flags for record (RECORD_COMMON, RECORD_PINNED)
  * @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 True if successful, false otherwise.
  */
-bool dap_chain_global_db_gr_set(const char *a_key, const void *a_value, size_t a_value_len, const char *a_group)
+bool dap_chain_global_db_flags_gr_set(const char *a_key, const void *a_value, size_t a_value_len, uint8_t a_flags, const char *a_group)
 {
     dap_store_obj_t store_data = {0};
 
     store_data.key = a_key;
+    store_data.flags = a_flags;
     store_data.value_len = (a_value_len == (size_t) -1) ? dap_strlen(a_value) : a_value_len;
     store_data.value = store_data.value_len ? (void *)a_value : NULL;
     store_data.group = (char *)a_group;
@@ -594,13 +611,35 @@ bool dap_chain_global_db_gr_set(const char *a_key, const void *a_value, size_t a
     return !l_res;
 }
 
+/**
+ * @brief Adds a value to a database.
+ * @param a_key a object key string
+ * @param a_value a value to be added
+ * @param a_value_len length of value. If a_value_len=-1, the function calculates length.
+ * @param a_group a group name string
+ * @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 True if successful, false otherwise.
+ */
+bool dap_chain_global_db_gr_set(const char *a_key, const void *a_value, size_t a_value_len, const char *a_group)
+{
+    uint8_t l_flags = RECORD_COMMON;
+    return dap_chain_global_db_flags_gr_set(a_key, a_value, a_value_len, l_flags, a_group);
+}
+
+bool dap_chain_global_db_pinned_gr_set(const char *a_key, const void *a_value, size_t a_value_len, const char *a_group)
+{
+    // Add a value to the database as a pinned record
+    uint8_t l_flags = RECORD_PINNED;
+    return dap_chain_global_db_flags_gr_set(a_key, a_value, a_value_len, l_flags, a_group);
+}
+
 /**
  * @brief Adds a value to a database for the "local.general" group
  * @param a_value a value to be added
  * @param a_value_len length of value. If a_value_len=-1, the function counts length.
  * @return True if successful, false otherwise.
  */
-bool dap_chain_global_db_set( char *a_key,  void *a_value, size_t a_value_len)
+bool dap_chain_global_db_set(const char *a_key, const 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);
 }
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 fdcec0d15..accfa8aea 100644
--- a/modules/global-db/dap_chain_global_db_driver_cdb.c
+++ b/modules/global-db/dap_chain_global_db_driver_cdb.c
@@ -88,6 +88,8 @@ static void cdb_serialize_val_to_dap_store_obj(pdap_store_obj_t a_obj, const cha
     a_obj->key = dap_strdup(key);
     a_obj->id = dap_hex_to_uint(val, sizeof(uint64_t));
     offset += sizeof(uint64_t);
+    a_obj->flags = dap_hex_to_uint(val + offset, sizeof(uint8_t));
+    offset += sizeof(uint8_t);
     a_obj->value_len = dap_hex_to_uint(val + offset, sizeof(uint64_t));
     offset += sizeof(uint64_t);
     a_obj->value = DAP_NEW_SIZE(uint8_t, a_obj->value_len);
@@ -611,15 +613,21 @@ int dap_db_driver_cdb_apply_store_obj(pdap_store_obj_t a_store_obj) {
         cdb_record l_rec;
         l_rec.key = (char *)a_store_obj->key; //dap_strdup(a_store_obj->key);
         int offset = 0;
-        char *l_val = DAP_NEW_Z_SIZE(char, sizeof(uint64_t) + sizeof(uint64_t) + a_store_obj->value_len + sizeof(uint64_t));
+        char *l_val = DAP_NEW_Z_SIZE(char, sizeof(uint64_t) + sizeof(uint8_t) + sizeof(uint64_t) + a_store_obj->value_len + sizeof(uint64_t));
         dap_uint_to_hex(l_val, ++l_cdb_i->id, sizeof(uint64_t));
         offset += sizeof(uint64_t);
+        // Add flags
+        dap_uint_to_hex(l_val + offset, a_store_obj->flags, sizeof(uint8_t));
+        offset += sizeof(uint8_t);
+        // Add length of value
         dap_uint_to_hex(l_val + offset, a_store_obj->value_len, sizeof(uint64_t));
         offset += sizeof(uint64_t);
+        // Add value
         if(a_store_obj->value && a_store_obj->value_len){
             memcpy(l_val + offset, a_store_obj->value, a_store_obj->value_len);
         }
         offset += a_store_obj->value_len;
+        // Add a timestamp
         dap_uint_to_hex(l_val + offset, a_store_obj->timestamp, sizeof(uint64_t));
         offset += sizeof(uint64_t);
         l_rec.val = l_val;
@@ -633,7 +641,7 @@ int dap_db_driver_cdb_apply_store_obj(pdap_store_obj_t a_store_obj) {
         if(a_store_obj->key) {
             if(cdb_del(l_cdb_i->cdb, a_store_obj->key, (int) strlen(a_store_obj->key)) == -3)
                 ret = 1;
-        } else if (dap_cdb_init_group(a_store_obj->group, CDB_TRUNC | CDB_PAGEWARMUP))
+        } else if (!dap_cdb_init_group(a_store_obj->group, CDB_TRUNC | CDB_PAGEWARMUP))
             ret = -1;
     }
     return ret;
diff --git a/modules/global-db/dap_chain_global_db_remote.c b/modules/global-db/dap_chain_global_db_remote.c
index fd597586f..3f998691a 100644
--- a/modules/global-db/dap_chain_global_db_remote.c
+++ b/modules/global-db/dap_chain_global_db_remote.c
@@ -629,9 +629,8 @@ dap_store_obj_t *dap_store_unpacket_multiple(const dap_store_obj_pkt_t *a_pkt, s
         l_offset += sizeof(uint16_t);
 
         if (l_offset+l_str_length> a_pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'group' field"); break;} // Check for buffer boundries
-        l_obj->group = DAP_NEW_SIZE(char, l_str_length + 1);
+        l_obj->group = DAP_NEW_Z_SIZE(char, l_str_length + 1);
         memcpy(l_obj->group, a_pkt->data + l_offset, l_str_length);
-        l_obj->group[l_str_length] = '\0';
         l_offset += l_str_length;
 
         if (l_offset+sizeof (uint64_t)> a_pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'id' field"); break;} // Check for buffer boundries
@@ -647,9 +646,8 @@ dap_store_obj_t *dap_store_unpacket_multiple(const dap_store_obj_pkt_t *a_pkt, s
         l_offset += sizeof(uint16_t);
 
         if (l_offset+ l_str_length > a_pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'key' field"); break;} // Check for buffer boundries
-        l_obj->key = DAP_NEW_SIZE(char, l_str_length + 1);
-        memcpy((char *)l_obj->key, a_pkt->data + l_offset, l_str_length);
-        ((char *)l_obj->key)[l_str_length] = '\0';
+        l_obj->key = DAP_NEW_Z_SIZE(char, l_str_length + 1);
+        memcpy((char*) l_obj->key, a_pkt->data + l_offset, l_str_length);
         l_offset += l_str_length;
 
         if (l_offset+sizeof (uint64_t)> a_pkt->data_size) {log_it(L_ERROR, "Broken GDB element: can't read 'value_length' field"); break;} // Check for buffer boundries
diff --git a/modules/global-db/include/dap_chain_global_db.h b/modules/global-db/include/dap_chain_global_db.h
index a2951e8b7..94ec521b8 100644
--- a/modules/global-db/include/dap_chain_global_db.h
+++ b/modules/global-db/include/dap_chain_global_db.h
@@ -72,14 +72,17 @@ void dap_global_db_change_notify(dap_store_obj_t *a_store_data);
  */
 dap_store_obj_t *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* dap_chain_global_db_flags_gr_get(const char *a_key, size_t *a_data_len_out, uint8_t *a_flags_out, const char *a_group);
 uint8_t * dap_chain_global_db_gr_get(const char *a_key, size_t *a_data_len_out, const char *a_group);
 uint8_t * dap_chain_global_db_get(const char *a_key, size_t *a_data_len_out);
 
 /**
  * Set one entry to base
  */
+bool dap_chain_global_db_flags_gr_set(const char *a_key, const void *a_value, size_t a_value_len, uint8_t a_flags, const char *a_group);
 bool dap_chain_global_db_gr_set(const char *a_key,  const void *a_value, size_t a_value_len, const char *a_group);
-bool dap_chain_global_db_set( char *a_key, void *a_value, size_t a_value_len);
+bool dap_chain_global_db_pinned_gr_set(const char *a_key, const void *a_value, size_t a_value_len, const char *a_group);
+bool dap_chain_global_db_set(const char *a_key, const void *a_value, size_t a_value_len);
 
 /**
  * Delete entry from base
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 fb9be8d2c..3c63acd55 100644
--- a/modules/global-db/include/dap_chain_global_db_driver.h
+++ b/modules/global-db/include/dap_chain_global_db_driver.h
@@ -36,11 +36,16 @@ enum    {
 
 };
 
+enum RECORD_FLAGS {
+    RECORD_COMMON = 0,    // 0000
+    RECORD_PINNED = 1,    // 0001
+};
 
 typedef struct dap_store_obj {
     uint64_t id;
     uint64_t timestamp;
     uint32_t type;                              /* Operation type: ADD/DELETE, see DAP_DB$K_OPTYPE_* constants */
+    uint8_t flags;                              /* RECORD_FLAGS */
     char *group;
     const char *key;
     const char *c_key;
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index e7342201a..3a9f84238 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -721,7 +721,7 @@ static int node_info_dump_with_reply(dap_chain_net_t * a_net, dap_chain_node_add
 int com_global_db(int a_argc, char ** a_argv, char **a_str_reply)
 {
     enum {
-        CMD_NONE, CMD_NAME_CELL, CMD_ADD, CMD_FLUSH
+        CMD_NONE, CMD_NAME_CELL, CMD_ADD, CMD_FLUSH, CMD_RECORD
     };
     int arg_index = 1;
     int cmd_name = CMD_NONE;
@@ -730,6 +730,8 @@ int com_global_db(int a_argc, char ** a_argv, char **a_str_reply)
         cmd_name = CMD_NAME_CELL;
     else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "flush", NULL))
         cmd_name = CMD_FLUSH;
+    else if(dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "record", NULL))
+            cmd_name = CMD_RECORD;
     switch (cmd_name) {
     case CMD_NAME_CELL:
     {
@@ -750,7 +752,7 @@ int com_global_db(int a_argc, char ** a_argv, char **a_str_reply)
 
         // Check for chain
         if(!l_chain_str) {
-            dap_chain_node_cli_set_reply_text(a_str_reply, "%s requires parameter 'chain' to be valid");
+            dap_chain_node_cli_set_reply_text(a_str_reply, "%s requires parameter 'chain' to be valid", a_argv[0]);
             return -12;
         }
 
@@ -819,6 +821,105 @@ int com_global_db(int a_argc, char ** a_argv, char **a_str_reply)
         }
         return 0;
     }
+    case CMD_RECORD:
+    {
+        enum {
+            SUMCMD_GET, SUMCMD_PIN, SUMCMD_UNPIN
+        };
+        if(!arg_index || a_argc < 3) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "parameters are not valid");
+            return -1;
+        }
+        int arg_index_n = ++arg_index;
+        int l_subcmd;
+        // Get value
+        if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "get", NULL))!= 0) {
+            l_subcmd = SUMCMD_GET;
+        }
+        // Pin record
+        else if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "pin", NULL)) != 0) {
+            l_subcmd = SUMCMD_PIN;
+        }
+        // Unpin record
+        else if((arg_index_n = dap_chain_node_cli_find_option_val(a_argv, arg_index, min(a_argc, arg_index + 1), "unpin", NULL)) != 0) {
+            l_subcmd = SUMCMD_UNPIN;
+        }
+        else{
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Subcommand '%s' not recognized, available subcommands are 'get', 'pin' or 'unpin'", a_argv[2]);
+            return -1;
+        }
+        // read record from database
+        const char *l_key = NULL;
+        const char *l_group = NULL;
+        // find key and group
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-key", &l_key);
+        dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-group", &l_group);
+        size_t l_value_len = 0;
+        uint8_t l_flags = 0;
+        uint8_t *l_value = dap_chain_global_db_flags_gr_get(l_key, &l_value_len, &l_flags, l_group);
+        if(!l_value || !l_value_len) {
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Record not found\n\n");
+            return -1;
+        }
+        bool is_pinned = l_flags & RECORD_PINNED;
+
+        int l_ret = 0;
+        // prepare record information
+        switch (l_subcmd) {
+        case SUMCMD_GET: // Get value
+        {
+            dap_hash_fast_t l_hash;
+            char *l_hash_str = NULL;
+            if(dap_hash_fast(l_value, l_value_len, &l_hash)) {
+                l_hash_str = dap_chain_hash_fast_to_str_new(&l_hash);
+            }
+            char *l_value_str = DAP_NEW_Z_SIZE(char, l_value_len * 2 + 2);
+            size_t ret = dap_bin2hex(l_value_str, l_value, l_value_len);
+            dap_chain_node_cli_set_reply_text(a_str_reply, "Record found\n"
+                    "lenght:\t%u byte\n"
+                    "hash:\t%s\n"
+                    "pinned:\t%s\n"
+                    "value:\t0x%s\n\n", l_value_len, l_hash_str, is_pinned ? "Yes" : "No", l_value_str);
+            DAP_DELETE(l_value_str);
+            DAP_DELETE(l_hash_str);
+            break;
+        }
+        case SUMCMD_PIN: // Pin record
+        {
+            if(is_pinned){
+                dap_chain_node_cli_set_reply_text(a_str_reply, "record already pinned");
+                break;
+            }
+            if(dap_chain_global_db_flags_gr_set(l_key, l_value, l_value_len, l_flags | RECORD_PINNED, l_group)){
+                dap_chain_node_cli_set_reply_text(a_str_reply, "record successfully pinned");
+            }
+            else{
+                dap_chain_node_cli_set_reply_text(a_str_reply, "can't pin the record");
+                l_ret = -2;
+            }
+            break;
+        }
+        case SUMCMD_UNPIN: // Unpin record
+        {
+            if(!is_pinned) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "record already unpinned");
+                break;
+            }
+            l_flags &= ~RECORD_PINNED;
+            if(dap_chain_global_db_flags_gr_set(l_key, l_value, l_value_len, l_flags & ~RECORD_PINNED, l_group)) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "record successfully unpinned");
+            }
+            else {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "can't unpin the record");
+                l_ret = -2;
+            }
+            break;
+        }
+
+        }
+        DAP_DELETE(l_value);
+        return l_ret;
+    }
     default:
         dap_chain_node_cli_set_reply_text(a_str_reply, "parameters are not valid");
         return -1;
-- 
GitLab


From f1d366ef6dce7a6fcca9a36ed7ed1703107a2546 Mon Sep 17 00:00:00 2001
From: Alexander Lysikov <alexander.lysikov@demlabs.net>
Date: Wed, 20 Apr 2022 16:13:51 +0500
Subject: [PATCH 2/3] Feature-6060: Changing the GDB format; Changing gdb time
 to more accurate

---
 dap-sdk/core/CMakeLists.txt                   |  10 +-
 dap-sdk/core/include/dap_common.h             |  19 --
 dap-sdk/core/include/dap_file_utils.h         |  17 ++
 dap-sdk/core/include/dap_time.h               |  55 +++++
 dap-sdk/core/libdap.pri                       |   6 +-
 dap-sdk/core/src/core.pri                     |   6 +-
 dap-sdk/core/src/dap_common.c                 | 101 +--------
 dap-sdk/core/src/dap_file_utils.c             | 154 +++++++++++++
 dap-sdk/core/src/dap_time.c                   | 211 ++++++++++++++++++
 dap-sdk/net/core/dap_worker.c                 |   2 +-
 modules/chain/dap_chain_ledger.c              |   4 +-
 modules/channel/chain/dap_stream_ch_chain.c   |   8 +-
 modules/common/dap_chain_common.c             |   8 -
 modules/common/dap_chain_datum.c              |   3 +-
 modules/common/include/dap_chain_common.h     |   3 -
 .../include/dap_chain_datum_tx_out_cond.h     |   5 +-
 .../block-ton/dap_chain_cs_block_ton.c        |  18 +-
 .../include/dap_chain_cs_block_ton.h          |  14 +-
 modules/global-db/dap_chain_global_db.c       | 117 +++++++---
 .../global-db/dap_chain_global_db_remote.c    |  12 +-
 .../global-db/include/dap_chain_global_db.h   |   3 +-
 .../include/dap_chain_global_db_driver.h      |   5 +-
 modules/net/srv/dap_chain_net_srv.c           |   4 +-
 modules/net/srv/dap_chain_net_srv_order.c     |   6 +-
 .../net/srv/include/dap_chain_net_srv_order.h |  12 +-
 modules/type/blocks/include/dap_chain_block.h |   3 +-
 26 files changed, 593 insertions(+), 213 deletions(-)
 create mode 100644 dap-sdk/core/include/dap_time.h
 create mode 100644 dap-sdk/core/src/dap_time.c

diff --git a/dap-sdk/core/CMakeLists.txt b/dap-sdk/core/CMakeLists.txt
index 5956ea553..9aa871984 100755
--- a/dap-sdk/core/CMakeLists.txt
+++ b/dap-sdk/core/CMakeLists.txt
@@ -44,25 +44,25 @@ endif()
 if(UNIX)
     add_subdirectory(src/unix)
     if(DARWIN)
-        target_link_libraries(${PROJECT_NAME} dap_core_unix)
+        target_link_libraries(${PROJECT_NAME} dap_core_unix zip)
     else()
-        target_link_libraries(${PROJECT_NAME} dap_core_unix rt)
+        target_link_libraries(${PROJECT_NAME} dap_core_unix zip rt)
     endif()
 endif()
 
 if(DARWIN)
     add_subdirectory(src/darwin)
-    target_link_libraries(${PROJECT_NAME} dap_core_darwin)
+    target_link_libraries(${PROJECT_NAME} dap_core_darwin zip)
 endif()
 
 if(ANDROID)
     add_subdirectory(src/android)
-    target_link_libraries(${PROJECT_NAME} dap_core_android rt)
+    target_link_libraries(${PROJECT_NAME} dap_core_android zip rt)
 endif()
 
 if (WIN32)
     add_subdirectory(src/win32)
-    target_link_libraries(${PROJECT_NAME} dap_core_win32)
+    target_link_libraries(${PROJECT_NAME} dap_core_win32 zip)
 endif()
 
 if(BUILD_DAP_TESTS)
diff --git a/dap-sdk/core/include/dap_common.h b/dap-sdk/core/include/dap_common.h
index 52dddae63..d79e2d7b9 100755
--- a/dap-sdk/core/include/dap_common.h
+++ b/dap-sdk/core/include/dap_common.h
@@ -51,8 +51,6 @@
 #include <fcntl.h>
 #define pipe(pfds) _pipe(pfds, 4096, _O_BINARY)
 #define strerror_r(arg1, arg2, arg3) strerror_s(arg2, arg3, arg1)
-#define ctime_r(arg1, arg2) ctime_s(arg2, sizeof(arg2), arg1)
-//#define asctime_r(arg1, arg2) asctime_s(arg2, sizeof(arg2), arg1)
 #endif
 #ifdef __MACH__
 #include <dispatch/dispatch.h>
@@ -74,8 +72,6 @@ typedef uint8_t byte_t;
 // Extracts a size_t from a pointer
 #define DAP_POINTER_TO_SIZE(p) ((size_t) (p))
 
-#define DAP_END_OF_DAYS 4102444799
-
 #if defined(__GNUC__) ||defined (__clang__)
   #define DAP_ALIGN_PACKED  __attribute__((aligned(1),packed))
 #else
@@ -470,9 +466,6 @@ void dap_set_appname(const char * a_appname);
 
 char *dap_itoa(int i);
 
-int dap_time_to_str_rfc822(char * out, size_t out_size_max, time_t t);
-int timespec_diff(struct timespec *a_start, struct timespec *a_stop, struct timespec *a_result);
-
 int get_select_breaker(void);
 int send_select_break(void);
 int exec_with_ret(char**, const char*);
@@ -497,18 +490,6 @@ uint64_t dap_lendian_get64(const uint8_t *a_buf);
 void dap_lendian_put64(uint8_t *a_buf, uint64_t a_val);
 
 
-// crossplatform usleep
-#define DAP_USEC_PER_SEC 1000000
-void dap_usleep(time_t a_microseconds);
-
-/**
- * @brief dap_ctime_r This function does the same as ctime_r, but if it returns (null), a line break is added.
- * @param a_time
- * @param a_buf The minimum buffer size is 26 elements.
- * @return
- */
-char* dap_ctime_r(time_t *a_time, char* a_buf);
-
 static inline void * dap_mempcpy(void * a_dest,const void * a_src,size_t n)
 {
     return ((byte_t*) memcpy(a_dest,a_src,n))+n;
diff --git a/dap-sdk/core/include/dap_file_utils.h b/dap-sdk/core/include/dap_file_utils.h
index cd5ba8bfc..af274469b 100755
--- a/dap-sdk/core/include/dap_file_utils.h
+++ b/dap-sdk/core/include/dap_file_utils.h
@@ -170,6 +170,23 @@ char* dap_canonicalize_filename(const char *filename, const char *relative_to);
  */
 char* dap_get_current_dir(void);
 
+/**
+ * rm_rf
+ *
+ * A fairly naive `rm -rf` implementation
+ */
+void dap_rm_rf(const char *path);
+
+/*
+ * Pack a directory to zip file
+ *
+ * @a_inputdir: input dir
+ * @a_output_filename: output zip file path
+ *
+ * Returns: True, if successfully
+ */
+bool zip_directory(const char *a_inputdir, const char * a_output_filename);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/dap-sdk/core/include/dap_time.h b/dap-sdk/core/include/dap_time.h
new file mode 100644
index 000000000..5f854b6b6
--- /dev/null
+++ b/dap-sdk/core/include/dap_time.h
@@ -0,0 +1,55 @@
+#pragma once
+#include <stdint.h>
+
+#ifdef DAP_OS_WINDOWS
+#define ctime_r(arg1, arg2) ctime_s(arg2, sizeof(arg2), arg1)
+//#define asctime_r(arg1, arg2) asctime_s(arg2, sizeof(arg2), arg1)
+#endif
+
+#define DAP_END_OF_DAYS 4102444799
+// Constant to convert seconds to nanoseconds
+#define DAP_NSEC_PER_SEC 1000000000
+// Constant to convert seconds to microseconds
+#define DAP_USEC_PER_SEC 1000000
+
+
+// time in seconds
+typedef uint64_t dap_time_t;
+// time in nanoseconds
+typedef uint64_t dap_gdb_time_t;
+
+// Create gdb time from second
+dap_gdb_time_t dap_gdb_time_from_sec(uint32_t a_time);
+// Get seconds from gdb time
+long dap_gdb_time_to_sec(dap_gdb_time_t a_time);
+
+/**
+ * @brief dap_chain_time_now Get current time in seconds since January 1, 1970 (UTC)
+ * @return Returns current UTC time in seconds.
+ */
+dap_gdb_time_t dap_time_now(void);
+/**
+ * @brief dap_clock_gettime Get current time in nanoseconds since January 1, 1970 (UTC)
+ * @return Returns current UTC time in nanoseconds.
+ */
+dap_gdb_time_t dap_gdb_time_now(void);
+
+
+// crossplatform usleep
+void dap_usleep(time_t a_microseconds);
+
+/**
+ * @brief dap_ctime_r This function does the same as ctime_r, but if it returns (null), a line break is added.
+ * @param a_time
+ * @param a_buf The minimum buffer size is 26 elements.
+ * @return
+ */
+char* dap_ctime_r(dap_time_t *a_time, char* a_buf);
+char* dap_gdb_ctime_r(dap_gdb_time_t *a_time, char* a_buf);
+
+
+int dap_time_to_str_rfc822(char * out, size_t out_size_max, time_t t);
+int dap_gbd_time_to_str_rfc822(char *a_out, size_t a_out_size_max, dap_gdb_time_t a_chain_time);
+int timespec_diff(struct timespec *a_start, struct timespec *a_stop, struct timespec *a_result);
+
+
diff --git a/dap-sdk/core/libdap.pri b/dap-sdk/core/libdap.pri
index e3b46af7e..3b73f16fd 100755
--- a/dap-sdk/core/libdap.pri
+++ b/dap-sdk/core/libdap.pri
@@ -68,7 +68,8 @@ HEADERS += $$PWD/include/dap_common.h \
     $$PWD/include/dap_list.h \
     $$PWD/include/dap_module.h \
     $$PWD/include/dap_strfuncs.h \
-    $$PWD/include/dap_string.h
+    $$PWD/include/dap_string.h \
+    $$PWD/include/dap_time.h
 
 SOURCES += $$PWD/src/dap_common.c \
     $$PWD/src/dap_binary_tree.c \
@@ -78,7 +79,8 @@ SOURCES += $$PWD/src/dap_common.c \
     $$PWD/src/dap_list.c \
     $$PWD/src/dap_module.c \
     $$PWD/src/dap_strfuncs.c \
-    $$PWD/src/dap_string.c
+    $$PWD/src/dap_string.c \
+    $$PWD/src/dap_time.c
 
 INCLUDEPATH += $$PWD/include \
     $$PWD/../../3rdparty/uthash/src/
diff --git a/dap-sdk/core/src/core.pri b/dap-sdk/core/src/core.pri
index 81ce43173..7702cd71f 100755
--- a/dap-sdk/core/src/core.pri
+++ b/dap-sdk/core/src/core.pri
@@ -18,7 +18,8 @@ HEADERS += $$PWD/dap_common.h \
     $$PWD/dap_list.h \
     $$PWD/dap_module.h \
     $$PWD/dap_strfuncs.h \
-    $$PWD/dap_string.h
+    $$PWD/dap_string.h \
+    $$PWD/dap_time.h
 
 SOURCES += $$PWD/dap_common.c \
     $$PWD/dap_config.c \
@@ -27,6 +28,7 @@ SOURCES += $$PWD/dap_common.c \
     $$PWD/dap_list.c \
     $$PWD/dap_module.c \
     $$PWD/dap_strfuncs.c \
-    $$PWD/dap_string.c
+    $$PWD/dap_string.c \
+    $$PWD/dap_time.c
 
 INCLUDEPATH += $$PWD
diff --git a/dap-sdk/core/src/dap_common.c b/dap-sdk/core/src/dap_common.c
index 06d52663f..8b844b71f 100755
--- a/dap-sdk/core/src/dap_common.c
+++ b/dap-sdk/core/src/dap_common.c
@@ -33,7 +33,7 @@
 #include <stdatomic.h>
 
 #include "utlist.h"
-#include <errno.h>
+//#include <errno.h>
 
 #ifdef DAP_OS_ANDROID
   #include <android/log.h>
@@ -498,66 +498,6 @@ char *dap_itoa(int i)
 
 #endif
 
-
-/**
- * @brief time_to_rfc822 Convert time_t to string with RFC822 formatted date and time
- * @param[out] out Output buffer
- * @param[out] out_size_mac Maximum size of output buffer
- * @param[in] t UNIX time
- * @return Length of resulting string if ok or lesser than zero if not
- */
-int dap_time_to_str_rfc822(char * out, size_t out_size_max, time_t t)
-{
-  struct tm *tmp;
-  tmp = localtime( &t );
-
-  if ( tmp == NULL ) {
-    log_it( L_ERROR, "Can't convert data from unix fromat to structured one" );
-    return -2;
-  }
-
-  int ret;
-
-  #ifndef _WIN32
-    ret = strftime( out, out_size_max, "%a, %d %b %y %T %z", tmp );
-  #else
-    ret = strftime( out, out_size_max, "%a, %d %b %y %H:%M:%S", tmp );
-  #endif
-
-  if ( !ret ) {
-    log_it( L_ERROR, "Can't print formatted time in string" );
-    return -1;
-  }
-
-  return ret;
-}
-
-/**
- * @brief Calculate diff of two struct timespec
- * @param[in] a_start - first time
- * @param[in] a_stop - second time
- * @param[out] a_result -  diff time, may be NULL
- * @return diff time in millisecond
- */
-int timespec_diff(struct timespec *a_start, struct timespec *a_stop, struct timespec *a_result)
-{
-    if(!a_start || !a_stop)
-        return 0;
-    if(!a_result) {
-        struct timespec l_time_tmp = { 0 };
-        a_result = &l_time_tmp;
-    }
-    if((a_stop->tv_nsec - a_start->tv_nsec) < 0) {
-        a_result->tv_sec = a_stop->tv_sec - a_start->tv_sec - 1;
-        a_result->tv_nsec = a_stop->tv_nsec - a_start->tv_nsec + 1000000000;
-    } else {
-        a_result->tv_sec = a_stop->tv_sec - a_start->tv_sec;
-        a_result->tv_nsec = a_stop->tv_nsec - a_start->tv_nsec;
-    }
-
-    return (a_result->tv_sec * 1000 + a_result->tv_nsec / 1000000);
-}
-
 #define BREAK_LATENCY   1
 
 static int breaker_set[2] = { -1, -1 };
@@ -1144,45 +1084,6 @@ void dap_lendian_put64(uint8_t *a_buf, uint64_t a_val)
     dap_lendian_put32(a_buf + 4, a_val >> 32);
 }
 
-/**
- * dap_usleep:
- * @a_microseconds: number of microseconds to pause
- *
- * Pauses the current thread for the given number of microseconds.
- */
-void dap_usleep(time_t a_microseconds)
-{
-#ifdef DAP_OS_WINDOWS
-    Sleep (a_microseconds / 1000);
-#else
-    struct timespec l_request, l_remaining;
-    l_request.tv_sec = a_microseconds / DAP_USEC_PER_SEC;
-    l_request.tv_nsec = 1000 * (a_microseconds % DAP_USEC_PER_SEC);
-    while(nanosleep(&l_request, &l_remaining) == -1 && errno == EINTR)
-        l_request = l_remaining;
-#endif
-}
-
-
-char* dap_ctime_r(time_t *a_time, char* a_buf){
-    char *l_fail_ret = "(null)\r\n";
-    if (!a_buf)
-        return l_fail_ret;
-    if(!a_time || *a_time > DAP_END_OF_DAYS) {
-        strcpy(a_buf, l_fail_ret);
-        return l_fail_ret;
-    }
-    struct tm l_time;
-    localtime_r(a_time, &l_time);
-    char *l_str_time = asctime_r(&l_time, a_buf);
-    if (l_str_time)
-        return  l_str_time;
-    else {
-        strcpy(a_buf, l_fail_ret);
-        return l_fail_ret;
-    }
-}
-
 int dap_is_alpha_and_(char e)
 {
     if ((e >= '0' && e <= '9')||(e >= 'a' && e <= 'z')||(e >= 'A' && e <= 'Z')||(e == '_')) return 1;
diff --git a/dap-sdk/core/src/dap_file_utils.c b/dap-sdk/core/src/dap_file_utils.c
index fea3cf97a..8dfbe1b1d 100755
--- a/dap-sdk/core/src/dap_file_utils.c
+++ b/dap-sdk/core/src/dap_file_utils.c
@@ -31,6 +31,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <limits.h>
+#include <zip.h>
 #if (OS_TARGET == OS_MACOS)
     #include <stdio.h>
 #else
@@ -1298,3 +1299,156 @@ char* dap_get_current_dir(void)
 
 #endif
 }
+
+static const char* dap_dir_read_name(DIR *dir)
+{
+#ifdef _WIN32
+  char *utf8_name;
+  struct _wdirent *wentry;
+#else
+    struct dirent *entry;
+#endif
+
+    dap_return_val_if_fail(dir != NULL, NULL);
+
+#ifdef _WIN32
+    while(1)
+    {
+        wentry = _wreaddir(dir->wdirp);
+        while(wentry
+                && (0 == wcscmp(wentry->d_name, L".") ||
+                        0 == wcscmp(wentry->d_name, L"..")))
+            wentry = _wreaddir(dir->wdirp);
+
+        if(wentry == NULL)
+            return NULL;
+
+        utf8_name = dap_utf16_to_utf8(wentry->d_name, -1, NULL, NULL, NULL);
+
+        if(utf8_name == NULL)
+            continue; /* Huh, impossible? Skip it anyway */
+
+        strcpy(dir->utf8_buf, utf8_name);
+        DAP_DELETE(utf8_name);
+
+        return dir->utf8_buf;
+    }
+#else
+    entry = readdir(dir);
+    while(entry
+            && (0 == strcmp(entry->d_name, ".") ||
+                    0 == strcmp(entry->d_name, "..")))
+        entry = readdir(dir);
+
+    if(entry)
+        return entry->d_name;
+    else
+        return NULL;
+#endif
+}
+
+/**
+ * rm_rf
+ *
+ * A fairly naive `rm -rf` implementation
+ */
+void dap_rm_rf(const char *path)
+{
+    DIR *dir = NULL;
+    const char *entry;
+
+    dir = opendir(path);
+    if(dir == NULL)
+    {
+        /* Assume it’s a file. Ignore failure. */
+        remove(path);
+        return;
+    }
+
+    while((entry = dap_dir_read_name(dir)) != NULL)
+    {
+        char *sub_path = dap_build_filename(path, entry, NULL);
+        dap_rm_rf(sub_path);
+        DAP_DELETE(sub_path);
+    }
+
+    closedir(dir);
+
+    rmdir(path);
+}
+
+static bool walk_directory(const char *a_startdir, const char *a_inputdir, zip_t *a_zipper)
+{
+    DIR *l_dir = opendir(a_inputdir);
+    if(l_dir == NULL)
+    {
+        log_it(L_ERROR, "Failed to open input directory ");
+        zip_close(a_zipper);
+        return false;
+    }
+
+    struct dirent *l_dirp;
+    while((l_dirp = readdir(l_dir)) != NULL) {
+        if(strcmp(l_dirp->d_name, ".") && strcmp(l_dirp->d_name, "..")) {
+            char *l_fullname = dap_build_filename(a_inputdir, l_dirp->d_name, NULL);
+            if(dap_dir_test(l_fullname)) {
+
+                if(zip_dir_add(a_zipper, l_fullname + dap_strlen(a_startdir) + 1, ZIP_FL_ENC_UTF_8) < 0) {
+                    log_it(L_ERROR, "Failed to add directory to zip: %s", zip_strerror(a_zipper));
+                    DAP_DELETE(l_fullname);
+                    closedir(l_dir);
+                    return false;
+                }
+                walk_directory(a_startdir, l_fullname, a_zipper);
+            } else {
+                zip_source_t *l_source = zip_source_file(a_zipper, l_fullname, 0, 0);
+                if(l_source == NULL) {
+                    log_it(L_ERROR, "Failed to add file to zip: %s", zip_strerror(a_zipper));
+                    closedir(l_dir);
+                    DAP_DELETE(l_fullname);
+                    return false;
+                }
+                if(zip_file_add(a_zipper, l_fullname + dap_strlen(a_startdir) + 1, l_source, ZIP_FL_ENC_UTF_8) < 0) {
+                    zip_source_free(l_source);
+                    log_it(L_ERROR, "Failed to add file to zip: %s", zip_strerror(a_zipper));
+                    DAP_DELETE(l_fullname);
+                    closedir(l_dir);
+                    return false;
+                }
+            }
+            DAP_DELETE(l_fullname);
+        }
+    }
+    closedir(l_dir);
+    return true;
+}
+
+
+/*
+ * Pack a directory to zip file
+ *
+ * @a_inputdir: input dir
+ * @a_output_filename: output zip file path
+ *
+ * Returns: True, if successfully
+ */
+bool zip_directory(const char *a_inputdir, const char *a_output_filename)
+{
+    int l_errorp;
+    zip_t *l_zipper = zip_open(a_output_filename, ZIP_CREATE | ZIP_EXCL, &l_errorp);
+    if(l_zipper == NULL) {
+        zip_error_t l_ziperror;
+        zip_error_init_with_code(&l_ziperror, l_errorp);
+        if(l_errorp == ZIP_ER_EXISTS) {
+            if(!remove(a_output_filename))
+                return zip_directory(a_inputdir, a_output_filename);
+        }
+        log_it(L_ERROR, "Failed to open output file %s: %s ", a_output_filename, zip_error_strerror(&l_ziperror));
+        return false;
+    }
+
+    bool l_ret = walk_directory(a_inputdir, a_inputdir, l_zipper);
+
+    zip_close(l_zipper);
+    return l_ret;
+}
diff --git a/dap-sdk/core/src/dap_time.c b/dap-sdk/core/src/dap_time.c
new file mode 100644
index 000000000..ba8b797b7
--- /dev/null
+++ b/dap-sdk/core/src/dap_time.c
@@ -0,0 +1,211 @@
+
+#pragma once
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+
+#include "dap_common.h"
+#include "dap_time.h"
+
+#define LOG_TAG "dap_common"
+
+#ifdef _WIN32
+
+/* Identifier for system-wide realtime clock.  */
+#ifndef CLOCK_REALTIME
+#define CLOCK_REALTIME              0
+
+#ifndef clockid_t
+typedef int clockid_t;
+#endif
+
+struct timespec {
+    uint64_t tv_sec; // seconds
+    uint64_t tv_nsec;// nanoseconds
+};
+
+int clock_gettime(clockid_t clock_id, struct timespec *spec)
+{
+//    __int64 wintime;
+//    GetSystemTimeAsFileTime((FILETIME*) &wintime);
+//    spec->tv_sec = wintime / 10000000i64; //seconds
+//    spec->tv_nsec = wintime % 10000000i64 * 100; //nano-seconds
+//    return 0;
+    uint64_t ft;
+    GetSystemTimeAsFileTime(FILETIME*)&ft); //return the number of 100-nanosecond intervals since January 1, 1601 (UTC)
+    // from 1 jan 1601 to 1 jan 1970
+    ft -= 116444736000000000i64;
+    spec->tv_sec = ft / 10000000i64; //seconds
+    spec->tv_nsec = ft % 10000000i64 * 100; //nano-seconds
+    return 0;
+}
+#endif
+#endif
+
+
+// Create time from second
+dap_gdb_time_t dap_gdb_time_from_sec(uint32_t a_time)
+{
+    return (a_time << 32);
+}
+
+// Get seconds from time
+long dap_gdb_time_to_sec(dap_gdb_time_t a_time)
+{
+    return a_time >> 32;
+}
+
+/**
+ * @brief dap_chain_time_now Get current time in seconds since January 1, 1970 (UTC)
+ * @return Returns current UTC time in seconds.
+ */
+dap_gdb_time_t dap_time_now(void)
+{
+    time_t l_time = time(NULL);
+    return l_time;
+}
+
+/**
+ * @brief dap_chain_time_now Get current time in nanoseconds since January 1, 1970 (UTC)
+ * @return Returns current UTC time in nanoseconds.
+ */
+dap_gdb_time_t dap_gdb_time_now(void)
+{
+    dap_gdb_time_t l_time_nsec;
+    struct timespec cur_time;
+    clock_gettime(CLOCK_REALTIME, &cur_time);
+    l_time_nsec = (cur_time.tv_sec << 32) + cur_time.tv_nsec;
+    //l_time_nsec = cur_time.tv_sec * DAP_NSEC_PER_SEC + cur_time.tv_nsec;
+    return l_time_nsec;
+}
+
+/**
+ * dap_usleep:
+ * @a_microseconds: number of microseconds to pause
+ *
+ * Pauses the current thread for the given number of microseconds.
+ */
+void dap_usleep(time_t a_microseconds)
+{
+#ifdef DAP_OS_WINDOWS
+    Sleep (a_microseconds / 1000);
+#else
+    struct timespec l_request, l_remaining;
+    l_request.tv_sec = a_microseconds / DAP_USEC_PER_SEC;
+    l_request.tv_nsec = 1000 * (a_microseconds % DAP_USEC_PER_SEC);
+    while(nanosleep(&l_request, &l_remaining) == -1 && errno == EINTR)
+        l_request = l_remaining;
+#endif
+}
+
+/**
+ * @brief Calculate diff of two struct timespec
+ * @param[in] a_start - first time
+ * @param[in] a_stop - second time
+ * @param[out] a_result -  diff time, may be NULL
+ * @return diff time in millisecond
+ */
+int timespec_diff(struct timespec *a_start, struct timespec *a_stop, struct timespec *a_result)
+{
+    if(!a_start || !a_stop)
+        return 0;
+    if(!a_result) {
+        struct timespec l_time_tmp = { 0 };
+        a_result = &l_time_tmp;
+    }
+    if((a_stop->tv_nsec - a_start->tv_nsec) < 0) {
+        a_result->tv_sec = a_stop->tv_sec - a_start->tv_sec - 1;
+        a_result->tv_nsec = a_stop->tv_nsec - a_start->tv_nsec + 1000000000;
+    } else {
+        a_result->tv_sec = a_stop->tv_sec - a_start->tv_sec;
+        a_result->tv_nsec = a_stop->tv_nsec - a_start->tv_nsec;
+    }
+
+    return (a_result->tv_sec * 1000 + a_result->tv_nsec / 1000000);
+}
+
+/**
+ * @brief time_to_rfc822 Convert time_t to string with RFC822 formatted date and time
+ * @param[out] out Output buffer
+ * @param[out] out_size_mac Maximum size of output buffer
+ * @param[in] t UNIX time
+ * @return Length of resulting string if ok or lesser than zero if not
+ */
+int dap_time_to_str_rfc822(char * a_out, size_t a_out_size_max, time_t a_t)
+{
+  struct tm *l_tmp;
+  l_tmp = localtime( &a_t );
+
+  if ( l_tmp == NULL ) {
+    log_it( L_ERROR, "Can't convert data from unix fromat to structured one" );
+    return -2;
+  }
+
+  int l_ret;
+  #ifndef _WIN32
+    l_ret = strftime( a_out, a_out_size_max, "%a, %d %b %y %T %z", l_tmp);
+  #else
+    l_ret = strftime( a_out, a_out_size_max, "%a, %d %b %y %H:%M:%S", l_tmp );
+  #endif
+
+  if ( !l_ret ) {
+    log_it( L_ERROR, "Can't print formatted time in string" );
+    return -1;
+  }
+
+  return l_ret;
+}
+
+/**
+ * @brief time_to_rfc822 Convert dap_chain_time_t to string with RFC822 formatted date and time
+ * @param[out] out Output buffer
+ * @param[out] out_size_mac Maximum size of output buffer
+ * @param[in] t UNIX time
+ * @return Length of resulting string if ok or lesser than zero if not
+ */
+int dap_gbd_time_to_str_rfc822(char *a_out, size_t a_out_size_max, dap_gdb_time_t a_chain_time)
+{
+    time_t l_time = dap_gdb_time_to_sec(a_chain_time);
+    return dap_time_to_str_rfc822(a_out, a_out_size_max, l_time);
+}
+
+/**
+ * @brief dap_ctime_r This function does the same as ctime_r, but if it returns (null), a line break is added.
+ * @param a_time
+ * @param a_buf The minimum buffer size is 26 elements.
+ * @return
+ */
+char* dap_ctime_r(dap_time_t *a_time, char* a_buf){
+    char *l_fail_ret = "(null)\r\n";
+    if (!a_buf)
+        return l_fail_ret;
+    if(!a_time || *a_time > DAP_END_OF_DAYS) {
+        strcpy(a_buf, l_fail_ret);
+        return l_fail_ret;
+    }
+    struct tm l_time;
+    localtime_r((time_t*)a_time, &l_time);
+    char *l_str_time = asctime_r(&l_time, a_buf);
+    if (l_str_time)
+        return  l_str_time;
+    else {
+        strcpy(a_buf, l_fail_ret);
+        return l_fail_ret;
+    }
+}
+
+/**
+ * @brief dap_chain_ctime_r This function does the same as ctime_r, but if it returns (null), a line break is added.
+ * @param a_time
+ * @param a_buf The minimum buffer size is 26 elements.
+ * @return
+ */
+char* dap_gdb_ctime_r(dap_gdb_time_t *a_chain_time, char* a_buf){
+    dap_time_t l_time = dap_gdb_time_to_sec(*a_chain_time);
+    return dap_ctime_r(&l_time, a_buf);
+}
+
diff --git a/dap-sdk/net/core/dap_worker.c b/dap-sdk/net/core/dap_worker.c
index fa1e06647..e60de2c94 100644
--- a/dap-sdk/net/core/dap_worker.c
+++ b/dap-sdk/net/core/dap_worker.c
@@ -1118,7 +1118,7 @@ static bool s_socket_all_check_activity( void * a_arg)
     dap_events_socket_t *l_es = NULL, *tmp = NULL;
     char l_curtimebuf[64];
     time_t l_curtime= time(NULL);
-    dap_ctime_r(&l_curtime, l_curtimebuf);
+    //dap_ctime_r(&l_curtime, l_curtimebuf);
     //log_it(L_DEBUG,"Check sockets activity on worker #%u at %s", l_worker->id, l_curtimebuf);
     pthread_rwlock_rdlock(&l_worker->esocket_rwlock);
     HASH_ITER(hh_worker, l_worker->esockets, l_es, tmp ) {
diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index 9d420cd15..7d5595222 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -115,7 +115,7 @@ typedef struct dap_chain_ledger_tx_item {
     dap_chain_hash_fast_t tx_hash_fast;
     dap_chain_datum_tx_t *tx;
     struct {
-        time_t ts_created;
+        dap_time_t ts_created;
         int n_outs;
         int n_outs_used;
         char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
@@ -2905,7 +2905,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,
     memcpy(&l_tx_item->tx_hash_fast, a_tx_hash, sizeof(dap_chain_hash_fast_t));
     size_t l_tx_size = dap_chain_datum_tx_get_size(a_tx);
     l_tx_item->tx = DAP_DUP_SIZE(a_tx, l_tx_size);
-    l_tx_item->cache_data.ts_created = time(NULL); // Time of transasction added to ledger
+    l_tx_item->cache_data.ts_created = dap_time_now(); // Time of transasction added to ledger
     dap_list_t *l_tist_tmp = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_ALL, &l_tx_item->cache_data.n_outs);
     // If debug mode dump the UTXO
     if (dap_log_level_get() == L_DEBUG && s_debug_more) {
diff --git a/modules/channel/chain/dap_stream_ch_chain.c b/modules/channel/chain/dap_stream_ch_chain.c
index fb38ea7ac..8f89af107 100644
--- a/modules/channel/chain/dap_stream_ch_chain.c
+++ b/modules/channel/chain/dap_stream_ch_chain.c
@@ -25,7 +25,6 @@
 
 #include <stdlib.h>
 #include <stdio.h>
-#include <time.h>
 #include <stdlib.h>
 #include <stddef.h>
 #include <stdint.h>
@@ -44,6 +43,7 @@
 #include "dap_list.h"
 #include "dap_config.h"
 #include "dap_hash.h"
+#include "dap_time.h"
 #include "utlist.h"
 
 #include "dap_worker.h"
@@ -506,7 +506,7 @@ static bool s_sync_in_chains_callback(dap_proc_thread_t *a_thread, void *a_arg)
     dap_hash_fast(l_atom_copy, l_atom_copy_size, &l_atom_hash);
     dap_chain_atom_verify_res_t l_atom_add_res = l_chain->callback_atom_add(l_chain, l_atom_copy, l_atom_copy_size);
     char l_atom_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE] = {[0]='\0'};
-    dap_chain_hash_fast_to_str(&l_atom_hash,l_atom_hash_str,sizeof (l_atom_hash_str)-1 );
+    dap_chain_hash_fast_to_str(&l_atom_hash,l_atom_hash_str,sizeof (l_atom_hash_str));
     switch (l_atom_add_res) {
     case ATOM_PASS:
         if (s_debug_more){
@@ -705,8 +705,8 @@ static bool s_gdb_in_pkt_proc_callback(dap_proc_thread_t *a_thread, void *a_arg)
         const char *l_last_group = l_store_obj->group;
         uint32_t l_last_type = l_store_obj->type;
         bool l_group_changed = false;
-        uint32_t l_time_store_lim = dap_config_get_item_uint32_default(g_config, "resources", "dap_global_db_time_store_limit", 72);
-        uint64_t l_limit_time = l_time_store_lim ? (uint64_t)time(NULL) - l_time_store_lim * 3600 : 0;
+        uint32_t l_time_store_lim_hours = dap_config_get_item_uint32_default(g_config, "resources", "dap_global_db_time_store_limit", 72);
+        uint64_t l_limit_time = l_time_store_lim_hours ? dap_gdb_time_now() - dap_gdb_time_from_sec(l_time_store_lim_hours * 3600) : 0;
 
         for (size_t i = 0; i < l_data_obj_count; i++) {
             // obj to add
diff --git a/modules/common/dap_chain_common.c b/modules/common/dap_chain_common.c
index a7b5043bc..8c4d21e91 100644
--- a/modules/common/dap_chain_common.c
+++ b/modules/common/dap_chain_common.c
@@ -46,14 +46,6 @@
 char        *dap_cvt_uint256_to_str (uint256_t a_uint256);
 uint256_t   dap_cvt_str_to_uint256 (const char *a_256bit_num);
 
-dap_chain_time_t dap_chain_time_now()
-{
-    struct timespec ts;
-    clock_gettime(CLOCK_REALTIME, &ts);
-    dap_chain_time_t ret = ts.tv_sec << 32 | ts.tv_nsec;
-    return ret;
-}
-
 /**
  * @brief dap_chain_hash_to_str
  * @param a_hash
diff --git a/modules/common/dap_chain_datum.c b/modules/common/dap_chain_datum.c
index ca90883f9..52040b3cc 100644
--- a/modules/common/dap_chain_datum.c
+++ b/modules/common/dap_chain_datum.c
@@ -24,6 +24,7 @@
 #include <string.h>
 
 #include "dap_common.h"
+#include "dap_time.h"
 #include "dap_chain_datum.h"
 #include "dap_chain_datum_tx.h"
 #include "dap_chain_datum_tx_items.h"
@@ -394,7 +395,7 @@ bool dap_chain_datum_dump_tx(dap_chain_datum_tx_t *a_datum,
                                                 "\t\t\t value: %s (%s)\n"
                                                 "\t\t\t subtype: %s\n"
                                                 "\t\t SubType:\n",
-                                     dap_ctime_r((time_t*)((dap_chain_tx_out_cond_t*)item)->header.ts_expires, l_tmp_buf),
+                                     dap_ctime_r((dap_time_t*)((dap_chain_tx_out_cond_t*)item)->header.ts_expires, l_tmp_buf),
                                      l_coins_str,
                                      l_value_str,
                                      dap_chain_tx_out_cond_subtype_to_str(((dap_chain_tx_out_cond_t*)item)->header.subtype));
diff --git a/modules/common/include/dap_chain_common.h b/modules/common/include/dap_chain_common.h
index 3c45f11e1..2f273f6e2 100644
--- a/modules/common/include/dap_chain_common.h
+++ b/modules/common/include/dap_chain_common.h
@@ -141,9 +141,6 @@ typedef struct dap_chain_addr{
     dap_chain_hash_fast_t checksum;
 }  DAP_ALIGN_PACKED dap_chain_addr_t;
 
-typedef uint64_t dap_chain_time_t;
-dap_chain_time_t dap_chain_time_now();
-
 #define DAP_CHAIN_NET_SRV_UID_SIZE 8
 
 typedef union {
diff --git a/modules/common/include/dap_chain_datum_tx_out_cond.h b/modules/common/include/dap_chain_datum_tx_out_cond.h
index b1f8a23da..8a328923b 100644
--- a/modules/common/include/dap_chain_datum_tx_out_cond.h
+++ b/modules/common/include/dap_chain_datum_tx_out_cond.h
@@ -26,6 +26,7 @@
 
 #include <stdint.h>
 #include "dap_common.h"
+#include "dap_time.h"
 #include "dap_chain_common.h"
 #include "dap_chain_datum_tx.h"
 
@@ -62,7 +63,7 @@ typedef struct dap_chain_tx_out_cond {
         /// Number of Datoshis ( DAP/10^18 ) to be reserved for service
         uint256_t value;
         /// When time expires this output could be used only by transaction owner
-        dap_chain_time_t ts_expires;
+        dap_time_t ts_expires;
         /// Service uid that only could be used for this out
         dap_chain_net_srv_uid_t srv_uid;
 #if DAP_CHAIN_NET_SRV_UID_SIZE == 8
@@ -122,7 +123,7 @@ typedef struct dap_chain_tx_out_cond_old {      // Obsolete
         /// Number of Datoshis ( DAP/10^9 ) to be reserver for service
         uint64_t value;
         /// When time expires this output could be used only by transaction owner
-        dap_chain_time_t ts_expires;
+        dap_time_t ts_expires;
     } header;
     union {
         /// Structure with specific for service pay condition subtype
diff --git a/modules/consensus/block-ton/dap_chain_cs_block_ton.c b/modules/consensus/block-ton/dap_chain_cs_block_ton.c
index 9927de32f..3aa2d15a8 100644
--- a/modules/consensus/block-ton/dap_chain_cs_block_ton.c
+++ b/modules/consensus/block-ton/dap_chain_cs_block_ton.c
@@ -324,7 +324,7 @@ static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cf
 	l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE;
 	l_session->time_proc_lock = false;
 	
-	dap_chain_time_t l_time = (dap_chain_time_t)time(NULL);
+	dap_time_t l_time = dap_time_now();
 	while (true) {
 		l_time++;
 		if ( (l_time % PVT(l_session->ton)->round_start_multiple_of) == 0) {
@@ -368,7 +368,7 @@ static void s_session_round_start(dap_chain_cs_block_ton_items_t *a_session) {
 	a_session->cur_round.messages_count = 0;
 	a_session->cur_round.submit = false;
 
-	a_session->ts_round_sync_start = (dap_chain_time_t)time(NULL);
+	a_session->ts_round_sync_start = dap_time_now();
 	a_session->cur_round.id.uint64++;
 }
 
@@ -406,7 +406,7 @@ static bool s_session_send_votefor(s_session_send_votefor_data_t *a_data){
 }
 
 static bool s_session_timer() {
-	dap_chain_time_t l_time = (dap_chain_time_t)time(NULL);
+	dap_time_t l_time = dap_time_now();
 	dap_chain_cs_block_ton_items_t *l_session = NULL;
 	DL_FOREACH(s_session_items, l_session) {
 		if ( l_session->time_proc_lock ) {
@@ -501,7 +501,7 @@ static bool s_session_timer() {
 					if ( l_my_number != -1 ) {
 						l_my_number++;
 						if ( (l_time-l_session->ts_round_start) >=
-									(dap_chain_time_t)((PVT(l_session->ton)->next_candidate_delay*l_my_number)+PVT(l_session->ton)->first_message_delay) ) {
+									(dap_time_t)((PVT(l_session->ton)->next_candidate_delay*l_my_number)+PVT(l_session->ton)->first_message_delay) ) {
 							l_session->cur_round.submit = true;
 							s_session_candidate_submit(l_session);
 						}
@@ -509,7 +509,7 @@ static bool s_session_timer() {
 				}
 
 				if ( (l_time-l_session->ts_round_start) >=
-							(dap_chain_time_t)(PVT(l_session->ton)->round_attempt_duration*l_session->attempt_current_number) ) {
+							(dap_time_t)(PVT(l_session->ton)->round_attempt_duration*l_session->attempt_current_number) ) {
 
 					l_session->attempt_current_number++;
 					if ( l_session->attempt_current_number > PVT(l_session->ton)->round_attempts_max ) {
@@ -816,7 +816,7 @@ static bool s_hash_is_null(dap_chain_hash_fast_t *a_hash){
 static bool s_session_round_finish(dap_chain_cs_block_ton_items_t *a_session) {
 
 	a_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE;
-	a_session->ts_round_finish = (dap_chain_time_t)time(NULL);
+	a_session->ts_round_finish = dap_time_now();
 
     size_t l_objs_size = 0;
     dap_global_db_obj_t *l_objs = dap_chain_global_db_gr_load(a_session->gdb_group_store, &l_objs_size);
@@ -1022,7 +1022,7 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
     	goto handler_finish;
     }
 
-    dap_chain_time_t l_time = (dap_chain_time_t)time(NULL);
+    dap_time_t l_time = dap_time_now();
 	l_message->hdr.is_verified=false;
 
     dap_chain_hash_fast_t l_data_hash;
@@ -1769,7 +1769,7 @@ static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_nod
 							DAP_DELETE(l_candidate_sign);
 							
 							l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS;
-							l_session->ts_round_state_commit = (dap_chain_time_t)time(NULL);
+							l_session->ts_round_state_commit = dap_time_now();
 							
 							if (PVT(l_session->ton)->debug)
                                 log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" attempt:%hu Candidate:%s collected PRE_COMMIT more than 2/3 of the validators, so to sent a COMMIT_SIGN",
@@ -1905,7 +1905,7 @@ static void s_message_send(dap_chain_cs_block_ton_items_t *a_session, uint8_t a_
 						DAP_NEW_SIZE(dap_chain_cs_block_ton_message_t, l_message_size);
 	l_message->hdr.id.uint64 = (uint64_t)a_session->cur_round.messages_count;
 	l_message->hdr.chain_id.uint64 = a_session->chain->id.uint64;
-	l_message->hdr.ts_created = (dap_chain_time_t)time(NULL);
+	l_message->hdr.ts_created = dap_time_now();
 	l_message->hdr.type = a_message_type;
 	memcpy(&l_message->hdr.sender_node_addr,
 				dap_chain_net_get_cur_addr(l_net), sizeof(dap_chain_node_addr_t));
diff --git a/modules/consensus/block-ton/include/dap_chain_cs_block_ton.h b/modules/consensus/block-ton/include/dap_chain_cs_block_ton.h
index 821714b28..0ad67933e 100644
--- a/modules/consensus/block-ton/include/dap_chain_cs_block_ton.h
+++ b/modules/consensus/block-ton/include/dap_chain_cs_block_ton.h
@@ -73,10 +73,10 @@ typedef struct dap_chain_cs_block_ton_items {
 	dap_chain_node_addr_t *attempt_coordinator; // validator-coordinator in current attempt
 	uint16_t attempt_current_number;
 
-	dap_chain_time_t ts_round_sync_start; // time start sync
-	dap_chain_time_t ts_round_start; // time round-start
-	dap_chain_time_t ts_round_state_commit;
-	dap_chain_time_t ts_round_finish;
+	dap_time_t ts_round_sync_start; // time start sync
+	dap_time_t ts_round_start; // time round-start
+	dap_time_t ts_round_state_commit;
+	dap_time_t ts_round_finish;
 
 	char * gdb_group_setup;
 	char * gdb_group_store;
@@ -104,7 +104,7 @@ typedef struct dap_chain_cs_block_ton_message_hdr {
 	size_t sign_size;
 	size_t message_size;
 
-	dap_chain_time_t ts_created;
+	dap_time_t ts_created;
 	//dap_chain_cs_block_ton_round_id_t round_id;
 
 	dap_chain_node_addr_t sender_node_addr;
@@ -135,7 +135,7 @@ typedef struct dap_chain_cs_block_ton_message_getinfo {
 
 // technical messages
 typedef struct dap_chain_cs_block_ton_message_startsync {
-	dap_chain_time_t ts;
+	dap_time_t ts;
 	dap_chain_cs_block_ton_round_id_t round_id;
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_startsync_t;
 
@@ -202,7 +202,7 @@ typedef struct dap_chain_cs_block_ton_store_hdr {
 	size_t candidate_size;
 	dap_chain_cs_block_ton_round_id_t round_id;
 	dap_chain_hash_fast_t candidate_hash;
-	dap_chain_time_t ts_candidate_submit;
+	dap_time_t ts_candidate_submit;
 } DAP_ALIGN_PACKED dap_chain_cs_block_ton_store_hdr_t;
 
 typedef struct dap_chain_cs_block_ton_store {
diff --git a/modules/global-db/dap_chain_global_db.c b/modules/global-db/dap_chain_global_db.c
index dfc00fedc..9ed81eefd 100644
--- a/modules/global-db/dap_chain_global_db.c
+++ b/modules/global-db/dap_chain_global_db.c
@@ -26,13 +26,15 @@
 #include <stdint.h>
 #include <pthread.h>
 #include <errno.h>
-#include <time.h>
 #include <assert.h>
+#include <zip.h>
 //#include <string.h>
 #include "dap_chain_global_db.h"
 #include "uthash.h"
 #include "dap_strfuncs.h"
+#include "dap_file_utils.h"
 #include "dap_chain_common.h"
+#include "dap_time.h"
 
 #ifdef WIN32
 #include "registry.h"
@@ -207,6 +209,62 @@ size_t i;
     DAP_DELETE(a_objs);                                     /* Finaly kill the the array */
 }
 
+
+static int s_check_db_version(dap_config_t *g_config)
+{
+    int res = 0;
+    // Read current version of database
+    size_t l_gdb_version_len = 0;
+    uint16_t l_gdb_version = 0;
+    uint16_t *l_gdb_version_p = (uint16_t*) dap_chain_global_db_get("gdb_version", &l_gdb_version_len);
+    if(l_gdb_version_p && l_gdb_version_len == sizeof(uint16_t)) {
+        l_gdb_version = *l_gdb_version_p;
+    }
+    if(l_gdb_version < GDB_VERSION) {
+        log_it(L_NOTICE, "GlobalDB version %d, but %d required. The current database will be recreated",l_gdb_version, GDB_VERSION);
+        dap_chain_global_db_deinit();
+        // Database path
+        const char *l_storage_path = dap_config_get_item_str(g_config, "resources", "dap_global_db_path");
+        // Delete database
+        if(dap_file_test(l_storage_path) || dap_dir_test(l_storage_path)) {
+            // Backup filename: backup_global_db_ver.X_DATE_TIME.zip
+            char now[255];
+            time_t t = time(NULL);
+            strftime(now, 200, "%y.%m.%d-%H_%M_%S", localtime(&t));
+            char *l_output_file_name = dap_strdup_printf("backup_%s_ver.%d_%s.zip", dap_path_get_basename(l_storage_path), l_gdb_version, now);
+            char *l_output_file_path = dap_build_filename(l_storage_path, "../", l_output_file_name, NULL);
+
+            // Create backup
+            if(zip_directory(l_storage_path, l_output_file_path)) {
+                // Delete database file or directory
+                dap_rm_rf(l_storage_path);
+            }
+            else{
+                log_it(L_ERROR, "Can't backup GlobalDB version %d", l_gdb_version);
+                return -2;
+            }
+            DAP_DELETE(l_output_file_name);
+            DAP_DELETE(l_output_file_path);
+        }
+        // Reinitialize database
+        res = dap_chain_global_db_init(g_config);
+        // Save current db version
+        if(!res) {
+            l_gdb_version = GDB_VERSION;
+            dap_chain_global_db_set("gdb_version", &l_gdb_version, sizeof(uint16_t));
+        }
+    } else if(l_gdb_version > GDB_VERSION) {
+        log_it(L_ERROR, "GlobalDB version %d is newer than supported version %d", l_gdb_version, GDB_VERSION);
+        res  =-1;
+    }
+    else {
+        log_it(L_NOTICE, "GlobalDB version %d", l_gdb_version);
+    }
+    if(l_gdb_version_p)
+        DAP_DELETE(l_gdb_version_p);
+    return res;
+}
+
 /**
  * @brief Initializes a database by g_config structure.
  * @note You should call this function before calling any other functions in this library.
@@ -234,13 +292,18 @@ int dap_chain_global_db_init(dap_config_t * g_config)
 
     if( res != 0 )
         log_it(L_CRITICAL, "Hadn't initialized db driver \"%s\" on path \"%s\"", l_driver_name, l_storage_path);
-    else
-        log_it(L_NOTICE, "GlobalDB initialized");
-
+    else {
+        static bool is_check_version = false;
+        if(!is_check_version){
+            is_check_version = true;
+            res = s_check_db_version(g_config);
+        }
+        if(!res)
+            log_it(L_NOTICE, "GlobalDB initialized");
+    }
     return res;
 }
 
-
 static void s_clear_sync_grp(void *a_elm)
 {
     dap_sync_group_item_t *l_item = (dap_sync_group_item_t *)a_elm;
@@ -375,7 +438,7 @@ uint8_t * dap_chain_global_db_get(const char *a_key, size_t *a_data_len_out)
  * @param a_timestamp an object time stamp
  * @return True if successful, false otherwise.
  */
-static int global_db_gr_del_add(const char *a_key, const char *a_group, time_t a_timestamp)
+static int global_db_gr_del_add(const char *a_key, const char *a_group, uint64_t a_timestamp)
 {
 dap_store_obj_t store_data = {0};
 char	l_group[DAP_DB_K_MAXGRPLEN];
@@ -428,13 +491,13 @@ int	l_res = 0;
  * @param a_key an object key string, looked like "0x8FAFBD00B..."
  * @return If successful, a time stamp, otherwise 0.
  */
-time_t global_db_gr_del_get_timestamp(const char *a_group, const char *a_key)
+uint64_t global_db_gr_del_get_timestamp(const char *a_group, const char *a_key)
 {
-time_t l_timestamp = 0;
-dap_store_obj_t store_data = {0};
-char    l_group [512];
-size_t l_count_out = 0;
-dap_store_obj_t *l_obj;
+    uint64_t l_timestamp = 0;
+    dap_store_obj_t store_data = { 0 };
+    char l_group[512];
+    size_t l_count_out = 0;
+    dap_store_obj_t *l_obj;
 
     if(!a_key)
         return l_timestamp;
@@ -504,34 +567,34 @@ dap_store_obj_t* dap_chain_global_db_cond_load(const char *a_group, uint64_t a_f
 /**
  * @brief Gets all data from a database by a_group.
  * @param a_group a group name string
- * @param a_data_size[in] a poiter to return a number of data
- * @param a_data_size[out] a number of data
+ * @param a_records_count_out[in] a poiter to return a number of data
+ * @param a_records_count_out[out] a number of data
  * @return If successful, a pointer to data; otherwise NULL.
  */
-dap_global_db_obj_t* dap_chain_global_db_gr_load(const char *a_group, size_t *a_data_size_out)
+dap_global_db_obj_t* dap_chain_global_db_gr_load(const char *a_group, size_t *a_records_count_out)
 {
     size_t l_count = 0;
-    if (!a_data_size_out)
-        a_data_size_out = &l_count;
-    dap_store_obj_t *l_store_obj = dap_chain_global_db_driver_read(a_group, NULL, a_data_size_out);
+    if (!a_records_count_out)
+        a_records_count_out = &l_count;
+    dap_store_obj_t *l_store_obj = dap_chain_global_db_driver_read(a_group, NULL, a_records_count_out);
     if(!l_store_obj)
         return NULL;
 
     dap_global_db_obj_t *l_data = DAP_NEW_Z_SIZE(dap_global_db_obj_t,
-                                                 (*a_data_size_out + 1) * sizeof(dap_global_db_obj_t)); // last item in mass must be zero
+                                                 (*a_records_count_out + 1) * sizeof(dap_global_db_obj_t)); // last item in mass must be zero
     if (!l_data) {
-        dap_store_obj_free(l_store_obj, *a_data_size_out);
+        dap_store_obj_free(l_store_obj, *a_records_count_out);
         return NULL;
     }
 
-    for(size_t i = 0; i < *a_data_size_out; i++) {
+    for(size_t i = 0; i < *a_records_count_out; i++) {
         l_data[i] = (dap_global_db_obj_t) {
                 .key = dap_strdup(l_store_obj[i].key),
                 .value_len = l_store_obj[i].value_len,
                 .value = DAP_DUP_SIZE(l_store_obj[i].value, l_store_obj[i].value_len)
         };
     }
-    dap_store_obj_free(l_store_obj, *a_data_size_out);
+    dap_store_obj_free(l_store_obj, *a_records_count_out);
     return l_data;
 }
 
@@ -589,7 +652,7 @@ bool dap_chain_global_db_flags_gr_set(const char *a_key, const void *a_value, si
     store_data.value_len = (a_value_len == (size_t) -1) ? dap_strlen(a_value) : a_value_len;
     store_data.value = store_data.value_len ? (void *)a_value : NULL;
     store_data.group = (char *)a_group;
-    store_data.timestamp = time(NULL);
+    store_data.timestamp = dap_gdb_time_now();
 
     lock();
     int l_res = dap_chain_global_db_driver_add(&store_data, 1);
@@ -664,7 +727,7 @@ dap_store_obj_t store_data = {0};
     if (a_key) {
         if (l_res >= 0) {
             // add to Del group
-            global_db_gr_del_add(a_key, store_data.group, time(NULL));
+            global_db_gr_del_add(a_key, store_data.group, dap_gdb_time_now());
         }
         // do not add to history if l_res=1 (already deleted)
         if (!l_res) {
@@ -721,9 +784,9 @@ dap_store_obj_t *l_store_obj;
  */
 bool dap_chain_global_db_gr_save(dap_global_db_obj_t* a_objs, size_t a_objs_count, const char *a_group)
 {
-dap_store_obj_t l_store_data[a_objs_count], *store_data_cur;
-dap_global_db_obj_t *l_obj_cur;
-time_t l_timestamp = time(NULL);
+    dap_store_obj_t l_store_data[a_objs_count], *store_data_cur;
+    dap_global_db_obj_t *l_obj_cur;
+    uint64_t l_timestamp = dap_gdb_time_now();
 
     store_data_cur = l_store_data;
     l_obj_cur = a_objs;
diff --git a/modules/global-db/dap_chain_global_db_remote.c b/modules/global-db/dap_chain_global_db_remote.c
index a4eef57f8..d32da07d8 100644
--- a/modules/global-db/dap_chain_global_db_remote.c
+++ b/modules/global-db/dap_chain_global_db_remote.c
@@ -1,6 +1,5 @@
 #include <string.h>
 #include <stdlib.h>
-#include <time.h>
 
 #include "dap_chain_global_db.h"
 #include "dap_chain_global_db_remote.h"
@@ -8,6 +7,7 @@
 #include "dap_strfuncs.h"
 #include "dap_string.h"
 #include "dap_chain.h"
+#include "dap_time.h"
 
 #define LOG_TAG "dap_chain_global_db_remote"
 
@@ -40,8 +40,8 @@ uint64_t dap_db_log_get_group_last_id(const char *a_group_name)
 static void *s_list_thread_proc(void *arg)
 {
     dap_db_log_list_t *l_dap_db_log_list = (dap_db_log_list_t *)arg;
-    uint32_t l_time_store_lim = dap_config_get_item_uint32_default(g_config, "resources", "dap_global_db_time_store_limit", 72);
-    uint64_t l_limit_time = l_time_store_lim ? (uint64_t)time(NULL) - l_time_store_lim * 3600 : 0;
+    uint32_t l_time_store_lim_hours = dap_config_get_item_uint32_default(g_config, "resources", "dap_global_db_time_store_limit", 72);
+    uint64_t l_limit_time = l_time_store_lim_hours ? dap_gdb_time_now() - dap_gdb_time_from_sec(l_time_store_lim_hours * 3600) : 0;
     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_group_cur = (dap_db_log_list_group_t *)l_groups->data;
         char *l_del_group_name_replace = NULL;
@@ -357,11 +357,11 @@ bool dap_db_set_cur_node_addr(uint64_t a_address, char *a_net_name )
 }
 
 /**
- * @brief Sets an adress of a current node and expire time.
+ * @brief Sets an address of a current node and expire time.
  *
- * @param a_address an adress of a current node
+ * @param a_address an address of a current node
  * @param a_net_name a net name string
- * @return Returns true if siccessful, otherwise false
+ * @return Returns true if successful, otherwise false
  */
 bool dap_db_set_cur_node_addr_exp(uint64_t a_address, char *a_net_name )
 {
diff --git a/modules/global-db/include/dap_chain_global_db.h b/modules/global-db/include/dap_chain_global_db.h
index 94ec521b8..695cff2a3 100644
--- a/modules/global-db/include/dap_chain_global_db.h
+++ b/modules/global-db/include/dap_chain_global_db.h
@@ -10,6 +10,7 @@
 #include "dap_list.h"
 #include "dap_chain_common.h"
 
+#define GDB_VERSION 1
 #define GROUP_LOCAL_NODE_LAST_ID "local.node.last_id"
 #define GROUP_LOCAL_GENERAL "local.general"
 #define GROUP_LOCAL_NODE_ADDR "local.node-addr"
@@ -93,7 +94,7 @@ bool dap_chain_global_db_del(char *a_key);
 /**
  * Get timestamp of the deleted entry
  */
-time_t global_db_gr_del_get_timestamp(const char *a_group, const char *a_key);
+uint64_t global_db_gr_del_get_timestamp(const char *a_group, const char *a_key);
 
 /**
  * Read the entire database into an array of size bytes
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 e44ebee5c..fd0463e09 100644
--- a/modules/global-db/include/dap_chain_global_db_driver.h
+++ b/modules/global-db/include/dap_chain_global_db_driver.h
@@ -24,6 +24,7 @@
 
 #pragma once
 
+#include "dap_time.h"
 #include "dap_proc_thread.h"
 #include "dap_list.h"
 
@@ -43,7 +44,7 @@ enum RECORD_FLAGS {
 
 typedef struct dap_store_obj {
     uint64_t id;
-    uint64_t timestamp;
+    dap_gdb_time_t timestamp;
     uint32_t type;                              /* Operation type: ADD/DELETE, see DAP_DB$K_OPTYPE_* constants */
     uint8_t flags;                              /* RECORD_FLAGS */
     char *group;
@@ -56,7 +57,7 @@ typedef struct dap_store_obj {
 } dap_store_obj_t, *pdap_store_obj_t;
 
 typedef struct dap_store_obj_pkt {
-    uint64_t timestamp;
+    dap_gdb_time_t timestamp;
     uint64_t data_size;
     uint32_t obj_count;
     uint8_t data[];
diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c
index 4c0afa65f..7359d64b2 100644
--- a/modules/net/srv/dap_chain_net_srv.c
+++ b/modules/net/srv/dap_chain_net_srv.c
@@ -466,7 +466,7 @@ static int s_cli_net_srv( int argc, char **argv, char **a_str_reply)
                 dap_chain_net_srv_uid_t l_srv_uid={{0}};
                 dap_chain_node_addr_t l_node_addr={0};
                 dap_chain_hash_fast_t l_tx_cond_hash={{0}};
-                dap_chain_time_t l_expires=0; // TS when the service expires
+                dap_time_t l_expires=0; // TS when the service expires
                 uint256_t l_price = {};
                 char l_price_token[DAP_CHAIN_TICKER_SIZE_MAX]={0};
                 dap_chain_net_srv_price_unit_uid_t l_price_unit={{0}};
@@ -484,7 +484,7 @@ static int s_cli_net_srv( int argc, char **argv, char **a_str_reply)
 
 
                 if (l_expires_str)
-                    l_expires = (dap_chain_time_t ) atoll( l_expires_str);
+                    l_expires = (dap_time_t ) atoll( l_expires_str);
                 l_srv_uid.uint64 = (uint64_t) atoll( l_srv_uid_str);
                 if (l_node_addr_str){
 
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index 07406de49..9d4b146e4 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -250,7 +250,7 @@ char * dap_chain_net_srv_order_create(
         uint256_t a_price, //  service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT  for one unit.
         dap_chain_net_srv_price_unit_uid_t a_price_unit, // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
         const char a_price_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-        dap_chain_time_t a_expires, // TS when the service expires
+        dap_time_t a_expires, // TS when the service expires
         const uint8_t *a_ext,
         uint32_t a_ext_size,
         const char *a_region,
@@ -277,7 +277,7 @@ dap_chain_net_srv_order_t *dap_chain_net_srv_order_compose(
         uint256_t a_price, //  service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT  for one unit.
         dap_chain_net_srv_price_unit_uid_t a_price_unit, // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
         const char a_price_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-        dap_chain_time_t a_expires, // TS when the service expires
+        dap_time_t a_expires, // TS when the service expires
         const uint8_t *a_ext,
         uint32_t a_ext_size,
         const char *a_region,
@@ -302,7 +302,7 @@ dap_chain_net_srv_order_t *dap_chain_net_srv_order_compose(
     l_order->version = 3;
     l_order->srv_uid = a_srv_uid;
     l_order->direction = a_direction;
-    l_order->ts_created = (dap_chain_time_t) time(NULL);
+    l_order->ts_created = dap_time_now();
 
     if ( a_node_addr.uint64)
         l_order->node_addr.uint64 = a_node_addr.uint64;
diff --git a/modules/net/srv/include/dap_chain_net_srv_order.h b/modules/net/srv/include/dap_chain_net_srv_order.h
index 0923e8b8f..e405b6b43 100644
--- a/modules/net/srv/include/dap_chain_net_srv_order.h
+++ b/modules/net/srv/include/dap_chain_net_srv_order.h
@@ -38,8 +38,8 @@ typedef struct dap_chain_net_srv_order_old
     dap_chain_node_addr_t node_addr; // Node address that servs the order (if present)
     dap_chain_hash_fast_t tx_cond_hash; // Hash index of conditioned transaction attached with order
     dap_chain_net_srv_price_unit_uid_t price_unit; // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
-    dap_chain_time_t ts_created;
-    dap_chain_time_t ts_expires;
+    dap_time_t ts_created;
+    dap_time_t ts_expires;
     uint64_t price; //  service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT  for one unit.
     char price_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; // Token ticker to pay for service
     //uint8_t continent;
@@ -60,8 +60,8 @@ typedef struct dap_chain_net_srv_order
     dap_chain_node_addr_t node_addr; // Node address that servs the order (if present)
     dap_chain_hash_fast_t tx_cond_hash; // Hash index of conditioned transaction attached with order
     dap_chain_net_srv_price_unit_uid_t price_unit; // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
-    dap_chain_time_t ts_created;
-    dap_chain_time_t ts_expires;
+    dap_time_t ts_created;
+    dap_time_t ts_expires;
     uint256_t price; //  service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT  for one unit.
     char price_ticker[DAP_CHAIN_TICKER_SIZE_MAX]; // Token ticker to pay for service
     uint32_t ext_size;
@@ -122,7 +122,7 @@ char *dap_chain_net_srv_order_create(dap_chain_net_t * a_net,
         uint256_t a_price, //  service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT  for one unit.
         dap_chain_net_srv_price_unit_uid_t a_price_unit, // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
         const char a_price_ticker[],
-        dap_chain_time_t a_expires, // TS when the service expires
+        dap_time_t a_expires, // TS when the service expires
         const uint8_t *a_ext,
         uint32_t a_ext_size,
         const char *a_region,
@@ -139,7 +139,7 @@ dap_chain_net_srv_order_t *dap_chain_net_srv_order_compose(
         uint256_t a_price, //  service price in datoshi, for SERV_CLASS_ONCE ONCE for the whole service, for SERV_CLASS_PERMANENT  for one unit.
         dap_chain_net_srv_price_unit_uid_t a_price_unit, // Unit of service (seconds, megabytes, etc.) Only for SERV_CLASS_PERMANENT
         const char a_price_ticker[DAP_CHAIN_TICKER_SIZE_MAX],
-        dap_chain_time_t a_expires, // TS when the service expires
+        dap_time_t a_expires, // TS when the service expires
         const uint8_t *a_ext,
         uint32_t a_ext_size,
         const char *a_region,
diff --git a/modules/type/blocks/include/dap_chain_block.h b/modules/type/blocks/include/dap_chain_block.h
index 32d35388a..d7500cd91 100644
--- a/modules/type/blocks/include/dap_chain_block.h
+++ b/modules/type/blocks/include/dap_chain_block.h
@@ -22,6 +22,7 @@
 */
 #pragma once
 #include "dap_common.h"
+#include "dap_time.h"
 #include "dap_math_ops.h"
 #include "dap_hash.h"
 #include "dap_cert.h"
@@ -46,7 +47,7 @@ typedef struct dap_chain_block_hdr{
     int32_t version; /// @param version @brief block version (be carefull, signed value, as Bitcoin has)
     dap_chain_cell_id_t cell_id; /// Cell id
     dap_chain_id_t chain_id; /// Chain id
-    dap_chain_time_t ts_created; /// @param timestamp @brief Block create time timestamp
+    dap_time_t ts_created; /// @param timestamp @brief Block create time timestamp
     uint16_t meta_count; // Meta values number
     uint16_t datum_count; // Datums's count
     dap_chain_hash_fast_t merkle;
-- 
GitLab


From 14ae0b6f5a0bceb32f575e7eb1482c96bca1a88f Mon Sep 17 00:00:00 2001
From: Alexander Lysikov <alexander.lysikov@demlabs.net>
Date: Wed, 20 Apr 2022 17:49:15 +0500
Subject: [PATCH 3/3] comment unused code for win32

---
 dap-sdk/core/src/dap_file_utils.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/dap-sdk/core/src/dap_file_utils.c b/dap-sdk/core/src/dap_file_utils.c
index 8dfbe1b1d..ccc1c8c44 100755
--- a/dap-sdk/core/src/dap_file_utils.c
+++ b/dap-sdk/core/src/dap_file_utils.c
@@ -1302,7 +1302,7 @@ char* dap_get_current_dir(void)
 
 static const char* dap_dir_read_name(DIR *dir)
 {
-#ifdef _WIN32
+#ifdef _WIN32_MSVS
   char *utf8_name;
   struct _wdirent *wentry;
 #else
@@ -1311,7 +1311,7 @@ static const char* dap_dir_read_name(DIR *dir)
 
     dap_return_val_if_fail(dir != NULL, NULL);
 
-#ifdef _WIN32
+#ifdef _WIN32_MSVS
     while(1)
     {
         wentry = _wreaddir(dir->wdirp);
-- 
GitLab