diff --git a/CMakeLists.txt b/CMakeLists.txt
index e644e875a0268e5803b7ade17c50af8b86eac13b..6ba5ba01588a009b8e19fd9dadadf27ed01d0e1b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,13 +1,8 @@
 cmake_minimum_required(VERSION 2.8)
 project (dap_chain_global_db)
   
-set(DAP_CHAIN_GLOBAL_DB_SRC
-    dap_chain_global_db.c
-   )
-
-set(DAP_CHAIN_GLOBAL_DB_HDR
-    dap_chain_global_db.h
-   )
+file(GLOB DAP_CHAIN_GLOBAL_DB_SRC *.c)
+file(GLOB DAP_CHAIN_GLOBAL_DB_HDR *.h)
 
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_GLOBAL_DB_SRC} ${DAP_CHAIN_GLOBAL_DB_HDR})
 
diff --git a/dap_chain_global_db.c b/dap_chain_global_db.c
index 77823a1c8e1fd8578702d767b28e91e360d45e98..9e5f777c78d090a3daa80af180dad9e0653975a0 100644
--- a/dap_chain_global_db.c
+++ b/dap_chain_global_db.c
@@ -1,251 +1,55 @@
+#include "dap_chain_global_db_pvt.h"
+
 #include <string.h>
 #include <stdio.h>
-//#include "talloc.h"
-#include "dap_chain_global_db.h"
-
-#define LOG_TAG "dap_global_db"
-#define TDB_PREFIX_LEN 7
-
-/* add single entry which is not supposed to be an array
-    e.g.: dap_db_add_record(&store_obj)
-*/
-#define CALL2(a, b, ...) (a), (b)
-#define dap_db_add_record(...) dap_db_merge(CALL2(__VA_ARGS__, 0))
-
-int dap_db_init(const char *path) {
-    mem_ctx = talloc_new(NULL);
-    if (ldb_global_init() != 0) {
-        log_it(L_ERROR, "Couldn't initialize LDB's global information");
-        return -1;
-    };
-    if ((ldb = ldb_init(mem_ctx, NULL)) != LDB_SUCCESS) {
-        log_it(L_INFO, "ldb context initialized");
-        char tdb_path[strlen(path) + TDB_PREFIX_LEN];
-        memset(tdb_path, '\0', strlen(path) + TDB_PREFIX_LEN);
-        strcat(tdb_path, "tdb://"); // using tdb for simplicity, no need for separate LDAP server
-        strcat(tdb_path, path);
-        struct ldb_result *data_message;
-        if (ldb_connect(ldb, tdb_path, 0, NULL) != LDB_SUCCESS) {
-            log_it(L_ERROR, "Couldn't connect to database");
-            return 1;
-        }
-        dap_db_path = strdup(tdb_path);
-        const char *query = "(dn=*)";
-        if (ldb_search(ldb, mem_ctx, &data_message, NULL, LDB_SCOPE_DEFAULT, NULL, query) != LDB_SUCCESS) {
-            log_it(L_ERROR, "Database querying failed");
-            return 2;
-        }
-        struct ldb_message *msg;
-        if (data_message->count == 0) {
-            // level 1: section record
-            msg = ldb_msg_new(ldb);
-            msg->dn = ldb_dn_new(mem_ctx, ldb,      "dc=kelvin_nodes");
-            ldb_msg_add_string(msg, "dc",           "kelvin_nodes");
-            ldb_msg_add_string(msg, "objectClass",  "top");
-            ldb_msg_add_string(msg, "objectClass",  "section");
-            dap_db_add_msg(msg);
-            talloc_free(msg->dn);
-            talloc_free(msg);
-
-            // level 2: group record
-            msg = ldb_msg_new(ldb);
-            msg->dn = ldb_dn_new(mem_ctx, ldb,      "ou=addrs_leased,dc=kelvin_nodes");
-            ldb_msg_add_string(msg, "ou",           "addrs_leased");
-            ldb_msg_add_string(msg, "objectClass",  "group");
-            ldb_msg_add_string(msg, "description",  "Whitelist of Kelvin blockchain nodes");
-            dap_db_add_msg(msg);
-            talloc_free(msg->dn);
-            talloc_free(msg);
-        }
-        talloc_free(data_message);
-        return 0;
-    }
-    else {
-        log_it(L_ERROR, "Couldn't initialize LDB context");
-        return -2;
-    }
-}
 
-int dap_db_add_msg(struct ldb_message *msg) {
-    if (ldb_msg_sanity_check(ldb, msg) != LDB_SUCCESS) {
-        log_it(L_ERROR, "LDB message is inconsistent: %s", ldb_errstring(ldb) );
-        return -1;
-    }
-    ldb_transaction_start(ldb);
-    int status = ldb_add(ldb, msg);
-    if (status != LDB_SUCCESS) {
-        if (status == LDB_ERR_ENTRY_ALREADY_EXISTS) {
-            log_it(L_INFO, "Entry %s already present, skipped", ldb_dn_get_linearized(msg->dn) );
-        }
-        else {
-            log_it(L_ERROR, "LDB adding error: %s", ldb_errstring(ldb) );
-        }
-        ldb_transaction_cancel(ldb);
-        return -2;
-    }
-    else {
-        ldb_transaction_commit(ldb);
-        log_it(L_INFO, "Entry %s added", ldb_dn_get_linearized(msg->dn) );
-        return 0;
+int dap_chain_global_db_init(const char *a_storage_path)
+{
+    if(a_storage_path)
+    {
+        int res = dap_db_init(a_storage_path);
+        return res;
     }
+    return -1;
 }
 
-/* path is supposed to have been obtained by smth like
-    dap_config_get_item_str(g_config, "resources", "dap_global_db_path");
-*/
-pdap_store_obj_t dap_db_read_data(void) {
-    struct ldb_result *data_message;
-    const char *query = "(objectClass=addr_leased)";
-    if (ldb_connect(ldb, dap_db_path, LDB_FLG_RDONLY, NULL) != LDB_SUCCESS) {
-        log_it(L_ERROR, "Couldn't connect to database");
-        return NULL;
-    }
-    if (ldb_search(ldb, NULL, &data_message, NULL, LDB_SCOPE_DEFAULT, NULL, query) != LDB_SUCCESS) {
-        log_it(L_ERROR, "Database querying failed");
-        return NULL;
-    }
-    log_it(L_INFO, "Obtained binary data, %d entries", data_message->count);
-
-    pdap_store_obj_t store_data =DAP_NEW_Z_SIZE(dap_store_obj_t,data_message->count * sizeof(struct dap_store_obj) );
-    if (store_data != NULL) {
-        log_it(L_INFO, "We're about to put entries into store objects");
-    }
-    else {
-        log_it(L_ERROR, "Couldn't allocate memory, store objects unobtained");
-        talloc_free(data_message);
-        return NULL;
-    }
-    dap_store_len = data_message->count;
-    int q;
-    for (q = 0; q < dap_store_len; ++q) {
-        store_data[q].section = "kelvin_nodes";
-        store_data[q].group = "addrs_leased";
-        store_data[q].type = 1;
-        store_data[q].key = strdup(ldb_msg_find_attr_as_string(data_message->msgs[q], "cn", NULL));
-        store_data[q].value = strdup(ldb_msg_find_attr_as_string(data_message->msgs[q], "time", NULL));
-        log_it(L_INFO, "Record %s stored successfully", ldb_dn_get_linearized(data_message->msgs[q]->dn) );
-    }
-    talloc_free(data_message);
-    return store_data;
+void dap_chain_global_db_deinit(void)
+{
+    dap_db_deinit();
 }
 
-/* Get the entire content without using query expression
- * This function is highly dissuaded from being used
- * */
-pdap_store_obj_t dap_db_read_file_data(const char *path) {
-    struct ldb_ldif *ldif_msg;
-    FILE *fs = fopen(path, "r");
-    if (!fs) {
-        log_it(L_ERROR, "Can't open file %s", path);
-        return NULL;
-    }
-    pdap_store_obj_t store_data = (pdap_store_obj_t)malloc(256 * sizeof(dap_store_obj_t));
-    if (store_data != NULL) {
-        log_it(L_INFO, "We're about to put entries in store objects");
-    }
-    else {
-        log_it(L_ERROR, "Couldn't allocate memory, store objects unobtained");
+/**
+ * get entry from
+ */
+char * dap_chain_global_db_get(const char *a_key)
+{
+    char *str = NULL;
+    int count = 0;
+    if(!a_key)
         return NULL;
-    }
-
-    int q = 0;
-    for (ldif_msg = ldb_ldif_read_file(ldb, fs); ldif_msg; ldif_msg = ldb_ldif_read_file(ldb, fs), q++) {
-        if (q % 256 == 0) {
-            store_data = (pdap_store_obj_t)realloc(store_data, (q + 256) * sizeof(dap_store_obj_t));
-        }
-        /* if (ldif_msg->changetype == LDB_CHANGETYPE_ADD) {
-          / ... /
-        } */ // in case we gonna use extra LDIF functionality
-        const char *key = ldb_msg_find_attr_as_string(ldif_msg->msg, "cn", NULL);
-        if (key != NULL) {
-            store_data[q].section = "kelvin_nodes";
-            store_data[q].group = "addrs_leased";
-            store_data[q].type = 1;
-            store_data[q].key = strdup(key);
-            store_data[q].value = strdup(ldb_msg_find_attr_as_string(ldif_msg->msg, "time", NULL));
-            log_it(L_INFO, "Record %s stored successfully", ldb_dn_get_linearized(ldif_msg->msg->dn) );
-        }
-        ldb_ldif_read_free(ldb, ldif_msg);
-    }
-    return store_data;
+    int a = strlen("(cn=key2)(objectClass=addr_leased)");
+    char query[32 + strlen(a_key)];
+    sprintf(query, "(cn=%s)(objectClass=addr_leased)", a_key);
+    pdap_store_obj_t store_data = dap_db_read_data(query, &count); //"(objectClass=addr_leased),cn=key1");
+    if(count == 1 && store_data && !strcmp(store_data->key, a_key))
+        str = (store_data->value) ? strdup(store_data->value) : NULL;
+    dab_db_free_pdap_store_obj_t(store_data);
+    return str;
+}
+
+bool dap_chain_global_db_set(const char *a_key, const char *a_value)
+{
+    pdap_store_obj_t store_data = DAP_NEW_Z_SIZE(dap_store_obj_t, sizeof(struct dap_store_obj));
+    store_data->key = (char*) a_key;
+    store_data->value = (char*) a_value;
+    int res = dap_db_merge(store_data, 1);
+    DAP_DELETE(store_data);
+    if(!res)
+        return true;
+    return false;
 }
 
 /*
- * Add multiple entries received from remote node to local database.
- * Since we don't know the size, it must be supplied too
+ dap_chain_global_db_load ()
+ dap_chain_global_db_save()
  */
-int dap_db_merge(pdap_store_obj_t store_obj, int dap_store_size) {
-    if (store_obj == NULL) {
-        log_it(L_ERROR, "Invalid Dap store objects passed");
-        return -1;
-    }
-    if (ldb_connect(ldb, dap_db_path, 0, NULL) != LDB_SUCCESS) {
-        log_it(L_ERROR, "Couldn't connect to database");
-        return -2;
-    }
-    log_it(L_INFO, "We're about to put %d records into database", dap_store_size);
-    struct ldb_message *msg;
-    int q;
-    if (dap_store_size == 0) {
-        dap_store_size = 1;
-    }
-    for (q = 0; q < dap_store_size; q++) {
-        // level 3: leased address, single whitelist entity
-        msg = ldb_msg_new(ldb);
-        char dn[128];
-        memset(dn, '\0', 128);
-        strcat(dn, "cn=");
-        strcat(dn, store_obj[q].key);
-        strcat(dn, ",ou=addrs_leased,dc=kelvin_nodes");
-        msg->dn = ldb_dn_new(mem_ctx, ldb, dn);
-        ldb_msg_add_string(msg, "cn", store_obj[q].key);
-        ldb_msg_add_string(msg, "objectClass", "addr_leased");
-        ldb_msg_add_string(msg, "description", "Approved Kelvin node");
-        ldb_msg_add_string(msg, "time", store_obj[q].value);
-        dap_db_add_msg(msg);
-        talloc_free(msg->dn);
-        talloc_free(msg);
-    }
-    return 0;
-}
-
-/* serialization */
-dap_store_obj_pkt_t *dap_store_packet_single(pdap_store_obj_t store_obj) {
-    dap_store_obj_pkt_t *pkt =
-            (dap_store_obj_pkt_t*)calloc(1, sizeof(int) + 4 + strlen(store_obj->group) + strlen(store_obj->key) + strlen(store_obj->section) + strlen(store_obj->value));
-    pkt->grp_size = strlen(store_obj->group) + 1;
-    pkt->name_size = strlen(store_obj->key) + 1;
-    pkt->sec_size = strlen(store_obj->section) + 1;
-    pkt->type = store_obj->type;
-    memcpy(pkt->data, &store_obj->section, pkt->sec_size);
-    memcpy(pkt->data+pkt->sec_size, &store_obj->group, pkt->grp_size);
-    memcpy(pkt->data+pkt->sec_size+pkt->grp_size, &store_obj->key, pkt->name_size);
-    memcpy(pkt->data+pkt->sec_size+pkt->grp_size+pkt->name_size, &store_obj->value, strlen(store_obj->value)+1);
-    return pkt;
-}
-
-dap_store_obj_pkt_t *dap_store_packet_multiple(pdap_store_obj_t store_obj) {
-    dap_store_obj_pkt_t *pkt =
-            (dap_store_obj_pkt_t*)calloc(1, sizeof(int) + 2 + strlen(store_obj->group) + dap_store_len*(1+strlen(store_obj->key)) + strlen(store_obj->section) + dap_store_len*(1+strlen(store_obj->value)));
-    pkt->grp_size = strlen(store_obj[0].group) + 1;
-    pkt->name_size = strlen(store_obj[0].key) + 1; // useless here since it can differ from one store_obj to another
-    pkt->sec_size = strlen(store_obj[0].section) + 1;
-    pkt->type = store_obj[0].type;
-    memcpy(pkt->data, &store_obj[0].section, pkt->sec_size);
-    memcpy(pkt->data+pkt->sec_size, &store_obj[0].group, pkt->grp_size);
-    uint64_t offset = pkt->sec_size+pkt->grp_size;
-    int q;
-    for (q = 0; q < dap_store_len; ++q) {
-        memcpy(pkt->data + offset, &store_obj[q].key, strlen(store_obj[q].key) + 1);
-        offset += strlen(store_obj[q].key) + 1;
-        memcpy(pkt->data + offset, &store_obj[q].value, strlen(store_obj[q].value) + 1);
-        offset += strlen(store_obj[q].value) + 1;
-    }
-    return pkt;
-}
-
-void dap_db_deinit() {
-    talloc_free(ldb);
-    talloc_free(mem_ctx);
-    free(dap_db_path);
-}
diff --git a/dap_chain_global_db.h b/dap_chain_global_db.h
index d8e6525fc176de63609c95456cde84fd25cf9270..af31658edaee68be539ed09ba2eb0b285a9568d7 100644
--- a/dap_chain_global_db.h
+++ b/dap_chain_global_db.h
@@ -1,39 +1,12 @@
 #pragma once
+#include <stdbool.h>
 
-#include <stdint.h>
-#include "dap_common.h"
-#include "ldb.h"
+int dap_chain_global_db_init(const char *a_storage_path);
 
-typedef struct dap_store_obj {
-    char    *section;
-    char    *group;
-    char    *key;
-    uint8_t type;
-    char    *value;
-} DAP_ALIGN_PACKED dap_store_obj_t, *pdap_store_obj_t;
+void dap_chain_global_db_deinit();
 
-typedef struct dap_store_obj_pkt {
-     uint8_t type;
-     uint8_t sec_size;
-     uint8_t grp_size;
-     uint8_t name_size;
-     uint8_t data[];
-} __attribute__((packed)) dap_store_obj_pkt_t;
+char* dap_chain_global_db_get(const char *a_key);
+bool dap_chain_global_db_set(const char *a_key, const char *a_value);
 
-int dap_store_len = 0; // initialized only when reading from local db
-
-char *dap_db_path = NULL;
-
-static struct ldb_context *ldb  = NULL;
-static TALLOC_CTX *mem_ctx      = NULL;
-
-int     dap_db_init     (const char*);
-void    dap_db_deinit   (void);
-
-int dap_db_add_msg(struct ldb_message *);
-int dap_db_merge(pdap_store_obj_t, int);
-
-pdap_store_obj_t dap_db_read_data       (void);
-pdap_store_obj_t dap_db_read_file_data  (const char *); // state of emergency only, if LDB database is inaccessible
-dap_store_obj_pkt_t *dap_store_packet_single(pdap_store_obj_t);
-dap_store_obj_pkt_t *dap_store_packet_multiple(pdap_store_obj_t);
+char* dap_chain_global_db_load();
+bool dap_chain_global_db_save(char *data);
diff --git a/dap_chain_global_db_pvt.c b/dap_chain_global_db_pvt.c
new file mode 100644
index 0000000000000000000000000000000000000000..c3a691c2b16385793260934a1a0cf5a8cef25f53
--- /dev/null
+++ b/dap_chain_global_db_pvt.c
@@ -0,0 +1,299 @@
+#include "dap_chain_global_db_pvt.h"
+
+#include <string.h>
+#include <stdio.h>
+//#include "talloc.h"
+
+#define LOG_TAG "dap_global_db"
+#define TDB_PREFIX_LEN 7
+
+static int dap_store_len = 0; // initialized only when reading from local db
+static char *dap_db_path = NULL;
+
+#define CALL2(a, b, ...) (a), (b)
+#define dap_db_add_record(...) dap_db_merge(CALL2(__VA_ARGS__, 0))
+
+int dap_db_init(const char *path)
+{
+    mem_ctx = talloc_new(NULL);
+    if(ldb_global_init() != 0) {
+        log_it(L_ERROR, "Couldn't initialize LDB's global information");
+        return -1;
+    };
+    if((ldb = ldb_init(mem_ctx, NULL)) != LDB_SUCCESS) {
+        log_it(L_INFO, "ldb context initialized");
+        char tdb_path[strlen(path) + TDB_PREFIX_LEN];
+        memset(tdb_path, '\0', strlen(path) + TDB_PREFIX_LEN);
+        strcat(tdb_path, "tdb://"); // using tdb for simplicity, no need for separate LDAP server
+        strcat(tdb_path, path);
+        struct ldb_result *data_message;
+        if(ldb_connect(ldb, tdb_path, 0, NULL) != LDB_SUCCESS) {
+            log_it(L_ERROR, "Couldn't connect to database");
+            return 1;
+        }
+        dap_db_path = strdup(tdb_path);
+        const char *query = "(dn=*)";
+        if(ldb_search(ldb, mem_ctx, &data_message, NULL, LDB_SCOPE_DEFAULT, NULL, query) != LDB_SUCCESS) {
+            log_it(L_ERROR, "Database querying failed");
+            return 2;
+        }
+        struct ldb_message *msg;
+        if(data_message->count == 0) {
+            // level 1: section record
+            msg = ldb_msg_new(ldb);
+            msg->dn = ldb_dn_new(mem_ctx, ldb, "dc=kelvin_nodes");
+            ldb_msg_add_string(msg, "dc", "kelvin_nodes");
+            ldb_msg_add_string(msg, "objectClass", "top");
+            ldb_msg_add_string(msg, "objectClass", "section");
+            dap_db_add_msg(msg);
+            talloc_free(msg->dn);
+            talloc_free(msg);
+
+            // level 2: group record
+            msg = ldb_msg_new(ldb);
+            msg->dn = ldb_dn_new(mem_ctx, ldb, "ou=addrs_leased,dc=kelvin_nodes");
+            ldb_msg_add_string(msg, "ou", "addrs_leased");
+            ldb_msg_add_string(msg, "objectClass", "group");
+            ldb_msg_add_string(msg, "description", "Whitelist of Kelvin blockchain nodes");
+            dap_db_add_msg(msg);
+            talloc_free(msg->dn);
+            talloc_free(msg);
+        }
+        talloc_free(data_message);
+        return 0;
+    }
+    else {
+        log_it(L_ERROR, "Couldn't initialize LDB context");
+        return -2;
+    }
+}
+
+int dap_db_add_msg(struct ldb_message *msg)
+{
+    if(ldb_msg_sanity_check(ldb, msg) != LDB_SUCCESS) {
+        log_it(L_ERROR, "LDB message is inconsistent: %s", ldb_errstring(ldb));
+        return -1;
+    }
+    ldb_transaction_start(ldb);
+    int status = ldb_add(ldb, msg);
+    // Delete the entry if it already exist and add again
+    if(status == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+        ldb_delete(ldb, msg->dn);
+        status = ldb_add(ldb, msg);
+    }
+    if(status != LDB_SUCCESS) {
+        if(status == LDB_ERR_ENTRY_ALREADY_EXISTS) {
+            log_it(L_INFO, "Entry %s already present, skipped", ldb_dn_get_linearized(msg->dn));
+        }
+        else {
+            log_it(L_ERROR, "LDB adding error: %s", ldb_errstring(ldb));
+        }
+        ldb_transaction_cancel(ldb);
+        return -2;
+    }
+    else {
+        ldb_transaction_commit(ldb);
+        log_it(L_INFO, "Entry %s added", ldb_dn_get_linearized(msg->dn));
+        return 0;
+    }
+}
+
+/* path is supposed to have been obtained by smth like
+ dap_config_get_item_str(g_config, "resources", "dap_global_db_path");
+ */
+pdap_store_obj_t dap_db_read_data(const char *query, int *count)
+{
+    struct ldb_result *data_message;
+    /*
+     CN      commonName (2.5.4.3)
+     L       localityName (2.5.4.7)
+     ST      stateOrProvinceName (2.5.4.8)
+     O       organizationName (2.5.4.10)
+     OU      organizationalUnitName (2.5.4.11)
+     C       countryName (2.5.4.6)
+     STREET  streetAddress (2.5.4.9)
+     DC      domainComponent (0.9.2342.19200300.100.1.25)
+     UID     userId (0.9.2342.19200300.100.1.1)
+     */
+    //const char *query = "(objectClass=addr_leased)";
+    if(ldb_connect(ldb, dap_db_path, LDB_FLG_RDONLY, NULL) != LDB_SUCCESS) {
+        log_it(L_ERROR, "Couldn't connect to database");
+        return NULL;
+    }
+    if(ldb_search(ldb, NULL, &data_message, NULL, LDB_SCOPE_DEFAULT, NULL, query) != LDB_SUCCESS) {
+        log_it(L_ERROR, "Database querying failed");
+        return NULL;
+    }
+    log_it(L_INFO, "Obtained binary data, %d entries", data_message->count);
+
+    pdap_store_obj_t store_data = DAP_NEW_Z_SIZE(dap_store_obj_t, data_message->count * sizeof(struct dap_store_obj));
+    if(store_data != NULL) {
+        log_it(L_INFO, "We're about to put entries into store objects");
+    }
+    else {
+        log_it(L_ERROR, "Couldn't allocate memory, store objects unobtained");
+        talloc_free(data_message);
+        return NULL;
+    }
+    dap_store_len = data_message->count;
+    int q;
+    for(q = 0; q < dap_store_len; ++q) {
+        store_data[q].section = "kelvin_nodes";
+        store_data[q].group = "addrs_leased";
+        store_data[q].type = 1;
+        store_data[q].key = strdup(ldb_msg_find_attr_as_string(data_message->msgs[q], "cn", NULL));
+        store_data[q].value = strdup(ldb_msg_find_attr_as_string(data_message->msgs[q], "time", NULL));
+        log_it(L_INFO, "Record %s stored successfully", ldb_dn_get_linearized(data_message->msgs[q]->dn));
+    }
+    if(count)
+        *count = data_message->count;
+    talloc_free(data_message);
+    return store_data;
+}
+
+/**
+ * clean memory
+ */
+void dab_db_free_pdap_store_obj_t(pdap_store_obj_t store_data)
+{
+    if(!store_data)
+        return;
+    free(store_data->key);
+    free(store_data->value);
+    DAP_DELETE(store_data);
+}
+
+/* Get the entire content without using query expression
+ * This function is highly dissuaded from being used
+ * */
+pdap_store_obj_t dap_db_read_file_data(const char *path)
+{
+    struct ldb_ldif *ldif_msg;
+    FILE *fs = fopen(path, "r");
+    if(!fs) {
+        log_it(L_ERROR, "Can't open file %s", path);
+        return NULL;
+    }
+    pdap_store_obj_t store_data = (pdap_store_obj_t) malloc(256 * sizeof(dap_store_obj_t));
+    if(store_data != NULL) {
+        log_it(L_INFO, "We're about to put entries in store objects");
+    }
+    else {
+        log_it(L_ERROR, "Couldn't allocate memory, store objects unobtained");
+        fclose(fs);
+        return NULL;
+    }
+
+    int q = 0;
+    for(ldif_msg = ldb_ldif_read_file(ldb, fs); ldif_msg; ldif_msg = ldb_ldif_read_file(ldb, fs), q++) {
+        if(q % 256 == 0) {
+            store_data = (pdap_store_obj_t) realloc(store_data, (q + 256) * sizeof(dap_store_obj_t));
+        }
+        /* if (ldif_msg->changetype == LDB_CHANGETYPE_ADD) {
+         / ... /
+         } */ // in case we gonna use extra LDIF functionality
+        const char *key = ldb_msg_find_attr_as_string(ldif_msg->msg, "cn", NULL);
+        if(key != NULL) {
+            store_data[q].section = "kelvin_nodes";
+            store_data[q].group = "addrs_leased";
+            store_data[q].type = 1;
+            store_data[q].key = strdup(key);
+            store_data[q].value = strdup(ldb_msg_find_attr_as_string(ldif_msg->msg, "time", NULL));
+            log_it(L_INFO, "Record %s stored successfully", ldb_dn_get_linearized(ldif_msg->msg->dn));
+        }
+        ldb_ldif_read_free(ldb, ldif_msg);
+    }
+    fclose(fs);
+    return store_data;
+}
+
+/*
+ * Add multiple entries received from remote node to local database.
+ * Since we don't know the size, it must be supplied too
+ */
+int dap_db_merge(pdap_store_obj_t store_obj, int dap_store_size)
+{
+    if(store_obj == NULL) {
+        log_it(L_ERROR, "Invalid Dap store objects passed");
+        return -1;
+    }
+    if(ldb_connect(ldb, dap_db_path, 0, NULL) != LDB_SUCCESS) {
+        log_it(L_ERROR, "Couldn't connect to database");
+        return -2;
+    }
+    log_it(L_INFO, "We're about to put %d records into database", dap_store_size);
+    struct ldb_message *msg;
+    int q;
+    if(dap_store_size == 0) {
+        dap_store_size = 1;
+    }
+    for(q = 0; q < dap_store_size; q++) {
+        // level 3: leased address, single whitelist entity
+        msg = ldb_msg_new(ldb);
+        char dn[128];
+        memset(dn, '\0', 128);
+        strcat(dn, "cn=");
+        strcat(dn, store_obj[q].key);
+        strcat(dn, ",ou=addrs_leased,dc=kelvin_nodes");
+        msg->dn = ldb_dn_new(mem_ctx, ldb, dn);
+        ldb_msg_add_string(msg, "cn", store_obj[q].key);
+        ldb_msg_add_string(msg, "objectClass", "addr_leased");
+        ldb_msg_add_string(msg, "description", "Approved Kelvin node");
+        ldb_msg_add_string(msg, "time", store_obj[q].value);
+        dap_db_add_msg(msg);
+        talloc_free(msg->dn);
+        talloc_free(msg);
+    }
+    return 0;
+}
+
+/* serialization */
+dap_store_obj_pkt_t *dap_store_packet_single(pdap_store_obj_t store_obj)
+{
+    dap_store_obj_pkt_t *pkt =
+            (dap_store_obj_pkt_t*) calloc(1,
+                    sizeof(int) + 4 + strlen(store_obj->group) + strlen(store_obj->key) + strlen(store_obj->section)
+                            + strlen(store_obj->value));
+    pkt->grp_size = strlen(store_obj->group) + 1;
+    pkt->name_size = strlen(store_obj->key) + 1;
+    pkt->sec_size = strlen(store_obj->section) + 1;
+    pkt->type = store_obj->type;
+    memcpy(pkt->data, &store_obj->section, pkt->sec_size);
+    memcpy(pkt->data + pkt->sec_size, &store_obj->group, pkt->grp_size);
+    memcpy(pkt->data + pkt->sec_size + pkt->grp_size, &store_obj->key, pkt->name_size);
+    memcpy(pkt->data + pkt->sec_size + pkt->grp_size + pkt->name_size, &store_obj->value, strlen(store_obj->value) + 1);
+    return pkt;
+}
+
+dap_store_obj_pkt_t *dap_store_packet_multiple(pdap_store_obj_t store_obj)
+{
+    dap_store_obj_pkt_t *pkt =
+            (dap_store_obj_pkt_t*) calloc(1,
+                    sizeof(int) + 2 + strlen(store_obj->group) + dap_store_len * (1 + strlen(store_obj->key))
+                            + strlen(store_obj->section) + dap_store_len * (1 + strlen(store_obj->value)));
+    pkt->grp_size = strlen(store_obj[0].group) + 1;
+    pkt->name_size = strlen(store_obj[0].key) + 1; // useless here since it can differ from one store_obj to another
+    pkt->sec_size = strlen(store_obj[0].section) + 1;
+    pkt->type = store_obj[0].type;
+    memcpy(pkt->data, &store_obj[0].section, pkt->sec_size);
+    memcpy(pkt->data + pkt->sec_size, &store_obj[0].group, pkt->grp_size);
+    uint64_t offset = pkt->sec_size + pkt->grp_size;
+    int q;
+    for(q = 0; q < dap_store_len; ++q) {
+        memcpy(pkt->data + offset, &store_obj[q].key, strlen(store_obj[q].key) + 1);
+        offset += strlen(store_obj[q].key) + 1;
+        memcpy(pkt->data + offset, &store_obj[q].value, strlen(store_obj[q].value) + 1);
+        offset += strlen(store_obj[q].value) + 1;
+    }
+    return pkt;
+}
+
+void dap_db_deinit()
+{
+    talloc_free(ldb);
+    talloc_free(mem_ctx);
+    free(dap_db_path);
+    ldb = NULL;
+    mem_ctx = NULL;
+    dap_db_path = NULL;
+}
diff --git a/dap_chain_global_db_pvt.h b/dap_chain_global_db_pvt.h
new file mode 100644
index 0000000000000000000000000000000000000000..3fbbac3ca913f63cdcc01be63483f8af252df469
--- /dev/null
+++ b/dap_chain_global_db_pvt.h
@@ -0,0 +1,38 @@
+#pragma once
+
+#include <stdint.h>
+#include "dap_common.h"
+#include "ldb.h"
+
+typedef struct dap_store_obj {
+    char    *section;
+    char    *group;
+    char    *key;
+    uint8_t type;
+    char    *value;
+} DAP_ALIGN_PACKED dap_store_obj_t, *pdap_store_obj_t;
+
+typedef struct dap_store_obj_pkt {
+     uint8_t type;
+     uint8_t sec_size;
+     uint8_t grp_size;
+     uint8_t name_size;
+     uint8_t data[];
+} __attribute__((packed)) dap_store_obj_pkt_t;
+
+static struct ldb_context *ldb  = NULL;
+static TALLOC_CTX *mem_ctx      = NULL;
+
+int     dap_db_init     (const char*);
+void dap_db_deinit(void);
+
+int dap_db_add_msg(struct ldb_message *);
+int dap_db_merge(pdap_store_obj_t, int);
+
+pdap_store_obj_t dap_db_read_data(const char *query, int *count);
+pdap_store_obj_t dap_db_read_file_data(const char *); // state of emergency only, if LDB database is inaccessible
+dap_store_obj_pkt_t *dap_store_packet_single(pdap_store_obj_t);
+dap_store_obj_pkt_t *dap_store_packet_multiple(pdap_store_obj_t);
+
+void dab_db_free_pdap_store_obj_t(pdap_store_obj_t store_data);
+