diff --git a/dap-sdk b/dap-sdk
index 20315e499c2e61e8870e411fcc5fa64facd3c978..6f328918f8081071e0bdb8466515f5c6f4981cb4 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 20315e499c2e61e8870e411fcc5fa64facd3c978
+Subproject commit 6f328918f8081071e0bdb8466515f5c6f4981cb4
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 70870d88215d607f84f32eb5251e105030190d5c..6bfea9e5fa17c1a824136d9f5d2dd5a534b0a63b 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -715,7 +715,7 @@ ssize_t dap_chain_atom_save(dap_chain_cell_t *a_chain_cell, const uint8_t *a_ato
     dap_chain_t *l_chain = a_chain_cell->chain;
 
     if (a_new_atom_hash) { // Atom is new and need to be distributed for the net
-        dap_cluster_t *l_net_cluster = dap_cluster_find(dap_cluster_guuid_compose(l_chain->net_id.uint64, 0));
+        dap_cluster_t *l_net_cluster = dap_cluster_find(dap_guuid_compose(l_chain->net_id.uint64, 0));
         if (l_net_cluster) {
             size_t l_pkt_size = a_atom_size + sizeof(dap_chain_ch_pkt_t);
             dap_chain_ch_pkt_t *l_pkt = dap_chain_ch_pkt_new(l_chain->net_id.uint64, l_chain->id.uint64,
diff --git a/modules/chain/dap_chain_ch.c b/modules/chain/dap_chain_ch.c
index 5276e274ac1e48e155e50f1578dacf92594ac36d..d8cb37ec110c83a8292428597917b989543ea30c 100644
--- a/modules/chain/dap_chain_ch.c
+++ b/modules/chain/dap_chain_ch.c
@@ -840,7 +840,7 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
     } break;
 
     case DAP_CHAIN_CH_PKT_TYPE_CHAIN: {
-        dap_cluster_t *l_cluster = dap_cluster_find(dap_cluster_guuid_compose(l_chain_pkt->hdr.net_id.uint64, 0));
+        dap_cluster_t *l_cluster = dap_cluster_find(dap_guuid_compose(l_chain_pkt->hdr.net_id.uint64, 0));
         if (!l_cluster) {
             log_it(L_WARNING, "Can't find cluster with ID 0x%" DAP_UINT64_FORMAT_X, l_chain_pkt->hdr.net_id.uint64);
             s_stream_ch_write_error_unsafe(a_ch, l_chain_pkt->hdr.net_id.uint64,
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 f27ac58f681d62d6cfb5520f1f1e6e4c7f50a700..81f8d0afcb7937fd2a64bc5914bf54ff9781b450 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
@@ -874,6 +874,7 @@ static bool s_grace_period_finish(dap_chain_net_srv_grace_usage_t *a_grace_item)
             l_err.code = error ; \
             s_grace_error(l_grace, l_err); \
         } \
+        DAP_DELETE(l_grace); \
         DAP_DELETE(a_grace_item); \
         return false; \
     } \
@@ -1042,7 +1043,6 @@ static bool s_grace_period_finish(dap_chain_net_srv_grace_usage_t *a_grace_item)
                                                                             sizeof(dap_chain_datum_tx_receipt_t) + l_grace->usage->receipt->size + l_grace->usage->receipt->exts_size);
                     DAP_DELETE(l_success);
                 }
-                DAP_DELETE(l_grace);
                 DAP_DELETE(l_remain_service);
                 RET_WITH_DEL_A_GRACE(0);
             }
diff --git a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
index 516c56c572877a9072bac15618b29af54f4374a9..5b89f0212bf66458fda55967bc3dd2e782577196 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -76,6 +76,7 @@ typedef struct dap_chain_cs_dag_poa_pvt {
     uint32_t confirmations_timeout; // wait signs over min value (auth_certs_count_verify)
     uint32_t wait_sync_before_complete;
     dap_chain_cs_dag_poa_presign_callback_t *callback_pre_sign;
+    dap_interval_timer_t mempool_timer;
 } dap_chain_cs_dag_poa_pvt_t;
 
 #define PVT(a) ((dap_chain_cs_dag_poa_pvt_t *) a->_pvt )
@@ -694,6 +695,26 @@ static bool s_callback_sync_all_on_start(dap_global_db_instance_t *a_dbi, int a_
     return false;
 }
 
+static void s_round_changes_notify(dap_store_obj_t *a_obj, void *a_arg)
+{
+    dap_chain_cs_dag_t *l_dag = (dap_chain_cs_dag_t *)a_arg;
+    assert(l_dag);
+    dap_chain_net_t *l_net = dap_chain_net_by_id(l_dag->chain->net_id);
+    log_it(L_DEBUG, "%s.%s: op_code='%c' group=\"%s\" key=\"%s\" value_size=%zu",
+        l_net->pub.name, l_dag->chain->name, a_obj->type, a_obj->group, a_obj->key, a_obj->value_len);
+    if (a_obj->type == DAP_GLOBAL_DB_OPTYPE_ADD) {
+        if (dap_strcmp(a_obj->key, DAG_ROUND_CURRENT_KEY))  // check key for round increment, if no than process event
+            s_callback_event_round_sync(l_dag, a_obj->type, a_obj->group, a_obj->key, a_obj->value, a_obj->value_len);
+        else
+            log_it(L_INFO, "Global round ID: %lu", *(uint64_t*)a_obj->value);
+    }
+}
+
+static void s_timer_process_callback(void *a_arg)
+{
+    dap_chain_node_mempool_process_all((dap_chain_t *)a_arg, false);
+}
+
 /**
  * @brief create callback load certificate for event signing for specific chain
  * path to certificate iw written to chain config file in dag_poa section
@@ -714,10 +735,25 @@ static int s_callback_created(dap_chain_t * a_chain, dap_config_t *a_chain_net_c
             log_it(L_NOTICE,"Loaded \"%s\" certificate to sign poa event", l_events_sign_cert);
 
     }
-    dap_chain_net_t *l_cur_net = dap_chain_net_by_name(a_chain->net_name);
-    dap_chain_node_role_t l_role = dap_chain_net_get_role(l_cur_net);
+    dap_chain_net_t *l_net = dap_chain_net_by_name(a_chain->net_name);
+    assert(l_net);
+    dap_global_db_cluster_t *l_dag_cluster = dap_global_db_cluster_add(dap_global_db_instance_get_default(), NULL,
+                                                                       dap_guuid_compose(l_net->pub.id.uint64, DAP_CHAIN_CLUSTER_ID_DAG),
+                                                                       l_dag->gdb_group_events_round_new, 900, true,
+                                                                       DAP_GDB_MEMBER_ROLE_NOBODY, DAP_CLUSTER_ROLE_AUTONOMIC);
+    dap_global_db_cluster_add_notify_callback(l_dag_cluster, s_round_changes_notify, l_dag);
+    dap_chain_net_add_auth_nodes_to_cluster(l_net, l_dag_cluster);
+    dap_link_manager_add_net_associate(l_net->pub.id.uint64, l_dag_cluster->links_cluster);
+
+    byte_t *l_current_round = dap_global_db_get_sync(l_dag->gdb_group_events_round_new, DAG_ROUND_CURRENT_KEY, NULL, NULL, NULL);
+    l_dag->round_current = l_current_round ? *(uint64_t*)l_current_round : 0;
+    DAP_DELETE(l_current_round);
+    log_it(L_INFO, "Current round id %"DAP_UINT64_FORMAT_U, l_dag->round_current);
+
+    PVT(l_poa)->mempool_timer = dap_interval_timer_create(15000, s_timer_process_callback, a_chain);
+
+    dap_chain_node_role_t l_role = dap_chain_net_get_role(l_net);
     if (l_role.enums == NODE_ROLE_ROOT_MASTER || l_role.enums == NODE_ROLE_ROOT) {
-        l_dag->callback_cs_event_round_sync = s_callback_event_round_sync;
         l_dag->round_completed = l_dag->round_current++;
         log_it(L_MSG, "Round complete ID %"DAP_UINT64_FORMAT_U", current ID %"DAP_UINT64_FORMAT_U, l_dag->round_completed, l_dag->round_current);
         dap_global_db_get_all(l_dag->gdb_group_events_round_new, 0, s_callback_sync_all_on_start, l_dag);
@@ -738,6 +774,8 @@ static void s_callback_delete(dap_chain_cs_dag_t * a_dag)
     if ( l_poa->_pvt ) {
         dap_chain_cs_dag_poa_pvt_t * l_poa_pvt = PVT ( l_poa );
 
+        dap_interval_timer_delete(l_poa_pvt->mempool_timer);
+
         if ( l_poa_pvt->auth_certs )
             DAP_DELETE ( l_poa_pvt->auth_certs);
 
diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
index b1b5ac2f6f86ed783ca8404ba9ad97ae0b6060a3..5233bd3581116838137e90c01a1f0da09c0b94ae 100644
--- a/modules/consensus/esbocs/dap_chain_cs_esbocs.c
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -484,11 +484,12 @@ static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cf
     l_session->my_signing_addr = l_my_signing_addr;
     char *l_sync_group = s_get_penalty_group(l_net->pub.id);
     l_session->db_cluster = dap_global_db_cluster_add(dap_global_db_instance_get_default(), NULL,
-                                                      dap_cluster_guuid_compose(l_net->pub.id.uint64, DAP_CHAIN_CLUSTER_ID_ESBOCS),
+                                                      dap_guuid_compose(l_net->pub.id.uint64, DAP_CHAIN_CLUSTER_ID_ESBOCS),
                                                       l_sync_group, 72 * 3600, true,
                                                       DAP_GDB_MEMBER_ROLE_NOBODY, DAP_CLUSTER_ROLE_AUTONOMIC);
     DAP_DELETE(l_sync_group);
     dap_global_db_cluster_add_notify_callback(l_session->db_cluster, s_db_change_notifier, l_session);
+    dap_link_manager_add_net_associate(l_net->pub.id.uint64, l_session->db_cluster->links_cluster);
 
     for (dap_list_t *it = l_validators; it; it = it->next) {
         dap_stream_node_addr_t *l_addr = &((dap_chain_net_srv_stake_item_t *)it->data)->node_addr;
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 1ff166f62e25a8495ee542bef5d57cba209a861d..fbbcba3321c04f01a5b0635c239c992922688891 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -132,10 +132,16 @@
 
 static bool s_debug_more = false;
 
+struct request_link_info {
+    char addr[DAP_HOSTADDR_STRLEN];
+    uint16_t port;
+};
+
 struct balancer_link_request {
-    dap_chain_node_info_t *link_info;
+    struct request_link_info *info;
     dap_chain_net_t *net;
     dap_worker_t *worker;
+    uint16_t links_requested_count;
 };
 
 struct block_reward {
@@ -173,19 +179,17 @@ typedef struct dap_chain_net_pvt{
 
     dap_chain_node_info_t *node_info;  // Current node's info
 
-    bool balancer_http;
-    bool links_static_only;
+    int balancer_type;
     bool load_mode;
 
     uint16_t permanent_links_count;
-    dap_stream_node_addr_t *permanent_links;
+    dap_link_info_t **permanent_links;
 
-    uint16_t poa_nodes_count;
-    dap_stream_node_addr_t *poa_nodes_addrs;
-    bool seeds_is_poas;
+    uint16_t authorized_nodes_count;
+    dap_stream_node_addr_t *authorized_nodes_addrs;
 
     uint16_t seed_nodes_count;
-    dap_chain_node_info_t **seed_nodes_info;
+    struct request_link_info **seed_nodes_info;
 
     struct chain_sync_context sync_context;
 
@@ -218,9 +222,7 @@ static const char *c_net_states[] = {
     [NET_STATE_LINKS_PREPARE ]      = "NET_STATE_LINKS_PREPARE",
     [NET_STATE_LINKS_CONNECTING]    = "NET_STATE_LINKS_CONNECTING",
     [NET_STATE_LINKS_ESTABLISHED]   = "NET_STATE_LINKS_ESTABLISHED",
-    [NET_STATE_SYNC_GDB]            = "NET_STATE_SYNC_GDB",
     [NET_STATE_SYNC_CHAINS]         = "NET_STATE_SYNC_CHAINS",
-    [NET_STATE_ADDR_REQUEST]        = "NET_STATE_ADDR_REQUEST",
     [NET_STATE_ONLINE]              = "NET_STATE_ONLINE"
 };
 
@@ -229,13 +231,11 @@ static inline const char * dap_chain_net_state_to_str(dap_chain_net_state_t a_st
 }
 
 // Node link callbacks
-static void s_node_link_callback_stage(dap_chain_node_client_t * a_node_client,dap_client_stage_t a_stage, void * a_arg);
-
 static void s_link_manager_callback_connected(dap_link_t *a_link, uint64_t a_net_id);
 static void s_link_manager_callback_error(dap_link_t *a_link, uint64_t a_net_id, int a_error);
-static void s_link_manager_callback_disconnected(dap_link_t *a_link, uint64_t a_net_id, int a_links_count);
+static bool s_link_manager_callback_disconnected(dap_link_t *a_link, uint64_t a_net_id, int a_links_count);
 static int s_link_manager_fill_net_info(dap_link_t *a_link);
-static void s_link_manager_link_request(uint64_t a_net_id);
+static int s_link_manager_link_request(uint64_t a_net_id);
 
 static const dap_link_manager_callbacks_t s_link_manager_callbacks = {
     .connected      = s_link_manager_callback_connected,
@@ -256,7 +256,6 @@ static int s_net_load(dap_chain_net_t *a_net);
 static int s_net_try_online(dap_chain_net_t *a_net);
 static int s_cli_net(int argc, char ** argv, void **a_str_reply);
 static uint8_t *s_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash);
-static bool s_new_balancer_link_request(dap_chain_net_t *a_net);
 static void s_sync_timer_callback(void *a_arg);
 
 /**
@@ -273,6 +272,7 @@ int dap_chain_net_init()
     dap_chain_node_client_init();
     dap_chain_net_voting_init();
     dap_http_ban_list_client_init();
+    dap_link_manager_init(&s_link_manager_callbacks);
     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"
@@ -379,23 +379,31 @@ int dap_chain_net_state_go_to(dap_chain_net_t *a_net, dap_chain_net_state_t a_ne
         log_it(L_ERROR, "Can't change state of loading network '%s'", a_net->pub.name);
         return -1;
     }
-    if (PVT(a_net)->state != NET_STATE_OFFLINE){
-        PVT(a_net)->state = PVT(a_net)->state_target = NET_STATE_OFFLINE;
-        s_net_states_proc(a_net);
+    if (PVT(a_net)->state_target == a_new_state) {
+        log_it(L_NOTICE, "Network %s already %s state %s", a_net->pub.name,
+                                PVT(a_net)->state == a_new_state ? "have" : "going to", dap_chain_net_state_to_str(a_new_state));
+        return 0;
     }
-    PVT(a_net)->state_target = a_new_state;
     //PVT(a_net)->flags |= F_DAP_CHAIN_NET_SYNC_FROM_ZERO;  // TODO set this flag according to -mode argument from command line
-    if(a_new_state == NET_STATE_ONLINE) {
-        dap_chain_esbocs_start_timer(a_net->pub.id);
-        dap_link_manager_set_net_condition(a_net->pub.id.uint64, true);
-    }
-
-    if (a_new_state == NET_STATE_OFFLINE){
-        dap_chain_esbocs_stop_timer(a_net->pub.id);
+    PVT(a_net)->state_target = a_new_state;
+    if (a_new_state == NET_STATE_OFFLINE) {
         dap_link_manager_set_net_condition(a_net->pub.id.uint64, false);
-        return 0;
+        dap_chain_esbocs_stop_timer(a_net->pub.id);
+    } else if (PVT(a_net)->state == NET_STATE_OFFLINE) {
+        dap_link_manager_set_net_condition(a_net->pub.id.uint64, true);
+        for (uint16_t i = 0; i < PVT(a_net)->permanent_links_count; ++i) {
+            dap_link_info_t *l_permalink_info = PVT(a_net)->permanent_links[i];
+            dap_link_t *l_link = dap_link_manager_link_create(&l_permalink_info->node_addr, true, a_net->pub.id.uint64);
+            if (!l_link) {
+                log_it(L_ERROR, "Can't create permanent link to addr " NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(l_permalink_info->node_addr));
+                continue;
+            }
+            if (l_permalink_info->uplink_port)
+                dap_link_manager_link_update(l_link, l_permalink_info->uplink_addr, l_permalink_info->uplink_port);
+        }
+        if (a_new_state == NET_STATE_ONLINE)
+            dap_chain_esbocs_start_timer(a_net->pub.id);
     }
-
     return dap_proc_thread_callback_add(NULL, s_net_states_proc, a_net);
 }
 
@@ -405,7 +413,7 @@ dap_chain_net_state_t dap_chain_net_get_target_state(dap_chain_net_t *a_net)
     return l_ret;
 }
 
-dap_chain_node_info_t *dap_chain_net_balancer_link_from_cfg(dap_chain_net_t *a_net)
+static struct request_link_info *s_balancer_link_from_cfg(dap_chain_net_t *a_net)
 {
     switch (PVT(a_net)->seed_nodes_count) {
     case 0: return log_it(L_ERROR, "No available links! Add them in net config"), NULL;
@@ -414,39 +422,36 @@ dap_chain_node_info_t *dap_chain_net_balancer_link_from_cfg(dap_chain_net_t *a_n
     }
 }
 
-dap_chain_node_info_t *dap_chain_net_get_my_node_info(dap_chain_net_t *a_net) {
+dap_chain_node_info_t *dap_chain_net_get_my_node_info(dap_chain_net_t *a_net)
+{
+    dap_return_val_if_fail(a_net, NULL);
     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)
+bool dap_chain_net_is_my_node_authorized(dap_chain_net_t *a_net)
 {
-    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);
+    dap_return_val_if_fail(a_net, false);
+    return dap_cluster_member_find_role(PVT(a_net)->nodes_cluster->role_cluster, &g_node_addr) == DAP_GDB_MEMBER_ROLE_ROOT;
 }
 
-/**
- * @brief s_fill_links_from_root_aliases
- * @param a_net
- */
-static void s_fill_links_from_root_aliases(dap_chain_net_t *a_net)
+dap_stream_node_addr_t *dap_chain_net_get_authorized_nodes(dap_chain_net_t *a_net, size_t *a_nodes_count)
 {
-// sanity check
-    dap_return_if_pass(!a_net);
-// func work
-    dap_chain_net_pvt_t *l_net_pvt = PVT(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(&l_net_pvt->seed_nodes_info[i]->address);
-        l_link = dap_link_manager_link_update(l_link, l_net_pvt->seed_nodes_info[i]->ext_host, l_net_pvt->seed_nodes_info[i]->ext_port, false);
-        if (!l_link)
-            continue;
-        dap_link_manager_link_add(a_net->pub.id.uint64, l_link);
+    dap_return_val_if_fail(a_net, false);
+    return dap_cluster_get_all_members_addrs(PVT(a_net)->nodes_cluster->role_cluster, a_nodes_count, DAP_GDB_MEMBER_ROLE_ROOT);
+}
+
+static int s_net_link_add(dap_chain_net_t *a_net, dap_stream_node_addr_t *a_addr, const char *a_host, uint16_t a_port)
+{
+    dap_link_t *l_link = dap_link_manager_link_create(a_addr, true, a_net->pub.id.uint64);
+    if (!l_link) {
+        if (a_addr->uint64 != g_node_addr.uint64)
+            log_it(L_ERROR, "Can't create link to addr " NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS(a_addr));
+        return -1;
     }
+    int rc = dap_link_manager_link_update(l_link, a_host, a_port);
+    if (rc)
+        log_it(L_ERROR, "Can't update link to addr " NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS(a_addr));
+    return rc;
 }
 
 /**
@@ -463,13 +468,13 @@ static void s_link_manager_callback_connected(dap_link_t *a_link, uint64_t a_net
     dap_chain_net_pvt_t *l_net_pvt = PVT(l_net);
 
     log_it(L_NOTICE, "Established connection with %s."NODE_ADDR_FP_STR,l_net->pub.name,
-           NODE_ADDR_FP_ARGS_S(a_link->client->link_info.node_addr));
+           NODE_ADDR_FP_ARGS_S(a_link->addr));
 
     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)
                  , "Established connection with link " NODE_ADDR_FP_STR
-                 , NODE_ADDR_FP_ARGS_S(a_link->client->link_info.node_addr));
+                 , NODE_ADDR_FP_ARGS_S(a_link->addr));
     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);
@@ -478,47 +483,40 @@ static void s_link_manager_callback_connected(dap_link_t *a_link, uint64_t a_net
     }
     dap_stream_ch_chain_net_pkt_hdr_t l_announce = { .version = DAP_STREAM_CH_CHAIN_NET_PKT_VERSION,
                                                      .net_id  = l_net->pub.id };
-    dap_client_write_unsafe(a_link->client, 'N', DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ANNOUNCE,
+    dap_client_write_unsafe(a_link->uplink.client, 'N', DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ANNOUNCE,
                                      &l_announce, sizeof(l_announce));
 }
 
+static bool s_net_check_link_is_premanent(dap_chain_net_t *a_net, dap_stream_node_addr_t *a_addr)
+{
+    dap_chain_net_pvt_t *l_net_pvt = PVT(a_net);
+    for (uint16_t i = 0; i < l_net_pvt->permanent_links_count; i++) {
+        if (l_net_pvt->permanent_links[i]->node_addr.uint64 == a_addr->uint64)
+            return true;
+    }
+    return false;
+}
+
 /**
  * @brief s_link_manager_callback_disconnected
  * @param a_node_client
  * @param a_arg
  */
 
-static void s_link_manager_callback_disconnected(dap_link_t *a_link, uint64_t a_net_id, int a_links_count)
+static bool s_link_manager_callback_disconnected(dap_link_t *a_link, uint64_t a_net_id, int a_links_count)
 {
 // sanity check
-    dap_return_if_pass(!a_link);
+    dap_return_val_if_pass(!a_link, false);
 // 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_INFO, "%s."NODE_ADDR_FP_STR" disconnected.%s", l_net ? l_net->pub.name : "(unknown)" ,
-            NODE_ADDR_FP_ARGS_S(a_link->client->link_info.node_addr),
-            l_net_pvt->state_target == NET_STATE_OFFLINE ? "" : " Replace it...");
-    if(!a_links_count && l_net_pvt->state == NET_STATE_ONLINE ){
+    bool l_link_is_permanent = s_net_check_link_is_premanent(l_net, &a_link->addr);
+    log_it(L_INFO, "%s."NODE_ADDR_FP_STR" can't connect for now. %s", l_net ? l_net->pub.name : "(unknown)" ,
+            NODE_ADDR_FP_ARGS_S(a_link->addr),
+            l_link_is_permanent ? "Setting reconnection pause for it." : "Dropping it.");
+    if (!a_links_count && l_net_pvt->state == NET_STATE_ONLINE)
         l_net_pvt->state = NET_STATE_LINKS_PREPARE;
-    }
-}
-
-/**
- * @brief s_node_link_callback_stage
- * @param a_node_client
- * @param a_stage
- * @param a_arg
- */
-static void s_node_link_callback_stage(dap_chain_node_client_t * a_node_client,dap_client_stage_t a_stage, void * a_arg)
-{
-    dap_chain_net_t * l_net = (dap_chain_net_t *) a_arg;
-    if( s_debug_more)
-        log_it(L_INFO,"%s."NODE_ADDR_FP_STR" stage %s",l_net->pub.name,NODE_ADDR_FP_ARGS_S(a_node_client->remote_node_addr),
-                                                        dap_client_stage_str(a_stage));
-    struct json_object *l_json = s_net_states_json_collect(l_net);
-    json_object_object_add(l_json, "errorMessage", json_object_new_string(" "));
-    dap_notify_server_send_mt(json_object_get_string(l_json));
-    json_object_put(l_json);
+    return l_link_is_permanent;
 }
 
 /**
@@ -533,15 +531,14 @@ static void s_link_manager_callback_error(dap_link_t *a_link, uint64_t a_net_id,
     dap_return_if_pass(!a_link);
 // 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->client->link_info.node_addr));
+           l_net ? l_net->pub.name : "(unknown)", NODE_ADDR_FP_ARGS_S(a_link->addr));
     if (l_net){
         struct json_object *l_json = s_net_states_json_collect(l_net);
         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->client->link_info.node_addr), a_link->client->link_info.uplink_addr, a_error);
+                     , NODE_ADDR_FP_ARGS_S(a_link->addr), a_link->uplink.client->link_info.uplink_addr, a_error);
         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);
@@ -554,42 +551,26 @@ static void s_link_manager_callback_error(dap_link_t *a_link, uint64_t a_net_id,
  * @param a_node_info
  * @param a_arg
  */
-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)
+static void s_balancer_link_prepare_success(dap_chain_net_t *a_net, dap_chain_net_links_t *a_link_full_node_list)
 {
-    if(s_debug_more) {
-        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) {
-            log_it( L_DEBUG,"Link " NODE_ADDR_FP_STR " [ %s : %u ] prepare success",
-                   NODE_ADDR_FP_ARGS_S(l_node_info->address), l_node_info->ext_host, l_node_info->ext_port);
-        }
-    }
-
-    struct balancer_link_request *l_balancer_request = (struct balancer_link_request *) a_arg;
-    dap_chain_net_t * l_net = l_balancer_request->net;
-    dap_link_info_t *l_link_info = (dap_link_info_t *)a_link_full_node_list->nodes_info;
     char l_err_str[128] = {0};
     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(&l_link_info[i].node_addr);
-        l_link = dap_link_manager_link_update(l_link, l_link_info[i].uplink_addr, l_link_info[i].uplink_port, false);
-        if (!l_link)
+    for (size_t i = 0; i < a_link_full_node_list->count_node; ++i) {
+        dap_link_info_t *l_link_info = (dap_link_info_t *)a_link_full_node_list->nodes_info + i;
+        debug_if(s_debug_more, L_DEBUG,"Link " NODE_ADDR_FP_STR " [ %s : %u ] prepare success",
+               NODE_ADDR_FP_ARGS_S(l_link_info->node_addr), l_link_info->uplink_addr, l_link_info->uplink_port);
+        if (s_net_link_add(a_net, &l_link_info->node_addr, l_link_info->uplink_addr, l_link_info->uplink_port))
             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_link_info[i].node_addr));
-            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_link_info[i].node_addr));
-            break;
-        default: break;
-        }
+        l_json = s_net_states_json_collect(a_net);
+        snprintf(l_err_str, sizeof(l_err_str)
+                     , "Link " NODE_ADDR_FP_STR " prepared"
+                     , NODE_ADDR_FP_ARGS_S(l_link_info->node_addr));
+        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_link_info->node_addr));
     }
-    DAP_DELETE(l_balancer_request);
 }
 
 /**
@@ -599,47 +580,40 @@ static void s_net_balancer_link_prepare_success(dap_worker_t * a_worker, dap_cha
  * @param a_arg
  * @param a_errno
  */
-static void s_net_balancer_link_prepare_error(dap_worker_t * a_worker, void * a_arg, int a_errno)
+static void s_balancer_link_prepare_error(dap_chain_net_t *a_net, const char *a_addr, int a_errno)
 {
-    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;
-
-    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);
+    struct json_object *l_json = s_net_states_json_collect(a_net);
     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->address), l_node_info->ext_host, a_errno);
+                 , "Link from balancer %s can't be prepared, errno %d"
+                 , a_addr, a_errno);
+    log_it(L_WARNING, l_err_str);
     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);
-
-    DAP_DELETE(l_balancer_request);
 }
 
 
-void s_net_http_link_prepare_success(void *a_response, size_t a_response_size, void *a_arg)
+void s_http_balancer_link_prepare_success(void *a_response, size_t a_response_size, void *a_arg)
 {
     struct balancer_link_request *l_balancer_request = (struct balancer_link_request *)a_arg;
-    dap_chain_net_node_balancer_t* l_link_full_node_list = (dap_chain_net_node_balancer_t*)a_response;
+    dap_chain_net_links_t *l_link_full_node_list = (dap_chain_net_links_t*)a_response;
 
-    size_t l_response_size_need = sizeof(dap_chain_net_node_balancer_t) + (sizeof(dap_link_info_t) * l_link_full_node_list->count_node);
-    log_it(L_WARNING, "Get data size - %lu need - (%lu)", a_response_size, l_response_size_need);
-    if (a_response_size != l_response_size_need) {
-        log_it(L_ERROR, "Invalid balancer response size %lu (expected %lu)", a_response_size, l_response_size_need);
+    size_t l_response_size_need = sizeof(dap_chain_net_links_t) + (sizeof(dap_link_info_t) * l_balancer_request->links_requested_count);
+    if (a_response_size < sizeof(dap_chain_net_links_t) + sizeof(dap_link_info_t) || a_response_size > l_response_size_need) {
+        log_it(L_ERROR, "Invalid balancer response size %zu (expected %zu)", a_response_size, l_response_size_need);
         DAP_DELETE(l_balancer_request);
         return;
     }
-    s_net_balancer_link_prepare_success(l_balancer_request->worker, l_link_full_node_list, a_arg);
+    s_balancer_link_prepare_success(l_balancer_request->net, l_link_full_node_list);
+    DAP_DELETE(l_balancer_request);
 }
 
-void s_net_http_link_prepare_error(int a_error_code, void *a_arg)
+void s_http_balancer_link_prepare_error(int a_error_code, void *a_arg)
 {
     struct balancer_link_request *l_balancer_request = (struct balancer_link_request *)a_arg;
-    s_net_balancer_link_prepare_error(l_balancer_request->worker, a_arg, a_error_code);
+    s_balancer_link_prepare_error(l_balancer_request->net, l_balancer_request->info->addr, a_error_code);
+    DAP_DELETE(l_balancer_request);
 }
 
 /**
@@ -648,111 +622,97 @@ void s_net_http_link_prepare_error(int a_error_code, void *a_arg)
  * @param a_link_node_info node parameters
  * @return list of dap_chain_node_info_t
  */
-static bool s_new_balancer_link_request(dap_chain_net_t *a_net)
+int s_link_manager_link_request(uint64_t a_net_id)
 {
 // sanity check
-    dap_return_val_if_pass(!a_net || !PVT(a_net) || PVT(a_net)->state_target == NET_STATE_OFFLINE , false);
+    dap_chain_net_t *l_net = dap_chain_net_by_id((dap_chain_net_id_t){.uint64 = a_net_id});
+    dap_return_val_if_pass(!l_net, -1);
 // func work
-    dap_chain_net_pvt_t *l_net_pvt = PVT(a_net);
-    if (l_net_pvt->state == NET_STATE_LINKS_PREPARE && l_net_pvt->state_target != NET_STATE_OFFLINE) {
+    dap_chain_net_pvt_t *l_net_pvt = PVT(l_net);
+    if (l_net_pvt->state_target == NET_STATE_OFFLINE)
+        return -2;
+    if (l_net_pvt->state == NET_STATE_LINKS_PREPARE)
         l_net_pvt->state = NET_STATE_LINKS_CONNECTING;
-    }
-    // static links
-    if (dap_link_manager_links_count(a_net->pub.id.uint64) < l_net_pvt->seed_nodes_count) {
-        s_fill_links_from_root_aliases(a_net);
-        // Extra links from cfg
-        for (int i = 0; i < l_net_pvt->permanent_links_count; i++) {
-            dap_chain_node_info_t *l_link_node_info = dap_chain_node_info_read(a_net, l_net_pvt->permanent_links + i);
-            if (!l_link_node_info) {
-                log_it(L_WARNING, "Can't find addr info for permanent link " NODE_ADDR_FP_STR,
-                        NODE_ADDR_FP_ARGS(l_net_pvt->permanent_links + i));
-                continue;
-            }
-            dap_link_t *l_link = dap_link_manager_link_create(&l_link_node_info->address);
-            l_link = dap_link_manager_link_update(l_link, l_link_node_info->ext_host, l_link_node_info->ext_port, false);
-            dap_link_manager_link_add(a_net->pub.id.uint64, l_link);
-            DAP_DELETE(l_link_node_info);
-        }
-    }
-    if(l_net_pvt->links_static_only)
-        return true;
-    // dynamic links from node list
-    static bool l_load_from_node_list = true;
-    if(l_load_from_node_list) {
-        l_load_from_node_list = !l_load_from_node_list;  // switch mode
-        size_t l_nodes_count = 0;
-        dap_global_db_obj_t *l_objs = dap_global_db_get_all_sync(a_net->pub.gdb_nodes, &l_nodes_count);
-        if (!l_nodes_count || !l_objs) {
-            log_it(L_ERROR, "Node list is empty");
-            return false;
-        }
-        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;
-            dap_link_t *l_link = dap_link_manager_link_create(&l_node_info->address);
-            l_link = dap_link_manager_link_update(l_link, l_node_info->ext_host, l_node_info->ext_port, false);
-            if (!l_link)
-                continue;
-            dap_link_manager_link_add(a_net->pub.id.uint64, l_link);
-        }
-        return true;
-    }
-    l_load_from_node_list = !l_load_from_node_list;
+    size_t l_required_links_count = dap_link_manager_needed_links_count(l_net->pub.id.uint64);
+    /* TODO make correct asynchronous local balancer request
+    dap_chain_net_links_t *l_links = dap_chain_net_balancer_get_node(l_net->pub.name, l_required_links_count);
+    if (l_links) {
+        s_balancer_link_prepare_success(l_net, l_links);
+        return 0;
+    }*/
     // dynamic links from http balancer request
-    int a_required_links_count = dap_link_manager_needed_links_count(a_net->pub.id.uint64);
     struct balancer_link_request *l_balancer_request = NULL;
-    DAP_NEW_Z_RET_VAL(l_balancer_request, struct balancer_link_request, false, NULL);
+    DAP_NEW_Z_RET_VAL(l_balancer_request, struct balancer_link_request, -4, NULL);
     *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()
+        .info = s_balancer_link_from_cfg(l_net),
+        .net = l_net,
+        .worker = dap_events_worker_get_auto(),
+        .links_requested_count = l_required_links_count
     };
-    if (!l_balancer_request->link_info) {
-        log_it(L_ERROR, "Can't process balancer link %s request", PVT(a_net)->balancer_http ? "HTTP" : "DNS");
+    if (!l_balancer_request->info) {
+        log_it(L_ERROR, "Can't process balancer link %s request", PVT(l_net)->balancer_type == 0 ? "HTTP" : "DNS");
         DAP_DELETE(l_balancer_request);
-        return false;
+        return -5;
     }
     log_it(L_DEBUG, "Start balancer %s request to %s",
-           PVT(a_net)->balancer_http ? "HTTP" : "DNS", l_balancer_request->link_info->ext_host);
+           PVT(l_net)->balancer_type == 0 ? "HTTP" : "DNS", l_balancer_request->info->addr);
     
     int ret;
-    if (PVT(a_net)->balancer_http) {
+    if (PVT(l_net)->balancer_type == 0) {
         char *l_request = dap_strdup_printf("%s/%s?version=%d,method=r,needlink=%d,net=%s",
                                                 DAP_UPLINK_PATH_BALANCER,
                                                 DAP_BALANCER_URI_HASH,
                                                 DAP_BALANCER_PROTOCOL_VERSION,
-                                                a_required_links_count * 2,
-                                                a_net->pub.name);
+                                                (int)l_required_links_count,
+                                                l_net->pub.name);
         ret = dap_client_http_request(l_balancer_request->worker,
-                                                l_balancer_request->link_info->ext_host,
-                                                l_balancer_request->link_info->ext_port,
+                                                l_balancer_request->info->addr,
+                                                l_balancer_request->info->port,
                                                 "GET",
                                                 "text/text",
                                                 l_request,
                                                 NULL,
                                                 0,
                                                 NULL,
-                                                s_net_http_link_prepare_success,
-                                                s_net_http_link_prepare_error,
+                                                s_http_balancer_link_prepare_success,
+                                                s_http_balancer_link_prepare_error,
                                                 l_balancer_request,
                                                 NULL) == NULL;
         DAP_DELETE(l_request);
     } else {
-        l_balancer_request->link_info->ext_port = DNS_LISTEN_PORT;
+        l_balancer_request->info->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,
+                                                s_dns_balancer_link_prepare_success,
+                                                s_dns_balancer_link_prepare_error,
                                                 l_balancer_request); */ -1;
     }
     if (ret) {
-        log_it(L_ERROR, "Can't process balancer link %s request", PVT(a_net)->balancer_http ? "HTTP" : "DNS");
+        log_it(L_ERROR, "Can't process balancer link %s request", PVT(l_net)->balancer_type == 0 ? "HTTP" : "DNS");
         DAP_DELETE(l_balancer_request);
-        return false;
+        return -6;
     }
-    return true;
+    return 0;
+}
+
+int s_link_manager_fill_net_info(dap_link_t *a_link)
+{
+// sanity check
+    dap_return_val_if_pass(!a_link, -1);
+// func work
+    dap_chain_net_item_t *l_net_item = NULL, *l_tmp = NULL;
+    dap_chain_node_info_t *l_node_info = NULL;
+    HASH_ITER(hh, s_net_items, l_net_item, l_tmp)
+        if ((l_node_info = dap_chain_node_info_read(l_net_item->chain_net, &a_link->addr)))
+            break;
+    if (!l_node_info)
+        return -3;
+    dap_link_manager_link_update(a_link, l_node_info->ext_host, l_node_info->ext_port);
+    DAP_DELETE(l_node_info);
+    return 0;
 }
 
 struct json_object *s_net_states_json_collect(dap_chain_net_t *a_net)
@@ -824,10 +784,6 @@ static bool s_net_states_proc(void *a_arg)
             log_it(L_INFO,"%s.state: NET_STATE_LINKS_ESTABLISHED", l_net->pub.name);
             break;
 
-        case NET_STATE_SYNC_GDB:
-            log_it(L_INFO,"%s.state: NET_STATE_SYNC_GDB", l_net->pub.name);
-            break;
-
         case NET_STATE_SYNC_CHAINS:
             log_it(L_INFO,"%s.state: NET_STATE_SYNC_CHAINS", l_net->pub.name);
             break;
@@ -1664,7 +1620,7 @@ static int s_cli_net(int argc, char **argv, void **reply)
 
         } else if( l_sync_str) {
             json_object *l_jobj_state_machine = json_object_new_object();
-            json_object *l_jobj_requested;
+            json_object *l_jobj_requested = json_object_new_string("SYNC_ALL");
             json_object *l_jobj_current = json_object_new_string(c_net_states[PVT(l_net)->state]);
             if (!l_jobj_state_machine || !l_jobj_current) {
                 json_object_put(l_jobj_state_machine);
@@ -1673,26 +1629,7 @@ static int s_cli_net(int argc, char **argv, void **reply)
                 dap_json_rpc_allocation_error;
                 return DAP_JSON_RPC_ERR_CODE_MEMORY_ALLOCATED;
             }
-
-            if ( strcmp(l_sync_str,"all") == 0 ) {
-                l_jobj_requested = json_object_new_string("SYNC_ALL");
-                dap_chain_net_sync_all(l_net);
-            } else if ( strcmp(l_sync_str,"gdb") == 0) {
-                l_jobj_requested = json_object_new_string("SYNC_GDB");
-                dap_chain_net_sync_gdb(l_net);
-            }  else if ( strcmp(l_sync_str,"chains") == 0) {
-                l_jobj_requested = json_object_new_string("SYNC_CHAINS");
-                // TODO set PVT flag to exclude GDB sync
-                dap_chain_net_sync_chains(l_net);
-
-            } else {
-                json_object_put(l_jobj_return);
-                json_object_put(l_jobj_state_machine);
-                json_object_put(l_jobj_current);
-                dap_json_rpc_error_add(DAP_CHAIN_NET_JSON_RPC_UNDEFINED_PARAMETERS_COMMAND_SYNC, "%s",
-                                       "Subcommand 'sync' requires one of parameters: all, gdb, chains");
-                l_ret = DAP_CHAIN_NET_JSON_RPC_UNDEFINED_PARAMETERS_COMMAND_SYNC;
-            }
+            dap_chain_net_sync(l_net);
             if (!l_jobj_requested) {
                 json_object_put(l_jobj_state_machine);
                 json_object_put(l_jobj_current);
@@ -1991,7 +1928,7 @@ void dap_chain_net_delete(dap_chain_net_t *a_net)
         HASH_DELETE(hh2, s_net_ids, l_net_item);
         DAP_DELETE(l_net_item);
     }
-    DAP_DEL_Z(PVT(a_net)->poa_nodes_addrs);
+    DAP_DEL_Z(PVT(a_net)->authorized_nodes_addrs);
     DAP_DEL_Z(PVT(a_net)->node_info);
     if (a_net->pub.ledger) {
         dap_ledger_purge(a_net->pub.ledger, true);
@@ -2082,72 +2019,92 @@ int s_net_init(const char *a_net_name, uint16_t a_acl_idx)
     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);
 
-    uint16_t l_seed_nodes_addrs_len =0;
-    char **l_seed_nodes_addrs = dap_config_get_array_str( l_cfg , "general" ,"seed_nodes_addrs", &l_seed_nodes_addrs_len);
-    char **l_permamnet_nodes_addrs = dap_config_get_array_str( l_cfg , "general" ,"permanent_nodes_addrs", &l_net_pvt->permanent_links_count);
-    if (l_net_pvt->permanent_links_count)
-        l_net_pvt->permanent_links = DAP_NEW_Z_COUNT(dap_chain_node_addr_t, l_net_pvt->permanent_links_count);
-    char **l_poa_nodes_addrs = dap_config_get_array_str(l_cfg, "general", "seed_nodes_addrs", &l_net_pvt->poa_nodes_count);
-    if (!l_net_pvt->poa_nodes_count) {
-        log_it(L_ERROR, "Can't read seed nodes addresses");
-        dap_chain_net_delete(l_net);
-        dap_config_close(l_cfg);
-        return -15;
-    }
-    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 -4;
+    char **l_permanent_nodes_addrs = dap_config_get_array_str(l_cfg, "general", "permanent_nodes_addrs", &l_net_pvt->permanent_links_count);
+    if (l_net_pvt->permanent_links_count) {
+        l_net_pvt->permanent_links = DAP_NEW_Z_COUNT(dap_link_info_t *, l_net_pvt->permanent_links_count);
+        if (!l_net_pvt->permanent_links) {
+            log_it(L_CRITICAL, "%s", g_error_memory_alloc);
+            dap_chain_net_delete(l_net);
+            dap_config_close(l_cfg);
+            return -4;
+        }
     }
-
-    for (uint16_t i = 0; i < l_net_pvt->poa_nodes_count; ++i) {
+    for (uint16_t i = 0; i < l_net_pvt->permanent_links_count; ++i) {
+        l_net_pvt->permanent_links[i] = DAP_NEW_Z(dap_link_info_t);
+        if (l_net_pvt->permanent_links[i]) {
+            log_it(L_CRITICAL, "%s", g_error_memory_alloc);
+            dap_chain_net_delete(l_net);
+            dap_config_close(l_cfg);
+            return -4;
+        }
+        if (dap_stream_node_addr_from_str(&l_net_pvt->permanent_links[i]->node_addr, l_permanent_nodes_addrs[i])) {
+            log_it(L_ERROR, "Incorrect format of address \"%s\", fix net config and restart node", l_permanent_nodes_addrs[i]);
+            dap_chain_net_delete(l_net);
+            dap_config_close(l_cfg);
+            return -16;
+        }
+    }
+    uint16_t l_permalink_hosts_count = 0;
+    char **l_permanent_links_hosts = dap_config_get_array_str(l_cfg, "general", "seed_nodes_hosts", &l_permalink_hosts_count);
+    for (uint16_t i = 0; i < dap_min(l_permalink_hosts_count, l_net_pvt->permanent_links_count); ++i) {
         uint16_t l_port = 0;
         char l_host[DAP_HOSTADDR_STRLEN + 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]);
+        if (dap_net_parse_hostname(l_permanent_links_hosts[i], l_host, &l_port) || !l_port) {
+            log_it(L_ERROR, "Incorrect format of address \"%s\", fix net config and restart node",
+                            l_permanent_links_hosts[i]);
             dap_chain_net_delete(l_net);
             dap_config_close(l_cfg);
             return -16;
         }
-        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 = DAP_NEW_Z_SIZE(dap_chain_node_info_t, sizeof(dap_chain_node_info_t) + DAP_HOSTADDR_STRLEN + 1);
-            dap_mempcpy(l_net_pvt->node_info, l_net_pvt->seed_nodes_info[i], dap_chain_node_info_get_size(l_net_pvt->seed_nodes_info[i]));
-        }
+        l_net_pvt->permanent_links[i]->uplink_port = l_port;
+        dap_strncpy(l_net_pvt->permanent_links[i]->uplink_addr, l_host, DAP_HOSTADDR_STRLEN);
     }
 
-    for (uint16_t i = 0; i < l_net_pvt->permanent_links_count; ++i) {
+    char **l_authorized_nodes_addrs = dap_config_get_array_str(l_cfg, "general", "authorized_nodes_addrs", &l_net_pvt->authorized_nodes_count);
+    if (!l_net_pvt->authorized_nodes_count)
+        log_it(L_WARNING, "Can't read PoA nodes addresses");
+    else
+        l_net_pvt->authorized_nodes_addrs = DAP_NEW_Z_COUNT(dap_chain_node_addr_t, l_net_pvt->authorized_nodes_count);
+    for (uint16_t i = 0; i < l_net_pvt->authorized_nodes_count; ++i) {
         dap_chain_node_addr_t l_addr;
-        if ( dap_stream_node_addr_from_str(&l_addr, l_permamnet_nodes_addrs[i])) {
-            log_it(L_ERROR, "Incorrect format of address \"%s\", fix net config and restart node", l_poa_nodes_addrs[i]);
+        if (dap_stream_node_addr_from_str(&l_addr, l_authorized_nodes_addrs[i])) {
+            log_it(L_ERROR, "Incorrect format of address \"%s\", fix net config and restart node", l_authorized_nodes_addrs[i]);
+            dap_chain_net_delete(l_net);
+            dap_config_close(l_cfg);
+            return -17;
+        }
+        l_net_pvt->authorized_nodes_addrs[i].uint64 = l_addr.uint64;
+    }
+    char **l_seed_nodes_hosts = dap_config_get_array_str(l_cfg, "general", "seed_nodes_hosts", &l_net_pvt->seed_nodes_count);
+    if (!l_net_pvt->seed_nodes_count)
+         l_seed_nodes_hosts  = dap_config_get_array_str(l_cfg, "general", "bootstrap_hosts", &l_net_pvt->seed_nodes_count);
+    if (!l_net_pvt->seed_nodes_count)
+        log_it(L_WARNING, "Can't read seed nodes addresses, wark with local balancer only");
+    else if (!(l_net_pvt->seed_nodes_info = DAP_NEW_Z_COUNT(struct request_link_info *, l_net_pvt->seed_nodes_count))) {
+        log_it(L_CRITICAL, "%s", g_error_memory_alloc);
+        dap_chain_net_delete(l_net);
+        dap_config_close(l_cfg);
+        return -4;
+    }
+    for (uint16_t i = 0; i < l_net_pvt->seed_nodes_count; ++i) {
+        uint16_t l_port = 0;
+        char l_host[DAP_HOSTADDR_STRLEN + 1] = { '\0' };
+        if (dap_net_parse_hostname(l_seed_nodes_hosts[i], l_host, &l_port) || !l_port) {
+            log_it(L_ERROR, "Incorrect format of address \"%s\", fix net config and restart node",
+                            l_seed_nodes_hosts[i]);
             dap_chain_net_delete(l_net);
             dap_config_close(l_cfg);
             return -16;
         }
-        l_net_pvt->permanent_links[i].uint64 = l_addr.uint64;
+        l_net_pvt->seed_nodes_info[i] = DAP_NEW_Z(struct request_link_info);
+        if (!l_net_pvt->seed_nodes_info[i]) {
+            log_it(L_CRITICAL, "%s", g_error_memory_alloc);
+            dap_chain_net_delete(l_net);
+            dap_config_close(l_cfg);
+            return -4;
+        }
+        l_net_pvt->seed_nodes_info[i]->port = l_port;
+        dap_strncpy(l_net_pvt->seed_nodes_info[i]->addr, l_host, DAP_HOSTADDR_STRLEN);
     }
 
     /* *** Chains init by configs *** */
@@ -2342,7 +2299,6 @@ int s_net_load(dap_chain_net_t *a_net)
     // Do specific role actions post-chain created
     l_net_pvt->state_target = NET_STATE_OFFLINE;
 
-    l_net_pvt->links_static_only = false;
     switch ( l_net_pvt->node_role.enums ) {
         case NODE_ROLE_ROOT_MASTER:{
             // Set to process everything in datum pool
@@ -2357,7 +2313,6 @@ int s_net_load(dap_chain_net_t *a_net)
             dap_chain_t * l_chain = dap_chain_find_by_id(l_net->pub.id,l_chain_id);
             if (l_chain )
                l_chain->is_datum_pool_proc = true;
-            l_net_pvt->links_static_only = true;
             log_it(L_INFO,"Root node role established");
         } break;
         case NODE_ROLE_CELL_MASTER:
@@ -2384,12 +2339,10 @@ int s_net_load(dap_chain_net_t *a_net)
             log_it(L_INFO,"Light node role established");
 
     }
-    if (!l_net_pvt->links_static_only)
-        l_net_pvt->links_static_only = dap_config_get_item_bool_default(l_cfg, "general", "links_static_only", true);
     
     l_net_pvt->load_mode = false;
 
-    l_net_pvt->balancer_http = !dap_config_get_item_bool_default(l_cfg, "general", "use_dns_links", false);
+    l_net_pvt->balancer_type = dap_config_get_item_bool_default(l_cfg, "general", "use_dns_links", false);
 
     // Init GlobalDB clusters for mempool, service and nodes (with aliases)
     char *l_gdb_groups_mask = NULL;
@@ -2398,7 +2351,7 @@ int s_net_load(dap_chain_net_t *a_net)
         l_gdb_groups_mask = dap_strdup_printf("%s.chain-%s.mempool", l_net->pub.gdb_groups_prefix, l_chain->name);
         dap_global_db_cluster_t *l_cluster = dap_global_db_cluster_add(
                                                     dap_global_db_instance_get_default(),
-                                                    l_net->pub.name, dap_cluster_guuid_compose(l_net->pub.id.uint64, 0),
+                                                    l_net->pub.name, dap_guuid_compose(l_net->pub.id.uint64, 0),
                                                     l_gdb_groups_mask, DAP_CHAIN_NET_MEMPOOL_TTL, true,
                                                     DAP_GDB_MEMBER_ROLE_USER,
                                                     DAP_CLUSTER_ROLE_EMBEDDED);
@@ -2406,7 +2359,7 @@ int s_net_load(dap_chain_net_t *a_net)
             log_it(L_ERROR, "Can't initialize mempool cluster for network %s", l_net->pub.name);
             return -1;
         }
-        dap_chain_net_add_poa_certs_to_cluster(l_net, l_cluster);
+        dap_chain_net_add_auth_nodes_to_cluster(l_net, l_cluster);
         DAP_DELETE(l_gdb_groups_mask);
         if (l_net->pub.chains == l_chain)   // Pointer for first mempool cluster in global double-linked list of clusters
             l_net_pvt->mempool_clusters = l_cluster;
@@ -2414,7 +2367,7 @@ int s_net_load(dap_chain_net_t *a_net)
     // Service orders cluster
     l_gdb_groups_mask = dap_strdup_printf("%s.service.orders", l_net->pub.gdb_groups_prefix);
     l_net_pvt->orders_cluster = dap_global_db_cluster_add(dap_global_db_instance_get_default(),
-                                                          l_net->pub.name, dap_cluster_guuid_compose(l_net->pub.id.uint64, 0),
+                                                          l_net->pub.name, dap_guuid_compose(l_net->pub.id.uint64, 0),
                                                           l_gdb_groups_mask, 0, true,
                                                           DAP_GDB_MEMBER_ROLE_GUEST,
                                                           DAP_CLUSTER_ROLE_EMBEDDED);
@@ -2422,14 +2375,14 @@ int s_net_load(dap_chain_net_t *a_net)
         log_it(L_ERROR, "Can't initialize orders cluster for network %s", l_net->pub.name);
         return -1;
     }
-    dap_chain_net_add_poa_certs_to_cluster(l_net, l_net_pvt->orders_cluster);
+    dap_chain_net_add_auth_nodes_to_cluster(l_net, l_net_pvt->orders_cluster);
     DAP_DELETE(l_gdb_groups_mask);
     // Nodes and its aliases cluster
     l_net->pub.gdb_nodes = dap_strdup_printf("%s.nodes",l_net->pub.gdb_groups_prefix);
     l_net->pub.gdb_nodes_aliases = dap_strdup_printf("%s.nodes.aliases",l_net->pub.gdb_groups_prefix);
     l_gdb_groups_mask = dap_strdup_printf("%s.nodes*", l_net->pub.gdb_groups_prefix);
     l_net_pvt->nodes_cluster = dap_global_db_cluster_add(dap_global_db_instance_get_default(),
-                                                         l_net->pub.name, dap_cluster_guuid_compose(l_net->pub.id.uint64, 0),
+                                                         l_net->pub.name, dap_guuid_compose(l_net->pub.id.uint64, 0),
                                                          l_gdb_groups_mask, 0, true,
                                                          DAP_GDB_MEMBER_ROLE_GUEST,
                                                          DAP_CLUSTER_ROLE_EMBEDDED);
@@ -2437,10 +2390,15 @@ int s_net_load(dap_chain_net_t *a_net)
         log_it(L_ERROR, "Can't initialize nodes cluster for network %s", l_net->pub.name);
         return -1;
     }
-    dap_chain_net_add_poa_certs_to_cluster(l_net, l_net_pvt->nodes_cluster);
+    dap_chain_net_add_auth_nodes_to_cluster(l_net, l_net_pvt->nodes_cluster);
     dap_chain_net_add_nodelist_notify_callback(l_net, s_nodelist_change_notify, l_net);
     DAP_DELETE(l_gdb_groups_mask);
 
+    if (dap_link_manager_add_net(l_net->pub.id.uint64, l_net_pvt->nodes_cluster->links_cluster,
+                                dap_config_get_item_uint16_default(l_cfg, "general", "links_required", 3))) {
+        log_it(L_WARNING, "Can't add net %s to link manager", l_net->pub.name);
+    }
+
     DL_FOREACH(l_net->pub.chains, l_chain)
         if (l_chain->callback_created)
             l_chain->callback_created(l_chain, l_cfg);
@@ -2504,9 +2462,6 @@ int s_net_load(dap_chain_net_t *a_net)
     l_net_pvt->sync_context.sync_idle_time = dap_config_get_item_uint32_default(g_config, "chain", "sync_idle_time", 60);
     dap_proc_thread_timer_add(NULL, s_sync_timer_callback, l_net, 1000);
 
-    if(dap_link_manager_add_net(l_net->pub.id.uint64, l_net_pvt->nodes_cluster->links_cluster)) {
-        log_it(L_WARNING, "Can't add net %s to link manager", l_net->pub.name);
-    }
     log_it(L_INFO, "Chain network \"%s\" initialized",l_net->pub.name);
     dap_config_close(l_cfg);
 
@@ -2713,11 +2668,11 @@ void dap_chain_net_srv_order_add_notify_callback(dap_chain_net_t *a_net, dap_sto
     dap_global_db_cluster_add_notify_callback(PVT(a_net)->orders_cluster, a_callback, a_cb_arg);
 }
 
-int dap_chain_net_add_poa_certs_to_cluster(dap_chain_net_t *a_net, dap_global_db_cluster_t *a_cluster)
+int dap_chain_net_add_auth_nodes_to_cluster(dap_chain_net_t *a_net, dap_global_db_cluster_t *a_cluster)
 {
     dap_return_val_if_fail(a_net && a_cluster, -1);
-    for (uint16_t i = 0; i < PVT(a_net)->poa_nodes_count; i++)
-        dap_global_db_cluster_member_add(a_cluster, PVT(a_net)->poa_nodes_addrs + i, DAP_GDB_MEMBER_ROLE_ROOT);
+    for (uint16_t i = 0; i < PVT(a_net)->authorized_nodes_count; i++)
+        dap_global_db_cluster_member_add(a_cluster, PVT(a_net)->authorized_nodes_addrs + i, DAP_GDB_MEMBER_ROLE_ROOT);
     return 0;
 }
 
@@ -2941,51 +2896,6 @@ 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->cell_id: 0;
 }
 
-/**
- * Get remote nodes list (list of dap_chain_node_addr_t struct)
- */
-dap_list_t* dap_chain_net_get_node_list(dap_chain_net_t *l_net)
-{
-    dap_list_t *l_node_list = NULL;
-
-    // get nodes list from global_db
-    dap_global_db_obj_t *l_objs = NULL;
-    size_t l_nodes_count = 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_list;
-    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;
-        dap_chain_node_addr_t *l_address = DAP_NEW(dap_chain_node_addr_t);
-        if (!l_address) {
-        log_it(L_CRITICAL, "Memory allocation error");
-            return NULL;
-        }
-        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);
-    return l_node_list;
-}
-
-/**
- * Get nodes list from config file (list of dap_chain_node_addr_t struct)
- */
-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_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
@@ -3325,44 +3235,10 @@ 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->ext_port ) {
-        dap_chain_net_node_list_request(a_net, NULL, l_net_pvt->node_info->ext_port, false, 'a');
+        dap_chain_net_node_list_request(a_net, 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);
     }
 }
-
-void s_link_manager_link_request(uint64_t a_net_id)
-{
-// sanity check
-    dap_chain_net_t *l_net = dap_chain_net_by_id((dap_chain_net_id_t){.uint64 = a_net_id});
-    dap_return_if_pass(!l_net);
-// func work
-    s_new_balancer_link_request(l_net);
-}
-
-int dap_chain_net_link_manager_init()
-{
-    return dap_link_manager_init(&s_link_manager_callbacks);
-}
-
-int s_link_manager_fill_net_info(dap_link_t *a_link)
-{
-// sanity check
-    dap_return_val_if_pass(!a_link, -1);
-// func work
-    int l_ret = 0;
-    dap_chain_net_item_t *l_net_item = NULL, *l_tmp = NULL;
-    dap_chain_node_info_t *l_node_info = NULL;
-    HASH_ITER(hh, s_net_items, l_net_item, l_tmp) {
-        if ((l_node_info = dap_chain_node_info_read(l_net_item->chain_net, &a_link->client->link_info.node_addr)))
-            break;
-    }
-    if (!l_node_info) {
-        return -3;
-    }
-    dap_link_manager_link_update(a_link, l_node_info->ext_host, l_node_info->ext_port, false);
-    DAP_DELETE(l_node_info);
-    return l_ret;
-}
diff --git a/modules/net/dap_chain_net_balancer.c b/modules/net/dap_chain_net_balancer.c
index 36c5c03535f3de7cfe74fd0dc46c62f6cdc57a10..a1427d078fcb41ab5f641f53f1a67f94b739a037 100644
--- a/modules/net/dap_chain_net_balancer.c
+++ b/modules/net/dap_chain_net_balancer.c
@@ -30,8 +30,8 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 
 #define LOG_TAG "dap_chain_net_balancer"
 
-static_assert(sizeof(dap_chain_net_node_balancer_t) + sizeof(dap_chain_node_info_old_t) < DAP_BALANCER_MAX_REPLY_SIZE, "DAP_BALANCER_MAX_REPLY_SIZE cannot accommodate information minimum about 1 link");
-static const size_t s_max_links_responce_count = (DAP_BALANCER_MAX_REPLY_SIZE - sizeof(dap_chain_net_node_balancer_t)) / sizeof(dap_chain_node_info_old_t);
+static_assert(sizeof(dap_chain_net_links_t) + sizeof(dap_chain_node_info_old_t) < DAP_BALANCER_MAX_REPLY_SIZE, "DAP_BALANCER_MAX_REPLY_SIZE cannot accommodate information minimum about 1 link");
+static const size_t s_max_links_response_count = (DAP_BALANCER_MAX_REPLY_SIZE - sizeof(dap_chain_net_links_t)) / sizeof(dap_chain_node_info_old_t);
 
 int dap_chain_net_balancer_handshake(dap_chain_node_info_t *a_node_info, dap_chain_net_t *a_net)
 {
@@ -57,10 +57,89 @@ int dap_chain_net_balancer_handshake(dap_chain_node_info_t *a_node_info, dap_cha
         }
     }
     return l_blocks_events;
-}*/
+}
+
+dap_link_info_t *dap_link_manager_get_net_links_info_list(uint64_t a_net_id, size_t *a_count)
+{
+// sanity check
+    dap_managed_net_t *l_net = s_find_net_by_id(a_net_id);
+    dap_return_val_if_pass(!l_net, 0);
+// func work
+    size_t l_count = 0;
+    dap_link_info_t *l_ret = NULL;
+    dap_stream_node_addr_t *l_links_addrs = dap_cluster_get_all_members_addrs((dap_cluster_t *)l_net->link_clusters->data, &l_count);
+    if (!l_links_addrs || !l_count) {
+        return NULL;
+    }
+    DAP_NEW_Z_COUNT_RET_VAL(l_ret, dap_link_info_t, l_count, NULL, l_links_addrs);
+    pthread_rwlock_rdlock(&s_link_manager->links_lock);
+        for (int i = l_count - 1; i >= 0; --i) {
+            dap_link_t *l_link = NULL;
+            HASH_FIND(hh, s_link_manager->links, l_links_addrs + i, sizeof(l_links_addrs[i]), l_link);
+            if (!l_link || l_link->uplink.state != LINK_STATE_ESTABLISHED) {
+                --l_count;
+                continue;
+            }
+            dap_mempcpy(l_ret + i, &l_link->uplink.client->link_info, sizeof(dap_link_info_t));
+        }
+    pthread_rwlock_unlock(&s_link_manager->links_lock);
+    DAP_DELETE(l_links_addrs);
+    if (!l_count) {
+        DAP_DELETE(l_ret);
+        return NULL;
+    }
+    if (a_count)
+        *a_count = l_count;
+    return l_ret;
+}
+*/
 
+dap_link_info_t *s_get_links_info_list(dap_chain_net_t *a_net, size_t *a_count, bool a_external_call)
+{
+    static _Thread_local dap_global_db_driver_hash_t l_last_read_hash = {};
+    assert(a_net && a_count);
+    size_t l_count = *a_count;
+    if (!l_count) {
+        l_count = dap_global_db_driver_count(a_net->pub.gdb_nodes, c_dap_global_db_driver_hash_blank);
+        if (!l_count)
+            return NULL;
+    }
+    dap_store_obj_t *l_objs = dap_global_db_driver_cond_read(a_net->pub.gdb_nodes, l_last_read_hash, &l_count);
+    if (!l_objs || !l_count) {
+        l_last_read_hash = c_dap_global_db_driver_hash_blank;
+        return a_external_call ? s_get_links_info_list(a_net, a_count, false) : NULL;
+    }
+    l_last_read_hash = dap_global_db_driver_hash_get(l_objs + l_count - 1);
+    if (dap_global_db_driver_hash_is_blank(&l_last_read_hash))
+        l_count--;
+    dap_link_info_t *l_ret = NULL;
+    DAP_NEW_Z_COUNT_RET_VAL(l_ret, dap_link_info_t, l_count, NULL, NULL);
+    for (size_t i = 0; i < l_count; i++) {
+        dap_link_info_t *l_cur_info = l_ret + i;
+        dap_chain_node_info_t *l_db_info = (dap_chain_node_info_t *)(l_objs + i)->value;
+        l_cur_info->node_addr = l_db_info->address;
+        l_cur_info->uplink_port = l_db_info->ext_port;
+        dap_strncpy(l_cur_info->uplink_addr, l_db_info->ext_host, dap_min(l_db_info->ext_host_len, DAP_HOSTADDR_STRLEN));
+    }
+    dap_store_obj_free(l_objs, l_count);
+    if (a_external_call && l_count < *a_count) {
+        size_t l_total_count = dap_global_db_driver_count(a_net->pub.gdb_nodes, c_dap_global_db_driver_hash_blank);
+        if (l_count < l_total_count) {
+            size_t l_tail_count = dap_min(l_total_count, *a_count) - l_count;
+            dap_link_info_t *l_tail = s_get_links_info_list(a_net, &l_tail_count, false);
+            if (l_tail && l_tail_count) {
+                l_ret = DAP_REALLOC(l_ret, sizeof(dap_link_info_t) * (l_count + l_tail_count));
+                memcpy(l_ret + sizeof(dap_link_info_t) * l_count, l_tail, sizeof(dap_link_info_t) * l_tail_count);
+                l_count += l_tail_count;
+                DAP_DELETE(l_tail);
+            }
+        }
+    }
+    *a_count = l_count;
+    return l_ret;
+}
 
-dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node(const char *a_net_name, uint16_t a_links_need)
+dap_chain_net_links_t *dap_chain_net_balancer_get_node(const char *a_net_name, uint16_t a_links_need)
 {
 // sanity check
     dap_return_val_if_pass(!a_net_name || !a_links_need, NULL);
@@ -70,16 +149,16 @@ dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node(const char *a_net
         return NULL;
     }
 // preparing
-    size_t l_node_num_prep = 0;
-    dap_link_info_t *l_links_info = dap_link_manager_get_net_links_info_list(l_net->pub.id.uint64, &l_node_num_prep);
+    size_t l_node_num_prep = a_links_need;
+    dap_link_info_t *l_links_info = s_get_links_info_list(l_net, &l_node_num_prep, true);
     if (!l_links_info || !l_node_num_prep){        
-        log_it(L_ERROR, "Active links list in net %s is empty", a_net_name);
+        log_it(L_ERROR, "Active node list in net %s is empty", a_net_name);
         return NULL;
     }
-    size_t l_node_num_send = dap_min(s_max_links_responce_count, dap_min(l_node_num_prep, a_links_need));
+    size_t l_node_num_send = dap_min(s_max_links_response_count, l_node_num_prep);
 // memory alloc
-    dap_chain_net_node_balancer_t *l_node_list_res = NULL;
-    DAP_NEW_Z_SIZE_RET_VAL(l_node_list_res, dap_chain_net_node_balancer_t, sizeof(dap_chain_net_node_balancer_t) + l_node_num_send * sizeof(dap_link_info_t), NULL, l_links_info);
+    dap_chain_net_links_t *l_node_list_res = NULL;
+    DAP_NEW_Z_SIZE_RET_VAL(l_node_list_res, dap_chain_net_links_t, sizeof(dap_chain_net_links_t) + l_node_num_send * sizeof(dap_link_info_t), NULL, l_links_info);
     dap_link_info_t *l_node_info = (dap_link_info_t *)l_node_list_res->nodes_info;
 // func work
     // if we can't send full list, choose random, not always firsts
@@ -95,7 +174,7 @@ dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node(const char *a_net
 }
 
 
-dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node_old(const char *a_net_name, uint16_t a_links_need)
+dap_chain_net_links_t *dap_chain_net_balancer_get_node_old(const char *a_net_name, uint16_t a_links_need)
 {
 // sanity check
     dap_return_val_if_pass(!a_net_name || !a_links_need, NULL);
@@ -105,16 +184,16 @@ dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node_old(const char *a
         return NULL;
     }
 // preparing
-    size_t l_node_num_prep = 0;
-    dap_link_info_t *l_links_info = dap_link_manager_get_net_links_info_list(l_net->pub.id.uint64, &l_node_num_prep);
+    size_t l_node_num_prep = a_links_need;
+    dap_link_info_t *l_links_info = s_get_links_info_list(l_net, &l_node_num_prep, true);
     if (!l_links_info || !l_node_num_prep){        
-        log_it(L_ERROR, "Active links list in net %s is empty", a_net_name);
+        log_it(L_ERROR, "Active node list in net %s is empty", a_net_name);
         return NULL;
     }
-    size_t l_node_num_send = dap_min(s_max_links_responce_count, dap_min(l_node_num_prep, a_links_need));
+    size_t l_node_num_send = dap_min(s_max_links_response_count, l_node_num_prep);
 // memory alloc
-    dap_chain_net_node_balancer_t *l_node_list_res = NULL;
-    DAP_NEW_Z_SIZE_RET_VAL(l_node_list_res, dap_chain_net_node_balancer_t, sizeof(dap_chain_net_node_balancer_t) + l_node_num_send * sizeof(dap_chain_node_info_old_t), NULL, l_links_info);
+    dap_chain_net_links_t *l_node_list_res = NULL;
+    DAP_NEW_Z_SIZE_RET_VAL(l_node_list_res, dap_chain_net_links_t, sizeof(dap_chain_net_links_t) + l_node_num_send * sizeof(dap_chain_node_info_old_t), NULL, l_links_info);
     dap_chain_node_info_old_t *l_node_info = (dap_chain_node_info_old_t *)l_node_list_res->nodes_info;
 // func work
     // if we can't send full list, choose random, not always firsts
@@ -137,23 +216,9 @@ dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node_old(const char *a
     return l_node_list_res;
 }
 
-dap_chain_net_node_balancer_t *s_balancer_issue_link(const char *a_net_name, uint16_t a_links_need, int a_protocol_version)
+DAP_STATIC_INLINE dap_chain_net_links_t *s_balancer_issue_link(const char *a_net_name, uint16_t a_links_need, int a_protocol_version)
 {
-    dap_chain_net_t *l_net = dap_chain_net_by_name(a_net_name);
-    dap_chain_net_node_balancer_t *l_link_full_node_list = NULL;
-    if (a_protocol_version == 1) {
-        l_link_full_node_list = dap_chain_net_balancer_get_node_old(a_net_name, a_links_need);
-    } else {
-        l_link_full_node_list = dap_chain_net_balancer_get_node(a_net_name, a_links_need);
-    }
-    if (!l_link_full_node_list)
-        return NULL;
-    dap_link_info_t *l_node_info = (dap_link_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",
-                (l_node_info + i)->uplink_addr);
-    }
-    return l_link_full_node_list;
+    return a_protocol_version == 1 ? dap_chain_net_balancer_get_node_old(a_net_name, a_links_need) : dap_chain_net_balancer_get_node(a_net_name, a_links_need);
 }
 
 void dap_chain_net_balancer_http_issue_link(dap_http_simple_t *a_http_simple, void *a_arg)
@@ -189,7 +254,7 @@ void dap_chain_net_balancer_http_issue_link(dap_http_simple_t *a_http_simple, vo
     strncpy(l_net_name, l_net_str, 127);
     links_need = links_need ? links_need : 5;
     log_it(L_DEBUG, "HTTP balancer parser retrieve netname %s", l_net_name);
-    dap_chain_net_node_balancer_t *l_link_full_node_list = s_balancer_issue_link(l_net_name,links_need, l_protocol_version);
+    dap_chain_net_links_t *l_link_full_node_list = s_balancer_issue_link(l_net_name, links_need, l_protocol_version);
     if (!l_link_full_node_list) {
         log_it(L_WARNING, "Can't issue link for network %s, no acceptable links found", l_net_name);
         *l_return_code = Http_Status_NotFound;
@@ -213,7 +278,7 @@ void dap_chain_net_balancer_http_issue_link(dap_http_simple_t *a_http_simple, vo
 dap_link_info_t *dap_chain_net_balancer_dns_issue_link(char *a_str)
 {
     log_it(L_DEBUG, "DNS balancer parser retrieve netname %s", a_str);
-    dap_chain_net_node_balancer_t *l_balancer_reply = s_balancer_issue_link(a_str, 1, DAP_BALANCER_PROTOCOL_VERSION);
+    dap_chain_net_links_t *l_balancer_reply = s_balancer_issue_link(a_str, 1, DAP_BALANCER_PROTOCOL_VERSION);
     if (!l_balancer_reply || !l_balancer_reply->count_node) {
         DAP_DEL_Z(l_balancer_reply);
         return NULL;
diff --git a/modules/net/dap_chain_net_node_list.c b/modules/net/dap_chain_net_node_list.c
index 8e5a61dbc4e29a37949eb41db997c803fd9f0f09..0fbe622b3d04e29dcaa993e4396609cb66edc39f 100644
--- a/modules/net/dap_chain_net_node_list.c
+++ b/modules/net/dap_chain_net_node_list.c
@@ -250,35 +250,11 @@ static int s_cb_node_addr_compare(dap_list_t *a_list_elem, dap_list_t *a_addr_el
     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)
+int dap_chain_net_node_list_request(dap_chain_net_t *a_net, uint16_t a_port, bool a_sync, char a_cmd)
 {
     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");
-    }
-    
-    dap_chain_node_addr_t l_node_addr_cur = {
-        .uint64 = dap_chain_net_get_cur_addr_int(a_net)
-    };
-
-    /*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");
@@ -287,10 +263,14 @@ int dap_chain_net_node_list_request (dap_chain_net_t *a_net, UNUSED_ARG const ch
 
     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 );
+                                         g_node_addr.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];
+    size_t l_seeds_count = 0;
+    dap_stream_node_addr_t *l_seeds_addrs = dap_chain_net_get_authorized_nodes(a_net, &l_seeds_count);
+    for (size_t i = 0; i < l_seeds_count; ++i) {
+        dap_chain_node_info_t *l_remote = dap_chain_node_info_read(a_net, l_seeds_addrs + i);
+        if (!l_remote)
+            continue;
         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,
@@ -298,6 +278,7 @@ int dap_chain_net_node_list_request (dap_chain_net_t *a_net, UNUSED_ARG const ch
         {
             l_ret = a_sync ? dap_chain_net_node_list_wait(l_link_node_request, 8000) : ADD_OK;
         }
+        DAP_DELETE(l_remote);
         if (l_ret == ADD_OK || l_ret == ERR_EXISTS || l_ret == DELETED_OK)
             break;
         else {
@@ -322,6 +303,7 @@ int dap_chain_net_node_list_request (dap_chain_net_t *a_net, UNUSED_ARG const ch
         }
     }
     DAP_DELETE(l_request);
+    DAP_DELETE(l_seeds_addrs);
     s_node_list_request_deinit(l_link_node_request);
     return l_ret;
 }
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index a85fe65d9adbae57d5b8c4eaf270ac6c2115402a..d25d1a846489caea6fe78aa373a087fbb3af6fbc 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -79,6 +79,7 @@
 #include "dap_chain_node_ping.h"
 #include "dap_chain_net_srv.h"
 #include "dap_chain_net_tx.h"
+#include "dap_chain_net_balancer.h"
 #include "dap_chain_block.h"
 #include "dap_chain_cs_blocks.h"
 
@@ -888,7 +889,7 @@ static dap_tsd_t* s_chain_node_cli_com_node_create_tsd_addr(char **a_argv, int a
 int com_node(int a_argc, char ** a_argv, void **a_str_reply)
 {
     enum {
-        CMD_NONE, CMD_ADD, CMD_DEL, CMD_ALIAS, CMD_HANDSHAKE, CMD_CONNECT, CMD_DUMP, CMD_CONNECTIONS, CMD_BALANCER,
+        CMD_NONE, CMD_ADD, CMD_DEL, CMD_ALIAS, CMD_HANDSHAKE, CMD_CONNECT, CMD_LIST, CMD_DUMP, CMD_CONNECTIONS, CMD_BALANCER,
         CMD_BAN, CMD_UNBAN, CMD_BANLIST
     };
     int arg_index = 1;
@@ -908,6 +909,9 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
     else if(dap_cli_server_cmd_find_option_val(a_argv, arg_index, dap_min(a_argc, arg_index + 1), "alias", NULL)) {
         cmd_num = CMD_ALIAS;
     }
+    else if(dap_cli_server_cmd_find_option_val(a_argv, arg_index, dap_min(a_argc, arg_index + 1), "list", NULL)) {
+        cmd_num = CMD_LIST;
+    }
     else if(dap_cli_server_cmd_find_option_val(a_argv, arg_index, dap_min(a_argc, arg_index + 1), "dump", NULL)) {
         cmd_num = CMD_DUMP;
     }
@@ -955,16 +959,18 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
 
     //TODO need to rework with new node info / alias /links concept
 
-    if(l_addr_str) {
-        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));
+    if (l_addr_str) {
+        if (dap_chain_node_addr_from_str(&l_node_info->address, l_addr_str)) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't parse node address %s", l_addr_str);
+            return -5;
         }
-        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->ext_port = l_node_port;
+    if (l_port_str) {
+        dap_digit_from_string(l_port_str, &l_node_info->ext_port, sizeof(uint16_t));
+        if (!l_node_info->ext_port) {
+            dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't parse host port %s", l_port_str);
+            return -4;
+        }
     }
     if (l_cell_str) {
         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);
@@ -974,53 +980,69 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
             dap_digit_from_string(l_link_str, l_link.raw, sizeof(l_link.raw));
         }
     }
-    int l_ret =0;
     switch (cmd_num)
     {    
     case CMD_ADD: {
-        /*if(!l_port_str) {
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "node requires parameter -port");
-            return -1;
-        }
-        l_node_info->ext_host_len = dap_strncpy(l_node_info->ext_host, l_hostname, DAP_HOSTADDR_STRLEN) - 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");
-                return 0;
+        if (l_addr_str && dap_chain_net_is_my_node_authorized(l_net)) {
+            // We're in authorized list, add directly
+            uint16_t l_port = 0;
+            if (dap_net_parse_hostname(l_hostname, l_node_info->ext_host, &l_port)) {
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't parse host string %s", l_hostname);
+                return -6;
             }
-            dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't add node address to node list");
-            return -3;
-        }*/
+            if (!l_node_info->ext_port) {
+                if (l_port)
+                    l_node_info->ext_port = l_port;
+                else {
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Host port is absent");
+                    return -7;
+                }
+            }
+            l_node_info->ext_host_len = dap_strlen(l_node_info->ext_host);
+            int l_res = dap_chain_node_info_save(l_net, l_node_info);
+            if (l_res)
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't add node %s, error %d", l_addr_str, l_res);
+            else
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Successfully added node %s", l_addr_str);
+            return l_res;
+        }
         // Synchronous request, wait for reply
-        int l_res = dap_chain_net_node_list_request(l_net, NULL,
+        int l_res = dap_chain_net_node_list_request(l_net,
             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 1: dap_cli_server_cmd_set_reply_text(a_str_reply, "Successfully added"); break;
+            case 1: dap_cli_server_cmd_set_reply_text(a_str_reply, "Successfully added"); return 0;
             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 3: dap_cli_server_cmd_set_reply_text(a_str_reply, "Didn't add your address 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;
+        return l_res;
     }
         //break;
-    case CMD_DEL:
+    case CMD_DEL: {
         // handler of command 'node del'
-    {
-        int l_res = dap_chain_net_node_list_request(l_net, NULL, 0, true, 'r');
+        if (l_addr_str && dap_chain_net_is_my_node_authorized(l_net)) {
+            int l_res = dap_chain_node_info_del(l_net, l_node_info);
+            if (l_res)
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't delete node %s, error %d", l_addr_str, l_res);
+            else
+                dap_cli_server_cmd_set_reply_text(a_str_reply, "Successfully deleted node %s", l_addr_str);
+            return l_res;
+        }
+        // Synchronous request, wait for reply
+        int l_res = dap_chain_net_node_list_request(l_net, 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;
+            case 8:  dap_cli_server_cmd_set_reply_text(a_str_reply, "Sucessfully deleted"); return 0;
+            default: dap_cli_server_cmd_set_reply_text(a_str_reply, "Can't process request, error %d", l_res); return l_res;
         }
-        return l_ret;
     }
 
+    case CMD_LIST:
     case CMD_DUMP: {
         // handler of command 'node dump'
         bool l_is_full = dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-full", NULL);
@@ -1285,11 +1307,11 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
             }
             *a_str_reply = dap_cluster_get_links_info(l_links_cluster);
         } else {
-            const char *l_guuid_str;
+            const char *l_guuid_str = NULL;
             dap_cluster_t *l_cluster = NULL;
             dap_cli_server_cmd_find_option_val(a_argv, arg_index, a_argc, "-cluster", &l_guuid_str);
             if (l_guuid_str) {
-                dap_guuid_t l_guuid = { .raw = dap_uint128_from_hex_str(l_guuid_str) };
+                dap_guuid_t l_guuid = dap_guuid_from_hex_str(l_guuid_str);
                 l_cluster = dap_cluster_find(l_guuid);
                 if (!l_cluster) {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Not found cluster with ID %s", l_guuid_str);
@@ -1432,19 +1454,19 @@ int com_node(int a_argc, char ** a_argv, void **a_str_reply)
 
     case CMD_BALANCER: {
         //balancer link list
-        size_t l_node_num = 0;
-        dap_link_info_t *l_links_info_list = dap_link_manager_get_net_links_info_list(l_net->pub.id.uint64, &l_node_num);
-        dap_string_t *l_string_balanc = dap_string_new("\n");
-        dap_string_append_printf(l_string_balanc, "Got %d records\n", (uint16_t)l_node_num);
-        for(size_t i = 0; i < l_node_num; ++i) {
-            dap_string_append_printf(l_string_balanc, NODE_ADDR_FP_STR"    %-20s%u\n",
-                                     NODE_ADDR_FP_ARGS_S(l_links_info_list[i].node_addr),
-                                     l_links_info_list[i].uplink_addr,
-                                     /*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);
-        dap_string_free(l_string_balanc, true);
+        dap_chain_net_links_t *l_links_info_list = dap_chain_net_balancer_get_node(l_net->pub.name, 0);
+        dap_string_t *l_links_str = dap_string_new(l_links_info_list ? "" : "Empty");
+        uint64_t l_node_num = l_links_info_list ? l_links_info_list->count_node : 0;
+        for (uint64_t i = 0; i < l_node_num; ++i) {
+            dap_link_info_t *l_link_info = (dap_link_info_t *)l_links_info_list->nodes_info + i;
+            dap_string_append_printf(l_links_str, NODE_ADDR_FP_STR"    %-20s\n",
+                                     NODE_ADDR_FP_ARGS_S(l_link_info->node_addr),
+                                     l_link_info->uplink_addr);
+                                     /*l_node_link->info.links_number);*/
+        }
+        dap_cli_server_cmd_set_reply_text(a_str_reply, "Balancer link list for total %" DAP_UINT64_FORMAT_U " records:\n %s \n",
+                                          l_node_num, l_links_str->str);
+        dap_string_free(l_links_str, true);
         DAP_DEL_Z(l_links_info_list);
     } break;
 
diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c
index 9caed1f5bce3e71cd16115b27153fa84027e9cde..33decfe0cbd3d51cb333f5de4654b7b213f8c399 100644
--- a/modules/net/dap_chain_node_client.c
+++ b/modules/net/dap_chain_node_client.c
@@ -82,9 +82,6 @@ static void s_ch_chain_callback_notify_packet_in(dap_chain_ch_t* a_ch_chain, uin
         dap_chain_ch_pkt_t *a_pkt, size_t a_pkt_data_size,
         void * a_arg);
 
-bool s_stream_ch_chain_debug_more = false;
-uint32_t s_timer_update_states = 600;
-
 #ifdef DAP_OS_WINDOWS
 #define dap_cond_signal(x) SetEvent(x)
 #else
@@ -97,8 +94,6 @@ uint32_t s_timer_update_states = 600;
  */
 int dap_chain_node_client_init()
 {
-    s_stream_ch_chain_debug_more = dap_config_get_item_bool_default(g_config, "stream_ch_chain", "debug_more", false);
-    s_timer_update_states = dap_config_get_item_uint32_default(g_config, "node_client", "timer_update_states", s_timer_update_states);
     return 0;
 }
 
@@ -110,21 +105,6 @@ void dap_chain_node_client_deinit()
     dap_client_deinit();
 }
 
-static bool s_timer_node_reconnect(void *a_arg)
-{
-    if (!a_arg)
-        return false;
-    dap_chain_node_client_t *l_me = a_arg;
-    if (l_me->keep_connection && l_me->state == NODE_CLIENT_STATE_DISCONNECTED) {
-        if (dap_client_get_stage(l_me->client) == STAGE_BEGIN) {
-            log_it(L_INFO, "Reconnecting node client with peer "NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(l_me->remote_node_addr));
-            l_me->state = NODE_CLIENT_STATE_CONNECTING ;
-            dap_client_go_stage(l_me->client, STAGE_STREAM_STREAMING, s_stage_connected_callback);
-        }
-    }
-    return false;
-}
-
 /**
  * @brief s_stage_status_error_callback
  * @param a_client
@@ -132,8 +112,7 @@ static bool s_timer_node_reconnect(void *a_arg)
  */
 static void s_stage_status_error_callback(dap_client_t *a_client, void *a_arg)
 {
-    if (s_stream_ch_chain_debug_more)
-        log_it(L_DEBUG, "s_stage_status_error_callback");
+    log_it(L_DEBUG, "s_stage_status_error_callback");
 
     dap_chain_node_client_t *l_node_client = DAP_CHAIN_NODE_CLIENT(a_client);
     if(!l_node_client)
@@ -159,87 +138,12 @@ static void s_stage_status_error_callback(dap_client_t *a_client, void *a_arg)
         if (l_node_client->callbacks.disconnected) {
             l_node_client->callbacks.disconnected(l_node_client, l_node_client->callbacks_arg);
         }
-        if (l_node_client->keep_connection) {
-            if (dap_client_get_stage(l_node_client->client) != STAGE_BEGIN)
-                dap_client_go_stage(l_node_client->client, STAGE_BEGIN, NULL);
-            l_node_client->reconnect_timer = dap_timerfd_start(45 * 1000, s_timer_node_reconnect, l_node_client);
-        }
+        if (dap_client_get_stage(l_node_client->client) != STAGE_BEGIN)
+            dap_client_go_stage(l_node_client->client, STAGE_BEGIN, NULL);
     } else if(l_node_client->callbacks.error) // TODO make different error codes
         l_node_client->callbacks.error(l_node_client, EINVAL, l_node_client->callbacks_arg);
 }
 
-
-/**
- * @brief dap_chain_node_client_start_sync
- * @param a_uuid
- * @param a_wrlock
- * @return
- */
-dap_chain_node_sync_status_t dap_chain_node_client_start_sync(dap_chain_node_client_t *a_node_client)
-{
-    assert(a_node_client);
-    // check if esocket still in worker
-    dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(a_node_client->stream_worker, a_node_client->ch_chain_uuid);
-    if (l_ch) {
-        dap_chain_ch_t *l_ch_chain = DAP_CHAIN_CH(l_ch);
-        assert(l_ch_chain);
-        dap_chain_net_t * l_net = a_node_client->net;
-        assert(l_net);
-        // If we do nothing - init sync process
-
-        if (l_ch_chain->state == DAP_CHAIN_CH_STATE_IDLE) {
-            // bool l_trylocked = dap_chain_net_sync_trylock(l_net, a_node_client);
-            bool l_trylocked = true;
-            if (l_trylocked) {
-                log_it(L_INFO, "Start synchronization process with "NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(a_node_client->remote_node_addr));
-                a_node_client->cur_chain = l_net->pub.chains;
-                a_node_client->cur_cell = a_node_client->cur_chain ? a_node_client->cur_chain->cells : NULL;
-                dap_chain_ch_sync_request_t l_sync_chain = {};
-                l_sync_chain.node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
-                dap_chain_ch_pkt_write_unsafe(a_node_client->ch_chain,
-                                                     DAP_CHAIN_CH_PKT_TYPE_UPDATE_CHAINS_REQ,
-                                                     l_net->pub.id.uint64, l_net->pub.chains->id.uint64, 0,
-                                                     &l_sync_chain, sizeof(l_sync_chain));
-                if (!l_ch_chain->activity_timer)
-                    dap_chain_ch_timer_start(l_ch_chain);
-                return NODE_SYNC_STATUS_STARTED;
-            } else
-                return NODE_SYNC_STATUS_WAITING;
-        } else
-            return NODE_SYNC_STATUS_IN_PROGRESS;
-    }
-    return NODE_SYNC_STATUS_FAILED;
-}
-
-/**
- * @brief s_timer_update_states_callback
- * @param a_arg
- * @return
- */
-static bool s_timer_update_states_callback(void *a_arg)
-{
-    dap_chain_node_client_t *l_me = a_arg;
-    dap_chain_node_sync_status_t l_status = dap_chain_node_client_start_sync(l_me);
-    if (l_status == NODE_SYNC_STATUS_FAILED) {
-        l_me->state = NODE_CLIENT_STATE_DISCONNECTED;
-        if (l_me->keep_connection) {
-            if (dap_client_get_stage(l_me->client) != STAGE_BEGIN) {
-                dap_client_go_stage(l_me->client, STAGE_BEGIN, NULL);
-                return true;
-            }
-            if (l_me->is_connected && l_me->callbacks.disconnected)
-                l_me->callbacks.disconnected(l_me, l_me->callbacks_arg);
-            if (l_me->keep_connection) {
-                log_it(L_INFO, "Reconnecting node client with peer "NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(l_me->remote_node_addr));
-                l_me->state = NODE_CLIENT_STATE_CONNECTING;
-                dap_client_go_stage(l_me->client, STAGE_STREAM_STREAMING, s_stage_connected_callback);
-            }
-        }
-    }
-    return true;
-}
-
-
 /**
  * @brief a_stage_end_callback
  * @param a_client
@@ -254,7 +158,8 @@ static void s_stage_connected_callback(dap_client_t *a_client, void *a_arg)
                     NODE_ADDR_FP_ARGS_S(l_node_client->remote_node_addr),
                     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
+        l_node_client->esocket_uuid = DAP_CLIENT_PVT(a_client)->stream_es->uuid;
+        // set callbacks for R and N channels
         if (a_client->active_channels) {
             size_t l_channels_count = dap_strlen(a_client->active_channels);
             for(size_t i = 0; i < l_channels_count; i++) {
@@ -265,41 +170,6 @@ static void s_stage_connected_callback(dap_client_t *a_client, void *a_arg)
         }
         if(l_node_client->callbacks.connected)
             l_node_client->callbacks.connected(l_node_client, l_node_client->callbacks_arg);
-        dap_stream_ch_chain_net_pkt_hdr_t l_announce = { .version = DAP_STREAM_CH_CHAIN_NET_PKT_VERSION,
-                                                         .net_id  = l_node_client->net->pub.id };
-        // Announce net on downlink
-        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->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))
-                dap_cluster_member_add(it->links_cluster, l_uplink_addr, 0, NULL);
-        // dap_chain_net_add_cluster_link(l_node_client->net, l_uplink_addr);
-
-        pthread_mutex_lock(&l_node_client->wait_mutex);
-        l_node_client->state = NODE_CLIENT_STATE_ESTABLISHED;
-        if (s_stream_ch_chain_debug_more)
-            log_it(L_DEBUG, "Wakeup all who waits");
-        dap_cond_signal(l_node_client->wait_cond);
-        pthread_mutex_unlock(&l_node_client->wait_mutex);
-        dap_stream_t * l_stream  = dap_client_get_stream(a_client);
-        if (l_stream) {
-            l_node_client->esocket_uuid = l_stream->esocket->uuid;
-            l_node_client->stream_worker = l_stream->stream_worker;
-            if (l_node_client->keep_connection) {
-                if(l_node_client->stream_worker){
-                    s_timer_update_states_callback(l_node_client);
-                    l_node_client->sync_timer = dap_timerfd_start_on_worker(l_stream->esocket->worker,
-                                                                            s_timer_update_states * 1000,
-                                                                            s_timer_update_states_callback,
-                                                                            l_node_client);
-                }else{
-                    log_it(L_ERROR,"After NODE_CLIENT_STATE_ESTABLISHED: Node client has no worker, too dangerous to run update states in alien context");
-                }
-            }
-        }
     }
 }
 
@@ -332,280 +202,6 @@ static void s_ch_chain_callback_notify_packet_in2(dap_stream_ch_chain_net_t* a_c
     }
 }
 
-
-/**
- * @brief s_ch_chain_callback_notify_packet_in - for dap_chain_ch
- * @param a_ch_chain
- * @param a_pkt_type
- * @param a_pkt
- * @param a_pkt_data_size
- * @param a_arg
- */
-static void s_ch_chain_callback_notify_packet_in(dap_chain_ch_t* a_ch_chain, uint8_t a_pkt_type,
-        dap_chain_ch_pkt_t *a_pkt, size_t a_pkt_data_size,
-        void * a_arg)
-{
-    UNUSED(a_pkt_data_size);
-    dap_chain_node_client_t * l_node_client = (dap_chain_node_client_t *) a_arg;
-    dap_chain_net_t *l_net = l_node_client->net;
-    assert(l_net);
-    bool l_finished = false;
-    switch (a_pkt_type) {
-        case DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ERROR:
-            snprintf(l_node_client->last_error, sizeof(l_node_client->last_error),
-                    "%s", (char*) a_pkt->data);
-            log_it(L_WARNING, "In: Received packet DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_ERROR with error \"%s\"",
-                    l_node_client->last_error);
-            l_node_client->state = NODE_CLIENT_STATE_ERROR;
-            if (!strcmp(l_node_client->last_error, "ERROR_SYNC_REQUEST_ALREADY_IN_PROCESS")) {
-                dap_chain_ch_reset_unsafe(a_ch_chain);
-                l_finished = true;
-            }
-        break;
-        case DAP_CHAIN_CH_PKT_TYPE_UPDATE_GLOBAL_DB_REQ:{
-            l_node_client->state = NODE_CLIENT_STATE_SYNC_GDB_UPDATES;
-        }break;
-        case DAP_CHAIN_CH_PKT_TYPE_UPDATE_GLOBAL_DB_START:{
-            l_node_client->state = NODE_CLIENT_STATE_SYNC_GDB_RVRS;
-            dap_chain_net_t * l_net = l_node_client->net;
-            assert(l_net);
-            dap_chain_net_set_state(l_net, NET_STATE_SYNC_GDB);
-        }break;
-        case DAP_CHAIN_CH_PKT_TYPE_FIRST_GLOBAL_DB:{
-            l_node_client->state = NODE_CLIENT_STATE_SYNC_GDB;
-        }break;
-        case DAP_CHAIN_CH_PKT_TYPE_UPDATE_CHAINS_REQ:{
-            l_node_client->state = NODE_CLIENT_STATE_SYNC_CHAINS_UPDATES;
-        }break;
-        case DAP_CHAIN_CH_PKT_TYPE_UPDATE_CHAINS_START:{
-            l_node_client->state = NODE_CLIENT_STATE_SYNC_CHAINS_RVRS;
-            dap_chain_net_t * l_net = l_node_client->net;
-            assert(l_net);
-            dap_chain_net_set_state(l_net, NET_STATE_SYNC_CHAINS);
-        }break;
-        case DAP_CHAIN_CH_PKT_TYPE_FIRST_CHAIN:{
-            l_node_client->state = NODE_CLIENT_STATE_SYNC_CHAINS;
-        }break;
-        case DAP_CHAIN_CH_PKT_TYPE_SYNCED_GLOBAL_DB:
-        case DAP_CHAIN_CH_PKT_TYPE_SYNCED_CHAINS: {
-            dap_chain_id_t  l_chain_id = {};
-            dap_chain_cell_id_t l_cell_id = {};
-            if (a_pkt_type == DAP_CHAIN_CH_PKT_TYPE_SYNCED_GLOBAL_DB) {
-                if (dap_chain_net_get_target_state(l_net) != NET_STATE_SYNC_GDB) {
-                    if(s_stream_ch_chain_debug_more)
-                        log_it(L_INFO,"In: Link %s."NODE_ADDR_FP_STR" synced GDB. Going to update chains", l_net->pub.name, NODE_ADDR_FP_ARGS_S(l_node_client->remote_node_addr ));
-                    l_node_client->cur_chain = l_net->pub.chains;
-                    l_node_client->cur_cell = l_node_client->cur_chain ? l_node_client->cur_chain->cells : NULL;
-                } else
-                    l_node_client->cur_chain = NULL;
-            } else {
-                // Check if we over with it before
-                if ( ! l_node_client->cur_cell ){
-                    if(s_stream_ch_chain_debug_more)
-                        log_it(L_INFO, "In: No current cell in sync state, anyway we over it");
-                }else
-                    l_node_client->cur_cell =(dap_chain_cell_t *)  l_node_client->cur_cell->hh.next;
-
-                // If  over with cell, switch on next chain
-                if ( l_node_client->cur_cell){
-                    // Check if we over with it before
-                    if ( !l_node_client->cur_chain ){
-                        log_it(L_ERROR, "In: No chain but cell is present, over with it");
-                    }
-                }else{
-                    // Check if we over with it before
-                    if ( !l_node_client->cur_chain ){
-                        log_it(L_WARNING, "In: No current chain in sync state, anyway we over it");
-                    }else{
-                        l_node_client->cur_chain = (dap_chain_t *) l_node_client->cur_chain->next;
-                        l_node_client->cur_cell = l_node_client->cur_chain ? l_node_client->cur_chain->cells : NULL;
-                    }
-                }
-            }
-
-            if (l_node_client->cur_cell)
-                l_cell_id = l_node_client->cur_cell->id;
-            // Check if we have some more chains and cells in it to sync
-            dap_chain_node_addr_t l_node_addr;
-            l_node_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
-            if( l_node_client->cur_chain ){
-                l_chain_id=l_node_client->cur_chain->id;
-                if (s_stream_ch_chain_debug_more) {
-                    log_it(L_INFO,"In: Link %s."NODE_ADDR_FP_STR" started to sync %s chain",l_net->pub.name,
-                           NODE_ADDR_FP_ARGS_S(l_node_addr), l_node_client->cur_chain->name );
-                }
-                dap_chain_ch_pkt_write_unsafe(l_node_client->ch_chain, DAP_CHAIN_CH_PKT_TYPE_UPDATE_CHAINS_REQ,
-                                                     l_net->pub.id.uint64 ,
-                                                     l_chain_id.uint64,l_cell_id.uint64,NULL,0);
-            } else { // If no - over with sync process
-                log_it(L_INFO, "In: State node %s."NODE_ADDR_FP_STR" is SYNCED",l_net->pub.name, NODE_ADDR_FP_ARGS_S(l_node_addr) );
-                l_finished = true;
-            }
-        } break;
-        default: break;
-    }
-    if (l_finished) {
-        pthread_mutex_lock(&l_node_client->wait_mutex);
-        l_node_client->state = NODE_CLIENT_STATE_SYNCED;
-        dap_cond_signal(l_node_client->wait_cond);
-        pthread_mutex_unlock(&l_node_client->wait_mutex);
-        // bool l_have_waiting = dap_chain_net_sync_unlock(l_net, l_node_client);
-        bool l_have_waiting = true;
-        if (dap_chain_net_get_target_state(l_net) == NET_STATE_ONLINE) {
-            dap_timerfd_reset_unsafe(l_node_client->sync_timer);
-            dap_chain_net_set_state(l_net, NET_STATE_ONLINE);
-        }
-        else if (!l_have_waiting)
-        {
-            // l_node_client object is not presented after dap_chain_net_state_go_to with NET_STATE_OFFLINE
-            dap_chain_net_state_go_to(l_net, NET_STATE_OFFLINE);
-        }
-    }
-}
-
-
-
-/**
- * @brief s_ch_chain_callback_notify_packet_in
- * @param a_ch_chain
- * @param a_pkt_type
- * @param a_pkt
- * @param a_pkt_data_size
- * @param a_arg
- */
-static void s_ch_chain_callback_notify_packet_out(dap_chain_ch_t* a_ch_chain, uint8_t a_pkt_type,
-        dap_chain_ch_pkt_t *a_pkt, size_t a_pkt_data_size,
-        void * a_arg)
-{
-    (void) a_pkt;
-    (void) a_pkt_data_size;
-    (void) a_ch_chain;
-    dap_chain_node_client_t * l_node_client = (dap_chain_node_client_t *) a_arg;
-    assert(a_arg);
-    switch (a_pkt_type) {
-        case DAP_CHAIN_CH_PKT_TYPE_SYNCED_GLOBAL_DB: {
-            if(s_stream_ch_chain_debug_more)
-                log_it(L_INFO,"Out: global database sent to uplink "NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(l_node_client->remote_node_addr));
-        } break;
-        case DAP_CHAIN_CH_PKT_TYPE_SYNCED_CHAINS: {
-            if(s_stream_ch_chain_debug_more)
-                log_it(L_INFO,"Out: chain %"DAP_UINT64_FORMAT_x" sent to uplink "NODE_ADDR_FP_STR,l_node_client->cur_chain ? l_node_client->cur_chain->id.uint64 : 0, NODE_ADDR_FP_ARGS_S(l_node_client->remote_node_addr));
-        } break;
-        case DAP_CHAIN_CH_PKT_TYPE_TIMEOUT:
-        case DAP_CHAIN_CH_PKT_TYPE_DELETE: {
-            dap_chain_net_t *l_net = l_node_client->net;
-            assert(l_net);
-            log_it(L_DEBUG, "In: State node %s."NODE_ADDR_FP_STR" %s", l_net->pub.name, NODE_ADDR_FP_ARGS_S(g_node_addr),
-                            a_pkt_type == DAP_CHAIN_CH_PKT_TYPE_TIMEOUT ? "is timeout for sync" : "stream closed");
-            l_node_client->state = NODE_CLIENT_STATE_ERROR;
-            if (l_node_client->sync_timer)
-                dap_timerfd_reset_unsafe(l_node_client->sync_timer);
-            // bool l_have_waiting = dap_chain_net_sync_unlock(l_net, l_node_client);
-            bool l_have_waiting = true;
-            if (!l_have_waiting) {
-                if (dap_chain_net_get_target_state(l_net) == NET_STATE_ONLINE)
-                    dap_chain_net_set_state(l_net, NET_STATE_ONLINE);
-                else
-                    dap_chain_net_state_go_to(l_net, NET_STATE_OFFLINE);
-            }
-        } break;
-        default:;
-    }
-}
-
-/**
- * @brief s_save_stat_to_database_callback_set_stat
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_len
- * @param a_value_ts
- * @param a_is_pinned
- * @param a_arg
- */
-static void s_save_stat_to_database_callback_set_stat(dap_global_db_instance_t *a_dbi, int a_rc, const char * a_group, const char * a_key, const void * a_value, const size_t a_value_len, dap_nanotime_t a_value_ts, bool a_is_pinned, void * a_arg)
-{
-    if( a_rc != DAP_GLOBAL_DB_RC_SUCCESS)
-        log_it(L_ERROR,"Can't save stats to GlobalDB, code %d", a_rc);
-
-    DAP_DELETE(a_arg);
-}
-
-/**
- * @brief s_save_stat_to_database_callback_get_last_stat
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_len
- * @param a_value_ts
- * @param a_is_pinned
- * @param a_arg
- */
-static void s_save_stat_to_database_callback_get_last_stat(dap_global_db_instance_t *a_dbi, int a_rc, const char * a_group, const char * a_key, const void * a_value, const size_t a_value_len, dap_nanotime_t a_value_ts, bool a_is_pinned, void * a_arg)
-{
-    char * l_json_str = (char *) a_arg;
-    uint64_t l_key = 0;
-    if(a_rc == DAP_GLOBAL_DB_RC_SUCCESS) {
-        l_key = strtoll(a_key, NULL, 16);
-    }
-
-    char *l_key_str = dap_strdup_printf("%06"DAP_UINT64_FORMAT_x, ++l_key);
-    dap_global_db_set(a_group, l_key_str, l_json_str, strlen(l_json_str) + 1,false, s_save_stat_to_database_callback_set_stat, l_json_str);
-
-    DAP_DELETE(l_key_str);
-
-}
-
-/**
- * @brief save_stat_to_database
- *
- * @param a_request
- * @param a_node_client
- * @return int
- */
-static int s_save_stat_to_database(dap_stream_ch_chain_net_srv_pkt_test_t *a_request, dap_chain_node_client_t * a_node_client)
-{
-    UNUSED(a_node_client);
-    int l_ret = 0;
-    if(!a_request)
-        return -1;
-    long l_t1_ms = a_request->send_time1 / 1e6;
-    long l_t2_ms = a_request->recv_time1 / 1e6;
-    struct json_object *jobj = json_object_new_object();
-    time_t l_cur_t = time(NULL);
-    char buf[1024];
-    dap_time_to_str_rfc822( buf, sizeof(buf), l_cur_t );
-    json_object_object_add(jobj, "time_save", json_object_new_int64(l_cur_t));
-    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->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));
-    const char* l_json_str = json_object_to_json_string(jobj);
-    // save statistics
-    char *l_group = NULL;
-    dap_chain_net_t * l_net = dap_chain_net_by_id(a_request->net_id);
-    if(l_net) {
-        l_group = dap_strdup_printf("local.%s.orders-test-stat", l_net->pub.gdb_groups_prefix);
-    }
-    if(l_group) {
-        dap_global_db_get_last( l_group, s_save_stat_to_database_callback_get_last_stat,
-                                dap_strdup(l_json_str));
-        DAP_DELETE(l_group);
-    }
-    else
-        l_ret = -2;
-    json_object_put(jobj);
-    return l_ret;
-}
-
 /**
  * @brief s_ch_chain_callback_notify_packet_R - Callback for channel 'R'
  * @param a_ch_chain
@@ -626,7 +222,7 @@ static void s_ch_chain_callback_notify_packet_R(dap_stream_ch_chain_net_srv_t* a
                 log_it(L_WARNING, "Wrong request size, less or more than required");
                 break;
             }
-            s_save_stat_to_database(l_request, l_node_client);
+            //s_save_stat_to_database(l_request, l_node_client);
             pthread_mutex_lock(&l_node_client->wait_mutex);
             l_node_client->state = NODE_CLIENT_STATE_CHECKED;
             dap_cond_signal(l_node_client->wait_cond);
@@ -698,14 +294,6 @@ dap_chain_node_client_t *dap_chain_node_client_create(dap_chain_net_t *a_net,
     return l_node_client;
 }
 
-
- void s_client_delete_callback(UNUSED_ARG dap_client_t *a_client, void *a_arg)
- {
-     // TODO make decision for possible client replacement
-     assert(a_arg);
-     ((dap_chain_node_client_t *)a_arg)->client = NULL;
-     dap_chain_node_client_close_unsafe(a_arg);
- }
 /**
  * @brief dap_chain_node_client_connect
  * Create new dap_client, setup it, and send it in adventure trip
@@ -718,7 +306,7 @@ bool dap_chain_node_client_connect(dap_chain_node_client_t *a_node_client, const
 {
     if (!a_node_client)
         return false;
-    a_node_client->client = dap_client_new(s_client_delete_callback, s_stage_status_error_callback, a_node_client);
+    a_node_client->client = dap_client_new(NULL, s_stage_status_error_callback, a_node_client);
     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);
@@ -730,25 +318,13 @@ bool dap_chain_node_client_connect(dap_chain_node_client_t *a_node_client, const
     }
 
     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);
+    dap_client_set_uplink_unsafe(a_node_client->client, &a_node_client->info->address, 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);
     return true;
 }
 
-/**
- * @brief dap_chain_node_client_reset
- *
- * @param a_client dap_chain_node_client_t
- */
-void dap_chain_node_client_reset(dap_chain_node_client_t *a_client)
-{
-    if (a_client->state > NODE_CLIENT_STATE_ESTABLISHED) {
-        a_client->state = NODE_CLIENT_STATE_ESTABLISHED;
-    }
-}
-
 /**
  * @brief dap_chain_node_client_close
  * Close connection to server, delete chain_node_client_t *client
@@ -769,13 +345,7 @@ void dap_chain_node_client_close_unsafe(dap_chain_node_client_t *a_node_client)
         a_node_client->callbacks.delete(a_node_client, a_node_client->net);
 
     if (a_node_client->stream_worker) {
-        dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(a_node_client->stream_worker, a_node_client->ch_chain_uuid);
-        if (l_ch) {
-            dap_chain_ch_t *l_ch_chain = DAP_CHAIN_CH(l_ch);
-            l_ch_chain->callback_notify_packet_in = NULL;
-            l_ch_chain->callback_notify_packet_out = NULL;
-        }
-        l_ch = dap_stream_ch_find_by_uuid_unsafe(a_node_client->stream_worker, a_node_client->ch_chain_net_uuid);
+        dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(a_node_client->stream_worker, a_node_client->ch_chain_net_uuid);
         if (l_ch) {
             dap_stream_ch_chain_net_t *l_ch_chain_net = DAP_STREAM_CH_CHAIN_NET(l_ch);
             l_ch_chain_net->notify_callback = NULL;
@@ -796,7 +366,7 @@ void dap_chain_node_client_close_unsafe(dap_chain_node_client_t *a_node_client)
     DAP_DELETE(a_node_client);
 }
 
-void s_close_on_worker_callback(UNUSED_ARG dap_worker_t *a_worker, void *a_arg)
+void s_close_on_worker_callback(dap_worker_t UNUSED_ARG *a_worker, void *a_arg)
 {
     assert(a_arg);
     dap_chain_node_client_close_unsafe(a_arg);
@@ -810,28 +380,6 @@ void dap_chain_node_client_close_mt(dap_chain_node_client_t *a_node_client)
         dap_chain_node_client_close_unsafe(a_node_client);
 }
 
-/**
- * @brief dap_chain_node_client_send_ch_pkt
- * Send stream request to server
- * @param a_client
- * @param a_ch_id
- * @param a_type
- * @param a_pkt_data
- * @param a_pkt_data_size
- * @return int
- */
-int dap_chain_node_client_send_ch_pkt(dap_chain_node_client_t *a_client, uint8_t a_ch_id, uint8_t a_type,
-        const void *a_pkt_data, size_t a_pkt_data_size)
-{
-    if(!a_client || a_client->state < NODE_CLIENT_STATE_ESTABLISHED)
-        return -1;
-
-    dap_stream_worker_t *l_stream_worker = dap_client_get_stream_worker(a_client->client);
-    dap_stream_ch_pkt_write_mt(l_stream_worker , a_client->ch_chain_uuid , a_type, a_pkt_data, a_pkt_data_size);
-    return 0;
-}
-
-
 /**
  * @brief dap_chain_node_client_wait
  * wait for the complete of request
@@ -850,7 +398,6 @@ int dap_chain_node_client_wait(dap_chain_node_client_t *a_client, int a_waited_s
         log_it(L_ERROR, "Can't wait for status for (null) object");
         return -3;
     }
-    a_client->keep_connection = false;
     pthread_mutex_lock(&a_client->wait_mutex);
     // have waited
     if(a_client->state == a_waited_state) {
@@ -918,8 +465,6 @@ int dap_chain_node_client_wait(dap_chain_node_client_t *a_client, int a_waited_s
  */
 static int s_node_client_set_notify_callbacks(dap_client_t *a_client, uint8_t a_ch_id)
 {
-    //TODO pass callbacks through stream creation to internal ch structures
-
     int l_ret = -1;
     dap_chain_node_client_t *l_node_client = a_client->_inheritor;
     if(l_node_client) {
@@ -929,16 +474,6 @@ static int s_node_client_set_notify_callbacks(dap_client_t *a_client, uint8_t a_
         if(l_ch) {
             l_ret = 0;
             switch (a_ch_id) {
-                //  'C'
-            case DAP_CHAIN_CH_ID: {
-                dap_chain_ch_t *l_ch_chain       = DAP_CHAIN_CH(l_ch);
-                l_ch_chain->callback_notify_packet_out  = s_ch_chain_callback_notify_packet_out;
-                l_ch_chain->callback_notify_packet_in   = s_ch_chain_callback_notify_packet_in;
-                l_ch_chain->callback_notify_arg         = l_node_client;
-                l_node_client->ch_chain         = l_ch;
-                l_node_client->ch_chain_uuid    = l_ch->uuid;
-                break;
-            }
                 //  'N'
             case DAP_STREAM_CH_NET_ID: {
                 dap_stream_ch_chain_net_t *l_ch_chain   = DAP_STREAM_CH_CHAIN_NET(l_ch);
@@ -973,21 +508,3 @@ static int s_node_client_set_notify_callbacks(dap_client_t *a_client, uint8_t a_
     }
     return l_ret;
 }
-
-/**
- * @brief dap_chain_node_client_send_nodelist_req
- * Send nodelist request to server
- * @param a_client
- * @return int
- */
-int dap_chain_node_client_send_nodelist_req(dap_chain_node_client_t *a_client)
-{
-    if(!a_client || !a_client->client || a_client->state < NODE_CLIENT_STATE_ESTABLISHED)
-        return -1;
-    //dap_client_pvt_t * l_client_pvt = DAP_CLIENT_PVT(a_client->client);
-
-    //TODO send request to get nodelist
-    //dap_client_request_enc(a_client->client, DAP_UPLINK_PATH_NODE_LIST, "", "", "", 0,
-    //        nodelist_response_callback, nodelist_response_error_callback);
-    return 1;
-}
diff --git a/modules/net/dap_chain_node_dns_client.c b/modules/net/dap_chain_node_dns_client.c
index b02fdbaa12f64efa46a985e10acd98a29b63b1b4..e0f4f715d8ff547b30518db46754ef873e2b1aff 100644
--- a/modules/net/dap_chain_node_dns_client.c
+++ b/modules/net/dap_chain_node_dns_client.c
@@ -86,8 +86,8 @@ static void s_dns_client_esocket_read_callback(dap_events_socket_t * a_esocket,
     }
     l_cur = l_buf + l_addr_point;
 
-    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_net_links_t *l_link_full_node_list = DAP_NEW_Z_SIZE(dap_chain_net_links_t,
+                                                                          sizeof(dap_chain_net_links_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); TODO: implement other request and response
     l_cur = l_buf + 5 * sizeof(uint16_t);
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index 79ffdad84a52213eb1c5ba9a5d7c15cc54f97cac..c03d1d457a7212ec403da8f90c56bd1e99d008f7 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -57,8 +57,6 @@ typedef enum dap_chain_net_state{
     NET_STATE_LINKS_PREPARE,
     NET_STATE_LINKS_CONNECTING,
     NET_STATE_LINKS_ESTABLISHED,
-    NET_STATE_ADDR_REQUEST, // Waiting for address assign
-    NET_STATE_SYNC_GDB,
     NET_STATE_SYNC_CHAINS,
     NET_STATE_ONLINE
 } dap_chain_net_state_t;
@@ -124,9 +122,7 @@ inline static int dap_chain_net_stop(dap_chain_net_t *a_net)
     return false;
 }
 inline static int dap_chain_net_links_establish(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_LINKS_ESTABLISHED); }
-inline static int dap_chain_net_sync_gdb(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_GDB); }
-inline static int dap_chain_net_sync_chains(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_CHAINS); }
-inline static int dap_chain_net_sync_all(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_CHAINS); }
+inline static int dap_chain_net_sync(dap_chain_net_t * a_net) { return dap_chain_net_state_go_to(a_net,NET_STATE_SYNC_CHAINS); }
 
 void dap_chain_net_delete( dap_chain_net_t * a_net);
 void dap_chain_net_proc_mempool(dap_chain_net_t *a_net);
@@ -147,15 +143,13 @@ uint64_t dap_chain_net_get_cur_addr_int(dap_chain_net_t * l_net);
 dap_chain_cell_id_t * dap_chain_net_get_cur_cell( dap_chain_net_t * l_net);
 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);
+// Get inintial authorized nodes pointed by config
 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);
+bool dap_chain_net_is_my_node_authorized(dap_chain_net_t *a_net);
+dap_stream_node_addr_t *dap_chain_net_get_authorized_nodes(dap_chain_net_t *a_net, size_t *a_nodes_count);
 
-int dap_chain_net_add_poa_certs_to_cluster(dap_chain_net_t *a_net, dap_global_db_cluster_t *a_cluster);
+int dap_chain_net_add_auth_nodes_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);
 bool dap_chain_net_remove_validator_from_clusters(dap_chain_t *a_chain, dap_stream_node_addr_t *a_addr);
 dap_global_db_cluster_t *dap_chain_net_get_mempool_cluster(dap_chain_t *a_chain);
@@ -213,7 +207,6 @@ int dap_chain_datum_add(dap_chain_t * a_chain, dap_chain_datum_t *a_datum, size_
 bool dap_chain_net_get_load_mode(dap_chain_net_t * a_net);
 void dap_chain_net_announce_addrs(dap_chain_net_t *a_net);
 char *dap_chain_net_links_dump(dap_chain_net_t*);
-int dap_chain_net_link_manager_init();
 
 enum dap_chain_net_json_rpc_error_list{
     DAP_CHAIN_NET_JSON_RPC_OK,
diff --git a/modules/net/include/dap_chain_net_balancer.h b/modules/net/include/dap_chain_net_balancer.h
index 70f33fd666436cf2207a8e69d014c52b6f7b6eef..4d3a1cf651c479e2f0bcc345c1da7d0b9fab3af0 100644
--- a/modules/net/include/dap_chain_net_balancer.h
+++ b/modules/net/include/dap_chain_net_balancer.h
@@ -33,10 +33,10 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 typedef struct dap_chain_net_node_balancer {
     uint64_t count_node;
     byte_t nodes_info[];
-} dap_chain_net_node_balancer_t;
+} DAP_ALIGN_PACKED dap_chain_net_links_t;
 
 void dap_chain_net_balancer_http_issue_link(dap_http_simple_t *a_http_simple, void *a_arg);
 dap_link_info_t *dap_chain_net_balancer_dns_issue_link(char *a_str);
-dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node(const char *a_net_name,uint16_t a_links_need);
+dap_chain_net_links_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);
 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 56b05e44fae2c669860219bb49bc0427fac7098e..cacbd70f2cb535eabad94cd54c84c746067aab16 100644
--- a/modules/net/include/dap_chain_net_node_list.h
+++ b/modules/net/include/dap_chain_net_node_list.h
@@ -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, const char *a_addr, uint16_t a_port, bool a_sync, char a_cmd);
+int dap_chain_net_node_list_request(dap_chain_net_t *a_net, 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_client.h b/modules/net/include/dap_chain_node_client.h
index 75d476b6bc1fb7cc58a477b4232c519898063973..bcae5c2cd60abb62ff8ef4e42f79b513054df3ec 100644
--- a/modules/net/include/dap_chain_node_client.h
+++ b/modules/net/include/dap_chain_node_client.h
@@ -34,30 +34,14 @@
 typedef enum dap_chain_node_client_state {
     NODE_CLIENT_STATE_ERROR = -1,
     NODE_CLIENT_STATE_DISCONNECTED = 0,
-    NODE_CLIENT_STATE_GET_NODE_ADDR = 1,
-    NODE_CLIENT_STATE_NODE_ADDR_LEASED = 2,
     NODE_CLIENT_STATE_PING = 3,
     NODE_CLIENT_STATE_PONG = 4,
     NODE_CLIENT_STATE_CONNECTING = 5,
     NODE_CLIENT_STATE_ESTABLISHED = 100,
-    NODE_CLIENT_STATE_SYNC_GDB_UPDATES = 101,
-    NODE_CLIENT_STATE_SYNC_GDB = 102,
-    NODE_CLIENT_STATE_SYNC_GDB_RVRS = 103,
-    NODE_CLIENT_STATE_SYNC_CHAINS_UPDATES = 110,
-    NODE_CLIENT_STATE_SYNC_CHAINS = 111,
-    NODE_CLIENT_STATE_SYNC_CHAINS_RVRS = 112,
-    NODE_CLIENT_STATE_SYNCED = 120,
     NODE_CLIENT_STATE_CHECKED = 130,
     NODE_CLIENT_STATE_VALID_READY = 140,
 } dap_chain_node_client_state_t;
 
-typedef enum dap_chain_node_sync_status {
-    NODE_SYNC_STATUS_STARTED = 0,
-    NODE_SYNC_STATUS_WAITING = 1,
-    NODE_SYNC_STATUS_IN_PROGRESS = 2,
-    NODE_SYNC_STATUS_FAILED = -1
-} dap_chain_node_sync_status_t;
-
 typedef struct dap_chain_node_client dap_chain_node_client_t;
 
 typedef void (*dap_chain_node_client_callback_t)(dap_chain_node_client_t *, void*);
@@ -73,8 +57,6 @@ typedef struct dap_chain_node_client_callbacks {
 } dap_chain_node_client_callbacks_t;
 
 typedef struct dap_chain_node_client_notify_callbacks {
-    dap_stream_ch_callback_packet_t chain_pkt_in;
-    dap_stream_ch_callback_packet_t chain_pkt_out;
     dap_stream_ch_callback_packet_t net_pkt_in;
     dap_stream_ch_callback_packet_t net_pkt_out;
     dap_stream_ch_callback_packet_t srv_pkt_in;
@@ -84,8 +66,6 @@ typedef struct dap_chain_node_client_notify_callbacks {
 // state for a client connection
 typedef struct dap_chain_node_client {
     dap_chain_node_client_state_t state;
-    bool resync_gdb;
-    bool resync_chains;
 
     dap_chain_cell_id_t cell_id;
 
@@ -96,9 +76,6 @@ typedef struct dap_chain_node_client {
     dap_chain_t * cur_chain; // Current chain to update
     dap_chain_cell_t * cur_cell; // Current cell to update
 
-    // Channel chain
-    dap_stream_ch_t * ch_chain;
-    dap_stream_ch_uuid_t ch_chain_uuid;
     // Channel chain net
     dap_stream_ch_t * ch_chain_net;
     dap_stream_ch_uuid_t ch_chain_net_uuid;
@@ -125,7 +102,6 @@ typedef struct dap_chain_node_client {
     dap_chain_node_addr_t cur_node_addr;
     dap_chain_node_addr_t remote_node_addr;
 
-    bool keep_connection;
     bool is_connected;
     dap_timerfd_t *sync_timer;
     dap_timerfd_t *reconnect_timer;
@@ -146,10 +122,6 @@ dap_chain_node_client_t *dap_chain_node_client_create(dap_chain_net_t *a_net, da
 
 bool dap_chain_node_client_connect(dap_chain_node_client_t *a_node_client, const char *a_active_channels);
 
-void dap_chain_node_client_added_gdb(dap_chain_node_client_t *a_node_client);
-
-void dap_chain_node_client_link_remove_gdb(dap_chain_node_client_t *a_node_client);
-
 /**
  * Create handshake to server
  *
@@ -177,22 +149,12 @@ DAP_STATIC_INLINE int dap_chain_node_client_write_mt(dap_chain_node_client_t *a_
 DAP_STATIC_INLINE void dap_chain_node_client_queue_clear(dap_chain_node_client_t *a_client)
 { if (!a_client) return; dap_client_queue_clear(a_client->client); };
 
-/**
- * Reset client state to connected state if it is connected
- */
-void dap_chain_node_client_reset(dap_chain_node_client_t *a_client);
 /**
  * Close connection to server, delete chain_node_client_t with specified UUID
  */
 void dap_chain_node_client_close_unsafe(dap_chain_node_client_t *a_node_client);
 void dap_chain_node_client_close_mt(dap_chain_node_client_t *a_node_client);
 
-/**
- * Send stream request to server
- */
-int dap_chain_node_client_send_ch_pkt(dap_chain_node_client_t *a_client, uint8_t a_ch_id, uint8_t a_type,
-        const void *a_buf, size_t a_buf_size);
-
 /**
  * wait for the complete of request
  *
@@ -202,24 +164,15 @@ int dap_chain_node_client_send_ch_pkt(dap_chain_node_client_t *a_client, uint8_t
  */
 int dap_chain_node_client_wait(dap_chain_node_client_t *a_client, int a_waited_state, int a_timeout_ms);
 
-int dap_chain_node_client_send_nodelist_req(dap_chain_node_client_t *a_client);
-
-dap_chain_node_sync_status_t dap_chain_node_client_start_sync(dap_chain_node_client_t *a_node_client);
-
 static inline const char * dap_chain_node_client_state_to_str( dap_chain_node_client_state_t a_state)
 {
     switch (a_state) {
         case NODE_CLIENT_STATE_ERROR: return "ERROR";
         case NODE_CLIENT_STATE_DISCONNECTED: return "DISCONNECTED";
-        case NODE_CLIENT_STATE_GET_NODE_ADDR: return "GET_NODE_ADDR";
-        case NODE_CLIENT_STATE_NODE_ADDR_LEASED: return "NODE_ADDR_LEASED";
         case NODE_CLIENT_STATE_PING: return "PING";
         case NODE_CLIENT_STATE_PONG: return "PONG";
         case NODE_CLIENT_STATE_CONNECTING: return "CONNECT";
         case NODE_CLIENT_STATE_ESTABLISHED: return "CONNECTED";
-        case NODE_CLIENT_STATE_SYNC_GDB: return "SYNC_GDB";
-        case NODE_CLIENT_STATE_SYNC_CHAINS: return "SYNC_CHAINS";
-        case NODE_CLIENT_STATE_SYNCED: return "SYNCED";
         case NODE_CLIENT_STATE_CHECKED: return "CHECKED";
         default: return "(Undefined node client state)";
     }
diff --git a/modules/net/include/dap_chain_node_dns_client.h b/modules/net/include/dap_chain_node_dns_client.h
index d43fb284851299641b19ddb76f13c7ca405726d8..5ab385243cd7cead3be6fbec35eb1beb49bcf307 100644
--- a/modules/net/include/dap_chain_node_dns_client.h
+++ b/modules/net/include/dap_chain_node_dns_client.h
@@ -39,7 +39,7 @@ typedef struct _dap_dns_buf_t {
 } dap_dns_buf_t;
 
 // node info request callbacks
-typedef void (*dap_dns_client_node_info_request_success_callback_t) (dap_worker_t *a_worker, dap_chain_net_node_balancer_t *a_result, void *a_arg);
+typedef void (*dap_dns_client_node_info_request_success_callback_t) (dap_worker_t *a_worker, dap_chain_net_links_t *a_result, void *a_arg);
 typedef void (*dap_dns_client_node_info_request_error_callback_t) (dap_worker_t *a_worker, void *a_arg, int a_errno);
 
 int dap_chain_node_info_dns_request(dap_worker_t *a_worker, struct in_addr a_addr, uint16_t a_port, char *a_name,
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn.c b/modules/service/vpn/dap_chain_net_srv_vpn.c
index 6c811059737fd1a8b382c9a30e83d2690f9823bd..f207fb10adf0b4256ecc0f81e1e69f9f0557d1c6 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn.c
@@ -81,7 +81,7 @@ typedef struct iphdr dap_os_iphdr_t;
 #include "dap_common.h"
 #include "dap_strfuncs.h"
 #include "dap_config.h"
-
+#include "dap_context.h"
 #include "dap_events_socket.h"
 #include "dap_http_client.h"
 
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 4ddb1393bfa7aa06423a6637f4b703245beeebf4..cac044c804aa681a8edac5d41f7c5713bca52ab4 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -636,12 +636,13 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void **a_str_reply)
         } break;
 
         case SUBCMD_NEW_COMPLETE:{
-            dap_chain_net_sync_all(l_net);
+            // TODO
         } break;
 
         case SUBCMD_DROP:{
-            dap_chain_net_sync_all(l_net);
+            // TODO
         }break;
+
         case SUBCMD_DUMP:{
             dap_chain_hash_fast_t l_block_hash={0};
             if (!l_subcmd_str_arg) {
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index e7cbf18eb304ad4eea20fc1c22b130a887381b94..b96a079e1fb1a84ce927556e34169561cae7949d 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -82,7 +82,6 @@ typedef struct dap_chain_cs_dag_pvt {
     dap_chain_cs_dag_event_item_t * events_treshold_conflicted;
     dap_chain_cs_dag_event_item_t * events_lasts_unlinked;
     dap_chain_cs_dag_blocked_t *removed_events_from_treshold;
-    dap_interval_timer_t mempool_timer;
     dap_interval_timer_t treshold_fee_timer;
     size_t tx_count;
 } dap_chain_cs_dag_pvt_t;
@@ -180,41 +179,6 @@ void dap_chain_cs_dag_deinit(void)
 
 }
 
-static void s_round_changes_notify(dap_store_obj_t *a_obj, void *a_arg)
-{
-    dap_chain_cs_dag_t *l_dag = (dap_chain_cs_dag_t *)a_arg;
-    assert(l_dag);
-    dap_chain_net_t *l_net = dap_chain_net_by_id(l_dag->chain->net_id);
-    debug_if(s_debug_more, L_DEBUG, "%s.%s: op_code='%c' group=\"%s\" key=\"%s\" value_size=%zu",
-        l_net->pub.name, l_dag->chain->name, a_obj->type, a_obj->group, a_obj->key, a_obj->value_len);
-    if (a_obj->type == DAP_GLOBAL_DB_OPTYPE_ADD && l_dag->callback_cs_event_round_sync) {
-        if (dap_strcmp(a_obj->key, DAG_ROUND_CURRENT_KEY))  // check key for round increment, if no than process event
-            l_dag->callback_cs_event_round_sync(l_dag, a_obj->type, a_obj->group, a_obj->key, a_obj->value, a_obj->value_len);
-        else
-            log_it(L_INFO, "Global round ID: %lu", *(uint64_t*)a_obj->value);
-    }
-}
-
-static bool s_dag_rounds_events_iter(dap_global_db_instance_t *a_dbi,
-                                     int a_rc, const char *a_group,
-                                     const size_t a_values_current, const size_t a_values_count,
-                                     dap_store_obj_t *a_values, void *a_arg)
-{
-    dap_return_val_if_pass(a_rc == DAP_GLOBAL_DB_RC_ERROR, false);
-
-    for (size_t i = 0; i < a_values_count; i++) {
-        dap_store_obj_t *l_obj_cur = a_values + i;
-        l_obj_cur->type = DAP_GLOBAL_DB_OPTYPE_ADD;
-        s_round_changes_notify(a_values + i, a_arg);
-    }
-    return true;
-}
-
-static void s_timer_process_callback(void *a_arg)
-{
-    dap_chain_node_mempool_process_all((dap_chain_t *)a_arg, false);
-}
-
 /**
  * @brief s_chain_cs_dag_new
  * @param a_chain
@@ -313,28 +277,10 @@ static int s_chain_cs_dag_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
     dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
     l_dag->gdb_group_events_round_new = dap_strdup_printf(l_dag->is_celled ? "dag-%s-%s-%016llx-round.new" : "dag-%s-%s-round.new",
                                           l_net->pub.gdb_groups_prefix, a_chain->name, 0LLU);
-    dap_global_db_cluster_t *l_dag_cluster = dap_global_db_cluster_add(dap_global_db_instance_get_default(), NULL,
-                                                                       dap_cluster_guuid_compose(l_net->pub.id.uint64, DAP_CHAIN_CLUSTER_ID_DAG),
-                                                                       l_dag->gdb_group_events_round_new, 900, true,
-                                                                       DAP_GDB_MEMBER_ROLE_NOBODY, DAP_CLUSTER_ROLE_AUTONOMIC);
-    dap_global_db_cluster_add_notify_callback(l_dag_cluster, s_round_changes_notify, l_dag);
-    dap_chain_net_add_poa_certs_to_cluster(l_net, l_dag_cluster);
-    byte_t *l_current_round = dap_global_db_get_sync(l_dag->gdb_group_events_round_new, DAG_ROUND_CURRENT_KEY, NULL, NULL, NULL);
-    l_dag->round_current = l_current_round ? *(uint64_t*)l_current_round : 0;
-    DAP_DELETE(l_current_round);
-    debug_if(s_debug_more, L_INFO, "Current round id %"DAP_UINT64_FORMAT_U, l_dag->round_current);
-
-    dap_global_db_get_all_raw(l_dag->gdb_group_events_round_new, 0, 0, s_dag_rounds_events_iter, l_dag);
-
-
-    PVT(l_dag)->mempool_timer = dap_interval_timer_create(15000, s_timer_process_callback, a_chain);
-    PVT(l_dag)->events_treshold = NULL;
-    PVT(l_dag)->events_treshold_conflicted = NULL;
+
     PVT(l_dag)->treshold_fee_timer = dap_interval_timer_create(900000, (dap_timer_callback_t)s_dap_chain_cs_dag_threshold_free, l_dag);
-    if (l_dag->is_single_line)
-        log_it (L_NOTICE, "DAG chain initialized (single line)");
-    else
-        log_it (L_NOTICE, "DAG chain initialized (multichain)");
+
+    log_it (L_NOTICE, "DAG chain initialized (%s)", l_dag->is_single_line ? "single line" : "multichain");
 
     return 0;
 }
@@ -344,7 +290,7 @@ static void s_dap_chain_cs_dag_threshold_free(dap_chain_cs_dag_t *a_dag) {
     dap_chain_cs_dag_event_item_t *l_current = NULL, *l_tmp = NULL;
     dap_nanotime_t  l_time_cut_off = dap_nanotime_now() - dap_nanotime_from_sec(7200); //7200 sec = 2 hours.
     pthread_mutex_lock(&l_pvt->events_mutex);
-    //Fee treshold
+    //Free threshold
     HASH_ITER(hh, l_pvt->events_treshold, l_current, l_tmp) {
         if (l_current->ts_added < l_time_cut_off) {
             dap_chain_cs_dag_blocked_t *l_el = DAP_NEW(dap_chain_cs_dag_blocked_t);
@@ -414,7 +360,6 @@ static void s_chain_cs_dag_delete(dap_chain_t * a_chain)
     s_dap_chain_cs_dag_purge(a_chain);
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG ( a_chain );
     pthread_mutex_destroy(& PVT(l_dag)->events_mutex);
-    dap_interval_timer_delete(PVT(l_dag)->mempool_timer);
     if(l_dag->callback_delete )
         l_dag->callback_delete(l_dag);
     if(l_dag->_inheritor)
diff --git a/modules/type/dag/include/dap_chain_cs_dag.h b/modules/type/dag/include/dap_chain_cs_dag.h
index 3db39941b26ddfdf6b2c8a0069c9bf08602bb101..3a55ab0341d763f3cb8e78577322ccfca2ed07cc 100644
--- a/modules/type/dag/include/dap_chain_cs_dag.h
+++ b/modules/type/dag/include/dap_chain_cs_dag.h
@@ -69,7 +69,6 @@ typedef struct dap_chain_cs_dag
     dap_chain_cs_dag_callback_t callback_delete;
     dap_chain_cs_dag_callback_event_create_t callback_cs_event_create;
     dap_chain_cs_dag_callback_event_t callback_cs_verify;
-    dap_chain_cs_dag_callback_event_round_sync_t callback_cs_event_round_sync;
 
     void * _pvt;
     void * _inheritor;
diff --git a/modules/type/none/dap_chain_cs_none.c b/modules/type/none/dap_chain_cs_none.c
index 67484a00d4248d3b8a7af8a4c9f4c169a7857692..3becb81be5b269413a830790106313ae4f1f3c58 100644
--- a/modules/type/none/dap_chain_cs_none.c
+++ b/modules/type/none/dap_chain_cs_none.c
@@ -163,7 +163,7 @@ static int s_cs_callback_new(dap_chain_t *a_chain, dap_config_t UNUSED_ARG *a_ch
     // Add group prefix that will be tracking all changes
     dap_global_db_cluster_t *l_nonconsensus_cluster =
             dap_global_db_cluster_add(dap_global_db_instance_get_default(),
-                                      l_net->pub.name, dap_cluster_guuid_compose(l_net->pub.id.uint64, 0),
+                                      l_net->pub.name, dap_guuid_compose(l_net->pub.id.uint64, 0),
                                       l_nochain_priv->group_datums, 0,
                                       true, DAP_GDB_MEMBER_ROLE_USER, DAP_CLUSTER_ROLE_EMBEDDED);
     if (!l_nonconsensus_cluster) {