diff --git a/dap-sdk b/dap-sdk
index b3ff1c9d8e1d1744c3d58d03c0fe7861115f27e6..277fc0459376d770da32c4a6d885824fbebd7b69 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit b3ff1c9d8e1d1744c3d58d03c0fe7861115f27e6
+Subproject commit 277fc0459376d770da32c4a6d885824fbebd7b69
diff --git a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
index fd65fc77799b8f83340383c5358f491f82d84e41..762a57f1caf58836a566a090667950eda0375457 100644
--- a/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
+++ b/modules/channel/chain-net-srv/dap_stream_ch_chain_net_srv.c
@@ -1190,8 +1190,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
         }
         l_request->err_code = 0;
 
-        strncpy(l_request->ip_send, a_ch->stream->esocket->remote_addr_str, INET_ADDRSTRLEN - 1);
-        l_request->ip_send[INET_ADDRSTRLEN - 1] = '\0'; // Compiler warning escape
+        dap_strncpy(l_request->host_send, a_ch->stream->esocket->remote_addr_str, 0xFF);
         l_request->recv_time2 = dap_nanotime_now();
 
         dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE, l_request,
diff --git a/modules/channel/chain-voting/dap_stream_ch_chain_voting.c b/modules/channel/chain-voting/dap_stream_ch_chain_voting.c
index bc51e1c74d2febc7eae877b0bfefde7d83b73ae1..4f3c204c3719c19078659613fc100f268d700bbc 100644
--- a/modules/channel/chain-voting/dap_stream_ch_chain_voting.c
+++ b/modules/channel/chain-voting/dap_stream_ch_chain_voting.c
@@ -89,11 +89,9 @@ void dap_stream_ch_chain_voting_message_write(dap_chain_net_t *a_net, dap_chain_
         pthread_rwlock_unlock(&s_node_client_list_lock);
         if (!l_node_client_item) {
             size_t node_info_size = 0;
-            char *l_key = dap_chain_node_addr_to_hash_str(a_remote_node_addr);
-            dap_chain_node_info_t *l_node_info =
-                    (dap_chain_node_info_t *)dap_global_db_get_sync(a_net->pub.gdb_nodes, l_key,
-                                                                        &node_info_size, NULL, NULL);
-            DAP_DELETE(l_key);
+            dap_chain_node_info_t *l_node_info = (dap_chain_node_info_t*)dap_global_db_get_sync(a_net->pub.gdb_nodes,
+                    dap_chain_node_addr_to_str_static(a_remote_node_addr),
+                    &node_info_size, NULL, NULL);
             if (!l_node_info) {
                 log_it(L_WARNING, "Can't find validator's addr "NODE_ADDR_FP_STR" in database", NODE_ADDR_FP_ARGS(a_remote_node_addr));
                 return;
diff --git a/modules/common/dap_chain_datum_decree.c b/modules/common/dap_chain_datum_decree.c
index 6878b0af90492c084653c7d8c7f48b634a7de11f..38758a133ae949afc47c62ef1859caf438ae719f 100644
--- a/modules/common/dap_chain_datum_decree.c
+++ b/modules/common/dap_chain_datum_decree.c
@@ -303,22 +303,9 @@ void dap_chain_datum_decree_dump(dap_string_t *a_str_out, dap_chain_datum_decree
                 char *l_min_signers_count_str = dap_uint256_to_char(l_min_signers_count, NULL);
                 dap_string_append_printf(a_str_out, "\tMin signers count: %s\n", l_min_signers_count_str);
                 break;
-            case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V4: {
-                struct in_addr l_ip_addr = dap_tsd_get_scalar(l_tsd, struct in_addr);
-                char l_tm[INET_ADDRSTRLEN];
-                dap_string_append_printf(a_str_out, "\tIP address: %s\n", inet_ntop(AF_INET, &l_ip_addr,
-                                                                                  l_tm, INET_ADDRSTRLEN));
-            } break;
-            case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V6: {
-                struct in6_addr l_ip_addr = dap_tsd_get_scalar(l_tsd, struct in6_addr);
-                char l_tm[INET6_ADDRSTRLEN];
-                dap_string_append_printf(a_str_out, "\tIP address: %s\n", inet_ntop(AF_INET6,
-                                                                                  &l_ip_addr, l_tm,
-                                                                                  INET6_ADDRSTRLEN));
-            } break;
+            case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HOST:
             case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR: {
-                dap_chain_node_addr_t l_addr = dap_tsd_get_scalar(l_tsd, dap_chain_node_addr_t);
-                dap_string_append_printf(a_str_out, "\tNode address: "NODE_ADDR_FP_STR"\n", NODE_ADDR_FP_ARGS_S(l_addr));
+                dap_string_append_printf(a_str_out, "\tNode address: %s\n", dap_tsd_get_string(l_tsd));
             } break;
             default:
                 dap_string_append_printf(a_str_out, "\t<UNKNOWN_TYPE_TSD_SECTION>\n");
diff --git a/modules/common/include/dap_chain_datum_decree.h b/modules/common/include/dap_chain_datum_decree.h
index 6cef21196f774b820e6de33579617b0154346aee..42964d99c508c3717876134c261584b57ca79b77 100644
--- a/modules/common/include/dap_chain_datum_decree.h
+++ b/modules/common/include/dap_chain_datum_decree.h
@@ -87,8 +87,7 @@ DAP_STATIC_INLINE size_t dap_chain_datum_decree_get_size(dap_chain_datum_decree_
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_SIGNER_NODE_ADDR              0x0110
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_MIN_VALUE                     0x0111
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_MIN_SIGNERS_COUNT             0x0112
-#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V4                               0x0113
-#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V6                               0x0114
+#define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HOST                                0x0113
 #define DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR                           0x0115
 
 DAP_STATIC_INLINE const char *dap_chain_datum_decree_subtype_to_str(uint16_t a_decree_subtype)
@@ -145,10 +144,8 @@ DAP_STATIC_INLINE const char *dap_chain_datum_decree_tsd_type_to_str(uint16_t a_
             return "DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_MIN_VALUE";
         case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_MIN_SIGNERS_COUNT:
             return "DAP_CHAIN_DATUM_DECREE_TSD_TYPE_STAKE_MIN_SIGNERS_COUNT";
-        case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V4:
-            return "DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V4";
-        case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V6:
-            return "DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V6";
+        case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HOST:
+            return "DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HOST";
         case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR:
             return "DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR";
         default:
diff --git a/modules/net/dap_chain_ledger.c b/modules/net/dap_chain_ledger.c
index 6d5ab8d9e6b5f41e0a4b740ddf513bd2ba71e76d..67b87f9b7c1efdd3f444fd2754ccadf197b7decb 100644
--- a/modules/net/dap_chain_ledger.c
+++ b/modules/net/dap_chain_ledger.c
@@ -3834,7 +3834,7 @@ int dap_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx
                 if (l_err_num)
                     break;
                 l_bound_item->in.addr_from = *l_addr_from;
-                strncpy(l_bound_item->in.token_ticker, l_token, DAP_CHAIN_TICKER_SIZE_MAX - 1);
+                dap_strncpy(l_bound_item->in.token_ticker, l_token, DAP_CHAIN_TICKER_SIZE_MAX - 1);
                 // 4. compare public key hashes in the signature of the current transaction and in the 'out' item of the previous transaction
                 if (!dap_hash_fast_compare(&l_tx_first_sign_pkey_hash, &l_addr_from->data.hash_fast)) {
                     l_err_num = DAP_LEDGER_TX_CHECK_PKEY_HASHES_DONT_MATCH;
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 6cf246bbf22414b6704e17c05352c94ca7784c68..0ca54f3c6bb76632b92bbe85b122bd0c4c731e51 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -115,12 +115,12 @@
 #include "json_object.h"
 #include "dap_chain_net_srv_stake_pos_delegate.h"
 #include "dap_chain_net_srv_xchange.h"
-#include "dap_chain_node_net_ban_list.h"
 #include "dap_chain_cs_esbocs.h"
 #include "dap_chain_net_voting.h"
 #include "dap_global_db_cluster.h"
 #include "dap_link_manager.h"
 #include "dap_stream_cluster.h"
+#include "dap_http_ban_list_client.h"
 
 #include <stdio.h>
 #include <sys/types.h>
@@ -136,7 +136,6 @@ struct balancer_link_request {
     dap_chain_node_info_t *link_info;
     dap_chain_net_t *net;
     dap_worker_t *worker;
-    bool from_http;
     int link_replace_tries;
 };
 
@@ -169,10 +168,10 @@ typedef struct dap_chain_net_pvt{
     uint16_t poa_nodes_count;
     dap_stream_node_addr_t *poa_nodes_addrs;
     bool seeds_is_poas;
+
     uint16_t seed_nodes_count;
-    struct sockaddr_in *seed_nodes_ipv4;
-    struct sockaddr_in6 *seed_nodes_ipv6;       // TODO
-    dap_stream_node_addr_t *seed_nodes_addrs;
+    dap_chain_node_info_t **seed_nodes_info;
+
     _Atomic(dap_chain_net_state_t) state, state_target;
     uint16_t acl_idx;
 
@@ -189,7 +188,7 @@ typedef struct dap_chain_net_pvt{
 } dap_chain_net_pvt_t;
 
 typedef struct dap_chain_net_item{
-    char name[DAP_CHAIN_NET_NAME_MAX];
+    char name[DAP_CHAIN_NET_NAME_MAX + 1];
     dap_chain_net_id_t net_id;
     dap_chain_net_t *chain_net;
     UT_hash_handle hh, hh2;
@@ -263,7 +262,7 @@ int dap_chain_net_init()
     dap_stream_ch_chain_net_init();
     dap_chain_node_client_init();
     dap_chain_net_voting_init();
-    dap_chain_node_net_ban_list_init();
+    dap_http_ban_list_client_init();
     dap_cli_server_cmd_add ("net", s_cli_net, "Network commands",
         "net list [chains -net <chain net name>]\n"
             "\tList all networks or list all chains in selected network\n"
@@ -398,17 +397,25 @@ dap_chain_net_state_t dap_chain_net_get_target_state(dap_chain_net_t *a_net)
 
 dap_chain_node_info_t *dap_chain_net_balancer_link_from_cfg(dap_chain_net_t *a_net)
 {
-// sanity check
-    dap_return_val_if_pass_err(!a_net || !PVT(a_net) || !PVT(a_net)->seed_nodes_count, NULL, "No valid balancer links found");
-// memory alloc
-    dap_chain_node_info_t *l_link_node_info = NULL;
-    DAP_NEW_Z_RET_VAL(l_link_node_info, dap_chain_node_info_t, NULL, NULL);
-// func work
-    dap_chain_net_pvt_t *l_net_pvt = PVT(a_net);
-    uint16_t i = dap_random_uint16() % l_net_pvt->seed_nodes_count;
-    l_link_node_info->hdr.ext_addr_v4 = l_net_pvt->seed_nodes_ipv4[i].sin_addr;
-    l_link_node_info->hdr.ext_port = l_net_pvt->seed_nodes_ipv4[i].sin_port;
-    return l_link_node_info;
+    switch (PVT(a_net)->seed_nodes_count) {
+    case 0: return log_it(L_ERROR, "No available links! Add them in net config"), NULL;
+    case 1: return PVT(a_net)->seed_nodes_info[0];
+    default: return PVT(a_net)->seed_nodes_info[dap_random_uint16() % PVT(a_net)->seed_nodes_count];
+    }
+}
+
+dap_chain_node_info_t *dap_chain_net_get_my_node_info(dap_chain_net_t *a_net) {
+    return PVT(a_net)->node_info;
+}
+
+void dap_chain_net_add_cluster_link(dap_chain_net_t *a_net, dap_stream_node_addr_t *a_node_addr)
+{
+    dap_return_if_fail(a_net && a_node_addr);
+    dap_cluster_t *l_links_cluster = dap_cluster_by_mnemonim(a_net->pub.name);
+    if (l_links_cluster)
+        dap_cluster_member_add(l_links_cluster, a_node_addr, 0, NULL);
+    else
+        log_it(L_ERROR, "Not found links cluster for net %s", a_net->pub.name);
 }
 
 /**
@@ -425,12 +432,12 @@ static void s_fill_links_from_root_aliases(dap_chain_net_t *a_net)
     for (size_t i = 0; i < l_net_pvt->seed_nodes_count; i++) {
         //if (PVT(a_net)->seeds_is_poas)
         //    l_link_node_info.hdr.address = l_net_pvt->poa_nodes_addrs[i];
-        dap_link_t *l_link = dap_link_manager_link_create_or_update(&l_net_pvt->seed_nodes_addrs[i], 
-            &l_net_pvt->seed_nodes_ipv4[i].sin_addr, &l_net_pvt->seed_nodes_ipv6[i].sin6_addr, l_net_pvt->seed_nodes_ipv4[i].sin_port);
-        if (!l_link)
+        if ( !(l_link = dap_link_manager_link_create_or_update(&l_net_pvt->seed_nodes_info[i]->address,
+                l_net_pvt->seed_nodes_info[i]->ext_host,
+                l_net_pvt->seed_nodes_info[i]->ext_port)) )
             continue;
         if (dap_link_manager_link_add(a_net->pub.id.uint64, l_link))
-            DAP_DELETE(l_link);
+            DAP_DEL_Z(l_link);
     }
 }
 
@@ -519,11 +526,11 @@ static void s_link_manager_callback_error(dap_link_t *a_link, uint64_t a_net_id,
 // func work
     dap_chain_net_t *l_net = dap_chain_net_by_id((dap_chain_net_id_t){.uint64 = a_net_id});
     dap_chain_net_pvt_t *l_net_pvt = PVT(l_net);
-    log_it(L_WARNING, "Can't establish link with %s."NODE_ADDR_FP_STR, l_net ? l_net->pub.name : "(unknown)" ,
-           NODE_ADDR_FP_ARGS_S(a_link->node_addr));
+    log_it(L_WARNING, "Can't establish link with %s."NODE_ADDR_FP_STR,
+           l_net ? l_net->pub.name : "(unknown)", NODE_ADDR_FP_ARGS_S(a_link->node_addr));
     if (l_net){
         struct json_object *l_json = s_net_states_json_collect(l_net);
-        char l_err_str[128] = { };
+        char l_err_str[512] = { };
         snprintf(l_err_str, sizeof(l_err_str)
                      , "Link " NODE_ADDR_FP_STR " [%s] can't be established, errno %d"
                      , NODE_ADDR_FP_ARGS_S(a_link->node_addr), a_link->client->uplink_addr, a_error);
@@ -563,12 +570,10 @@ static void s_net_links_complete_and_start(dap_chain_net_t *a_net, dap_worker_t
 static void s_net_balancer_link_prepare_success(dap_worker_t * a_worker, dap_chain_net_node_balancer_t * a_link_full_node_list, void * a_arg)
 {
     if(s_debug_more){
-        char l_node_addr_str[INET_ADDRSTRLEN]={};
         dap_chain_node_info_t * l_node_info = (dap_chain_node_info_t *)a_link_full_node_list->nodes_info;
-        for(size_t i = 0; i < a_link_full_node_list->count_node; ++i){
-            inet_ntop(AF_INET,&(l_node_info + i)->hdr.ext_addr_v4,l_node_addr_str, INET_ADDRSTRLEN);
-            log_it(L_DEBUG,"Link " NODE_ADDR_FP_STR " (%s) prepare success", NODE_ADDR_FP_ARGS_S((l_node_info + i)->hdr.address),
-                                                                                         l_node_addr_str );
+        for(size_t i = 0; i < a_link_full_node_list->count_node; ++i) {
+            log_it( L_DEBUG,"Link " NODE_ADDR_FP_STR " [ %s : %u ] prepare success",
+                   NODE_ADDR_FP_ARGS_S((l_node_info + i)->address), (l_node_info + i)->ext_host, (l_node_info + i)->ext_port);
         }
     }
 
@@ -578,30 +583,24 @@ static void s_net_balancer_link_prepare_success(dap_worker_t * a_worker, dap_cha
     char l_err_str[128] = { };
     struct json_object *l_json;
     for(size_t i = 0; i < a_link_full_node_list->count_node; ++i){
-        dap_link_t *l_link = dap_link_manager_link_create_or_update(&l_node_info[i].hdr.address, 
-            &l_node_info[i].hdr.ext_addr_v4, &l_node_info[i].hdr.ext_addr_v6, l_node_info[i].hdr.ext_port);
+        dap_link_t *l_link = dap_link_manager_link_create_or_update(&l_node_info[i].address, 
+            l_node_info[i].ext_host, l_node_info[i].ext_port);
         if (!l_link)
             continue;
         switch (dap_link_manager_link_add(l_net->pub.id.uint64, l_link)) {
-            case 0:
-                l_json = s_net_states_json_collect(l_net);
-
-                snprintf(l_err_str, sizeof(l_err_str)
-                            , "Link " NODE_ADDR_FP_STR " prepared"
-                            , NODE_ADDR_FP_ARGS_S((l_node_info + i)->hdr.address));
-                json_object_object_add(l_json, "errorMessage", json_object_new_string(l_err_str));
-                dap_notify_server_send_mt(json_object_get_string(l_json));
-                json_object_put(l_json);
-                debug_if(s_debug_more, L_DEBUG, "Link "NODE_ADDR_FP_STR" successfully added",
-                                                    NODE_ADDR_FP_ARGS_S((l_node_info + i)->hdr.address));
-                break;
-            case 1:
-                debug_if(s_debug_more, L_DEBUG, "Maximum prepared links reached");
-                break;
-            case -1:
-                break;
-            default:
-                break;
+        case 0:
+            l_json = s_net_states_json_collect(l_net);
+            snprintf(l_err_str, sizeof(l_err_str)
+                         , "Link " NODE_ADDR_FP_STR " prepared"
+                         , NODE_ADDR_FP_ARGS_S((l_node_info + i)->address));
+            json_object_object_add(l_json, "errorMessage", json_object_new_string(l_err_str));
+            dap_notify_server_send_mt(json_object_get_string(l_json));
+            json_object_put(l_json);
+            debug_if(s_debug_more, L_DEBUG, "Link "NODE_ADDR_FP_STR" successfully added",
+                     NODE_ADDR_FP_ARGS_S((l_node_info + i)->address));
+            break;
+        case 1: debug_if(s_debug_more, L_DEBUG, "Maximum prepared links reached"); break;
+        default: break;
         }
     }
 
@@ -624,15 +623,15 @@ static void s_net_balancer_link_prepare_error(dap_worker_t * a_worker, void * a_
     struct balancer_link_request *l_balancer_request = (struct balancer_link_request *)a_arg;
     dap_chain_net_t * l_net = l_balancer_request->net;
     dap_chain_node_info_t *l_node_info = l_balancer_request->link_info;
-    char l_node_addr_str[INET_ADDRSTRLEN]={};
-    inet_ntop(AF_INET, &l_node_info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
-    log_it(L_WARNING, "Link from balancer "NODE_ADDR_FP_STR" (%s) prepare error with code %d",
-                                NODE_ADDR_FP_ARGS_S(l_node_info->hdr.address), l_node_addr_str,a_errno);
+
+    log_it(L_WARNING, "Link from balancer "NODE_ADDR_FP_STR" [ %s ] prepare error with code %d",
+                      NODE_ADDR_FP_ARGS_S(l_node_info->address),
+                      l_node_info->ext_host, a_errno);
     struct json_object *l_json = s_net_states_json_collect(l_net);
-    char l_err_str[128] = { };
-    snprintf(l_err_str, sizeof(l_err_str)
+    char l_err_str[512] = { '\0' };
+    dap_snprintf(l_err_str, sizeof(l_err_str)
                  , "Link from balancer " NODE_ADDR_FP_STR " [%s] can't be prepared, errno %d"
-                 , NODE_ADDR_FP_ARGS_S(l_node_info->hdr.address), l_node_addr_str, a_errno);
+                 , NODE_ADDR_FP_ARGS_S(l_node_info->address), l_node_info->ext_host, a_errno);
     json_object_object_add(l_json, "errorMessage", json_object_new_string(l_err_str));
     dap_notify_server_send_mt(json_object_get_string(l_json));
     json_object_put(l_json);
@@ -690,8 +689,8 @@ static bool s_new_balancer_link_request(dap_chain_net_t *a_net, int a_link_repla
                         NODE_ADDR_FP_ARGS(l_net_pvt->permanent_links + i));
                 continue;
             }
-            dap_link_t *l_link = dap_link_manager_link_create_or_update(&l_link_node_info[i].hdr.address, 
-                    &l_link_node_info[i].hdr.ext_addr_v4, &l_link_node_info[i].hdr.ext_addr_v6, l_link_node_info[i].hdr.ext_port);
+            dap_link_t *l_link = dap_link_manager_link_create_or_update(&l_link_node_info[i].address, 
+                    l_link_node_info[i].ext_host, l_link_node_info[i].ext_port);
             dap_link_manager_link_add(a_net->pub.id.uint64, l_link);
             DAP_DELETE(l_link_node_info);
         }
@@ -708,58 +707,48 @@ static bool s_new_balancer_link_request(dap_chain_net_t *a_net, int a_link_repla
 
             for(size_t i = 0; i < l_node_cnt; ++i) {
                 int l_net_link_add = 0;
-                dap_link_t *l_link = dap_link_manager_link_create_or_update(&l_node_info[i].hdr.address, 
-                    &l_node_info[i].hdr.ext_addr_v4, &l_node_info[i].hdr.ext_addr_v6, l_node_info[i].hdr.ext_port);
+                dap_link_t *l_link = dap_link_manager_link_create_or_update(&l_node_info[i].address, 
+                    l_node_info[i].ext_host, l_node_info[i].ext_port);
                 if (!l_link)
                     continue;
                 l_net_link_add = dap_link_manager_link_add(a_net->pub.id.uint64, l_link);
                 switch (l_net_link_add) {
-                    case 0:
-                        log_it(L_MSG, "Network LOCAL balancer issues link IP %s, [%ld blocks]", l_link->client->uplink_addr,l_node_info->info.atoms_count);
-                        break;
-                    case -1:
-                        log_it(L_MSG, "Network LOCAL balancer: Node %s is already among links", l_link->client->uplink_addr);
-                        break;
-                    case -2:
-                        log_it(L_MSG, "Network LOCAL balancer: Link manager not active");
-                        break;
-                    case 1:
-                        log_it(L_MSG, "Network links table is full");
-                        break;
-                    default:
-                        break;
+                case 0: log_it(L_MSG, "Network LOCAL balancer issues link IP %s", (l_node_info + i)->ext_host); break;
+                case -1: log_it(L_MSG, "Network LOCAL balancer: IP %s is already among links", (l_node_info + i)->ext_host); break;
+                case -2: log_it(L_MSG, "Network LOCAL balancer: Link manager not active"); break;
+                case 1: log_it(L_MSG, "Network links table is full"); break;
+                default: break;
                 }
             }
             DAP_DEL_MULTY(l_link_full_node_list);
         }
     }
-    dap_chain_node_info_t *l_link_node_info = dap_chain_net_balancer_link_from_cfg(a_net);
-    if (!l_link_node_info)
-        return false;
-    char l_node_addr_str[INET_ADDRSTRLEN] = {};
-    inet_ntop(AF_INET, &l_link_node_info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
-    log_it(L_DEBUG, "Start balancer %s request to %s", PVT(a_net)->balancer_http ? "HTTP" : "DNS", l_node_addr_str);
+    
     struct balancer_link_request *l_balancer_request = DAP_NEW_Z(struct balancer_link_request);
     if (!l_balancer_request) {
         log_it(L_CRITICAL, "Memory allocation error");
-        DAP_DELETE(l_link_node_info);
         return false;
     }
-    l_balancer_request->net = a_net;
-    l_balancer_request->link_info = l_link_node_info;
-    l_balancer_request->worker = dap_events_worker_get_auto();
-    l_balancer_request->link_replace_tries = a_link_replace_tries + 1;
+    *l_balancer_request = (struct balancer_link_request) {
+        .link_info = dap_chain_net_balancer_link_from_cfg(a_net),
+        .net = a_net,
+        .worker = dap_events_worker_get_auto(),
+        .link_replace_tries = a_link_replace_tries + 1
+    };
+
+    log_it(L_DEBUG, "Start balancer %s request to %s",
+           PVT(a_net)->balancer_http ? "HTTP" : "DNS", l_balancer_request->link_info->ext_host);
+    
     int ret;
     if (PVT(a_net)->balancer_http) {
-        l_balancer_request->from_http = true;
         char *l_request = dap_strdup_printf("%s/%s?version=1,method=r,needlink=%d,net=%s",
                                                 DAP_UPLINK_PATH_BALANCER,
                                                 DAP_BALANCER_URI_HASH,
                                                 a_required_links_count,
                                                 a_net->pub.name);
         ret = dap_client_http_request(l_balancer_request->worker,
-                                                l_node_addr_str,
-                                                l_link_node_info->hdr.ext_port,
+                                                l_balancer_request->link_info->ext_host,
+                                                l_balancer_request->link_info->ext_port,
                                                 "GET",
                                                 "text/text",
                                                 l_request,
@@ -772,18 +761,18 @@ static bool s_new_balancer_link_request(dap_chain_net_t *a_net, int a_link_repla
                                                 NULL) == NULL;
         DAP_DELETE(l_request);
     } else {
-        l_link_node_info->hdr.ext_port = DNS_LISTEN_PORT;
-        ret = dap_chain_node_info_dns_request(l_balancer_request->worker,
+        l_balancer_request->link_info->ext_port = DNS_LISTEN_PORT;
+        // TODO: change signature and implementation
+        ret = /* dap_chain_node_info_dns_request(l_balancer_request->worker,
                                                 l_link_node_info->hdr.ext_addr_v4,
                                                 l_link_node_info->hdr.ext_port,
                                                 a_net->pub.name,
                                                 s_net_balancer_link_prepare_success,
                                                 s_net_balancer_link_prepare_error,
-                                                l_balancer_request);
+                                                l_balancer_request); */ -1;
     }
     if (ret) {
         log_it(L_ERROR, "Can't process balancer link %s request", PVT(a_net)->balancer_http ? "HTTP" : "DNS");
-        DAP_DELETE(l_balancer_request->link_info);
         DAP_DELETE(l_balancer_request);
         return false;
     }
@@ -1527,7 +1516,7 @@ static int s_cli_net(int argc, char **argv, void **reply)
                     return DAP_JSON_RPC_ERR_CODE_MEMORY_ALLOCATED;
                 }
                 json_object_object_add(l_jobj_return, "to", l_jobj_to);
-                dap_chain_net_balancer_prepare_list_links(l_net->pub.name,true);
+                dap_chain_net_balancer_prepare_list_links(l_net->pub.name);
                 dap_chain_net_state_go_to(l_net, NET_STATE_ONLINE);
                 l_ret = DAP_CHAIN_NET_JSON_RPC_OK;
             } else if ( strcmp(l_go_str,"offline") == 0 ) {
@@ -2005,7 +1994,7 @@ void s_main_timer_callback(void *a_arg)
             l_net_pvt->state >= NET_STATE_LINKS_ESTABLISHED &&
             !dap_link_manager_links_count(l_net->pub.id.uint64)) // restart network
         dap_chain_net_start(l_net);
-    dap_chain_net_balancer_prepare_list_links(l_net->pub.name,false);
+    dap_chain_net_balancer_prepare_list_links(l_net->pub.name);
 }
 
 /**
@@ -2021,7 +2010,7 @@ void dap_chain_net_deinit()
         dap_chain_net_delete(l_current_item->chain_net);
         DAP_DELETE(l_current_item);
     }
-    dap_chain_node_net_ban_list_deinit();
+    dap_http_ban_list_client_deinit();
 }
 
 /**
@@ -2044,8 +2033,6 @@ void dap_chain_net_delete(dap_chain_net_t *a_net)
     if (PVT(a_net)->main_timer)
         dap_interval_timer_delete(PVT(a_net)->main_timer);
     DAP_DEL_Z(PVT(a_net)->poa_nodes_addrs);
-    DAP_DEL_Z(PVT(a_net)->seed_nodes_ipv4);
-    DAP_DEL_Z(PVT(a_net)->seed_nodes_ipv6);
     DAP_DEL_Z(PVT(a_net)->node_info);
     if (a_net->pub.ledger) {
         dap_ledger_purge(a_net->pub.ledger, true);
@@ -2071,7 +2058,7 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx)
         return -1;
     }
     DAP_DEL_Z(l_cfg_path);
-    dap_chain_net_t * l_net = s_net_new(
+    dap_chain_net_t *l_net = s_net_new(
                                         dap_config_get_item_str(l_cfg , "general" , "id" ),
                                         dap_config_get_item_str(l_cfg , "general" , "name" ),
                                         dap_config_get_item_str(l_cfg , "general" , "native_ticker"),
@@ -2082,24 +2069,19 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx)
         dap_config_close(l_cfg);
         return -1;
     }
-    // check nets with same IDs and names
-    dap_chain_net_item_t *l_net_items_current = NULL, *l_net_items_tmp = NULL;
-    HASH_ITER(hh, s_net_items, l_net_items_current, l_net_items_tmp) {
-        if (l_net_items_current->net_id.uint64 == l_net->pub.id.uint64) {
-            log_it(L_ERROR,"Can't create net %s, net %s has the same ID %"DAP_UINT64_FORMAT_U"", l_net->pub.name, l_net_items_current->name, l_net->pub.id.uint64);
-            log_it(L_ERROR, "Please, fix your configs and restart node");
-            dap_chain_net_delete(l_net);
-            dap_config_close(l_cfg);
-            return -2;
-        }
-        if (!strcmp(l_net_items_current->name, l_net->pub.name)) {
-            log_it(L_ERROR,"Can't create l_net ID %"DAP_UINT64_FORMAT_U", net ID %"DAP_UINT64_FORMAT_U" has the same name %s", l_net->pub.id.uint64, l_net_items_current->net_id.uint64, l_net->pub.name);
-            log_it(L_ERROR, "Please, fix your configs and restart node");
-            dap_chain_net_delete(l_net);
-            dap_config_close(l_cfg);
-            return -3;
-        }
+    
+    dap_chain_net_item_t *l_net_sought = NULL;
+    HASH_FIND_STR(s_net_items, l_net->pub.name, l_net_sought);
+    if (!l_net_sought)
+        HASH_FIND(hh2, s_net_ids, &l_net->pub.id, sizeof(l_net->pub.id), l_net_sought);
+    if (l_net_sought) {
+        log_it(L_ERROR,"Network %s with id %"DAP_UINT64_FORMAT_U" already exists!\n\tFix net configs and restart node",
+               l_net->pub.name, l_net->pub.id.uint64);
+        dap_chain_net_delete(l_net);
+        dap_config_close(l_cfg);
+        return -2;
     }
+    
     l_net->pub.gdb_groups_prefix = dap_strdup(
                 dap_config_get_item_str_default(l_cfg, "general", "gdb_groups_prefix",
                                                 dap_config_get_item_str(l_cfg, "general", "name")));
@@ -2109,7 +2091,7 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx)
     // Bridged netwoks allowed to send transactions to
     uint16_t l_net_ids_count = 0;
     char **l_bridged_net_ids = dap_config_get_array_str(l_cfg, "general", "bridged_network_ids", &l_net_ids_count);
-    for (uint16_t i = 0; i< l_net_ids_count; i++) {
+    for (uint16_t i = 0; i < l_net_ids_count; i++) {
         dap_chain_net_id_t l_id;
         if (dap_chain_net_id_parse(l_bridged_net_ids[i], &l_id) != 0)
             continue;
@@ -2117,17 +2099,17 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx)
     }
 
     // Add network to the list
-    dap_chain_net_item_t *l_net_item = DAP_NEW_Z( dap_chain_net_item_t);
+    dap_chain_net_item_t *l_net_item = DAP_NEW_Z(dap_chain_net_item_t);
     if (!l_net_item) {
-        log_it(L_CRITICAL, "Memory allocation error");
+        log_it(L_CRITICAL, g_error_memory_alloc);
         dap_chain_net_delete(l_net);
         dap_config_close(l_cfg);
         return -4;
     }
-    snprintf(l_net_item->name,sizeof (l_net_item->name),"%s"
-                 ,dap_config_get_item_str(l_cfg , "general" , "name" ));
+    dap_strncpy(l_net_item->name, dap_config_get_item_str(l_cfg, "general", "name"), DAP_CHAIN_NET_NAME_MAX);
     l_net_item->chain_net = l_net;
     l_net_item->net_id.uint64 = l_net->pub.id.uint64;
+    
     HASH_ADD_STR(s_net_items, name, l_net_item);
     HASH_ADD(hh2, s_net_ids, net_id, sizeof(l_net_item->net_id), l_net_item);
 
@@ -2143,141 +2125,47 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx)
         dap_config_close(l_cfg);
         return -15;
     }
-    l_net_pvt->poa_nodes_addrs = DAP_NEW_SIZE(dap_stream_node_addr_t, l_net_pvt->poa_nodes_count * sizeof(dap_stream_node_addr_t));
-    if (!l_net_pvt->poa_nodes_addrs) {
+    l_net_pvt->poa_nodes_addrs = DAP_NEW_Z_COUNT(dap_chain_node_addr_t, l_net_pvt->poa_nodes_count);
+    uint16_t l_seed_nodes_count = 0, l_bootstrap_nodes_count = 0;
+    char **l_seed_nodes_hosts       = dap_config_get_array_str(l_cfg, "general", "seed_nodes_hosts", &l_seed_nodes_count),
+         **l_bootstrap_nodes_hosts  = dap_config_get_array_str(l_cfg, "general", "bootstrap_hosts", &l_bootstrap_nodes_count);
+    l_net_pvt->seed_nodes_count = l_seed_nodes_count;
+    if (l_seed_nodes_count != l_net_pvt->poa_nodes_count) {
+        log_it(L_ERROR, "PoA addresses count mismatches host names count: %u != %u, number of seed links will be reduced",
+            l_net_pvt->poa_nodes_count, l_seed_nodes_count);
+        l_net_pvt->poa_nodes_count = dap_min(l_net_pvt->poa_nodes_count, l_seed_nodes_count);
+    }
+    // TODO: improve bootstrap balancer logic...
+    if ( l_seed_nodes_count 
+        && !(l_net_pvt->seed_nodes_info = DAP_NEW_Z_COUNT(dap_chain_node_info_t*, l_net_pvt->poa_nodes_count)) )
+    {
         log_it(L_CRITICAL, "%s", g_error_memory_alloc);
         dap_chain_net_delete(l_net);
         dap_config_close(l_cfg);
-        return -1;
+        return -4;
     }
-    for (uint16_t i = 0; i < l_net_pvt->poa_nodes_count; i++) {
-        if (dap_stream_node_addr_from_str(l_net_pvt->poa_nodes_addrs + i, l_poa_nodes_addrs[i])) {
-            log_it(L_ERROR, "Incorrect format for address #%hu", i);
+
+    for (uint16_t i = 0; i < l_net_pvt->poa_nodes_count; ++i) {
+        uint16_t l_port = 0;
+        char l_host[0xFF + 1] = { '\0' };
+        dap_chain_node_addr_t l_addr;
+        if ( dap_stream_node_addr_from_str(&l_addr, l_poa_nodes_addrs[i])
+             || dap_net_parse_hostname(l_seed_nodes_hosts[i], l_host, &l_port)) {
+            log_it(L_ERROR, "Incorrect format of address \"%s\" or \"%s\", fix net config and restart node",
+                            l_seed_nodes_hosts[i], l_poa_nodes_addrs[i]);
             dap_chain_net_delete(l_net);
             dap_config_close(l_cfg);
             return -16;
         }
-    }
-    uint16_t l_seed_nodes_ipv4_len = 0;
-    char **l_seed_nodes_ipv4 = dap_config_get_array_str(l_cfg, "general", "seed_nodes_ipv4", &l_seed_nodes_ipv4_len);
-    uint16_t l_seed_nodes_ipv6_len = 0;
-    char **l_seed_nodes_ipv6 = dap_config_get_array_str(l_cfg, "general", "seed_nodes_ipv6", &l_seed_nodes_ipv6_len);
-    uint16_t l_seed_nodes_hostnames_len = 0;
-    char **l_seed_nodes_hostnames = dap_config_get_array_str(l_cfg, "general", "seed_nodes_hostnames", &l_seed_nodes_hostnames_len);
-    uint16_t l_seed_nodes_port_len = 0;
-    char **l_seed_nodes_port = dap_config_get_array_str(l_cfg, "general" ,"seed_nodes_port", &l_seed_nodes_port_len);
-    uint16_t l_bootstrap_nodes_len = 0;
-    char **l_bootstrap_nodes = dap_config_get_array_str(l_cfg, "general", "bootstrap_hostnames", &l_bootstrap_nodes_len);
-    if (l_seed_nodes_addrs_len) {
-        if (    l_seed_nodes_addrs_len != l_seed_nodes_port_len ||
-                (l_seed_nodes_ipv4_len && l_seed_nodes_ipv4_len != l_seed_nodes_port_len) ||
-                (l_seed_nodes_ipv6_len && l_seed_nodes_ipv6_len != l_seed_nodes_port_len) ||
-                (l_seed_nodes_hostnames_len && l_seed_nodes_hostnames_len != l_seed_nodes_port_len) ||
-                (!l_seed_nodes_ipv4_len && !l_seed_nodes_ipv6_len && !l_seed_nodes_hostnames_len) ||
-                l_net_pvt->poa_nodes_count != l_seed_nodes_port_len) {
-            log_it (L_ERROR, "Configuration mistake for seed nodes");
-            dap_chain_net_delete(l_net);
-            dap_config_close(l_cfg);
-            return -6;
-        }
-        l_net_pvt->seed_nodes_count = l_seed_nodes_addrs_len;
-        l_net_pvt->seeds_is_poas = true;
-    } else {
-        if (!l_bootstrap_nodes_len)
-            log_it(L_WARNING, "Configuration for network %s doesn't contains any links", l_net->pub.name);
-        l_net_pvt->seed_nodes_count = l_bootstrap_nodes_len;
-    }
-    l_net_pvt->permanent_links_count = l_permamnet_nodes_addrs_len;
-    log_it (L_DEBUG, "Read %u seed nodes params", l_net_pvt->seed_nodes_count);
-    l_net_pvt->seed_nodes_addrs = DAP_NEW_SIZE(dap_stream_node_addr_t, l_net_pvt->seed_nodes_count * sizeof(dap_stream_node_addr_t));
-    l_net_pvt->permanent_links = DAP_NEW_SIZE(dap_stream_node_addr_t, l_net_pvt->permanent_links_count * sizeof(dap_stream_node_addr_t));
-    // Load permanent nodes from cfg file
-    for (uint16_t i = 0; i < l_net_pvt->permanent_links_count; i++) {
-        if (dap_chain_node_addr_from_str(l_net_pvt->permanent_links + i, l_permamnet_nodes_addrs[i])) {
-            log_it(L_ERROR,"Wrong address format, must be 0123::4567::89AB::CDEF");
-            l_net_pvt->permanent_links_count--;
-            continue;
-        }
-    }
-    if (l_seed_nodes_ipv6_len) {
-        l_net_pvt->seed_nodes_ipv6 = DAP_NEW_SIZE(struct sockaddr_in6, l_net_pvt->seed_nodes_count * sizeof(struct sockaddr_in6));
-        if (!l_net_pvt->seed_nodes_ipv6) {
-            log_it(L_CRITICAL, "%s", g_error_memory_alloc);
-            dap_chain_net_delete(l_net);
-            dap_config_close(l_cfg);
-            return -1;
-        }
-    } else {   // Just only IPv4 can be resolved for now
-        l_net_pvt->seed_nodes_ipv4 = DAP_NEW_SIZE(struct sockaddr_in, l_net_pvt->seed_nodes_count * sizeof(struct sockaddr_in));
-        if (!l_net_pvt->seed_nodes_ipv4) {
-            log_it(L_CRITICAL, "%s", g_error_memory_alloc);
-            dap_chain_net_delete(l_net);
-            dap_config_close(l_cfg);
-            return -1;
-        }
-    }
-    // Load seed nodes from cfg file
-    for (uint16_t i = 0; i < l_net_pvt->seed_nodes_count; i++) {
-        char *l_node_hostname = NULL;
-        uint16_t l_node_port = 0;
-        if (dap_chain_node_addr_from_str(l_net_pvt->seed_nodes_addrs + i, l_seed_nodes_addrs[i])) {
-            log_it(L_ERROR,"Wrong address format, must be 0123::4567::89AB::CDEF");
-            l_net_pvt->seed_nodes_count--;
-            continue;
-        }
-        if (l_seed_nodes_port_len) {
-            l_node_port = strtoul(l_seed_nodes_port[i], NULL, 10);
-            if (l_seed_nodes_ipv4_len)
-                inet_pton(AF_INET, l_seed_nodes_ipv4[i], &l_net_pvt->seed_nodes_ipv4[i].sin_addr);
-            else if (l_seed_nodes_ipv6_len)
-                inet_pton(AF_INET6, l_seed_nodes_ipv6[i], &l_net_pvt->seed_nodes_ipv6[i].sin6_addr);
-            else if (l_seed_nodes_hostnames_len)
-                l_node_hostname = l_seed_nodes_hostnames[i];
-        } else if (l_bootstrap_nodes_len) {
-            char *dummy;
-            char *l_bootstrap_port_str = strtok_r(l_bootstrap_nodes[i], ":", &dummy);
-            if (l_bootstrap_port_str)
-                l_node_port = atoi(l_bootstrap_port_str);
-            l_node_hostname = l_bootstrap_nodes[i];
-        }
-        if (!l_node_port) {
-            log_it(L_ERROR, "Can't find port for seed node #%hu", i);
-            dap_chain_net_delete(l_net);
-            dap_config_close(l_cfg);
-            return -12;
-        } else {
-            if (l_seed_nodes_ipv6_len)
-                l_net_pvt->seed_nodes_ipv6[i].sin6_port = l_node_port;
-            else
-                l_net_pvt->seed_nodes_ipv4[i].sin_port = l_node_port;
-        }
-        if (l_node_hostname) {
-            struct in_addr l_res = {};
-            log_it(L_DEBUG, "Resolve %s hostname", l_node_hostname);
-            // TODO add IPv6 support
-            int l_ret_code = dap_net_resolve_host(l_node_hostname, AF_INET, (struct sockaddr *)&l_res);
-            if (l_ret_code == 0) {
-                log_it(L_NOTICE, "Resolved %s to %s (ipv4)", l_node_hostname, inet_ntoa(l_res));
-                l_net_pvt->seed_nodes_ipv4[i].sin_addr = l_res;
-            } else {
-                log_it(L_ERROR, "%s", gai_strerror(l_ret_code));
-                dap_chain_net_delete(l_net);
-                dap_config_close(l_cfg);
-                return -5;                  // TODO let resolve it later
-            }
-        }
-    }
-    dap_config_close(l_cfg);
-    // randomize seed nodes list
-    for (int j = l_net_pvt->seed_nodes_count - 1; j > 0; j--) {
-        short n = dap_random_uint16() % j;
-        struct sockaddr_in tmp = l_net_pvt->seed_nodes_ipv4[n];
-        l_net_pvt->seed_nodes_ipv4[n] = l_net_pvt->seed_nodes_ipv4[j];
-        l_net_pvt->seed_nodes_ipv4[j] = tmp;
-        if (!l_bootstrap_nodes_len) {
-            dap_stream_node_addr_t l_addr = l_net_pvt->poa_nodes_addrs[n];
-            l_net_pvt->poa_nodes_addrs[n] = l_net_pvt->poa_nodes_addrs[j];
-            l_net_pvt->poa_nodes_addrs[j] = l_addr;
+        uint8_t l_hostlen = dap_strlen(l_host);
+        l_net_pvt->seed_nodes_info[i] = DAP_NEW_Z_SIZE(dap_chain_node_info_t, sizeof(dap_chain_node_info_t) + l_hostlen + 1);
+        l_net_pvt->seed_nodes_info[i]->ext_port = l_port;
+        l_net_pvt->seed_nodes_info[i]->address = l_net_pvt->poa_nodes_addrs[i] = l_addr;
+        l_net_pvt->seed_nodes_info[i]->ext_host_len
+            = dap_strncpy(l_net_pvt->seed_nodes_info[i]->ext_host, l_host, l_hostlen) - l_net_pvt->seed_nodes_info[i]->ext_host;
+        if (g_node_addr.uint64 == l_addr.uint64) {
+            // We're in PoA seed list, predefine node info regardless of host set in [server] config section
+            l_net_pvt->node_info = l_net_pvt->seed_nodes_info[i];
         }
     }
 
@@ -2576,33 +2464,46 @@ int s_net_load(dap_chain_net_t *a_net)
         if (l_chain->callback_created)
             l_chain->callback_created(l_chain, l_cfg);
 
-    l_net_pvt->node_info = dap_chain_node_info_read(l_net, &g_node_addr);
-    if ( !l_net_pvt->node_info ) { // If not present - create it
-        l_net_pvt->node_info = DAP_NEW_Z(dap_chain_node_info_t);
-        if (!l_net_pvt->node_info) {
-            log_it(L_CRITICAL, "Memory allocation error");
-            dap_chain_net_delete(l_net);
-            return -6;
+     if ( dap_config_get_item_bool_default(g_config, "server", "enabled", false) ) {
+        if ( !l_net_pvt->node_info ) {
+            char l_host[0xFF + 1] = { '\0' };
+            uint16_t l_ext_port = 0;
+            const char *l_ext_addr = dap_config_get_item_str_default(g_config, "server", "ext_address", NULL);
+            if (!l_ext_addr) {
+                log_it(L_INFO, "External address is not set, will be detected automatically");
+                l_net_pvt->node_info = DAP_NEW_Z(dap_chain_node_info_t);
+            } else {
+                if ( dap_net_parse_hostname(l_ext_addr, l_host, &l_ext_port) )
+                    log_it(L_ERROR, "Invalid server address \"%s\", fix config and restart node", l_ext_addr);
+                else {
+                    uint8_t l_hostlen = dap_strlen(l_host);
+                    l_net_pvt->node_info = DAP_NEW_Z_SIZE(dap_chain_node_info_t, sizeof(dap_chain_node_info_t) + l_hostlen + 1 );
+                    l_net_pvt->node_info->ext_port = l_ext_port;
+                    l_net_pvt->node_info->ext_host_len = dap_strncpy(l_net_pvt->node_info->ext_host, l_host, l_hostlen) - l_net_pvt->node_info->ext_host;
+                }
+            }
+            if ( !l_net_pvt->node_info->ext_port ) {
+                char **l_listening = dap_config_get_array_str(g_config, "server", "listen_address", NULL);
+                l_net_pvt->node_info->ext_port = l_listening && !dap_net_parse_hostname(*l_listening, NULL, &l_ext_port) && l_ext_port
+                    ? l_ext_port : 8079; // TODO: default port?
+            }
+        } // otherwise, we're in seed list - seed config predominates server config thus disambiguating the settings
+        
+        if (l_net_pvt->node_info->ext_host_len) {
+            log_it(L_INFO, "Server is configured with external address %s : %u",
+               l_net_pvt->node_info->ext_host, l_net_pvt->node_info->ext_port);
         }
-        l_net_pvt->node_info->hdr.address = g_node_addr;
-        if (dap_config_get_item_bool_default(g_config, "server", "enabled", false)) {
-            const char *l_ext_addr_v4 = dap_config_get_item_str_default(g_config, "server", "ext_address", NULL);
-            const char *l_ext_addr_v6 = dap_config_get_item_str_default(g_config, "server", "ext_address6", NULL);
-            uint16_t l_node_info_port = dap_config_get_item_uint16_default(g_config, "server", "ext_port_tcp",
-                                        dap_config_get_item_uint16_default(g_config, "server", "listen_port_tcp", 8079));
-            if (l_ext_addr_v4)
-                inet_pton(AF_INET, l_ext_addr_v4, &l_net_pvt->node_info->hdr.ext_addr_v4);
-            if (l_ext_addr_v6)
-                inet_pton(AF_INET6, l_ext_addr_v6, &l_net_pvt->node_info->hdr.ext_addr_v6);
-            l_net_pvt->node_info->hdr.ext_port = l_node_info_port;
-        } else
-            log_it(L_INFO, "Server is disabled, add only node address in nodelist");
-    }
+    } else
+        log_it(L_INFO, "Server is disabled");
+
+    if (!l_net_pvt->node_info)
+        l_net_pvt->node_info = DAP_NEW_Z(dap_chain_node_info_t);
+    l_net_pvt->node_info->address = g_node_addr;
 
-    log_it(L_NOTICE, "Net load information: node_addr " NODE_ADDR_FP_STR ", balancers links %u, cell_id 0x%016"DAP_UINT64_FORMAT_X,
+    log_it(L_NOTICE, "Net load information: node_addr " NODE_ADDR_FP_STR ", seed links %u, cell_id 0x%016"DAP_UINT64_FORMAT_X,
            NODE_ADDR_FP_ARGS_S(g_node_addr),
            l_net_pvt->seed_nodes_count,
-           l_net_pvt->node_info->hdr.cell_id.uint64);
+           l_net_pvt->node_info->cell_id.uint64);
 
     // TODO rework alias concept
     const char * l_node_addr_type = dap_config_get_item_str_default(l_cfg , "general", "node_addr_type", "auto");
@@ -2648,7 +2549,7 @@ static int s_net_try_online(dap_chain_net_t *a_net)
     
     if (dap_config_get_item_bool_default(g_config ,"general", "auto_online", false))
     {
-        dap_chain_net_balancer_prepare_list_links(l_net->pub.name, true);
+        dap_chain_net_balancer_prepare_list_links(l_net->pub.name);
         l_target_state = NET_STATE_ONLINE;
     }
     
@@ -2712,16 +2613,13 @@ static void s_nodelist_change_notify(dap_store_obj_t *a_obj, void *a_arg)
     dap_return_if_fail(a_obj->type == DAP_GLOBAL_DB_OPTYPE_ADD && !dap_strcmp(l_net->pub.gdb_nodes, a_obj->group));
     dap_chain_node_info_t *l_node_info = (dap_chain_node_info_t *)a_obj->value;
     assert(dap_chain_node_info_get_size(l_node_info) == a_obj->value_len);
-    char l_node_ipv4_str[INET_ADDRSTRLEN]={ '\0' }, l_node_ipv6_str[INET6_ADDRSTRLEN]={ '\0' };
-    inet_ntop(AF_INET, &l_node_info->hdr.ext_addr_v4, l_node_ipv4_str, INET_ADDRSTRLEN);
-    inet_ntop(AF_INET6, &l_node_info->hdr.ext_addr_v6, l_node_ipv6_str, INET6_ADDRSTRLEN);
-    char l_ts[128] = { '\0' };
+    char l_ts[80] = { '\0' };
     dap_nanotime_to_str_rfc822(l_ts, sizeof(l_ts), a_obj->timestamp);
 
-    log_it(L_ATT, "Add node "NODE_ADDR_FP_STR" ipv4 %s(ipv6 %s):%s at %s to network\n",
-                             NODE_ADDR_FP_ARGS_S(l_node_info->hdr.address),
-                             l_node_ipv4_str, dap_itoa(l_node_info->hdr.ext_port),
-                             l_ts, l_net->pub.name);
+    log_it(L_NOTICE, "Add node "NODE_ADDR_FP_STR" [%s : %u] to network %s at %s\n",
+                             NODE_ADDR_FP_ARGS_S(l_node_info->address),
+                             l_node_info->ext_host, l_node_info->ext_port,
+                             l_net->pub.name, l_ts);
 }
 
 void dap_chain_net_add_nodelist_notify_callback(dap_chain_net_t *a_net, dap_store_obj_callback_notify_t a_callback, void *a_cb_arg)
@@ -2756,32 +2654,22 @@ bool dap_chain_net_remove_validator_from_clusters(dap_chain_t *a_chain, dap_stre
     return l_ret;
 }
 
-/**
- * @brief dap_chain_net_list
- * @return NULL if error
- */
-dap_chain_net_t **dap_chain_net_list(uint16_t *a_size)
-{
-    if (!a_size)
-        return NULL;
-    *a_size = HASH_COUNT(s_net_items);
-    if(*a_size){
-        dap_chain_net_t **l_net_list = DAP_NEW_SIZE(dap_chain_net_t *, (*a_size) * sizeof(dap_chain_net_t *));
-        if (!l_net_list) {
-            log_it(L_CRITICAL, "Memory allocation error");
-            return NULL;
-        }
-        dap_chain_net_item_t *l_current_item = NULL, *l_tmp = NULL;
-        int i = 0;
-        HASH_ITER(hh, s_net_items, l_current_item, l_tmp) {
-            l_net_list[i++] = l_current_item->chain_net;
-            if(i >= *a_size)
-                break;
-        }
-        return l_net_list;
-    } else {
+size_t dap_chain_net_count() {
+    return HASH_COUNT(s_net_items);
+}
+
+dap_chain_net_t *dap_chain_net_iter_start() {
+    return s_net_items->chain_net;
+}
+
+dap_chain_net_t *dap_chain_net_iter_next(dap_chain_net_t *a_it) {
+    if (!a_it)
         return NULL;
-    }
+    dap_chain_net_item_t *l_net_sought = NULL;
+    HASH_FIND_STR(s_net_items, a_it->pub.name, l_net_sought);
+    return l_net_sought && l_net_sought->hh.next
+        ? ((dap_chain_net_item_t*)l_net_sought->hh.next)->chain_net 
+        : NULL;
 }
 
 /**
@@ -2969,7 +2857,7 @@ void dap_chain_net_set_state(dap_chain_net_t *l_net, dap_chain_net_state_t a_sta
 
 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;
+    return  PVT(l_net)->node_info ? &PVT(l_net)->node_info->cell_id: 0;
 }
 
 /**
@@ -2993,7 +2881,7 @@ dap_list_t* dap_chain_net_get_node_list(dap_chain_net_t *l_net)
         log_it(L_CRITICAL, "Memory allocation error");
             return NULL;
         }
-        l_address->uint64 = l_node_info->hdr.address.uint64;
+        l_address->uint64 = l_node_info->address.uint64;
         l_node_list = dap_list_append(l_node_list, l_address);
     }
     dap_global_db_objs_delete(l_objs, l_nodes_count);
@@ -3008,10 +2896,15 @@ dap_list_t* dap_chain_net_get_node_list_cfg(dap_chain_net_t * a_net)
     dap_list_t *l_node_list = NULL;
     dap_chain_net_pvt_t *l_pvt_net = PVT(a_net);
     for (size_t i = 0; i < l_pvt_net->seed_nodes_count; i++)
-        l_node_list = dap_list_append(l_node_list, &l_pvt_net->seed_nodes_ipv4[i]);
+        l_node_list = dap_list_append(l_node_list, l_pvt_net->seed_nodes_info[i]);
     return l_node_list;
 }
 
+dap_chain_node_info_t** dap_chain_net_get_seed_nodes(dap_chain_net_t *a_net, uint16_t *a_count) {
+    dap_return_val_if_fail(a_net && a_count, NULL);
+    return *a_count = PVT(a_net)->seed_nodes_count, PVT(a_net)->seed_nodes_info;
+}
+
 /**
  * @brief dap_chain_net_set_flag_sync_from_zero
  * @param a_net
@@ -3171,24 +3064,15 @@ static bool s_net_check_acl(dap_chain_net_t *a_net, dap_chain_hash_fast_t *a_pke
  */
 static uint8_t *s_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash)
 {
-    uint16_t l_net_count;
-    dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
-    if (l_net_count && l_net_list) {
-        uint8_t *l_ret = DAP_NEW_SIZE(uint8_t, l_net_count);
-        if (!l_ret) {
-            log_it(L_CRITICAL, "Memory allocation error");
-            DAP_DELETE(l_net_list);
-            return NULL;
-        }
-        for (uint16_t i = 0; i < l_net_count; i++) {
-            l_ret[i] = s_net_check_acl(l_net_list[i], a_pkey_hash);
-        }
-        DAP_DELETE(l_net_list);
-        return l_ret;
+    if (!HASH_COUNT(s_net_items))
+        return NULL;
+    uint8_t *l_ret = DAP_NEW_Z_SIZE(uint8_t, HASH_COUNT(s_net_items));
+    unsigned i = 0;
+    dap_chain_net_item_t *l_net_cur = NULL, *l_net_tmp = NULL;
+    HASH_ITER(hh, s_net_items, l_net_cur, l_net_tmp) {
+        l_ret[i++] = s_net_check_acl(l_net_cur->chain_net, a_pkey_hash);
     }
-    if (l_net_list)
-        DAP_DELETE(l_net_list);
-    return NULL;
+    return l_ret;
 }
 
 /**
@@ -3359,14 +3243,12 @@ void dap_chain_net_announce_addrs(dap_chain_net_t *a_net)
 {
     dap_return_if_fail(a_net);
     dap_chain_net_pvt_t *l_net_pvt = PVT(a_net);
-    if (l_net_pvt->node_info->hdr.ext_port &&
-            (l_net_pvt->node_info->hdr.ext_addr_v4.s_addr != INADDR_ANY
-            || memcmp(&l_net_pvt->node_info->hdr.ext_addr_v6, &in6addr_any, sizeof(struct in6_addr)))) {
-        dap_chain_net_node_list_request(a_net, l_net_pvt->node_info, false);
-        char l_node_addr_str[INET_ADDRSTRLEN] = { '\0' };
-        inet_ntop(AF_INET, &l_net_pvt->node_info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
-        log_it(L_MSG, "Announce our node address "NODE_ADDR_FP_STR" < %s:%u > in net %s",
-               NODE_ADDR_FP_ARGS_S(g_node_addr), l_node_addr_str, l_net_pvt->node_info->hdr.ext_port, a_net->pub.name);
+    if ( l_net_pvt->node_info->ext_port ) {
+        dap_chain_net_node_list_request(a_net, NULL, l_net_pvt->node_info->ext_port, false, 'a');
+        log_it(L_INFO, "Announce our node address "NODE_ADDR_FP_STR" [ %s : %u ] in net %s",
+               NODE_ADDR_FP_ARGS_S(g_node_addr),
+               l_net_pvt->node_info->ext_host,
+               l_net_pvt->node_info->ext_port, a_net->pub.name);
     }
 }
 
@@ -3399,8 +3281,8 @@ int s_link_manager_fill_net_info(dap_link_t *a_link)
     if (!l_node_info) {
         return -3;
     }
-    if (a_link != dap_link_manager_link_create_or_update(&l_node_info->hdr.address, 
-            &l_node_info->hdr.ext_addr_v4, &l_node_info->hdr.ext_addr_v6, l_node_info->hdr.ext_port)) {
+    if (a_link != dap_link_manager_link_create_or_update(&l_node_info->address, 
+            l_node_info->ext_host, l_node_info->ext_port)) {
         log_it(L_WARNING, "LEAKS, links dublicate to node "NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(a_link->node_addr));
     }
     DAP_DELETE(l_node_info);
diff --git a/modules/net/dap_chain_net_balancer.c b/modules/net/dap_chain_net_balancer.c
index f216c52cb7d761b3896add361b63d9ccf9675997..71cf0d9cbece06a96a2dd30642b31b085ec17b11 100644
--- a/modules/net/dap_chain_net_balancer.c
+++ b/modules/net/dap_chain_net_balancer.c
@@ -31,14 +31,13 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 
 static bool dap_chain_net_balancer_find_link(dap_chain_node_info_t *a_node_info,dap_chain_net_t * a_net)
 {
-    dap_list_t * l_link_list = a_net->pub.link_list;
+    dap_list_t *l_link_list = a_net->pub.link_list;
     for(dap_list_t *ll = l_link_list; ll; ll = ll->next)
     {
         dap_chain_node_info_t *l_node_link = (dap_chain_node_info_t*)ll->data;
-        if(l_node_link && l_node_link->hdr.ext_addr_v4.s_addr == a_node_info->hdr.ext_addr_v4.s_addr)
+        if( l_node_link && !dap_strcmp(l_node_link->ext_host, a_node_info->ext_host) )
             return true;
     }
-
     return false;
 }
 
@@ -52,7 +51,7 @@ void dap_chain_net_balancer_set_link_list(dap_chain_node_info_t *a_node_info, co
     *l_node_info = *a_node_info;
     l_net->pub.link_list = dap_list_append(l_net->pub.link_list,l_node_info);
 
-    log_it(L_DEBUG, "Add addr "NODE_ADDR_FP_STR" to balancer link list",NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address));
+    log_it(L_DEBUG, "Add addr "NODE_ADDR_FP_STR" to balancer link list",NODE_ADDR_FP_ARGS_S(a_node_info->address));
 }
 
 void dap_chain_net_balancer_free_link_list(dap_chain_net_t * a_net)
@@ -62,33 +61,13 @@ void dap_chain_net_balancer_free_link_list(dap_chain_net_t * a_net)
     log_it(L_DEBUG, "Balancer link list cleared");
 }
 
-bool dap_chain_net_balancer_handshake(dap_chain_node_info_t *a_node_info,dap_chain_net_t * a_net)
-{
-    dap_chain_node_client_t *l_client = dap_chain_node_client_connect_default_channels(a_net,a_node_info);
-    if(!l_client) {
-        return false;
-    }
-    // wait handshake
-    int timeout_ms = 4000;
-    int res = dap_chain_node_client_wait(l_client, NODE_CLIENT_STATE_ESTABLISHED, timeout_ms);
-    dap_chain_node_client_close_mt(l_client);
-    if (res) {
-        return false;
-    }
-    return true;
-}
-static bool is_it_node_from_list(dap_list_t *a_node_addr_list, dap_chain_node_info_t *a_node_cand)
+int dap_chain_net_balancer_handshake(dap_chain_node_info_t *a_node_info, dap_chain_net_t *a_net)
 {
-    for(dap_list_t *node_i = a_node_addr_list; node_i; node_i = node_i->next)
-    {
-        struct in_addr *l_node_addr_cfg = (struct in_addr*)node_i->data;
-        if(a_node_cand->hdr.ext_addr_v4.s_addr && a_node_cand->hdr.ext_port &&
-          (l_node_addr_cfg->s_addr == a_node_cand->hdr.ext_addr_v4.s_addr))
-            return true;
-    }
-    return false;
+    dap_chain_node_client_t *l_client = dap_chain_node_client_connect_default_channels(a_net, a_node_info);
+    return l_client ? dap_chain_node_client_wait(l_client, NODE_CLIENT_STATE_ESTABLISHED, 5000) : -1;
 }
-static uint64_t min_count_blocks_events(dap_global_db_obj_t * a_objs,size_t a_node_count,dap_list_t * a_node_addr_list)
+
+/*static uint64_t min_count_blocks_events(dap_global_db_obj_t * a_objs, size_t a_node_count, dap_chain_node_info_t **a_node_info_list, size_t a_count)
 {
     uint64_t l_blocks_events = 0;
     for (size_t i = 0; i < a_node_count; i++) {
@@ -97,8 +76,8 @@ static uint64_t min_count_blocks_events(dap_global_db_obj_t * a_objs,size_t a_no
             log_it(L_ERROR, "Invalid record, key %s", a_objs[i].key);
             continue;
         }
-        for (dap_list_t *node_i = a_node_addr_list; node_i; node_i = node_i->next) {
-            if(((struct in_addr*)node_i->data)->s_addr == l_node_cand->hdr.ext_addr_v4.s_addr) {
+        for (dap_list_t *node_i = a_node_info_list; node_i; node_i = node_i->next) {
+            if( !dap_strcmp(((dap_chain_node_info_t*)node_i->data)->ext_host, l_node_cand->ext_host) ) {
                 if (!l_blocks_events || l_blocks_events > l_node_cand->info.atoms_count)
                     l_blocks_events = l_node_cand->info.atoms_count;
                 break;
@@ -106,13 +85,12 @@ static uint64_t min_count_blocks_events(dap_global_db_obj_t * a_objs,size_t a_no
         }
     }
     return l_blocks_events;
-}
+}*/
 
-void dap_chain_net_balancer_prepare_list_links(const char *a_net_name,bool handshake_on)
+void dap_chain_net_balancer_prepare_list_links(const char *a_net_name)
 {
-    if(!dap_config_get_item_bool_default(g_config ,"general", "balancer", false))
+    if(!dap_config_get_item_bool_default(g_config ,"general", "balancer", true))
         return;
-    dap_list_t *l_node_addr_list = NULL,*l_links_temp = NULL;
     dap_chain_net_t *l_net = dap_chain_net_by_name(a_net_name);
     if (l_net == NULL) {
         log_it(L_WARNING, "There isn't any network by this name - %s", a_net_name);
@@ -120,60 +98,37 @@ void dap_chain_net_balancer_prepare_list_links(const char *a_net_name,bool hands
     }
 
     dap_global_db_obj_t *l_objs = NULL;
-    size_t l_nodes_count = 0,link_list_count = 0;
+    size_t l_nodes_count = 0;
     uint64_t l_blocks_events = 0;
     // read all node
     l_objs = dap_global_db_get_all_sync(l_net->pub.gdb_nodes, &l_nodes_count);
     if (!l_nodes_count || !l_objs)
         return;
 
-    l_node_addr_list = dap_chain_net_get_node_list_cfg(l_net);
-    l_blocks_events = min_count_blocks_events(l_objs,l_nodes_count,l_node_addr_list);
+    /*dap_list_t *l_node_info_list = dap_chain_net_get_node_list_cfg(l_net);
+    l_blocks_events = min_count_blocks_events(l_objs,l_nodes_count,l_node_info_list);
+    dap_list_free_full(l_node_info_list, NULL);*/
     pthread_mutex_lock(&l_net->pub.balancer_mutex);
-    //clear list links
-    //link_list_count = dap_list_length(l_net->pub.link_list);
-    if(!handshake_on)
+
+    log_it(L_DEBUG, "Overwrite node list");
+    dap_list_free_full(l_net->pub.link_list, NULL);
+    l_net->pub.link_list = NULL;
+    dap_time_t l_time = dap_time_now();
+    uint32_t l_timeout = 2 * dap_config_get_item_uint32_default(g_config, "node_client", "timer_update_states", 600);
+    for (size_t i = 0; i < l_nodes_count; i++)
     {
-        log_it(L_DEBUG, "Adjusting node list");
-        for (size_t i = 0; i < l_nodes_count; i++) {
-            dap_chain_node_info_t *l_node_cand = (dap_chain_node_info_t *)l_objs[i].value;
-            for(dap_list_t *node_i = l_net->pub.link_list; node_i; node_i = node_i->next)
-            {
-                dap_chain_node_info_t *l_node_list = (dap_chain_node_info_t *)node_i->data;
-                if(l_node_list->hdr.address.uint64 == l_node_cand->hdr.address.uint64)
-                {
-                   // if(l_node_cand->info.atoms_count >= l_blocks_events/2)
-                   // {
-                        dap_chain_node_info_t * l_node_info = DAP_NEW_Z( dap_chain_node_info_t);
-                        *l_node_info = *l_node_cand;
-                        l_links_temp = dap_list_append(l_links_temp,l_node_info);
-                   // }
-                }
-            }
-        }
-        dap_chain_net_balancer_free_link_list(l_net);
-        l_net->pub.link_list = dap_list_copy(l_links_temp);
-        dap_list_free(l_links_temp);
-    }
-    else{
-        log_it(L_DEBUG, "Overwrite node list");
-        dap_list_free_full(l_net->pub.link_list, NULL);
-        l_net->pub.link_list = NULL;
-        for (size_t i = 0; i < l_nodes_count; i++)
-        {
-            dap_chain_node_info_t *l_node_cand = (dap_chain_node_info_t *)l_objs[i].value;
-            if(!is_it_node_from_list(l_node_addr_list, l_node_cand)){
-                if(l_node_cand->info.atoms_count >= l_blocks_events){
-                    if(dap_chain_net_balancer_handshake(l_node_cand,l_net)){
-                        dap_chain_net_balancer_set_link_list(l_node_cand,l_net->pub.name);
-                    }
-                }
-            }
-        }
+        dap_chain_node_info_t *l_node_cand = (dap_chain_node_info_t *)l_objs[i].value;
+        //if(!is_it_node_from_list(l_node_addr_list, l_node_cand)){//without root nodes
+        if(l_time > (l_objs[i].timestamp / DAP_NSEC_PER_SEC) &&
+          (l_time - (l_objs[i].timestamp / DAP_NSEC_PER_SEC)) < l_timeout)
+            //if(l_node_cand->info.atoms_count >= l_blocks_events){
+                dap_chain_net_balancer_set_link_list(l_node_cand,l_net->pub.name);
+            //}
+        //}
     }
+
     pthread_mutex_unlock(&l_net->pub.balancer_mutex);
     dap_global_db_objs_delete(l_objs, l_nodes_count);
-    dap_list_free(l_node_addr_list);
 }
 
 static int callback_compare_node_list(dap_list_t *a_item1, dap_list_t *a_item2)
@@ -185,8 +140,8 @@ static int callback_compare_node_list(dap_list_t *a_item1, dap_list_t *a_item2)
         return 0;
     }
 
-    return l_item1->info.links_number == l_item2->info.links_number
-            ? 0 : l_item1->info.links_number > l_item2->info.links_number ? 1 : -1;
+    return 0; /*l_item1->info.links_number == l_item2->info.links_number
+            ? 0 : l_item1->info.links_number > l_item2->info.links_number ? 1 : -1;*/
 }
 
 dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node(const char *a_net_name,uint16_t a_links_need)
@@ -202,9 +157,10 @@ dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node(const char *a_net
     l_net->pub.link_list = dap_list_sort(l_net->pub.link_list, callback_compare_node_list);
     l_node_num = dap_list_length(l_net->pub.link_list);
     dap_chain_node_info_t *l_node_candidate;
-    if(l_node_num)
+    if(l_node_num >= a_links_need)
     {
-        l_links_need = l_node_num > a_links_need ? a_links_need : l_node_num;
+        //l_links_need = l_node_num > a_links_need ? a_links_need : l_node_num;
+        l_links_need = a_links_need;
         dap_chain_net_node_balancer_t *l_node_list_res = DAP_NEW_Z_SIZE(dap_chain_net_node_balancer_t,
                    sizeof(dap_chain_net_node_balancer_t) + l_links_need * sizeof(dap_chain_node_info_t));
         dap_chain_node_info_t * l_node_info = (dap_chain_node_info_t *)l_node_list_res->nodes_info;
@@ -235,8 +191,8 @@ dap_chain_net_node_balancer_t *s_balancer_issue_link(const char *a_net_name, uin
         dap_chain_node_info_t * l_node_info = (dap_chain_node_info_t *)l_link_full_node_list->nodes_info;
         for(size_t i=0;i<l_link_full_node_list->count_node;i++)
         {
-            log_it(L_DEBUG, "Network balancer issues ip %s, [%ld blocks]",inet_ntoa((l_node_info + i)->hdr.ext_addr_v4),l_node_info->info.atoms_count);
-
+            log_it(L_DEBUG, "Network balancer issues ip %s",
+                   (l_node_info + i)->ext_host);
         }
         return l_link_full_node_list;
     }
@@ -245,7 +201,7 @@ dap_chain_net_node_balancer_t *s_balancer_issue_link(const char *a_net_name, uin
         dap_chain_node_info_t *l_link_node_info = dap_chain_net_balancer_link_from_cfg(l_net);
         if(l_link_node_info)
         {          
-            log_it(L_DEBUG, "Network balancer issues ip from net conf - %s",inet_ntoa(l_link_node_info->hdr.ext_addr_v4));
+            log_it(L_DEBUG, "Network balancer issues address %s from net conf", l_link_node_info->ext_host);
             dap_chain_net_node_balancer_t * l_node_list_res = DAP_NEW_Z_SIZE(dap_chain_net_node_balancer_t,
                                                                              sizeof(dap_chain_net_node_balancer_t) + sizeof(dap_chain_node_info_t));
             l_node_list_res->count_node = 1;
diff --git a/modules/net/dap_chain_net_decree.c b/modules/net/dap_chain_net_decree.c
index b6db60d2cd5329a944647f118dd99f6f4aaacc63..fd0f78e13f826b1d2d37224760bdefa72d7378c1 100644
--- a/modules/net/dap_chain_net_decree.c
+++ b/modules/net/dap_chain_net_decree.c
@@ -33,7 +33,6 @@
 #include "dap_chain_net_srv.h"
 #include "dap_chain_net_tx.h"
 #include "dap_chain_net_srv_stake_pos_delegate.h"
-#include "dap_chain_node_net_ban_list.h"
 #include "dap_http_ban_list_client.h"
 
 
@@ -476,17 +475,15 @@ static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain
                 }
                 dap_hash_fast_t l_decree_hash = {0};
                 dap_hash_fast(a_decree, dap_chain_datum_decree_get_size(a_decree), &l_decree_hash);
-                if (l_tsd->type == DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V4){
-                    struct in_addr l_ip_addr = dap_tsd_get_scalar(l_tsd, struct in_addr);
-                    dap_http_ban_list_client_add_ipv4(l_ip_addr, l_decree_hash, a_decree->header.ts_created);
-                } else if (l_tsd->type == DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V6){
-                    struct in6_addr l_ip_addr = dap_tsd_get_scalar(l_tsd, struct in6_addr);
-                    dap_http_ban_list_client_add_ipv6(l_ip_addr, l_decree_hash, a_decree->header.ts_created);
-                } else if (l_tsd->type == DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR){
-                    dap_chain_node_addr_t l_addr_node = dap_tsd_get_scalar(l_tsd, dap_chain_node_addr_t);
-                    if (!dap_chain_node_net_ban_list_add_node_addr(l_addr_node, l_decree_hash, a_decree->header.ts_created, a_net))
+                char *l_addr = dap_tsd_get_string(l_tsd);
+                switch (l_tsd->type) {
+                case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HOST:
+                case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR:
+                    if ( dap_http_ban_list_client_add(l_addr, l_decree_hash, a_decree->header.ts_created) ) {
+                        log_it(L_ERROR, "Can't ban addr %s: already banlisted", l_addr);
                         return -4;
-                } else {
+                    } break;
+                default:
                     log_it(L_WARNING, "Invalid section TSD type for sub-decree datum of type "
                                       "DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_BAN.");
                     return  -3;
@@ -505,21 +502,18 @@ static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain
                     log_it(L_WARNING,"TSD size is greater than all data size. It's possible corrupt data.");
                     return -2;
                 }
-                dap_hash_fast_t l_decree_hash = {0};
-                dap_hash_fast(a_decree, dap_chain_datum_decree_get_size(a_decree), &l_decree_hash);
-                if (l_tsd->type == DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V4){
-                    struct in_addr l_ip_addr = dap_tsd_get_scalar(l_tsd, struct in_addr);
-                    dap_http_ban_list_client_remove_ipv4(l_ip_addr);
-                } else if (l_tsd->type == DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V6){
-                    struct in6_addr l_ip_addr = dap_tsd_get_scalar(l_tsd, struct in6_addr);
-                    dap_http_ban_list_client_remove_ipv6(l_ip_addr);
-                } else if (l_tsd->type == DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR){
-                    dap_chain_node_addr_t l_addr_node = dap_tsd_get_scalar(l_tsd, dap_chain_node_addr_t);
-                    dap_chain_node_net_ban_list_remove_node_addr(a_net, l_addr_node);
-                } else {
+                char *l_addr = dap_tsd_get_string(l_tsd);
+                switch (l_tsd->type) {
+                case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HOST:
+                case DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR:
+                    if ( dap_http_ban_list_client_remove(l_addr) ) {
+                        log_it(L_ERROR, "Can't unban addr %s: not banlisted", l_addr);
+                        return -4;
+                    } break;
+                default:
                     log_it(L_WARNING, "Invalid section TSD type for sub-decree datum of type "
-                                      "DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_UNBAN.");
-                    return  -4;
+                                      "DAP_CHAIN_DATUM_DECREE_COMMON_SUBTYPE_BAN.");
+                    return  -3;
                 }
                 l_tsd_offset += l_tsd_size;
             }
diff --git a/modules/net/dap_chain_net_node_list.c b/modules/net/dap_chain_net_node_list.c
index 74ee7e389c6988c5d518bc0336b3f9842edb7f7b..dc920e8a48c15779b88d07845bad27bb366245ba 100644
--- a/modules/net/dap_chain_net_node_list.c
+++ b/modules/net/dap_chain_net_node_list.c
@@ -1,9 +1,10 @@
 /*
 * Authors:
 * Dmitriy Gerasimov <naeper@demlabs.net>
+* Roman Padenkov <roman.padenkov@demlabs.net>
 * Cellframe       https://cellframe.net
 * DeM Labs Inc.   https://demlabs.net
-* Copyright  (c) 2017-2019
+* Copyright  (c) 2017-2023
 * All rights reserved.
 
 This file is part of CellFrame SDK the open source project
@@ -30,6 +31,39 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 
 #define LOG_TAG "dap_chain_net_node_list"
 
+enum RetCode {
+    ADD_OK = 1,
+    ERR_NO_SERVER,
+    ERR_NOT_ADDED,
+    ERR_HASH,
+    ERR_HANDSHAKE,
+    ERR_EXISTS,
+    ERR_NOT_PINNER,
+    DELETED_OK,
+    ERR_WAIT_TIMEOUT,
+    ERR_UNKNOWN
+};
+
+static int s_dap_chain_net_node_list_add(dap_chain_net_t *a_net, dap_chain_node_info_t *a_node_info) {
+    return !dap_chain_node_info_save(a_net, a_node_info)
+        ? ( log_it( L_DEBUG, "Add address " NODE_ADDR_FP_STR " '%s : %u' to nodelist",
+                 NODE_ADDR_FP_ARGS_S(a_node_info->address),
+                 a_node_info->ext_host, a_node_info->ext_port ), ADD_OK )
+        : ( log_it( L_ERROR, "Address " NODE_ADDR_FP_STR " '%s : %u' not added",
+                 NODE_ADDR_FP_ARGS_S(a_node_info->address),
+                 a_node_info->ext_host, a_node_info->ext_port ), ERR_NOT_ADDED );
+}
+
+static int s_dap_chain_net_node_list_del(dap_chain_net_t *a_net, dap_chain_node_info_t *a_node_info) {
+    return !dap_chain_node_info_del(a_net, a_node_info)
+        ? ( log_it( L_DEBUG, "Delete address" NODE_ADDR_FP_STR " '%s : %u' from nodelist",
+                 NODE_ADDR_FP_ARGS_S(a_node_info->address),
+                 a_node_info->ext_host, a_node_info->ext_port ), DELETED_OK )
+        : ( log_it( L_ERROR, "Address" NODE_ADDR_FP_STR " '%s : %u' not deleted",
+                 NODE_ADDR_FP_ARGS_S(a_node_info->address),
+                 a_node_info->ext_host, a_node_info->ext_port ), ERR_UNKNOWN );
+}
+
 /**
  * @brief server function, makes handshake and add node to node list
  *
@@ -41,31 +75,42 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
  * 3 - Can't calculate hash for addr
  * 4 - Can't do handshake
  * 5 - Already exists
+ * 6 - I'am not the pinner this node (only for update links count)
+ * 7 - Node deleted
  */
 void dap_chain_net_node_check_http_issue_link(dap_http_simple_t *a_http_simple, void *a_arg)
 {
     log_it(L_DEBUG,"Proc enc http request");
-    http_status_code_t *l_return_code = (http_status_code_t *)a_arg;
-
-    if (strcmp(a_http_simple->http_client->url_path, DAP_NODE_LIST_URI_HASH)) {
+    http_status_code_t *l_return_code = (http_status_code_t*)a_arg;    
+    if ( strcmp(a_http_simple->http_client->url_path, DAP_NODE_LIST_URI_HASH) ) {
         log_it(L_ERROR, "Wrong path '%s' in the request to dap_chain_net_node_list module",
-                                                            a_http_simple->http_client->url_path);
+                        a_http_simple->http_client->url_path);
         *l_return_code = Http_Status_BadRequest;
         return;
     }
     int l_protocol_version = 0;
     char l_issue_method = 0;
     uint64_t addr = 0;
-    uint32_t ipv4 = 0;
     uint16_t port = 0;
     const char l_net_token[] = "net=";
-    sscanf(a_http_simple->http_client->in_query_string, "version=%d,method=%c,addr=%lu,ipv4=%d,port=%hu,net=",
-                                                            &l_protocol_version, &l_issue_method, &addr, &ipv4, &port);
-    if (l_protocol_version != 1 || l_issue_method != 'r') {
+    if ( 4 != sscanf(a_http_simple->http_client->in_query_string, "version=%d,method=%c,addr=%zu,port=%hu,net=",
+                                                                  &l_protocol_version, &l_issue_method, &addr, &port) )
+    {
+        log_it( L_ERROR, "Bad request \"%s\"", a_http_simple->http_client->in_query_string );
+        *l_return_code = Http_Status_BadRequest;
+        return;
+    }
+    if (l_protocol_version != 1) {
         log_it(L_ERROR, "Unsupported protocol version/method in the request to dap_chain_net_node_list module");
         *l_return_code = Http_Status_MethodNotAllowed;
         return;
     }
+    char *l_key = dap_chain_node_addr_to_str_static( &(dap_chain_node_addr_t){.uint64 = addr} );
+    if (!l_key) {
+        log_it(L_ERROR, "Bad node address %zu", addr);
+        *l_return_code = Http_Status_BadRequest;
+        return;
+    }
     char *l_net_str = strstr(a_http_simple->http_client->in_query_string, l_net_token);
     if (!l_net_str) {
         log_it(L_ERROR, "Net name token not found in the request to dap_chain_net_node_list module");
@@ -74,69 +119,59 @@ void dap_chain_net_node_check_http_issue_link(dap_http_simple_t *a_http_simple,
     }
     l_net_str += strlen(l_net_token);
     log_it(L_DEBUG, "HTTP Node check parser retrieve netname %s", l_net_str);
-
+    dap_chain_node_info_t *l_node_info;
     dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
-    dap_chain_node_info_t l_node_info = {
-        .hdr.address.uint64 = addr,
-        .hdr.ext_addr_v4.s_addr = ipv4,
-        .hdr.ext_port = port
-    };
+    uint8_t l_response = ERR_UNKNOWN;
+    switch (l_issue_method) {
+    case 'a': {
+        uint8_t l_host_size = dap_min(INET6_ADDRSTRLEN, (int)dap_strlen(a_http_simple->es_hostaddr) + 1);
+        l_node_info = DAP_NEW_STACK_SIZE(dap_chain_node_info_t, sizeof(dap_chain_node_info_t) + l_host_size);
+        *l_node_info = (dap_chain_node_info_t) {
+            .address = addr,
+            .ext_port = port,
+            .ext_host_len = dap_strncpy(l_node_info->ext_host, a_http_simple->es_hostaddr, l_host_size) - l_node_info->ext_host
+        };
+        l_response = !dap_chain_net_balancer_handshake(l_node_info, l_net)
+            ? s_dap_chain_net_node_list_add(l_net, l_node_info)
+            : ( log_it(L_DEBUG, "Can't do handshake with %s [ %s : %u ]", l_key, l_node_info->ext_host, l_node_info->ext_port),
+            ERR_HANDSHAKE );
+        *l_return_code = Http_Status_OK;
+    } break;
 
-    uint8_t response = 0;
-    char *l_key = dap_chain_node_addr_to_hash_str(&l_node_info.hdr.address);
-    if(!l_key)
-    {
-        log_it(L_DEBUG, "Can't calculate hash for addr");
-        response = 3;
-    } else{
-        size_t node_info_size = 0;
-        dap_chain_node_info_t *l_node_inf_check;
-        l_node_inf_check = (dap_chain_node_info_t *) dap_global_db_get_sync(l_net->pub.gdb_nodes, l_key, &node_info_size, NULL, NULL);
-        if(l_node_inf_check)
-        {
-            log_it(L_DEBUG, "The node is already exists");
-            response = 5;
-            DAP_DELETE(l_node_inf_check);
-        }
-        else{
-            if(dap_chain_net_balancer_handshake(&l_node_info,l_net))
-                response = 1;
-            if(response)
-            {
-                size_t l_node_info_size = dap_chain_node_info_get_size(&l_node_info);
-                bool res = dap_global_db_set_sync(l_net->pub.gdb_nodes, l_key, (uint8_t*)&l_node_info, l_node_info_size, false) == 0;
-                if(res)
-                {
-                    char l_node_addr_str[INET_ADDRSTRLEN]={};
-                    inet_ntop(AF_INET, &l_node_info.hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
-                    log_it(L_DEBUG, "Add address"NODE_ADDR_FP_STR" (%s) to node list",
-                                NODE_ADDR_FP_ARGS_S(l_node_info.hdr.address),l_node_addr_str);
-                    response = 1;
-                }
-                else
-                {
-                    response = 2;
-                    log_it(L_DEBUG, "Don't add this addres to node list");
-                }
-            }
-            else
-            {
-                log_it(L_DEBUG, "Can't do handshake");
-                response = 4;
+    case 'r': {
+        if ( !(l_node_info = (dap_chain_node_info_t*)dap_global_db_get_sync(l_net->pub.gdb_nodes, l_key, NULL, NULL, NULL)) ) {
+            log_it(L_DEBUG,"Address %s is not present in nodelist", l_key);
+            l_response = ERR_NOT_ADDED;
+        } else {
+            if ( dap_strcmp(l_node_info->ext_host, a_http_simple->es_hostaddr) ) {
+                l_response = ERR_NOT_PINNER;
+                *l_return_code = Http_Status_Forbidden;
+            } else {
+                l_response = !dap_global_db_del_sync(l_net->pub.gdb_nodes, l_key)
+                    ? ( log_it(L_DEBUG, "Node %s successfully deleted from nodelist", l_key),
+                    DELETED_OK )
+                    : ( log_it(L_DEBUG, "Can't delete node %s from nodelist", l_key),
+                    ERR_EXISTS );
+                *l_return_code = Http_Status_OK;
             }
+            DAP_DELETE(l_node_info);
         }
+    } break;
+
+    default:
+        log_it(L_ERROR, "Unsupported protocol version/method in the request to dap_chain_net_node_list module");
+        *l_return_code = Http_Status_MethodNotAllowed;
+        return;
     }
-    DAP_DELETE(l_key);
-    *l_return_code = Http_Status_OK;
-    size_t l_data_send_size = sizeof(uint8_t);
-    dap_http_simple_reply(a_http_simple, &response, l_data_send_size);
+    
+    dap_http_simple_reply(a_http_simple, &l_response, sizeof(uint8_t));
 }
 
 static void s_net_node_link_prepare_success(void *a_response, size_t a_response_size, void *a_arg) {
     struct node_link_request *l_node_list_request = (struct node_link_request *)a_arg;
     pthread_mutex_lock(&l_node_list_request->wait_mutex);
     l_node_list_request->response = *(uint8_t*)a_response;
-    pthread_cond_broadcast(&l_node_list_request->wait_cond);
+    pthread_cond_signal(&l_node_list_request->wait_cond);
     pthread_mutex_unlock(&l_node_list_request->wait_mutex);
 }
 static void s_net_node_link_prepare_error(int a_error_code, void *a_arg){
@@ -146,10 +181,13 @@ static void s_net_node_link_prepare_error(int a_error_code, void *a_arg){
         log_it(L_WARNING, "Link prepare error, code %d", a_error_code);
         return;
     }
-    char l_node_addr_str[INET_ADDRSTRLEN]={};
-    inet_ntop(AF_INET, &l_node_info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
-    log_it(L_WARNING, "Link from  "NODE_ADDR_FP_STR" (%s) prepare error with code %d",
-                                NODE_ADDR_FP_ARGS_S(l_node_info->hdr.address), l_node_addr_str,a_error_code);
+    pthread_mutex_lock(&l_node_list_request->wait_mutex);
+    l_node_list_request->response = a_error_code;
+    pthread_cond_signal(&l_node_list_request->wait_cond);
+    pthread_mutex_unlock(&l_node_list_request->wait_mutex);
+    log_it(L_WARNING, "Link from  "NODE_ADDR_FP_STR" [ %s : %u ] prepare error with code %d",
+           NODE_ADDR_FP_ARGS_S(l_node_info->address), l_node_info->ext_host,
+           l_node_info->ext_port, a_error_code);
 }
 static struct node_link_request *s_node_list_request_init ()
 {
@@ -158,12 +196,17 @@ static struct node_link_request *s_node_list_request_init ()
         return NULL;
     }
     l_node_list_request->worker = dap_events_worker_get_auto();
-    l_node_list_request->from_http = true;
     l_node_list_request->response = 0;
 
     pthread_condattr_t attr;
     pthread_condattr_init(&attr);
-#ifndef DAP_OS_DARWIN
+#ifdef DAP_OS_DARWIN
+    struct timespec ts;
+    ts.tv_sec = 8;
+    ts.tv_nsec = 0;
+    pthread_cond_timedwait_relative_np(&l_node_list_request->wait_cond, &l_node_list_request->wait_mutex,
+                                       &ts);
+#else
     pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
 #endif
     pthread_cond_init(&l_node_list_request->wait_cond, &attr);
@@ -178,79 +221,146 @@ static void s_node_list_request_deinit (struct node_link_request *a_node_list_re
     DAP_DEL_Z(a_node_list_request->link_info);
 }
 static int dap_chain_net_node_list_wait(struct node_link_request *a_node_list_request, int a_timeout_ms){
-
-    int ret = -1;
     pthread_mutex_lock(&a_node_list_request->wait_mutex);
     if(a_node_list_request->response)
     {
         pthread_mutex_unlock(&a_node_list_request->wait_mutex);
-        return 0;
+        return a_node_list_request->response;
     }
     struct timespec l_cond_timeout;
-    clock_gettime(CLOCK_REALTIME, &l_cond_timeout);
+    clock_gettime(CLOCK_MONOTONIC, &l_cond_timeout);
     l_cond_timeout.tv_sec += a_timeout_ms/1000;
-    int l_ret_wait = pthread_cond_timedwait(&a_node_list_request->wait_cond, &a_node_list_request->wait_mutex, &l_cond_timeout);
-    if(!l_ret_wait) {
-        ret = a_node_list_request->response ? 0 : -2;
-    } else if(l_ret_wait == ETIMEDOUT) {
-        log_it(L_NOTICE,"Wait for status is stopped by timeout");
-        ret = -1;
-    } else if (l_ret_wait) {
-        char l_errbuf[128];
-        l_errbuf[0] = '\0';
-        strerror_r(l_ret_wait,l_errbuf,sizeof (l_errbuf));
-        log_it(L_ERROR, "Pthread condition timed wait returned \"%s\"(code %d)", l_errbuf, l_ret_wait);
-        ret = -3;
+    while (!a_node_list_request->response) {
+        int l_wait = pthread_cond_timedwait(&a_node_list_request->wait_cond, &a_node_list_request->wait_mutex, &l_cond_timeout);
+        if (l_wait == ETIMEDOUT) {
+            log_it(L_NOTICE, "Waiting for status timeout");
+            a_node_list_request->response = ERR_WAIT_TIMEOUT;
+            break;
+        } else {
+            break;
+        }
     }
     pthread_mutex_unlock(&a_node_list_request->wait_mutex);
-    return ret;
+    return a_node_list_request->response;
 }
 
-int dap_chain_net_node_list_request(dap_chain_net_t *a_net, dap_chain_node_info_t *a_link_node_request, bool a_sync)
+static int s_cb_node_addr_compare(dap_list_t *a_list_elem, dap_list_t *a_addr_elem) {
+    dap_chain_node_info_t *l_link_node_info = (dap_chain_node_info_t*)a_list_elem->data;
+    dap_chain_node_addr_t *l_addr = (dap_chain_node_addr_t*)a_addr_elem->data;
+    return l_addr->uint64 != l_link_node_info->address.uint64;
+}
+
+int dap_chain_net_node_list_request (dap_chain_net_t *a_net, UNUSED_ARG const char *a_addr, uint16_t a_port, bool a_sync, char a_cmd)
 {
-    dap_chain_node_info_t *l_link_node_info = dap_chain_net_balancer_link_from_cfg(a_net);
-    if (!l_link_node_info)
-        return false;
-    char l_node_addr_str[INET_ADDRSTRLEN] = {};
-    inet_ntop(AF_INET, &l_link_node_info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
-    log_it(L_DEBUG, "Start node list HTTP request to %s", l_node_addr_str);
-    struct node_link_request *l_node_list_request = s_node_list_request_init();
-    if(!l_node_list_request){
-        log_it(L_CRITICAL, "Memory allocation error");
-        DAP_DELETE(l_link_node_info);
-        return false;
+    if (!a_net)
+        return -1;
+    
+    uint16_t l_seeds_count = 0, i;
+    dap_chain_node_info_t   **l_seed_nodes = dap_chain_net_get_seed_nodes(a_net, &l_seeds_count),
+                            *l_my_node = dap_chain_net_get_my_node_info(a_net);
+    if (!l_seed_nodes) {
+        log_it(L_ERROR, "No servers available to make request. Check network config for seed nodes presence");
     }
-    l_node_list_request->net = a_net;
-    l_node_list_request->link_info = l_link_node_info;
-    int ret = 0;
+    
+    dap_chain_node_addr_t l_node_addr_cur = {
+        .uint64 = dap_chain_net_get_cur_addr_int(a_net)
+    };
 
-    char *l_request = dap_strdup_printf("%s/%s?version=1,method=r,addr=%lu,ipv4=%d,port=%hu,net=%s",
-                                            DAP_UPLINK_PATH_NODE_LIST,
-                                            DAP_NODE_LIST_URI_HASH,
-                                            a_link_node_request->hdr.address.uint64,
-                                            a_link_node_request->hdr.ext_addr_v4.s_addr,
-                                            a_link_node_request->hdr.ext_port,
-                                            a_net->pub.name);
-    ret = dap_client_http_request(l_node_list_request->worker,
-                                            l_node_addr_str,
-                                            l_link_node_info->hdr.ext_port,
-                                            "GET",
-                                            "text/text",
-                                            l_request,
-                                            NULL,
-                                            0,
-                                            NULL,
-                                            s_net_node_link_prepare_success,
-                                            s_net_node_link_prepare_error,
-                                            l_node_list_request,
-                                            NULL) == NULL;
+    /*a_node_info->info.atoms_count = 0;
+    dap_chain_t *l_chain; DL_FOREACH(a_net->pub.chains, l_chain) {
+        if(l_chain->callback_count_atom)
+            a_node_info->info.atoms_count += l_chain->callback_count_atom(l_chain);
+    }
+    a_node_info->info.links_number = 0; */ // TODO: dap_chain_net_get_downlink_count(a_net);
+    
+    for (i = 0; i < l_seeds_count; ++i) {
+        if ( l_seed_nodes[i] == l_my_node )
+            // We're in seed list, add directly
+            return s_dap_chain_net_node_list_add( a_net, l_my_node );
+    }
+
+    struct node_link_request *l_link_node_request = s_node_list_request_init();
+    if (!l_link_node_request) {
+        log_it(L_CRITICAL, "Memory allocation error");
+        return -4;
+    };
+
+    char *l_request = dap_strdup_printf( "%s/%s?version=1,method=%c,addr=%zu,port=%hu,net=%s",
+                                         DAP_UPLINK_PATH_NODE_LIST, DAP_NODE_LIST_URI_HASH, a_cmd,
+                                         l_node_addr_cur.uint64, a_port, a_net->pub.name );
+    int l_ret = -1;
+    for (i = 0; i < l_seeds_count; ++i) {
+        dap_chain_node_info_t *l_remote = (dap_chain_node_info_t*)l_seed_nodes[i];
+        if ( dap_client_http_request(l_link_node_request->worker, l_remote->ext_host, l_remote->ext_port,
+                                    "GET", "text/text", l_request, NULL, 0, NULL,
+                                    s_net_node_link_prepare_success, s_net_node_link_prepare_error,
+                                    l_link_node_request, NULL) )
+        {
+            l_ret = a_sync ? dap_chain_net_node_list_wait(l_link_node_request, 8000) : ADD_OK;
+        }
+        if (l_ret == ADD_OK || l_ret == ERR_EXISTS || l_ret == DELETED_OK)
+            break;
+        else {
+            l_link_node_request->response = 0;
+            switch (l_ret) {
+            case ERR_NO_SERVER:
+                log_it(L_WARNING, "No server");
+                break;
+            case ERR_NOT_ADDED:
+                log_it(L_WARNING, "Didn't add your addres node to node list");
+                break;
+            case ERR_HASH:
+                log_it(L_WARNING, "Can't calculate hash for your addr");
+                break;
+            case ERR_HANDSHAKE:
+                log_it(L_WARNING, "Can't do handshake for your node");
+                break;
+            default:
+                log_it(L_WARNING, "Can't process node list HTTP request, error %d", l_ret);
+                break;
+            }
+        }
+    }
     DAP_DELETE(l_request);
-    if (a_sync) {
-        int rc = dap_chain_net_node_list_wait(l_node_list_request, 10000);
-        ret = ret ? 6 : rc ? 0 : l_node_list_request->response;
+    s_node_list_request_deinit(l_link_node_request);
+    return l_ret;
+}
+
+int dap_chain_net_node_list_init()
+{
+    /*for (dap_chain_net_t *it = dap_chain_net_iter_start(); it; it = dap_chain_net_iter_next(it)) {
+        dap_chain_net_add_nodelist_notify_callback(it, s_node_list_callback_notify, it);
+    }*/
+    return 0;
+}
+
+/*static int node_info_del_with_reply(dap_chain_net_t *a_net, dap_chain_node_info_t *a_node_info, const char *alias_str,
+        void **a_str_reply)
+{
+    int l_res = -1;
+    if ( !a_node_info->address.uint64 && !alias_str ) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "addr not found");
+        return l_res;
+    }
+    // find addr by alias or addr_str
+    dap_chain_node_addr_t *l_addr_by_alias = dap_chain_node_alias_find(a_net, alias_str);
+    if ( alias_str && !l_addr_by_alias ) {
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "alias not found");
+        return l_res;
+    }
+    dap_chain_node_addr_t l_addr = l_addr_by_alias ? *l_addr_by_alias : a_node_info->address;
+    char *a_key = dap_chain_node_addr_to_str_static(&l_addr);
+    if ( !(l_res = dap_global_db_del_sync(a_net->pub.gdb_nodes, a_key)) ) {
+        dap_list_t *list_aliases = get_aliases_by_name(a_net, &l_addr), *l_el = list_aliases;
+        while (l_el) {
+            dap_chain_node_alias_delete(a_net, (const char*)l_el->data);
+            l_el = l_el->next;
+        }
+        dap_list_free_full(list_aliases, NULL);
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Node deleted with all it's aliases");
     } else {
-        ret = 7;
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Node was not deleted from database");
     }
-    s_node_list_request_deinit(l_node_list_request);
-    return ret;
-}
+    DAP_DELETE(l_addr_by_alias);
+    return l_res;
+}*/
\ No newline at end of file
diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c
index 73d7bb016c891316521e5e4b4f21b0bf839384dc..58e95668990b0b4fef9c24679bf512fb87bf091c 100644
--- a/modules/net/dap_chain_node.c
+++ b/modules/net/dap_chain_node.c
@@ -66,15 +66,13 @@ bool dap_chain_node_alias_register(dap_chain_net_t *a_net, const char *a_alias,
 dap_chain_node_addr_t *dap_chain_node_alias_find(dap_chain_net_t *a_net, const char *a_alias)
 {
     dap_return_val_if_fail(a_alias && a_net, NULL);
-    size_t l_addr_size =0;
-    dap_chain_node_addr_t *l_addr = (dap_chain_node_addr_t *)dap_global_db_get_sync(a_net->pub.gdb_nodes_aliases,
-                                                                                    a_alias, &l_addr_size, NULL, NULL);
-    if (l_addr && l_addr_size != sizeof(dap_chain_node_addr_t)) {
-        log_it(L_WARNING, "Address in database is corrupted for alias %s", a_alias);
-        DAP_DELETE(l_addr);
-        return NULL;
-    }
-    return l_addr;
+    size_t l_size = 0;
+    dap_chain_node_addr_t *l_addr = (dap_chain_node_addr_t*)dap_global_db_get_sync(a_net->pub.gdb_nodes_aliases,
+                                                                                   a_alias, &l_size, NULL, NULL);
+    return l_addr && l_size != sizeof(dap_chain_node_addr_t)
+        ? log_it(L_WARNING, "Node record is corrupted for alias %s: %zu != %zu",
+                 a_alias, l_size, sizeof(dap_chain_node_addr_t)), DAP_DELETE(l_addr), NULL
+        : l_addr;
 }
 
 /**
@@ -92,18 +90,9 @@ bool dap_chain_node_alias_delete(dap_chain_net_t * a_net,const char *a_alias)
  */
 bool dap_chain_node_info_addr_match(dap_chain_node_info_t *node_info1, dap_chain_node_info_t *node_info2)
 {
-    if(!node_info1 || !node_info2) {
-        return false;
-    }
-    //if(memcmp(&node_info1->hdr.address, &node_info2->hdr.address, sizeof(dap_chain_addr_t))) {
-    //    return false;
-    //}
-    if(memcmp(&node_info1->hdr.ext_addr_v6, &node_info2->hdr.ext_addr_v6, sizeof(struct in6_addr)) ||
-            memcmp(&node_info1->hdr.ext_addr_v4, &node_info2->hdr.ext_addr_v4, sizeof(struct in_addr)) ||
-            (node_info1->hdr.ext_port != node_info2->hdr.ext_port)) {
-        return false;
-    }
-    return true;
+    return node_info1 && node_info2
+        && !dap_strcmp(node_info1->ext_host, node_info2->ext_host)
+        && node_info1->ext_port == node_info2->ext_port;
 }
 
 
@@ -112,58 +101,42 @@ bool dap_chain_node_info_addr_match(dap_chain_node_info_t *node_info1, dap_chain
  * @param node_info
  * @return
  */
-int dap_chain_node_info_save(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info)
+int dap_chain_node_info_save(dap_chain_net_t *a_net, dap_chain_node_info_t *a_node_info)
 {
-    if(!a_node_info || !a_node_info->hdr.address.uint64){
-        log_it(L_ERROR,"Can't save node info: %s", a_node_info? "null address":"null object" );
-        return  -1;
-    }
-    char *l_key = dap_chain_node_addr_to_hash_str(&a_node_info->hdr.address);
-
-    if(!l_key){
-        log_it(L_ERROR,"Can't produce key to save node info ");
-        return -2;
-    }
-    //char *a_value = dap_chain_node_info_serialize(node_info, NULL);
-    size_t l_node_info_size = dap_chain_node_info_get_size(a_node_info);
-    int l_res = dap_global_db_set_sync( a_net->pub.gdb_nodes, l_key, a_node_info, l_node_info_size, false);
-
-    DAP_DELETE(l_key);
+    return !a_node_info || !a_node_info->address.uint64
+        ? log_it(L_ERROR,"Can't save node info, %s", a_node_info ? "null arg" : "zero address"), -1
+        : dap_global_db_set_sync( a_net->pub.gdb_nodes,
+                                 dap_chain_node_addr_to_str_static(&a_node_info->address),
+                                 a_node_info,
+                                 dap_chain_node_info_get_size(a_node_info), false );
+}
 
-    return l_res;
+int dap_chain_node_info_del(dap_chain_net_t *a_net, dap_chain_node_info_t *a_node_info) {
+    return !a_node_info || !a_node_info->address.uint64
+        ? log_it(L_ERROR,"Can't delete node info, %s", a_node_info ? "null arg" : "zero address"), -1
+        : dap_global_db_del_sync( a_net->pub.gdb_nodes,
+                                 dap_chain_node_addr_to_str_static(&a_node_info->address) );
 }
 
 /**
  * Read node from base
  */
-dap_chain_node_info_t* dap_chain_node_info_read( dap_chain_net_t * a_net,dap_chain_node_addr_t *a_address)
+dap_chain_node_info_t* dap_chain_node_info_read(dap_chain_net_t *a_net, dap_chain_node_addr_t *a_address)
 {
-    char *l_key = dap_chain_node_addr_to_hash_str(a_address);
-    if (!l_key) {
-        log_it(L_WARNING,"Can't calculate hash of addr");
-        return NULL;
-    }
+    char *l_key = dap_chain_node_addr_to_str_static(a_address);
     size_t node_info_size = 0;
-    dap_chain_node_info_t *l_node_info;
-    // read node
-    l_node_info = (dap_chain_node_info_t *)dap_global_db_get_sync(a_net->pub.gdb_nodes, l_key, &node_info_size, NULL, NULL);
+    dap_chain_node_info_t *l_node_info
+        = (dap_chain_node_info_t*)dap_global_db_get_sync(a_net->pub.gdb_nodes, l_key, &node_info_size, NULL, NULL);
 
     if (!l_node_info) {
         log_it(L_NOTICE, "Node with address %s not found in base of %s network", l_key, a_net->pub.name);
-        DAP_DELETE(l_key);
         return NULL;
     }
 
-    size_t node_info_size_must_be = dap_chain_node_info_get_size(l_node_info);
-    if(node_info_size_must_be != node_info_size) {
-        log_it(L_ERROR, "Node has bad size in base=%zu (must be %zu)", node_info_size, node_info_size_must_be);
-        DAP_DELETE(l_node_info);
-        DAP_DELETE(l_key);
-        return NULL;
-    }
-
-    DAP_DELETE(l_key);
-    return l_node_info;
+    return dap_chain_node_info_get_size(l_node_info) == node_info_size
+        ? l_node_info : log_it(L_ERROR, "Bad node \"%s\" record size, %zu != %zu", 
+            l_key, dap_chain_node_info_get_size(l_node_info), node_info_size),
+        DAP_DELETE(l_node_info), NULL;
 }
 
 bool dap_chain_node_mempool_need_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum) {
@@ -270,25 +243,23 @@ void dap_chain_node_mempool_process_all(dap_chain_t *a_chain, bool a_force)
  */
 bool dap_chain_node_mempool_autoproc_init()
 {
-    uint16_t l_net_count;
     if (!dap_config_get_item_bool_default(g_config, "mempool", "auto_proc", false))
         return false;
-    dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
-    for (uint16_t i = 0; i < l_net_count; i++) {
-        dap_chain_node_role_t l_role = dap_chain_net_get_role(l_net_list[i]);
-        switch (l_role.enums) {
+    
+    for (dap_chain_net_t *it = dap_chain_net_iter_start(); it; it = dap_chain_net_iter_next(it)) {
+        switch (dap_chain_net_get_role(it).enums) {
             case NODE_ROLE_ROOT:
             case NODE_ROLE_MASTER:
             case NODE_ROLE_ROOT_MASTER:
             case NODE_ROLE_CELL_MASTER:
-                l_net_list[i]->pub.mempool_autoproc = true;
+                it->pub.mempool_autoproc = true;
                 break;
             default:
-                l_net_list[i]->pub.mempool_autoproc = false;
+                it->pub.mempool_autoproc = false;
                 continue;
         }
     }
-    DAP_DELETE(l_net_list);
+
     return true;
 }
 
diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c
index 36574892638d87ff2c1d59f90004da326799e391..68f28e5447fba4bd6239ee62ab050257bc89c8e2 100644
--- a/modules/net/dap_chain_node_cli.c
+++ b/modules/net/dap_chain_node_cli.c
@@ -98,7 +98,7 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
                "mempool check -cert <priv_cert_name> -net <net_name> {-file <filename> | -hash <hash>} [-mime {<SIGNER_FILENAME,SIGNER_FILENAME_SHORT,SIGNER_FILESIZE,SIGNER_DATE,SIGNER_MIME_MAGIC> | <SIGNER_ALL_FLAGS>}]\n"
                                           );
     dap_cli_server_cmd_add("node", com_node, "Work with node",
-                    "node add  -net <net_name> -port <port> -ipv4 <ipv4 external address>\n\n"
+                    "node add -net <net_name> [ -port <port> ]\n\n"
                     "node del -net <net_name> {-addr <node_address> | -alias <node_alias>}\n\n"
                     "node link {add | del}  -net <net_name> {-addr <node_address> | -alias <node_alias>} -link <node_address>\n\n"
                     "node alias -addr <node_address> -alias <node_alias>\n\n"
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 14178a9ed991662b5a6600e9c935587c2863daef..57a7739067d95b7591629ae48e1bf0a1c8565bb0 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -105,11 +105,11 @@
 #include "dap_stream_ch_chain_net_pkt.h"
 #include "dap_enc_base64.h"
 #include "dap_chain_net_srv_stake_pos_delegate.h"
-#include "dap_chain_node_net_ban_list.h"
 #include "dap_chain_net_node_list.h"
 
 #include "dap_json_rpc_errors.h"
 #include "dap_json_rpc_chain_datum.h"
+#include "dap_http_ban_list_client.h"
 #include "dap_chain_datum_tx_voting.h"
 
 
@@ -151,25 +151,6 @@ static dap_list_t* get_aliases_by_name(dap_chain_net_t * l_net, dap_chain_node_a
     return list_aliases;
 }
 
-/**
- * @brief dap_chain_node_addr_t* s_node_info_get_addr
- *
- * @param a_net
- * @param a_node_info
- * @param a_addr
- * @param a_alias_str
- * @return dap_chain_node_addr_t*
- */
-static dap_chain_node_addr_t* s_node_info_get_addr(dap_chain_net_t * a_net, dap_chain_node_addr_t *a_addr, const char *a_alias_str)
-{
-    dap_chain_node_addr_t *l_address = a_alias_str
-            ? dap_chain_node_alias_find(a_net, a_alias_str)
-            : a_addr && a_addr->uint64 ? DAP_DUP(a_addr) : NULL;
-    if (!l_address)
-        log_it(L_ERROR, "Node address with specified params not found");
-    return l_address;
-}
-
 /**
  * @brief node_info_read_and_reply
  * Read node from base
@@ -181,35 +162,11 @@ static dap_chain_node_addr_t* s_node_info_get_addr(dap_chain_net_t * a_net, dap_
 static dap_chain_node_info_t* node_info_read_and_reply(dap_chain_net_t * a_net, dap_chain_node_addr_t *a_address,
         void **a_str_reply)
 {
-    char *l_key = dap_chain_node_addr_to_hash_str(a_address);
-    if(!l_key)
-    {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "can't calculate hash of addr");
-        return NULL;
-    }
-    size_t node_info_size = 0;
-    dap_chain_node_info_t *node_info;
-    // read node
-    node_info = (dap_chain_node_info_t *) dap_global_db_get_sync(a_net->pub.gdb_nodes, l_key, &node_info_size, NULL, NULL);
+    dap_chain_node_info_t* l_res = dap_chain_node_info_read(a_net, a_address);
+    if (!l_res)
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Node record is corrupted or doesn't exist");
 
-    if(!node_info) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "node not found in base");
-        DAP_DELETE(l_key);
-        return NULL;
-    }
-    /* if(!node_info->hdr.ext_port)
-        node_info->hdr.ext_port = 8079; */
-    size_t node_info_size_must_be = dap_chain_node_info_get_size(node_info);
-    if(node_info_size_must_be != node_info_size) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "node has bad size in base=%zu (must be %zu)", node_info_size,
-                node_info_size_must_be);
-        DAP_DELETE(node_info);
-        DAP_DELETE(l_key);
-        return NULL;
-    }
-
-    DAP_DELETE(l_key);
-    return node_info;
+    return l_res;
 }
 
 
@@ -222,34 +179,12 @@ static dap_chain_node_info_t* node_info_read_and_reply(dap_chain_net_t * a_net,
  * @return true
  * @return false
  */
-static bool node_info_save_and_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, void **a_str_reply)
+static int node_info_save_and_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, void **a_str_reply)
 {
-    if(!a_node_info || !a_node_info->hdr.address.uint64) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "node addr not found");
-        return false;
-    }
-    char *a_key = dap_chain_node_addr_to_hash_str(&a_node_info->hdr.address);
-    if(!a_key)
-    {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "can't calculate hash for addr");
-        return NULL;
-    }
-    //char *a_value = dap_chain_node_info_serialize(node_info, NULL);
-    size_t l_node_info_size = dap_chain_node_info_get_size(a_node_info);
-    //dap_chain_node_info_t *l_node_info = DAP_NEW_Z_SIZE(dap_chain_node_info_t, l_node_info_size);
-    //memcpy(l_node_info, a_node_info, l_node_info_size );
-
-    //size_t data_len_out = 0;
-    //dap_chain_node_info_t *a_node_info1 = dap_global_db_gr_get(a_key, &data_len_out, a_net->pub.gdb_nodes);
-
-    bool res = dap_global_db_set_sync(a_net->pub.gdb_nodes, a_key, (uint8_t *) a_node_info, l_node_info_size,
-                                 false) == 0;
-
-    //data_len_out = 0;
-    //dap_chain_node_info_t *a_node_info2 = dap_global_db_gr_get(a_key, &data_len_out, a_net->pub.gdb_nodes);
-    //DAP_DELETE(a_key);
-    //DAP_DELETE(a_value);
-    return res;
+    return !a_node_info || !a_node_info->address.uint64
+        ? dap_cli_server_cmd_set_reply_text(a_str_reply, "Invalid node address"), -1
+        : dap_global_db_set_sync(a_net->pub.gdb_nodes, dap_chain_node_addr_to_str_static(&a_node_info->address),
+            (uint8_t*)a_node_info, dap_chain_node_info_get_size(a_node_info), false);
 }
 
 
@@ -269,11 +204,10 @@ static bool node_info_save_and_reply(dap_chain_net_t * a_net, dap_chain_node_inf
  * @return int
  */
 static int node_info_add_with_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info,
-        const char *a_alias_str,
-        const char *a_cell_str, const char *a_ipv4_str, const char *a_ipv6_str, void **a_str_reply)
+        const char *a_alias_str, const char *a_cell_str, const char *a_ip_str, void **a_str_reply)
 {
 
-    if(!a_node_info->hdr.address.uint64) {
+    if(!a_node_info->address.uint64) {
         dap_cli_server_cmd_set_reply_text(a_str_reply, "not found -addr parameter");
         return -1;
     }
@@ -281,87 +215,20 @@ static int node_info_add_with_reply(dap_chain_net_t * a_net, dap_chain_node_info
         dap_cli_server_cmd_set_reply_text(a_str_reply, "not found -cell parameter");
         return -1;
     }
-    if(a_ipv4_str)
-        inet_pton(AF_INET, a_ipv4_str, &(a_node_info->hdr.ext_addr_v4));
-    if(a_ipv6_str)
-        inet_pton(AF_INET6, a_ipv6_str, &(a_node_info->hdr.ext_addr_v6));
-
-    // check match addr to cell or no
-    /*dap_chain_node_addr_t *addr = dap_chain_node_gen_addr(&node_info->hdr.cell_id);
-     if(!dap_chain_node_check_addr(&node_info->hdr.address, &node_info->hdr.cell_id)) {
-     set_reply_text(a_str_reply, "cell does not match addr");
-     return -1;
-     }*/
+
     if(a_alias_str) {
         // add alias
-        if(!dap_chain_node_alias_register(a_net, a_alias_str, &a_node_info->hdr.address)) {
+        if(!dap_chain_node_alias_register(a_net, a_alias_str, &a_node_info->address)) {
             log_it(L_WARNING, "can't save alias %s", a_alias_str);
             dap_cli_server_cmd_set_reply_text(a_str_reply, "alias '%s' can't be mapped to addr=0x%"DAP_UINT64_FORMAT_U,
-                    a_alias_str, a_node_info->hdr.address.uint64);
+                    a_alias_str, a_node_info->address.uint64);
             return -1;
         }
     }
 
-    // write to base
-    if(!node_info_save_and_reply(a_net, a_node_info, a_str_reply))
-        return -1;
-    dap_cli_server_cmd_set_reply_text(a_str_reply, "node added");
-    return 0;
-}
-
-
-/**
- * @brief node_info_del_with_reply
- * Handler of command 'global_db node add'
- * @param a_net
- * @param a_node_info
- * @param alias_str
- * @param str_reply str_reply[out] for reply
- * @return int
- * return 0 Ok, -1 error
- */
-static int node_info_del_with_reply(dap_chain_net_t * a_net, dap_chain_node_info_t *a_node_info, const char *alias_str,
-        void **a_str_reply)
-{
-    if(!a_node_info->hdr.address.uint64 && !alias_str) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "addr not found");
-        return -1;
-    }
-    // find addr by alias or addr_str
-    dap_chain_node_addr_t *address = s_node_info_get_addr(a_net, &a_node_info->hdr.address, alias_str);
-    if(!address) {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "alias not found");
-        return -1;
-    }
-    char *a_key = dap_chain_node_addr_to_hash_str(address);
-    if(a_key){
-        // delete node
-        int l_res = dap_global_db_del_sync(a_net->pub.gdb_nodes, a_key);
-        if(l_res == 0) {
-            // delete all aliases for node address
-            {
-                dap_list_t *list_aliases = get_aliases_by_name(a_net, address);
-                dap_list_t *list = list_aliases;
-                while(list)
-                {
-                    const char *alias = (const char *) list->data;
-                    dap_chain_node_alias_delete(a_net, alias);
-                    list = dap_list_next(list);
-                }
-                dap_list_free_full(list_aliases, NULL);
-            }
-            // set text response
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "node deleted");
-        }
-        else
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "node not deleted");
-        DAP_DELETE(a_key);
-        DAP_DELETE(address);
-        return l_res;
-    }
-    dap_cli_server_cmd_set_reply_text(a_str_reply, "addr to delete can't be defined");
-    DAP_DELETE(address);
-    return -1;
+    return !node_info_save_and_reply(a_net, a_node_info, a_str_reply)
+        ? dap_cli_server_cmd_set_reply_text(a_str_reply, "node added"), 0
+        : -1;
 }
 
 /**
@@ -473,13 +340,13 @@ static int node_info_dump_with_reply(dap_chain_net_t * a_net, dap_chain_node_add
             return -1;
         } else {
             dap_string_append_printf(l_string_reply, "Got %zu nodes:\n", l_nodes_count);
-            dap_string_append_printf(l_string_reply, "%-26s%-20s%-8s%-26s%s", "Address", "IPv4", "Port", "Pinner", "Timestamp\n");
+            dap_string_append_printf(l_string_reply, "%-26s%-20s%-8s%s", "Address", "IPv4", "Port", "Timestamp\n");
             size_t l_data_size = 0;
 
             dap_global_db_obj_t *l_aliases_objs = dap_global_db_get_all_sync(a_net->pub.gdb_nodes_aliases, &l_data_size);
             for (size_t i = 0; i < l_nodes_count; i++) {
                 dap_chain_node_info_t *l_node_info = (dap_chain_node_info_t*)l_objs[i].value;
-                if (dap_chain_node_addr_is_blank(&l_node_info->hdr.address)){
+                if (dap_chain_node_addr_is_blank(&l_node_info->address)){
                     log_it(L_ERROR, "Node address is empty");
                     continue;
                 }
@@ -493,17 +360,12 @@ static int node_info_dump_with_reply(dap_chain_net_t * a_net, dap_chain_node_add
                 } else
                     DAP_DELETE(l_node_info_read);
 */
-
-                char l_node_ipv4_str[INET_ADDRSTRLEN]={ '\0' }, l_node_ipv6_str[INET6_ADDRSTRLEN]={ '\0' };
-                inet_ntop(AF_INET, &l_node_info->hdr.ext_addr_v4, l_node_ipv4_str, INET_ADDRSTRLEN);
-                inet_ntop(AF_INET6, &l_node_info->hdr.ext_addr_v6, l_node_ipv6_str, INET6_ADDRSTRLEN);
-                char l_ts[128] = { '\0' };
+                char l_ts[80] = { '\0' };
                 dap_nanotime_to_str_rfc822(l_ts, sizeof(l_ts), l_objs[i].timestamp);
 
-                dap_string_append_printf(l_string_reply, NODE_ADDR_FP_STR"    %-20s%-8d"NODE_ADDR_FP_STR"    %-32s\n",
-                                         NODE_ADDR_FP_ARGS_S(l_node_info->hdr.address),
-                                         l_node_ipv4_str, l_node_info->hdr.ext_port,
-                                         NODE_ADDR_FP_ARGS_S(l_node_info->info.owner_addr),
+                dap_string_append_printf(l_string_reply, NODE_ADDR_FP_STR"    %-20s%-8d%-32s\n",
+                                         NODE_ADDR_FP_ARGS_S(l_node_info->address),
+                                         l_node_info->ext_host, l_node_info->ext_port,
                                          l_ts);
 
                 // get aliases in form of string
@@ -1011,50 +873,13 @@ int com_global_db(int a_argc, char ** a_argv, void **a_str_reply)
 
 static dap_tsd_t* s_chain_node_cli_com_node_create_tsd_addr(char **a_argv, int a_arg_start, int a_arg_end, void **a_str_reply, const char *a_specified_decree) {
     const char *l_ban_addr_str = NULL;
-    dap_tsd_t *l_addr_tsd = NULL;
-    if (dap_cli_server_cmd_find_option_val(a_argv, a_arg_start, a_arg_end, "-ip", &l_ban_addr_str)){
-        if (l_ban_addr_str[0] == ':' || dap_strlen(l_ban_addr_str) > 15) {
-            struct in6_addr l_ip_addr;
-            if (inet_pton(AF_INET6, l_ban_addr_str, &l_ip_addr)) {
-                l_addr_tsd = dap_tsd_create(DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V6,
-                                            &l_ip_addr,
-                                            sizeof(struct in6_addr));
-            } else {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "The -ip option can contain an "
-                                                               "ip address in V4 or V6 format. Well, it is "
-                                                               "possible to convert the string value of the "
-                                                               "V6 address into a binary representation.");
-                return NULL;
-            }
-        } else {
-            struct in_addr l_ip_addr;
-            if (inet_pton(AF_INET, l_ban_addr_str, &l_ip_addr)) {
-                l_addr_tsd = dap_tsd_create(DAP_CHAIN_DATUM_DECREE_TSD_TYPE_IP_V4,
-                                            &l_ip_addr,
-                                            sizeof(struct in_addr));
-
-            } else {
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "The -ip option can contain an "
-                                                               "ip address in V4 or V6 format. Well, it is "
-                                                               "possible to convert the string value of the "
-                                                               "V4 address into a binary representation.");
-                return NULL;
-            }
-        }
-    }else if (dap_cli_server_cmd_find_option_val(a_argv, a_arg_start, a_arg_end, "-addr", &l_ban_addr_str)){
-        dap_chain_node_addr_t l_node_addr = {0};
-        if (dap_chain_node_addr_from_str(&l_node_addr, l_ban_addr_str)) {
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "The node address is in the wrong format.");
-            return NULL;
-        } else {
-            l_addr_tsd = dap_tsd_create(DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR, &l_node_addr, sizeof(dap_chain_node_addr_t));
-        }
-    } else {
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "The -ip or -addr option was not "
-                                                       "specified to create a %s entry creation decree.", a_specified_decree);
-        return NULL;
-    }
-    return  l_addr_tsd;
+    if (dap_cli_server_cmd_find_option_val(a_argv, a_arg_start, a_arg_end, "-addr", &l_ban_addr_str))
+        return dap_tsd_create_string(DAP_CHAIN_DATUM_DECREE_TSD_TYPE_NODE_ADDR, l_ban_addr_str);
+    else if (dap_cli_server_cmd_find_option_val(a_argv, a_arg_start, a_arg_end, "-host", &l_ban_addr_str))
+        return dap_tsd_create_string(DAP_CHAIN_DATUM_DECREE_TSD_TYPE_HOST, l_ban_addr_str);
+    else
+        return dap_cli_server_cmd_set_reply_text(a_str_reply, "The -host or -addr option was not "
+                                                       "specified to create a %s entry creation decree.", a_specified_decree), NULL;
 }
 
 /**
@@ -1103,7 +928,7 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
         return -1;
     }
     const char *l_addr_str = NULL, *l_port_str = NULL, *alias_str = NULL;
-    const char *l_cell_str = NULL, *l_link_str = NULL, *a_ipv4_str = NULL, *a_ipv6_str = NULL;
+    const char *l_cell_str = NULL, *l_link_str = NULL, *l_hostname = NULL;
 
     // find net
     dap_chain_net_t *l_net = NULL;
@@ -1118,13 +943,15 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-port", &l_port_str);
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-alias", &alias_str);
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cell", &l_cell_str);
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-ipv4", &a_ipv4_str);
-    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-ipv6", &a_ipv6_str);
+    dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-host", &l_hostname);
     dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-link", &l_link_str);
 
     // struct to write to the global db
     dap_chain_node_addr_t l_node_addr = {}, l_link;
-    dap_chain_node_info_t l_node_info = {};
+    uint32_t l_info_size = l_hostname 
+        ? sizeof(dap_chain_node_info_t) + dap_strlen(l_hostname) + 1
+        : sizeof(dap_chain_node_info_t);
+    dap_chain_node_info_t *l_node_info = DAP_NEW_STACK_SIZE(dap_chain_node_info_t, l_info_size);
 
     //TODO need to rework with new node info / alias /links concept
 
@@ -1132,15 +959,15 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
         if(dap_chain_node_addr_from_str(&l_node_addr, l_addr_str) != 0) {
             dap_digit_from_string(l_addr_str, l_node_addr.raw, sizeof(l_node_addr.raw));
         }
-        l_node_info.hdr.address = l_node_addr;
+        l_node_info->address = l_node_addr;
     }
     if(l_port_str) {
         uint16_t l_node_port = 0;
         dap_digit_from_string(l_port_str, &l_node_port, sizeof(uint16_t));
-        l_node_info.hdr.ext_port = l_node_port;
+        l_node_info->ext_port = l_node_port;
     }
     if (l_cell_str) {
-        dap_digit_from_string(l_cell_str, l_node_info.hdr.cell_id.raw, sizeof(l_node_info.hdr.cell_id.raw)); //DAP_CHAIN_CELL_ID_SIZE);
+        dap_digit_from_string(l_cell_str, l_node_info->cell_id.raw, sizeof(l_node_info->cell_id.raw)); //DAP_CHAIN_CELL_ID_SIZE);
     }
     if (l_link_str) {   // TODO
         if(dap_chain_node_addr_from_str(&l_link, l_link_str) != 0) {
@@ -1150,15 +977,13 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
     int l_ret =0;
     switch (cmd_num)
     {    
-    case CMD_ADD:
-        if(!l_port_str || !a_ipv4_str) {
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "node requires parameter -ipv4 and -port");
+    case CMD_ADD: {
+        /*if(!l_port_str) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "node requires parameter -port");
             return -1;
         }
-        if (inet_pton(AF_INET, a_ipv4_str, &(l_node_info.hdr.ext_addr_v4)) <= 0) {
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "Incorrect ipv4 string");
-            return -2;
-        }
+        l_node_info->ext_host_len = dap_strncpy(l_node_info->ext_host, l_hostname, 0xFF) - l_node_info->ext_host;
+        l_node_info->address.uint64 = dap_chain_net_get_cur_addr_int(l_net);
         if (l_addr_str) {
             if (dap_chain_node_info_save(l_net, &l_node_info) == DAP_GLOBAL_DB_RC_SUCCESS) {
                 dap_cli_server_cmd_set_reply_text(a_str_reply, "Node address successfully added to node list");
@@ -1166,42 +991,34 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
             }
             dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't add node address to node list");
             return -3;
-        }
-        l_node_info.hdr.address.uint64 = dap_chain_net_get_cur_addr_int(l_net);
+        }*/
         // Synchronous request, wait for reply
-        int res = dap_chain_net_node_list_request(l_net, &l_node_info, true);
-        switch (res)
+        int l_res = dap_chain_net_node_list_request(l_net, NULL,
+            l_port_str ? strtoul(l_port_str, NULL, 10) : dap_chain_net_get_my_node_info(l_net)->ext_port,
+            true, 'a');
+        switch (l_res)
         {
-            case 0:
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "No server");
-            break;
-            case 1:
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Node addr successfully added to node list");
-            break;
-            case 2:
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Didn't add your addres node to node list");
-            break;
-            case 3:
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't calculate hash for your addr");
-            break;
-            case 4:
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't do handshake for your node");
-            break;
-            case 5:
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "The node is already exists");
-            break;
-            case 6:
-                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't process node list HTTP request");
-            break;
-            default:
-                break;
+            case 1: dap_cli_server_cmd_set_reply_text(a_str_reply, "Successfully added"); break;
+            case 2: dap_cli_server_cmd_set_reply_text(a_str_reply, "No server"); break;
+            case 3: dap_cli_server_cmd_set_reply_text(a_str_reply, "Didn't add your addres node to node list"); break;
+            case 4: dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't calculate hash for your addr"); break;
+            case 5: dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't do handshake for your node"); break;
+            case 6: dap_cli_server_cmd_set_reply_text(a_str_reply, "The node already exists"); break;
+            case 7: dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't process node list HTTP request"); break;
+            default:dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't process request, error %d", l_res); break;
         }
         return l_ret;
+    }
         //break;
     case CMD_DEL:
         // handler of command 'node del'
     {
-        return node_info_del_with_reply(l_net, &l_node_info, alias_str, a_str_reply);
+        int l_res = dap_chain_net_node_list_request(l_net, NULL, 0, true, 'r');
+        switch (l_res) {
+            case 8:  dap_cli_server_cmd_set_reply_text(a_str_reply, "Sucessfully deleted"); break;
+            default: dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't process request, error %d", l_res); break;
+        }
+        return l_ret;
     }
 
     case CMD_DUMP: {
@@ -1596,12 +1413,9 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
     } break;
 
     case CMD_BANLIST: {
-        dap_string_t *l_str_ban_list = dap_string_new("Ban list:\n");
-        dap_http_ban_list_client_ipv4_print(l_str_ban_list);
-        dap_http_ban_list_client_ipv6_print(l_str_ban_list);
-        dap_chain_node_net_ban_list_print(l_str_ban_list);
-        dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_ban_list->str);
-        dap_string_free(l_str_ban_list, true);
+        char *l_str_banlist = dap_http_ban_list_client_dump(NULL);
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "%s", l_str_banlist);
+        DAP_DELETE(l_str_banlist);
     } break;
 
     case CMD_BALANCER: {
@@ -1614,9 +1428,9 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
         {
             dap_chain_node_info_t *l_node_link = (dap_chain_node_info_t*)ll->data;
             dap_string_append_printf(l_string_balanc, NODE_ADDR_FP_STR"    %-20s%u\n",
-                                     NODE_ADDR_FP_ARGS_S(l_node_link->hdr.address),
-                                     inet_ntoa(l_node_link->hdr.ext_addr_v4),
-                                     l_node_link->info.links_number);
+                                     NODE_ADDR_FP_ARGS_S(l_node_link->address),
+                                     l_node_link->ext_host,
+                                     /*l_node_link->info.links_number*/ 0);
         }
         dap_cli_server_cmd_set_reply_text(a_str_reply, "Balancer link list:\n %s \n",
                                           l_string_balanc->str);
@@ -1903,11 +1717,9 @@ int com_version(int argc, char ** argv, void **a_str_reply)
     (void) argv;
 #ifndef DAP_VERSION
 #pragma message "[!WRN!] DAP_VERSION IS NOT DEFINED. Manual override engaged."
-#define DAP_VERSION 0.9-15
+#define DAP_VERSION "0.9-15"
 #endif
-    dap_cli_server_cmd_set_reply_text(a_str_reply,
-            "%s version %s\n", dap_get_appname(), DAP_VERSION );
-    return 0;
+    return dap_cli_server_cmd_set_reply_text(a_str_reply, "%s version "DAP_VERSION"\n", dap_get_appname()), 0;
 }
 
 
@@ -2754,8 +2566,6 @@ int com_token_decl_sign(int a_argc, char **a_argv, void **a_str_reply)
                             l_key_out_str, l_datum_hash_out_str);
                     DAP_DELETE(l_datum);
                     DAP_DELETE(l_gdb_group_mempool);
-                    DAP_DELETE(l_key_str);
-                    DAP_DELETE(l_key_str_base58);
                     return -2;
                 }
             } else {
@@ -7036,13 +6846,10 @@ int cmd_gdb_import(int a_argc, char **a_argv, void **a_str_reply)
 dap_list_t *s_go_all_nets_offline()
 {
     dap_list_t *l_net_returns = NULL;
-    uint16_t l_net_count;
-    dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
-    for (uint16_t i = 0; i < l_net_count; i++) {    // Shutdown all networks
-        if (dap_chain_net_stop(l_net_list[i]))
-            l_net_returns = dap_list_append(l_net_returns, l_net_list[i]);
+    for (dap_chain_net_t *it = dap_chain_net_iter_start(); it; it = dap_chain_net_iter_next(it)) {
+        if ( dap_chain_net_stop(it) )
+            l_net_returns = dap_list_append(l_net_returns, it);
     }
-    sleep(2);   // waiting for networks to go offline
     return l_net_returns;
 }
 
@@ -7096,10 +6903,8 @@ int cmd_remove(int a_argc, char **a_argv, void **a_str_reply)
     //perform deletion according to the specified parameters, if the path is specified
     if (l_gdb_path) {
         l_net_returns = s_go_all_nets_offline();
-        uint16_t l_net_count;
-        dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
         dap_list_t *l_gdb_aliases_list = NULL;
-        for (uint16_t i = 0; i < l_net_count; i++) {
+        for (dap_chain_net_t *it = dap_chain_net_iter_start(); it; it = dap_chain_net_iter_next(it)) {
             size_t l_aliases_count = 0;
             _pvt_net_aliases_list_t *l_gdb_groups = DAP_NEW(_pvt_net_aliases_list_t);
             if (!l_gdb_groups) {
@@ -7107,11 +6912,12 @@ int cmd_remove(int a_argc, char **a_argv, void **a_str_reply)
                 dap_list_free(l_net_returns);
                 return -1;
             }
-            l_gdb_groups->net = l_net_list[i];
+            l_gdb_groups->net = it;
             l_gdb_groups->group_aliases = dap_global_db_get_all_sync(l_gdb_groups->net->pub.gdb_nodes_aliases, &l_gdb_groups->count_aliases);
             l_gdb_groups->group_nodes = dap_global_db_get_all_sync(l_gdb_groups->net->pub.gdb_nodes, &l_gdb_groups->count_nodes);
             l_gdb_aliases_list = dap_list_append(l_gdb_aliases_list, l_gdb_groups);
         }
+
         dap_global_db_deinit();
         const char *l_gdb_driver = dap_config_get_item_str_default(g_config, "global_db", "driver", "mdbx");
         char *l_gdb_rm_path = dap_strdup_printf("%s/gdb-%s", l_gdb_path, l_gdb_driver);
@@ -7143,15 +6949,12 @@ int cmd_remove(int a_argc, char **a_argv, void **a_str_reply)
         if	(NULL == l_net_str && all >= 0) {
             if (NULL == l_gdb_path)
                 l_net_returns = s_go_all_nets_offline();
-            uint16_t l_net_count;
-            dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
-            for (uint16_t i = 0; i < l_net_count; i++) {
-                s_dap_chain_net_purge(l_net_list[i]);
+            for (dap_chain_net_t *it = dap_chain_net_iter_start(); it; it = dap_chain_net_iter_next(it)) {
+                s_dap_chain_net_purge(it);
             }
             if (!error)
                 successful |= REMOVED_CHAINS;
-
-        } else if	(NULL != l_net_str && all < 0) {
+        } else if (NULL != l_net_str && all < 0) {
             if (NULL != (l_net = dap_chain_net_by_name(l_net_str))) {
                 if (NULL == l_gdb_path && dap_chain_net_stop(l_net))
                     l_net_returns = dap_list_append(l_net_returns, l_net);
diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c
index bcb29652e18770aa73e1938eb1b3a44a3b1c1c86..60d9bbf32f5ae1716c20f3b0f811c1b7c80008db 100644
--- a/modules/net/dap_chain_node_client.c
+++ b/modules/net/dap_chain_node_client.c
@@ -251,11 +251,10 @@ static void s_stage_connected_callback(dap_client_t *a_client, void *a_arg)
     dap_chain_node_client_t *l_node_client = DAP_CHAIN_NODE_CLIENT(a_client);
     UNUSED(a_arg);
     if(l_node_client) {
-        char l_ip_addr_str[INET_ADDRSTRLEN] = {};
-        inet_ntop(AF_INET, &l_node_client->info->hdr.ext_addr_v4, l_ip_addr_str, INET_ADDRSTRLEN);
-        log_it(L_NOTICE, "Stream connection with node "NODE_ADDR_FP_STR" (%s:%hu) established",
+        log_it(L_NOTICE, "Stream connection with node "NODE_ADDR_FP_STR" [ %s : %hu ] established",
                     NODE_ADDR_FP_ARGS_S(l_node_client->remote_node_addr),
-                    l_ip_addr_str, l_node_client->info->hdr.ext_port);
+                    l_node_client->info->ext_host,
+                    l_node_client->info->ext_port);
         // set callbacks for C and N channels; for R and S it is not needed
         if (a_client->active_channels) {
             size_t l_channels_count = dap_strlen(a_client->active_channels);
@@ -273,7 +272,7 @@ static void s_stage_connected_callback(dap_client_t *a_client, void *a_arg)
         dap_client_write_unsafe(a_client, 'N', DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ANNOUNCE,
                                          &l_announce, sizeof(l_announce));
         // Add uplink to clusters
-        dap_stream_node_addr_t *l_uplink_addr = &l_node_client->info->hdr.address;
+        dap_stream_node_addr_t *l_uplink_addr = &l_node_client->info->address;
         dap_global_db_cluster_t *it;
         DL_FOREACH(dap_global_db_instance_get_default()->clusters, it)
             if (dap_cluster_member_find_unsafe(it->role_cluster, l_uplink_addr))
@@ -585,8 +584,8 @@ static int s_save_stat_to_database(dap_stream_ch_chain_net_srv_pkt_test_t *a_req
     json_object_object_add(jobj, "time_save_str", json_object_new_string(buf));
     json_object_object_add(jobj, "time_connect", json_object_new_int(a_request->time_connect_ms));
     json_object_object_add(jobj, "time_transmit", json_object_new_int(l_t2_ms-l_t1_ms));
-    json_object_object_add(jobj, "ip_send", json_object_new_string((char *)a_request->ip_send));
-    json_object_object_add(jobj, "ip_recv", json_object_new_string((char *)a_request->ip_recv));
+    json_object_object_add(jobj, "ip_send", json_object_new_string((char *)a_request->host_send));
+    json_object_object_add(jobj, "ip_recv", json_object_new_string((char *)a_request->host_recv));
     json_object_object_add(jobj, "time_len_send", json_object_new_int(a_request->data_size_send));
     json_object_object_add(jobj, "time_len_recv", json_object_new_int(a_request->data_size_recv));
     json_object_object_add(jobj, "err_code", json_object_new_int(a_request->err_code));
@@ -660,9 +659,7 @@ dap_chain_node_client_t *dap_chain_node_client_create_n_connect(dap_chain_net_t
                                                                 void *a_callback_arg)
 {
     dap_chain_node_client_t *l_node_client = dap_chain_node_client_create(a_net, a_node_info, a_callbacks, a_callback_arg);
-    if (dap_chain_node_client_connect(l_node_client, a_active_channels))
-        return l_node_client;
-    return NULL;
+    return dap_chain_node_client_connect(l_node_client, a_active_channels) ? l_node_client : ( DAP_DEL_MULTY(l_node_client->info, l_node_client), NULL );
 }
 
 dap_chain_node_client_t *dap_chain_node_client_create(dap_chain_net_t *a_net,
@@ -684,7 +681,7 @@ dap_chain_node_client_t *dap_chain_node_client_create(dap_chain_net_t *a_net,
     l_node_client->callbacks_arg = a_callback_arg;
     if (a_callbacks)
         l_node_client->callbacks = *a_callbacks;
-    l_node_client->info = DAP_DUP(a_node_info);
+    l_node_client->info = DAP_DUP_SIZE(a_node_info, sizeof(dap_chain_node_info_t) + a_node_info->ext_host_len + 1);
     l_node_client->net = a_net;
 #ifndef _WIN32
     pthread_condattr_t attr;
@@ -698,7 +695,7 @@ dap_chain_node_client_t *dap_chain_node_client_create(dap_chain_net_t *a_net,
 #endif
 
     pthread_mutex_init(&l_node_client->wait_mutex, NULL);
-    l_node_client->remote_node_addr.uint64 = a_node_info->hdr.address.uint64;
+    l_node_client->remote_node_addr.uint64 = a_node_info->address.uint64;
     return l_node_client;
 }
 
@@ -726,23 +723,15 @@ bool dap_chain_node_client_connect(dap_chain_node_client_t *a_node_client, const
     dap_client_set_is_always_reconnect(a_node_client->client, false);
     a_node_client->client->_inheritor = a_node_client;
     dap_client_set_active_channels_unsafe(a_node_client->client, a_active_channels);
-
     dap_client_set_auth_cert(a_node_client->client, a_node_client->net->pub.name);
-
-    char l_host_addr[INET6_ADDRSTRLEN] = { '\0' };
-    if(a_node_client->info->hdr.ext_addr_v4.s_addr){
-        struct sockaddr_in sa4 = { .sin_family = AF_INET, .sin_addr = a_node_client->info->hdr.ext_addr_v4 };
-        inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), l_host_addr, INET6_ADDRSTRLEN);
-    } else {
-        struct sockaddr_in6 sa6 = { .sin6_family = AF_INET6, .sin6_addr = a_node_client->info->hdr.ext_addr_v6 };
-        inet_ntop(AF_INET6, &(((struct sockaddr_in6 *) &sa6)->sin6_addr), l_host_addr, INET6_ADDRSTRLEN);
+    char *l_host_addr = a_node_client->info->ext_host;
+    
+    if ( !*l_host_addr || !strcmp(l_host_addr, "::") || !a_node_client->info->ext_port ) {
+        return log_it(L_WARNING, "Node client address undefined"), false;
     }
-    if(!strlen(l_host_addr) || !strcmp(l_host_addr, "::") || !a_node_client->info->hdr.ext_port) {
-        log_it(L_WARNING, "Undefined address of node client");
-        return false;
-    }
-    log_it(L_INFO, "Connecting to addr %s : %d", l_host_addr, a_node_client->info->hdr.ext_port);
-    dap_client_set_uplink_unsafe(a_node_client->client, l_host_addr, a_node_client->info->hdr.ext_port);
+
+    log_it(L_INFO, "Connecting to addr %s : %d", l_host_addr, a_node_client->info->ext_port);
+    dap_client_set_uplink_unsafe(a_node_client->client, l_host_addr, a_node_client->info->ext_port);
     a_node_client->state = NODE_CLIENT_STATE_CONNECTING;
     // Handshake & connect
     dap_client_go_stage(a_node_client->client, STAGE_STREAM_STREAMING, s_stage_connected_callback);
@@ -768,10 +757,10 @@ void dap_chain_node_client_reset(dap_chain_node_client_t *a_client)
  */
 void dap_chain_node_client_close_unsafe(dap_chain_node_client_t *a_node_client)
 {
-    char l_node_addr_str[INET_ADDRSTRLEN] = {};
-    inet_ntop(AF_INET, &a_node_client->info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
-    log_it(L_INFO, "Closing node client to uplink %s:%d ["NODE_ADDR_FP_STR"]",
-                    l_node_addr_str, a_node_client->info->hdr.ext_port, NODE_ADDR_FP_ARGS_S(a_node_client->remote_node_addr));
+    log_it(L_INFO, "Closing node client to uplink"NODE_ADDR_FP_STR" [ %s : %u ]",
+                    NODE_ADDR_FP_ARGS_S(a_node_client->remote_node_addr),
+                    a_node_client->info->ext_host,
+                    a_node_client->info->ext_port);
 
     if (a_node_client->sync_timer)
         dap_timerfd_delete_unsafe(a_node_client->sync_timer);
diff --git a/modules/net/dap_chain_node_dns_client.c b/modules/net/dap_chain_node_dns_client.c
index e0c462ac341d9bbdb610d89a4e88bc623d8c2731..b02fdbaa12f64efa46a985e10acd98a29b63b1b4 100644
--- a/modules/net/dap_chain_node_dns_client.c
+++ b/modules/net/dap_chain_node_dns_client.c
@@ -89,14 +89,14 @@ static void s_dns_client_esocket_read_callback(dap_events_socket_t * a_esocket,
     dap_chain_net_node_balancer_t *l_link_full_node_list = DAP_NEW_Z_SIZE(dap_chain_net_node_balancer_t,
                                                                           sizeof(dap_chain_net_node_balancer_t) + sizeof(dap_chain_node_info_t));
     dap_chain_node_info_t l_result = {};
-    l_result.hdr.ext_addr_v4.s_addr = ntohl(*(uint32_t *)l_cur);
+    //l_result.hdr.ext_addr_v4.s_addr = ntohl(*(uint32_t *)l_cur); TODO: implement other request and response
     l_cur = l_buf + 5 * sizeof(uint16_t);
     int l_additions_count = ntohs(*(uint16_t *)l_cur);
     if (l_additions_count == 1) {
         l_cur = l_buf + l_addr_point + DNS_ANSWER_SIZE;
-        l_result.hdr.ext_port = ntohs(*(uint16_t *)l_cur);
+        l_result.ext_port = ntohs(*(uint16_t *)l_cur);
         l_cur += sizeof(uint16_t);
-        l_result.hdr.address.uint64 = be64toh(*(uint64_t *)l_cur);
+        l_result.address.uint64 = be64toh(*(uint64_t *)l_cur);
     }
     *(dap_chain_node_info_t*)l_link_full_node_list->nodes_info = l_result;
     l_link_full_node_list->count_node = 1;
diff --git a/modules/net/dap_chain_node_dns_server.c b/modules/net/dap_chain_node_dns_server.c
index 2fd2c9fecf0e27103977c7605cff5e94ed023513..72e4fb6585bfaef91d46e9a9d54f20bb3d987afc 100644
--- a/modules/net/dap_chain_node_dns_server.c
+++ b/modules/net/dap_chain_node_dns_server.c
@@ -246,7 +246,7 @@ void dap_dns_client_read(dap_events_socket_t *a_es, void *a_arg) {
         uint32_t ttl = DNS_TIME_TO_LIVE;
         dap_dns_buf_put_uint32(dns_reply, ttl);                                    
         dap_dns_buf_put_uint16(dns_reply, 4);           // RD len for ipv4
-        dap_dns_buf_put_uint32(dns_reply, l_node_info->hdr.ext_addr_v4.s_addr);
+        //dap_dns_buf_put_uint32(dns_reply, l_node_info->hdr.ext_addr_v4.s_addr); TODO: implement other response format
         val = 0xc000 | DNS_HEADER_SIZE;                // Link to host name
         dap_dns_buf_put_uint16(dns_reply, val);
         val = DNS_RECORD_TYPE_TXT;
@@ -256,8 +256,8 @@ void dap_dns_client_read(dap_events_socket_t *a_es, void *a_arg) {
         dap_dns_buf_put_uint32(dns_reply, ttl);
         val = sizeof(uint16_t) + sizeof(uint64_t);
         dap_dns_buf_put_uint16(dns_reply, val);
-        dap_dns_buf_put_uint16(dns_reply, l_node_info->hdr.ext_port);
-        dap_dns_buf_put_uint64(dns_reply, l_node_info->hdr.address.uint64);
+        dap_dns_buf_put_uint16(dns_reply, l_node_info->ext_port);
+        dap_dns_buf_put_uint64(dns_reply, l_node_info->address.uint64);
         DAP_DELETE(l_node_info);
     } else if (flags->rcode == DNS_ERROR_NONE) {
         flags->rcode = DNS_ERROR_NAME;
diff --git a/modules/net/dap_chain_node_net_ban_list.c b/modules/net/dap_chain_node_net_ban_list.c
deleted file mode 100644
index 4ee911be5db6eb038bd9cb92c1719b4e6051fe91..0000000000000000000000000000000000000000
--- a/modules/net/dap_chain_node_net_ban_list.c
+++ /dev/null
@@ -1,109 +0,0 @@
-#include "dap_chain_node_net_ban_list.h"
-#include "dap_list.h"
-#include "dap_cli_server.h"
-#include "dap_chain_node.h"
-
-#undef LOG_TAG
-#define LOG_TAG "dap_chain_node_net_ban_list"
-
-static dap_chain_node_ban_list_record_t *s_ban_addr_list = NULL;
-static pthread_rwlock_t s_ban_addr_list_rwlock;
-
-bool s_chain_node_net_ban_list_addr_resolve_ip_v4(dap_chain_net_t  *a_net, dap_chain_node_addr_t a_node_addr, struct in_addr *a_out_ip) {
-    char *l_key = dap_chain_node_addr_to_hash_str(&a_node_addr);
-    if (!l_key)
-        return false;
-    size_t l_node_info_size = 0;
-    dap_chain_node_info_t *l_node_info = (dap_chain_node_info_t*) dap_global_db_get_sync(a_net->pub.gdb_nodes, l_key, &l_node_info_size, NULL, NULL);
-    if (!l_node_info) {
-        log_it(L_ERROR, "Unable to add node address to ban list: Node address could not be resolved to IP address, no information in GDB.");
-        return false;
-    }
-    size_t node_info_size_must_be = dap_chain_node_info_get_size(l_node_info);
-    if(node_info_size_must_be != l_node_info_size) {
-        DAP_DELETE(l_node_info);
-        DAP_DELETE(l_key);
-        return false;
-    }
-    DAP_DELETE(l_key);
-    *a_out_ip = l_node_info->hdr.ext_addr_v4;
-    return true;
-}
-
-bool dap_chain_node_net_ban_list_check_node_addr(dap_chain_node_addr_t node_addr){
-    pthread_rwlock_rdlock(&s_ban_addr_list_rwlock);
-    dap_chain_node_ban_list_record_t *l_record = NULL;
-    HASH_FIND(hh, s_ban_addr_list, &node_addr, sizeof(dap_chain_node_addr_t), l_record);
-    pthread_rwlock_unlock(&s_ban_addr_list_rwlock);
-    return l_record ? true : false;
-}
-
-bool dap_chain_node_net_ban_list_add_node_addr(dap_chain_node_addr_t node_addr, dap_hash_fast_t a_decree_hash, dap_time_t a_time_created, dap_chain_net_t *a_net){
-    dap_chain_node_ban_list_record_t *l_record = DAP_NEW(dap_chain_node_ban_list_record_t);
-    //Resolve addr to ip
-    struct in_addr l_in;
-    if (s_chain_node_net_ban_list_addr_resolve_ip_v4(a_net, node_addr, &l_in)) {
-        dap_http_ban_list_client_add_ipv4(l_in, a_decree_hash, a_time_created);
-        l_record->node_addr = node_addr;
-        l_record->decree_hash = a_decree_hash;
-        l_record->ts_created_decree = a_time_created;
-        pthread_rwlock_wrlock(&s_ban_addr_list_rwlock);
-        HASH_ADD(hh, s_ban_addr_list, node_addr, sizeof(dap_chain_node_addr_t), l_record);
-        pthread_rwlock_unlock(&s_ban_addr_list_rwlock);
-        return true;
-    } else {
-        DAP_DELETE(l_record);
-        return false;
-    }
-}
-
-void dap_chain_node_net_ban_list_print(dap_string_t *a_str_out) {
-    int number = 1;
-    a_str_out = dap_string_append(a_str_out, "\t Address node.\n");
-    pthread_rwlock_rdlock(&s_ban_addr_list_rwlock);
-    if (!s_ban_addr_list) {
-        a_str_out = dap_string_append(a_str_out, "\t\t Not found.\n\n");
-        return;
-    }
-    dap_chain_node_ban_list_record_t *l_record = NULL, *l_tmp = NULL;
-    HASH_ITER(hh, s_ban_addr_list, l_record, l_tmp) {
-        number++;
-        char *l_decree_hash_str = dap_hash_fast_to_str_new(&l_record->decree_hash);
-        char l_time_out[65] = {'\0'};
-        dap_time_to_str_rfc822(l_time_out, 65, l_record->ts_created_decree);
-        dap_string_append_printf(a_str_out, "\t\t%d) %s\n"
-                                        "\t\t\tAddress: "NODE_ADDR_FP_STR"\n"
-                                        "\t\t\tCreated: %s\n", number, l_decree_hash_str,
-                                        NODE_ADDR_FP_ARGS_S(l_record->node_addr), l_time_out);
-        DAP_DELETE(l_decree_hash_str);
-    }
-    pthread_rwlock_unlock(&s_ban_addr_list_rwlock);
-}
-
-void dap_chain_node_net_ban_list_remove_node_addr(dap_chain_net_t *a_net, dap_chain_node_addr_t node_addr) {
-    pthread_rwlock_wrlock(&s_ban_addr_list_rwlock);
-    dap_chain_node_ban_list_record_t *l_record = NULL;
-    HASH_FIND(hh, s_ban_addr_list, &node_addr, sizeof(dap_chain_node_addr_t), l_record);
-    if (l_record) {
-        if (l_record->node_addr.uint64 == node_addr.uint64) {
-            struct in_addr l_in;
-            if (s_chain_node_net_ban_list_addr_resolve_ip_v4(a_net, l_record->node_addr, &l_in)) {
-                dap_http_ban_list_client_remove_ipv4(l_in);
-            } else {
-                log_it(L_WARNING, "Can't resolve node address "NODE_ADDR_FP_STR" to ip at remove node addr from ban list",
-                       NODE_ADDR_FP_ARGS_S(l_record->node_addr));
-            }
-            DAP_DELETE(l_record);
-        }
-    }
-    pthread_rwlock_unlock(&s_ban_addr_list_rwlock);
-}
-
-int dap_chain_node_net_ban_list_init() {
-    s_ban_addr_list = NULL;
-    pthread_rwlock_init(&s_ban_addr_list_rwlock, NULL);
-    return 0;
-}
-void dap_chain_node_net_ban_list_deinit() {
-    pthread_rwlock_destroy(&s_ban_addr_list_rwlock);
-}
diff --git a/modules/net/dap_chain_node_ping.c b/modules/net/dap_chain_node_ping.c
index 53efc69218474697c533e39fbe392546d99fc03c..e8f3b9cb336116f80bf26d2fca564c92580ce989 100644
--- a/modules/net/dap_chain_node_ping.c
+++ b/modules/net/dap_chain_node_ping.c
@@ -91,7 +91,7 @@ static void* node_ping_proc(void *a_arg)
     struct in_addr l_addr  = *(struct in_addr*)(a_arg + sizeof(int) * 2);
     DAP_DELETE(a_arg);
 
-    char *host4 = DAP_NEW_SIZE(char, INET_ADDRSTRLEN);
+    /*char *host4 = DAP_NEW_SIZE(char, INET_ADDRSTRLEN);
     if (!host4) {
         log_it(L_CRITICAL, "Memory allocation error");
         return NULL;
@@ -101,7 +101,7 @@ static void* node_ping_proc(void *a_arg)
     if(!str_ip4){
         DAP_DELETE(host4);
         return NULL ;
-    }
+    }*/ // TODO implement string handling
     //printf(" %s %d ping start\n", str_ip4, l_count);
     /*
      // send ping
@@ -126,7 +126,7 @@ static void* node_ping_proc(void *a_arg)
         SOCKET l_socket = socket( PF_INET, SOCK_STREAM, 0);
         if(l_socket == INVALID_SOCKET) {
             log_it(L_ERROR, "Can't create socket");
-            DAP_DELETE(host4);
+            //DAP_DELETE(host4);
             return (void*) -1;
         }
         clock_gettime(CLOCK_MONOTONIC, &l_time_start);
@@ -135,10 +135,10 @@ static void* node_ping_proc(void *a_arg)
             size_t l_buf_size = 1024;
             uint8_t l_buf[l_buf_size];
 
-            const char* str_ip4 = inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), host4,
-            INET_ADDRSTRLEN);
+            //const char* str_ip4 = inet_ntop(AF_INET, &(((struct sockaddr_in *) &sa4)->sin_addr), host4,
+            //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);
+            DAP_UPLINK_PATH_ENC_INIT, "str_ip4");
             // send data to bad suburl
             int l_send_count = send(l_socket, l_str_to_send, dap_strlen(l_str_to_send), 0);
             long l_recv_count = 0;
@@ -155,7 +155,7 @@ static void* node_ping_proc(void *a_arg)
         else {
             ; //log_it(L_INFO, "Can't connect to node for ping");
         }
-        DAP_DELETE(host4);
+        //DAP_DELETE(host4);
         closesocket(l_socket);
     }
     return (void*)(size_t)res;
@@ -233,15 +233,9 @@ static void* node_ping_background_proc(void *a_arg)
             continue;
         }
 
-        char *host4 = DAP_NEW_STACK_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;
 #if defined(DAP_OS_LINUX) && ! defined(DAP_OS_ANDROID)
-        int res = traceroute_util(str_ip4, &hops, &time_usec);
+        //int res = traceroute_util(l_node_info->hdr.ext_addr, &hops, &time_usec);
 #endif
         if(l_min_hops>hops) {
             l_min_hops = hops;
@@ -249,8 +243,8 @@ static void* node_ping_background_proc(void *a_arg)
         }
 
         // 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;
+        //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->address.uint64;
         l_thread_id++;
         DAP_DELETE(l_node_info);
         l_node_list = dap_list_next(l_node_list);
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index 04540ea9aeabf36c5f76d17b3e3d7484c89faa07..fbc2e7a761c1a6f70cdc82d61fd57241e89555e4 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -152,8 +152,10 @@ const char* dap_chain_net_get_type(dap_chain_t *l_chain);
 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 * a_net);
 dap_list_t* dap_chain_net_get_node_list_cfg(dap_chain_net_t * a_net);
+dap_chain_node_info_t** dap_chain_net_get_seed_nodes(dap_chain_net_t * a_net, uint16_t *a_count);
 dap_chain_node_role_t dap_chain_net_get_role(dap_chain_net_t * a_net);
 dap_chain_node_info_t *dap_chain_net_balancer_link_from_cfg(dap_chain_net_t *a_net);
+dap_chain_node_info_t *dap_chain_net_get_my_node_info(dap_chain_net_t *a_net);
 
 int dap_chain_net_add_poa_certs_to_cluster(dap_chain_net_t *a_net, dap_global_db_cluster_t *a_cluster);
 bool dap_chain_net_add_validator_to_clusters(dap_chain_t *a_chain, dap_stream_node_addr_t *a_addr);
@@ -187,7 +189,9 @@ DAP_STATIC_INLINE char *dap_chain_net_get_gdb_group_nochain_new(dap_chain_t *a_c
 dap_chain_t *dap_chain_net_get_chain_by_chain_type(dap_chain_net_t *a_net, dap_chain_type_t a_datum_type);
 dap_chain_t *dap_chain_net_get_default_chain_by_chain_type(dap_chain_net_t *a_net, dap_chain_type_t a_datum_type);
 char *dap_chain_net_get_gdb_group_mempool_by_chain_type(dap_chain_net_t *a_net, dap_chain_type_t a_datum_type);
-dap_chain_net_t **dap_chain_net_list(uint16_t *a_size);
+size_t dap_chain_net_count();
+dap_chain_net_t *dap_chain_net_iter_start();
+dap_chain_net_t *dap_chain_net_iter_next(dap_chain_net_t*);
 
 int dap_chain_net_verify_datum_for_add(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, dap_hash_fast_t *a_datum_hash);
 char *dap_chain_net_verify_datum_err_code_to_str(dap_chain_datum_t *a_datum, int a_code);
diff --git a/modules/net/include/dap_chain_net_balancer.h b/modules/net/include/dap_chain_net_balancer.h
index 91162955008a7e4e4ee459f573b760ecd0f350b5..20ce336b2bcae3aeb76a24debd6815f5a853214a 100644
--- a/modules/net/include/dap_chain_net_balancer.h
+++ b/modules/net/include/dap_chain_net_balancer.h
@@ -34,7 +34,7 @@ typedef struct dap_chain_net_node_balancer {
 
 void dap_chain_net_balancer_http_issue_link(dap_http_simple_t *a_http_simple, void *a_arg);
 dap_chain_node_info_t *dap_chain_net_balancer_dns_issue_link(char *a_str);
-void dap_chain_net_balancer_prepare_list_links(const char *a_net_name,bool handshake_on);
+void dap_chain_net_balancer_prepare_list_links(const char *a_net_name);
 dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node(const char *a_net_name,uint16_t a_links_need);
 void dap_chain_net_balancer_set_link_ban(dap_chain_node_info_t *a_node_info, const char *a_net_name);
-bool dap_chain_net_balancer_handshake(dap_chain_node_info_t *a_node_info,dap_chain_net_t * a_net);
+int dap_chain_net_balancer_handshake(dap_chain_node_info_t *a_node_info,dap_chain_net_t * a_net);
diff --git a/modules/net/include/dap_chain_net_node_list.h b/modules/net/include/dap_chain_net_node_list.h
index 2e32bc60712f9570f5e384bc0fcc20e1a4255807..56b05e44fae2c669860219bb49bc0427fac7098e 100644
--- a/modules/net/include/dap_chain_net_node_list.h
+++ b/modules/net/include/dap_chain_net_node_list.h
@@ -1,9 +1,10 @@
 /*
 * Authors:
 * Roman Khlopkov <roman.khlopkov@demlabs.net>
+* Roman Padenkov <roman.padenkov@demlabs.net>
 * Cellframe       https://cellframe.net
 * DeM Labs Inc.   https://demlabs.net
-* Copyright  (c) 2017-2022
+* Copyright  (c) 2017-2023
 * All rights reserved.
 
 This file is part of CellFrame SDK the open source project
@@ -32,7 +33,6 @@ struct node_link_request {
     dap_chain_node_info_t *link_info;
     dap_chain_net_t *net;
     dap_worker_t *worker;
-    bool from_http;
     int link_replace_tries;
     int response;
     pthread_cond_t wait_cond;
@@ -49,5 +49,5 @@ DAP_STATIC_INLINE char * dap_chain_net_node_list_get_gdb_group(dap_chain_net_t *
 }
 
 void dap_chain_net_node_check_http_issue_link(dap_http_simple_t *a_http_simple, void *a_arg);
-int dap_chain_net_node_list_request (dap_chain_net_t *a_net, dap_chain_node_info_t *a_link_node_request, bool a_sync);
+int dap_chain_net_node_list_request (dap_chain_net_t *a_net, const char *a_addr, uint16_t a_port, bool a_sync, char a_cmd);
 int dap_chain_net_node_list_init();
diff --git a/modules/net/include/dap_chain_node.h b/modules/net/include/dap_chain_node.h
index 7c11e247ce5aee7274925b93ef27c4cd4d945201..6b3b4d82249acaceadc215065b31a189ecea4efb 100644
--- a/modules/net/include/dap_chain_node.h
+++ b/modules/net/include/dap_chain_node.h
@@ -21,6 +21,7 @@
 
 #pragma once
 
+#include <limits.h>
 #include "dap_common.h"
 #include "dap_list.h"
 #include "dap_worker.h"
@@ -32,7 +33,7 @@
 
 typedef struct dap_chain_net dap_chain_net_t;
 
-typedef struct dap_chain_node_info {
+typedef struct dap_chain_node_info_old {
     struct {
         dap_chain_node_addr_t address;
         dap_chain_cell_id_t cell_id;
@@ -48,8 +49,24 @@ typedef struct dap_chain_node_info {
     } DAP_ALIGN_PACKED info;
     uint16_t alias_len;
     byte_t alias[];
+} DAP_ALIGN_PACKED dap_chain_node_info_old_t;
+
+typedef struct dap_chain_node_info {
+    dap_chain_node_addr_t address;
+    dap_chain_cell_id_t cell_id;
+    char alias[64];
+    uint16_t ext_port;
+    uint8_t ext_host_len;
+    char ext_host[];
 } DAP_ALIGN_PACKED dap_chain_node_info_t;
 
+typedef struct dap_chain_node_states_info {
+    dap_chain_node_addr_t address;
+    uint64_t atoms_count;
+    uint32_t links_count;
+    dap_chain_node_addr_t links_addrs[];
+} DAP_ALIGN_PACKED dap_chain_node_states_info_t;
+
 typedef dap_stream_node_addr_t dap_chain_node_addr_t;
 #define dap_chain_node_addr_str_check dap_stream_node_addr_str_check
 #define dap_chain_node_addr_from_str dap_stream_node_addr_from_str
@@ -60,9 +77,7 @@ typedef dap_stream_node_addr_t dap_chain_node_addr_t;
  */
 DAP_STATIC_INLINE size_t dap_chain_node_info_get_size(dap_chain_node_info_t *a_node_info)
 {
-    if (!a_node_info)
-        return 0;
-    return (sizeof(dap_chain_node_info_t) + a_node_info->alias_len);
+    return !a_node_info ? 0 : sizeof(dap_chain_node_info_t) + a_node_info->ext_host_len + 1;
 }
 
 /**
@@ -89,15 +104,18 @@ bool dap_chain_node_alias_register(dap_chain_net_t *a_net, const char *a_alias,
 bool dap_chain_node_alias_delete(dap_chain_net_t * l_net,const char *alias);
 
 int dap_chain_node_info_save(dap_chain_net_t * l_net,dap_chain_node_info_t *node_info);
-dap_chain_node_info_t* dap_chain_node_info_read(dap_chain_net_t * l_net, dap_chain_node_addr_t *address);
+int dap_chain_node_info_del(dap_chain_net_t * l_net,dap_chain_node_info_t *node_info);
+dap_chain_node_info_t* dap_chain_node_info_read(dap_chain_net_t *l_net, dap_chain_node_addr_t *address);
 
-inline static char *dap_chain_node_addr_to_hash_str(dap_chain_node_addr_t *a_address)
+inline static char *dap_chain_node_addr_to_str_static(dap_chain_node_addr_t *a_address)
 {
-    return dap_strdup_printf(NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS(a_address));
+    static _Thread_local char s_buf[23] = { '\0' };
+    dap_snprintf(s_buf, sizeof(s_buf), NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS(a_address));
+    return s_buf;
 }
 
 bool dap_chain_node_mempool_need_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum);
 bool dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum, const char *a_datum_hash_str);
 void dap_chain_node_mempool_process_all(dap_chain_t *a_chain, bool a_force);
 bool dap_chain_node_mempool_autoproc_init();
-inline static void dap_chain_node_mempool_autoproc_deinit() {}
+inline static void dap_chain_node_mempool_autoproc_deinit() {}
\ No newline at end of file
diff --git a/modules/net/include/dap_chain_node_client.h b/modules/net/include/dap_chain_node_client.h
index 08e298d3f5493cb630024282cac5cf71bc1b53ad..acc3ef022b46e7dbdcd6793d2f5ac3ff558ed3b7 100644
--- a/modules/net/include/dap_chain_node_client.h
+++ b/modules/net/include/dap_chain_node_client.h
@@ -124,8 +124,6 @@ typedef struct dap_chain_node_client {
     UT_hash_handle hh;
     dap_chain_node_addr_t cur_node_addr;
     dap_chain_node_addr_t remote_node_addr;
-    struct in_addr remote_ipv4;
-    struct in6_addr remote_ipv6;
 
     bool keep_connection;
     bool is_connected;
diff --git a/modules/net/include/dap_chain_node_dns_client.h b/modules/net/include/dap_chain_node_dns_client.h
index dbebc757b75913bbe9dba5bb1f31b3dafb7e0dc8..d43fb284851299641b19ddb76f13c7ca405726d8 100644
--- a/modules/net/include/dap_chain_node_dns_client.h
+++ b/modules/net/include/dap_chain_node_dns_client.h
@@ -46,8 +46,6 @@ int dap_chain_node_info_dns_request(dap_worker_t *a_worker, struct in_addr a_add
                            dap_dns_client_node_info_request_success_callback_t a_callback_success,
                            dap_dns_client_node_info_request_error_callback_t a_callback_error, void * a_callback_arg);
 
-dap_chain_node_info_t *dap_dns_resolve_hostname(char *str);
-
 void dap_dns_buf_init(dap_dns_buf_t *buf, char *msg);
 void dap_dns_buf_put_uint64(dap_dns_buf_t *buf, uint64_t val);
 void dap_dns_buf_put_uint32(dap_dns_buf_t *buf, uint32_t val);
diff --git a/modules/net/include/dap_chain_node_net_ban_list.h b/modules/net/include/dap_chain_node_net_ban_list.h
deleted file mode 100644
index a017d7c9f93715961e660db6aa1e5e4fad583cf6..0000000000000000000000000000000000000000
--- a/modules/net/include/dap_chain_node_net_ban_list.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-
-#include "uthash.h"
-#ifdef WIN32
-#include <winsock2.h>
-#endif
-#ifdef DAP_OS_UNIX
-#include <arpa/inet.h>
-#endif
-#include "dap_chain_common.h"
-#include "dap_hash.h"
-#include "dap_time.h"
-#include "dap_http_ban_list_client.h"
-#include "dap_chain_net.h"
-#include "uthash.h"
-
-typedef struct dap_chain_node_ban_list_record{
-    dap_chain_node_addr_t node_addr;
-    dap_hash_fast_t decree_hash;
-    dap_time_t ts_created_decree;
-    UT_hash_handle hh;
-}dap_chain_node_ban_list_record_t;
-
-bool dap_chain_node_net_ban_list_check_node_addr(dap_chain_node_addr_t node_addr);
-
-bool dap_chain_node_net_ban_list_add_node_addr(dap_chain_node_addr_t node_addr, dap_hash_fast_t a_decree_hash, dap_time_t a_time_created, dap_chain_net_t *a_net);
-void dap_chain_node_net_ban_list_remove_node_addr(dap_chain_net_t *a_net, dap_chain_node_addr_t node_addr);
-void dap_chain_node_net_ban_list_print(dap_string_t *a_str_out);
-
-int dap_chain_node_net_ban_list_init();
-void dap_chain_node_net_ban_list_deinit();
diff --git a/modules/net/srv/dap_chain_net_srv_client.c b/modules/net/srv/dap_chain_net_srv_client.c
index 11d7fc5e69a55486855fde1e0a7adc127e1c32ea..ebb24d40199f8a0c1858e1830c29acd644831c69 100644
--- a/modules/net/srv/dap_chain_net_srv_client.c
+++ b/modules/net/srv/dap_chain_net_srv_client.c
@@ -54,22 +54,15 @@ dap_chain_net_srv_client_t *dap_chain_net_srv_client_create_n_connect(dap_chain_
         .disconnected = s_srv_client_callback_disconnected,
         .delete = s_srv_client_callback_deleted
     };
-
-    dap_chain_node_info_t *l_info = DAP_NEW_Z(dap_chain_node_info_t);
-
-    if (!l_info) {
-        log_it(L_CRITICAL, "Memory allocation error");
-        DAP_DEL_Z(l_ret);
-        return NULL;
-    }
-    inet_pton(AF_INET, a_addr, &l_info->hdr.ext_addr_v4);
-    l_info->hdr.ext_port = a_port;
+    
+    dap_chain_node_info_t *l_info = DAP_NEW_STACK_SIZE(dap_chain_node_info_t, sizeof(dap_chain_node_info_t) + dap_strlen(a_addr) + 1);
+    *l_info = (dap_chain_node_info_t) {
+        .ext_port = a_port
+    };
+    l_info->ext_host_len = dap_strncpy(l_info->ext_host, a_addr, INET6_ADDRSTRLEN) - l_info->ext_host;
     const char l_channels[] = {DAP_STREAM_CH_NET_SRV_ID, '\0'};
-    l_ret->node_client = dap_chain_node_client_create_n_connect(a_net, l_info,
-                                                                l_channels,
-                                                                &l_callbacks, l_ret);
+    l_ret->node_client = dap_chain_node_client_create_n_connect(a_net, l_info, l_channels, &l_callbacks, l_ret);
     l_ret->node_client->notify_callbacks.srv_pkt_in = (dap_stream_ch_callback_packet_t)s_srv_client_pkt_in;
-    DAP_DELETE(l_info);
     return l_ret;
 }
 void dap_chain_net_srv_client_close(dap_chain_net_srv_client_t *a_client){
diff --git a/modules/net/srv/include/dap_chain_net_srv.h b/modules/net/srv/include/dap_chain_net_srv.h
index cd10b101a0dbf041a0b7ea2477419ad6eaa5024b..091c90e48a1d767f10cd9011971683daa70f915c 100755
--- a/modules/net/srv/include/dap_chain_net_srv.h
+++ b/modules/net/srv/include/dap_chain_net_srv.h
@@ -178,7 +178,7 @@ typedef struct dap_stream_ch_chain_net_srv_pkt_test {
     dap_chain_net_srv_uid_t srv_uid;
     int32_t                 time_connect_ms;
     dap_nanotime_t          recv_time1, recv_time2, send_time1, send_time2;
-    char                    ip_send[INET_ADDRSTRLEN], ip_recv[INET_ADDRSTRLEN];
+    char                    host_send[0xFF + 1], host_recv[0xFF + 1];
     int32_t                 err_code;
     uint64_t                data_size_send, data_size_recv, data_size;
     dap_chain_hash_fast_t   data_hash;
diff --git a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
index 1a02af6e9ec0c653653a3abe56777da58460c93e..60912eb67fbafb1faad76763a4cf9470edda2beb 100644
--- a/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
+++ b/modules/service/stake/dap_chain_net_srv_stake_pos_delegate.c
@@ -146,10 +146,8 @@ void s_stake_net_clear(dap_chain_net_t *a_net)
  */
 void s_stake_clear()
 {
-    uint16_t l_net_count;
-    dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
-    for (uint16_t i = 0; i < l_net_count; i++) {
-        s_stake_net_clear(l_net_list[i]);
+    for (dap_chain_net_t *it = dap_chain_net_iter_start(); it; it = dap_chain_net_iter_next(it)) {
+        s_stake_net_clear(it);
     }
 }
 
@@ -2129,16 +2127,11 @@ int dap_chain_net_srv_stake_check_validator(dap_chain_net_t * a_net, dap_hash_fa
     }
     l_signer_node_addr = &l_tx_out_cond->subtype.srv_stake_pos_delegate.signer_node_addr;
 
-    l_key = dap_chain_node_addr_to_hash_str(l_signer_node_addr);
-    if(!l_key)
-    {
-        return -5;
-    }
     // read node
-    l_remote_node_info = (dap_chain_node_info_t *) dap_global_db_get_sync(a_net->pub.gdb_nodes, l_key, &l_node_info_size, NULL, NULL);
+    l_remote_node_info = (dap_chain_node_info_t*) dap_global_db_get_sync(a_net->pub.gdb_nodes,
+        dap_chain_node_addr_to_str_static(l_signer_node_addr), &l_node_info_size, NULL, NULL);
 
     if(!l_remote_node_info) {
-        DAP_DELETE(l_key);
         return -6;
     }
 
@@ -2146,10 +2139,8 @@ int dap_chain_net_srv_stake_check_validator(dap_chain_net_t * a_net, dap_hash_fa
     if(node_info_size_must_be != l_node_info_size) {
         log_it(L_WARNING, "node has bad size in base=%zu (must be %zu)", l_node_info_size, node_info_size_must_be);
         DAP_DELETE(l_remote_node_info);
-        DAP_DELETE(l_key);
         return -7;
     }
-    DAP_DELETE(l_key);
     // start connect
     l_node_client = dap_chain_node_client_connect_channels(a_net,l_remote_node_info,"N");
     if(!l_node_client) {
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c b/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c
index c2603e2c35e31fb9be3eaf2e931b087db5a3dc9f..8fb7670106aa0d22cee24df42f54ae58a818a904 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn_cmd.c
@@ -169,12 +169,12 @@ int com_vpn_client(int a_argc, char ** a_argv, void **a_str_reply)
         // default timeout 10ms
         int l_timeout_test_ms = dap_config_get_item_int32_default( g_config,"cdb", "servers_list_check_timeout", 20) * 1000;// read settings
         // start node check
-        int l_res = dap_chain_net_vpn_client_check(l_net, l_str_addr, NULL, l_srv_port, l_data_size_to_send, l_data_size_to_recv, l_timeout_test_ms);
+        int l_res = dap_chain_net_vpn_client_check(l_net, l_str_addr, l_srv_port, l_data_size_to_send, l_data_size_to_recv, l_timeout_test_ms);
         if(!l_res){
             l_data_size_to_send = 0;// no send data, only recv
             size_t l_data_size_to_recv = 10240;
             int l_timeout_test_ms = -1;// default timeout
-            l_res = dap_chain_net_vpn_client_check(l_net, l_str_addr, NULL, l_srv_port, l_data_size_to_send, l_data_size_to_recv, l_timeout_test_ms);
+            l_res = dap_chain_net_vpn_client_check(l_net, l_str_addr, l_srv_port, l_data_size_to_send, l_data_size_to_recv, l_timeout_test_ms);
         }
         switch (l_res) {
         case 0:
@@ -247,7 +247,7 @@ int com_vpn_client(int a_argc, char ** a_argv, void **a_str_reply)
                     "VPN server port not defined, use -port <vpn server port>  parameter");
             break;
         }
-        int l_res = dap_chain_net_vpn_client_start(l_net, l_str_addr, NULL, l_srv_port);
+        int l_res = dap_chain_net_vpn_client_start(l_net, l_str_addr, l_srv_port);
         switch (l_res) {
         case 0:
             dap_cli_server_cmd_set_reply_text(a_str_reply, "VPN client started successfully");
diff --git a/modules/service/vpn/dap_chain_net_vpn_client.c b/modules/service/vpn/dap_chain_net_vpn_client.c
index 68fd1d2b17f335dfeea71e9fc18e28bf3746e82d..dbe305b35043720a3f9c2313c261c83c23e2e739 100644
--- a/modules/service/vpn/dap_chain_net_vpn_client.c
+++ b/modules/service/vpn/dap_chain_net_vpn_client.c
@@ -490,8 +490,9 @@ char *dap_chain_net_vpn_client_check_result(dap_chain_net_t *a_net, const char*
  *
  * return: 0 Ok, <0 Error
  */
-int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_str, const char *a_ipv6_str, int a_port, size_t a_data_size_to_send, size_t a_data_size_to_recv, int a_timeout_test_ms)
+int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_host, uint16_t a_port, size_t a_data_size_to_send, size_t a_data_size_to_recv, int a_timeout_test_ms)
 {
+    dap_return_val_if_fail(a_net && a_host && (*a_host) && a_port, -1);
     // default 10k
     if(a_data_size_to_send== (size_t) -1)
         a_data_size_to_send = 10240;
@@ -503,11 +504,11 @@ int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_st
 
     int l_timeout_conn_ms = 10000;
     int l_ret = 0;
-    if(!a_ipv4_str) // && !a_ipv6_str)
-        return -1;
+    unsigned l_hostlen = dap_min((int)dap_strlen(a_host), 0xFF);
     if(!s_node_info)
-        s_node_info = DAP_NEW_Z(dap_chain_node_info_t);
-    s_node_info->hdr.ext_port = a_port;
+        s_node_info = DAP_NEW_Z_SIZE(dap_chain_node_info_t, sizeof(dap_chain_node_info_t) + l_hostlen + 1);
+    s_node_info->ext_host_len = dap_strncpy(s_node_info->ext_host, a_host, l_hostlen) - s_node_info->ext_host;
+    s_node_info->ext_port = a_port;
 
 
     // measuring connection time
@@ -516,27 +517,20 @@ int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_st
     long l_t1 = l_t.tv_sec * 1000 + l_t.tv_nsec / 1e6;
 
     const char l_active_channels[] = { DAP_STREAM_CH_NET_SRV_ID, 0 }; //only R, without S
-    if(a_ipv4_str)
-        inet_pton(AF_INET, a_ipv4_str, &(s_node_info->hdr.ext_addr_v4));
-    if(a_ipv6_str)
-        inet_pton(AF_INET6, a_ipv6_str, &(s_node_info->hdr.ext_addr_v6));
-
     s_vpn_client = dap_chain_node_client_create_n_connect(a_net, s_node_info, l_active_channels, NULL, NULL);
     if(!s_vpn_client) {
-        log_it(L_ERROR, "Can't connect to VPN server=%s:%d", a_ipv4_str, a_port);
-        DAP_DELETE(s_node_info);
-        s_node_info = NULL;
+        log_it(L_ERROR, "Can't connect to VPN server %s : %d", a_host, a_port);
+        DAP_DEL_Z(s_node_info);
         return -2;
     }
     // wait connected
     int l_timeout_ms = l_timeout_conn_ms; //5 sec = 5000 ms
     int l_res = dap_chain_node_client_wait(s_vpn_client, NODE_CLIENT_STATE_ESTABLISHED, l_timeout_ms);
     if(l_res) {
-        log_it(L_ERROR, "No response from VPN server=%s:%d", a_ipv4_str, a_port);
+        log_it(L_ERROR, "No response from VPN server %s : %d", a_host, a_port);
         // clean client struct
         dap_chain_node_client_close_mt(s_vpn_client);
-        DAP_DELETE(s_node_info);
-        s_node_info = NULL;
+        DAP_DEL_Z(s_node_info);
         return -3;
     }
 
@@ -557,8 +551,7 @@ int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_st
             l_request->data_size = a_data_size_to_send;
             randombytes(l_request->data, a_data_size_to_send);
             dap_hash_fast(l_request->data, l_request->data_size, &l_request->data_hash);
-            if(a_ipv4_str)
-                memcpy(l_request->ip_recv, a_ipv4_str, dap_min(sizeof(l_request->ip_recv), strlen(a_ipv4_str)));
+            dap_strncpy(l_request->host_recv, a_host, 0xFF);
             l_request->time_connect_ms = l_dtime_connect_ms;
             l_request->send_time1 = dap_nanotime_now();
             size_t l_request_size = l_request->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t);
@@ -573,12 +566,7 @@ int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_st
     if(a_timeout_test_ms<5000)
         a_timeout_test_ms = 5000;
     l_res = dap_chain_node_client_wait(s_vpn_client, NODE_CLIENT_STATE_CHECKED, a_timeout_test_ms);
-    if(l_res) {
-        log_it(L_ERROR, "No response from VPN server=%s:%d", a_ipv4_str, a_port);
-    }
-    else{
-        log_it(L_NOTICE, "Got response from VPN server=%s:%d", a_ipv4_str, a_port);
-    }
+    log_it(L_INFO, "%s response from VPN server %s : %d", l_res ? "No" : "Got", a_host, a_port);
     // clean client struct
     dap_chain_node_client_close_mt(s_vpn_client);
     DAP_DELETE(s_node_info);
@@ -594,24 +582,21 @@ int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_st
  *
  * return: 0 Ok, 1 Already started, <0 Error
  */
-int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_ipv4_str, const char *a_ipv6_str, int a_port)
+int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_host, uint16_t a_port)
 {
+    dap_return_val_if_fail(a_net && a_host, -1);
     int l_ret = 0;
-    if(!a_ipv4_str) // && !a_ipv6_str)
-        return -1;
+    unsigned l_hostlen = dap_min((int)strlen(a_host), 0xFF);
     if(!s_node_info)
-        s_node_info = DAP_NEW_Z(dap_chain_node_info_t);
-    s_node_info->hdr.ext_port = a_port;
+        s_node_info = DAP_NEW_Z_SIZE(dap_chain_node_info_t, sizeof(dap_chain_node_info_t) + l_hostlen + 1);
+    s_node_info->ext_host_len = dap_strncpy(s_node_info->ext_host, a_host, l_hostlen);
+    s_node_info->ext_port = a_port;
 
     const char l_active_channels[] = { DAP_STREAM_CH_NET_SRV_ID, DAP_STREAM_CH_NET_SRV_ID_VPN, 0 }; //R, S
-    if(a_ipv4_str)
-        inet_pton(AF_INET, a_ipv4_str, &(s_node_info->hdr.ext_addr_v4));
-    if(a_ipv6_str)
-        inet_pton(AF_INET6, a_ipv6_str, &(s_node_info->hdr.ext_addr_v6));
 
     s_vpn_client = dap_chain_node_client_connect_channels(a_net,s_node_info, l_active_channels);
     if(!s_vpn_client) {
-        log_it(L_ERROR, "Can't connect to VPN server=%s:%d", a_ipv4_str, a_port);
+        log_it(L_ERROR, "Can't connect to VPN server %s : %d", a_host, a_port);
         // clean client struct
         dap_chain_node_client_close_mt(s_vpn_client);
         DAP_DELETE(s_node_info);
@@ -622,7 +607,7 @@ int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_ipv4_st
     int timeout_ms = 5000; //5 sec = 5000 ms
     int res = dap_chain_node_client_wait(s_vpn_client, NODE_CLIENT_STATE_ESTABLISHED, timeout_ms);
     if(res) {
-        log_it(L_ERROR, "No response from VPN server=%s:%d", a_ipv4_str, a_port);
+        log_it(L_ERROR, "No response from VPN server %s : %d", a_host, a_port);
         // clean client struct
         dap_chain_node_client_close_mt(s_vpn_client);
         DAP_DELETE(s_node_info);
@@ -630,7 +615,7 @@ int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_ipv4_st
         return -3;
     }
 
-    l_ret = dap_chain_net_vpn_client_tun_init(a_ipv4_str);
+    l_ret = dap_chain_net_vpn_client_tun_init(a_host);
 
     // send first packet to server
     {
diff --git a/modules/service/vpn/dap_chain_net_vpn_client_tun.c b/modules/service/vpn/dap_chain_net_vpn_client_tun.c
index 43f92ee72a13ba2a2cea635aa4a7a615fab875f7..076fbd7e76c8a47b8776a76ff3c3daf81c277d44 100644
--- a/modules/service/vpn/dap_chain_net_vpn_client_tun.c
+++ b/modules/service/vpn/dap_chain_net_vpn_client_tun.c
@@ -328,9 +328,7 @@ static bool is_local_address(const char *a_address)
 
 int dap_chain_net_vpn_client_tun_init(const char *a_ipv4_server_str)
 {
-    if(s_cur_ipv4_server)
-        DAP_DELETE(s_cur_ipv4_server);
-    // set server address
+    DAP_DEL_Z(s_cur_ipv4_server);
     s_cur_ipv4_server = dap_strdup(a_ipv4_server_str);
     return 0;
 }
diff --git a/modules/service/vpn/include/dap_chain_net_vpn_client.h b/modules/service/vpn/include/dap_chain_net_vpn_client.h
index ac5ed4d4fcd27adb6a6c32e2e39aa7c271cb22a4..ea087cada2919a5699510c92827098aeb1e8c9b2 100644
--- a/modules/service/vpn/include/dap_chain_net_vpn_client.h
+++ b/modules/service/vpn/include/dap_chain_net_vpn_client.h
@@ -46,9 +46,9 @@ int dap_chain_net_vpn_client_update(dap_chain_net_t *a_net, const char *a_wallet
 int dap_chain_net_vpn_client_get_wallet_info(dap_chain_net_t *a_net, char **a_wallet_name, char **a_str_token, uint64_t *a_value_datoshi);
 
 char *dap_chain_net_vpn_client_check_result(dap_chain_net_t *a_net, const char* a_hash_out_type);
-int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_ipv4_str, const char *a_ipv6_str, int a_port, size_t a_data_size_to_send, size_t a_data_size_to_recv, int a_timeout_test_ms);
+int dap_chain_net_vpn_client_check(dap_chain_net_t *a_net, const char *a_host, uint16_t a_port, size_t a_data_size_to_send, size_t a_data_size_to_recv, int a_timeout_test_ms);
 
-int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_ipv4_str, const char *a_ipv6_str, int a_port);
+int dap_chain_net_vpn_client_start(dap_chain_net_t *a_net, const char *a_host, uint16_t a_port);
 int dap_chain_net_vpn_client_stop(void);
 dap_chain_net_vpn_client_status_t dap_chain_net_vpn_client_status(void);