diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4c86cc5c60f69e1260a24211e5b71dc75cafe8ec..1e04fb59a169d62f8d758bd2be989f18d1a2c06c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -55,6 +55,7 @@ if(WIN32)
   add_definitions ("-D_POSIX_")
   add_definitions ("-D_POSIX_THREAD_SAFE_FUNCTIONS")
   add_definitions ("-DNODE_NETNAME=\"cellframe\"")
+  add_compile_definitions(_GNU_SOURCE)
   include_directories(../libdap/src/win32/)
   include_directories(../3rdparty/wepoll/include/)
   include_directories(../3rdparty/uthash/src/)
diff --git a/dap_chain_net.c b/dap_chain_net.c
index ad42a7190b4e3b4ae4523ca8a80b36b2d05f370a..bcfb68cf33afcab1df8d055eef4f6b795430c2fc 100755
--- a/dap_chain_net.c
+++ b/dap_chain_net.c
@@ -720,6 +720,11 @@ static void s_net_proc_kill( dap_chain_net_t * a_net )
     return;
 }
 
+dap_chain_node_role_t dap_chain_net_get_role(dap_chain_net_t * a_net)
+{
+    return  PVT(a_net)->node_role;
+}
+
 /**
  * @brief dap_chain_net_new
  * @param a_id
@@ -824,6 +829,8 @@ int dap_chain_net_init()
     dap_chain_global_db_add_history_group_prefix("global");
 
     dap_chain_global_db_add_history_callback_notify("global", s_gbd_history_callback_notify, NULL );
+
+    dap_chain_net_load_all();
     return 0;
 }
 
@@ -1606,8 +1613,44 @@ dap_chain_cell_id_t * dap_chain_net_get_cur_cell( dap_chain_net_t * l_net)
     return  PVT(l_net)->node_info? &PVT(l_net)->node_info->hdr.cell_id: 0;
 }
 
+
 /**
- * Get remote node list
+ * Get nodes list (list of dap_chain_node_addr_t struct)
+ */
+dap_list_t* dap_chain_net_get_link_node_list(dap_chain_net_t * l_net, bool a_is_only_cur_cell)
+{
+    dap_list_t *l_node_list = NULL;
+    // get cur node address
+    dap_chain_node_addr_t l_cur_node_addr = { 0 };
+    l_cur_node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
+
+    dap_chain_node_info_t *l_cur_node_info = dap_chain_node_info_read(l_net, &l_cur_node_addr);
+    // add links to nodes list only from the same cell
+    if(l_cur_node_info) {
+        for(unsigned int i = 0; i < l_cur_node_info->hdr.links_number; i++) {
+            bool l_is_add = true;
+            dap_chain_node_addr_t *l_remote_address = l_cur_node_info->links + i;
+            if(a_is_only_cur_cell) {
+                // get remote node list
+                dap_chain_node_info_t *l_remote_node_info = dap_chain_node_info_read(l_net, l_remote_address);
+                if(!l_remote_node_info || l_remote_node_info->hdr.cell_id.uint64 != l_cur_node_info->hdr.cell_id.uint64)
+                    l_is_add = false;
+                DAP_DELETE(l_remote_node_info);
+            }
+            if(l_is_add) {
+                dap_chain_node_addr_t *l_address = DAP_NEW(dap_chain_node_addr_t);
+                l_address->uint64 = l_cur_node_info->links[i].uint64;
+                l_node_list = dap_list_append(l_node_list, l_address);
+            }
+        }
+
+    }
+    DAP_DELETE(l_cur_node_info);
+    return l_node_list;
+}
+
+/**
+ * Get remote nodes list (list of dap_chain_node_addr_t struct)
  */
 dap_list_t* dap_chain_net_get_node_list(dap_chain_net_t * l_net)
 {
@@ -1679,9 +1722,55 @@ dap_list_t* dap_chain_net_get_node_list(dap_chain_net_t * l_net)
  * @brief dap_chain_net_proc_datapool
  * @param a_net
  */
-void dap_chain_net_proc_datapool (dap_chain_net_t * a_net)
+void dap_chain_net_proc_mempool (dap_chain_net_t * a_net)
 {
 
+    dap_string_t * l_str_tmp = dap_string_new(NULL);
+    for(dap_chain_type_t i = CHAIN_TYPE_FIRST + 1; i < CHAIN_TYPE_LAST; i++) {
+        dap_chain_t * l_chain = dap_chain_net_get_chain_by_chain_type(a_net, i);
+        char * l_gdb_group_mempool = dap_chain_net_get_gdb_group_mempool(l_chain);
+
+        size_t l_objs_size = 0;
+        dap_global_db_obj_t * l_objs = dap_chain_global_db_gr_load(l_gdb_group_mempool, &l_objs_size);
+        if(l_objs_size) {
+            log_it(L_INFO, "%s.%s: Found %u records :", a_net->pub.name, l_chain->name,
+                    l_objs_size);
+            size_t l_datums_size = l_objs_size;
+            dap_chain_datum_t ** l_datums = DAP_NEW_Z_SIZE(dap_chain_datum_t*,
+                    sizeof(dap_chain_datum_t*) * l_datums_size);
+            size_t l_objs_size_tmp = (l_objs_size > 15) ? min(l_objs_size, 10) : l_objs_size;
+            for(size_t i = 0; i < l_objs_size; i++) {
+                dap_chain_datum_t * l_datum = (dap_chain_datum_t*) l_objs[i].value;
+                l_datums[i] = l_datum;
+                if(i < l_objs_size_tmp) {
+                    char buf[50];
+                    time_t l_ts_create = (time_t) l_datum->header.ts_create;
+                    log_it(L_INFO, "\t\t0x%s: type_id=%s ts_create=%s data_size=%u",
+                            l_objs[i].key, c_datum_type_str[l_datum->header.type_id],
+                            ctime_r(&l_ts_create, buf), l_datum->header.data_size);
+                }
+            }
+            size_t l_objs_processed = l_chain->callback_datums_pool_proc(l_chain, l_datums, l_datums_size);
+            // Delete processed objects
+            size_t l_objs_processed_tmp = (l_objs_processed > 15) ? min(l_objs_processed, 10) : l_objs_processed;
+            for(size_t i = 0; i < l_objs_processed; i++) {
+                dap_chain_global_db_gr_del(l_objs[i].key, l_gdb_group_mempool);
+                if(i < l_objs_processed_tmp) {
+                    dap_string_append_printf(l_str_tmp, "New event created, removed datum 0x%s from mempool \n",
+                            l_objs[i].key);
+                }
+            }
+            if(l_objs_processed < l_datums_size)
+                log_it(L_WARNING, "%s.%s: %d records not processed", a_net->pub.name, l_chain->name,
+                        l_datums_size - l_objs_processed);
+            dap_chain_global_db_objs_delete(l_objs, l_objs_size);
+        }
+        else {
+            log_it(L_INFO, "%s.%s: No records in mempool", a_net->pub.name, l_chain ? l_chain->name : "[no chain]");
+        }
+        DAP_DELETE(l_gdb_group_mempool);
+
+    }
 }
 
 /**
diff --git a/dap_chain_net.h b/dap_chain_net.h
index 1a7171f19d41c71bace4a85634f932bd06fd0f91..5cc4f2c16f2df38bad4f89efbfc342b4496693bb 100644
--- a/dap_chain_net.h
+++ b/dap_chain_net.h
@@ -36,6 +36,7 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 
 #include "win32/ip.h"
 #include "win32/iphdr.h"
+#define s6_addr32 s6_addr
 #define herror perror
 #endif
 
@@ -93,7 +94,7 @@ inline static int dap_chain_net_sync_gdb(dap_chain_net_t * a_net) { return dap_c
 inline static int dap_chain_net_sync_all(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_GDB); }//NET_STATE_ONLINE
 
 void dap_chain_net_delete( dap_chain_net_t * a_net);
-void dap_chain_net_proc_datapool (dap_chain_net_t * a_net);
+void dap_chain_net_proc_mempool (dap_chain_net_t * a_net);
 
 dap_chain_net_t * dap_chain_net_by_name( const char * a_name);
 dap_chain_net_t * dap_chain_net_by_id( dap_chain_net_id_t a_id);
@@ -106,6 +107,7 @@ dap_chain_node_addr_t * dap_chain_net_get_cur_addr( dap_chain_net_t * l_net);
 uint64_t dap_chain_net_get_cur_addr_int(dap_chain_net_t * l_net);
 dap_chain_cell_id_t * dap_chain_net_get_cur_cell( dap_chain_net_t * l_net);
 
+dap_list_t* dap_chain_net_get_link_node_list(dap_chain_net_t * l_net, bool a_is_only_cur_cell);
 dap_list_t* dap_chain_net_get_node_list(dap_chain_net_t * l_net);
 
 void dap_chain_net_links_connect(dap_chain_net_t * a_net);
@@ -126,6 +128,8 @@ typedef enum dap_chain_net_tx_search_type {
 dap_chain_datum_tx_t * dap_chain_net_get_tx_by_hash(dap_chain_net_t * a_net, dap_chain_hash_fast_t * a_tx_hash,
                                                      dap_chain_net_tx_search_type_t a_search_type);
 
+dap_chain_node_role_t dap_chain_net_get_role(dap_chain_net_t * a_net);
+
 /**
  * @brief dap_chain_net_get_gdb_group_mempool
  * @param l_chain
diff --git a/dap_chain_node.h b/dap_chain_node.h
index 1c7bff5ce37baf32e88b577b280888d8f2719994..95ca8c1bdd2cc5773f3d9d77aec27e68034d1081 100644
--- a/dap_chain_node.h
+++ b/dap_chain_node.h
@@ -36,8 +36,6 @@
 
 #include "win32/ip.h"
 #include "win32/iphdr.h"
-#define __in6_u _S6_un
-#define __u6_addr32 _S6_u8
 #endif
 
 
diff --git a/dap_chain_node_cli_cmd.c b/dap_chain_node_cli_cmd.c
index 2e859dea541072365f7d00a36f768ea87c87272a..41d5018ee9683b350ef9d46803a8dd5f3f2b5a0e 100644
--- a/dap_chain_node_cli_cmd.c
+++ b/dap_chain_node_cli_cmd.c
@@ -43,13 +43,13 @@
 #include <ws2tcpip.h>
 #include <io.h>
 #include <wepoll.h>
-#include <signal.h>
-#include <pthread.h>
 #else
 #include <sys/types.h>
 #include <arpa/inet.h>
 #include <netinet/in.h>
+#include <signal.h>
 #endif
+#include <pthread.h>
 
 #include "iputils/iputils.h"
 
@@ -72,9 +72,11 @@
 #include "dap_chain_node_cli_cmd_tx.h"
 #include "dap_chain_node_ping.h"
 #include "dap_chain_net_srv.h"
+#include "dap_chain_net_srv_vpn.h"
 #include "dap_chain_net_vpn_client.h"
 #include "dap_chain_cell.h"
 
+#include "dap_chain_common.h"
 #include "dap_chain_datum.h"
 #include "dap_chain_datum_token.h"
 #include "dap_chain_datum_tx_items.h"
@@ -913,109 +915,98 @@ int com_node(int a_argc, char ** a_argv, char **a_str_reply)
                 return -1;
             }
         }
+        // for auto mode
+        int l_is_auto = 0;
+        // list of dap_chain_node_addr_t struct
+        unsigned int l_nodes_count = 0;
+        dap_list_t *l_node_list = NULL;
+        dap_chain_node_addr_t *l_remote_node_addr = NULL;
         if(!l_node_addr.uint64) {
             // check whether auto mode
-            int l_is_auto = dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "auto", NULL);
+            l_is_auto = dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "auto", NULL);
             if(!l_is_auto) {
                 dap_chain_node_cli_set_reply_text(a_str_reply, "addr not found");
                 return -1;
             }
             // if auto mode, then looking for the node address
 
-            // list of dap_chain_node_addr_t struct
-            dap_list_t *l_node_list = dap_chain_net_get_node_list(l_net);
-            // add cur node links to list
-            dap_chain_node_info_t *l_cur_node_info = NULL;
-            {
-                // get cur node address
-                dap_chain_node_addr_t l_cur_node_addr = { 0 };
-                l_cur_node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
-                // get cur node info
-                l_cur_node_info = node_info_read_and_reply(l_net, &l_cur_node_addr, NULL);
-                // add links to nodes list only from the same cell
-                if(l_cur_node_info) {
-                    for(unsigned int i = 0; i < l_cur_node_info->hdr.links_number; i++) {
-                        //if(l_node_info && l_node_info->hdr.cell_id == l_cur_node_info->hdr.cell_id){
-                        l_node_list = dap_list_append(l_node_list, l_cur_node_info->links + i);
-                        //}
-                    }
-
-                }
-            }
-
-            // select the nearest node from the list
-            unsigned int l_nodes_count = dap_list_length(l_node_list);
-            unsigned int l_thread_id = 0;
-            pthread_t *l_threads = DAP_NEW_Z_SIZE(pthread_t, sizeof(pthread_t) * l_nodes_count);
-            uint64_t *l_nodes_addr = DAP_NEW_Z_SIZE(uint64_t, sizeof(uint64_t) * l_nodes_count);
-            dap_list_t *l_node_list0 = l_node_list;
-            // send ping to all nodes
-            while(l_node_list) {
-                dap_chain_node_addr_t *l_node_addr = l_node_list->data;
-                dap_chain_node_info_t *l_node_info = node_info_read_and_reply(l_net, l_node_addr, NULL);
-
-                // start sending ping
-                start_node_ping(&l_threads[l_thread_id], l_node_info->hdr.ext_addr_v4, l_node_info->hdr.ext_port, 1);
-
-                l_nodes_addr[l_thread_id] = l_node_info->hdr.address.uint64;
-                l_thread_id++;
-                DAP_DELETE(l_node_info);
-                l_node_list = dap_list_next(l_node_list);
-            }
-            // wait for reply from nodes
-            int best_node_pos = -1;
-            int best_node_reply = INT32_MAX;
-            // timeout for all threads
-            int l_timeout_full_ms = 3000;// wait max 3 second
-            for(l_thread_id = 0; l_thread_id < l_nodes_count; l_thread_id++) {
-                if(l_timeout_full_ms<100)
-                    l_timeout_full_ms = 100;// make small timeout anyway, may be
-                struct timespec l_time_start;
-                clock_gettime(CLOCK_MONOTONIC, &l_time_start);
-                int res = wait_node_ping(l_threads[l_thread_id], l_timeout_full_ms);
-                if(res > 0 && res < best_node_reply) {
-                    best_node_pos = l_thread_id;
-                    best_node_reply = res;
-                }
-                struct timespec l_time_stop;
-                clock_gettime(CLOCK_MONOTONIC, &l_time_stop);
-                l_timeout_full_ms -= timespec_diff(&l_time_start, &l_time_stop, NULL);
-                //printf(" thread %x ping=%d\n", l_threads[l_thread_id], res);
-            }
-            if(best_node_pos > 0) {
-                l_node_addr.uint64 = l_nodes_addr[best_node_pos];
+            // get cur node links
+            bool a_is_only_cur_cell = false;
+            dap_list_t *l_node_link_list = dap_chain_net_get_link_node_list(l_net, a_is_only_cur_cell);
+            // get all nodes list if no links
+            if(!l_node_link_list)
+                l_node_list = dap_chain_net_get_node_list(l_net);
+            else
+                l_node_list = dap_list_concat(l_node_link_list, l_node_list);
+
+            // select random node from the list
+            l_nodes_count = dap_list_length(l_node_list);
+            if(l_nodes_count > 0) {
+                unsigned int l_node_pos = rand() % l_nodes_count;
+                dap_list_t *l_tmp = dap_list_nth(l_node_list, l_node_pos);
+                l_remote_node_addr = l_tmp->data;
+                l_node_addr.uint64 = l_remote_node_addr->uint64;
             }
 
-            DAP_DELETE(l_nodes_addr);
-            DAP_DELETE(l_threads);
-            dap_list_free_full(l_node_list0, free);
-            DAP_DELETE(l_cur_node_info);
-
             if(!l_node_addr.uint64) {
                 dap_chain_node_cli_set_reply_text(a_str_reply, "no node is available");
                 return -1;
             }
         }
-
-        dap_chain_node_info_t *l_remote_node_info = node_info_read_and_reply(l_net, &l_node_addr, a_str_reply);
-        if(!l_remote_node_info) {
-            return -1;
+        dap_chain_node_info_t *l_remote_node_info;
+        dap_chain_node_client_t *l_node_client;
+        int res;
+        do {
+            l_remote_node_info = node_info_read_and_reply(l_net, &l_node_addr, a_str_reply);
+            if(!l_remote_node_info) {
+                return -1;
+            }
+            // start connect
+            l_node_client = dap_chain_node_client_connect(l_remote_node_info);
+            if(!l_node_client) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "can't connect");
+                DAP_DELETE(l_remote_node_info);
+                return -1;
+            }
+            // wait connected
+            int timeout_ms = 5000; //5 sec = 5000 ms
+            res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
+            // select new node addr
+            if(l_is_auto && res){
+                if(l_remote_node_addr && l_nodes_count>1){
+                    l_nodes_count--;
+                    l_node_list = dap_list_remove(l_node_list, l_remote_node_addr);
+                    DAP_DELETE(l_remote_node_addr);
+                    unsigned int l_node_pos = rand() % l_nodes_count;
+                    dap_list_t *l_tmp = dap_list_nth(l_node_list, l_node_pos);
+                    l_remote_node_addr = l_tmp->data;
+                    l_node_addr.uint64 = l_remote_node_addr->uint64;
+
+                    // clean client struct
+                    dap_chain_node_client_close(l_node_client);
+                    DAP_DELETE(l_remote_node_info);
+                    //return -1;
+                    continue;
+                }
+            }
+            break;
         }
-        // start connect
-        dap_chain_node_client_t *l_node_client = dap_chain_node_client_connect(l_remote_node_info);
-        if(!l_node_client) {
-            dap_chain_node_cli_set_reply_text(a_str_reply, "can't connect");
-            DAP_DELETE(l_remote_node_info);
-            return -1;
+        while(1);
+        // for auto mode only
+        if(l_is_auto) {
+            //start background thread for testing connect to the nodes
+            dap_chain_node_ping_background_start(l_net, l_node_list);
+            dap_list_free_full(l_node_list, free);
         }
-        // wait connected
-        int timeout_ms = 5000; //5 sec = 5000 ms
-        int res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_CONNECTED, timeout_ms);
+
+
+
         if(res) {
-            dap_chain_node_cli_set_reply_text(a_str_reply, "no response from node: code %d", res);
+            dap_chain_node_cli_set_reply_text(a_str_reply, "no response from remote node(s)");
+            log_it(L_WARNING, "No response from remote node(s): err code %d", res);
             // clean client struct
-            dap_chain_node_client_close(l_node_client);
-            DAP_DELETE(l_remote_node_info);
+            //dap_chain_node_client_close(l_node_client);
+            //DAP_DELETE(l_remote_node_info);
             return -1;
         }
 
@@ -1118,7 +1109,7 @@ int com_node(int a_argc, char ** a_argv, char **a_str_reply)
         }
         dap_stream_ch_set_ready_to_write(l_ch_chain, true);
         // wait for finishing of request
-        timeout_ms = 1200000; // 20 min = 1200 sec = 1 200 000 ms
+        int timeout_ms = 1200000; // 20 min = 1200 sec = 1 200 000 ms
         // TODO add progress info to console
         res = dap_chain_node_client_wait(l_node_client, NODE_CLIENT_STATE_SYNCED, timeout_ms);
         if(res < 0) {
@@ -2085,12 +2076,23 @@ int com_mempool_proc(int argc, char ** argv, char ** a_str_reply)
             if(l_objs_size > 15) {
                 dap_string_append_printf(l_str_tmp, "...\n");
             }
-            size_t l_objs_processed = l_chain->callback_datums_pool_proc(l_chain, l_datums, l_datums_size);
+
+            size_t l_objs_processed = 0;
+            bool l_procecced[l_objs_size];
+            for(size_t i = 0; i < l_objs_size; i++) {
+                int l_is_processed = l_chain->callback_datums_pool_proc(l_chain, l_datums + i, 1); //l_datums_size
+                l_objs_processed += l_is_processed;
+                l_procecced[i] = l_is_processed;
+            }
             // Delete processed objects
             size_t l_objs_processed_tmp = (l_objs_processed > 15) ? min(l_objs_processed, 10) : l_objs_processed;
-            for(size_t i = 0; i < l_objs_processed; i++) {
-                dap_chain_global_db_gr_del(l_objs[i].key, l_gdb_group_mempool);
-                if(i < l_objs_processed_tmp) {
+            size_t l_objs_processed_cur = 0;
+            for(size_t i = 0; i < l_datums_size; i++) {
+                if(l_procecced[i]!=1)
+                    continue;
+                dap_chain_global_db_gr_del(l_objs[i].key, l_gdb_group_mempool_tmp);
+                l_objs_processed_cur++;
+                if(l_objs_processed_cur < l_objs_processed_tmp) {
                     dap_string_append_printf(l_str_tmp, "New event created, removed datum 0x%s from mempool \n",
                             l_objs[i].key);
                 }
@@ -2562,24 +2564,122 @@ int com_token_emit(int argc, char ** argv, char ** str_reply)
 int com_tx_cond_create(int argc, char ** argv, char **str_reply)
 {
     (void) argc;
-    // test
-    /*
-    const char * l_token_ticker = NULL;
+    int arg_index = 1;
     const char *c_wallets_path = dap_chain_wallet_get_path(g_config);
-    const char *c_wallet_name_from = "w_tesla"; // where to take coins for service
-    const char *c_wallet_name_cond = "w_picnic"; // who will be use service, usually the same address (addr_from)
-    uint64_t l_value = 50;
+    const char * l_token_ticker = NULL;
+    const char * l_wallet_from_str = NULL;
+    const char * l_wallet_to_str = NULL; //l_addr_to_str
+    const char * l_value_datoshi_str = NULL;
+    const char * l_net_name = NULL;
+    const char * l_unit_str = NULL;
+    const char * l_service_str = NULL;
+    uint64_t l_value_datoshi = 0;
+
+    // Token ticker
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-token", &l_token_ticker);
+    // Wallet name - from
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-wallet_f", &l_wallet_from_str);
+    // Wallet address - to
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-wallet_t", &l_wallet_to_str);
+    // value datoshi
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-value", &l_value_datoshi_str);
+    // net
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
+    // unit
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-unit", &l_unit_str);
+    // service
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-service", &l_service_str);
+
+    if(!l_token_ticker) {
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_cond_create requires parameter '-token'");
+        return -1;
+    }
+    if(!l_wallet_from_str) {
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_cond_create requires parameter '-wallet_f'");
+        return -2;
+    }
+    if(!l_wallet_to_str) {
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_cond_create requires parameter '-wallet_t'");
+        return -3;
+    }
+    if(!l_value_datoshi_str) {
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_cond_create requires parameter '-value'");
+        return -4;
+    }
 
-    dap_chain_wallet_t *l_wallet_from = dap_chain_wallet_open(c_wallet_name_from, c_wallets_path);
-    dap_enc_key_t *l_key = dap_chain_wallet_get_key(l_wallet_from, 0);
-    dap_chain_wallet_t *l_wallet_cond = dap_chain_wallet_open(c_wallet_name_cond, c_wallets_path);
+    if(!l_net_name) {
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_cond_create requires parameter '-net'");
+        return -5;
+    }
+    if(!l_unit_str) {
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_cond_create requires parameter '-unit={mb|kb|b|sec|day}'");
+        return -6;
+    }
+    if(!l_service_str) {
+        dap_chain_node_cli_set_reply_text(str_reply, "tx_cond_create requires parameter '-service={vpn}'");
+        return -7;
+    }
+    dap_chain_net_srv_uid_t l_srv_uid = { 0 };
+    if(!dap_strcmp(l_service_str, "vpn"))
+        l_srv_uid.uint64 = DAP_CHAIN_NET_SRV_VPN_ID;
+    //dap_chain_addr_t *addr_to = dap_chain_addr_from_str(l_addr_to_str);
+    if(!l_srv_uid.uint64) {
+        dap_chain_node_cli_set_reply_text(str_reply, "can't recognize service='%s' unit must look like {vpn}",
+                l_service_str);
+        return -8;
+    }
+
+    dap_chain_net_srv_price_unit_uid_t l_price_unit = { .enm = SERV_UNIT_UNDEFINED };
+    if(!dap_strcmp(l_unit_str, "mb"))
+        l_price_unit.enm = SERV_UNIT_MB;
+    else if(!dap_strcmp(l_unit_str, "sec"))
+        l_price_unit.enm = SERV_UNIT_SEC;
+    else if(!dap_strcmp(l_unit_str, "day"))
+        l_price_unit.enm = SERV_UNIT_DAY;
+    else if(!dap_strcmp(l_unit_str, "kb"))
+        l_price_unit.enm = SERV_UNIT_KB;
+    else if(!dap_strcmp(l_unit_str, "b"))
+        l_price_unit.enm = SERV_UNIT_B;
+
+    if(l_price_unit.enm == SERV_UNIT_UNDEFINED) {
+        dap_chain_node_cli_set_reply_text(str_reply, "can't recognize unit='%s' unit must look like {mb|kb|b|sec|day}",
+                l_unit_str);
+        return -9;
+    }
+
+    l_value_datoshi = strtoll(l_value_datoshi_str, NULL, 10);
+    if(!l_value_datoshi) {
+        dap_chain_node_cli_set_reply_text(str_reply, "can't recognize value='%s' as a number", l_value_datoshi_str);
+        return -10;
+    }
+
+    dap_chain_net_t * l_net = l_net_name ? dap_chain_net_by_name(l_net_name) : NULL;
+    if(!l_net) {
+        dap_chain_node_cli_set_reply_text(str_reply, "can't find net '%s'", l_net_name);
+        return -11;
+    }
+    dap_chain_wallet_t *l_wallet_from = dap_chain_wallet_open(l_wallet_from_str, c_wallets_path);
+    if(!l_wallet_from) {
+        dap_chain_node_cli_set_reply_text(str_reply, "can't open wallet '%s'", l_wallet_from);
+        return -12;
+    }
+    dap_chain_wallet_t *l_wallet_cond = dap_chain_wallet_open(l_wallet_to_str, c_wallets_path);
+    if(!l_wallet_to_str) {
+        dap_chain_wallet_close(l_wallet_from);
+        dap_chain_node_cli_set_reply_text(str_reply, "can't open wallet '%s'", l_wallet_to_str);
+        return -13;
+    }
+    dap_enc_key_t *l_key_from = dap_chain_wallet_get_key(l_wallet_from, 0);
     dap_enc_key_t *l_key_cond = dap_chain_wallet_get_key(l_wallet_cond, 0);
+
+
     // where to take coins for service
-    const dap_chain_addr_t *addr_from = dap_chain_wallet_get_addr(l_wallet_from);
+    const dap_chain_addr_t *l_addr_from = dap_chain_wallet_get_addr(l_wallet_from, l_net->pub.id);
     // who will be use service, usually the same address (addr_from)
-    const dap_chain_addr_t *addr_cond = dap_chain_wallet_get_addr(l_wallet_cond);
+    //const dap_chain_addr_t *l_addr_cond = dap_chain_wallet_get_addr(l_wallet_cond, l_net->pub.id);
+
 
-    dap_chain_net_srv_abstract_t l_cond;
+/*    //dap_chain_net_srv_abstract_t l_cond;
 //    dap_chain_net_srv_abstract_set(&l_cond, SERV_CLASS_PERMANENT, SERV_ID_VPN, l_value, SERV_UNIT_MB,
 //            "test vpn service");
 //    dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name((const char *) c_net_name);
@@ -2587,14 +2687,33 @@ int com_tx_cond_create(int argc, char ** argv, char **str_reply)
     int res = dap_chain_mempool_tx_create_cond(NULL, l_key, l_key_cond, addr_from,
             addr_cond,
             NULL, l_token_ticker, l_value, 0, (const void*) &l_cond, sizeof(dap_chain_net_srv_abstract_t));
+*/
+
+    dap_chain_hash_fast_t *l_tx_cond_hash = dap_chain_mempool_tx_create_cond(l_net, l_key_from, l_key_cond, l_addr_from, l_token_ticker,
+            l_value_datoshi, 0, l_price_unit, l_srv_uid, 0, NULL, 0);
 
     dap_chain_wallet_close(l_wallet_from);
     dap_chain_wallet_close(l_wallet_cond);
-    dap_chain_node_cli_set_reply_text(str_reply, "cond create=%s\n",
+
+    char *l_hash_str = l_tx_cond_hash ? dap_chain_hash_fast_to_str_new(l_tx_cond_hash) : NULL;
+
+    /*dap_chain_node_cli_set_reply_text(str_reply, "cond create=%s\n",
             (res == 0) ? "Ok" : (res == -2) ? "False, not enough funds for service fee" : "False");
-    return res;
-    */
-    return  -1;
+    return res;*/
+
+    int l_ret;
+    // example: cond create succefully hash=0x4AA303EB7C10430C0AAC42F399D265BC7DD09E3983E088E02B8CED38DA22EDA9
+    if(l_hash_str){
+        dap_chain_node_cli_set_reply_text(str_reply, "cond create succefully hash=%s\n", l_hash_str);
+        l_ret = 0;
+    }
+    else{
+        dap_chain_node_cli_set_reply_text(str_reply, "cond can't create\n");
+        l_ret = -1;
+    }
+
+    DAP_DELETE(l_hash_str);
+    return  l_ret;
 }
 
 /**
diff --git a/dap_chain_node_client.c b/dap_chain_node_client.c
index bce0989d71e738eb7d3953a1b5d1953ee0a3a0e3..3ddaddcba9b8139172f25d9647fc13f1392d76fd 100644
--- a/dap_chain_node_client.c
+++ b/dap_chain_node_client.c
@@ -127,6 +127,8 @@ static void s_stage_status_callback(dap_client_t *a_client, void *a_arg)
 static void s_stage_status_error_callback(dap_client_t *a_client, void *a_arg)
 {
     dap_chain_node_client_t *l_node_client = DAP_CHAIN_NODE_CLIENT(a_client);
+    if(!l_node_client)
+        return;
     // check for last attempt
     bool l_is_last_attempt = a_arg ? true : false;
     if(l_is_last_attempt){
@@ -471,6 +473,8 @@ dap_chain_node_client_t* dap_chain_client_connect(dap_chain_node_info_t *a_node_
 //    dap_client_stage_t l_stage_target = STAGE_STREAM_STREAMING;
 
     l_node_client->state = NODE_CLIENT_STATE_CONNECT;
+    // ref pvt client
+    //dap_client_pvt_ref(DAP_CLIENT_PVT(l_node_client->client));
     // Handshake & connect
     dap_client_go_stage(l_node_client->client, a_stage_target, s_stage_connected_callback);
     return l_node_client;
diff --git a/dap_chain_node_client.h b/dap_chain_node_client.h
index 21678c23bf4ffb5d4b7a08f1dd004e5adda35dfc..4a5eb2e307768a133a46050a280d871b4bff22e2 100644
--- a/dap_chain_node_client.h
+++ b/dap_chain_node_client.h
@@ -75,7 +75,7 @@ typedef struct dap_chain_node_client {
 
     bool keep_connection;
 } dap_chain_node_client_t;
-#define DAP_CHAIN_NODE_CLIENT(a) ( (dap_chain_node_client_t *) (a)->_inheritor )
+#define DAP_CHAIN_NODE_CLIENT(a) (a ? (dap_chain_node_client_t *) (a)->_inheritor : NULL)
 
 int dap_chain_node_client_init(void);
 
diff --git a/dap_chain_node_ping.c b/dap_chain_node_ping.c
index bf3527d9ca07225715724c02c64cacabc6038d7a..39a3ad083d986dcf6c357d059c854e652f6dabeb 100644
--- a/dap_chain_node_ping.c
+++ b/dap_chain_node_ping.c
@@ -24,10 +24,14 @@
 //#include <sys/socket.h>
 #include <time.h>
 #include <errno.h>
+#include <pthread.h>
 
 #include "dap_common.h"
 #include "dap_client.h"
 #include "dap_strfuncs.h"
+#include "dap_list.h"
+#include "dap_chain_common.h"
+#include "dap_chain_node.h"
 #include "dap_chain_node_ping.h"
 
 /*
@@ -54,9 +58,10 @@
 #else
 #include <signal.h>
 #endif
-
 #include <pthread.h>
 
+#include "iputils/iputils.h"
+
 #include "dap_common.h"
 //#include "dap_client.h"
 #include "dap_strfuncs.h"
@@ -71,7 +76,7 @@ static void* node_ping_proc(void *a_arg)
     int l_port = 0;
     int l_count;
     if(!a_arg)
-        return NULL;
+        return NULL ;
     memcpy(&l_count, a_arg, sizeof(int));
     memcpy(&l_port, (a_arg + sizeof(int)), sizeof(int));
     memcpy(&l_addr, (a_arg + 2 * sizeof(int)), sizeof(struct in_addr));
@@ -81,7 +86,7 @@ static void* node_ping_proc(void *a_arg)
     struct sockaddr_in sa4 = { .sin_family = AF_INET, .sin_addr = l_addr };
     const char* str_ip4 = inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), host4, INET_ADDRSTRLEN);
     if(!str_ip4)
-        return NULL;
+        return NULL ;
     //printf(" %s %d ping start\n", str_ip4, l_count);
     /*
      // send ping
@@ -115,7 +120,7 @@ static void* node_ping_proc(void *a_arg)
             uint8_t l_buf[l_buf_size];
 
             const char* str_ip4 = inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), host4,
-                    INET_ADDRSTRLEN);
+            INET_ADDRSTRLEN);
             char *l_str_to_send = dap_strdup_printf("GET /%s/ping_sub_url HTTP/1.1\r\nHost: %s\r\n\r\n",
             DAP_UPLINK_PATH_ENC_INIT, str_ip4);
             // send data to bad suburl
@@ -131,8 +136,8 @@ static void* node_ping_proc(void *a_arg)
             }
             DAP_DELETE(l_str_to_send);
         }
-        else{
-            ;//log_it(L_INFO, "Can't connect to node for ping");
+        else {
+            ; //log_it(L_INFO, "Can't connect to node for ping");
         }
         closesocket(l_socket);
     }
@@ -160,11 +165,10 @@ int wait_node_ping(pthread_t l_thread, int timeout_ms)
     timeout_ms *= 1000;
     l_wait_time.tv_sec += timeout_ms / DAP_USEC_PER_SEC;
     l_wait_time.tv_nsec += 1000 * (timeout_ms % DAP_USEC_PER_SEC);
-
-#ifdef __ANDROID__
-    int res = pthread_join(l_thread, (void **) &l_ping_time);
-#else
+#if !defined(_WIN32) && !defined(__ANDROID__)
     int res = pthread_timedjoin_np(l_thread, (void **) &l_ping_time, &l_wait_time);
+#else
+    int res = pthread_join(l_thread, (void **) &l_ping_time);
 #endif
     if(res == ETIMEDOUT) {
         pthread_kill(l_thread, 3); // SIGQUIT SIGABRT
@@ -173,3 +177,142 @@ int wait_node_ping(pthread_t l_thread, int timeout_ms)
         return l_ping_time;
     return -1;
 }
+
+static dap_chain_node_addr_t *s_node_addr_tr = NULL, *s_node_addr_ping = NULL;
+
+static void* node_ping_background_proc(void *a_arg)
+{
+    dap_chain_net_t *l_net;
+    dap_list_t *l_node_list;
+    memcpy(&l_net, a_arg, sizeof(dap_chain_net_t*));
+    memcpy(&l_node_list, a_arg + sizeof(dap_chain_net_t*), sizeof(dap_list_t*));
+    DAP_DELETE(a_arg);
+    dap_chain_node_addr_t l_node_addr = { 0 };
+
+
+    // select the nearest node from the list
+    unsigned int l_nodes_count = dap_list_length(l_node_list);
+    unsigned int l_thread_id = 0;
+    pthread_t *l_threads = DAP_NEW_Z_SIZE(pthread_t, sizeof(pthread_t) * l_nodes_count);
+    uint64_t *l_nodes_addr = DAP_NEW_Z_SIZE(uint64_t, sizeof(uint64_t) * l_nodes_count);
+    dap_list_t *l_node_list0 = l_node_list;
+
+    dap_chain_node_addr_t *s_node_addr_tr = NULL, *l_node_addr_ping = NULL;
+    int l_min_hops = INT32_MAX;
+    int l_min_ping = INT32_MAX;
+    // send ping to all nodes
+    while(l_node_list) {
+        dap_chain_node_addr_t *l_node_addr = l_node_list->data;
+        dap_chain_node_info_t *l_node_info = dap_chain_node_info_read(l_net, l_node_addr);
+
+
+        char *host4 = DAP_NEW_SIZE(char, INET_ADDRSTRLEN);
+        struct sockaddr_in sa4 = { .sin_family = AF_INET, .sin_addr = l_node_info->hdr.ext_addr_v4 };
+        const char* str_ip4 = inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), host4, INET_ADDRSTRLEN);
+        if(!str_ip4)
+            continue;
+        int hops = 0, time_usec = 0;
+        int res = traceroute_util(str_ip4, &hops, &time_usec);
+        DAP_DELETE(host4);
+        if(l_min_hops>hops)
+            s_node_addr_tr = l_node_list->data;
+
+        // start sending ping
+        start_node_ping(&l_threads[l_thread_id], l_node_info->hdr.ext_addr_v4, l_node_info->hdr.ext_port, 1);
+
+        l_nodes_addr[l_thread_id] = l_node_info->hdr.address.uint64;
+        l_thread_id++;
+        DAP_DELETE(l_node_info);
+        l_node_list = dap_list_next(l_node_list);
+    }
+    // wait for reply from nodes
+    int best_node_pos = -1;
+    int best_node_reply = INT32_MAX;
+    // timeout for all threads
+    int l_timeout_full_ms = 3000; // wait max 3 second
+    for(l_thread_id = 0; l_thread_id < l_nodes_count; l_thread_id++) {
+        if(l_timeout_full_ms < 100)
+            l_timeout_full_ms = 100; // make small timeout anyway, may be
+        struct timespec l_time_start;
+        clock_gettime(CLOCK_MONOTONIC, &l_time_start);
+        int res = wait_node_ping(l_threads[l_thread_id], l_timeout_full_ms);
+        if(res > 0 && res < best_node_reply) {
+            best_node_pos = l_thread_id;
+            s_node_addr_ping = l_node_list->data;
+            best_node_reply = res;
+        }
+        struct timespec l_time_stop;
+        clock_gettime(CLOCK_MONOTONIC, &l_time_stop);
+        l_timeout_full_ms -= timespec_diff(&l_time_start, &l_time_stop, NULL);
+        //printf(" thread %x ping=%d\n", l_threads[l_thread_id], res);
+    }
+    if(best_node_pos > 0) {
+        l_node_addr.uint64 = l_nodes_addr[best_node_pos];
+    }
+
+    // allocate memory for best node addresses
+    dap_chain_node_addr_t *s_node_addr_tmp;
+    s_node_addr_tmp = DAP_NEW(dap_chain_node_addr_t);
+    memcmp(s_node_addr_tmp, s_node_addr_tr, sizeof(dap_chain_node_addr_t));
+    s_node_addr_tr = s_node_addr_tmp;
+    s_node_addr_tmp = DAP_NEW(dap_chain_node_addr_t);
+    memcmp(s_node_addr_tmp, s_node_addr_ping, sizeof(dap_chain_node_addr_t));
+    s_node_addr_ping = s_node_addr_tmp;
+
+    // delete memory
+    DAP_DELETE(l_nodes_addr);
+    DAP_DELETE(l_threads);
+    dap_list_free_full(l_node_list0, free);
+    return 0;
+}
+
+static pthread_t s_thread = 0;
+
+// start background thread for testing connect to the nodes
+int dap_chain_node_ping_background_start(dap_chain_net_t *a_net, dap_list_t *a_node_list)
+{
+    if(!a_node_list)
+        return -1;
+    // already started
+    if(s_thread)
+        return 0;
+    // copy list
+    dap_list_t *l_node_list = NULL;
+    dap_list_t *l_node_list_tmp = a_node_list;
+    while(l_node_list_tmp) {
+        dap_chain_node_addr_t *l_addr = DAP_NEW(dap_chain_node_addr_t);
+        memcpy(l_addr, l_node_list_tmp->data, sizeof(dap_chain_node_addr_t));
+        l_node_list = dap_list_append(l_node_list, l_addr);
+        l_node_list_tmp = dap_list_next(l_node_list_tmp);
+    }
+    // start searching for better nodes
+    uint8_t *l_arg = DAP_NEW_SIZE(uint8_t, sizeof(dap_chain_net_t*) + sizeof(dap_chain_net_t*));
+    memcpy(l_arg, &a_net, sizeof(dap_chain_net_t*));
+    memcpy(l_arg + sizeof(dap_chain_net_t*), &l_node_list, sizeof(dap_list_t*));
+    pthread_create(&s_thread, NULL, node_ping_background_proc, l_arg);
+    return 0;
+}
+
+const dap_chain_node_addr_t* dap_chain_node_ping_get_node_tr(void)
+{
+    return s_node_addr_tr;
+}
+
+const dap_chain_node_addr_t* dap_chain_node_ping_get_node_ping(void)
+{
+    return s_node_addr_ping;
+}
+
+int dap_chain_node_ping_background_stop(void)
+{
+    int l_ret = wait_node_ping(s_thread, 500);
+    s_thread = 0;
+    return l_ret;
+}
+
+int dap_chain_node_ping_background_status(void)
+{
+    if(s_thread)
+        return 1;
+    return 0;
+}
diff --git a/dap_chain_node_ping.h b/dap_chain_node_ping.h
index 8289031c8fab5b8ebfef3aa799ec38f48dc8b659..a44f4fc25966047b079e9f6d15daee117daa6150 100644
--- a/dap_chain_node_ping.h
+++ b/dap_chain_node_ping.h
@@ -20,7 +20,11 @@
  */
 #pragma once
 
+#ifndef _WIN32
 #include <netinet/in.h>
+#else
+#include <windows.h>
+#endif
 #include <pthread.h>
 
 // start sending ping
@@ -28,3 +32,9 @@ int start_node_ping(pthread_t *a_thread, struct in_addr a_addr, int a_port, int
 
 // wait for ending ping within timeout_ms milliseconds
 int wait_node_ping(pthread_t l_thread, int timeout_ms);
+
+
+// background thread for testing connect to the nodes
+int dap_chain_node_ping_background_start(dap_chain_net_t *a_net, dap_list_t *a_node_list);
+int dap_chain_node_ping_background_stop(void);
+int dap_chain_node_ping_background_status(void);
diff --git a/iputils/iputils.h b/iputils/iputils.h
index d7948fb516426365b93229a56c8d153127f5b035..0330b548f1a23b5b677a4218683a933a169669e5 100644
--- a/iputils/iputils.h
+++ b/iputils/iputils.h
@@ -7,7 +7,18 @@
 
 #include <stdint.h>
 #include <stdlib.h>
+#ifndef _WIN32
 #include <netinet/ip.h>
+#else
+#include <winsock2.h>
+#include <windows.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <io.h>
+#include "win32/iphdr.h"
+#include "win32/ip.h"
+#define uid_t uint32_t
+#endif
 #include <setjmp.h>
 #include <sys/time.h>