From 2e1fd2bf7c7bb33b6a09b14a8606950e894a0258 Mon Sep 17 00:00:00 2001
From: "roman.padenkov" <roman.padenkov@demlabs.net>
Date: Wed, 9 Aug 2023 07:03:09 +0000
Subject: [PATCH] Hotfix 9279

---
 modules/net/dap_chain_net.c                   | 174 +++++++++++-------
 modules/net/dap_chain_net_balancer.c          | 104 +++++++----
 modules/net/dap_chain_node_dns_client.c       |   6 +-
 modules/net/include/dap_chain_net_balancer.h  |   6 +-
 modules/net/include/dap_chain_node.h          |   3 +-
 .../net/include/dap_chain_node_dns_client.h   |   3 +-
 6 files changed, 187 insertions(+), 109 deletions(-)

diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 087e12b123..a2411e2e20 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -281,7 +281,7 @@ static bool s_new_balancer_link_request(dap_chain_net_t *a_net, int a_link_repla
 static void s_update_links_timer_callback(void *a_arg){
     dap_chain_net_t *l_net = (dap_chain_net_t*)a_arg;
     //Updated links
-    size_t l_count_downlinks = 0;
+    size_t l_count_downlinks = 0,l_blocks_events = 0;
     dap_stream_connection_t ** l_downlinks = dap_stream_connections_get_downlinks(&l_count_downlinks);
     DAP_DEL_Z(l_downlinks);
     dap_chain_node_addr_t *l_current_addr = dap_chain_net_get_cur_addr(l_net);
@@ -289,6 +289,12 @@ static void s_update_links_timer_callback(void *a_arg){
     if (!l_node_info)
         return;
     l_node_info->hdr.links_number = l_count_downlinks;
+    dap_chain_t *l_chain;
+    DL_FOREACH(l_net->pub.chains, l_chain) {
+        if(l_chain->callback_count_atom)
+            l_blocks_events += l_chain->callback_count_atom(l_chain);
+    }
+    l_node_info->hdr.blocks_events = l_blocks_events;
     char *l_key = dap_chain_node_addr_to_hash_str(l_current_addr);
     dap_global_db_set_sync(l_net->pub.gdb_nodes, l_key, l_node_info, dap_chain_node_info_get_size(l_node_info), false);
     DAP_DELETE(l_node_info);
@@ -878,6 +884,10 @@ static void s_node_link_callback_disconnected(dap_chain_node_client_t *a_node_cl
     if (l_net_pvt->state_target != NET_STATE_OFFLINE) {
         pthread_mutex_lock(&l_net_pvt->uplinks_mutex);
         s_net_link_remove(l_net_pvt, a_node_client, l_net_pvt->only_static_links);
+        char *l_key = dap_chain_node_addr_to_hash_str(&a_node_client->info->hdr.address);
+        dap_global_db_del_sync(l_net->pub.gdb_nodes, l_key);
+        DAP_DELETE(l_key);
+        log_it(L_DEBUG, "Remove "NODE_ADDR_FP_STR" from local db",NODE_ADDR_FP_ARGS_S(a_node_client->info->hdr.address));
         a_node_client->keep_connection = false;
         a_node_client->callbacks.delete = NULL;
         dap_chain_node_client_close_mt(a_node_client);  // Remove it on next context iteration
@@ -889,13 +899,8 @@ static void s_node_link_callback_disconnected(dap_chain_node_client_t *a_node_cl
         }
         if (!l_net_pvt->only_static_links) {
             size_t l_current_links_prepared = HASH_COUNT(l_net_pvt->net_links);
-            for (size_t i = l_current_links_prepared; i < l_net_pvt->max_links_count ; i++) {
-                dap_chain_node_info_t *l_link_node_info = dap_get_balancer_link_from_cfg(l_net);
-                if (l_link_node_info) {
-                    if (!s_new_balancer_link_request(l_net, 1))
-                        log_it(L_ERROR, "Can't process node info balancer request");
-                    DAP_DELETE(l_link_node_info);
-                }
+            for (size_t i = l_current_links_prepared; i < l_net_pvt->max_links_count ; i++) {                
+                s_new_balancer_link_request(l_net, 0);
             }
         }
         pthread_mutex_unlock(&l_net_pvt->uplinks_mutex);
@@ -1010,53 +1015,72 @@ static void s_net_links_complete_and_start(dap_chain_net_t *a_net, dap_worker_t
  * @param a_node_info
  * @param a_arg
  */
-static void s_net_balancer_link_prepare_success(dap_worker_t * a_worker, dap_chain_node_info_t * a_node_info, void * 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)
 {
     if(s_debug_more){
         char l_node_addr_str[INET_ADDRSTRLEN]={};
-        inet_ntop(AF_INET,&a_node_info->hdr.ext_addr_v4,l_node_addr_str, INET_ADDRSTRLEN);
-        log_it(L_DEBUG,"Link " NODE_ADDR_FP_STR " (%s) prepare success", NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address),
-                                                                                     l_node_addr_str );
+        dap_chain_node_info_t * l_node_info = (dap_chain_node_info_t *)a_link_full_node_list->nodes_info;
+        for(size_t i=0;i<a_link_full_node_list->count_node;i++){
+            inet_ntop(AF_INET,&(l_node_info + i)->hdr.ext_addr_v4,l_node_addr_str, INET_ADDRSTRLEN);
+            log_it(L_DEBUG,"Link " NODE_ADDR_FP_STR " (%s) prepare success", NODE_ADDR_FP_ARGS_S((l_node_info + i)->hdr.address),
+                                                                                         l_node_addr_str );
+        }
     }
 
     struct balancer_link_request *l_balancer_request = (struct balancer_link_request *) a_arg;
     dap_chain_net_t * l_net = l_balancer_request->net;
-    int l_res = s_net_link_add(l_net, a_node_info);
-    if (l_res < 0) {    // Can't add this link
-        debug_if(s_debug_more, L_DEBUG, "Can't add link "NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address));
-        if (l_balancer_request->link_replace_tries)
-            // Just try a new one
-            s_new_balancer_link_request(l_net, l_balancer_request->link_replace_tries);
-    } else if (l_res == 0) {
-        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)
-                     , "Link " NODE_ADDR_FP_STR " prepared"
-                     , NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address));
-        json_object_object_add(l_json, "errorMessage", json_object_new_string(l_err_str));
-        dap_notify_server_send_mt(json_object_get_string(l_json));
-        json_object_put(l_json);
-        debug_if(s_debug_more, L_DEBUG, "Link "NODE_ADDR_FP_STR" successfully added",
-                                               NODE_ADDR_FP_ARGS_S(a_node_info->hdr.address));
-        if (l_balancer_request->link_replace_tries &&
-                s_net_get_active_links_count(l_net) < PVT(l_net)->required_links_count) {
-            // Auto-start new link
-            pthread_rwlock_rdlock(&PVT(l_net)->states_lock);
-            if (PVT(l_net)->state_target != NET_STATE_OFFLINE) {
-                struct net_link *l_new_link = s_net_link_find(l_net, a_node_info);
-                if (l_new_link)
-                    s_net_link_start(l_net, l_new_link, PVT(l_net)->reconnect_delay);
-                else
-                    s_new_balancer_link_request(l_net, l_balancer_request->link_replace_tries);
-            }
-            pthread_rwlock_unlock(&PVT(l_net)->states_lock);
+    dap_chain_node_info_t * l_node_info = (dap_chain_node_info_t *)a_link_full_node_list->nodes_info;
+    int l_res = 0;
+    size_t i = 0;
+    char l_err_str[128] = { };
+    struct json_object *l_json;
+    while(!l_res){
+        if(i >= a_link_full_node_list->count_node)
+            break;
+        l_res = s_net_link_add(l_net, l_node_info + i);
+        switch (l_res) {
+        case 0:
+            l_json = s_net_states_json_collect(l_net);
+
+            snprintf(l_err_str, sizeof(l_err_str)
+                         , "Link " NODE_ADDR_FP_STR " prepared"
+                         , NODE_ADDR_FP_ARGS_S((l_node_info + i)->hdr.address));
+            json_object_object_add(l_json, "errorMessage", json_object_new_string(l_err_str));
+            dap_notify_server_send_mt(json_object_get_string(l_json));
+            json_object_put(l_json);
+            debug_if(s_debug_more, L_DEBUG, "Link "NODE_ADDR_FP_STR" successfully added",
+                                                   NODE_ADDR_FP_ARGS_S((l_node_info + i)->hdr.address));
+            break;
+        case 1:
+            debug_if(s_debug_more, L_DEBUG, "Maximum prepared links reached");
+            break;
+        case -1:
+
+            break;
+        default:
+            break;
         }
-    } else
-        debug_if(s_debug_more, L_DEBUG, "Maximum prepared links reached");
+        i++;
+    }
+    if (l_balancer_request->link_replace_tries &&
+            s_net_get_active_links_count(l_net) < PVT(l_net)->required_links_count) {
+        // Auto-start new link
+        pthread_rwlock_rdlock(&PVT(l_net)->states_lock);
+        if (PVT(l_net)->state_target != NET_STATE_OFFLINE) {
+            struct net_link *l_free_link = s_get_free_link(l_net);
+            if (l_free_link)
+                s_net_link_start(l_net, l_free_link, PVT(l_net)->reconnect_delay);
+            else
+                s_new_balancer_link_request(l_net, l_balancer_request->link_replace_tries);
+        }
+        pthread_rwlock_unlock(&PVT(l_net)->states_lock);
+    }
+
     if (!l_balancer_request->link_replace_tries)
         s_net_links_complete_and_start(l_net, a_worker);
     DAP_DELETE(l_balancer_request->link_info);
     DAP_DELETE(l_balancer_request);
+
 }
 
 /**
@@ -1095,13 +1119,18 @@ static void s_net_balancer_link_prepare_error(dap_worker_t * a_worker, void * a_
 void s_net_http_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;
-    if (a_response_size != sizeof(dap_chain_node_info_t)) {
-        log_it(L_ERROR, "Invalid balancer response size %zu (expect %zu)", a_response_size, sizeof(dap_chain_node_info_t));
+    dap_chain_net_node_balancer_t* l_link_full_node_list = (dap_chain_net_node_balancer_t*)a_response;
+
+
+    size_t l_response_size_need = sizeof(dap_chain_net_node_balancer_t) + (sizeof(dap_chain_node_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);
         s_new_balancer_link_request(l_balancer_request->net, l_balancer_request->link_replace_tries);
         DAP_DELETE(l_balancer_request);
         return;
     }
-    s_net_balancer_link_prepare_success(l_balancer_request->worker, (dap_chain_node_info_t *)a_response, a_arg);
+    s_net_balancer_link_prepare_success(l_balancer_request->worker, l_link_full_node_list, a_arg);
 }
 
 void s_net_http_link_prepare_error(int a_error_code, void *a_arg)
@@ -1138,22 +1167,34 @@ static bool s_new_balancer_link_request(dap_chain_net_t *a_net, int a_link_repla
         return false;
     }
     if(!a_link_replace_tries){
-        dap_chain_node_info_t *l_link_full_node = dap_chain_net_balancer_get_node(a_net->pub.name);
-        if(l_link_full_node)
+        dap_chain_net_node_balancer_t *l_link_full_node_list = dap_chain_net_balancer_get_node(a_net->pub.name);
+        size_t node_cnt = 0,i = 0;        
+        if(l_link_full_node_list)
         {
+            dap_chain_node_info_t * l_node_info = (dap_chain_node_info_t *)l_link_full_node_list->nodes_info;
+            node_cnt = l_link_full_node_list->count_node;
             pthread_rwlock_rdlock(&PVT(a_net)->states_lock);
-            int l_net_link_add = s_net_link_add(a_net, l_link_full_node);
-            switch (l_net_link_add) {
-            case 0:
-                log_it(L_MSG, "Network LOCAL balancer issues link IP %s", inet_ntoa(l_link_full_node->hdr.ext_addr_v4));
-                break;
-            case -1:
-                log_it(L_MSG, "Network LOCAL balancer: IP %s is already among links", inet_ntoa(l_link_full_node->hdr.ext_addr_v4));
-                break;
-            default:
-                break;
+            int l_net_link_add = 0;
+            while(!l_net_link_add){
+                if(i >= node_cnt)
+                    break;
+                l_net_link_add = s_net_link_add(a_net, l_node_info + i);
+                switch (l_net_link_add) {
+                case 0:
+                    log_it(L_MSG, "Network LOCAL balancer issues link IP %s, [%ld blocks]", inet_ntoa((l_node_info + i)->hdr.ext_addr_v4),l_node_info->hdr.blocks_events);
+                    break;
+                case -1:
+                    log_it(L_MSG, "Network LOCAL balancer: IP %s is already among links", inet_ntoa((l_node_info + i)->hdr.ext_addr_v4));
+                    break;
+                case 1:
+                    log_it(L_MSG, "Network links table is full");
+                    break;
+                default:
+                    break;
+                }
+                i++;
             }
-            DAP_DELETE(l_link_full_node);
+            DAP_DELETE(l_link_full_node_list);
             struct net_link *l_free_link = s_get_free_link(a_net);
             if (l_free_link)
                 s_net_link_start(a_net, l_free_link, l_net_pvt->reconnect_delay);
@@ -1225,17 +1266,10 @@ static void s_prepare_links_from_balancer(dap_chain_net_t *a_net)
         return;
     }
     // Get list of the unique links for l_net
-    size_t l_max_links_count = PVT(a_net)->max_links_count * 2;   // Not all will be success
-    for (size_t l_cur_links_count = 0, n = 0; l_cur_links_count < l_max_links_count; n++) {
-        if (n > 1000) // It's a problem with link prepare
-            break;
-        dap_chain_node_info_t *l_link_node_info = dap_get_balancer_link_from_cfg(a_net);
-        if (!l_link_node_info)
-            continue;
-        // Start connect to link hubs
-        s_new_balancer_link_request(a_net, 0);
-        l_cur_links_count++;
-        DAP_DEL_Z(l_link_node_info);
+    size_t l_max_links_count = PVT(a_net)->max_links_count;   // Not all will be success
+    for (size_t l_cur_links_count = 0, n = 0; n < 100 && l_cur_links_count < l_max_links_count; ++n) {
+        if (s_new_balancer_link_request(a_net, 0))
+            l_cur_links_count++;
     }
 }
 
diff --git a/modules/net/dap_chain_net_balancer.c b/modules/net/dap_chain_net_balancer.c
index be492b63b2..e051bdb328 100644
--- a/modules/net/dap_chain_net_balancer.c
+++ b/modules/net/dap_chain_net_balancer.c
@@ -27,35 +27,55 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 #include "http_status_code.h"
 
 #define LOG_TAG "dap_chain_net_balancer"
-dap_chain_node_info_t *dap_chain_net_balancer_get_node(const char *a_net_name)
+
+static int callback_compare_node_list(const void * a_item1, const void * a_item2, void *a_unused)
+{
+    UNUSED(a_unused);
+    if (!a_item1 || !a_item2) {
+        return 0;
+    }
+    dap_chain_node_info_t *l_item1 = (dap_chain_node_info_t*)a_item1, *l_item2 = (dap_chain_node_info_t*)a_item2;
+    return l_item1->hdr.links_number == l_item2->hdr.links_number
+            ? 0 : l_item1->hdr.links_number > l_item2->hdr.links_number
+              ? 1 : -1;
+}
+
+dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node(const char *a_net_name)
 {
     dap_list_t *l_node_addr_list = NULL,*l_objs_list = NULL;
     dap_chain_net_t *l_net = dap_chain_net_by_name(a_net_name);
     if (l_net == NULL) {
-        uint16_t l_nets_count;
-        dap_chain_net_t **l_nets = dap_chain_net_list(&l_nets_count);
-        if (!l_nets_count) {
-            log_it(L_WARNING, "No chain network present");
-            return NULL;
-        }
-        l_net = l_nets[rand() % l_nets_count];
+        log_it(L_WARNING, "There isn't any network by this name - %s", a_net_name);
+        return NULL;
     }
     // get nodes list from global_db
     dap_global_db_obj_t *l_objs = NULL;
-    size_t l_nodes_count = 0, l_nodes_selected_count = 0;
+    size_t l_nodes_count = 0;
     size_t l_node_num = 0;
+    uint64_t l_blocks_events = 0;
     // read all node
     l_objs = dap_global_db_get_all_sync(l_net->pub.gdb_nodes, &l_nodes_count);
     if (!l_nodes_count || !l_objs)
         return NULL;
     l_node_addr_list = dap_chain_net_get_node_list_cfg(l_net);
-    for(size_t i=0;i<l_nodes_count;i++)
+    for (size_t i = 0; i < l_nodes_count; i++) {
+        dap_chain_node_info_t *l_node_cand = (dap_chain_node_info_t *)l_objs[i].value;
+        for (dap_list_t *node_i = l_node_addr_list; node_i; node_i = node_i->next) {
+            if(((struct in_addr*)node_i->data)->s_addr == l_node_cand->hdr.ext_addr_v4.s_addr) {
+                if (!l_blocks_events || l_blocks_events > l_node_cand->hdr.blocks_events)
+                    l_blocks_events = l_node_cand->hdr.blocks_events;
+                break;
+            }
+        }
+    }
+    log_it(L_DEBUG, "The smallest block size among seed nodes is - %ld", l_blocks_events);
+    for (size_t i = 0; i < l_nodes_count; i++)
     {
         bool l_check = true;
+        dap_chain_node_info_t *l_node_cand = (dap_chain_node_info_t *)l_objs[i].value;
         for(dap_list_t *node_i = l_node_addr_list; node_i; node_i = node_i->next)
         {
-            struct in_addr *l_node_addr_cfg = (struct in_addr*)node_i->data;
-            dap_chain_node_info_t *l_node_cand = (dap_chain_node_info_t *)l_objs[i].value;
+            struct in_addr *l_node_addr_cfg = (struct in_addr*)node_i->data;            
             if(l_node_cand->hdr.ext_addr_v4.s_addr && l_node_cand->hdr.ext_port &&
                 (l_node_addr_cfg->s_addr != l_node_cand->hdr.ext_addr_v4.s_addr))
             {
@@ -68,27 +88,31 @@ dap_chain_node_info_t *dap_chain_net_balancer_get_node(const char *a_net_name)
             }
         }
         if(l_check){
-            l_objs_list = dap_list_append(l_objs_list,l_objs[i].value);
-            l_node_num++;
+            if(l_node_cand->hdr.blocks_events >= l_blocks_events){
+                l_objs_list = dap_list_append(l_objs_list,l_objs[i].value);
+                l_node_num++;
+            }
         }
     }
     dap_list_free(l_node_addr_list);
-    l_nodes_selected_count = l_node_num;
+    l_objs_list = dap_list_sort(l_objs_list, callback_compare_node_list);
     dap_chain_node_info_t *l_node_candidate;
-    if(l_nodes_selected_count)
+    if(l_node_num)
     {
-        l_node_num = rand() % l_nodes_selected_count;
-        l_node_candidate = (dap_chain_node_info_t*)dap_list_nth_data(l_objs_list, l_node_num);
-        dap_chain_node_info_t *l_node_info = DAP_NEW_Z(dap_chain_node_info_t);
-        if (!l_node_info) {
-            log_it(L_ERROR, "Memory allocation error in %s, line %d", __PRETTY_FUNCTION__, __LINE__);
-            dap_list_free(l_objs_list);
-            return NULL;
+
+        dap_chain_net_node_balancer_t *l_node_list_res = DAP_NEW_Z_SIZE(dap_chain_net_node_balancer_t,
+                   sizeof(dap_chain_net_node_balancer_t) + l_node_num * sizeof(dap_chain_node_info_t));
+        dap_chain_node_info_t * l_node_info = (dap_chain_node_info_t *)l_node_list_res->nodes_info;
+        dap_list_t *nl = l_objs_list;
+        for(size_t i=0; i<l_node_num; i++,nl = nl->next)
+        {
+            l_node_candidate = (dap_chain_node_info_t*)nl->data;
+            *(l_node_info + i) = *l_node_candidate;
         }
-        memcpy(l_node_info, l_node_candidate, sizeof(dap_chain_node_info_t));
+        l_node_list_res->count_node = l_node_num;
         dap_list_free(l_objs_list);
         dap_global_db_objs_delete(l_objs, l_nodes_count);
-        return l_node_info;
+        return l_node_list_res;
     }
     else
     {
@@ -99,14 +123,19 @@ dap_chain_node_info_t *dap_chain_net_balancer_get_node(const char *a_net_name)
     }
 }
 
-dap_chain_node_info_t *s_balancer_issue_link(const char *a_net_name)
+dap_chain_net_node_balancer_t *s_balancer_issue_link(const char *a_net_name)
 {
     dap_chain_net_t *l_net = dap_chain_net_by_name(a_net_name);
-    dap_chain_node_info_t *l_node_candidate = dap_chain_net_balancer_get_node(a_net_name);
-    if(l_node_candidate)
+    dap_chain_net_node_balancer_t *l_link_full_node_list = dap_chain_net_balancer_get_node(a_net_name);
+    if(l_link_full_node_list)
     {
-        log_it(L_DEBUG, "Network balancer issues ip %s",inet_ntoa(l_node_candidate->hdr.ext_addr_v4));
-        return l_node_candidate;
+        dap_chain_node_info_t * l_node_info = (dap_chain_node_info_t *)l_link_full_node_list->nodes_info;
+        for(size_t i=0;i<l_link_full_node_list->count_node;i++)
+        {
+            log_it(L_DEBUG, "Network balancer issues ip %s, [%ld blocks]",inet_ntoa((l_node_info + i)->hdr.ext_addr_v4),l_node_info->hdr.blocks_events);
+
+        }
+        return l_link_full_node_list;
     }
     else
     {
@@ -114,7 +143,11 @@ dap_chain_node_info_t *s_balancer_issue_link(const char *a_net_name)
         if(l_link_node_info)
         {          
             log_it(L_DEBUG, "Network balancer issues ip from net conf - %s",inet_ntoa(l_link_node_info->hdr.ext_addr_v4));
-            return l_link_node_info;
+            dap_chain_net_node_balancer_t * l_node_list_res = DAP_NEW_Z_SIZE(dap_chain_net_node_balancer_t,
+                                                                             sizeof(dap_chain_net_node_balancer_t) + sizeof(dap_chain_node_info_t));
+            l_node_list_res->count_node = 1;
+            *(dap_chain_node_info_t*)l_node_list_res->nodes_info = *l_link_node_info;
+            return l_node_list_res;
         }
     }
     return NULL;
@@ -151,15 +184,16 @@ void dap_chain_net_balancer_http_issue_link(dap_http_simple_t *a_http_simple, vo
     char l_net_name[128] = {};
     strncpy(l_net_name, l_net_str, 127);
     log_it(L_DEBUG, "HTTP balancer parser retrieve netname %s", l_net_name);
-    dap_chain_node_info_t *l_node_info = s_balancer_issue_link(l_net_name);
-    if (!l_node_info) {
+    dap_chain_net_node_balancer_t *l_link_full_node_list = s_balancer_issue_link(l_net_name);
+    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;
         return;
     }
     *l_return_code = Http_Status_OK;
-    dap_http_simple_reply(a_http_simple, l_node_info, sizeof(*l_node_info));
-    DAP_DELETE(l_node_info);
+    size_t l_data_send_size = sizeof(size_t) + (sizeof(dap_chain_node_info_t) * l_link_full_node_list->count_node);
+    dap_http_simple_reply(a_http_simple, l_link_full_node_list, l_data_send_size);
+    DAP_DELETE(l_link_full_node_list);
 }
 
 /**
diff --git a/modules/net/dap_chain_node_dns_client.c b/modules/net/dap_chain_node_dns_client.c
index 89cce74296..0f1460e8a2 100644
--- a/modules/net/dap_chain_node_dns_client.c
+++ b/modules/net/dap_chain_node_dns_client.c
@@ -85,6 +85,7 @@ 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_chain_node_info_t l_result = {};
     l_result.hdr.ext_addr_v4.s_addr = ntohl(*(uint32_t *)l_cur);
     l_cur = l_buf + 5 * sizeof(uint16_t);
@@ -95,8 +96,10 @@ static void s_dns_client_esocket_read_callback(dap_events_socket_t * a_esocket,
         l_cur += sizeof(uint16_t);
         l_result.hdr.address.uint64 = be64toh(*(uint64_t *)l_cur);
     }
+    *(dap_chain_node_info_t*)l_link_full_node_list.nodes_info = l_result;
+    l_link_full_node_list.count_node = 1;
 
-    l_dns_client->callback_success(a_esocket->context->worker ,&l_result, l_dns_client->callbacks_arg);
+    l_dns_client->callback_success(a_esocket->context->worker ,&l_link_full_node_list, l_dns_client->callbacks_arg);
     l_dns_client->is_callbacks_called = true;
     a_esocket->flags |= DAP_SOCK_SIGNAL_CLOSE;
     a_esocket->buf_in_size = a_esocket->buf_out_size = 0;
@@ -211,6 +214,7 @@ int dap_chain_node_info_dns_request(dap_worker_t *a_worker, struct in_addr a_add
     dap_dns_buf_init(&l_dns_client->dns_request, (char *)l_dns_client->buf);
     dap_dns_buf_put_uint16(&l_dns_client->dns_request, rand() % 0xFFFF);    // ID
 
+
     dap_dns_message_flags_t l_flags = {};
     dap_dns_buf_put_uint16(&l_dns_client->dns_request, l_flags.val);
     dap_dns_buf_put_uint16(&l_dns_client->dns_request, 1);                  // we have only 1 question
diff --git a/modules/net/include/dap_chain_net_balancer.h b/modules/net/include/dap_chain_net_balancer.h
index 5390af1a5d..1a3d21134e 100644
--- a/modules/net/include/dap_chain_net_balancer.h
+++ b/modules/net/include/dap_chain_net_balancer.h
@@ -27,7 +27,11 @@ along with any CellFrame SDK based project.  If not, see <http://www.gnu.org/lic
 #include "dap_http_simple.h"
 
 #define DAP_BALANCER_URI_HASH "f0intlt4eyl03htogu"
+typedef struct dap_chain_net_node_balancer {
+    size_t count_node;
+    byte_t nodes_info[];
+} dap_chain_net_node_balancer_t;
 
 void dap_chain_net_balancer_http_issue_link(dap_http_simple_t *a_http_simple, void *a_arg);
 dap_chain_node_info_t *dap_chain_net_balancer_dns_issue_link(char *a_str);
-dap_chain_node_info_t *dap_chain_net_balancer_get_node(const char *a_net_name);
+dap_chain_net_node_balancer_t *dap_chain_net_balancer_get_node(const char *a_net_name);
diff --git a/modules/net/include/dap_chain_node.h b/modules/net/include/dap_chain_node.h
index ff1ace8a76..3d14e6d7b4 100644
--- a/modules/net/include/dap_chain_node.h
+++ b/modules/net/include/dap_chain_node.h
@@ -74,7 +74,8 @@ typedef struct dap_chain_node_info {
         struct in_addr ext_addr_v4;
         struct in6_addr ext_addr_v6;
         uint16_t ext_port; // Port thats node listening
-        char alias[256];
+        char alias[248];
+        uint64_t blocks_events; /* truncated alias len */
     } DAP_ALIGN_PACKED hdr;
     dap_chain_node_addr_t links[]; // dap_chain_addr_t
 } DAP_ALIGN_PACKED dap_chain_node_info_t;
diff --git a/modules/net/include/dap_chain_node_dns_client.h b/modules/net/include/dap_chain_node_dns_client.h
index aee9ec1293..9c62b5443e 100644
--- a/modules/net/include/dap_chain_node_dns_client.h
+++ b/modules/net/include/dap_chain_node_dns_client.h
@@ -28,6 +28,7 @@
 #include <stdint.h>
 #include "dap_worker.h"
 #include "dap_chain_node.h"
+#include "dap_chain_net_balancer.h"
 
 #define DNS_LISTEN_PORT 53      // UDP
 
@@ -37,7 +38,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_node_info_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_node_balancer_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,
-- 
GitLab