diff --git a/CMakeLists.txt b/CMakeLists.txt
index c3113a99696a3bdf36037847a2453a6e0ffc7bda..74b876a7d093222a9cfea8084edce25b35c53961 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,7 +11,7 @@ set(DAPSDK_MODULES "")
 if(NOT DEFINED CELLFRAME_MODULES)
     include (cmake/OS_Detection.cmake)
 
-    set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-block-ton cs-none srv-app srv-app-db srv-datum srv-stake-pos-delegate srv-stake-lock srv-xchange")
+    set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-esbocs cs-none srv-app srv-app-db srv-datum srv-stake-pos-delegate srv-stake-lock srv-xchange")
 
     if(LINUX OR DARWIN)
         set(CELLFRAME_MODULES "${CELLFRAME_MODULES} srv-vpn")
@@ -144,8 +144,8 @@ if (CELLFRAME_MODULES MATCHES "cs-dag-pos")
 endif()
 
 # Blocks based consensus(es)
-if (CELLFRAME_MODULES MATCHES "cs-block-" )
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_cs_dag)
+if (CELLFRAME_MODULES MATCHES "cs-block-" OR CELLFRAME_MODULES MATCHES "cs-esbocs")
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_cs_blocks)
 endif()
 
 # PoA consensus for blocks
@@ -161,9 +161,9 @@ if (CELLFRAME_MODULES MATCHES "cs-block-pos")
 endif()
 
 # TON consensus for blocks
-if (CELLFRAME_MODULES MATCHES "cs-block-ton")
-    message("[+] Module 'cs-block-ton'")
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_cs_block_ton)
+if (CELLFRAME_MODULES MATCHES "cs-esbocs")
+    message("[+] Module 'cs-esbocs'")
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_cs_esbocs)
 endif()
 
 # PoW consensus for blocks
diff --git a/dap-sdk b/dap-sdk
index 6551148098209cc9237f67453205271a74802d06..2fa175608533db70a74d61ab1ed57edd85a01607 160000
--- a/dap-sdk
+++ b/dap-sdk
@@ -1 +1 @@
-Subproject commit 6551148098209cc9237f67453205271a74802d06
+Subproject commit 2fa175608533db70a74d61ab1ed57edd85a01607
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
index 5b2c9751855e2352bf26fe28f0ef0a2926c16a69..66cf900cedd7d54bc315393c4e688bf87bab22a4 100644
--- a/modules/CMakeLists.txt
+++ b/modules/CMakeLists.txt
@@ -67,8 +67,8 @@ if (CELLFRAME_MODULES MATCHES "cs-block-pos")
 endif()
 
 # Block TON
-if (CELLFRAME_MODULES MATCHES "cs-block-ton")
-    add_subdirectory(consensus/block-ton)
+if (CELLFRAME_MODULES MATCHES "cs-esbocs")
+    add_subdirectory(consensus/esbocs)
 endif()
 
 # Block PoW
diff --git a/modules/chain/dap_chain.c b/modules/chain/dap_chain.c
index 27dd828169b151dd3dd2227f95182c1f1d71096c..760e8acb6bebb635c7d3b138dfcb10c5ad099ad5 100644
--- a/modules/chain/dap_chain.c
+++ b/modules/chain/dap_chain.c
@@ -411,8 +411,8 @@ dap_chain_t * dap_chain_load_from_cfg(dap_ledger_t* a_ledger, const char * a_cha
             }
 
             l_chain =  dap_chain_create(a_ledger,a_chain_net_name,l_chain_name, a_chain_net_id,l_chain_id);
-            if ( dap_chain_cs_create(l_chain, l_cfg) == 0 )
-			{
+            if ( dap_chain_cs_create(l_chain, l_cfg) == 0 ) {
+
                 log_it (L_NOTICE, "Consensus initialized for chain id 0x%016"DAP_UINT64_FORMAT_x, l_chain_id.uint64);
 
                 if ( dap_config_get_item_path_default(l_cfg , "files","storage_dir",NULL ) )
diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index eaec9d67130994307fd2d8b0d2f9d4fa1d87568c..67df1a73f05bb5cce3e1b75e88ae3b79800935b0 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -55,7 +55,7 @@
 #include "dap_config.h"
 #include "dap_cert.h"
 #include "dap_timerfd.h"
-#include "dap_chain_datum_tx_token.h"
+#include "dap_chain_datum_tx_in_ems.h"
 #include "dap_chain_datum_token.h"
 #include "dap_chain_mempool.h"
 #include "dap_global_db.h"
@@ -148,9 +148,9 @@ typedef struct dap_chain_ledger_tx_item {
         uint32_t n_outs;
         uint32_t n_outs_used;
         char token_ticker[DAP_CHAIN_TICKER_SIZE_MAX];
-        char padding[6];
+        byte_t padding[6];
         byte_t multichannel;
-        char pad[15];
+        byte_t pad[15];
         // TODO dynamically allocates the memory in order not to limit the number of outputs in transaction
         dap_chain_hash_fast_t tx_hash_spent_fast[MAX_OUT_ITEMS]; // spent outs list
     } DAP_ALIGN_PACKED cache_data;
diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index 70dbf5096e3298494db617e3704414ca9210c5e7..9dd0602837a6bcf97a4c029cbe1653cfc20b5c01 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -46,15 +46,14 @@ typedef const void * dap_chain_atom_ptr_t;
 
 // Atomic element iterator
 typedef struct dap_chain_atom_iter{
-    dap_chain_t * chain;
+    dap_chain_t *chain;
     dap_chain_atom_ptr_t cur;
     dap_chain_hash_fast_t *cur_hash;
     dap_chain_cell_id_t cell_id;
     bool with_treshold;
     bool found_in_treshold;
     size_t cur_size;
-    void * cur_item;
-    void * _inheritor;
+    void *cur_item;
 } dap_chain_atom_iter_t;
 
 
@@ -90,7 +89,7 @@ typedef dap_chain_atom_ptr_t * (*dap_chain_callback_atom_iter_get_atoms_t)(dap_c
 typedef size_t (*dap_chain_callback_add_datums_t)(dap_chain_t * , dap_chain_datum_t **, size_t );
 
 typedef dap_chain_atom_ptr_t (*dap_chain_callback_atom_iter_get_next_t)(dap_chain_atom_iter_t *  ,size_t*);
-typedef void (*dap_chain_callback_atom_iter_delete_t)(dap_chain_atom_iter_t *  );
+typedef void (*dap_chain_callback_atom_iter_delete_t)(dap_chain_atom_iter_t *);
 
 typedef void (*dap_chain_callback_notify_t)(void * a_arg, dap_chain_t *a_chain, dap_chain_cell_id_t a_id, void* a_atom, size_t a_atom_size); //change in chain happened
 
diff --git a/modules/chain/include/dap_chain_ledger.h b/modules/chain/include/dap_chain_ledger.h
index 340d5ba7a218db675d44c4cacc23fb08f9ff1d07..486450c5748ca22d8310bc9bd18dc563f62c850e 100644
--- a/modules/chain/include/dap_chain_ledger.h
+++ b/modules/chain/include/dap_chain_ledger.h
@@ -33,7 +33,7 @@
 #include "dap_chain_common.h"
 #include "dap_chain_datum_token.h"
 #include "dap_chain_datum_tx.h"
-#include "dap_chain_datum_tx_token.h"
+#include "dap_chain_datum_tx_in_ems.h"
 #include "dap_chain_datum_tx_items.h"
 
 typedef struct dap_ledger {
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 554f953ab4ac7f04eb42a87c3d2c9838eb8937cc..0d3229773f508e2e0ef155fb06d05d00832d4ca3 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
@@ -370,8 +370,8 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
         typedef dap_stream_ch_chain_net_srv_pkt_test_t pkt_test_t;
         pkt_test_t *l_request = (pkt_test_t*)l_ch_pkt->data;
         size_t l_request_size = l_request->data_size + sizeof(pkt_test_t);
-        if (l_ch_pkt->hdr.size != l_request_size) {
-            log_it(L_WARNING, "Wrong request size %u, must be %zu [pkt seq %"DAP_UINT64_FORMAT_U"]", l_ch_pkt->hdr.size, l_request_size, l_ch_pkt->hdr.seq_id);
+        if (l_ch_pkt->hdr.data_size != l_request_size) {
+            log_it(L_WARNING, "Wrong request size %u, must be %zu [pkt seq %"DAP_UINT64_FORMAT_U"]", l_ch_pkt->hdr.data_size, l_request_size, l_ch_pkt->hdr.seq_id);
             l_err.code = DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_WRONG_SIZE;
             dap_stream_ch_pkt_write_unsafe(a_ch, DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR, &l_err, sizeof(l_err));
             break;
@@ -406,29 +406,29 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
     } break; /* DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_REQUEST */
 
     case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_REQUEST: {
-        if (l_ch_pkt->hdr.size < sizeof(dap_stream_ch_chain_net_srv_pkt_request_hdr_t) ){
+        if (l_ch_pkt->hdr.data_size < sizeof(dap_stream_ch_chain_net_srv_pkt_request_hdr_t) ){
             log_it( L_WARNING, "Wrong request size, less than minimum");
             break;
         }
         dap_chain_net_srv_grace_t *l_grace = DAP_NEW_Z(dap_chain_net_srv_grace_t);
         // Parse the request
-        l_grace->request = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_request_t, l_ch_pkt->hdr.size);
-        memcpy(l_grace->request, l_ch_pkt->data, l_ch_pkt->hdr.size);
+        l_grace->request = DAP_NEW_Z_SIZE(dap_stream_ch_chain_net_srv_pkt_request_t, l_ch_pkt->hdr.data_size);
+        memcpy(l_grace->request, l_ch_pkt->data, l_ch_pkt->hdr.data_size);
         l_ch_chain_net_srv->srv_uid.uint64 = l_grace->request->hdr.srv_uid.uint64;
-        l_grace->request_size = l_ch_pkt->hdr.size;
+        l_grace->request_size = l_ch_pkt->hdr.data_size;
         l_grace->ch_uuid = a_ch->uuid;
         l_grace->stream_worker = a_ch->stream_worker;
         s_grace_period_control(l_grace);
     } break; /* DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_REQUEST */
 
     case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_RESPONSE: {
-         if (l_ch_pkt->hdr.size < sizeof(dap_chain_receipt_info_t)) {
-            log_it(L_ERROR, "Wrong sign response size, %u when expected at least %zu with smth", l_ch_pkt->hdr.size,
+         if (l_ch_pkt->hdr.data_size < sizeof(dap_chain_receipt_info_t)) {
+            log_it(L_ERROR, "Wrong sign response size, %u when expected at least %zu with smth", l_ch_pkt->hdr.data_size,
                    sizeof(dap_chain_receipt_info_t));
             break;
         }
         dap_chain_datum_tx_receipt_t * l_receipt = (dap_chain_datum_tx_receipt_t *) l_ch_pkt->data;
-        size_t l_receipt_size = l_ch_pkt->hdr.size;
+        size_t l_receipt_size = l_ch_pkt->hdr.data_size;
         dap_chain_net_srv_usage_t * l_usage= NULL, *l_tmp= NULL;
         bool l_is_found = false;
         pthread_mutex_lock(& l_srv_session->parent->mutex );        // TODO rework it with packet usage_id
@@ -593,13 +593,13 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
     } break;
 
     case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_DATA: {
-        if (l_ch_pkt->hdr.size < sizeof(dap_stream_ch_chain_net_srv_pkt_data_hdr_t) ){
+        if (l_ch_pkt->hdr.data_size < sizeof(dap_stream_ch_chain_net_srv_pkt_data_hdr_t) ){
             log_it( L_WARNING, "Wrong request size, less than minimum");
             break;
         }
         typedef dap_stream_ch_chain_net_srv_pkt_data_t pkt_t;
         pkt_t * l_pkt =(pkt_t *) l_ch_pkt->data;
-        size_t l_pkt_size = l_ch_pkt->hdr.size - sizeof(pkt_t);
+        size_t l_pkt_size = l_ch_pkt->hdr.data_size - sizeof(pkt_t);
         dap_chain_net_srv_t * l_srv = dap_chain_net_srv_get( l_pkt->hdr.srv_uid);
         dap_chain_net_srv_usage_t * l_usage = dap_chain_net_srv_usage_find_unsafe( l_srv_session, l_pkt->hdr.usage_id );
         // If service not found
@@ -625,12 +625,12 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch , void* a_arg)
     } break;
 
     case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR:{
-        if ( l_ch_pkt->hdr.size == sizeof (dap_stream_ch_chain_net_srv_pkt_error_t) ){
+        if ( l_ch_pkt->hdr.data_size == sizeof (dap_stream_ch_chain_net_srv_pkt_error_t) ){
             dap_stream_ch_chain_net_srv_pkt_error_t * l_err = (dap_stream_ch_chain_net_srv_pkt_error_t *) l_ch_pkt->data;
             log_it( L_NOTICE, "Remote responsed with error code 0x%08X", l_err->code );
             // TODO code for service client mode
         }else{
-            log_it(L_ERROR, "Wrong error response size, %u when expected %zu", l_ch_pkt->hdr.size,
+            log_it(L_ERROR, "Wrong error response size, %u when expected %zu", l_ch_pkt->hdr.data_size,
                    sizeof ( dap_stream_ch_chain_net_srv_pkt_error_t) );
         }
     } break;
diff --git a/modules/channel/chain-net/dap_stream_ch_chain_net.c b/modules/channel/chain-net/dap_stream_ch_chain_net.c
index a2994fe2d2ab42b5338d62105d1a70d4aed69755..a05b21284956e9c176313df51091e61b66335e85 100644
--- a/modules/channel/chain-net/dap_stream_ch_chain_net.c
+++ b/modules/channel/chain-net/dap_stream_ch_chain_net.c
@@ -226,9 +226,8 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
                                               l_ch_chain_net_pkt->hdr.net_id, l_err_str, strlen(l_err_str) + 1);
             dap_stream_ch_set_ready_to_write_unsafe(a_ch, true);
         }
-        //size_t l_ch_chain_net_pkt_data_size = (size_t) l_ch_pkt->hdr.size - sizeof (l_ch_chain_net_pkt->hdr);
         if (!l_error && l_ch_chain_net_pkt) {
-            size_t l_ch_chain_net_pkt_data_size = l_ch_pkt->hdr.size - sizeof(dap_stream_ch_chain_net_pkt_hdr_t);
+            size_t l_ch_chain_net_pkt_data_size = l_ch_pkt->hdr.data_size - sizeof(dap_stream_ch_chain_net_pkt_hdr_t);
             switch (l_ch_pkt->hdr.type) {
                 case DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_DBG: {
                     dap_stream_ch_chain_net_pkt_write(a_ch, DAP_STREAM_CH_CHAIN_NET_PKT_TYPE_PING,
diff --git a/modules/channel/chain-voting/CMakeLists.txt b/modules/channel/chain-voting/CMakeLists.txt
index 5c12a8e74d9b9c40fdadc2bc2508292125aae3c4..39d888157b65eb06e7e4a7629ca0a7025aa585fd 100644
--- a/modules/channel/chain-voting/CMakeLists.txt
+++ b/modules/channel/chain-voting/CMakeLists.txt
@@ -6,7 +6,7 @@ file(GLOB DAP_STREAM_CH_CHAIN_VOTING_HDRS include/*.h)
 
 add_library(${PROJECT_NAME} STATIC ${DAP_STREAM_CH_CHAIN_VOTING_SRCS} ${DAP_STREAM_CH_CHAIN_VOTING_HDRS})
 
-target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_stream dap_stream_ch dap_stream_ch_chain dap_chain_net)
+target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_stream dap_stream_ch dap_chain_net)
 
 
 target_include_directories(${PROJECT_NAME} INTERFACE .)
diff --git a/modules/channel/chain-voting/dap_stream_ch_chain_voting.c b/modules/channel/chain-voting/dap_stream_ch_chain_voting.c
index 22542e7b20ce4c3c5ba611f7be65afe3cc47cec3..ff82afac35a96cc372f94498bc101ab1a16ad911 100644
--- a/modules/channel/chain-voting/dap_stream_ch_chain_voting.c
+++ b/modules/channel/chain-voting/dap_stream_ch_chain_voting.c
@@ -8,85 +8,46 @@
 #include "dap_stream_ch_chain_voting.h"
 #include "dap_chain_net.h"
 #include "dap_client_pvt.h"
-
+#include "dap_proc_queue.h"
 #include "dap_chain_node_cli.h"
 
 #define LOG_TAG "dap_stream_ch_chain_voting"
 
-typedef struct voting_pkt_in_callback{
+struct voting_pkt_in_callback {
     void * arg;
-    voting_ch_callback_t packet_in_callback;
-} voting_pkt_in_callback_t;
-
-typedef struct voting_pkt_addr {
-    dap_chain_node_addr_t node_addr;
-    dap_stream_ch_chain_voting_pkt_t *voting_pkt;
-} voting_pkt_addr_t;
+    dap_chain_voting_ch_callback_t packet_in_callback;
+};
 
-typedef struct voting_pkt_items {
-    pthread_rwlock_t rwlock_out;
-    pthread_rwlock_t rwlock_in;
-    dap_list_t * pkts_out; // voting_pkt_addr_t
-    dap_list_t * pkts_in; // dap_stream_ch_chain_voting_pkt_t
-} voting_pkt_items_t;
-
-typedef struct voting_node_client_list {
+struct voting_node_client_list {
+    dap_chain_node_addr_t node_addr;    // HT key
     dap_chain_node_info_t *node_info;
     dap_chain_node_client_t *node_client;
-    dap_chain_node_addr_t node_addr;
     UT_hash_handle hh;
-} voting_node_client_list_t;
-
-static size_t s_pkt_in_callback_count = 0;
-static voting_pkt_in_callback_t s_pkt_in_callback[256]={{0}};
-static voting_pkt_items_t *s_pkt_items = NULL;
-static voting_node_client_list_t *s_node_client_list = NULL;
-
-static void s_callback_send_all_loopback(uint64_t a_node_addr);
-static void s_callback_send_all_unsafe(dap_client_t *a_client, void *a_arg);
-
-static void s_callback_send_all_unsafe(dap_client_t *a_client, void *a_arg);
-static void s_stream_ch_new(dap_stream_ch_t* a_ch, void* a_arg);
-static void s_stream_ch_delete(dap_stream_ch_t* a_ch, void* a_arg);
+};
 
-static void s_packet_in_callback_handler(void * a_arg);
-static void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg);
-static void s_stream_ch_packet_out(dap_stream_ch_t* a_ch, void* a_arg);
+static struct voting_node_client_list *s_node_client_list = NULL;
 
-static dap_interval_timer_t *s_packet_in_callback_timer = NULL;
-static bool s_is_inited = false;
+static size_t s_pkt_in_callback_count = 0;
+static struct voting_pkt_in_callback s_pkt_in_callback[16] = {};
 
-//static int s_cli_voting(int argc, char ** argv, char **a_str_reply);
+static void s_stream_ch_new(dap_stream_ch_t *a_ch, void *a_arg);
+static void s_stream_ch_delete(dap_stream_ch_t *a_ch, void *a_arg);
+static void s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg);
 
-int dap_stream_ch_chain_voting_init() {
+int dap_stream_ch_chain_voting_init()
+{
     log_it(L_NOTICE, "Chains voting channel initialized");
-    if (s_is_inited) {
-        return 0;
-    }
-
-    if (!s_pkt_items) {
-        s_pkt_items = DAP_NEW_Z(voting_pkt_items_t);
-        s_pkt_items->pkts_out = NULL;
-        s_pkt_items->pkts_in = NULL;
-        pthread_rwlock_init(&s_pkt_items->rwlock_out, NULL);
-        pthread_rwlock_init(&s_pkt_items->rwlock_in, NULL);
-    }
 
     dap_stream_ch_proc_add(dap_stream_ch_chain_voting_get_id(),
                            s_stream_ch_new,
                            s_stream_ch_delete,
                            s_stream_ch_packet_in,
-                           s_stream_ch_packet_out);
+                           NULL);
 
-    if (!s_packet_in_callback_timer) {
-        s_packet_in_callback_timer = dap_interval_timer_create(1000, s_packet_in_callback_handler, NULL);
-    }
-    s_is_inited = true;
-    // s_packet_in_callback_handler();
     return 0;
 }
 
-void dap_stream_ch_chain_voting_in_callback_add(void* a_arg, voting_ch_callback_t packet_in_callback)
+void dap_stream_ch_chain_voting_in_callback_add(void* a_arg, dap_chain_voting_ch_callback_t packet_in_callback)
 {
     size_t i = s_pkt_in_callback_count;
     s_pkt_in_callback[i].arg = a_arg;
@@ -94,250 +55,122 @@ void dap_stream_ch_chain_voting_in_callback_add(void* a_arg, voting_ch_callback_
     s_pkt_in_callback_count++;
 }
 
-void dap_stream_ch_chain_voting_message_write(dap_chain_net_t * a_net, dap_list_t *a_sendto_nodes,
-                                              dap_chain_hash_fast_t * a_data_hash,
-                                              const void * a_data, size_t a_data_size)
+static bool s_callback_pkt_in_call_all(UNUSED_ARG dap_proc_thread_t *a_thread, void *a_arg)
 {
-    dap_stream_ch_chain_voting_pkt_t * l_voting_pkt;
-    size_t l_voting_pkt_size = sizeof(l_voting_pkt->hdr) + a_data_size;
-    l_voting_pkt = DAP_NEW_SIZE(dap_stream_ch_chain_voting_pkt_t, l_voting_pkt_size );
-    l_voting_pkt->hdr.data_size = a_data_size;
-    memcpy( &l_voting_pkt->hdr.data_hash, a_data_hash, sizeof(dap_chain_hash_fast_t));
-    l_voting_pkt->hdr.pkt_type = DAP_STREAM_CH_CHAIN_VOTING_PKT_TYPE_TEST;
-    l_voting_pkt->hdr.version = 1;
-    l_voting_pkt->hdr.net_id.uint64 = a_net->pub.id.uint64;
-    if (a_data_size && a_data) {
-        memcpy( l_voting_pkt->data, a_data, a_data_size);
+    dap_stream_ch_chain_voting_pkt_t *l_voting_pkt = a_arg;
+    for (size_t i = 0; i < s_pkt_in_callback_count; i++) {
+        struct voting_pkt_in_callback *l_callback = s_pkt_in_callback + i;
+        if (l_callback->packet_in_callback) {
+            l_callback->packet_in_callback(l_callback->arg, &l_voting_pkt->hdr.sender_node_addr,
+                                           &l_voting_pkt->hdr.data_hash, l_voting_pkt->data, l_voting_pkt->hdr.data_size);
+        }
     }
-    voting_pkt_addr_t * l_pkt_addr = DAP_NEW_Z(voting_pkt_addr_t);
-    l_pkt_addr->node_addr.uint64 = 0;
-    l_pkt_addr->voting_pkt = l_voting_pkt;
-    pthread_rwlock_wrlock(&s_pkt_items->rwlock_out);
-    s_pkt_items->pkts_out = dap_list_append(s_pkt_items->pkts_out, l_pkt_addr);
-    pthread_rwlock_unlock(&s_pkt_items->rwlock_out);
-
-    dap_stream_ch_chain_voting_pkt_broadcast(a_net, a_sendto_nodes);
+    return true;
 }
 
-static void s_callback_send_all_unsafe_on_worker(dap_worker_t *a_worker, void *a_arg)
+void dap_stream_ch_chain_voting_message_write(dap_chain_net_t *a_net, dap_chain_node_addr_t *a_remote_node_addr,
+                                              dap_stream_ch_chain_voting_pkt_t *a_voting_pkt)
 {
-    UNUSED(a_worker);
-    s_callback_send_all_unsafe((dap_client_t *)a_arg, NULL);
-}
-
-void dap_stream_ch_chain_voting_pkt_broadcast(dap_chain_net_t *a_net, dap_list_t *a_sendto_nodes)
-{
-    bool l_send_loop = false;
-    dap_list_t *l_nodes_list_temp = dap_list_first(a_sendto_nodes);
-    while(l_nodes_list_temp) {
-        dap_list_t *l_nodes_list = l_nodes_list_temp;
-        l_nodes_list_temp = l_nodes_list_temp->next;
-        dap_chain_node_addr_t *l_remote_node_addr = (dap_chain_node_addr_t *)l_nodes_list->data;
-
-        voting_node_client_list_t *l_node_item = NULL;
-        if ( l_remote_node_addr->uint64 != dap_chain_net_get_cur_addr_int(a_net) ) {
-            HASH_FIND(hh, s_node_client_list, l_remote_node_addr, sizeof(dap_chain_node_addr_t), l_node_item);
-            if (l_node_item) {
-                if (!dap_client_get_stream(l_node_item->node_client->client))
-                    dap_chain_node_client_close_mt(l_node_item->node_client);
-            } else {
-                size_t node_info_size = 0;
-                char *l_key = dap_chain_node_addr_to_hash_str(l_remote_node_addr);
-                dap_chain_node_info_t *l_node_info =
-                        (dap_chain_node_info_t *)dap_global_db_get_sync(a_net->pub.gdb_nodes, l_key,
-                                                                            &node_info_size, NULL, NULL);
-                DAP_DELETE(l_key);
-                if (!l_node_info) {
-                    continue;
-                }
-                char l_channels[] = {dap_stream_ch_chain_voting_get_id(),0};
-                dap_chain_node_client_t *l_node_client = dap_chain_node_client_connect_channels(a_net, l_node_info, l_channels);
-                if (!l_node_client) {
-                    continue;
-                }
-                voting_node_client_list_t *l_node_client_item = DAP_NEW_Z(voting_node_client_list_t);
-                l_node_client_item->node_addr = *l_remote_node_addr;
-                l_node_client_item->node_info = l_node_info;
-                l_node_client_item->node_client = l_node_client;
-                HASH_ADD(hh, s_node_client_list, node_addr, sizeof(dap_chain_node_addr_t), l_node_client_item);
-                l_node_item = l_node_client_item;
+    size_t l_voting_pkt_size =  sizeof(*a_voting_pkt) + a_voting_pkt->hdr.data_size;
+    struct voting_node_client_list *l_node_client_item = NULL;
+    if (a_remote_node_addr->uint64 != dap_chain_net_get_cur_addr_int(a_net)) {
+        HASH_FIND(hh, s_node_client_list, a_remote_node_addr, sizeof(dap_chain_node_addr_t), l_node_client_item);
+        if (!l_node_client_item) {
+            size_t node_info_size = 0;
+            char *l_key = dap_chain_node_addr_to_hash_str(a_remote_node_addr);
+            dap_chain_node_info_t *l_node_info =
+                    (dap_chain_node_info_t *)dap_global_db_get_sync(a_net->pub.gdb_nodes, l_key,
+                                                                        &node_info_size, NULL, NULL);
+            DAP_DELETE(l_key);
+            if (!l_node_info) {
+                log_it(L_WARNING, "Can't find validator's addr "NODE_ADDR_FP_STR" in database", NODE_ADDR_FP_ARGS(a_remote_node_addr));
+                return;
             }
-            if ( !l_node_item || !l_node_item->node_client ) {
-                continue;
+            char l_channels[] = {dap_stream_ch_chain_voting_get_id(),0};
+            dap_chain_node_client_t *l_node_client = dap_chain_node_client_connect_channels(a_net, l_node_info, l_channels);
+            if (!l_node_client || !l_node_client->client) {
+                log_it(L_ERROR, "Can't connect to remote node "NODE_ADDR_FP_STR, NODE_ADDR_FP_ARGS(a_remote_node_addr));
+                return;
             }
-            pthread_rwlock_wrlock(&s_pkt_items->rwlock_out);
-            dap_list_t* l_pkts_list_temp = s_pkt_items->pkts_out;
-            while(l_pkts_list_temp) {
-                dap_list_t *l_pkts_list = l_pkts_list_temp;
-                l_pkts_list_temp = l_pkts_list_temp->next;
-                voting_pkt_addr_t * l_pkt_addr = (voting_pkt_addr_t *)l_pkts_list->data;
-                if (!l_pkt_addr->node_addr.uint64) {
-                    voting_pkt_addr_t * l_pkt_addr_new = DAP_NEW(voting_pkt_addr_t);
-                    l_pkt_addr_new->node_addr.uint64 = l_remote_node_addr->uint64;
-                    l_pkt_addr_new->voting_pkt = DAP_DUP_SIZE(l_pkt_addr->voting_pkt,
-                                                              l_pkt_addr->voting_pkt->hdr.data_size+sizeof(dap_stream_ch_chain_voting_pkt_hdr_t));
-                    l_pkt_addr_new->voting_pkt->hdr.sender_node_addr.uint64 = dap_chain_net_get_cur_addr_int(a_net);
-                    l_pkt_addr_new->voting_pkt->hdr.recipient_node_addr.uint64 = l_remote_node_addr->uint64;
-                    s_pkt_items->pkts_out = dap_list_append(s_pkt_items->pkts_out, l_pkt_addr_new);
-                }
-            }
-            pthread_rwlock_unlock(&s_pkt_items->rwlock_out);
-
-            if (dap_client_get_stage(l_node_item->node_client->client) != STAGE_STREAM_STREAMING)
-                dap_client_go_stage(l_node_item->node_client->client, STAGE_STREAM_STREAMING, s_callback_send_all_unsafe);
-            else {
-                dap_stream_t *l_stream = dap_client_get_stream(l_node_item->node_client->client);
-                dap_worker_exec_callback_on(l_stream->stream_worker->worker, s_callback_send_all_unsafe_on_worker,
-                                            l_node_item->node_client->client);
-            }
-        } else
-            l_send_loop = true;
-    }
-    s_callback_send_all_loopback(l_send_loop ? dap_chain_net_get_cur_addr_int(a_net) : 0);
-}
+            l_node_client->client->connect_on_demand = true;
 
-static void s_callback_send_all_loopback(uint64_t a_node_addr)
-{
-    pthread_rwlock_wrlock(&s_pkt_items->rwlock_out);
-    dap_list_t* l_pkts_list = s_pkt_items->pkts_out;
-    while (l_pkts_list) {
-        dap_list_t *l_pkts_list_next = l_pkts_list->next;
-        voting_pkt_addr_t *l_pkt_addr = (voting_pkt_addr_t *)l_pkts_list->data;
-        if (l_pkt_addr->node_addr.uint64 == 0) {
-            if (a_node_addr) {
-                l_pkt_addr->voting_pkt->hdr.sender_node_addr.uint64 =
-                l_pkt_addr->voting_pkt->hdr.recipient_node_addr.uint64 =
-                        a_node_addr;
-                pthread_rwlock_wrlock(&s_pkt_items->rwlock_in);
-                s_pkt_items->pkts_in = dap_list_append(s_pkt_items->pkts_in, l_pkt_addr->voting_pkt);
-                pthread_rwlock_unlock(&s_pkt_items->rwlock_in);
-            } else
-                DAP_DELETE(l_pkt_addr->voting_pkt);
-            DAP_DELETE(l_pkt_addr);
-            s_pkt_items->pkts_out = dap_list_delete_link(s_pkt_items->pkts_out, l_pkts_list);
+            l_node_client_item = DAP_NEW_Z(struct voting_node_client_list);
+            l_node_client_item->node_addr = *a_remote_node_addr;
+            l_node_client_item->node_info = l_node_info;
+            l_node_client_item->node_client = l_node_client;
+            HASH_ADD(hh, s_node_client_list, node_addr, sizeof(dap_chain_node_addr_t), l_node_client_item);
         }
-        l_pkts_list = l_pkts_list_next;
-    }
-    pthread_rwlock_unlock(&s_pkt_items->rwlock_out);
-}
-
-static void s_callback_send_all_unsafe(dap_client_t *a_client, void *a_arg)
-{
-    UNUSED(a_arg);
-    pthread_rwlock_wrlock(&s_pkt_items->rwlock_out);
-    dap_chain_node_client_t *l_node_client = DAP_CHAIN_NODE_CLIENT(a_client);
-    if (l_node_client) {
-        dap_stream_ch_t * l_ch = dap_client_get_stream_ch_unsafe(a_client, dap_stream_ch_chain_voting_get_id() );
-        if (l_ch) {
-            dap_list_t* l_pkts_list = s_pkt_items->pkts_out;
-            while(l_pkts_list) {
-                dap_list_t *l_pkts_list_next = l_pkts_list->next;
-                voting_pkt_addr_t *l_pkt_addr = (voting_pkt_addr_t *)l_pkts_list->data;
-                dap_stream_ch_chain_voting_pkt_t * l_voting_pkt = l_pkt_addr->voting_pkt;
-                size_t l_voting_pkt_size = sizeof(l_voting_pkt->hdr) + l_voting_pkt->hdr.data_size;
-                if ( l_pkt_addr->node_addr.uint64 == l_node_client->remote_node_addr.uint64 ) {
-                    if (l_ch) {
-                        dap_stream_ch_pkt_write_unsafe(l_ch,
-                                                       l_voting_pkt->hdr.pkt_type, l_voting_pkt, l_voting_pkt_size);
-                        log_it(L_DEBUG, "Sent pkt size %zu to addr "NODE_ADDR_FP_STR, l_voting_pkt_size,
-                               NODE_ADDR_FP_ARGS_S(l_node_client->remote_node_addr));
-                    }
-                    DAP_DELETE(l_voting_pkt);
-                    DAP_DELETE(l_pkt_addr);
-                    s_pkt_items->pkts_out = dap_list_delete_link(s_pkt_items->pkts_out, l_pkts_list);
-                }
-                l_pkts_list = l_pkts_list_next;
-            }
+        if (!l_node_client_item->node_client) {
+            log_it(L_ERROR, "NULL node_client in item of voting channel");
+            return;
         }
-    }
-    pthread_rwlock_unlock(&s_pkt_items->rwlock_out);
+        dap_chain_node_client_write_mt(l_node_client_item->node_client, dap_stream_ch_chain_voting_get_id(),
+                                       DAP_STREAM_CH_CHAIN_VOTING_PKT_TYPE_DATA, a_voting_pkt,
+                                       l_voting_pkt_size);
+    } else
+        dap_proc_queue_add_callback(dap_events_worker_get_auto(), s_callback_pkt_in_call_all,
+                                    DAP_DUP_SIZE(a_voting_pkt, l_voting_pkt_size));
 }
 
-
 void dap_stream_ch_chain_voting_deinit() {
-    voting_node_client_list_t *l_node_info_item=NULL, *l_node_info_tmp=NULL;
+    struct voting_node_client_list *l_node_info_item, *l_node_info_tmp;
     HASH_ITER(hh, s_node_client_list, l_node_info_item, l_node_info_tmp) {
         // Clang bug at this, l_node_info_item should change at every loop cycle
         HASH_DEL(s_node_client_list, l_node_info_item);
-        DAP_DELETE(l_node_info_item->node_client);
+        dap_chain_node_client_close_mt(l_node_info_item->node_client);
         DAP_DELETE(l_node_info_item);
     }
 }
 
-static void s_stream_ch_new(dap_stream_ch_t* a_ch, void* a_arg) {
+static void s_stream_ch_new(dap_stream_ch_t *a_ch, void *a_arg) {
     UNUSED(a_arg);
     a_ch->internal = DAP_NEW_Z(dap_stream_ch_chain_voting_t);
-    dap_stream_ch_chain_voting_t * l_ch_chain_voting = DAP_STREAM_CH_CHAIN_VOTING(a_ch);
-    l_ch_chain_voting->ch = a_ch;
+    dap_stream_ch_chain_voting_t *l_ch_chain_voting = DAP_STREAM_CH_CHAIN_VOTING(a_ch);
+    l_ch_chain_voting->_inheritor = a_ch;
 }
 
-static void s_stream_ch_delete(dap_stream_ch_t* a_ch, void* a_arg)
+static void s_stream_ch_delete(dap_stream_ch_t *a_ch, UNUSED_ARG void *a_arg)
 {
     DAP_DEL_Z(a_ch->internal);
 }
 
-static void s_packet_in_callback_handler(void *a_arg)
+static void s_stream_ch_packet_in(dap_stream_ch_t *a_ch, void *a_arg)
 {
-    UNUSED(a_arg);
-    pthread_rwlock_wrlock(&s_pkt_items->rwlock_in);
-    if (s_pkt_items->pkts_in) {
-        dap_list_t* l_list_pkts = dap_list_copy(s_pkt_items->pkts_in);
-        dap_list_free(s_pkt_items->pkts_in);
-        s_pkt_items->pkts_in = NULL;
-        pthread_rwlock_unlock(&s_pkt_items->rwlock_in);
-        while(l_list_pkts) {
-            dap_stream_ch_chain_voting_pkt_t * l_voting_pkt = (dap_stream_ch_chain_voting_pkt_t *)l_list_pkts->data;
-            for (size_t i=0; i<s_pkt_in_callback_count; i++) {
-                voting_pkt_in_callback_t * l_callback = s_pkt_in_callback+i;
-                if (l_callback->packet_in_callback) {
-                    l_callback->packet_in_callback(l_callback->arg, &l_voting_pkt->hdr.sender_node_addr,
-                                                   &l_voting_pkt->hdr.data_hash, l_voting_pkt->data, l_voting_pkt->hdr.data_size);
-                }
-            }
-            DAP_DELETE(l_voting_pkt);
-            l_list_pkts = l_list_pkts->next;
-        }
-        dap_list_free(l_list_pkts);
-    } else {
-        pthread_rwlock_unlock(&s_pkt_items->rwlock_in);
-    }
-}
-
-
-static void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
-{
-    dap_stream_ch_pkt_t * l_ch_pkt = (dap_stream_ch_pkt_t *) a_arg;
+    dap_stream_ch_pkt_t *l_ch_pkt = (dap_stream_ch_pkt_t *) a_arg;
     if (!l_ch_pkt)
         return;
-    pthread_rwlock_wrlock(&s_pkt_items->rwlock_in);
-    size_t l_voting_pkt_size = l_ch_pkt->hdr.size;
+
+    size_t l_voting_pkt_size = l_ch_pkt->hdr.data_size;
     if (!l_voting_pkt_size || l_voting_pkt_size > UINT16_MAX)
         return;
-    dap_stream_ch_chain_voting_pkt_t *l_voting_pkt = DAP_DUP_SIZE(&l_ch_pkt->data, l_voting_pkt_size);
-    s_pkt_items->pkts_in = dap_list_append(s_pkt_items->pkts_in, l_voting_pkt);
-    pthread_rwlock_unlock(&s_pkt_items->rwlock_in);
-}
 
-static void s_stream_ch_packet_out(dap_stream_ch_t* a_ch, void* a_arg) {
-    UNUSED(a_arg);
+    dap_stream_ch_chain_voting_pkt_t *l_voting_pkt = (dap_stream_ch_chain_voting_pkt_t *)l_ch_pkt->data;
+    dap_proc_queue_add_callback(a_ch->stream_worker->worker, s_callback_pkt_in_call_all,
+                                DAP_DUP_SIZE(l_voting_pkt, l_voting_pkt_size));
+    dap_stream_ch_chain_voting_t *l_ch_chain_voting = DAP_STREAM_CH_CHAIN_VOTING(a_ch);
+    if (l_ch_chain_voting->callback_notify)
+        l_ch_chain_voting->callback_notify(l_ch_chain_voting, l_ch_pkt->hdr.type, l_voting_pkt,
+                                           l_voting_pkt->hdr.data_size, l_ch_chain_voting->callback_notify_arg);
 }
 
+dap_stream_ch_chain_voting_pkt_t *dap_stream_ch_chain_voting_pkt_new(uint64_t a_net_id, const void *a_data, size_t a_data_size)
+{
+    dap_stream_ch_chain_voting_pkt_t *l_voting_pkt = DAP_NEW_Z_SIZE(dap_stream_ch_chain_voting_pkt_t,
+                                                                   sizeof(dap_stream_ch_chain_voting_pkt_t) + a_data_size);
+    l_voting_pkt->hdr.data_size = a_data_size;
+    l_voting_pkt->hdr.version = 1;
+    l_voting_pkt->hdr.net_id.uint64 = a_net_id;
+    dap_hash_fast(a_data, a_data_size, &l_voting_pkt->hdr.data_hash);
+    if (a_data_size && a_data)
+        memcpy(l_voting_pkt->data, a_data, a_data_size);
+    return l_voting_pkt;
+}
 
 size_t dap_stream_ch_chain_voting_pkt_write_unsafe(dap_stream_ch_t *a_ch, uint8_t a_type, uint64_t a_net_id,
                                                    const void * a_data, size_t a_data_size)
 {
-    dap_stream_ch_chain_voting_pkt_t * l_chain_pkt;
-    size_t l_chain_pkt_size = sizeof (l_chain_pkt->hdr) + a_data_size;
-    l_chain_pkt = DAP_NEW_Z_SIZE(dap_stream_ch_chain_voting_pkt_t, l_chain_pkt_size );
-    l_chain_pkt->hdr.data_size = a_data_size;
-    l_chain_pkt->hdr.pkt_type = a_type;
-    l_chain_pkt->hdr.version = 1;
-    l_chain_pkt->hdr.net_id.uint64 = a_net_id;
-
-    if (a_data_size && a_data)
-        memcpy( &l_chain_pkt->data, a_data, a_data_size);
-
-    size_t l_ret  = dap_stream_ch_pkt_write_unsafe(a_ch, a_type , l_chain_pkt, l_chain_pkt_size);
-    DAP_DELETE(l_chain_pkt);
+    dap_stream_ch_chain_voting_pkt_t *l_voting_pkt = dap_stream_ch_chain_voting_pkt_new(a_net_id, a_data, a_data_size);
+    size_t l_ret  = dap_stream_ch_pkt_write_unsafe(a_ch, a_type, l_voting_pkt, sizeof(l_voting_pkt) + a_data_size);
+    DAP_DELETE(l_voting_pkt);
     return l_ret;
 }
diff --git a/modules/channel/chain-voting/include/dap_stream_ch_chain_voting.h b/modules/channel/chain-voting/include/dap_stream_ch_chain_voting.h
index 30163c46ae8e9c0ee07fcc2e6ad90efab7018075..6c361312b6eb348fe43cab46798ebbd8f9930e67 100644
--- a/modules/channel/chain-voting/include/dap_stream_ch_chain_voting.h
+++ b/modules/channel/chain-voting/include/dap_stream_ch_chain_voting.h
@@ -10,40 +10,19 @@
 // #include "dap_stream_ch_chain_pkt.h"
 #include "uthash.h"
 
-#define DAP_STREAM_CH_CHAIN_VOTING_PKT_TYPE_TEST                     0x01
-#define DAP_STREAM_CH_CHAIN_VOTING_PKT_TYPE_TEST_RES                 0x02
-
-typedef void (*voting_ch_callback_t) (void*,dap_chain_node_addr_t*,dap_chain_hash_fast_t*,uint8_t*,size_t);
-
-// typedef struct dap_stream_ch_chain_pkt_hdr{
-//     union{
-//         struct{
-//             uint8_t version;
-//             uint8_t padding[7];
-//         } DAP_ALIGN_PACKED;
-//         uint64_t ext_id;
-//     }DAP_ALIGN_PACKED;
-//     dap_chain_net_id_t net_id;
-//     dap_chain_id_t chain_id;
-//     dap_chain_cell_id_t cell_id;
-// }  DAP_ALIGN_PACKED dap_stream_ch_chain_pkt_hdr_t;
+#define DAP_STREAM_CH_CHAIN_VOTING_PKT_TYPE_DATA        0x01
+#define DAP_STREAM_CH_CHAIN_VOTING_PKT_TYPE_TEST        0x02
+
+typedef void (*dap_chain_voting_ch_callback_t)(void *a_arg, dap_chain_node_addr_t *a_addr, dap_chain_hash_fast_t *a_data_hash, uint8_t *a_data, size_t a_data_size);
 
 typedef struct dap_stream_ch_chain_voting_pkt_hdr {
-    uint8_t pkt_type;
-    union{
-        struct{
-            uint8_t version;
-            uint8_t padding[7];
-        } DAP_ALIGN_PACKED;
-        uint64_t ext_id;
-    }DAP_ALIGN_PACKED;
-    size_t data_size;
+    uint8_t version;
+    uint8_t padding[7];
+    uint64_t data_size;
     dap_chain_hash_fast_t data_hash;
     dap_chain_net_id_t net_id;
     dap_chain_node_addr_t sender_node_addr;
-    dap_chain_node_addr_t recipient_node_addr;
-    // dap_chain_id_t chain_id;
-    // dap_chain_cell_id_t cell_id;
+    dap_chain_node_addr_t receiver_node_addr;
 }  DAP_ALIGN_PACKED dap_stream_ch_chain_voting_pkt_hdr_t;
 
 typedef struct dap_stream_ch_chain_voting_pkt {
@@ -53,24 +32,12 @@ typedef struct dap_stream_ch_chain_voting_pkt {
 
 
 typedef struct dap_stream_ch_chain_voting dap_stream_ch_chain_voting_t;
-typedef void (*dap_stream_ch_chain_voting_callback_packet_t)(dap_stream_ch_chain_voting_t*, uint8_t a_pkt_type,
+typedef void (*dap_stream_ch_chain_voting_callback_packet_t)(dap_stream_ch_chain_voting_t *a_ch_voting, uint8_t a_pkt_type,
                                                              dap_stream_ch_chain_voting_pkt_t *a_pkt, size_t a_pkt_data_size,
                                                              void * a_arg);
 
 typedef struct dap_stream_ch_chain_voting {
-    //void *_inheritor;
-    dap_stream_ch_t * ch;
-    //dap_stream_ch_chain_state_t state;
-    dap_chain_node_client_t * node_client; // Node client associated with stream
-
-    // request section
-    //dap_stream_ch_chain_sync_request_t request;
-    //dap_stream_ch_chain_pkt_hdr_t request_hdr;
-    //dap_list_t *request_db_iter;
-
-    //bool was_active;
-
-    //dap_stream_ch_chain_voting_callback_packet_t callback_notify_packet_out;
+    void *_inheritor;   // parent stream ch
     dap_stream_ch_chain_voting_callback_packet_t callback_notify;
     void *callback_notify_arg;
 } dap_stream_ch_chain_voting_t;
@@ -79,16 +46,12 @@ typedef struct dap_stream_ch_chain_voting {
 
 inline static uint8_t dap_stream_ch_chain_voting_get_id(void) { return (uint8_t) 'V'; }
 
-void dap_stream_ch_chain_voting_in_callback_add(void* a_arg, voting_ch_callback_t packet_in_callback);
+void dap_stream_ch_chain_voting_in_callback_add(void* a_arg, dap_chain_voting_ch_callback_t packet_in_callback);
 
-void dap_stream_ch_chain_voting_message_write(dap_chain_net_t * a_net, dap_list_t *a_sendto_nodes,
-                                              dap_chain_hash_fast_t * a_data_hash,
-                                              const void * a_data, size_t a_data_size);
-void dap_stream_ch_chain_voting_pkt_broadcast(dap_chain_net_t * a_net, dap_list_t *a_sendto_nodes);
+void dap_stream_ch_chain_voting_message_write(dap_chain_net_t * a_net, dap_chain_node_addr_t *a_remote_node_addr,
+                                              dap_stream_ch_chain_voting_pkt_t *a_voting_pkt);
 
-// size_t dap_stream_ch_chain_voting_pkt_write_mt(dap_stream_worker_t *a_worker, dap_stream_ch_uuid_t a_ch_uuid,
-//                                         uint8_t a_type,uint64_t a_net_id,
-//                                         const void * a_data, size_t a_data_size);
+dap_stream_ch_chain_voting_pkt_t *dap_stream_ch_chain_voting_pkt_new(uint64_t a_net_id, const void *a_data, size_t a_data_size);
 
 size_t dap_stream_ch_chain_voting_pkt_write_unsafe(dap_stream_ch_t *a_ch, uint8_t a_type, uint64_t a_net_id,
                                                    const void * a_data, size_t a_data_size);
diff --git a/modules/channel/chain/dap_stream_ch_chain.c b/modules/channel/chain/dap_stream_ch_chain.c
index 83926112676f0ea1f812857fca17a36e30f6ed80..f33e764cc55a236e6edc4c2e763b5e6a8f843e8f 100644
--- a/modules/channel/chain/dap_stream_ch_chain.c
+++ b/modules/channel/chain/dap_stream_ch_chain.c
@@ -1023,12 +1023,12 @@ void s_stream_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
         log_it(L_ERROR, "No chain packet in channel packet, returning");
         return;
     }
-    if (l_ch_pkt->hdr.size < sizeof (l_chain_pkt->hdr)){
-        log_it(L_ERROR, "Corrupted packet: too small size %u, smaller then header size %zu", l_ch_pkt->hdr.size,
+    if (l_ch_pkt->hdr.data_size < sizeof (l_chain_pkt->hdr)){
+        log_it(L_ERROR, "Corrupted packet: too small size %u, smaller then header size %zu", l_ch_pkt->hdr.data_size,
                sizeof(l_chain_pkt->hdr));
         return;
     }
-    size_t l_chain_pkt_data_size = l_ch_pkt->hdr.size-sizeof (l_chain_pkt->hdr);
+    size_t l_chain_pkt_data_size = l_ch_pkt->hdr.data_size - sizeof(l_chain_pkt->hdr);
     dap_chain_net_t *l_net = dap_chain_net_by_id(l_chain_pkt->hdr.net_id);
     if (!l_net) {
         if (l_ch_pkt->hdr.type == DAP_STREAM_CH_CHAIN_PKT_TYPE_ERROR) {
diff --git a/modules/common/dap_chain_common.c b/modules/common/dap_chain_common.c
index 19e23fc6d378b40917f78703fe0c06788969d264..a2a8f77dd28ba8f538d6cbc569703c82dccbe08d 100644
--- a/modules/common/dap_chain_common.c
+++ b/modules/common/dap_chain_common.c
@@ -38,6 +38,7 @@
 #define LOG_TAG "dap_chain_common"
 
 const dap_chain_net_srv_uid_t c_dap_chain_net_srv_uid_null = {0};
+const dap_chain_cell_id_t c_dap_chain_cell_id_null = {0};
 
 /*
  * Forward declarations
@@ -173,19 +174,30 @@ dap_chain_net_srv_uid_t dap_chain_net_srv_uid_from_str( const char * a_net_srv_u
  * @param a_net_id
  * @return
  */
-void dap_chain_addr_fill_from_key(dap_chain_addr_t *a_addr, dap_enc_key_t *a_key, dap_chain_net_id_t a_net_id) {
+int dap_chain_addr_fill_from_key(dap_chain_addr_t *a_addr, dap_enc_key_t *a_key, dap_chain_net_id_t a_net_id)
+{
     dap_sign_type_t l_type = dap_sign_type_from_key_type(a_key->type);
     size_t l_pub_key_data_size;
     uint8_t *l_pub_key_data = dap_enc_key_serealize_pub_key(a_key, &l_pub_key_data_size);
     if (!l_pub_key_data) {
         log_it(L_ERROR,"Can't fill address from key, its empty");
-        return;
+        return -1;
     }
     dap_chain_hash_fast_t l_hash_public_key;
     // serialized key -> key hash
     dap_hash_fast(l_pub_key_data, l_pub_key_data_size, &l_hash_public_key);
     dap_chain_addr_fill(a_addr, l_type, &l_hash_public_key, a_net_id);
     DAP_DELETE(l_pub_key_data);
+    return 0;
+}
+
+int dap_chain_addr_fill_from_sign(dap_chain_addr_t *a_addr, dap_sign_t *a_sign, dap_chain_net_id_t a_net_id)
+{
+    dap_hash_fast_t l_sign_pkey_hash;
+    if (!dap_sign_get_pkey_hash(a_sign, &l_sign_pkey_hash))
+        return -1;
+    dap_chain_addr_fill(a_addr, a_sign->header.type, &l_sign_pkey_hash, a_net_id);
+    return 0;
 }
 
 /**
@@ -226,6 +238,8 @@ int dap_chain_addr_check_sum(const dap_chain_addr_t *a_addr)
     return -1;
 }
 
+
+
 uint64_t dap_chain_uint128_to(uint128_t a_from)
 {
 #ifdef DAP_GLOBAL_IS_INT128
diff --git a/modules/common/dap_chain_datum.c b/modules/common/dap_chain_datum.c
index 9ddec492ea931de34d216b0a82887baf15e85b37..bdac29630bd4ed27dd8065b49ad796c8b706393b 100644
--- a/modules/common/dap_chain_datum.c
+++ b/modules/common/dap_chain_datum.c
@@ -292,7 +292,7 @@ bool dap_chain_datum_dump_tx(dap_chain_datum_tx_t *a_datum,
             DAP_DELETE(l_hash_str);
         } break;
         case TX_ITEM_TYPE_IN_EMS_EXT: {
-            l_hash_tmp = &((dap_chain_tx_token_ext_t*)item)->header.ext_tx_hash;
+            l_hash_tmp = &((dap_chain_tx_in_ems_ext_t*)item)->header.ext_tx_hash;
             if (!dap_strcmp(a_hash_out_type, "hex"))
                 l_hash_str = dap_chain_hash_fast_to_str_new(l_hash_tmp);
             else
@@ -304,12 +304,12 @@ bool dap_chain_datum_dump_tx(dap_chain_datum_tx_t *a_datum,
                                          "\t\t Ext net id: 0x%016"DAP_UINT64_FORMAT_x"\n"
                                          "\t\t Ext tx hash: %s\n"
                                          "\t\t Ext tx out idx: %u\n",
-                                     ((dap_chain_tx_token_ext_t*)item)->header.version,
-                                     ((dap_chain_tx_token_ext_t*)item)->header.ticker,
-                                     ((dap_chain_tx_token_ext_t*)item)->header.ext_chain_id.uint64,
-                                     ((dap_chain_tx_token_ext_t*)item)->header.ext_net_id.uint64,
+                                     ((dap_chain_tx_in_ems_ext_t*)item)->header.version,
+                                     ((dap_chain_tx_in_ems_ext_t*)item)->header.ticker,
+                                     ((dap_chain_tx_in_ems_ext_t*)item)->header.ext_chain_id.uint64,
+                                     ((dap_chain_tx_in_ems_ext_t*)item)->header.ext_net_id.uint64,
                                      l_hash_str,
-                                     ((dap_chain_tx_token_ext_t*)item)->header.ext_tx_out_idx);
+                                     ((dap_chain_tx_in_ems_ext_t*)item)->header.ext_tx_out_idx);
             DAP_DELETE(l_hash_str);
         } break;
         case TX_ITEM_TYPE_SIG: {
diff --git a/modules/common/dap_chain_datum_tx_token.c b/modules/common/dap_chain_datum_tx_token.c
deleted file mode 100644
index 0379c5ae4640d3faf766f20becfde6e5139dd81a..0000000000000000000000000000000000000000
--- a/modules/common/dap_chain_datum_tx_token.c
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Authors:
- * Dmitriy A. Gearasimov <kahovski@gmail.com>
- * DeM Labs Inc.   https://demlabs.net
- * DeM Labs Open source community https://github.com/demlabsinc
- * Copyright  (c) 2017-2019
- * All rights reserved.
-
- This file is part of DAP (Deus Applications Prototypes) the open source project
-
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    DAP is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with any DAP based project.  If not, see <http://www.gnu.org/licenses/>.
-*/
-#include <dap_chain_datum_tx_token.h>
diff --git a/modules/common/include/dap_chain_common.h b/modules/common/include/dap_chain_common.h
index e17af915462c1d1f6ec167f13ba2a40a8816f647..49d7febfbc31cb0265fa528e14b25b3404785ae5 100644
--- a/modules/common/include/dap_chain_common.h
+++ b/modules/common/include/dap_chain_common.h
@@ -38,7 +38,7 @@
 #define DAP_CHAIN_ID_SIZE           8
 #define DAP_CHAIN_SHARD_ID_SIZE     8
 #define DAP_CHAIN_NET_ID_SIZE       8
-#define DAP_CHAIN_NODE_ROLE_SIZE    2
+#define DAP_CHAIN_NODE_ROLE_SIZE    4
 #define DAP_CHAIN_HASH_SLOW_SIZE    32
 #define DAP_CHAIN_TIMESTAMP_SIZE    8
 #define DAP_CHAIN_TICKER_SIZE_MAX   10
@@ -83,7 +83,6 @@ typedef union dap_chain_node_addr {
 #define NODE_ADDR_FPS_ARGS(a)  &a->words[3],&a->words[2],&a->words[1],&a->words[0]
 #define NODE_ADDR_FP_ARGS_S(a)  a.words[3],a.words[2],a.words[1],a.words[0]
 #define NODE_ADDR_FPS_ARGS_S(a)  &a.words[3],&a.words[2],&a.words[1],&a.words[0]
-
 #endif
 
 inline static int dap_chain_node_addr_from_str( dap_chain_node_addr_t * a_addr, const char * a_addr_str){
@@ -99,15 +98,17 @@ inline static bool dap_chain_node_addr_not_null(dap_chain_node_addr_t * a_addr){
   *
   *
   */
+enum {
+    NODE_ROLE_ROOT_MASTER=0x00,
+    NODE_ROLE_ROOT=0x01,
+    NODE_ROLE_ARCHIVE=0x02,
+    NODE_ROLE_CELL_MASTER=0x10,
+    NODE_ROLE_MASTER = 0x20,
+    NODE_ROLE_FULL=0xf0,
+    NODE_ROLE_LIGHT=0xff
+};
 typedef union dap_chain_node_role{
-    enum {
-        NODE_ROLE_ROOT_MASTER=0x00,
-        NODE_ROLE_ROOT=0x01,
-        NODE_ROLE_ARCHIVE=0x02,
-        NODE_ROLE_CELL_MASTER=0x10,
-        NODE_ROLE_MASTER = 0x20,
-        NODE_ROLE_FULL=0xf0,
-        NODE_ROLE_LIGHT=0xff } enums;
+    uint32_t enums;
     uint8_t raw[DAP_CHAIN_NODE_ROLE_SIZE];
 } DAP_ALIGN_PACKED dap_chain_node_role_t;
 
@@ -132,16 +133,16 @@ typedef struct dap_chain_addr{
     uint8_t addr_ver; // 0 for default
     dap_chain_net_id_t net_id;  // Testnet, mainnet or alternet
     dap_sign_type_t sig_type;
-    union{
+    union {
         //dap_chain_hash_fast_t hash;
         struct {
             uint8_t key_spend[sizeof(dap_chain_hash_fast_t)/2];
             uint8_t key_view[sizeof(dap_chain_hash_fast_t)/2];
-        } key_sv;
+        } DAP_ALIGN_PACKED key_sv;
         uint8_t key[sizeof(dap_chain_hash_fast_t)];
         uint8_t hash[sizeof(dap_chain_hash_fast_t)];
         dap_chain_hash_fast_t hash_fast;
-    } data;
+    } DAP_ALIGN_PACKED data;
     dap_chain_hash_fast_t checksum;
 }  DAP_ALIGN_PACKED dap_chain_addr_t;
 
@@ -159,8 +160,9 @@ typedef union {
 } dap_chain_net_srv_uid_t;
 
 extern const dap_chain_net_srv_uid_t c_dap_chain_net_srv_uid_null;
+extern const dap_chain_cell_id_t c_dap_chain_cell_id_null;
 
-typedef enum {
+enum serv_unit_enum {
     SERV_UNIT_UNDEFINED = 0 ,
     SERV_UNIT_MB = 0x00000001, // megabytes
     SERV_UNIT_SEC = 0x00000002, // seconds
@@ -168,7 +170,8 @@ typedef enum {
     SERV_UNIT_KB = 0x00000010,  // kilobytes
     SERV_UNIT_B = 0x00000011,   // bytes
     SERV_UNIT_PCS = 0x00000022  // pieces
-} serv_unit_enum_t;
+};
+typedef uint32_t serv_unit_enum_t;
 
 DAP_STATIC_INLINE const char *serv_unit_enum_to_str(serv_unit_enum_t *unit_enum){
     switch (*unit_enum) {
@@ -180,20 +183,14 @@ DAP_STATIC_INLINE const char *serv_unit_enum_to_str(serv_unit_enum_t *unit_enum)
     case SERV_UNIT_B: return "SERV_UNIT_B";
     case SERV_UNIT_PCS: return "SERV_UNIT_PCS";
     default: return "UNDEFINED";
-
     }
-//    switch (unit_enum){
-//    case SERV
-//    }
-//    return  "SERV_UNIT_UNDEFINED";
 }
 
 typedef union {
     uint8_t raw[4];
-    uint32_t raw_ui32[1];
     uint32_t uint32;
     serv_unit_enum_t enm;
-} dap_chain_net_srv_price_unit_uid_t;
+} DAP_ALIGN_PACKED dap_chain_net_srv_price_unit_uid_t;
 
 enum dap_chain_tx_item_type {
     TX_ITEM_TYPE_IN = 0x00, /// @brief  Transaction: inputs
@@ -249,15 +246,21 @@ bool dap_chain_addr_is_blank(const dap_chain_addr_t *a_addr);
 dap_chain_net_srv_uid_t dap_chain_net_srv_uid_from_str(const char* a_str);
 
 void dap_chain_addr_fill(dap_chain_addr_t *a_addr, dap_sign_type_t a_type, dap_chain_hash_fast_t *a_pkey_hash, dap_chain_net_id_t a_net_id);
-void dap_chain_addr_fill_from_key(dap_chain_addr_t *a_addr, dap_enc_key_t *a_key, dap_chain_net_id_t a_net_id);
+int dap_chain_addr_fill_from_key(dap_chain_addr_t *a_addr, dap_enc_key_t *a_key, dap_chain_net_id_t a_net_id);
+int dap_chain_addr_fill_from_sign(dap_chain_addr_t *a_addr, dap_sign_t *a_sign, dap_chain_net_id_t a_net_id);
 
 int dap_chain_addr_check_sum(const dap_chain_addr_t *a_addr);
+DAP_STATIC_INLINE bool dap_chain_addr_compare(dap_chain_addr_t *a_addr1, dap_chain_addr_t *a_addr2)
+{
+    return !memcmp(a_addr1, a_addr2, sizeof(dap_chain_addr_t));
+}
 
+// Deprecated
 DAP_STATIC_INLINE long double dap_chain_datoshi_to_coins(uint64_t a_count)
 {
     return (double)a_count / DATOSHI_LD;
 }
-
+// Deprecated
 DAP_STATIC_INLINE uint64_t dap_chain_coins_to_datoshi(long double a_count)
 {
     return (uint64_t)(a_count * DATOSHI_LD);
diff --git a/modules/common/include/dap_chain_datum_tx_token.h b/modules/common/include/dap_chain_datum_tx_in_ems.h
similarity index 94%
rename from modules/common/include/dap_chain_datum_tx_token.h
rename to modules/common/include/dap_chain_datum_tx_in_ems.h
index 63a86c6f1a4d541cf1674c2263e7b907dabd8e27..c0f46fbeecf0e6011e5ec50ab534996ce84b2f34 100644
--- a/modules/common/include/dap_chain_datum_tx_token.h
+++ b/modules/common/include/dap_chain_datum_tx_in_ems.h
@@ -32,7 +32,7 @@
   * @struct dap_chain_tx_token
   * @brief Token item
   */
-typedef struct dap_chain_tx_token{
+typedef struct dap_chain_tx_in_ems {
     struct {
         dap_chain_tx_item_type_t type;
         char ticker[DAP_CHAIN_TICKER_SIZE_MAX];
@@ -47,7 +47,7 @@ typedef struct dap_chain_tx_token{
   * @struct dap_chain_tx_token_ext
   * @brief External token swap
   */
-typedef struct dap_chain_tx_token_ext{
+typedef struct dap_chain_tx_in_ems_ext{
     struct {
         dap_chain_tx_item_type_t type;
         uint8_t version;
@@ -59,4 +59,4 @@ typedef struct dap_chain_tx_token_ext{
         uint16_t padding2;
         uint16_t ext_tx_out_idx; // Output index
     } header; /// Only header's hash is used for verification
-} DAP_ALIGN_PACKED dap_chain_tx_token_ext_t;
+} DAP_ALIGN_PACKED dap_chain_tx_in_ems_ext_t;
diff --git a/modules/common/include/dap_chain_datum_tx_items.h b/modules/common/include/dap_chain_datum_tx_items.h
index 8e83de002985ad6fa77e858d75ae3ddf85cf5a4e..050909ccd2bda840e6d62292163d7238f756186c 100644
--- a/modules/common/include/dap_chain_datum_tx_items.h
+++ b/modules/common/include/dap_chain_datum_tx_items.h
@@ -39,7 +39,7 @@
 #include "dap_chain_datum_tx_out_cond.h"
 #include "dap_chain_datum_tx_sig.h"
 #include "dap_chain_datum_tx_pkey.h"
-#include "dap_chain_datum_tx_token.h"
+#include "dap_chain_datum_tx_in_ems.h"
 #include "dap_chain_datum_tx_receipt.h"
 #include "dap_chain_datum_tx_tsd.h"
 
diff --git a/modules/consensus/block-ton/dap_chain_cs_block_ton.c b/modules/consensus/block-ton/dap_chain_cs_block_ton.c
deleted file mode 100644
index 688c50eea641cbf5e57eed211bbd060a283a7555..0000000000000000000000000000000000000000
--- a/modules/consensus/block-ton/dap_chain_cs_block_ton.c
+++ /dev/null
@@ -1,2347 +0,0 @@
-
-#include "dap_timerfd.h"
-#include "utlist.h"
-#include "dap_chain_net.h"
-#include "dap_chain_common.h"
-#include "dap_chain_cell.h"
-#include "dap_chain_cs.h"
-#include "dap_chain_cs_blocks.h"
-#include "dap_chain_cs_block_ton.h"
-#include "dap_stream_ch_chain_voting.h"
-#include "dap_chain_net_srv_stake_pos_delegate.h"
-#include "dap_chain_ledger.h"
-
-#define LOG_TAG "dap_chain_cs_blocks_ton"
-
-static int s_callback_new(dap_chain_t *a_chain, dap_config_t *a_chain_cfg);
-static void s_session_packet_in(void * a_arg, dap_chain_node_addr_t * a_sender_node_addr,
-                                dap_chain_hash_fast_t *a_data_hash, uint8_t *a_data, size_t a_data_size);
-static void s_session_candidate_to_chain(
-            dap_chain_cs_block_ton_session_t *a_session, dap_chain_hash_fast_t *a_candidate_hash,
-                            dap_chain_block_t *a_candidate, size_t a_candidate_size);
-static void s_session_candidate_submit(dap_chain_cs_block_ton_session_t *a_session);
-static void s_session_timer(void *a_arg);
-static int s_session_atom_validation(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t *a_block, size_t a_block_size);
-static uint8_t *s_message_data_sign(dap_chain_cs_block_ton_session_t *a_session,
-                        dap_chain_cs_block_ton_message_t *a_message, size_t *a_sign_size);
-static void s_message_send(dap_chain_cs_block_ton_session_t *a_session, uint8_t a_message_type,
-                                    uint8_t *a_data, size_t a_data_size, dap_list_t *a_validators);
-static void s_message_chain_add(dap_chain_cs_block_ton_session_t * a_session, dap_chain_node_addr_t * a_sender_node_addr,
-                                    dap_chain_cs_block_ton_message_t * a_message,
-                                    size_t a_message_size, dap_chain_hash_fast_t *a_message_hash);
-static void s_session_round_clear(dap_chain_cs_block_ton_session_t *a_session);
-static bool s_session_send_startsync(dap_chain_cs_block_ton_session_t *a_session);
-static void s_session_my_candidate_delete(dap_chain_cs_block_ton_session_t *a_session);
-static void s_session_round_finish(dap_chain_cs_block_ton_session_t *a_session, bool a_failed);
-static dap_chain_node_addr_t *s_session_get_validator(
-                    dap_chain_cs_block_ton_session_t *a_session, dap_chain_node_addr_t *a_addr,
-                        dap_list_t *a_validators);
-static uint16_t s_session_message_count(dap_chain_cs_block_ton_session_t *a_session, uint8_t a_type,
-                        dap_chain_hash_fast_t *a_candidate_hash, uint16_t *a_attempt_number);
-static void s_callback_delete(dap_chain_cs_blocks_t *a_blocks);
-static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cfg);
-static size_t s_callback_block_sign(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t **a_block_ptr, size_t a_block_size);
-static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t *a_block, size_t a_block_size);
-
-static int s_compare_validators_list_stake(const void * a_item1, const void * a_item2, void *a_unused);
-static int s_compare_validators_list_addr(const void * a_item1, const void * a_item2, void *a_unused);
-static dap_list_t *s_get_validators_addr_list(dap_chain_cs_block_ton_session_t *a_session); //(dap_chain_t *a_chain);
-
-static dap_chain_cs_block_ton_session_t * s_session_items;
-static dap_interval_timer_t s_session_cs_timer = NULL;
-
-typedef struct dap_chain_cs_block_ton_pvt
-{
-    dap_enc_key_t *blocks_sign_key;
-    char **tokens_hold;
-    uint64_t *tokens_hold_value;
-    dap_config_t *chain_cfg;
-    size_t tokens_hold_size;
-    // uint16_t confirmations_minimum;
-    dap_chain_callback_new_cfg_t prev_callback_created;
-
-    uint16_t poa_validators_count;
-    bool flag_sign_verify;
-
-    bool debug;
-    bool validators_list_by_stake;
-    uint16_t round_start_sync_timeout;
-    uint16_t round_start_multiple_of;
-    uint32_t allowed_clock_offset;
-    uint32_t session_idle_min;
-    uint16_t round_candidates_max;
-    uint16_t next_candidate_delay;
-    uint16_t round_attempts_max;
-    uint16_t round_attempt_duration;
-    uint16_t first_message_delay;
-    uint16_t my_candidate_attempts_max;
-
-    dap_list_t *ton_nodes_addrs; // dap_chain_node_addr_t
-
-    uint16_t auth_certs_count;
-    char *auth_certs_prefix;
-    dap_cert_t ** auth_certs;
-} dap_chain_cs_block_ton_pvt_t;
-
-#define PVT(a) ((dap_chain_cs_block_ton_pvt_t *)a->_pvt)
-
-int dap_chain_cs_block_ton_init() {
-    dap_stream_ch_chain_voting_init();
-    dap_chain_cs_add("block_ton", s_callback_new);
-    return 0;
-}
-
-void dap_chain_cs_block_ton_deinit(void) {
-
-}
-
-static int s_callback_new(dap_chain_t *a_chain, dap_config_t *a_chain_cfg) {
-    dap_chain_cs_blocks_new(a_chain, a_chain_cfg);
-    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
-    dap_chain_cs_block_ton_t *l_ton = DAP_NEW_Z(dap_chain_cs_block_ton_t);
-    l_blocks->_inheritor = l_ton;
-    l_blocks->callback_delete = s_callback_delete;
-    l_blocks->callback_block_verify = s_callback_block_verify;
-    l_blocks->callback_block_sign = s_callback_block_sign;
-    l_ton->_pvt = DAP_NEW_Z(dap_chain_cs_block_ton_pvt_t);
-
-    dap_chain_cs_block_ton_pvt_t *l_ton_pvt = PVT(l_ton);
-
-    char ** l_tokens_hold = NULL;
-    char ** l_tokens_hold_value_str = NULL;
-    uint16_t l_tokens_hold_size = 0;
-    uint16_t l_tokens_hold_value_size = 0;
-
-    l_tokens_hold = dap_config_get_array_str(a_chain_cfg, "block-ton", "stake_tokens", &l_tokens_hold_size);
-    l_tokens_hold_value_str = dap_config_get_array_str(a_chain_cfg, "block-ton", "stake_tokens_value", &l_tokens_hold_value_size);
-
-    if (l_tokens_hold_size != l_tokens_hold_value_size){
-        log_it(L_CRITICAL, "Entries tokens_hold and tokens_hold_value are different size!");
-        goto lb_err;
-    }
-    //l_ton_pvt->confirmations_minimum = dap_config_get_item_uint16_default(a_chain_cfg, "block-ton", "verifications_minimum", 1);
-    l_ton_pvt->flag_sign_verify = true;
-    l_ton_pvt->tokens_hold_size = l_tokens_hold_size;
-    l_ton_pvt->tokens_hold = DAP_NEW_Z_SIZE(char *, sizeof(char *) * l_tokens_hold_size);
-    l_ton_pvt->tokens_hold_value = DAP_NEW_Z_SIZE(uint64_t, l_tokens_hold_value_size * sizeof(uint64_t));
-    l_ton_pvt->debug = dap_config_get_item_bool_default(a_chain_cfg,"block-ton","consensus_debug", true);
-
-    l_ton_pvt->validators_list_by_stake = dap_config_get_item_bool_default(a_chain_cfg,"block-ton","validators_list_by_stake", false);
-    l_ton_pvt->round_start_sync_timeout = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_start_sync_timeout", 10);
-    l_ton_pvt->round_start_multiple_of = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_start_multiple_of", 30);
-    l_ton_pvt->allowed_clock_offset = dap_config_get_item_uint32_default(a_chain_cfg,"block-ton", "allowed_clock_offset", 5);
-    l_ton_pvt->session_idle_min = dap_config_get_item_uint32_default(a_chain_cfg,"block-ton", "session_idle_min", 15);
-    l_ton_pvt->round_candidates_max = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_candidates_max", 3);
-    l_ton_pvt->next_candidate_delay = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "next_candidate_delay", 2);
-    l_ton_pvt->round_attempts_max = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_attempts_max", 4);
-    l_ton_pvt->round_attempt_duration = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "round_attempt_duration", 60);
-    l_ton_pvt->first_message_delay = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "first_message_delay", 3);
-    l_ton_pvt->my_candidate_attempts_max = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton", "my_candidate_attempts_max", 2);
-
-    l_ton_pvt->ton_nodes_addrs = NULL;
-    l_ton_pvt->auth_certs_prefix = strdup( dap_config_get_item_str_default(a_chain_cfg,"block-ton","auth_certs_prefix", "ton") );
-    l_ton_pvt->auth_certs_count = dap_config_get_item_uint16_default(a_chain_cfg,"block-ton","auth_certs_number", 0);
-    if ( !l_ton_pvt->validators_list_by_stake ) { // auth by cert for PoA mode
-        if (l_ton_pvt->auth_certs_count) {
-            l_ton_pvt->auth_certs = DAP_NEW_Z_SIZE(dap_cert_t *, l_ton_pvt->auth_certs_count * sizeof(dap_cert_t*));
-            char l_cert_name[512];
-            for (size_t i = 0; i < l_ton_pvt->auth_certs_count; i++ ){
-                dap_snprintf(l_cert_name, sizeof(l_cert_name), "%s.%zu", l_ton_pvt->auth_certs_prefix, i);
-                if ((l_ton_pvt->auth_certs[i] = dap_cert_find_by_name( l_cert_name)) == NULL) {
-                    dap_snprintf(l_cert_name, sizeof(l_cert_name), "%s.%zu.pub", l_ton_pvt->auth_certs_prefix, i);
-                    if ((l_ton_pvt->auth_certs[i] = dap_cert_find_by_name(l_cert_name)) == NULL) {
-                        log_it(L_ERROR, "TON: Can't find cert \"%s\"", l_cert_name);
-                        return -1;
-                    }
-                }
-                log_it(L_NOTICE, "TON: Initialized auth cert \"%s\"", l_cert_name);
-            }
-        }
-
-        uint16_t l_node_addrs_count;
-        char **l_addrs = dap_config_get_array_str(a_chain_cfg, "block-ton", "ton_nodes_addrs", &l_node_addrs_count);
-        l_ton_pvt->poa_validators_count = l_node_addrs_count;
-        for(size_t i = 0; i < l_node_addrs_count; i++) {
-            dap_chain_node_addr_t *l_node_addr = DAP_NEW_Z(dap_chain_node_addr_t);
-            if (dap_sscanf(l_addrs[i],NODE_ADDR_FP_STR, NODE_ADDR_FPS_ARGS(l_node_addr) ) != 4 ){
-                log_it(L_ERROR,"TON: Wrong address format,  should be like 0123::4567::890AB::CDEF");
-                DAP_DELETE(l_node_addr);
-                //DAP_DELETE(l_node_info);
-                l_node_addr = NULL;
-                continue;
-            }
-            if (l_node_addr) {
-                log_it(L_MSG, "TON: add validator addr:"NODE_ADDR_FP_STR"", NODE_ADDR_FP_ARGS(l_node_addr));
-                l_ton_pvt->ton_nodes_addrs = dap_list_append(l_ton_pvt->ton_nodes_addrs, l_node_addr);
-            }
-        }
-
-    }
-    else { // stake
-        for (size_t i = 0; i < l_tokens_hold_value_size; i++) {
-            l_ton_pvt->tokens_hold[i] = dap_strdup(l_tokens_hold[i]);
-            if ((l_ton_pvt->tokens_hold_value[i] =
-                   strtoull(l_tokens_hold_value_str[i],NULL,10)) == 0) {
-                 log_it(L_CRITICAL, "Token %s has inproper hold value %s",
-                                    l_ton_pvt->tokens_hold[i], l_tokens_hold_value_str[i]);
-                 goto lb_err;
-            }
-        }
-    }
-
-
-    // Save old callback if present and set the call of its own (chain callbacks)
-    l_ton_pvt->prev_callback_created = l_blocks->chain->callback_created;
-    l_blocks->chain->callback_created = s_callback_created;
-    return 0;
-
-lb_err:
-    for (int i = 0; i < l_tokens_hold_size; i++)
-        DAP_DELETE(l_tokens_hold[i]);
-    DAP_DELETE(l_tokens_hold);
-    DAP_DELETE(l_ton_pvt->tokens_hold_value);
-    DAP_DELETE(l_ton_pvt);
-    DAP_DELETE(l_ton );
-    l_blocks->_inheritor = NULL;
-    l_blocks->callback_delete = NULL;
-    l_blocks->callback_block_verify = NULL;
-    return -1;
-
-}
-
-static void s_callback_delete(dap_chain_cs_blocks_t *a_blocks) {
-    dap_interval_timer_delete(s_session_cs_timer);
-    dap_chain_cs_block_ton_t *l_ton = DAP_CHAIN_CS_BLOCK_TON(a_blocks);
-    if (l_ton->_pvt)
-        DAP_DELETE(l_ton->_pvt);
-}
-
-
-static int s_compare_validators_list_stake(const void * a_item1, const void * a_item2, void *a_unused)
-{
-    UNUSED(a_unused);
-    dap_chain_net_srv_stake_item_t *l_item1 = (dap_chain_net_srv_stake_item_t *)a_item1;
-    dap_chain_net_srv_stake_item_t *l_item2 = (dap_chain_net_srv_stake_item_t *)a_item2;
-    return compare256(l_item1->value, l_item2->value)*-1;
-}
-
-static int s_compare_validators_list_addr(const void * a_item1, const void * a_item2, void *a_unused)
-{
-    UNUSED(a_unused);
-    dap_chain_node_addr_t *l_item1 = (dap_chain_node_addr_t *)a_item1;
-    dap_chain_node_addr_t *l_item2 = (dap_chain_node_addr_t *)a_item2;
-    if(!l_item1 || !l_item2 || l_item1->uint64 == l_item2->uint64)
-        return 0;
-    if(l_item1->uint64 > l_item2->uint64)
-        return 1;
-    return -1;
-}
-
-static dap_list_t *s_get_validators_addr_list(dap_chain_cs_block_ton_session_t *a_session) {//(dap_chain_t *a_chain) {
-
-    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_session->chain);
-    dap_chain_cs_block_ton_t *l_ton = DAP_CHAIN_CS_BLOCK_TON(l_blocks);
-    dap_chain_cs_block_ton_pvt_t *l_ton_pvt = PVT(l_ton);
-    dap_list_t *l_ret = NULL;
-
-    if ( l_ton_pvt->validators_list_by_stake) {
-        dap_list_t *l_validators = dap_chain_net_srv_stake_get_validators();
-        l_validators = dap_list_sort(l_validators, s_compare_validators_list_stake);
-        dap_list_t *l_list = dap_list_first(l_validators);
-        while (l_list){
-            dap_list_t *l_next = l_list->next;
-            dap_chain_node_addr_t *l_addr =
-                    (dap_chain_node_addr_t *)DAP_DUP_SIZE(
-                        &((dap_chain_net_srv_stake_item_t * )l_list->data)->node_addr,
-                            sizeof(dap_chain_node_addr_t));
-            DAP_DELETE(l_list->data);
-            l_ret = dap_list_append(l_ret, l_addr);
-            l_list = l_next;
-        }
-        dap_list_free(l_list);
-    }
-    else {
-        // dap_chain_net_t *l_net = dap_chain_net_by_id(a_session->chain->net_id);
-        dap_list_t *l_list = dap_list_first(PVT(a_session->ton)->ton_nodes_addrs);
-        while (l_list) {
-            dap_chain_node_addr_t *l_addr =
-                    (dap_chain_node_addr_t *)DAP_DUP_SIZE(
-                            l_list->data, sizeof(dap_chain_node_addr_t));
-            l_ret = dap_list_append(l_ret, l_addr);
-            l_list = l_list->next;
-        }
-        l_ret = dap_list_sort(l_ret, s_compare_validators_list_addr);
-    }
-    return l_ret;
-}
-
-static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cfg) {
-
-    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
-    dap_chain_cs_block_ton_t *l_ton = DAP_CHAIN_CS_BLOCK_TON(l_blocks);
-    dap_chain_cs_block_ton_pvt_t *l_ton_pvt = PVT(l_ton);
-
-    const char *l_sign_cert_str = NULL;
-    if ((l_sign_cert_str = dap_config_get_item_str(a_chain_net_cfg,"block-ton","blocks-sign-cert")) != NULL) {
-        dap_cert_t *l_sign_cert = dap_cert_find_by_name(l_sign_cert_str);
-        if (l_sign_cert == NULL) {
-            log_it(L_ERROR, "Can't load sign certificate, name \"%s\" is wrong", l_sign_cert_str);
-        } else if (l_sign_cert->enc_key->priv_key_data) {
-            l_ton_pvt->blocks_sign_key = l_sign_cert->enc_key;
-            log_it(L_INFO, "Loaded \"%s\" certificate to sign TON blocks", l_sign_cert_str);
-        } else {
-            log_it(L_ERROR, "Certificate \"%s\" has no private key", l_sign_cert_str);
-        }
-    } else {
-        log_it(L_ERROR, "No sign certificate provided, can't sign any blocks");
-    }
-
-    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
-    dap_chain_cs_block_ton_session_t *l_session = DAP_NEW_Z(dap_chain_cs_block_ton_session_t);
-    l_session->chain = a_chain;
-    l_session->ton = l_ton;
-
-    l_session->my_candidate = NULL;
-    l_session->my_candidate_size = 0;
-    l_session->my_candidate_attempts_count = 0;
-
-    l_session->cur_round.validators_list = s_get_validators_addr_list(l_session);
-    l_session->cur_round.validators_count = dap_list_length(l_session->cur_round.validators_list);
-
-    l_session->my_addr = DAP_NEW(dap_chain_node_addr_t);
-    l_session->my_addr->uint64 = dap_chain_net_get_cur_addr_int(l_net);
-
-    l_session->cur_round.id.uint64 = 1000;
-    pthread_rwlock_init(&l_session->cur_round.messages_rwlock, NULL);
-    l_session->gdb_group_store = dap_strdup_printf("local.ton.%s.%s.store",
-                                        a_chain->net_name, a_chain->name);
-    l_session->gdb_group_message = dap_strdup_printf("local.ton.%s.%s.message",
-                                        a_chain->net_name, a_chain->name);
-    l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE;
-
-    dap_time_t l_time = dap_time_now();
-    while (true) {
-        l_time++;
-        if ( (l_time % l_ton_pvt->round_start_multiple_of) == 0) {
-            l_session->ts_round_sync_start = l_time;
-            break;
-        }
-    }
-    pthread_rwlock_init(&l_session->rwlock, NULL);
-
-    log_it(L_INFO, "TON: init session for net:%s, chain:%s", a_chain->net_name, a_chain->name);
-    DL_APPEND(s_session_items, l_session);
-    dap_chain_node_role_t l_role = dap_chain_net_get_role(l_net);
-    if (l_ton_pvt->validators_list_by_stake ||
-                    (l_role.enums == NODE_ROLE_MASTER || l_role.enums == NODE_ROLE_ROOT) ) {
-        if ( s_session_get_validator(l_session, l_session->my_addr, l_session->cur_round.validators_list) ) {
-            if (!s_session_cs_timer) {
-                s_session_cs_timer = dap_interval_timer_create(1000, s_session_timer, NULL);
-                if (l_ton_pvt->debug)
-                    log_it(L_MSG, "TON: Consensus main timer is started");
-            }
-            dap_stream_ch_chain_voting_in_callback_add(l_session, s_session_packet_in);
-        }
-    }
-    return 0;
-}
-
-/**
- * @brief s_session_send_startsync
- * @param a_session
- * @return
- */
-static bool s_session_send_startsync(dap_chain_cs_block_ton_session_t *a_session)
-{
-    dap_chain_cs_block_ton_message_startsync_t *l_startsync =
-                                            DAP_NEW_Z(dap_chain_cs_block_ton_message_startsync_t);
-    l_startsync->ts = a_session->ts_round_sync_start;
-    l_startsync->round_id.uint64 = a_session->cur_round.id.uint64;
-    s_message_send(a_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_START_SYNC,
-                            (uint8_t*)l_startsync, sizeof(dap_chain_cs_block_ton_message_startsync_t),
-                                a_session->cur_round.validators_list);
-    if (PVT(a_session->ton)->debug)
-        log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" Sent START_SYNC pkt",
-                    a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id.uint64);
-
-    DAP_DELETE(l_startsync);
-    return false;
-}
-
-typedef struct s_session_send_votefor_data {
-    dap_chain_cs_block_ton_message_votefor_t *votefor;
-    dap_chain_cs_block_ton_session_t *session;
-} DAP_ALIGN_PACKED s_session_send_votefor_data_t;
-
-static bool s_session_send_votefor(s_session_send_votefor_data_t *a_data){
-    dap_chain_cs_block_ton_message_votefor_t *l_votefor = a_data->votefor;
-    dap_chain_cs_block_ton_session_t *l_session = a_data->session;
-    l_votefor->round_id.uint64 = l_session->cur_round.id.uint64;
-    s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR,
-                        (uint8_t*)l_votefor, sizeof(dap_chain_cs_block_ton_message_votefor_t),
-                            l_session->cur_round.validators_start);
-    DAP_DELETE(l_votefor);
-    DAP_DELETE(a_data);
-    return false;
-}
-
-/**
- * @brief s_session_round_start_callback_load_session_store_coordinator_state_proc
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_values_total
- * @param a_values_shift
- * @param a_values_count
- * @param a_values
- * @param a_arg
- */
-static void s_session_round_start_callback_load_session_store_coordinator_state_proc(dap_global_db_context_t *a_global_db_context,
-                                                                                     int a_rc, const char *a_group,
-                                                                                     const size_t a_values_total, const size_t a_values_count,
-                                                                                     dap_global_db_obj_t *a_values, void *a_arg)
-{
-    dap_chain_cs_block_ton_session_t * l_session = (dap_chain_cs_block_ton_session_t *) a_arg;
-    pthread_rwlock_wrlock(&l_session->rwlock);
-    dap_list_t *l_list_candidate = NULL;
-    // I am a coordinator :-) select candidate
-
-    if (a_values_count) {
-        for (size_t i = 0; i < a_values_count; i++) {
-            if (!a_values[i].value_len)
-                continue;
-
-            dap_chain_cs_block_ton_store_t *l_store =
-                        (dap_chain_cs_block_ton_store_t *)a_values[i].value;
-            if ( l_store->hdr.round_id.uint64 != l_session->cur_round.id.uint64 )
-                continue;
-
-            // add candidate in list if it has 2/3 approve
-            if ( l_store->hdr.approve_collected ) {
-                dap_chain_hash_fast_t * l_hash = DAP_NEW(dap_chain_hash_fast_t);
-                dap_chain_hash_fast_from_str(a_values[i].key, l_hash);
-                l_list_candidate = dap_list_append(l_list_candidate, l_hash);
-            }
-        }
-    }
-
-    size_t l_list_candidate_size = (size_t)dap_list_length(l_list_candidate);
-    dap_chain_cs_block_ton_message_votefor_t *l_votefor =
-                                    DAP_NEW_Z(dap_chain_cs_block_ton_message_votefor_t);
-    if (l_list_candidate) {
-        dap_chain_hash_fast_t *l_candidate_hash = dap_list_nth_data(l_list_candidate, (rand()%l_list_candidate_size));
-        l_votefor->candidate_hash = *l_candidate_hash;
-        dap_list_free_full(l_list_candidate, NULL);
-    } else {
-        l_votefor->candidate_hash = (dap_chain_hash_fast_t){ };
-    }
-    l_votefor->attempt_number = l_session->attempt_current_number;
-    s_session_send_votefor_data_t *l_data = DAP_NEW_Z(s_session_send_votefor_data_t);
-    l_data->votefor = l_votefor;
-    l_data->session = l_session;
-    dap_timerfd_start(PVT(l_session->ton)->first_message_delay*1000, // pause before send votefor
-            (dap_timerfd_callback_t)s_session_send_votefor,
-                l_data);
-    if (PVT(l_session->ton)->debug) {
-        char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_votefor->candidate_hash);
-        log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu I coordinator :-) Sent VoteFor candidate:%s",
-                l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                    l_session->attempt_current_number, l_hash_str);
-        DAP_DELETE(l_hash_str);
-    }
-    pthread_rwlock_unlock(&l_session->rwlock);
-}
-
-/**
- * @brief s_session_proc_state
- * @param l_session
- */
-static void s_session_proc_state( dap_chain_cs_block_ton_session_t * a_session)
-{
-    dap_time_t l_time = dap_time_now();
-    // Mostly we're writting in session on the next operations, at least we do it with state
-    if (pthread_rwlock_trywrlock(&a_session->rwlock) != 0) // Session is busy
-        return;
-    switch (a_session->state) {
-        case DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE: {
-            if ( (((l_time/10)*10) % PVT(a_session->ton)->round_start_multiple_of) == 0
-                        && (l_time - ((l_time/10)*10)) <= 3
-                        && l_time > a_session->ts_round_finish
-                        && (l_time-a_session->ts_round_finish) >= PVT(a_session->ton)->session_idle_min) {
-
-            // round start
-            s_session_round_clear(a_session);
-            a_session->cur_round.id.uint64++;
-            a_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_START;
-            a_session->ts_round_start = 0;
-            a_session->ts_round_state_commit = 0;
-            a_session->attempt_current_number = 1;
-            a_session->ts_round_sync_start = dap_time_now();
-            dap_chain_node_mempool_process_all(a_session->chain);
-            dap_list_free_full(a_session->cur_round.validators_list, free);
-            a_session->cur_round.validators_list = s_get_validators_addr_list(a_session);
-            a_session->cur_round.validators_count = dap_list_length(a_session->cur_round.validators_list);
-            dap_timerfd_start(PVT(a_session->ton)->first_message_delay*1000,
-                (dap_timerfd_callback_t)s_session_send_startsync, a_session);
-            if (PVT(a_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Start syncing validators ",
-                        a_session->chain->net_name, a_session->chain->name,
-                            a_session->cur_round.id.uint64, a_session->attempt_current_number);
-            } else
-                break;
-        }
-        case DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_START: {
-            if ( (l_time - a_session->ts_round_sync_start) < PVT(a_session->ton)->round_start_sync_timeout )
-                break; // timeout start sync
-            uint16_t l_startsync_count = a_session->cur_round.validators_start_count;
-            if (l_startsync_count * 3 >= a_session->cur_round.validators_count * 2) {
-                // if sync more 2/3 validators then start round and submit candidate
-                if (PVT(a_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu More than 2/3 of the validators are synchronized, so starting the round and send the candidate",
-                            a_session->chain->net_name, a_session->chain->name,
-                                a_session->cur_round.id.uint64, a_session->attempt_current_number);
-
-                a_session->ts_round_start = l_time;
-                a_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_CS_PROC;
-
-                // sort validators list
-                dap_list_t *l_validators_start = a_session->cur_round.validators_start;
-                a_session->cur_round.validators_start = NULL;
-                dap_list_t *l_validators_list_temp = dap_list_first(a_session->cur_round.validators_list);
-                while (l_validators_list_temp) {
-                    dap_chain_node_addr_t *l_validator_1 = (dap_chain_node_addr_t *)l_validators_list_temp->data;
-                    l_validators_list_temp = l_validators_list_temp->next;
-                    dap_list_t *l_validators_start_temp = dap_list_first(l_validators_start);
-                    while (l_validators_start_temp) {
-                        dap_chain_node_addr_t *l_validator_2 = (dap_chain_node_addr_t *)l_validators_start_temp->data;
-                        l_validators_start_temp = l_validators_start_temp->next;
-                        if ( l_validator_1->uint64 == l_validator_2->uint64 ) {
-                            a_session->cur_round.validators_start =
-                                    dap_list_append(a_session->cur_round.validators_start, l_validator_1);
-                        }
-                    }
-                }
-
-                // first coordinator
-                a_session->attempt_coordinator =
-                        (dap_chain_node_addr_t *)(dap_list_first(a_session->cur_round.validators_start)->data);
-            } else {
-                s_session_round_finish(a_session, true);
-                if (PVT(a_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Round finish by reason: can't synchronized 2/3 of the validators",
-                            a_session->chain->net_name, a_session->chain->name,
-                                a_session->cur_round.id.uint64, a_session->attempt_current_number);
-                break;
-            }
-        }
-        case DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS:
-        case DAP_STREAM_CH_CHAIN_SESSION_STATE_CS_PROC: {
-            if ( !a_session->cur_round.submit && a_session->attempt_current_number == 1 ) {
-                dap_list_t *l_validators_list = dap_list_first(a_session->cur_round.validators_start);
-                int l_my_number = -1;
-                int i = 0;
-                while(l_validators_list) {
-                    if( ((dap_chain_node_addr_t*)l_validators_list->data)->uint64 == a_session->my_addr->uint64) {
-                        l_my_number = i;
-                        break;
-                    }
-                    i++;
-                    l_validators_list = l_validators_list->next;
-                }
-                if ( l_my_number != -1 ) {
-                    l_my_number++;
-                    if ( (l_time-a_session->ts_round_start) >=
-                                (dap_time_t)((PVT(a_session->ton)->next_candidate_delay*l_my_number)+PVT(a_session->ton)->first_message_delay) ) {
-                        a_session->cur_round.submit = true;
-                        s_session_candidate_submit(a_session);
-                    }
-                }
-            }
-
-            if ( (l_time - a_session->ts_round_start) >=
-                        (dap_time_t)(PVT(a_session->ton)->round_attempt_duration * a_session->attempt_current_number) ) {
-
-                a_session->attempt_current_number++;
-                if ( a_session->attempt_current_number > PVT(a_session->ton)->round_attempts_max ) {
-                    s_session_round_finish(a_session,true); // attempts is out
-                    if (PVT(a_session->ton)->debug)
-                        log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Round finish by reason: attempts is out",
-                                a_session->chain->net_name, a_session->chain->name,
-                                    a_session->cur_round.id.uint64, a_session->attempt_current_number);
-                    break;
-                }
-                if ( a_session->cur_round.candidates_count == 0 ) { // no candidates
-                    s_session_round_finish(a_session,true);
-                    if (PVT(a_session->ton)->debug)
-                        log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Round finish by reason: no block candidates",
-                                a_session->chain->net_name, a_session->chain->name,
-                                    a_session->cur_round.id.uint64, a_session->attempt_current_number);
-                    break;
-                }
-                if ( a_session->state == DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS ) {
-                    break;
-                }
-
-                uint16_t l_validators_count = a_session->cur_round.validators_start_count;
-                uint64_t l_mod = 0;
-                if (!PVT(a_session->ton)->validators_list_by_stake) {
-                    // rotate validatir list in non-stake mode
-                    l_mod = a_session->cur_round.id.uint64;
-                }
-                uint16_t l_validators_index =
-                                ( (a_session->attempt_current_number-2+l_mod)
-                                    - (l_validators_count
-                                            *((a_session->attempt_current_number-2+l_mod)/l_validators_count)));
-
-                a_session->attempt_coordinator = (dap_chain_node_addr_t *)
-                                        (dap_list_nth(a_session->cur_round.validators_start,
-                                                l_validators_index)->data);
-                if (PVT(a_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Start attempt: selected coordinator "NODE_ADDR_FP_STR"(index:%u)",
-                            a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id.uint64,
-                                a_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_session->attempt_coordinator),
-                                    l_validators_index);
-
-                if ( a_session->my_addr->uint64 == a_session->attempt_coordinator->uint64 ) {
-                    // I am coordinator :-) select candidate
-                    dap_global_db_get_all(a_session->gdb_group_store,0,s_session_round_start_callback_load_session_store_coordinator_state_proc, a_session);
-                    break; // Unlock in its callback
-                }
-            }
-        }
-    }
-    pthread_rwlock_unlock(&a_session->rwlock);
-}
-
-/**
- * @brief s_session_timer
- * @return
- */
-static void s_session_timer(void *a_arg)
-{
-    UNUSED(a_arg);
-    dap_chain_cs_block_ton_session_t *l_session = NULL;
-    DL_FOREACH(s_session_items, l_session) {
-        s_session_proc_state(l_session);
-    }
-}
-
-/**
- * @brief s_session_candidate_to_chain
- * @param a_session
- * @param a_candidate_hash
- * @param a_candidate
- * @param a_candidate_size
- */
-static void s_session_candidate_to_chain(
-            dap_chain_cs_block_ton_session_t *a_session, dap_chain_hash_fast_t *a_candidate_hash,
-                            dap_chain_block_t *a_candidate, size_t a_candidate_size)
-{
-
-    dap_list_t *l_commitsign_list = NULL;
-    dap_chain_hash_fast_t *l_candidate_hash = NULL;
-    dap_chain_cs_block_ton_message_item_t *l_message_item=NULL, *l_message_tmp=NULL;
-    pthread_rwlock_rdlock(&a_session->cur_round.messages_rwlock);
-    HASH_ITER(hh, a_session->cur_round.messages_items, l_message_item, l_message_tmp) {
-        uint8_t l_message_type = l_message_item->message->hdr.type;
-        if ( l_message_type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN ) {
-            l_candidate_hash = &((dap_chain_cs_block_ton_message_commitsign_t *)
-                            (l_message_item->message->sign_n_message+l_message_item->message->hdr.sign_size))->candidate_hash;
-            if ( memcmp(l_candidate_hash, a_candidate_hash, sizeof(dap_chain_hash_fast_t)) == 0) {
-                l_commitsign_list = dap_list_append(l_commitsign_list, (void*)l_message_item->message);
-            }
-        }
-    }
-    pthread_rwlock_unlock(&a_session->cur_round.messages_rwlock);
-    if (!l_commitsign_list) {
-        return;
-    }
-    dap_chain_block_t *l_candidate =
-        (dap_chain_block_t *)DAP_DUP_SIZE(a_candidate, a_candidate_size);
-
-    size_t l_signs_count = 0;
-    dap_list_t *l_validators_list = dap_list_first(a_session->cur_round.validators_start);
-    while(l_validators_list) {
-        dap_chain_node_addr_t *l_validator = (dap_chain_node_addr_t *)l_validators_list->data;
-        l_validators_list = l_validators_list->next;
-        dap_list_t *l_submit_temp = dap_list_first(l_commitsign_list);
-        while(l_submit_temp) {
-            dap_chain_cs_block_ton_message_t *l_message = (dap_chain_cs_block_ton_message_t *)l_submit_temp->data;
-            dap_chain_cs_block_ton_message_commitsign_t *l_commitsign =
-                        (dap_chain_cs_block_ton_message_commitsign_t *)
-                                    (l_message->sign_n_message+l_message->hdr.sign_size);
-            if( l_message->hdr.is_verified
-                    && l_message->hdr.sender_node_addr.uint64 == l_validator->uint64) {
-                dap_sign_t *l_candidate_sign = (dap_sign_t *)l_commitsign->candidate_sign;
-                size_t l_candidate_sign_size = dap_sign_get_size(l_candidate_sign);
-                if (!l_candidate_sign_size) {
-                    continue;
-                }
-                l_candidate = DAP_REALLOC(l_candidate, a_candidate_size+l_candidate_sign_size);
-                memcpy(((byte_t *)l_candidate)+a_candidate_size, l_candidate_sign, l_candidate_sign_size);
-                a_candidate_size += l_candidate_sign_size;
-                l_signs_count++;
-            }
-            l_submit_temp = l_submit_temp->next;
-        }
-    }
-
-    if (l_signs_count * 3 >= a_session->cur_round.validators_count * 2) {
-        dap_chain_atom_verify_res_t l_res = a_session->chain->callback_atom_add(a_session->chain, l_candidate, a_candidate_size);
-        char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(a_candidate_hash);
-        switch (l_res) {
-            case ATOM_ACCEPT: {
-                // block save to chain
-                if (dap_chain_atom_save(a_session->chain, (uint8_t *)l_candidate, a_candidate_size, a_session->chain->cells->id) < 0) {
-                    log_it(L_ERROR, "TON: Can't save atom %s to the file", l_candidate_hash_str);
-                }
-                else {
-                    log_it(L_INFO, "TON: atom %s added in chain successfully", l_candidate_hash_str);
-                    dap_chain_hash_fast_t l_block_hash;
-                    dap_hash_fast(l_candidate, a_candidate_size, &l_block_hash);
-                    char *l_block_hash_str = dap_chain_hash_fast_to_str_new(&l_block_hash);
-                    log_it(L_INFO, "TON: block %s added in chain successfully", l_block_hash_str);
-                    DAP_DELETE(l_block_hash_str);
-                }
-            } break;
-            case ATOM_MOVE_TO_THRESHOLD: {
-                log_it(L_INFO, "TON: Thresholded atom with hash %s", l_candidate_hash_str);
-            } break;
-            case ATOM_PASS: {
-                log_it(L_WARNING, "TON: Atom with hash %s not accepted (code ATOM_PASS, already present)", l_candidate_hash_str);
-                DAP_DELETE(l_candidate);
-            } break;
-            case ATOM_REJECT: {
-                log_it(L_WARNING,"TON: Atom with hash %s rejected", l_candidate_hash_str);
-                DAP_DELETE(l_candidate);
-            } break;
-            default:
-                 log_it(L_CRITICAL, "TON: Wtf is this ret code ? Atom hash %s code %d", l_candidate_hash_str, l_res);
-                 DAP_DELETE(l_candidate);
-        }
-        DAP_DELETE(l_candidate_hash_str);
-        dap_chain_hash_fast_t l_my_candidate_hash;
-        dap_hash_fast(a_session->my_candidate, a_session->my_candidate_size, &l_my_candidate_hash);
-        if (dap_hash_fast_compare(&l_my_candidate_hash, a_candidate_hash))
-            s_session_my_candidate_delete(a_session);
-    }
-}
-
-static void s_session_candidate_submit(dap_chain_cs_block_ton_session_t *a_session)
-{
-    dap_chain_t *l_chain = a_session->chain;
-    s_session_my_candidate_delete(a_session);
-    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(l_chain);
-    a_session->my_candidate = l_blocks->callback_new_block_move(l_blocks, &a_session->my_candidate_size);
-    size_t l_submit_size = a_session->my_candidate ?
-                sizeof(dap_chain_cs_block_ton_message_submit_t)+a_session->my_candidate_size
-                    : sizeof(dap_chain_cs_block_ton_message_submit_t);
-    dap_chain_cs_block_ton_message_submit_t *l_submit =
-                            DAP_NEW_SIZE(dap_chain_cs_block_ton_message_submit_t, l_submit_size);
-    l_submit->round_id.uint64 = a_session->cur_round.id.uint64;
-    l_submit->candidate_size = a_session->my_candidate_size;
-
-    if ( a_session->my_candidate ) {
-        dap_chain_hash_fast_t l_candidate_hash;
-        dap_hash_fast(a_session->my_candidate, a_session->my_candidate_size, &l_candidate_hash);
-        a_session->cur_round.my_candidate_hash = l_submit->candidate_hash = l_candidate_hash;
-        memcpy(l_submit->candidate, a_session->my_candidate, a_session->my_candidate_size);
-        if (PVT(a_session->ton)->debug) {
-            char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_candidate_hash);
-            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" Submit my candidate:%s",
-                    a_session->chain->net_name, a_session->chain->name,
-                        a_session->cur_round.id.uint64, l_hash_str);
-            DAP_DELETE(l_hash_str);
-        }
-        a_session->my_candidate_attempts_count++;
-    } else { // no my candidate, send null hash
-        a_session->cur_round.my_candidate_hash = l_submit->candidate_hash = (dap_chain_hash_fast_t){};
-        if (PVT(a_session->ton)->debug)
-            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu I don't have a candidate. I submit a null candidate.",
-                        a_session->chain->net_name, a_session->chain->name,
-                            a_session->cur_round.id.uint64, a_session->attempt_current_number);
-    }
-    s_message_send(a_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT,
-                    (uint8_t*)l_submit, l_submit_size, a_session->cur_round.validators_start);
-    DAP_DELETE(l_submit);
-}
-
-static int s_session_atom_validation(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t *a_block, size_t a_block_size){
-    dap_chain_cs_block_ton_t *l_ton = DAP_CHAIN_CS_BLOCK_TON(a_blocks);
-    dap_chain_atom_verify_res_t l_res = ATOM_ACCEPT;
-    PVT(l_ton)->flag_sign_verify = false;
-    l_res = a_blocks->chain->callback_atom_verify(a_blocks->chain, a_block, a_block_size);
-    PVT(l_ton)->flag_sign_verify = true;
-    if(l_res == ATOM_ACCEPT){
-        return 0;
-    }
-    return -1;
-}
-
-static void s_session_my_candidate_delete(dap_chain_cs_block_ton_session_t *a_session) {
-    if (a_session->my_candidate){
-        if (PVT(a_session->ton)->debug) {
-            dap_chain_hash_fast_t l_candidate_hash;
-            dap_hash_fast(a_session->my_candidate, a_session->my_candidate_size, &l_candidate_hash);
-            char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_candidate_hash);
-            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Delete my candidate %s",
-                    a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id.uint64,
-                        a_session->attempt_current_number, l_hash_str );
-            DAP_DELETE(l_hash_str);
-        }
-        DAP_DEL_Z(a_session->my_candidate);
-    }
-    a_session->my_candidate_size = 0;
-    a_session->my_candidate_attempts_count = 0;
-}
-
-static void s_session_round_clear(dap_chain_cs_block_ton_session_t *a_session)
-{
-    a_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE;
-    a_session->ts_round_finish = dap_time_now();
-    // Truncate this group
-    dap_global_db_del(a_session->gdb_group_store, NULL, NULL, NULL);
-    dap_chain_cs_block_ton_message_item_t *l_message_item=NULL, *l_message_tmp=NULL;
-    pthread_rwlock_wrlock(&a_session->cur_round.messages_rwlock);
-    HASH_ITER(hh, a_session->cur_round.messages_items, l_message_item, l_message_tmp) {
-        HASH_DEL(a_session->cur_round.messages_items, l_message_item);
-        DAP_DELETE(l_message_item->message);
-        DAP_DELETE(l_message_item);
-    }
-    pthread_rwlock_unlock(&a_session->cur_round.messages_rwlock);
-    pthread_rwlock_destroy(&a_session->cur_round.messages_rwlock);
-
-    if (a_session->cur_round.validators_start)
-        // delete only links
-        dap_list_free(a_session->cur_round.validators_start);
-    if (a_session->cur_round.validators_list)
-        // delete validators
-        dap_list_free_full(a_session->cur_round.validators_list, NULL);
-
-    dap_chain_cs_block_ton_round_id_t l_round_id = a_session->cur_round.id;
-    a_session->cur_round = (dap_chain_cs_block_ton_round_t){.id = l_round_id};
-    pthread_rwlock_init(&a_session->cur_round.messages_rwlock, NULL);
-    log_it(L_MSG, "All data for round %"DAP_UINT64_FORMAT_U" cleared", l_round_id.uint64);
-}
-
-/**
- * @brief s_session_round_finish_callback_load_store
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_values_total
- * @param a_values_shift
- * @param a_values_count
- * @param a_values
- * @param a_arg
- */
-static void s_session_round_finish_callback_load_store(dap_global_db_context_t *a_global_db_context,
-                                                       int a_rc, const char *a_group,
-                                                       const size_t a_values_total, const size_t a_values_count,
-                                                       dap_global_db_obj_t *a_values, void *a_arg)
-
-{
-    dap_chain_cs_block_ton_session_t *l_session = (dap_chain_cs_block_ton_session_t *)a_arg;
-
-    pthread_rwlock_wrlock(&l_session->rwlock); // lock for writting
-
-    l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE;
-    l_session->ts_round_finish = dap_time_now();
-
-    for (size_t i = 0; i < a_values_count; i++) {
-        if (!a_values[i].value_len)
-            continue;
-        dap_chain_cs_block_ton_store_t *l_store = (dap_chain_cs_block_ton_store_t*)a_values[i].value;
-        if (l_store->hdr.round_id.uint64 != l_session->cur_round.id.uint64)
-            continue;
-        if (l_store->hdr.sign_collected)
-            s_session_candidate_to_chain(l_session, &l_store->hdr.candidate_hash,
-                                             (dap_chain_block_t*)l_store->candidate_n_signs,
-                                             l_store->hdr.candidate_size);
-        else if (dap_hash_fast_compare(&l_store->hdr.candidate_hash, &l_session->cur_round.my_candidate_hash)) {
-            if (PVT(l_session->ton)->debug) {
-                char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_store->hdr.candidate_hash);
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu My candidate:%s %s. Delete block_new.",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            l_session->attempt_current_number, l_hash_str,
-                            (l_store->hdr.approve_collected ? "approved with consensus" : "didn't collect 2/3 approve."));
-                DAP_DELETE(l_hash_str);
-            }
-            s_session_my_candidate_delete(l_session);
-            memset(&l_session->cur_round.my_candidate_hash, 0, sizeof(l_session->cur_round.my_candidate_hash));
-
-        }
-    }
-    s_session_round_clear(l_session);
-    pthread_rwlock_unlock(&l_session->rwlock); // then unlock anyway
-}
-/**
- * @brief Finish TON round (asyncroniusly)
- * @param a_session
- * @param a_is_time_proc_lock
- * @return
- */
-static void s_session_round_finish(dap_chain_cs_block_ton_session_t *a_session, bool a_failed)
-{
-    if (a_failed) {
-        s_session_round_clear(a_session);
-        return;
-    }
-    if (dap_global_db_get_all(a_session->gdb_group_store,0,s_session_round_finish_callback_load_store, a_session) != 0)
-        log_it(L_ERROR,"Can't process get_all request for group \"%s\"", a_session->gdb_group_store);
-}
-
-// this is planned for get validator addr if validator addr list to be changed to stakes,
-// but currently it using for check validator addr exists
-static dap_chain_node_addr_t *s_session_get_validator(dap_chain_cs_block_ton_session_t *a_session,
-                                                      dap_chain_node_addr_t *a_addr,
-                                                      dap_list_t *a_validators)
-{
-
-    // dap_chain_cs_block_ton_round_t *l_round = a_round_name == DAP_TON$ROUND_CUR ? // 'c' or 'o'
-    // 					&a_session->cur_round : &a_session->old_round;
-    dap_list_t* l_list_validator = dap_list_first(a_validators);
-    while(l_list_validator) {
-        dap_list_t *l_list_validator_next = l_list_validator->next;
-        if ( ((dap_chain_node_addr_t *)l_list_validator->data)->uint64 == a_addr->uint64 )
-            return l_list_validator->data;
-        l_list_validator = l_list_validator_next;
-    }
-    return NULL;
-}
-
-static uint16_t s_session_message_count(dap_chain_cs_block_ton_session_t *a_session, uint8_t a_type,
-                                        dap_chain_hash_fast_t *a_candidate_hash, uint16_t *a_attempt_number)
-{
-    dap_chain_cs_block_ton_message_item_t *l_messages_items = NULL;
-    l_messages_items = a_session->cur_round.messages_items;
-    uint16_t l_message_count = 0;
-    dap_chain_cs_block_ton_message_item_t *l_chain_message=NULL, *l_chain_message_tmp=NULL;
-    HASH_ITER(hh, l_messages_items, l_chain_message, l_chain_message_tmp) {
-        dap_chain_cs_block_ton_message_getinfo_t *l_getinfo = (dap_chain_cs_block_ton_message_getinfo_t *)
-                            (l_chain_message->message->sign_n_message+l_chain_message->message->hdr.sign_size);
-        if (l_chain_message->message->hdr.type == a_type &&
-                (!a_candidate_hash || memcmp(&l_getinfo->candidate_hash, a_candidate_hash,
-                                            sizeof(dap_chain_hash_fast_t)) == 0)) {
-            switch(a_type) {
-                // case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT:
-                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR:
-                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
-                    if ( a_attempt_number && *a_attempt_number == l_getinfo->attempt_number) {
-                        l_message_count++;
-                    }
-                } break;
-                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
-                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: {
-                    if (l_chain_message->message->hdr.is_verified){
-                        l_message_count++;
-                    }
-                } break;
-                default:
-                    l_message_count++;
-                    break;
-            }
-        }
-    }
-    return l_message_count;
-}
-
-struct vote_for_load_store_args
-{
-    dap_chain_cs_block_ton_session_t *session;
-    dap_chain_hash_fast_t candidate_hash;
-};
-
-/**
- * @brief s_session_packet_in_callback_vote_for_load_store
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_values_total
- * @param a_values_shift
- * @param a_values_count
- * @param a_values
- * @param a_arg
- */
-static void s_session_packet_in_callback_vote_for_load_store(dap_global_db_context_t *a_global_db_context,
-                                                             int a_rc, const char *a_group,
-                                                             const size_t a_values_total, const size_t a_values_count,
-                                                             dap_global_db_obj_t *a_values, void *a_arg)
-{
-    dap_chain_cs_block_ton_session_t * l_session = ((struct vote_for_load_store_args *) a_arg)->session;
-    dap_chain_hash_fast_t * l_candidate_hash = &((struct vote_for_load_store_args *) a_arg)->candidate_hash;
-
-    dap_chain_cs_block_ton_store_t *l_found_best = NULL;
-    dap_chain_cs_block_ton_store_t *l_found_vote = NULL;
-    dap_chain_cs_block_ton_store_t *l_found_approve_vf = NULL;
-    // dap_chain_cs_block_ton_store_t *l_found_approve = NULL;
-    pthread_rwlock_rdlock(&l_session->rwlock);
-    if (a_values_count) {
-        for (size_t i = 0; i < a_values_count; i++) {
-            if (!a_values[i].value_len)
-                continue;
-            dap_chain_cs_block_ton_store_t *l_store =
-                    (dap_chain_cs_block_ton_store_t *)a_values[i].value;
-            if ( l_store->hdr.round_id.uint64 != l_session->cur_round.id.uint64 )
-                continue;
-            if (l_store->hdr.vote_collected) {
-                // best choice :-) 2/3 vote (i.e. PreCommit) and VoteFor candidate
-                if (memcmp(l_candidate_hash, &l_store->hdr.candidate_hash, sizeof(dap_chain_hash_fast_t)) == 0) {
-                    l_found_best = (dap_chain_cs_block_ton_store_t *)a_values[i].value;
-                    break;
-                }
-
-                // other PreCommit candidate (ignore VoteFor)
-                if ( !l_found_vote
-                        || l_found_vote->hdr.ts_candidate_submit<l_store->hdr.ts_candidate_submit ) {
-                    l_found_vote = (dap_chain_cs_block_ton_store_t *)a_values[i].value;
-                }
-            }
-            if ( l_store->hdr.approve_collected ) {
-                // 2/3 Approve & VoteFor
-                if (memcmp(l_candidate_hash, &l_store->hdr.candidate_hash, sizeof(dap_chain_hash_fast_t)) == 0) {
-                    l_found_approve_vf = (dap_chain_cs_block_ton_store_t *)a_values[i].value;
-                    break;
-                }
-                // 2/3 Approve (ignore VoteFor)
-                //	if ( !l_found_approve
-                // 		|| l_found_approve->hdr.ts_candidate_submit<l_store->hdr.ts_candidate_submit ) {
-                // 	l_found_approve = (dap_chain_cs_block_ton_store_t *)l_objs[i].value;
-                // }
-            }
-        }
-
-        dap_chain_cs_block_ton_store_t *l_found_candidate = NULL;
-        if (l_found_best) {
-            l_found_candidate = l_found_best;
-        }
-        else if (l_found_vote) {
-            l_found_candidate = l_found_vote;
-        }
-        else if (l_found_approve_vf) {
-            l_found_candidate = l_found_approve_vf;
-        }
-        // else if (l_found_approve) {
-        // 	l_found_candidate = l_found_approve;
-        // }
-
-        if (l_found_candidate) {
-            // candidate found, gen event Vote
-            dap_chain_cs_block_ton_message_vote_t *l_vote =
-                                                DAP_NEW_Z(dap_chain_cs_block_ton_message_vote_t);
-            l_vote->candidate_hash = l_found_candidate->hdr.candidate_hash;
-            l_vote->round_id.uint64 = l_session->cur_round.id.uint64;
-            l_vote->attempt_number = l_session->attempt_current_number;
-
-            s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE, (uint8_t*)l_vote,
-                            sizeof(dap_chain_cs_block_ton_message_vote_t), l_session->cur_round.validators_start);
-            if (PVT(l_session->ton)->debug) {
-                char *l_hash_str = dap_chain_hash_fast_to_str_new(&l_vote->candidate_hash);
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Sent VOTE for candidate:%s",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            l_session->attempt_current_number, l_hash_str);
-                DAP_DELETE(l_hash_str);
-            }
-            DAP_DELETE(l_vote);
-        }
-    }
-    pthread_rwlock_unlock(&l_session->rwlock);
-    DAP_DELETE(a_arg);
-}
-
-/**
- * @brief The proc_msg_type_commit_sign struct
- */
-struct proc_msg_type_commit_sign{
-    dap_chain_cs_block_ton_session_t *session;
-    dap_chain_hash_fast_t candidate_hash;
-    dap_sign_t *candidate_sign;
-    char * candidate_hash_str;
-
-    dap_chain_cs_block_ton_round_t * round;
-    dap_chain_cs_block_ton_round_id_t round_id;
-
-    dap_chain_cs_block_ton_message_t * message;
-    size_t message_size;
-    dap_chain_node_addr_t sender_node_addr;
-};
-
-/**
- * @brief s_callback_get_candidate_block_and_commit_sign
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_size
- * @param a_value_ts
- * @param a_is_pinned
- * @param a_arg
- */
-static void s_callback_get_candidate_block_and_commit_sign(dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const void * a_value, const size_t a_value_size, dap_nanotime_t a_value_ts, bool a_is_pinned, void * a_arg)
-{
-    struct proc_msg_type_commit_sign * l_args = (struct proc_msg_type_commit_sign *) a_arg;
-    dap_chain_cs_block_ton_session_t *l_session = l_args->session;
-    dap_chain_hash_fast_t l_candidate_hash = l_args->candidate_hash;
-    dap_sign_t *l_candidate_sign = l_args->candidate_sign;
-    char * l_candidate_hash_str = l_args->candidate_hash_str;
-    dap_chain_cs_block_ton_message_t * l_message = l_args->message;
-    size_t l_message_size = l_args->message_size;
-    dap_chain_node_addr_t l_sender_node_addr = l_args->sender_node_addr;
-    dap_chain_cs_block_ton_round_t * l_round = l_args->round; // Part of session, rwlock need to be locked properly with it
-    dap_chain_cs_block_ton_round_id_t l_round_id = l_args->round_id;
-
-    DAP_DELETE(l_args);
-
-    size_t l_store_size = a_value_size;
-    dap_chain_cs_block_ton_store_t *l_store = (dap_chain_cs_block_ton_store_t *) a_value;
-
-    pthread_rwlock_wrlock(&l_session->rwlock);
-
-    if (l_store) {
-        size_t l_candidate_size = l_store->hdr.candidate_size;
-        dap_chain_block_t *l_candidate =
-                (dap_chain_block_t *)DAP_DUP_SIZE(&l_store->candidate_n_signs, l_candidate_size);
-        size_t l_offset = dap_chain_block_get_sign_offset(l_candidate, l_candidate_size);
-
-        int l_sign_verified=0;
-        // check candidate hash sign
-        if ( (l_sign_verified=dap_sign_verify(l_candidate_sign,
-                                        l_candidate, l_offset+sizeof(l_candidate->hdr))) == 1 ) {
-            l_store->hdr.sign_collected = true;
-            s_message_chain_add(l_session, &l_sender_node_addr, l_message, l_message_size, NULL);
-            if (dap_global_db_set_unsafe(a_global_db_context, l_session->gdb_group_store, l_candidate_hash_str, l_store,
-                            l_store_size, true) == 0 ) {
-                uint16_t l_commitsign_count = s_session_message_count(
-                                l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN,
-                                &l_candidate_hash, NULL);
-                if (l_commitsign_count * 3 >= l_round->validators_count * 2) {
-                    if (PVT(l_session->ton)->debug)
-                        log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Candidate:%s collected COMMIT_SIGN more than 2/3 of the validators, so finish this round",
-                                l_session->chain->net_name, l_session->chain->name, l_round->id.uint64,
-                                    l_session->attempt_current_number, l_candidate_hash_str);
-                    if (l_round_id.uint64 == l_session->cur_round.id.uint64)
-                        s_session_round_finish(l_session, false);
-                }
-            }
-        } else
-            log_it(L_WARNING, "Candidate:%s sign is incorrect: code %d", l_candidate_hash_str, l_sign_verified);
-    }
-    pthread_rwlock_unlock(&l_session->rwlock);
-    DAP_DELETE(l_message);
-    DAP_DELETE(l_candidate_hash_str);
-}
-
-
-/**
- * @brief The proc_msg_type_pre_commit struct
- */
-struct proc_msg_type_pre_commit{
-    dap_chain_cs_block_ton_session_t *session;
-    dap_chain_hash_fast_t candidate_hash;
-    char * candidate_hash_str;
-};
-
-/**
- * @brief s_callback_get_candidate_block_and_pre_commit
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_size
- * @param a_value_ts
- * @param a_is_pinned
- * @param a_arg
- */
-static void s_callback_get_candidate_block_and_pre_commit (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const void * a_value, const size_t a_value_size, dap_nanotime_t a_value_ts, bool a_is_pinned, void * a_arg)
-{
-    struct proc_msg_type_pre_commit * l_args = (struct proc_msg_type_pre_commit *) a_arg;
-    dap_chain_cs_block_ton_session_t *l_session = l_args->session;
-    dap_chain_hash_fast_t l_candidate_hash = l_args->candidate_hash;
-    char * l_candidate_hash_str = l_args->candidate_hash_str;
-    DAP_DELETE(l_args);
-
-    size_t l_store_size = a_value_size;
-    dap_chain_cs_block_ton_store_t *l_store = (dap_chain_cs_block_ton_store_t *) a_value;
-
-    pthread_rwlock_rdlock(&l_session->rwlock);
-
-    // event CommitSign
-    if (l_store) {
-        if (PVT(l_session->ton)->blocks_sign_key) {
-            l_store->hdr.precommit_collected = true;
-
-            if (dap_global_db_set_unsafe(a_global_db_context, l_session->gdb_group_store,l_candidate_hash_str, l_store,
-                                  l_store_size, true ) == 0 ) {
-                size_t l_candidate_size = l_store->hdr.candidate_size;
-                dap_chain_block_t *l_candidate =
-                        (dap_chain_block_t *)DAP_DUP_SIZE(&l_store->candidate_n_signs, l_candidate_size);
-                size_t l_offset = dap_chain_block_get_sign_offset(l_candidate, l_candidate_size);
-                dap_sign_t *l_candidate_sign = dap_sign_create(PVT(l_session->ton)->blocks_sign_key,
-                                                l_candidate, l_offset + sizeof(l_candidate->hdr), 0);
-                size_t l_candidate_sign_size = dap_sign_get_size(l_candidate_sign);
-
-                size_t l_commitsign_size = sizeof(dap_chain_cs_block_ton_message_commitsign_t)+l_candidate_sign_size;
-                dap_chain_cs_block_ton_message_commitsign_t *l_commitsign =
-                                        DAP_NEW_SIZE(dap_chain_cs_block_ton_message_commitsign_t, l_commitsign_size);
-                l_commitsign->round_id.uint64 = l_session->cur_round.id.uint64;
-//                memcpy(&l_commitsign->candidate_hash, &l_candidate_hash, sizeof(dap_chain_hash_fast_t));
-                l_commitsign->candidate_hash = l_candidate_hash;
-                memcpy(l_commitsign->candidate_sign, l_candidate_sign, l_candidate_sign_size);
-                s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN, (uint8_t*)l_commitsign,
-                                    l_commitsign_size, l_session->cur_round.validators_start);
-                DAP_DELETE(l_commitsign);
-                DAP_DELETE(l_candidate);
-                DAP_DELETE(l_candidate_sign);
-                pthread_rwlock_unlock(&l_session->rwlock);
-
-                pthread_rwlock_wrlock(&l_session->rwlock);
-                l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS;
-                l_session->ts_round_state_commit = dap_time_now();
-
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" attempt:%hu Candidate:%s collected PRE_COMMIT more than 2/3 of the validators, so to sent a COMMIT_SIGN",
-                            l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                                l_session->attempt_current_number, l_candidate_hash_str);
-            }
-        }
-        else {
-            log_it(L_WARNING, "Can't sign block with blocks-sign-cert in [block-ton] section");
-        }
-    }
-    pthread_rwlock_unlock(&l_session->rwlock);
-
-    DAP_DELETE(l_candidate_hash_str);
-
-}
-
-/**
- * @brief The proc_msg_type_vote struct
- */
-struct proc_msg_type_vote{
-    dap_chain_cs_block_ton_session_t *session;
-    dap_chain_hash_fast_t candidate_hash;
-    char * candidate_hash_str;
-};
-
-/**
- * @brief s_callback_get_candidate_block_and_vote
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_size
- * @param a_value_ts
- * @param a_is_pinned
- * @param a_arg
- */
-static void s_callback_get_candidate_block_and_vote (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const void * a_value, const size_t a_value_size, dap_nanotime_t a_value_ts, bool a_is_pinned, void * a_arg)
-{
-    struct proc_msg_type_vote * l_args = (struct proc_msg_type_vote *) a_arg;
-    dap_chain_cs_block_ton_session_t *l_session = l_args->session;
-    dap_chain_hash_fast_t l_candidate_hash = l_args->candidate_hash;
-    char * l_candidate_hash_str = l_args->candidate_hash_str;
-    DAP_DELETE(l_args);
-    size_t l_store_size = a_value_size;
-    dap_chain_cs_block_ton_store_t *l_store = (dap_chain_cs_block_ton_store_t *) a_value;
-    if (l_store) {
-        l_store->hdr.vote_collected = true;
-        if (dap_global_db_set_unsafe(a_global_db_context, l_session->gdb_group_store, l_candidate_hash_str,
-                              l_store,	l_store_size, true ) == 0 ) {
-            // Send PreCommit
-            dap_chain_cs_block_ton_message_precommit_t l_precommit = {
-                .round_id.uint64 = l_session->cur_round.id.uint64,
-                .candidate_hash = l_candidate_hash,
-                .attempt_number = l_session->attempt_current_number
-            };
-            s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT, (uint8_t*)&l_precommit,
-                            sizeof(dap_chain_cs_block_ton_message_precommit_t), l_session->cur_round.validators_start);
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Candidate:%s collected VOTE more than 2/3 of the validators, so to sent a PRE_COMMIT",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            l_session->attempt_current_number, l_candidate_hash_str);
-        }
-    }
-    DAP_DELETE(l_candidate_hash_str);
-
-}
-
-
-/**
- * @brief The proc_msg_type_approve struct
- */
-struct proc_msg_type_approve{
-    dap_chain_cs_block_ton_session_t *session;
-    dap_chain_hash_fast_t candidate_hash;
-    char * candidate_hash_str;
-};
-
-/**
- * @brief s_callback_get_candidate_block_and_approve
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_size
- * @param a_value_ts
- * @param a_is_pinned
- * @param a_arg
- */
-static void s_callback_get_candidate_block_and_approve (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const void * a_value, const size_t a_value_size, dap_nanotime_t a_value_ts, bool a_is_pinned, void * a_arg)
-{
-    struct proc_msg_type_approve * l_args = (struct proc_msg_type_approve *) a_arg;
-    dap_chain_cs_block_ton_session_t *l_session = l_args->session;
-    dap_chain_hash_fast_t l_candidate_hash = l_args->candidate_hash;
-    char * l_candidate_hash_str = l_args->candidate_hash_str;
-
-    DAP_DELETE(l_args);
-
-    dap_chain_cs_block_ton_store_t *l_store = (dap_chain_cs_block_ton_store_t *) a_value;
-    size_t l_store_size = a_value_size;
-
-    pthread_rwlock_rdlock(&l_session->rwlock);
-
-    if (l_store && !l_store->hdr.approve_collected) {
-        if (PVT(l_session->ton)->debug)
-            log_it(L_MSG, "TON: APPROVE: candidate found in store:%s & !approve_collected", l_candidate_hash_str);
-        l_store->hdr.approve_collected = true;
-        if (dap_global_db_set_unsafe( a_global_db_context, l_session->gdb_group_store,l_candidate_hash_str,
-                                       l_store,l_store_size, true) == 0 ) {
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: APPROVE: candidate update:%s approve_collected=true", l_candidate_hash_str);
-        } else
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: APPROVE: can`t update candidate:%s", l_candidate_hash_str);
-
-        // event Vote
-        dap_chain_cs_block_ton_message_vote_t l_vote = {};
-        l_vote.round_id.uint64 = l_session->cur_round.id.uint64;
-//        memcpy(&l_vote->candidate_hash, &l_candidate_hash, sizeof(dap_chain_hash_fast_t));
-        l_vote.candidate_hash = l_candidate_hash;
-        l_vote.attempt_number = l_session->attempt_current_number;
-        s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE, (uint8_t *)&l_vote,
-            sizeof(dap_chain_cs_block_ton_message_vote_t), l_session->cur_round.validators_start);
-        if (PVT(l_session->ton)->debug)
-            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu This is first attempt, so to sent a VOTE for candidate:%s",
-                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                        l_session->attempt_current_number, l_candidate_hash_str);
-    }
-    pthread_rwlock_unlock(&l_session->rwlock);
-    DAP_DELETE(l_candidate_hash_str);
-}
-
-/**
- * @brief The proc_msg_type_submit struct
- */
-struct proc_msg_type_submit{
-    dap_chain_cs_block_ton_session_t *session;
-    dap_chain_hash_fast_t candidate_hash;
-    char * candidate_hash_str;
-    dap_chain_block_t * candidate;
-    size_t candidate_size;
-    dap_nanotime_t time;
-};
-
-/**
- * @brief s_check_block_exist_in_store
- * @param a_global_db_context
- * @param a_rc
- * @param a_group
- * @param a_key
- * @param a_value
- * @param a_value_size
- * @param a_value_ts
- * @param a_is_pinned
- * @param a_arg
- */
-static void s_callback_check_and_save_candidate_block  (dap_global_db_context_t * a_global_db_context,int a_rc, const char * a_group, const char * a_key, const void * a_value, const size_t a_value_size, dap_nanotime_t a_value_ts, bool a_is_pinned, void * a_arg)
-{
-    struct proc_msg_type_submit * l_args = (struct proc_msg_type_submit *) a_arg;
-    assert(l_args);
-    dap_chain_cs_block_ton_session_t *l_session = l_args->session;
-    char *l_candidate_hash_str = l_args->candidate_hash_str;
-    dap_chain_block_t * l_candidate = l_args->candidate;
-    size_t l_candidate_size = l_args->candidate_size;
-    dap_nanotime_t l_time = l_args->time;
-    dap_chain_hash_fast_t l_candidate_hash = l_args->candidate_hash;
-    DAP_DELETE(l_args);
-
-    dap_chain_cs_block_ton_store_t *l_store_temp = (dap_chain_cs_block_ton_store_t *) a_value;
-    if (l_store_temp) {
-        log_it(L_WARNING, "TON: Duplicate candidate:%s", l_candidate_hash_str);
-        DAP_DELETE(l_candidate_hash_str);
-        DAP_DELETE(l_candidate);
-        return;
-    }
-    // store for new candidate
-    size_t l_store_size = sizeof(dap_chain_cs_block_ton_store_hdr_t) + l_candidate_size;
-    dap_chain_cs_block_ton_store_t *l_store = DAP_NEW_Z_SIZE(dap_chain_cs_block_ton_store_t, l_store_size);
-
-    l_store->hdr.candidate_size = l_candidate_size;
-    l_store->hdr.ts_candidate_submit = l_time;
-    l_store->hdr.round_id.uint64 = l_session->cur_round.id.uint64;
-    l_store->hdr.candidate_hash = l_candidate_hash;
-    memcpy(&l_store->candidate_n_signs, l_candidate, l_candidate_size);
-
-    pthread_rwlock_wrlock(&l_session->rwlock);
-    // save new block candidate
-    if (dap_global_db_set_unsafe(a_global_db_context, l_session->gdb_group_store, l_candidate_hash_str, l_store,
-                                            l_store_size, true) == 0) {
-        l_session->cur_round.candidates_count++;
-        dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(l_session->chain);
-        if ( !s_session_atom_validation(l_blocks, l_candidate, l_candidate_size) ) {
-            // validation - OK, gen event Approve
-            if (PVT(l_session->ton)->blocks_sign_key) {
-                // size_t l_candidate_size = l_store->hdr.candidate_size;
-                dap_sign_t *l_hash_sign = dap_sign_create(PVT(l_session->ton)->blocks_sign_key,
-                                                &l_candidate_hash, sizeof(dap_chain_hash_fast_t), 0);
-
-                size_t l_hash_sign_size = dap_sign_get_size(l_hash_sign);
-                size_t l_approve_size = sizeof(dap_chain_cs_block_ton_message_approve_t)+l_hash_sign_size;
-
-                dap_chain_cs_block_ton_message_approve_t *l_approve =
-                                        DAP_NEW_SIZE(dap_chain_cs_block_ton_message_approve_t, l_approve_size);
-                l_approve->round_id.uint64 = l_session->cur_round.id.uint64;
-                l_approve->candidate_hash = l_candidate_hash;
-                memcpy(l_approve->candidate_hash_sign, l_hash_sign, l_hash_sign_size);
-
-                s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE,
-                                        (uint8_t*)l_approve, l_approve_size, l_session->cur_round.validators_start);
-                DAP_DELETE(l_approve);
-
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Sent APPROVE candidate:%s",
-                            l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                                    l_session->attempt_current_number, l_candidate_hash_str);
-            }
-            else
-                log_it(L_WARNING, "Can't sign block with blocks-sign-cert in [block-ton] section");
-        }
-        else {
-            // validation - fail, gen event Reject
-            dap_chain_cs_block_ton_message_reject_t *l_reject =
-                                                    DAP_NEW_Z(dap_chain_cs_block_ton_message_reject_t);
-            l_reject->round_id.uint64 = l_session->cur_round.id.uint64;
-            l_reject->candidate_hash = l_candidate_hash;
-            s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT, (uint8_t*)l_reject,
-                        sizeof(dap_chain_cs_block_ton_message_reject_t), l_session->cur_round.validators_start);
-            DAP_DELETE(l_reject);
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Sent REJECT candidate:%s",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                                l_session->attempt_current_number, l_candidate_hash_str);
-        }
-    }
-    pthread_rwlock_unlock(&l_session->rwlock);
-
-    DAP_DELETE(l_store);
-    DAP_DELETE(l_candidate_hash_str);
-    DAP_DELETE(l_candidate);
-}
-
-/**
- * @brief s_session_packet_in
- * @param a_arg
- * @param a_sender_node_addr
- * @param a_data_hash
- * @param a_data
- * @param a_data_size
- */
-static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_node_addr,
-                                dap_chain_hash_fast_t *a_data_hash, uint8_t *a_data, size_t a_data_size)
-{
-    dap_chain_cs_block_ton_session_t *l_session = a_arg;
-    dap_chain_cs_block_ton_message_t *l_message = (dap_chain_cs_block_ton_message_t *)a_data;
-
-    if (PVT(l_session->ton)->debug)
-        log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive pkt type:%x from addr:"NODE_ADDR_FP_STR", my_addr:"NODE_ADDR_FP_STR"",
-                l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                    l_session->attempt_current_number, l_message->hdr.type,
-                        NODE_ADDR_FP_ARGS(a_sender_node_addr), NODE_ADDR_FP_ARGS(l_session->my_addr));
-
-    if( sizeof(*l_message)+l_message->hdr.sign_size > a_data_size){
-        log_it(L_WARNING, "TON: incorrect message size in header is %zu when data size is only %zu and header size is %zu",
-               l_message->hdr.sign_size, a_data_size, sizeof(*l_message));
-        return;
-    }
-    size_t l_message_data_size = a_data_size - sizeof(*l_message) - l_message->hdr.sign_size ;
-    byte_t * l_message_data = l_message->sign_n_message + l_message->hdr.sign_size;
-
-    if ( !PVT(l_session->ton)->validators_list_by_stake ) {
-        size_t l_data_size = 0;
-        dap_sign_t *l_sign = (dap_sign_t*)l_message->sign_n_message;
-        uint8_t *l_data = s_message_data_sign(l_session, l_message, &l_data_size);
-        bool l_verify_passed = false;
-        for (uint16_t j = 0; j < PVT(l_session->ton)->auth_certs_count; j++) {
-            if ( dap_cert_compare_with_sign(PVT(l_session->ton)->auth_certs[j], l_sign) == 0
-                    && dap_sign_verify(l_sign, l_data, l_data_size) == 1 ) {
-                l_verify_passed = true;
-                break;
-            }
-        }
-        DAP_DELETE(l_data);
-        if (!l_verify_passed) {
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected from addr:"NODE_ADDR_FP_STR" not passed verification",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
-            return;
-        }
-    }
-
-    if (l_message->hdr.chain_id.uint64 != l_session->chain->id.uint64 )
-        return;
-
-    dap_time_t l_time = dap_time_now();
-
-    dap_chain_hash_fast_t l_data_hash = {};
-    dap_hash_fast(a_data, a_data_size, &l_data_hash);
-    if (!dap_hash_fast_compare(a_data_hash, &l_data_hash)) {
-        if (PVT(l_session->ton)->debug)
-            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: message hash does not match",
-                    l_session->chain->net_name, l_session->chain->name,
-                        l_session->cur_round.id.uint64, l_session->attempt_current_number);
-        return;
-    }
-
-    // consensus round start sync
-    if ( l_message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_START_SYNC ) {
-        // check time offset
-        dap_chain_cs_block_ton_message_startsync_t *l_startsync =
-                            (dap_chain_cs_block_ton_message_startsync_t *)
-                                    (l_message->sign_n_message+l_message->hdr.sign_size);
-
-        if (PVT(l_session->ton)->debug)
-            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive START_SYNC: from addr:"NODE_ADDR_FP_STR"",
-                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                        l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
-
-        dap_chain_node_addr_t *l_validator =
-                s_session_get_validator(l_session, a_sender_node_addr, l_session->cur_round.validators_list);
-
-        if (!l_validator) {
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: validator addr:"NODE_ADDR_FP_STR" not in the list.",
-                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                        l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
-            return;
-        }
-
-        if (
-            (l_time>l_startsync->ts && (l_time-l_startsync->ts) > PVT(l_session->ton)->allowed_clock_offset )
-                || (l_time<l_startsync->ts && (l_startsync->ts-l_time) > PVT(l_session->ton)->allowed_clock_offset )
-                    ) {
-            // offset is more than allowed_clock_offset
-            // skip this validator
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: too much time difference: my time:%"DAP_UINT64_FORMAT_U" sender time:%"DAP_UINT64_FORMAT_U"",
-                        l_session->chain->net_name, l_session->chain->name,
-                            l_session->cur_round.id.uint64, l_session->attempt_current_number, l_time, l_startsync->ts);
-            return;
-        }
-
-        // add check&save sender addr
-        dap_list_t *l_list_temp = dap_list_first(l_session->cur_round.validators_start);
-        while(l_list_temp) {
-            dap_list_t *l_list_next = l_list_temp->next;
-            if (((dap_chain_node_addr_t *)l_list_temp->data)->uint64 == l_validator->uint64) {
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: repeated sync message from addr:"NODE_ADDR_FP_STR"",
-                            l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                                l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
-                return;
-            }
-            l_list_temp = l_list_next;
-        }
-
-        //sync round_id
-        if ( l_session->cur_round.id.uint64 < l_startsync->round_id.uint64 ) {
-            l_session->cur_round.id.uint64 = l_startsync->round_id.uint64;
-        }
-
-        l_session->cur_round.validators_start = dap_list_append(l_session->cur_round.validators_start, l_validator);
-        l_session->cur_round.validators_start_count = dap_list_length(l_session->cur_round.validators_start);
-        s_session_send_startsync(l_session);
-        return;
-    }
-
-    // validator check
-    uint64_t l_round_id =
-                ((dap_chain_cs_block_ton_message_getinfo_t *)
-                        (l_message->sign_n_message+l_message->hdr.sign_size))->round_id.uint64;
-    dap_chain_node_addr_t *l_validator = NULL;
-    if (l_round_id == l_session->cur_round.id.uint64)
-        l_validator = s_session_get_validator(l_session, a_sender_node_addr, l_session->cur_round.validators_start);
-    if (!l_validator) {
-        if (PVT(l_session->ton)->debug)
-            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: validator addr:"NODE_ADDR_FP_STR" not in the list.",
-                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                        l_session->attempt_current_number, NODE_ADDR_FP_ARGS(a_sender_node_addr));
-        return;
-    }
-
-    // round check
-    if ( l_message->hdr.type != DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN ) {
-        if ( l_session->state != DAP_STREAM_CH_CHAIN_SESSION_STATE_CS_PROC
-                && l_session->state != DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS ) {
-            return;
-        }
-        if ( l_round_id != l_session->cur_round.id.uint64) {
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: round in message does not match to current round",
-                        l_session->chain->net_name, l_session->chain->name,
-                            l_session->cur_round.id.uint64, l_session->attempt_current_number);
-            return;
-        }
-    } else {
-        if (l_round_id != l_session->cur_round.id.uint64) {
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: round in message does not match to current round",
-                        l_session->chain->net_name, l_session->chain->name,
-                            l_session->cur_round.id.uint64, l_session->attempt_current_number);
-            return;
-        }
-    }
-
-    if ( l_session->attempt_current_number != 1 ) {
-        switch (l_message->hdr.type) { // this types allow only in first attempt
-            case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT:
-            case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
-            case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT: {
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: message type:%x allowed only in first attempt",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            l_session->attempt_current_number, l_message->hdr.type);
-                return;
-            }
-        }
-    }
-
-    dap_chain_cs_block_ton_round_t *l_round = &l_session->cur_round;
-
-    // check hash message dup
-    dap_chain_cs_block_ton_message_item_t *l_message_item_temp = NULL;
-    pthread_rwlock_rdlock(&l_round->messages_rwlock);
-    HASH_FIND(hh, l_round->messages_items, a_data_hash, sizeof(dap_chain_hash_fast_t), l_message_item_temp);
-    pthread_rwlock_unlock(&l_round->messages_rwlock);
-    if (l_message_item_temp) {
-        if (PVT(l_session->ton)->debug)
-            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: message hash is exists in chain (duplicate?)",
-                    l_session->chain->net_name, l_session->chain->name,
-                        l_session->cur_round.id.uint64, l_session->attempt_current_number);
-        return;
-    }
-
-    // check validator index in queue for event Submit
-    if ( l_message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT ) {
-        dap_list_t *l_validators_list = dap_list_first(l_session->cur_round.validators_start);
-        int l_validator_number = 0;
-        int i = 0;
-        while(l_validators_list) {
-            if( ((dap_chain_node_addr_t *)l_validators_list->data)->uint64 == a_sender_node_addr->uint64) {
-                l_validator_number = i;
-                break;
-            }
-            i++;
-            l_validators_list = l_validators_list->next;
-        }
-        if ( l_validator_number ) { // pass if I first validator
-            int l_submit_count = 0;
-            dap_chain_cs_block_ton_message_item_t *l_chain_message=NULL, *l_chain_message_tmp=NULL;
-            pthread_rwlock_rdlock(&l_round->messages_rwlock);
-            HASH_ITER(hh, l_round->messages_items, l_chain_message, l_chain_message_tmp) {
-                if ( l_chain_message->message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT ) {
-                    l_submit_count++;
-                }
-            }
-            pthread_rwlock_unlock(&l_round->messages_rwlock);
-            if ( l_validator_number < l_submit_count ) {
-                // Skip this SUBMIT. Validator must wait its queue.
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: Validator must wait its queue for sent SUBMIT",
-                            l_session->chain->net_name, l_session->chain->name,
-                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                return;
-            }
-        }
-    }
-
-    uint32_t /* l_approve_count = 0, */ l_vote_count = 0, l_precommit_count = 0;
-    // check messages chain
-    dap_chain_cs_block_ton_message_item_t *l_chain_message=NULL, *l_chain_message_tmp=NULL;
-    pthread_rwlock_rdlock(&l_round->messages_rwlock);
-    HASH_ITER(hh, l_round->messages_items, l_chain_message, l_chain_message_tmp) {
-        if (l_chain_message->message->hdr.sender_node_addr.uint64 == a_sender_node_addr->uint64) {
-            dap_chain_hash_fast_t *l_candidate_hash_cur =
-                    &((dap_chain_cs_block_ton_message_getinfo_t *)
-                            (l_message->sign_n_message+l_message->hdr.sign_size))->candidate_hash;
-
-            dap_chain_hash_fast_t *l_candidate_hash =
-                &((dap_chain_cs_block_ton_message_getinfo_t *)
-                    (l_chain_message->message->sign_n_message+l_chain_message->message->hdr.sign_size))->candidate_hash;
-
-            bool l_candidate_hash_match = (memcmp(l_candidate_hash_cur, l_candidate_hash,
-                                                            sizeof(dap_chain_hash_fast_t)) == 0);
-
-            uint8_t l_chain_msg_type = l_chain_message->message->hdr.type;
-
-            // search & check messages from this validator
-            switch (l_chain_msg_type) {
-                // check dup messages APPROVE, REJECT for one candidate
-                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
-                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT: {
-                    switch (l_message->hdr.type) {
-                        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
-                        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT:
-                            if (l_candidate_hash_match) {
-                                if (PVT(l_session->ton)->debug)
-                                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: duplicate messages APPROVE or REJECT for one candidate",
-                                            l_session->chain->net_name, l_session->chain->name,
-                                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                                return;
-                            }
-                    }
-                } break;
-                //check dup messages VOTE for one candidate in this attempt
-                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
-                    dap_chain_cs_block_ton_message_vote_t *l_vote =
-                                    (dap_chain_cs_block_ton_message_vote_t *)
-                                        (l_message->sign_n_message+l_message->hdr.sign_size);
-                    dap_chain_cs_block_ton_message_vote_t *l_vote_item =
-                                    (dap_chain_cs_block_ton_message_vote_t *)
-                                        (l_chain_message->message->sign_n_message+l_chain_message->message->hdr.sign_size);
-                    if ( l_chain_msg_type == l_message->hdr.type
-                            && l_vote->attempt_number == l_vote_item->attempt_number ) {
-                        if (PVT(l_session->ton)->debug)
-                            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: duplicate messages VOTE for one candidate for one attempt",
-                                    l_session->chain->net_name, l_session->chain->name,
-                                        l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                        return;
-                    }
-                } break;
-                // this messages should only appear once per round //attempt
-                // case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE:
-                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT:
-                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN:
-                case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT:{
-                    if ( l_chain_msg_type == l_message->hdr.type ){
-                        if (PVT(l_session->ton)->debug)
-                            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: duplicate messages VOTE or PRE_COMMIT for one candidate for one attempt",
-                                    l_session->chain->net_name, l_session->chain->name,
-                                        l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                        return;
-                    }
-                }
-            }
-            // count messages in chain for this candidate
-            if (l_candidate_hash_match) {
-                switch (l_chain_msg_type) {
-                    // case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE: {
-                    // 	l_approve_count++;
-                    // } break;
-                    case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
-                        l_vote_count++;
-                    } break;
-                    case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT: {
-                        l_precommit_count++;
-                    } break;
-                }
-            }
-        }
-    }
-    pthread_rwlock_unlock(&l_round->messages_rwlock);
-
-    // check message chain is correct
-    switch (l_message->hdr.type) {
-        // case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
-        // 	if (!l_approve_count) { // if this validator not sent Approve for this candidate
-        // 		goto handler_finish;
-        // 	}
-        // } break;
-        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT: {
-            if (!l_vote_count) { // if this validator not sent Vote for this candidate
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: this validator can't send a PRE_COMMIT because it didn't send a VOTE for this candidate",
-                            l_session->chain->net_name, l_session->chain->name,
-                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                return;
-            }
-        } break;
-        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: {
-            if (!l_precommit_count) { // if this validator not sent PreCommit for this candidate
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: this validator can't send a COMMIT_SIGN because it didn't send a PRE_COMMIT for this candidate",
-                            l_session->chain->net_name, l_session->chain->name,
-                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                return;
-            }
-        } break;
-    }
-
-    switch (l_message->hdr.type) {
-        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT: {
-            if( sizeof(dap_chain_cs_block_ton_message_submit_t) > l_message_data_size){
-                log_it(L_WARNING, "Wrong submit message size,have %zu bytes for data section when only a header requires %zu bytes",
-                       l_message_data_size,sizeof(dap_chain_cs_block_ton_message_submit_t));
-                return;
-            }
-            dap_chain_cs_block_ton_message_submit_t *l_submit = (dap_chain_cs_block_ton_message_submit_t *)l_message_data;
-            size_t l_candidate_size = l_submit->candidate_size;
-            if( l_message_data_size < l_candidate_size + sizeof(*l_submit) ){
-                log_it(L_WARNING, "Wrong submit message size %zu when maximum is %zu for received message", l_candidate_size,
-                       l_message_data_size - sizeof(*l_submit));
-                return;
-            }
-
-            dap_chain_hash_fast_t l_candidate_hash;
-            dap_hash_fast(l_submit->candidate, l_candidate_size, &l_candidate_hash);
-
-            // check candidate hash
-            if (!dap_hash_fast_compare(&l_submit->candidate_hash, &l_candidate_hash))
-                return;
-
-            s_message_chain_add(l_session, a_sender_node_addr, l_message, a_data_size, NULL);
-            if (!l_candidate_size || dap_hash_fast_is_blank(&l_submit->candidate_hash)) { // null candidate - save chain and exit
-
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive SUBMIT: candidate: NULL",
-                            l_session->chain->net_name, l_session->chain->name,
-                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                return;
-            }
-
-            dap_chain_block_t *l_candidate = (dap_chain_block_t *) DAP_DUP_SIZE(l_submit->candidate, l_candidate_size);
-            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(&l_candidate_hash);
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive SUBMIT: candidate:%s, size:%zu",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            l_session->attempt_current_number, l_candidate_hash_str, l_candidate_size);
-
-            // check block exist in store
-            //s_check_block_exist_in_store(,)
-            struct proc_msg_type_submit * l_args = DAP_NEW_Z(struct proc_msg_type_submit);
-            l_args->session = l_session;
-            l_args->candidate_hash_str = l_candidate_hash_str;
-            l_args->candidate = l_candidate;
-            l_args->candidate_size = l_candidate_size;
-            l_args->candidate_hash = l_candidate_hash;
-            l_args->time = l_time;
-            if(dap_global_db_get(l_session->gdb_group_store,l_candidate_hash_str,s_callback_check_and_save_candidate_block, l_args) != 0){
-                log_it(L_ERROR, "Can't call get request for s_check_block_exist_in_store() callback");
-                DAP_DELETE(l_candidate_hash_str);
-                DAP_DELETE(l_args);
-            }
-        } break;
-
-        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT: {
-            if  ( sizeof(dap_chain_cs_block_ton_message_reject_t) >l_message_data_size  ){
-                log_it(L_WARNING, "Wrong reject message size,have %zu bytes for data section when requires %zu bytes",
-                       l_message_data_size,sizeof(dap_chain_cs_block_ton_message_reject_t));
-                return;
-            }
-            dap_chain_cs_block_ton_message_reject_t *l_reject = (dap_chain_cs_block_ton_message_reject_t *) l_message_data;
-            dap_chain_hash_fast_t *l_candidate_hash = &l_reject->candidate_hash;
-
-            s_message_chain_add(l_session, a_sender_node_addr, l_message, a_data_size, NULL);
-
-            pthread_rwlock_rdlock(&l_session->rwlock);
-            if (dap_hash_fast_is_blank(l_candidate_hash)) {
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive REJECT: NULL",
-                            l_session->chain->net_name, l_session->chain->name,
-                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                pthread_rwlock_unlock(&l_session->rwlock);
-                return;
-            }
-            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive REJECT: candidate:%s",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            l_session->attempt_current_number, l_candidate_hash_str);
-            pthread_rwlock_unlock(&l_session->rwlock);
-
-            pthread_rwlock_wrlock(&l_session->rwlock);
-            uint16_t l_reject_count = s_session_message_count(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT,
-                                                              l_candidate_hash, NULL);
-            if (l_reject_count * 3 >= l_session->cur_round.validators_count * 2) {
-                dap_global_db_del_sync(l_session->gdb_group_store, l_candidate_hash_str);
-                dap_chain_hash_fast_t l_my_candidate_hash;
-                dap_hash_fast(l_session->my_candidate, l_session->my_candidate_size, &l_my_candidate_hash);
-                if (dap_hash_fast_compare(&l_my_candidate_hash, l_candidate_hash))
-                    s_session_my_candidate_delete(l_session);
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Candidate:%s collected rejected more than 2/3 of the validators, so to removed this candidate",
-                            l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                                l_session->attempt_current_number, l_candidate_hash_str);
-            }
-            pthread_rwlock_unlock(&l_session->rwlock);
-            DAP_DELETE(l_candidate_hash_str);
-        } break;
-
-        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE: {
-            if  ( sizeof(dap_chain_cs_block_ton_message_approve_t) >l_message_data_size  ){
-                log_it(L_WARNING, "Wrong approve message size,have %zu bytes for data section when requires %zu bytes",
-                       l_message_data_size,sizeof(dap_chain_cs_block_ton_message_approve_t));
-                return;
-            }
-            dap_chain_cs_block_ton_message_approve_t *l_approve = (dap_chain_cs_block_ton_message_approve_t *) l_message_data;
-            dap_sign_t * l_candidate_sign = (dap_sign_t *) l_approve->candidate_hash_sign;
-            size_t l_candidate_sign_size = dap_sign_get_size(l_candidate_sign);
-            size_t l_candidate_hash_sign_size = l_message_data_size - sizeof(dap_chain_cs_block_ton_message_approve_t);
-            if (l_candidate_sign_size > l_candidate_hash_sign_size) {
-                log_it(L_WARNING, "Wrong approve message size,have %zu bytes for candidate sign section when requires  maximum %zu bytes",
-                                   l_candidate_sign_size, l_candidate_hash_sign_size);
-                return;
-            }
-            dap_chain_hash_fast_t *l_candidate_hash = &l_approve->candidate_hash;
-            if (dap_hash_fast_is_blank(l_candidate_hash)) {
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive APPROVE: candidate: NULL",
-                            l_session->chain->net_name, l_session->chain->name,
-                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                return;
-            }
-            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-
-            pthread_rwlock_rdlock(&l_session->rwlock);
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive APPROVE: candidate:%s",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            l_session->attempt_current_number, l_candidate_hash_str);
-
-            int l_sign_verified=0;
-            // check candidate hash sign
-            if ( (l_sign_verified=dap_sign_verify( (dap_sign_t*)l_approve->candidate_hash_sign,
-                                                    l_candidate_hash, sizeof(dap_chain_hash_fast_t))) == 1 ) {
-
-                s_message_chain_add(l_session, a_sender_node_addr, l_message, a_data_size, NULL);
-
-                if ( l_session->attempt_current_number == 1 ) { // if this first attempt then send Vote event
-                    uint16_t l_approve_count = s_session_message_count(
-                            l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE,
-                                        l_candidate_hash, NULL);
-                    if (l_approve_count * 3 >= l_session->cur_round.validators_count * 2) {
-                        if (PVT(l_session->ton)->debug)
-                            log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" attempt:%hu Candidate:%s collected approve more than 2/3 of the validators",
-                                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                                        l_session->attempt_current_number, l_candidate_hash_str);
-
-                        struct proc_msg_type_approve * l_args = DAP_NEW_Z(struct proc_msg_type_approve);
-                        l_args->session = l_session;
-                        l_args->candidate_hash_str = l_candidate_hash_str;
-                        l_args->candidate_hash = *l_candidate_hash;
-
-                        if ( dap_global_db_get(l_session->gdb_group_store,l_candidate_hash_str,s_callback_get_candidate_block_and_approve, l_args) != 0 ){
-                            log_it(L_ERROR, "Can't get candidate block for approvement");
-                            DAP_DELETE(l_args);
-                            DAP_DELETE(l_candidate_hash_str);
-                        }
-                    }else{
-                        DAP_DELETE(l_candidate_hash_str);
-                    }
-                }else{
-                    DAP_DELETE(l_candidate_hash_str);
-                }
-            } else {
-                log_it(L_WARNING, "Candidate hash sign is incorrect: code %d", l_sign_verified);
-                DAP_DELETE(l_candidate_hash_str);
-            }
-            pthread_rwlock_unlock(&l_session->rwlock);
-        } break;
-
-        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR: {
-            if  ( sizeof(dap_chain_cs_block_ton_message_votefor_t) >l_message_data_size  ){
-                log_it(L_WARNING, "Wrong vote_for message size,have %zu bytes for data section when requires %zu bytes",
-                       l_message_data_size,sizeof(dap_chain_cs_block_ton_message_votefor_t));
-                return;
-            }
-
-            dap_chain_cs_block_ton_message_votefor_t *l_votefor = (dap_chain_cs_block_ton_message_votefor_t *) l_message_data;
-            dap_chain_hash_fast_t *l_candidate_hash = &l_votefor->candidate_hash;
-
-            pthread_rwlock_rdlock(&l_session->rwlock);
-
-            uint16_t l_attempt_current = l_session->attempt_current_number;
-            if ( l_votefor->attempt_number != l_attempt_current) {
-                pthread_rwlock_unlock(&l_session->rwlock);
-                return; // wrong attempt number in message
-            }
-
-            if (PVT(l_session->ton)->debug) {
-                char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive VOTE_FOR: candidate:%s",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            l_session->attempt_current_number, l_candidate_hash_str);
-                DAP_DELETE(l_candidate_hash_str);
-            }
-
-            if ( a_sender_node_addr->uint64 != l_session->attempt_coordinator->uint64 ) {
-                pthread_rwlock_unlock(&l_session->rwlock);
-                return; // wrong coordinator addr
-            }
-
-            uint16_t l_votefor_count = s_session_message_count(
-                        l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR,
-                                    NULL, &l_attempt_current);
-            if ( l_votefor_count != 0 ) {
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Ignored because it's not the first VOTE_FOR in this attempt",
-                            l_session->chain->net_name, l_session->chain->name,
-                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                pthread_rwlock_unlock(&l_session->rwlock);
-                return;
-            }
-
-            s_message_chain_add(l_session, a_sender_node_addr, l_message, a_data_size, NULL);
-
-            struct vote_for_load_store_args * l_args = DAP_NEW_Z(struct vote_for_load_store_args);
-            l_args->session = l_session;
-            l_args->candidate_hash = *l_candidate_hash;
-            // search candidate with 2/3 vote
-            if(dap_global_db_get_all(l_session->gdb_group_store, 0,
-                                  s_session_packet_in_callback_vote_for_load_store,
-                                  l_session) != 0 ){
-                log_it (L_ERROR, "Can't process get_all request for vote_for_load_store");
-                DAP_DELETE(l_args);
-            }
-            pthread_rwlock_unlock(&l_session->rwlock);
-        } return;
-
-        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
-            if  ( sizeof(dap_chain_cs_block_ton_message_vote_t) >l_message_data_size  ){
-                log_it(L_WARNING, "Wrong vote message size,have %zu bytes for data section when requires %zu bytes",
-                       l_message_data_size,sizeof(dap_chain_cs_block_ton_message_vote_t));
-                return;
-            }
-            dap_chain_cs_block_ton_message_vote_t *l_vote =	(dap_chain_cs_block_ton_message_vote_t *) l_message_data;
-            dap_chain_hash_fast_t *l_candidate_hash = &l_vote->candidate_hash;
-
-            if ( l_vote->attempt_number != l_session->attempt_current_number) {
-                return;
-            }
-
-            if (dap_hash_fast_is_blank(l_candidate_hash)) {
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive VOTE: candidate: NULL",
-                            l_session->chain->net_name, l_session->chain->name,
-                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                return;
-            }
-
-            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive VOTE: candidate:%s",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            l_session->attempt_current_number, l_candidate_hash_str);
-
-            s_message_chain_add(l_session, a_sender_node_addr, l_message, a_data_size, NULL);
-
-            pthread_rwlock_rdlock(&l_session->rwlock);
-            uint16_t l_attempt_number = l_session->attempt_current_number;
-            uint16_t l_vote_count = s_session_message_count(
-                        l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE,
-                                    l_candidate_hash, &l_attempt_number);
-
-            if (l_vote_count * 3 >= l_session->cur_round.validators_count * 2) {
-                struct proc_msg_type_vote * l_args = DAP_NEW_Z(struct proc_msg_type_vote);
-                l_args->session = l_session;
-                l_args->candidate_hash_str = l_candidate_hash_str;
-                l_args->candidate_hash = *l_candidate_hash;
-                if (dap_global_db_get(l_session->gdb_group_store,l_candidate_hash_str,s_callback_get_candidate_block_and_vote, l_args ) != 0 ){
-                    log_it (L_ERROR, "Can't process get request for s_callback_get_candidate_block_and_vote()");
-                    DAP_DELETE(l_candidate_hash_str);
-                    DAP_DELETE(l_args);
-                }
-            }
-            pthread_rwlock_unlock(&l_session->rwlock);
-        } return;
-
-        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT: {
-            if  ( sizeof(dap_chain_cs_block_ton_message_precommit_t) >l_message_data_size  ){
-                log_it(L_WARNING, "Wrong pre_commit message size,have %zu bytes for data section when requires %zu bytes",
-                       l_message_data_size,sizeof(dap_chain_cs_block_ton_message_precommit_t));
-                return;
-            }
-
-            dap_chain_cs_block_ton_message_precommit_t *l_precommit = (dap_chain_cs_block_ton_message_precommit_t *) l_message_data;
-            dap_chain_hash_fast_t *l_candidate_hash = &l_precommit->candidate_hash;
-
-            pthread_rwlock_wrlock(&l_session->rwlock);
-
-            if ( l_precommit->attempt_number != l_session->attempt_current_number) {
-                pthread_rwlock_unlock(&l_session->rwlock);
-                return;
-            }
-            if (dap_hash_fast_is_blank(l_candidate_hash)) {
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive PRE_COMMIT: candidate: NULL",
-                            l_session->chain->net_name, l_session->chain->name,
-                                l_session->cur_round.id.uint64, l_session->attempt_current_number);
-                pthread_rwlock_unlock(&l_session->rwlock);
-                return;
-            }
-
-            s_message_chain_add(l_session, a_sender_node_addr, l_message, a_data_size, NULL);
-
-            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive PRE_COMMIT: candidate:%s",
-                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id.uint64,
-                            l_session->attempt_current_number, l_candidate_hash_str);
-
-            uint16_t l_attempt_number = l_session->attempt_current_number;
-            uint16_t l_precommit_count = s_session_message_count(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT,
-                                                                 l_candidate_hash, &l_attempt_number);
-
-            if ( 3* l_precommit_count >= 2*l_session->cur_round.validators_count  ) {
-                struct proc_msg_type_pre_commit * l_args = DAP_NEW_Z(struct proc_msg_type_pre_commit);
-                l_args->session = l_session;
-                l_args->candidate_hash = *l_candidate_hash;
-                l_args->candidate_hash_str = l_candidate_hash_str;
-                if( dap_global_db_get(l_session->gdb_group_store, l_candidate_hash_str,s_callback_get_candidate_block_and_pre_commit, l_args ) != 0 ){
-                    log_it (L_ERROR, "Can't process get request for s_callback_get_candidate_block_and_pre_commit()");
-                    DAP_DELETE(l_candidate_hash_str);
-                    DAP_DELETE(l_args);
-                }
-            }
-            pthread_rwlock_unlock(&l_session->rwlock);
-        } return;
-
-        case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: {
-            if  ( sizeof(dap_chain_cs_block_ton_message_commitsign_t) >l_message_data_size  ){
-                log_it(L_WARNING, "Wrong commit_sign message size,have %zu bytes for data section when requires %zu bytes",
-                       l_message_data_size,sizeof(dap_chain_cs_block_ton_message_commitsign_t));
-                return;
-            }
-
-            dap_chain_cs_block_ton_message_commitsign_t *l_commitsign =	(dap_chain_cs_block_ton_message_commitsign_t *) l_message_data;
-            dap_chain_hash_fast_t *l_candidate_hash = &l_commitsign->candidate_hash;
-
-            dap_sign_t * l_candidate_sign = (dap_sign_t *) l_commitsign->candidate_sign;
-            size_t l_candidate_sign_size = dap_sign_get_size(l_candidate_sign);
-            size_t l_message_candidate_sign_size_max = l_message_data_size - sizeof(dap_chain_cs_block_ton_message_commitsign_t);
-            if (l_candidate_sign_size > l_message_candidate_sign_size_max ){
-                log_it(L_WARNING, "Wrong commit_sign message size,have %zu bytes for candidate sign section when requires  maximum %zu bytes",
-                                  l_candidate_sign_size, l_message_candidate_sign_size_max);
-                return;
-            }
-
-            pthread_rwlock_rdlock(&l_session->rwlock);
-            dap_chain_cs_block_ton_round_t *l_round = &l_session->cur_round;
-            if (dap_hash_fast_is_blank(l_candidate_hash)) {
-                if (PVT(l_session->ton)->debug)
-                    log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive COMMIT_SIGN: candidate: NULL",
-                            l_session->chain->net_name, l_session->chain->name,
-                                l_round->id.uint64, l_session->attempt_current_number);
-                pthread_rwlock_unlock(&l_session->rwlock);
-
-                return;
-            }
-
-            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
-            if (PVT(l_session->ton)->debug)
-                log_it(L_MSG, "TON: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive COMMIT_SIGN: candidate:%s",
-                        l_session->chain->net_name, l_session->chain->name, l_round->id.uint64,
-                            l_session->attempt_current_number, l_candidate_hash_str);
-
-            struct proc_msg_type_commit_sign * l_args = DAP_NEW_Z(struct proc_msg_type_commit_sign);
-            l_args->session = l_session;
-            l_args->round = l_round;
-            l_args->round_id = l_commitsign->round_id;
-            l_args->candidate_hash_str = l_candidate_hash_str;
-            l_args->candidate_hash = *l_candidate_hash;
-            l_args->candidate_sign = DAP_DUP_SIZE(l_candidate_sign, l_candidate_sign_size);
-            l_args->message = DAP_DUP_SIZE(l_message, a_data_size);
-            l_args->message_size = a_data_size;
-            l_args->sender_node_addr = *a_sender_node_addr;
-
-            if (dap_global_db_get(l_session->gdb_group_store, l_candidate_hash_str,s_callback_get_candidate_block_and_commit_sign , l_args) != 0 ){
-                log_it (L_ERROR, "Can't process get request for s_callback_get_candidate_block_and_commit_sign()");
-                DAP_DELETE(l_candidate_hash_str);
-                DAP_DELETE(l_args);
-            } // Message we'll proc in callback later
-            pthread_rwlock_unlock(&l_session->rwlock);
-            return;
-        }
-        default:
-            break;
-    }
-}
-
-static uint8_t *s_message_data_sign(dap_chain_cs_block_ton_session_t *a_session,
-                                    dap_chain_cs_block_ton_message_t *a_message, size_t *a_sign_size)
-{
-    struct ton_msg_signing_data {
-        dap_chain_cs_block_ton_msg_id_t id;
-        dap_time_t ts_created;
-        uint8_t type;
-        dap_chain_id_t chain_id;
-        dap_chain_node_addr_t sender_node_addr;
-    } DAP_ALIGN_PACKED;
-
-    struct ton_msg_signing_data *l_data = DAP_NEW(struct ton_msg_signing_data);
-    l_data->id                  = a_message->hdr.id;
-    l_data->ts_created          = a_message->hdr.ts_created;
-    l_data->type                = a_message->hdr.type;
-    l_data->chain_id            = a_message->hdr.chain_id;
-    l_data->sender_node_addr    = a_message->hdr.sender_node_addr;
-    if (a_sign_size)
-        *a_sign_size = sizeof(l_data);
-    return (uint8_t *)l_data;
-}
-
-
-static void s_message_send(dap_chain_cs_block_ton_session_t *a_session, uint8_t a_message_type,
-                                    uint8_t *a_data, size_t a_data_size, dap_list_t *a_validators)
-{
-    dap_chain_net_t *l_net = dap_chain_net_by_id(a_session->chain->net_id);
-    size_t l_message_size = sizeof(dap_chain_cs_block_ton_message_hdr_t)+a_data_size;
-    dap_chain_cs_block_ton_message_t *l_message =
-                        DAP_NEW_SIZE(dap_chain_cs_block_ton_message_t, l_message_size);
-    l_message->hdr.id.uint64 = (uint64_t)a_session->cur_round.messages_count;
-    l_message->hdr.chain_id.uint64 = a_session->chain->id.uint64;
-    l_message->hdr.ts_created = dap_time_now();
-    l_message->hdr.type = a_message_type;
-    l_message->hdr.sender_node_addr = *dap_chain_net_get_cur_addr(l_net);
-
-    size_t l_sign_size = 0;
-    if ( !PVT(a_session->ton)->validators_list_by_stake ) {
-        size_t l_data_size = sizeof(l_message->hdr.sender_node_addr);
-        uint8_t *l_data = s_message_data_sign(a_session, l_message, &l_data_size);
-        dap_sign_t *l_sign = dap_sign_create(PVT(a_session->ton)->blocks_sign_key, l_data, l_data_size, 0);
-        l_sign_size = dap_sign_get_size(l_sign);
-        l_message_size += l_sign_size;
-        l_message = DAP_REALLOC(l_message, l_message_size);
-        memcpy(l_message->sign_n_message, l_sign, l_sign_size);
-        DAP_DELETE(l_sign);
-        DAP_DELETE(l_data);
-    }
-    l_message->hdr.sign_size = l_sign_size;
-    memcpy(l_message->sign_n_message+l_sign_size, a_data, a_data_size);
-    l_message->hdr.message_size = a_data_size;
-
-    dap_chain_hash_fast_t l_message_hash;
-    dap_hash_fast(l_message, l_message_size, &l_message_hash);
-
-    dap_stream_ch_chain_voting_message_write(l_net, a_validators, //a_session->cur_round.validators_start,
-                                                &l_message_hash, l_message, l_message_size);
-    DAP_DELETE(l_message);
-}
-
-
-static void s_message_chain_add(dap_chain_cs_block_ton_session_t *a_session, dap_chain_node_addr_t *a_sender_node_addr,
-                                    dap_chain_cs_block_ton_message_t *a_message,
-                                    size_t a_message_size, dap_chain_hash_fast_t *a_message_hash)
-{
-    if (a_session->state == DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE)
-        return;
-    dap_chain_cs_block_ton_round_t *l_round = &a_session->cur_round;
-    a_message->hdr.is_genesis = dap_hash_fast_is_blank(&l_round->last_message_hash);
-    if (!a_message->hdr.is_genesis) {
-        a_message->hdr.prev_message_hash = l_round->last_message_hash;
-    }
-
-    dap_chain_cs_block_ton_message_item_t *l_message_item = DAP_NEW_Z(dap_chain_cs_block_ton_message_item_t);
-    dap_chain_hash_fast_t l_message_hash;
-    dap_hash_fast(a_message, a_message_size, &l_message_hash);
-    l_round->last_message_hash = l_message_item->message_hash = l_message_hash;
-    l_message_item->message = DAP_DUP_SIZE(a_message, a_message_size);
-    if (a_message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR ||
-            a_message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE)
-        l_message_item->message->hdr.is_verified = true;
-
-    pthread_rwlock_wrlock(&l_round->messages_rwlock);
-    HASH_ADD(hh, l_round->messages_items, message_hash, sizeof(l_message_item->message_hash), l_message_item);
-    pthread_rwlock_unlock(&l_round->messages_rwlock);
-
-    l_round->messages_count++;
-    if (a_message_hash)
-        *a_message_hash = l_message_hash;
-}
-
-static size_t s_callback_block_sign(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t **a_block_ptr, size_t a_block_size)
-{
-    assert(a_blocks);
-    dap_chain_cs_block_ton_t *l_ton = DAP_CHAIN_CS_BLOCK_TON(a_blocks);
-    dap_chain_cs_block_ton_pvt_t *l_ton_pvt = PVT(l_ton);
-    if (!l_ton_pvt->blocks_sign_key) {
-        log_it(L_WARNING, "Can't sign block with blocks-sign-cert in [block-ton] section");
-        return 0;
-    }
-    if (!a_block_ptr || !(*a_block_ptr) || !a_block_size) {
-        log_it(L_WARNING, "Block size or block pointer is NULL");
-        return 0;
-    }
-    return dap_chain_block_sign_add(a_block_ptr, a_block_size, l_ton_pvt->blocks_sign_key);
-}
-
-static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t *a_block, size_t a_block_size)
-{
-    dap_chain_cs_block_ton_t *l_ton = DAP_CHAIN_CS_BLOCK_TON(a_blocks);
-    dap_chain_cs_block_ton_pvt_t *l_ton_pvt = PVT(l_ton);
-    if (a_blocks->chain->ledger == NULL) {
-        log_it(L_CRITICAL,"Ledger is NULL can't check TON on this chain %s", a_blocks->chain->name);
-        return -3;
-    }
-    if (sizeof(a_block->hdr) >= a_block_size) {
-        log_it(L_WARNING,"Incorrect size with block %p on chain %s", a_block, a_blocks->chain->name);
-        return  -7;
-    }
-
-    if ( l_ton_pvt->flag_sign_verify && !l_ton_pvt->validators_list_by_stake ) { // PoA mode
-        size_t l_offset = dap_chain_block_get_sign_offset(a_block, a_block_size);
-        size_t l_signs_count = 0;
-        dap_sign_t **l_signs = dap_sign_get_unique_signs(a_block->meta_n_datum_n_sign+l_offset,
-                                                a_block_size-sizeof(a_block->hdr)-l_offset, &l_signs_count);
-        if (!l_signs_count){
-            log_it(L_ERROR, "No any signatures at all for block");
-            DAP_DELETE(l_signs);
-            return -2;
-        }
-
-        if (l_signs_count * 3  < l_ton_pvt->poa_validators_count * 2) {
-            log_it(L_ERROR, "Corrupted block: not enough signs: %zu of %hu", l_signs_count, l_ton_pvt->poa_validators_count);
-            DAP_DELETE(l_signs);
-            return -1;
-        }
-
-        // Parse the rest signs
-        int l_ret = 0;
-        uint16_t l_signs_verified_count = 0;
-        size_t l_block_excl_sign_size = dap_chain_block_get_sign_offset(a_block, a_block_size)+sizeof(a_block->hdr);
-        for (size_t i=0; i<l_signs_count; i++) {
-            dap_sign_t *l_sign = (dap_sign_t *)l_signs[i];
-            if (!dap_sign_verify_size(l_sign, a_block_size - l_block_excl_sign_size + sizeof(a_block->hdr))) {
-                log_it(L_ERROR, "Corrupted block: sign size is bigger than block size");
-                l_ret = -3;
-                break;
-            }
-
-            // Compare signature with auth_certs
-            for (uint16_t j = 0; j < l_ton_pvt->auth_certs_count; j++) {
-                if (dap_cert_compare_with_sign( l_ton_pvt->auth_certs[j], l_sign) == 0
-                        && dap_sign_verify(l_sign, a_block, l_block_excl_sign_size) == 1 ){
-                    l_signs_verified_count++;
-                    break;
-                }
-            }
-        }
-        DAP_DELETE(l_signs);
-        if ( l_ret != 0 ) {
-            return l_ret;
-        }
-        if (l_signs_verified_count * 3 < l_ton_pvt->poa_validators_count * 2) {
-            log_it(L_ERROR, "Corrupted block: not enough signs: %u of %u", l_signs_verified_count, l_ton_pvt->poa_validators_count);
-            return -1;
-        }
-    }
-    return 0;
-}
-
diff --git a/modules/consensus/block-ton/include/dap_chain_cs_block_ton.h b/modules/consensus/block-ton/include/dap_chain_cs_block_ton.h
deleted file mode 100644
index 562b4f662d34eb56b65cab0a0815819da8ff82ca..0000000000000000000000000000000000000000
--- a/modules/consensus/block-ton/include/dap_chain_cs_block_ton.h
+++ /dev/null
@@ -1,204 +0,0 @@
-
-#include "dap_chain.h"
-#include "dap_chain_block.h"
-#include "dap_chain_cs_blocks.h"
-#include "dap_cert.h"
-
-#define DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE                  0x04
-#define DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_START            0x08
-#define DAP_STREAM_CH_CHAIN_SESSION_STATE_CS_PROC               0x12
-#define DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS            0x16
-
-#define DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_START_SYNC		0x32
-
-#define DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT         0x04
-#define DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE        0x08
-#define DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT        	0x12
-#define DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN    0x16
-#define DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE        	0x20
-#define DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR       0x24
-#define DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT     0x28
-
-#define DAP_CHAIN_BLOCKS_SESSION_ROUND_ID_SIZE		8
-#define DAP_CHAIN_BLOCKS_SESSION_MESSAGE_ID_SIZE	8
-
-typedef struct dap_chain_cs_block_ton_message dap_chain_cs_block_ton_message_t;
-typedef struct dap_chain_cs_block_ton_message_item dap_chain_cs_block_ton_message_item_t;
-
-typedef struct dap_chain_cs_block_ton
-{
-    dap_chain_t *chain;
-    dap_chain_cs_blocks_t *blocks;
-    void *_pvt;
-} dap_chain_cs_block_ton_t;
-
-typedef union dap_chain_cs_block_ton_round_id {
-    uint8_t raw[DAP_CHAIN_BLOCKS_SESSION_ROUND_ID_SIZE];
-    uint64_t uint64;
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_round_id_t;
-
-typedef union dap_chain_cs_block_ton_msg_id {
-    uint8_t raw[DAP_CHAIN_BLOCKS_SESSION_MESSAGE_ID_SIZE];
-    uint64_t uint64;
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_msg_id_t;
-
-typedef struct dap_chain_cs_block_ton_round {
-    dap_chain_cs_block_ton_round_id_t id;
-    dap_list_t *validators_start; // dap_chain_node_addr_t
-    uint16_t validators_start_count;
-    dap_chain_hash_fast_t last_message_hash;
-    dap_chain_cs_block_ton_message_item_t *messages_items;
-    pthread_rwlock_t messages_rwlock;
-    bool submit;
-    uint16_t messages_count;
-    dap_chain_hash_fast_t my_candidate_hash;
-    dap_list_t *validators_list; // dap_chain_node_addr_t
-    uint16_t validators_count;
-    uint16_t candidates_count;
-} dap_chain_cs_block_ton_round_t;
-
-typedef struct dap_chain_cs_block_ton_session {
-    dap_chain_t *chain;
-    dap_chain_cs_block_ton_t *ton;
-
-    dap_chain_node_addr_t *my_addr;
-
-    dap_chain_block_t *my_candidate;
-    size_t my_candidate_size;
-    uint16_t my_candidate_attempts_count;
-
-    uint8_t state; // session state
-    dap_chain_cs_block_ton_round_t cur_round;
-
-    dap_chain_node_addr_t *attempt_coordinator; // validator-coordinator in current attempt
-    uint16_t attempt_current_number;
-
-    dap_time_t ts_round_sync_start; // time start sync
-    dap_time_t ts_round_start; // time round-start
-    dap_time_t ts_round_state_commit;
-    dap_time_t ts_round_finish;
-
-    char * gdb_group_setup;
-    char * gdb_group_store;
-    char * gdb_group_message;
-
-    dap_enc_key_t *blocks_sign_key;
-
-    struct dap_chain_cs_block_ton_session *next;
-    struct dap_chain_cs_block_ton_session *prev;
-
-    dap_worker_t * worker; // Worker where it was processed last time
-    pthread_rwlock_t rwlock;
-} dap_chain_cs_block_ton_session_t;
-
-typedef struct dap_chain_cs_block_ton_message_hdr {
-    uint8_t type;
-    dap_chain_cs_block_ton_msg_id_t id;
-    uint64_t sign_size;
-    uint64_t message_size;
-    dap_time_t ts_created;
-    dap_chain_node_addr_t sender_node_addr;
-    uint16_t  is_genesis;
-    uint16_t  is_verified;
-    dap_chain_hash_fast_t prev_message_hash;
-    dap_chain_id_t chain_id;
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_hdr_t;
-
-typedef struct dap_chain_cs_block_ton_message {
-    dap_chain_cs_block_ton_message_hdr_t hdr;
-    uint8_t sign_n_message[];
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_t;
-
-typedef struct dap_chain_cs_block_ton_message_item {
-    dap_chain_cs_block_ton_message_t *message;
-    dap_chain_hash_fast_t message_hash;
-    UT_hash_handle hh;
-} dap_chain_cs_block_ton_message_item_t;
-
-// struct for get info from any messages
-typedef struct dap_chain_cs_block_ton_message_getinfo {
-    dap_chain_hash_fast_t candidate_hash;
-    dap_chain_cs_block_ton_round_id_t round_id;
-    uint16_t attempt_number;
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_getinfo_t;
-
-// technical messages
-typedef struct dap_chain_cs_block_ton_message_startsync {
-    dap_time_t ts;
-    dap_chain_cs_block_ton_round_id_t round_id;
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_startsync_t;
-
-/*
-consensus messages
-• Submit(round, candidate) — suggest a new block candidate
-• Approve(round, candidate, signature) — a block candidate has passed local validation
-• Reject(round, candidate) — a block candidate has failed local valida- tion
-• CommitSign(round,candidate,signature) — a block candidate has been accepted and signed
-• Vote(round, candidate) — a vote for a block candidate
-• VoteFor(round, candidate) — this block candidate must be voted for
-in this round (even if the current process has another opinion)
-• PreCommit(round,candidate) — a preliminary commitment to a block candidate (used in three-phase commit scheme)
-*/
-
-typedef struct dap_chain_cs_block_ton_message_submit {
-    dap_chain_hash_fast_t candidate_hash;
-    dap_chain_cs_block_ton_round_id_t round_id;
-    size_t candidate_size;
-    uint8_t candidate[];
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_submit_t;
-
-typedef struct dap_chain_cs_block_ton_message_approve {
-    dap_chain_hash_fast_t candidate_hash;
-    dap_chain_cs_block_ton_round_id_t round_id;
-    uint8_t candidate_hash_sign[];
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_approve_t;
-
-typedef struct dap_chain_cs_block_ton_message_reject {
-    dap_chain_hash_fast_t candidate_hash;
-    dap_chain_cs_block_ton_round_id_t round_id;
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_reject_t;
-
-typedef struct dap_chain_cs_block_ton_message_votefor {
-    dap_chain_hash_fast_t candidate_hash;
-    dap_chain_cs_block_ton_round_id_t round_id;
-    uint16_t attempt_number;
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_votefor_t;
-
-typedef struct dap_chain_cs_block_ton_message_vote {
-    dap_chain_hash_fast_t candidate_hash;
-    dap_chain_cs_block_ton_round_id_t round_id;
-    uint16_t attempt_number;
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_vote_t;
-
-typedef struct dap_chain_cs_block_ton_message_precommit {
-    dap_chain_hash_fast_t candidate_hash;
-    dap_chain_cs_block_ton_round_id_t round_id;
-    uint16_t attempt_number;
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_precommit_t;
-
-typedef struct dap_chain_cs_block_ton_message_commitsign {
-    dap_chain_hash_fast_t candidate_hash;
-    dap_chain_cs_block_ton_round_id_t round_id;
-    uint8_t candidate_sign[];
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_message_commitsign_t;
-
-typedef struct dap_chain_cs_block_ton_store_hdr {
-    bool sign_collected; // collect 2/3 min
-    bool approve_collected;
-    // bool reject_done;
-    bool vote_collected;
-    bool precommit_collected;
-    size_t candidate_size;
-    dap_chain_cs_block_ton_round_id_t round_id;
-    dap_chain_hash_fast_t candidate_hash;
-    dap_time_t ts_candidate_submit;
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_store_hdr_t;
-
-typedef struct dap_chain_cs_block_ton_store {
-    dap_chain_cs_block_ton_store_hdr_t hdr;
-    uint8_t candidate_n_signs[];
-} DAP_ALIGN_PACKED dap_chain_cs_block_ton_store_t;
-
-#define DAP_CHAIN_CS_BLOCK_TON(a) ((dap_chain_cs_block_ton_t *)(a)->_inheritor)
-int dap_chain_cs_block_ton_init();
-void dap_chain_cs_block_ton_deinit(void);
diff --git a/modules/consensus/block-ton/CMakeLists.txt b/modules/consensus/esbocs/CMakeLists.txt
similarity index 57%
rename from modules/consensus/block-ton/CMakeLists.txt
rename to modules/consensus/esbocs/CMakeLists.txt
index 0f5cf209e1c22c0a365281bbf63e48eb700e0eb4..beada9e5a9f93e97c545212b9a73c83bfd95d610 100644
--- a/modules/consensus/block-ton/CMakeLists.txt
+++ b/modules/consensus/esbocs/CMakeLists.txt
@@ -1,10 +1,10 @@
 cmake_minimum_required(VERSION 3.10)
-project (dap_chain_cs_block_ton)
+project (dap_chain_cs_esbocs)
   
-file(GLOB DAP_CHAIN_CS_BLOCK_TON_SRCS *.c)
-file(GLOB DAP_CHAIN_CS_BLOCK_TON_HEADERS include/*.h)
+file(GLOB DAP_CHAIN_ESBOCS_SRCS *.c)
+file(GLOB DAP_CHAIN_CS_ESBOCS_HEADERS include/*.h)
 
-add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_CS_BLOCK_TON_SRCS} ${DAP_CHAIN_CS_BLOCK_TON_HEADERS})
+add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_ESBOCS_SRCS} ${DAP_CHAIN_CS_ESBOCS_HEADERS})
 
 target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_cs_blocks dap_chain_net_srv_stake_pos_delegate dap_stream_ch_chain_voting)
 target_include_directories(${PROJECT_NAME} INTERFACE .)
diff --git a/modules/consensus/esbocs/dap_chain_cs_esbocs.c b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
new file mode 100644
index 0000000000000000000000000000000000000000..9616097550628889d9ccae6096505c7b4854e464
--- /dev/null
+++ b/modules/consensus/esbocs/dap_chain_cs_esbocs.c
@@ -0,0 +1,1377 @@
+#include "utlist.h"
+#include "dap_timerfd.h"
+#include "rand/dap_rand.h"
+#include "dap_chain_net.h"
+#include "dap_chain_common.h"
+#include "dap_chain_cell.h"
+#include "dap_chain_cs.h"
+#include "dap_chain_cs_blocks.h"
+#include "dap_chain_cs_esbocs.h"
+#include "dap_stream_ch_chain_voting.h"
+#include "dap_chain_net_srv_stake_pos_delegate.h"
+#include "dap_chain_ledger.h"
+
+#define LOG_TAG "dap_chain_cs_esbocs"
+
+enum s_esbocs_session_state {
+    DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_START,
+    DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_PROC,
+    DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_SIGNS,
+    DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_FINISH
+};
+
+static dap_list_t *s_validator_check(dap_chain_addr_t *a_addr, dap_list_t *a_validators);
+static void s_get_last_block_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_last_hash_ptr);
+static void s_session_state_change(dap_chain_esbocs_session_t *a_session, enum s_esbocs_session_state a_new_state, dap_time_t a_time);
+static void s_session_packet_in(void * a_arg, dap_chain_node_addr_t * a_sender_node_addr,
+                                dap_chain_hash_fast_t *a_data_hash, uint8_t *a_data, size_t a_data_size);
+static void s_session_round_clear(dap_chain_esbocs_session_t *a_session);
+static void s_session_round_new(dap_chain_esbocs_session_t *a_session);
+static void s_session_candidate_to_chain(
+            dap_chain_esbocs_session_t *a_session, dap_chain_hash_fast_t *a_candidate_hash,
+                            dap_chain_block_t *a_candidate, size_t a_candidate_size);
+static void s_session_candidate_submit(dap_chain_esbocs_session_t *a_session);
+static void s_session_candidate_verify(dap_chain_esbocs_session_t *a_session, dap_chain_block_t *a_candidate,
+                                       size_t a_candidate_size, dap_hash_fast_t *a_candidate_hash);
+static bool s_session_timer(void *a_arg);
+static void s_message_send(dap_chain_esbocs_session_t *a_session, uint8_t a_message_type, dap_hash_fast_t *a_block_hash,
+                                    const void *a_data, size_t a_data_size, dap_list_t *a_validators);
+static void s_message_chain_add(dap_chain_esbocs_session_t * a_session,
+                                    dap_chain_esbocs_message_t * a_message,
+                                    size_t a_message_size, dap_chain_hash_fast_t *a_message_hash);
+
+static int s_callback_new(dap_chain_t *a_chain, dap_config_t *a_chain_cfg);
+static void s_callback_delete(dap_chain_cs_blocks_t *a_blocks);
+static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cfg);
+static size_t s_callback_block_sign(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t **a_block_ptr, size_t a_block_size);
+static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t *a_block, size_t a_block_size);
+
+DAP_STATIC_INLINE const char *s_VOTING_MSG_type_to_str(uint8_t a_type)
+{
+    switch (a_type) {
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_START_SYNC: return "START_SYNC";
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_SUBMIT: return "SUBMIT";
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_APPROVE: return "APPROVE";
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_REJECT: return "REJECT";
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_COMMIT_SIGN: return "COMMIT_SIGN";
+    //case DAP_STREAM_CH_VOTING_MSG_TYPE_VOTE: return "VOTE";
+    //case DAP_STREAM_CH_VOTING_MSG_TYPE_VOTE_FOR: return "VOTE_FOR"
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_PRE_COMMIT: return "PRE_COMMIT";
+    default: return "UNKNOWN";
+    }
+}
+
+static dap_chain_esbocs_session_t * s_session_items;
+static dap_timerfd_t *s_session_cs_timer = NULL;
+
+typedef struct dap_chain_esbocs_pvt {
+    // Base params
+    dap_enc_key_t *blocks_sign_key;
+    // Validators section
+    bool poa_mode;
+    uint16_t min_validators_count;
+    // Debug flag
+    bool debug;
+    // Round params
+    uint16_t new_round_delay;
+    uint16_t round_start_sync_timeout;
+    uint16_t round_attempts_max;
+    uint16_t round_attempt_timeout;
+    // PoA section
+    dap_list_t *poa_validators;
+} dap_chain_esbocs_pvt_t;
+
+#define PVT(a) ((dap_chain_esbocs_pvt_t *)a->_pvt)
+
+int dap_chain_cs_esbocs_init()
+{
+    dap_stream_ch_chain_voting_init();
+    dap_chain_cs_add("esbocs", s_callback_new);
+    return 0;
+}
+
+void dap_chain_cs_esbocs_deinit(void)
+{
+}
+
+static int s_callback_new(dap_chain_t *a_chain, dap_config_t *a_chain_cfg)
+{
+    dap_chain_cs_blocks_new(a_chain, a_chain_cfg);
+    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
+    dap_chain_esbocs_t *l_esbocs = DAP_NEW_Z(dap_chain_esbocs_t);
+    l_blocks->_inheritor = l_esbocs;
+    l_blocks->callback_delete = s_callback_delete;
+    l_blocks->callback_block_verify = s_callback_block_verify;
+    l_blocks->callback_block_sign = s_callback_block_sign;
+    l_esbocs->_pvt = DAP_NEW_Z(dap_chain_esbocs_pvt_t);
+
+    dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(l_esbocs);
+
+    l_esbocs_pvt->debug = dap_config_get_item_bool_default(a_chain_cfg, "esbocs", "consensus_debug", false);
+
+    l_esbocs_pvt->poa_mode = dap_config_get_item_bool_default(a_chain_cfg, "esbocs", "poa_mode", false);
+    l_esbocs_pvt->round_start_sync_timeout = dap_config_get_item_uint16_default(a_chain_cfg, "esbocs", "round_start_sync_timeout", 15);
+    l_esbocs_pvt->new_round_delay = dap_config_get_item_uint16(a_chain_cfg, "esbocs", "new_round_delay");
+    l_esbocs_pvt->round_attempts_max = dap_config_get_item_uint16_default(a_chain_cfg, "esbocs", "round_attempts_max", 4);
+    l_esbocs_pvt->round_attempt_timeout = dap_config_get_item_uint16_default(a_chain_cfg, "esbocs", "round_attempt_timeout", 10);
+
+    int l_ret = 0;
+    l_esbocs_pvt->min_validators_count = dap_config_get_item_uint16(a_chain_cfg, "esbocs", "min_validators_count");
+    if (!l_esbocs_pvt->min_validators_count) {
+        l_ret = -1;
+        goto lb_err;
+    }
+    if (l_esbocs_pvt->poa_mode) { // auth by certs in PoA mode
+        const char *l_auth_certs_prefix = dap_config_get_item_str(a_chain_cfg, "esbocs", "auth_certs_prefix");
+        uint16_t l_node_addrs_count;
+        char **l_addrs = dap_config_get_array_str(a_chain_cfg, "esbocs", "validators_addrs", &l_node_addrs_count);
+        uint16_t l_auth_certs_count = l_node_addrs_count;
+        if (l_auth_certs_count < l_esbocs_pvt->min_validators_count) {
+            l_ret = -2;
+            goto lb_err;
+        }
+        char l_cert_name[512];
+        dap_cert_t *l_cert_cur;
+        for (size_t i = 0; i < l_auth_certs_count; i++) {
+            dap_chain_esbocs_validator_t *l_validator = DAP_NEW(dap_chain_esbocs_validator_t);
+
+            dap_snprintf(l_cert_name, sizeof(l_cert_name), "%s.%zu", l_auth_certs_prefix, i);
+            if ((l_cert_cur = dap_cert_find_by_name(l_cert_name)) == NULL) {
+                dap_snprintf(l_cert_name, sizeof(l_cert_name), "%s.%zu.pub", l_auth_certs_prefix, i);
+                if ((l_cert_cur = dap_cert_find_by_name(l_cert_name)) == NULL) {
+                    log_it(L_ERROR, "ESBOCS: Can't find cert \"%s\"", l_cert_name);
+                    DAP_DELETE(l_validator);
+                    l_ret = -3;
+                    goto lb_err;
+                }
+            }
+            log_it(L_NOTICE, "ESBOCS: Initialized auth cert \"%s\"", l_cert_name);
+            dap_chain_addr_fill_from_key(&l_validator->signing_addr, l_cert_cur->enc_key, a_chain->net_id);
+
+            if (dap_sscanf(l_addrs[i], NODE_ADDR_FP_STR, NODE_ADDR_FPS_ARGS_S(l_validator->node_addr) ) != 4) {
+                log_it(L_ERROR,"ESBOCS: Wrong address format, should be like 0123::4567::89AB::CDEF");
+                DAP_DELETE(l_validator);
+                l_ret = -4;
+                goto lb_err;
+            }
+            log_it(L_MSG, "ESBOCS: add validator addr:"NODE_ADDR_FP_STR"", NODE_ADDR_FP_ARGS_S(l_validator->node_addr));
+
+            l_validator->weight = uint256_1;
+            l_esbocs_pvt->poa_validators = dap_list_append(l_esbocs_pvt->poa_validators, l_validator);
+        }
+    }
+    l_blocks->chain->callback_created = s_callback_created;
+    return 0;
+
+lb_err:
+    dap_list_free_full(l_esbocs_pvt->poa_validators, NULL);
+    DAP_DELETE(l_esbocs_pvt);
+    DAP_DELETE(l_esbocs);
+    l_blocks->_inheritor = NULL;
+    l_blocks->callback_delete = NULL;
+    l_blocks->callback_block_verify = NULL;
+    return l_ret;
+}
+
+static  void s_atom_notifier(void *a_arg, UNUSED_ARG dap_chain_t *a_chain, UNUSED_ARG dap_chain_cell_id_t a_id,
+                             UNUSED_ARG void* a_atom, UNUSED_ARG size_t a_atom_size)
+{
+    dap_chain_esbocs_session_t *l_session = a_arg;
+    pthread_rwlock_wrlock(&l_session->rwlock);
+    dap_chain_hash_fast_t l_last_block_hash;
+    s_get_last_block_hash(l_session->chain, &l_last_block_hash);
+    if (!dap_hash_fast_compare(&l_last_block_hash, &l_session->cur_round.last_block_hash))
+        s_session_round_new(l_session);
+    pthread_rwlock_unlock(&l_session->rwlock);
+}
+
+static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cfg) {
+
+    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
+    dap_chain_esbocs_t *l_esbocs = DAP_CHAIN_ESBOCS(l_blocks);
+    dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(l_esbocs);
+
+    const char *l_sign_cert_str = NULL;
+    if ((l_sign_cert_str = dap_config_get_item_str(a_chain_net_cfg, "esbocs", "blocks-sign-cert")) != NULL) {
+        dap_cert_t *l_sign_cert = dap_cert_find_by_name(l_sign_cert_str);
+        if (l_sign_cert == NULL) {
+            log_it(L_ERROR, "Can't load sign certificate, name \"%s\" is wrong", l_sign_cert_str);
+            return 0;
+        } else if (l_sign_cert->enc_key->priv_key_data) {
+            l_esbocs_pvt->blocks_sign_key = l_sign_cert->enc_key;
+            log_it(L_INFO, "Loaded \"%s\" certificate to sign TON blocks", l_sign_cert_str);
+        } else {
+            log_it(L_ERROR, "Certificate \"%s\" has no private key", l_sign_cert_str);
+            return 0;
+        }
+    } else {
+        log_it(L_NOTICE, "No sign certificate provided, can't sign any blocks. This node can't be a consensus validator");
+        return 0;
+    }
+
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
+    dap_chain_node_role_t l_role = dap_chain_net_get_role(l_net);
+    if (l_role.enums > NODE_ROLE_MASTER) {
+        log_it(L_NOTICE, "Node role is lower than master role, so this node can't be a consensus validator");
+        return 0;
+    }
+
+    dap_chain_addr_t l_my_signing_addr;
+    dap_chain_addr_fill_from_key(&l_my_signing_addr, l_esbocs_pvt->blocks_sign_key, a_chain->net_id);
+    if (!l_esbocs_pvt->poa_mode) {
+        if (!dap_chain_net_srv_stake_key_delegated(&l_my_signing_addr)) {
+            log_it(L_WARNING, "Signing key is not delegated by stake service. Switch off validator mode");
+            return 0;
+        }
+    } else {
+        if (s_validator_check(&l_my_signing_addr, l_esbocs_pvt->poa_validators)) {
+            log_it(L_WARNING, "Signing key is not present in PoA certs list. Switch off validator mode");
+            return 0;
+        }
+    }
+
+    dap_chain_esbocs_session_t *l_session = DAP_NEW_Z(dap_chain_esbocs_session_t);
+    l_session->chain = a_chain;
+    l_session->esbocs = l_esbocs;
+    l_session->my_addr.uint64 = dap_chain_net_get_cur_addr_int(l_net);
+    pthread_rwlock_init(&l_session->rwlock, NULL);
+    dap_stream_ch_chain_voting_in_callback_add(l_session, s_session_packet_in);
+    dap_chain_add_callback_notify(a_chain, s_atom_notifier, l_session);
+    s_session_round_new(l_session);
+
+    log_it(L_INFO, "ESBOCS: init session for net:%s, chain:%s", a_chain->net_name, a_chain->name);
+    DL_APPEND(s_session_items, l_session);
+    if (!s_session_cs_timer) {
+        s_session_cs_timer = dap_timerfd_start(1000, s_session_timer, NULL);
+        debug_if(l_esbocs_pvt->debug, L_MSG, "ESBOCS: Consensus main timer is started");
+    }
+    return 0;
+}
+
+static void s_callback_delete(dap_chain_cs_blocks_t *a_blocks)
+{
+    dap_chain_esbocs_t *l_esbocs = DAP_CHAIN_ESBOCS(a_blocks);
+    dap_chain_esbocs_session_t *l_session = l_esbocs->session;
+    pthread_rwlock_wrlock(&l_session->rwlock);
+    DL_DELETE(s_session_items, l_session);
+    if (!s_session_items)
+        dap_timerfd_delete(s_session_cs_timer);
+    s_session_round_clear(l_session);
+    dap_chain_esbocs_sync_item_t *l_item, *l_tmp;
+    HASH_ITER(hh, l_session->sync_items, l_item, l_tmp) {
+        HASH_DEL(l_session->sync_items, l_item);
+        dap_list_free_full(l_item->messages, NULL);
+        DAP_DELETE(l_item);
+    }
+    pthread_rwlock_unlock(&l_session->rwlock);
+    DAP_DELETE(l_session);
+    if (l_esbocs->_pvt)
+        DAP_DELETE(l_esbocs->_pvt);
+    DAP_DEL_Z(a_blocks->_inheritor);
+}
+
+static void *s_callback_list_copy(const void *a_validator, UNUSED_ARG void *a_data)
+{
+    return DAP_DUP((dap_chain_esbocs_validator_t *)a_validator);
+}
+
+static void *s_callback_list_form(const void *a_srv_validator, UNUSED_ARG void *a_data)
+{
+    dap_chain_esbocs_validator_t *l_validator = DAP_NEW(dap_chain_esbocs_validator_t);
+    l_validator->node_addr = ((dap_chain_net_srv_stake_item_t *)a_srv_validator)->node_addr;
+    l_validator->signing_addr = ((dap_chain_net_srv_stake_item_t *)a_srv_validator)->signing_addr;
+    l_validator->weight = ((dap_chain_net_srv_stake_item_t *)a_srv_validator)->value;
+    l_validator->is_synced = false;
+    return l_validator;
+}
+
+static dap_list_t *s_get_validators_list(dap_chain_esbocs_session_t *a_session, dap_chain_hash_fast_t *a_seed_hash)
+{
+    dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(a_session->esbocs);
+    dap_list_t *l_ret = NULL;
+
+    if (!l_esbocs_pvt->poa_mode) {
+        dap_list_t *l_validators = dap_chain_net_srv_stake_get_validators();
+        size_t l_validators_count = dap_list_length(l_validators);
+        if (l_validators_count < l_esbocs_pvt->min_validators_count) {
+            dap_list_free_full(l_validators, NULL);
+            return NULL;
+        }
+        size_t n = (size_t)l_esbocs_pvt->min_validators_count * 3;
+        size_t l_consensus_optimum = (n / 2) + (n % 2);
+        size_t l_need_vld_cnt = MIN(l_validators_count, l_consensus_optimum);
+        if (l_validators_count == l_need_vld_cnt) {
+            l_ret = dap_list_copy_deep(l_validators, s_callback_list_form, NULL);
+            dap_list_free_full(l_validators, NULL);
+            return l_ret;
+        }
+
+        // TODO: make dap_chain_net_srv_stake_get_total_weight() call
+        uint256_t l_total_weight = uint256_0;
+        for (dap_list_t *it = l_validators; it; it = it->next) {
+            if (SUM_256_256(l_total_weight,
+                            ((dap_chain_net_srv_stake_item_t *)it->data)->value,
+                            &l_total_weight)) {
+                log_it(L_CRITICAL, "Total stake locked value overflow"); // Is it possible?
+                dap_list_free_full(l_validators, NULL);
+                return NULL;
+            }
+        }
+        if (a_seed_hash)
+            dap_pseudo_random_seed(*(uint256_t *)a_seed_hash);
+        for (size_t l_current_vld_cnt = 0; l_current_vld_cnt < l_need_vld_cnt; l_current_vld_cnt++) {
+            uint256_t l_chosen_weight = dap_pseudo_random_get(l_total_weight);
+            dap_list_t *l_chosen = NULL;
+            uint256_t l_cur_weight = uint256_0;
+            for (dap_list_t *it = l_validators; it; it = it->next) {
+                SUM_256_256(l_cur_weight,
+                            ((dap_chain_net_srv_stake_item_t *)it->data)->value,
+                            &l_cur_weight);
+                if (compare256(l_chosen_weight, l_cur_weight) == -1) {
+                    l_chosen = it;
+                    break;
+                }
+            }
+            l_ret = dap_list_append(l_ret, s_callback_list_form(l_chosen->data, NULL));
+
+            SUBTRACT_256_256(l_total_weight,
+                             ((dap_chain_net_srv_stake_item_t *)l_chosen->data)->value,
+                             &l_total_weight);
+            l_validators = dap_list_remove_link(l_validators, l_chosen);
+            DAP_DELETE(l_chosen->data);
+            DAP_DELETE(l_chosen);
+        }
+        dap_list_free_full(l_validators, NULL);
+    } else
+        l_ret = dap_list_copy_deep(l_esbocs_pvt->poa_validators, s_callback_list_copy, NULL);
+
+    return l_ret;
+}
+
+static void s_get_last_block_hash(dap_chain_t *a_chain, dap_chain_hash_fast_t *a_last_hash_ptr)
+{
+    dap_chain_atom_iter_t *l_iter = a_chain->callback_atom_iter_create(a_chain, c_dap_chain_cell_id_null, false);
+    dap_chain_atom_ptr_t *l_ptr_list = a_chain->callback_atom_iter_get_lasts(l_iter, NULL, NULL);
+    DAP_DEL_Z(l_ptr_list);
+    *a_last_hash_ptr = *l_iter->cur_hash;
+    a_chain->callback_atom_iter_delete(l_iter);
+}
+
+static int s_addr_compare(const void *a_list_data, const void *a_user_data)
+{
+    return dap_chain_addr_compare(&((dap_chain_esbocs_validator_t *)a_list_data)->signing_addr,
+                                  (dap_chain_addr_t *)a_user_data);
+}
+
+static dap_list_t *s_validator_check(dap_chain_addr_t *a_addr, dap_list_t *a_validators)
+{
+    return dap_list_find_custom(a_validators, a_addr, s_addr_compare);
+}
+
+static void s_session_send_startsync(dap_chain_esbocs_session_t *a_session)
+{
+    dap_chain_hash_fast_t l_last_block_hash;
+    s_get_last_block_hash(a_session->chain, &l_last_block_hash);
+    a_session->ts_round_sync_start = dap_time_now();    
+    if (!dap_hash_fast_compare(&l_last_block_hash, &a_session->cur_round.last_block_hash))
+        return;     // My last block hash is different, so skip this round
+    if (!s_validator_check(&a_session->my_signing_addr, a_session->cur_round.validators_list))
+        return;     // I'm not a selected validator, just skip sync message
+    s_message_send(a_session, DAP_STREAM_CH_VOTING_MSG_TYPE_START_SYNC, &l_last_block_hash,
+                   NULL, 0, a_session->cur_round.validators_list);
+    debug_if(PVT(a_session->esbocs)->debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" Sent START_SYNC pkt",
+                    a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id);
+}
+
+static bool s_session_send_startsync_on_timer(void *a_arg)
+{
+    dap_chain_esbocs_session_t *l_session = a_arg;
+    pthread_rwlock_wrlock(&l_session->rwlock);
+    s_session_send_startsync(l_session);
+    pthread_rwlock_unlock(&l_session->rwlock);
+    return false;
+}
+
+static void s_session_round_clear(dap_chain_esbocs_session_t *a_session)
+{
+    dap_chain_esbocs_message_item_t *l_message_item, *l_message_tmp;
+    HASH_ITER(hh, a_session->cur_round.message_items, l_message_item, l_message_tmp) {
+        HASH_DEL(a_session->cur_round.message_items, l_message_item);
+        DAP_DELETE(l_message_item->message);
+        DAP_DELETE(l_message_item);
+    }
+    dap_chain_esbocs_store_t *l_store_item, *l_store_tmp;
+    HASH_ITER(hh, a_session->cur_round.store_items, l_store_item, l_store_tmp) {
+        HASH_DEL(a_session->cur_round.store_items, l_store_item);
+        dap_list_free_full(l_store_item->candidate_signs, NULL);
+        DAP_DELETE(l_store_item);
+    }
+    dap_list_free_full(a_session->cur_round.validators_list, NULL);
+
+    a_session->cur_round = (dap_chain_esbocs_round_t){
+            .id = a_session->cur_round.id,
+            .last_block_hash = a_session->cur_round.last_block_hash
+    };
+    dap_timerfd_delete(a_session->sync_timer);
+}
+
+static void s_session_round_new(dap_chain_esbocs_session_t *a_session)
+{
+    s_session_round_clear(a_session);
+    a_session->cur_round.id++;
+    a_session->state = DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_START;
+    dap_hash_fast_t *l_seed_hash = NULL;
+    dap_hash_fast_t l_last_block_hash;
+    s_get_last_block_hash(a_session->chain, &l_last_block_hash);
+    if (dap_hash_fast_is_blank(&a_session->cur_round.last_block_hash) ||
+            !dap_hash_fast_compare(&l_last_block_hash, &a_session->cur_round.last_block_hash)) {
+        l_seed_hash = &l_last_block_hash;
+        a_session->cur_round.last_block_hash = l_last_block_hash;
+    }
+    a_session->cur_round.validators_list = s_get_validators_list(a_session, l_seed_hash);
+
+    if (s_validator_check(&a_session->my_signing_addr, a_session->cur_round.validators_list)) {
+        //I am a current round validator
+        dap_chain_esbocs_sync_item_t *l_item, *l_tmp;
+        bool l_round_already_started = false;
+        HASH_FIND(hh, a_session->sync_items, &a_session->cur_round.last_block_hash, sizeof(dap_hash_fast_t), l_item);
+        if (l_item) {
+            debug_if(PVT(a_session->esbocs)->debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" already started. Process sync messages",
+                                                                a_session->chain->net_name, a_session->chain->name,
+                                                                    a_session->cur_round.id);
+            l_round_already_started = true;
+            for (dap_list_t *it = l_item->messages; it; it = it->next) {
+                dap_hash_fast_t l_msg_hash;
+                dap_chain_esbocs_message_t *l_msg = it->data;
+                size_t l_msg_size = sizeof(*l_msg) + l_msg->hdr.sign_size + l_msg->hdr.message_size;
+                dap_hash_fast(l_msg, l_msg_size, &l_msg_hash);
+                s_session_packet_in(a_session, NULL, &l_msg_hash, (uint8_t *)l_msg, l_msg_size);
+            }
+        }
+        HASH_ITER(hh, a_session->sync_items, l_item, l_tmp) {
+            HASH_DEL(a_session->sync_items, l_item);
+            dap_list_free_full(l_item->messages, NULL);
+            DAP_DELETE(l_item);
+        }
+        if (l_round_already_started) {
+            s_session_send_startsync(a_session);
+            return;
+        }
+
+        debug_if(PVT(a_session->esbocs)->debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" start. Syncing validators in %u seconds",
+                                                            a_session->chain->net_name, a_session->chain->name,
+                                                                a_session->cur_round.id, PVT(a_session->esbocs)->new_round_delay);
+    }
+    if (PVT(a_session->esbocs)->new_round_delay)
+        a_session->sync_timer = dap_timerfd_start(PVT(a_session->esbocs)->new_round_delay, s_session_send_startsync_on_timer, a_session);
+    else
+        s_session_send_startsync(a_session);
+}
+
+static void s_session_attempt_new(dap_chain_esbocs_session_t *a_session)
+{
+    if (++a_session->cur_round.attempt_num > PVT(a_session->esbocs)->round_attempts_max ) {
+        debug_if(PVT(a_session->esbocs)->debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U"."
+                                                        " Round finish by reason: attempts is out",
+                                                            a_session->chain->net_name, a_session->chain->name,
+                                                                a_session->cur_round.id);
+        s_session_round_new(a_session);
+        return;
+    }
+    for (dap_list_t *it = a_session->cur_round.validators_list; it; it = it->next) {
+        dap_chain_esbocs_validator_t *l_validator = it->data;
+        if (l_validator->is_synced && !l_validator->is_chosen) {
+            // We have synced validator with no submitted candidate
+            debug_if(PVT(a_session->esbocs)->debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U". Attempt:%hu is started"                                                     " Round finish by reason: attempts is out",
+                                                                a_session->chain->net_name, a_session->chain->name,
+                                                                    a_session->cur_round.id, a_session->cur_round.attempt_num);
+            s_session_state_change(a_session, DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_PROC, dap_time_now());
+        }
+    }
+    debug_if(PVT(a_session->esbocs)->debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U"."
+                                                    " Round finish by reason: all synced validators already tryed its attempt",
+                                                        a_session->chain->net_name, a_session->chain->name,
+                                                            a_session->cur_round.id);
+    s_session_round_new(a_session);
+}
+
+static uint64_t s_session_calc_current_round_id(dap_chain_esbocs_session_t *a_session)
+{
+    struct {
+        uint64_t id;
+        uint16_t counter;
+    } l_id_candidates[a_session->cur_round.validators_synced_count];
+    uint16_t l_fill_idx = 0;
+    dap_chain_esbocs_message_item_t *l_item, *l_tmp;
+    HASH_ITER(hh, a_session->cur_round.message_items, l_item, l_tmp) {
+        if (l_item->message->hdr.type == DAP_STREAM_CH_VOTING_MSG_TYPE_START_SYNC) {
+            uint64_t l_id_candidate = l_item->message->hdr.round_id;
+            bool l_candidate_found = false;
+            for (uint16_t i = 0; i < l_fill_idx; i++)
+                if (l_id_candidates[i].id == l_id_candidate) {
+                    l_id_candidates[i].counter++;
+                    l_candidate_found = true;
+                    break;
+                }
+            if (!l_candidate_found) {
+                l_id_candidates[l_fill_idx].id = l_id_candidate;
+                l_id_candidates[l_fill_idx].counter = 1;
+                l_fill_idx++;
+            }
+        }
+    }
+    uint64_t l_ret = 0;
+    uint16_t l_counter_max = 0;
+    for (uint16_t i = 0; i < l_fill_idx; i++) {
+        if (l_id_candidates[i].counter > l_counter_max) { // Choose maximum counter
+            l_counter_max = l_id_candidates[i].counter;
+            l_ret = l_id_candidates[i].id;
+        } else if (l_id_candidates[i].counter == l_counter_max) // Choose maximum round ID
+            l_ret = MAX(l_ret, l_id_candidates[i].id);
+    }
+    return l_ret;
+}
+
+static int s_signs_sort_callback(const void *a_sign1, const void *a_sign2, UNUSED_ARG void *a_user_data)
+{
+    size_t l_size1 = dap_sign_get_size((dap_sign_t *)a_sign1);
+    size_t l_size2 = dap_sign_get_size((dap_sign_t *)a_sign2);
+    size_t l_size_min = MIN(l_size1, l_size2);
+    int l_ret = memcmp(a_sign1, a_sign2, l_size_min);
+    if (!l_ret) {
+        if (l_size1 < l_size2)
+            l_ret = -1;
+        else if (l_size1 > l_size2)
+            l_ret = 1;
+    }
+    return l_ret;
+}
+
+static void s_session_state_change(dap_chain_esbocs_session_t *a_session, enum s_esbocs_session_state a_new_state, dap_time_t a_time)
+{
+    a_session->state = a_new_state;
+    a_session->ts_attempt_start = a_time;
+    switch (a_session->state) {
+    case DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_PROC: {
+        uint256_t l_total_weight = uint256_0;
+        dap_chain_esbocs_validator_t *l_validator;
+        for (dap_list_t *it = a_session->cur_round.validators_list; it; it = it->next) {
+            l_validator = it->data;
+            if (l_validator->is_synced && !l_validator->is_chosen)
+                SUM_256_256(l_total_weight, l_validator->weight, &l_total_weight);
+        }
+        uint256_t l_chosen_weight = dap_pseudo_random_get(l_total_weight);
+        uint256_t l_cur_weight = uint256_0;
+        for (dap_list_t *it = a_session->cur_round.validators_list; it; it = it->next) {
+            l_validator = it->data;
+            if (l_validator->is_synced && !l_validator->is_chosen) {
+                SUM_256_256(l_total_weight, l_validator->weight, &l_cur_weight);
+                if (compare256(l_chosen_weight, l_cur_weight) == -1) {
+                    l_validator->is_chosen = true;
+                    break;
+                }
+            }
+        }
+        a_session->cur_round.attempt_submit_validator = l_validator->signing_addr;
+        if (dap_chain_addr_compare(&a_session->cur_round.attempt_submit_validator, &a_session->my_signing_addr))
+            s_session_candidate_submit(a_session);
+        else {
+            dap_chain_esbocs_message_item_t *l_item, *l_tmp;
+            HASH_ITER(hh, a_session->cur_round.message_items, l_item, l_tmp) {
+                if (l_item->message->hdr.type == DAP_STREAM_CH_VOTING_MSG_TYPE_SUBMIT &&
+                        dap_chain_addr_compare(&l_item->signing_addr, &a_session->cur_round.attempt_submit_validator)) {
+                    // Verify and vote already submitted candidate
+                    s_session_candidate_verify(a_session, (dap_chain_block_t *)l_item->message->msg_n_sign,
+                                               l_item->message->hdr.message_size, &l_item->message->hdr.candidate_hash);
+                }
+            }
+        }
+    } break;
+    case DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_FINISH: {
+        dap_chain_esbocs_store_t *l_store;
+        HASH_FIND(hh, a_session->cur_round.store_items, &a_session->cur_round.attempt_candidate_hash, sizeof(dap_hash_fast_t), l_store);
+        if (!l_store) {
+            log_it(L_ERROR, "ESBOCS: No finish candidate found!");
+            break;
+        }
+        dap_list_sort(l_store->candidate_signs, s_signs_sort_callback);
+        size_t l_candidate_size_exclude_signs = l_store->candidate_size;
+        for (dap_list_t *it = l_store->candidate_signs; it; it = it->next) {
+            dap_sign_t *l_candidate_sign = (dap_sign_t *)it->data;
+            size_t l_candidate_sign_size = dap_sign_get_size(l_candidate_sign);
+            dap_chain_addr_t l_signing_addr_cur;
+            dap_chain_addr_fill_from_sign(&l_signing_addr_cur, l_candidate_sign, a_session->chain->net_id);
+            l_store->candidate = DAP_REALLOC(l_store->candidate, l_store->candidate_size + l_candidate_sign_size);
+            if (dap_chain_addr_compare(&l_signing_addr_cur, &a_session->cur_round.attempt_submit_validator)) {
+                // If it's the primary attempt validator sign, place it in the beginnig
+                if (l_store->candidate_size > l_candidate_size_exclude_signs)
+                    memmove((byte_t *)l_store->candidate + l_candidate_size_exclude_signs + l_candidate_sign_size,
+                            (byte_t *)l_store->candidate + l_candidate_size_exclude_signs,
+                            l_candidate_sign_size);
+                memcpy((byte_t *)l_store->candidate + l_candidate_size_exclude_signs, l_candidate_sign, l_candidate_sign_size);
+            } else
+                memcpy(((byte_t *)l_store->candidate) + l_store->candidate_size, l_candidate_sign, l_candidate_sign_size);
+            l_store->candidate_size += l_candidate_sign_size;
+        }
+        l_store->candidate->hdr.meta_n_datum_n_signs_size = l_store->candidate_size - sizeof(l_store->candidate->hdr);
+        dap_hash_fast(l_store->candidate, l_store->candidate_size, &l_store->precommit_candidate_hash);
+        // Send PreCommit
+        s_message_send(a_session, DAP_STREAM_CH_VOTING_MSG_TYPE_PRE_COMMIT, &l_store->candidate_hash,
+                            &l_store->precommit_candidate_hash, sizeof(dap_chain_hash_fast_t),
+                                a_session->cur_round.validators_list);
+    } break;
+    default:
+        break;
+    }
+}
+
+static void s_session_proc_state(dap_chain_esbocs_session_t *a_session)
+{
+    if (pthread_rwlock_trywrlock(&a_session->rwlock) != 0)
+        return; // Session is busy
+    bool l_cs_debug = PVT(a_session->esbocs)->debug;
+    dap_time_t l_time = dap_time_now();
+    switch (a_session->state) {
+    case DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_START:
+        if (l_time - a_session->ts_round_sync_start >= PVT(a_session->esbocs)->round_start_sync_timeout) {
+            if (a_session->cur_round.validators_synced_count * 3 >= dap_list_length(a_session->cur_round.validators_list) * 2) {
+                a_session->cur_round.id = s_session_calc_current_round_id(a_session);
+                debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                                            " More than 2/3 of the validators are synchronized, wait to submit candidate",
+                                                a_session->chain->net_name, a_session->chain->name,
+                                                    a_session->cur_round.id, a_session->cur_round.attempt_num);
+                s_session_state_change(a_session, DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_PROC, l_time);
+            } else { // timeout start sync
+                debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                                            " Round finish by reason: can't synchronize 2/3 of the validators",
+                                                a_session->chain->net_name, a_session->chain->name,
+                                                    a_session->cur_round.id, a_session->cur_round.attempt_num);
+                s_session_round_new(a_session);
+            }
+        }
+        break;
+    case DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_PROC:
+        if (l_time - a_session->ts_attempt_start >= PVT(a_session->esbocs)->round_attempt_timeout) {
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                                        " Attempt finish by reason: haven't cantidate submitted",
+                                            a_session->chain->net_name, a_session->chain->name,
+                                                a_session->cur_round.id, a_session->cur_round.attempt_num);
+            s_session_attempt_new(a_session);
+        }
+        break;
+    case DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_SIGNS:
+        if (l_time - a_session->ts_attempt_start >= PVT(a_session->esbocs)->round_attempt_timeout) {
+            dap_chain_esbocs_store_t *l_store;
+            HASH_FIND(hh, a_session->cur_round.store_items, &a_session->cur_round.attempt_candidate_hash, sizeof(dap_hash_fast_t), l_store);
+            if (!l_store) {
+                log_it(L_ERROR, "ESBOCS: No round candidate found!");
+                s_session_attempt_new(a_session);
+                break;
+            }
+            if (dap_list_length(l_store->candidate_signs) >= PVT(a_session->esbocs)->min_validators_count) {
+                if(l_cs_debug) {
+                    char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(&a_session->cur_round.attempt_candidate_hash);
+                    log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu"
+                                            " Candidate:%s collected sings of more than 2/3 of the validators, so to sent a PRE_COMMIT",
+                                                a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id,
+                                                    a_session->cur_round.attempt_num, l_candidate_hash_str);
+                    DAP_DELETE(l_candidate_hash_str);
+                }
+                s_session_state_change(a_session, DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_FINISH, l_time);
+                break;
+            }
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                                        " Attempt finish by reason: cant't collect 2/3 validator signs",
+                                            a_session->chain->net_name, a_session->chain->name,
+                                                a_session->cur_round.id, a_session->cur_round.attempt_num);
+            s_session_attempt_new(a_session);
+        }
+        break;
+    case DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_FINISH:
+        if (l_time - a_session->ts_attempt_start >= PVT(a_session->esbocs)->round_attempt_timeout) {
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                                        " Attempt finish by reason: cant't collect 2/3 validator precommits with same final hash",
+                                            a_session->chain->net_name, a_session->chain->name,
+                                                a_session->cur_round.id, a_session->cur_round.attempt_num);
+            s_session_attempt_new(a_session);
+        }
+        break;
+    default:
+        break;
+    }
+
+    pthread_rwlock_unlock(&a_session->rwlock);
+}
+
+static bool s_session_timer(void *a_arg)
+{
+    UNUSED(a_arg);
+    dap_chain_esbocs_session_t *l_session = NULL;
+    DL_FOREACH(s_session_items, l_session) {
+        s_session_proc_state(l_session);
+    }
+    return true;
+}
+
+static void s_message_chain_add(dap_chain_esbocs_session_t *a_session,
+                                    dap_chain_esbocs_message_t *a_message,
+                                    size_t a_message_size, dap_chain_hash_fast_t *a_message_hash)
+{
+    dap_chain_esbocs_round_t *l_round = &a_session->cur_round;
+    dap_chain_esbocs_message_item_t *l_message_item = DAP_NEW_Z(dap_chain_esbocs_message_item_t);
+    if (!a_message_hash) {
+        dap_chain_hash_fast_t l_message_hash;
+        dap_hash_fast(a_message, a_message_size, &l_message_hash);
+        l_message_item->message_hash = l_message_hash;
+    } else
+        l_message_item->message_hash = *a_message_hash;
+    l_message_item->message = DAP_DUP_SIZE(a_message, a_message_size);
+    HASH_ADD(hh, l_round->message_items, message_hash, sizeof(l_message_item->message_hash), l_message_item);
+}
+
+static void s_session_candidate_submit(dap_chain_esbocs_session_t *a_session)
+{
+    dap_chain_t *l_chain = a_session->chain;
+    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(l_chain);
+    dap_chain_block_t *l_candidate;
+    size_t l_candidate_size = 0;
+    dap_hash_fast_t l_candidate_hash = {0};
+    dap_chain_node_mempool_process_all(a_session->chain);
+    l_candidate = l_blocks->callback_new_block_move(l_blocks, &l_candidate_size);
+    if (l_candidate_size) {
+        dap_hash_fast(l_candidate, l_candidate_size, &l_candidate_hash);
+        if (PVT(a_session->esbocs)->debug) {
+            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(&l_candidate_hash);
+            log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U" Submit my candidate:%s",
+                    a_session->chain->net_name, a_session->chain->name,
+                        a_session->cur_round.id, l_candidate_hash_str);
+            DAP_DELETE(l_candidate_hash_str);
+        }
+    } else { // there is no my candidate, send null hash
+        if (PVT(a_session->esbocs)->debug)
+            log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu I don't have a candidate. I submit a null candidate.",
+                        a_session->chain->net_name, a_session->chain->name,
+                            a_session->cur_round.id, a_session->cur_round.attempt_num);
+    }
+    s_message_send(a_session, DAP_STREAM_CH_VOTING_MSG_TYPE_SUBMIT, &l_candidate_hash,
+                    l_candidate, l_candidate_size, a_session->cur_round.validators_list);
+}
+
+static void s_session_candidate_verify(dap_chain_esbocs_session_t *a_session, dap_chain_block_t *a_candidate,
+                                       size_t a_candidate_size, dap_hash_fast_t *a_candidate_hash)
+{
+    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_session->chain);
+    if (l_blocks->chain->callback_atom_verify(l_blocks->chain, a_candidate, a_candidate_size) == ATOM_ACCEPT) {
+        // validation - OK, gen event Approve
+        s_message_send(a_session, DAP_STREAM_CH_VOTING_MSG_TYPE_APPROVE, a_candidate_hash,
+                       NULL, 0, a_session->cur_round.validators_list);
+        if (PVT(a_session->esbocs)->debug) {
+            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(a_candidate_hash);
+            log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Sent APPROVE candidate:%s",
+                                a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id,
+                                        a_session->cur_round.attempt_num, l_candidate_hash_str);
+            DAP_DELETE(l_candidate_hash_str);
+        }
+    } else {
+        // validation - fail, gen event Reject
+        s_message_send(a_session, DAP_STREAM_CH_VOTING_MSG_TYPE_REJECT, a_candidate_hash,
+                       NULL, 0, a_session->cur_round.validators_list);
+        if (PVT(a_session->esbocs)->debug) {
+            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(a_candidate_hash);
+            log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Sent REJECT candidate:%s",
+                                a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id,
+                                        a_session->cur_round.attempt_num, l_candidate_hash_str);
+            DAP_DELETE(l_candidate_hash_str);
+        }
+    }
+}
+
+static void s_session_candidate_to_chain(dap_chain_esbocs_session_t *a_session, dap_chain_hash_fast_t *a_candidate_hash,
+                                         dap_chain_block_t *a_candidate, size_t a_candidate_size)
+{
+    dap_chain_block_t *l_candidate = DAP_DUP_SIZE(a_candidate, a_candidate_size);
+    dap_chain_atom_verify_res_t l_res = a_session->chain->callback_atom_add(a_session->chain, l_candidate, a_candidate_size);
+    char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(a_candidate_hash);
+    switch (l_res) {
+    case ATOM_ACCEPT:
+        // block save to chain
+        if (dap_chain_atom_save(a_session->chain, (uint8_t *)l_candidate, a_candidate_size, a_session->chain->cells->id) < 0)
+            log_it(L_ERROR, "ESBOCS: Can't save atom %s to the file", l_candidate_hash_str);
+        else
+            log_it(L_INFO, "ESBOCS: block %s added in chain successfully", l_candidate_hash_str);
+        break;
+    case ATOM_MOVE_TO_THRESHOLD:
+        log_it(L_INFO, "ESBOCS: Thresholded atom with hash %s", l_candidate_hash_str);
+        break;
+    case ATOM_PASS:
+        log_it(L_WARNING, "ESBOCS: Atom with hash %s not accepted (code ATOM_PASS, already present)", l_candidate_hash_str);
+        DAP_DELETE(l_candidate);
+        break;
+    case ATOM_REJECT:
+        log_it(L_WARNING,"ESBOCS: Atom with hash %s rejected", l_candidate_hash_str);
+        DAP_DELETE(l_candidate);
+        break;
+    default:
+         log_it(L_CRITICAL, "ESBOCS: Wtf is this ret code ? Atom hash %s code %d", l_candidate_hash_str, l_res);
+         DAP_DELETE(l_candidate);
+    }
+    DAP_DELETE(l_candidate_hash_str);
+}
+
+static void s_session_round_finish(dap_chain_esbocs_session_t *a_session, dap_chain_esbocs_store_t *l_store)
+{
+    bool l_cs_debug = PVT(a_session->esbocs)->debug;
+    uint16_t l_cs_level = PVT(a_session->esbocs)->min_validators_count;
+
+    if (!dap_hash_fast_compare(&a_session->cur_round.attempt_candidate_hash, &l_store->candidate_hash)) {
+        char *l_current_candidate_hash_str = dap_chain_hash_fast_to_str_new(&a_session->cur_round.attempt_candidate_hash);
+        char *l_finish_candidate_hash_str = dap_chain_hash_fast_to_str_new(&l_store->candidate_hash);
+        debug_if(l_cs_debug, L_WARNING, "ESBOCS: Trying to finish candidate of not the current attempt (%s but not %s)",
+                                        l_current_candidate_hash_str, l_finish_candidate_hash_str);
+        DAP_DELETE(l_current_candidate_hash_str);
+        DAP_DELETE(l_finish_candidate_hash_str);
+        return;
+    }
+
+    if (l_store->reject_count >= l_cs_level) {
+        char *l_finish_candidate_hash_str = dap_chain_hash_fast_to_str_new(&l_store->candidate_hash);
+        debug_if(l_cs_debug, L_WARNING, "ESBOCS: Trying to finish rejected candidate %s", l_finish_candidate_hash_str);
+        DAP_DELETE(l_finish_candidate_hash_str);
+        return;
+    }
+
+    if (l_store->approve_count < l_cs_level) {
+        char *l_finish_candidate_hash_str = dap_chain_hash_fast_to_str_new(&l_store->candidate_hash);
+        debug_if(l_cs_debug, L_WARNING, "ESBOCS: Trying to finish not properly approved candidate %s", l_finish_candidate_hash_str);
+        DAP_DELETE(l_finish_candidate_hash_str);
+        return;
+    }
+
+    if (dap_list_length(l_store->candidate_signs) < l_cs_level) {
+        char *l_finish_candidate_hash_str = dap_chain_hash_fast_to_str_new(&l_store->candidate_hash);
+        debug_if(l_cs_debug, L_WARNING, "ESBOCS: Trying to finish not properly signed candidate %s", l_finish_candidate_hash_str);
+        DAP_DELETE(l_finish_candidate_hash_str);
+        return;
+    }
+
+    if (l_store->precommit_count < l_cs_level) {
+        char *l_finish_candidate_hash_str = dap_chain_hash_fast_to_str_new(&l_store->candidate_hash);
+        debug_if(l_cs_debug, L_WARNING, "ESBOCS: Trying to finish not properly precommited candidate %s", l_finish_candidate_hash_str);
+        DAP_DELETE(l_finish_candidate_hash_str);
+        return;
+    }
+
+    if (l_cs_debug) {
+        char *l_finish_candidate_hash_str = dap_chain_hash_fast_to_str_new(&l_store->candidate_hash);
+        char *l_finish_block_hash_str = dap_chain_hash_fast_to_str_new(&l_store->precommit_candidate_hash);
+        log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu My candidate:%s passed the consensus!\n"
+                      "Move block %s to chains",
+                        a_session->chain->net_name, a_session->chain->name, a_session->cur_round.id,
+                            a_session->cur_round.attempt_num, l_finish_candidate_hash_str, l_finish_block_hash_str);
+        DAP_DELETE(l_finish_candidate_hash_str);
+        DAP_DELETE(l_finish_block_hash_str);
+    }
+    s_session_candidate_to_chain(a_session, &l_store->precommit_candidate_hash, l_store->candidate, l_store->candidate_size);
+}
+
+/**
+ * @brief s_session_packet_in
+ * @param a_arg
+ * @param a_sender_node_addr
+ * @param a_data_hash
+ * @param a_data
+ * @param a_data_size
+ */
+static void s_session_packet_in(void *a_arg, dap_chain_node_addr_t *a_sender_node_addr,
+                                dap_chain_hash_fast_t *a_data_hash, uint8_t *a_data, size_t a_data_size)
+{
+    dap_chain_esbocs_session_t *l_session = a_arg;
+    dap_chain_esbocs_message_t *l_message = (dap_chain_esbocs_message_t *)a_data;
+    bool l_cs_debug = PVT(l_session->esbocs)->debug;
+    uint16_t l_cs_level = PVT(l_session->esbocs)->min_validators_count;
+    size_t l_message_data_size = l_message->hdr.message_size;
+    byte_t *l_message_data = l_message->msg_n_sign;
+    dap_sign_t *l_sign = (dap_sign_t *)(l_message_data + l_message_data_size);
+    size_t l_sign_size = l_message->hdr.sign_size;
+
+    pthread_rwlock_wrlock(&l_session->rwlock);
+    if (a_sender_node_addr) { //Process network message
+        debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive pkt type:%x from addr:"NODE_ADDR_FP_STR", my_addr:"NODE_ADDR_FP_STR"",
+                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                        l_session->cur_round.attempt_num, l_message->hdr.type,
+                            NODE_ADDR_FP_ARGS(a_sender_node_addr), NODE_ADDR_FP_ARGS_S(l_session->my_addr));
+
+        if (sizeof(*l_message) + l_message->hdr.sign_size + l_message->hdr.message_size != a_data_size) {
+            log_it(L_WARNING, "ESBOCS: incorrect message size in header is %zu when data size is only %zu and header size is %zu",
+                   l_message->hdr.sign_size, a_data_size, sizeof(*l_message));
+            goto session_unlock;
+        }
+
+        if (l_message->hdr.chain_id.uint64 != l_session->chain->id.uint64) {
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: Invalid chain ID %"DAP_UINT64_FORMAT_U, l_message->hdr.chain_id.uint64);
+            goto session_unlock;
+        }
+
+        dap_chain_hash_fast_t l_data_hash = {};
+        dap_hash_fast(l_message, a_data_size, &l_data_hash);
+        if (!dap_hash_fast_compare(a_data_hash, &l_data_hash)) {
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: message hash does not match",
+                        l_session->chain->net_name, l_session->chain->name,
+                            l_session->cur_round.id, l_session->cur_round.attempt_num);
+            goto session_unlock;
+        }
+
+        l_message->hdr.sign_size = 0;   // restore header on signing time
+        bool l_verify_passed = dap_sign_verify_all(l_sign, l_sign_size, l_message, l_message_data_size + sizeof(l_message->hdr)) == 1;
+        if (!l_verify_passed) {
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected from addr:"NODE_ADDR_FP_STR" not passed verification",
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                            l_session->cur_round.attempt_num, NODE_ADDR_FP_ARGS(a_sender_node_addr));
+            goto session_unlock;
+        }
+        l_message->hdr.sign_size = l_sign_size; // restore original header
+
+        // consensus round start sync
+        if (l_message->hdr.type == DAP_STREAM_CH_VOTING_MSG_TYPE_START_SYNC) {
+            if (!dap_hash_fast_compare(&l_message->hdr.candidate_hash, &l_session->cur_round.last_block_hash)) {
+                dap_chain_esbocs_sync_item_t *l_sync_item;
+                HASH_FIND(hh, l_session->sync_items, &l_message->hdr.candidate_hash, sizeof(dap_hash_fast_t), l_sync_item);
+                if (!l_sync_item) {
+                    l_sync_item = DAP_NEW(dap_chain_esbocs_sync_item_t);
+                    l_sync_item->last_block_hash = l_message->hdr.candidate_hash;
+                }
+                l_sync_item->messages = dap_list_append(l_sync_item->messages, DAP_DUP(l_message));
+                goto session_unlock;
+            }
+        } else if (l_message->hdr.round_id != l_session->cur_round.id ||
+                   l_message->hdr.attempt_num < l_session->cur_round.attempt_num) {
+            // round check
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: round or attempt in message does not match",
+                        l_session->chain->net_name, l_session->chain->name,
+                            l_session->cur_round.id, l_session->cur_round.attempt_num);
+            goto session_unlock;
+        }
+    }
+    // Process local & network messages
+    dap_chain_addr_t l_signing_addr;
+    char *l_validator_addr_str = NULL;
+    dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, l_session->chain->net_id);
+    if (l_cs_debug)
+        l_validator_addr_str = dap_chain_addr_to_str(&l_signing_addr);
+    if (!s_validator_check(&l_signing_addr, l_session->cur_round.validators_list)) {
+        debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: validator addr:%s not in the list.",
+                l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                    l_session->cur_round.attempt_num, l_validator_addr_str);
+        goto session_unlock;
+    }
+
+    dap_chain_esbocs_round_t *l_round = &l_session->cur_round;
+
+    // check hash message dup
+    dap_chain_esbocs_message_item_t *l_message_item_temp = NULL;
+    HASH_FIND(hh, l_round->message_items, a_data_hash, sizeof(dap_chain_hash_fast_t), l_message_item_temp);
+    if (l_message_item_temp) {
+        debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Message rejected: message hash is exists in chain (duplicate?)",
+                    l_session->chain->net_name, l_session->chain->name,
+                        l_session->cur_round.id, l_session->cur_round.attempt_num);
+        goto session_unlock;
+    }
+
+    // check messages chain
+    dap_chain_esbocs_message_item_t *l_chain_message, *l_chain_message_tmp;
+    HASH_ITER(hh, l_round->message_items, l_chain_message, l_chain_message_tmp) {
+        bool l_same_type = l_chain_message->message->hdr.type == l_message->hdr.type ||
+                (l_chain_message->message->hdr.type == DAP_STREAM_CH_VOTING_MSG_TYPE_APPROVE &&
+                 l_message->hdr.type == DAP_STREAM_CH_VOTING_MSG_TYPE_REJECT) ||
+                (l_chain_message->message->hdr.type == DAP_STREAM_CH_VOTING_MSG_TYPE_REJECT &&
+                 l_message->hdr.type == DAP_STREAM_CH_VOTING_MSG_TYPE_APPROVE);
+        if (l_same_type && dap_chain_addr_compare(&l_chain_message->signing_addr, &l_signing_addr) &&
+                dap_hash_fast_compare(&l_chain_message->message->hdr.candidate_hash, &l_message->hdr.candidate_hash)) {
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu. Message rejected: duplicate message %s",
+                                            l_session->chain->net_name, l_session->chain->name,
+                                                l_session->cur_round.id, l_session->cur_round.attempt_num,
+                                                    s_VOTING_MSG_type_to_str(l_message->hdr.type));
+            goto session_unlock;
+        }
+    }
+
+    dap_chain_hash_fast_t *l_candidate_hash = &l_message->hdr.candidate_hash;
+    switch (l_message->hdr.type) {
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_START_SYNC:
+        debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu. Receive START_SYNC: from validator:%s",
+                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                        l_session->cur_round.attempt_num, l_validator_addr_str);
+        s_message_chain_add(l_session, l_message, a_data_size, a_data_hash);
+        for (dap_list_t *it = l_session->cur_round.validators_list; it; it = it->next) {
+            dap_chain_esbocs_validator_t *l_validator = it->data;
+            if (dap_chain_addr_compare(&l_validator->signing_addr, &l_signing_addr))
+                l_validator->is_synced = true;
+        }
+        if (++l_session->cur_round.validators_synced_count == dap_list_length(l_session->cur_round.validators_list)) {
+            l_session->cur_round.id = s_session_calc_current_round_id(l_session);
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                                        " All validators are synchronized, wait to submit candidate",
+                                            l_session->chain->net_name, l_session->chain->name,
+                                                l_session->cur_round.id, l_session->cur_round.attempt_num);
+            s_session_state_change(l_session, DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_PROC, dap_time_now());
+        }
+        break;
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_SUBMIT: {
+        uint8_t *l_candidate = l_message->msg_n_sign;
+        size_t l_candidate_size = l_message->hdr.message_size;
+        if (!l_candidate_size || dap_hash_fast_is_blank(&l_message->hdr.candidate_hash)) {
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu. Receive SUBMIT candidate NULL",
+                                            l_session->chain->net_name, l_session->chain->name,
+                                                l_session->cur_round.id, l_session->cur_round.attempt_num);
+            if (dap_chain_addr_compare(&l_session->cur_round.attempt_submit_validator, &l_signing_addr))
+                s_session_attempt_new(l_session);
+            break;
+        }
+        // check candidate hash
+        dap_chain_hash_fast_t l_check_hash;
+        dap_hash_fast(l_candidate, l_candidate_size, &l_check_hash);
+        if (!dap_hash_fast_compare(&l_check_hash, l_candidate_hash)) {
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu. Receive SUBMIT candidate hash broken",
+                                            l_session->chain->net_name, l_session->chain->name,
+                                                l_session->cur_round.id, l_session->cur_round.attempt_num);
+            break;
+        }
+
+        s_message_chain_add(l_session, l_message, a_data_size, a_data_hash);
+
+        if (l_cs_debug) {
+            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu. Receive SUBMIT candidate %s, size %zu",
+                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                        l_session->cur_round.attempt_num, l_candidate_hash_str, l_candidate_size);
+            DAP_DELETE(l_candidate_hash_str);
+        }
+
+        dap_chain_esbocs_store_t *l_store;
+        HASH_FIND(hh, l_session->cur_round.store_items, l_candidate_hash, sizeof(dap_chain_hash_fast_t), l_store);
+        if (l_store) {
+            char *l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            log_it(L_WARNING, "ESBOCS: Duplicate candidate:%s", l_candidate_hash_str);
+            DAP_DELETE(l_candidate_hash_str);
+            break;
+        }
+
+        // store for new candidate
+        l_store = DAP_NEW_Z(dap_chain_esbocs_store_t);
+        l_store->candidate_size = l_candidate_size;
+        l_store->candidate_hash = *l_candidate_hash;
+        l_store->candidate = DAP_DUP_SIZE(l_candidate, l_candidate_size);
+
+        // save new block candidate
+        HASH_ADD(hh, l_session->cur_round.store_items, candidate_hash, sizeof(dap_hash_fast_t), l_store);
+        // check it and send APPROVE/REJECT
+        if (dap_chain_addr_compare(&l_session->cur_round.attempt_submit_validator, &l_signing_addr)) {
+            l_session->cur_round.attempt_candidate_hash = *l_candidate_hash;
+            s_session_state_change(l_session, DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_SIGNS, dap_time_now());
+            s_session_candidate_verify(l_session, l_store->candidate, l_store->candidate_size, &l_store->candidate_hash);
+        }
+    } break;
+
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_REJECT: {
+        dap_chain_esbocs_store_t *l_store;
+        char *l_candidate_hash_str = NULL;
+        HASH_FIND(hh, l_session->cur_round.store_items, l_candidate_hash, sizeof(dap_chain_hash_fast_t), l_store);
+        if (!l_store) {
+            l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            log_it(L_WARNING, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu, Receive REJECT message for unknown candidate:%s",
+                       l_session->chain->net_name, l_session->chain->name,
+                           l_session->cur_round.id, l_session->cur_round.attempt_num,
+                                l_candidate_hash_str);
+            DAP_DELETE(l_candidate_hash_str);
+            break;
+        }
+
+        s_message_chain_add(l_session, l_message, a_data_size, a_data_hash);
+
+        if (l_cs_debug) {
+            l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive REJECT: candidate:%s",
+                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                        l_session->cur_round.attempt_num, l_candidate_hash_str);
+        }
+        if (++l_store->reject_count >= l_cs_level && !l_store->decide_reject &&
+                dap_hash_fast_compare(&l_session->cur_round.attempt_candidate_hash, l_candidate_hash)) {
+            l_store->decide_reject = true;
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                                        " Candidate:%s rejected by more than 2/3 of the validators",
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                            l_session->cur_round.attempt_num, l_candidate_hash_str);
+            s_session_attempt_new(l_session);
+        }
+        DAP_DEL_Z(l_candidate_hash_str);
+    } break;
+
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_APPROVE: {
+        dap_chain_esbocs_store_t *l_store;
+        char *l_candidate_hash_str = NULL;
+        HASH_FIND(hh, l_session->cur_round.store_items, l_candidate_hash, sizeof(dap_chain_hash_fast_t), l_store);
+        if (!l_store) {
+            l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            log_it(L_WARNING, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu, Receive APPROVE message for unknown candidate:%s",
+                       l_session->chain->net_name, l_session->chain->name,
+                           l_session->cur_round.id, l_session->cur_round.attempt_num,
+                                l_candidate_hash_str);
+            DAP_DELETE(l_candidate_hash_str);
+            break;
+        }
+
+        s_message_chain_add(l_session, l_message, a_data_size, a_data_hash);
+
+        if (l_cs_debug) {
+            l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive APPROVE: candidate:%s",
+                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                        l_session->cur_round.attempt_num, l_candidate_hash_str);
+        }
+        if (++l_store->approve_count >= l_cs_level && !l_store->decide_approve &&
+                dap_hash_fast_compare(&l_session->cur_round.attempt_candidate_hash, l_candidate_hash)) {
+            l_store->decide_approve = true;
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu."
+                                        " Candidate:%s approved by more than 2/3 of the validators, let's sign it",
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                            l_session->cur_round.attempt_num, l_candidate_hash_str);
+            size_t l_offset = dap_chain_block_get_sign_offset(l_store->candidate, l_store->candidate_size);
+            dap_sign_t *l_candidate_sign = dap_sign_create(PVT(l_session->esbocs)->blocks_sign_key,
+                                            l_store->candidate, l_offset + sizeof(l_store->candidate->hdr), 0);
+            size_t l_candidate_sign_size = dap_sign_get_size(l_candidate_sign);
+            s_message_send(l_session, DAP_STREAM_CH_VOTING_MSG_TYPE_COMMIT_SIGN, l_candidate_hash,
+                           l_candidate_sign, l_candidate_sign_size, l_session->cur_round.validators_list);
+            DAP_DELETE(l_candidate_sign);
+        }
+        DAP_DEL_Z(l_candidate_hash_str);
+    } break;
+
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_COMMIT_SIGN: {
+        dap_sign_t *l_candidate_sign = (dap_sign_t *)l_message_data;
+        size_t l_candidate_sign_size = dap_sign_get_size(l_candidate_sign);
+        if (l_candidate_sign_size != l_message_data_size) {
+            log_it(L_WARNING, "Wrong commit_sign message size, have %zu bytes for candidate sign section when requires %zu bytes",
+                              l_candidate_sign_size, l_message_data_size);
+            break;
+        }
+
+        dap_chain_esbocs_store_t *l_store;
+        char *l_candidate_hash_str = NULL;
+        HASH_FIND(hh, l_session->cur_round.store_items, l_candidate_hash, sizeof(dap_chain_hash_fast_t), l_store);
+        if (!l_store) {
+            l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            log_it(L_WARNING, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu, Receive COMMIT_SIGN message for unknown candidate:%s",
+                       l_session->chain->net_name, l_session->chain->name,
+                           l_session->cur_round.id, l_session->cur_round.attempt_num,
+                                l_candidate_hash_str);
+            DAP_DELETE(l_candidate_hash_str);
+            break;
+        }
+
+        if (l_cs_debug) {
+            l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive COMMIT_SIGN: candidate:%s",
+                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                        l_session->cur_round.attempt_num, l_candidate_hash_str);
+        }
+
+        size_t l_offset = dap_chain_block_get_sign_offset(l_store->candidate, l_store->candidate_size);
+        bool l_sign_verified = dap_sign_verify(l_candidate_sign, l_store->candidate,
+                                                l_offset + sizeof(l_store->candidate->hdr)) == 1;
+        // check candidate's sign
+        if (l_sign_verified) {
+            s_message_chain_add(l_session, l_message, a_data_size, a_data_hash);
+            l_store->candidate_signs = dap_list_append(l_store->candidate_signs,
+                                                       DAP_DUP_SIZE(l_candidate_sign, l_candidate_sign_size));
+            if (dap_list_length(l_store->candidate_signs) == l_round->validators_synced_count) {
+                if (PVT(l_session->esbocs)->debug)
+                    log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Candidate:%s collected signs of all synced validators",
+                            l_session->chain->net_name, l_session->chain->name, l_round->id,
+                                l_session->cur_round.attempt_num, l_candidate_hash_str);
+                s_session_state_change(l_session, DAP_CHAIN_ESBOCS_SESSION_STATE_WAIT_FINISH, dap_time_now());
+            }
+        } else {
+            if (!l_candidate_hash_str)
+                l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            log_it(L_WARNING, "Candidate:%s sign is incorrect: code %d", l_candidate_hash_str, l_sign_verified);
+        }
+        DAP_DEL_Z(l_candidate_hash_str);
+    } break;
+
+    case DAP_STREAM_CH_VOTING_MSG_TYPE_PRE_COMMIT: {
+        dap_chain_esbocs_store_t *l_store;
+        char *l_candidate_hash_str = NULL;
+        HASH_FIND(hh, l_session->cur_round.store_items, l_candidate_hash, sizeof(dap_chain_hash_fast_t), l_store);
+        if (!l_store) {
+            l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            log_it(L_WARNING, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu, Receive PRE_COMMIT message for unknown candidate:%s",
+                       l_session->chain->net_name, l_session->chain->name,
+                           l_session->cur_round.id, l_session->cur_round.attempt_num,
+                                l_candidate_hash_str);
+            DAP_DELETE(l_candidate_hash_str);
+            break;
+        }
+
+        dap_hash_fast_t *l_precommit_hash = (dap_hash_fast_t *)l_message_data;
+        if (!dap_hash_fast_compare(l_precommit_hash, &l_store->precommit_candidate_hash)) {
+            if (l_cs_debug) {
+                l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+                char *l_my_precommit_hash_str = dap_chain_hash_fast_to_str_new(&l_store->precommit_candidate_hash);
+                char *l_remote_precommit_hash_str = dap_chain_hash_fast_to_str_new(l_precommit_hash);
+                log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Candidate:%s has different final hash of local and remote validators\n"
+                               "(%s and %s)",
+                            l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                                l_session->cur_round.attempt_num, l_candidate_hash_str,
+                                    l_my_precommit_hash_str, l_remote_precommit_hash_str);
+                DAP_DELETE(l_candidate_hash_str);
+                DAP_DELETE(l_my_precommit_hash_str);
+                DAP_DELETE(l_remote_precommit_hash_str);
+            }
+            break;
+        }
+
+        s_message_chain_add(l_session, l_message, a_data_size, a_data_hash);
+
+        if (l_cs_debug) {
+            l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+            log_it(L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Receive PRE_COMMIT: candidate:%s",
+                    l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                        l_session->cur_round.attempt_num, l_candidate_hash_str);
+        }
+        if (++l_store->precommit_count >= l_cs_level && !l_store->decide_commit &&
+                dap_hash_fast_compare(&l_session->cur_round.attempt_candidate_hash, l_candidate_hash)) {
+            l_store->decide_commit = true;
+            debug_if(l_cs_debug, L_MSG, "ESBOCS: net:%s, chain:%s, round:%"DAP_UINT64_FORMAT_U", attempt:%hu Candidate:%s rejected by more than 2/3 of the validators, remove it",
+                        l_session->chain->net_name, l_session->chain->name, l_session->cur_round.id,
+                            l_session->cur_round.attempt_num, l_candidate_hash_str);
+            s_session_round_finish(l_session, l_store);
+            s_session_round_new(l_session);
+        }
+        DAP_DEL_Z(l_candidate_hash_str);
+    } break;
+    default:
+        break;
+    }
+session_unlock:
+    pthread_rwlock_unlock(&l_session->rwlock);
+}
+
+static void s_message_send(dap_chain_esbocs_session_t *a_session, uint8_t a_message_type, dap_hash_fast_t *a_block_hash,
+                                    const void *a_data, size_t a_data_size, dap_list_t *a_validators)
+{
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_session->chain->net_id);
+    size_t l_message_size = sizeof(dap_chain_esbocs_message_hdr_t) + a_data_size;
+    dap_chain_esbocs_message_t *l_message =
+                        DAP_NEW_Z_SIZE(dap_chain_esbocs_message_t, l_message_size);
+    l_message->hdr.round_id = a_session->cur_round.id;
+    l_message->hdr.attempt_num = a_session->cur_round.attempt_num;
+    l_message->hdr.chain_id = a_session->chain->id;
+    l_message->hdr.ts_created = dap_time_now();
+    l_message->hdr.type = a_message_type;
+    l_message->hdr.message_size = a_data_size;
+    l_message->hdr.candidate_hash = *a_block_hash;
+    if (a_data && a_data_size)
+        memcpy(l_message->msg_n_sign, a_data, a_data_size);
+
+    dap_sign_t *l_sign = dap_sign_create(PVT(a_session->esbocs)->blocks_sign_key, l_message,
+                                         sizeof(l_message->hdr) + a_data_size, 0);
+    size_t l_sign_size = dap_sign_get_size(l_sign);
+    l_message_size += l_sign_size;
+    l_message = DAP_REALLOC(l_message, l_message_size);
+    memcpy(l_message->msg_n_sign + a_data_size, l_sign, l_sign_size);
+    DAP_DELETE(l_sign);
+    l_message->hdr.sign_size = l_sign_size;
+
+    dap_stream_ch_chain_voting_pkt_t *l_voting_pkt = dap_stream_ch_chain_voting_pkt_new(l_net->pub.id.uint64, l_message, l_message_size);
+    DAP_DELETE(l_message);
+
+    for (dap_list_t *it = a_validators; it; it = it->next) {
+        dap_chain_esbocs_validator_t *l_validator = it->data;
+        if (l_validator->is_synced)
+            dap_stream_ch_chain_voting_message_write(l_net, &l_validator->node_addr, l_voting_pkt);
+    }
+    DAP_DELETE(l_voting_pkt);
+}
+
+
+static size_t s_callback_block_sign(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t **a_block_ptr, size_t a_block_size)
+{
+    assert(a_blocks);
+    dap_chain_esbocs_t *l_esbocs = DAP_CHAIN_ESBOCS(a_blocks);
+    dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(l_esbocs);
+    if (!l_esbocs_pvt->blocks_sign_key) {
+        log_it(L_WARNING, "Can't sign block with blocks-sign-cert in [esbocs] section");
+        return 0;
+    }
+    if (!a_block_ptr || !(*a_block_ptr) || !a_block_size) {
+        log_it(L_WARNING, "Block size or block pointer is NULL");
+        return 0;
+    }
+    return dap_chain_block_sign_add(a_block_ptr, a_block_size, l_esbocs_pvt->blocks_sign_key);
+}
+
+static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t *a_block, size_t a_block_size)
+{
+    dap_chain_esbocs_t *l_esbocs = DAP_CHAIN_ESBOCS(a_blocks);
+    dap_chain_esbocs_pvt_t *l_esbocs_pvt = PVT(l_esbocs);
+    if (a_blocks->chain->ledger == NULL) {
+        log_it(L_CRITICAL,"Ledger is NULL can't check consensus conditions on this chain %s", a_blocks->chain->name);
+        return -3;
+    }
+    if (sizeof(a_block->hdr) >= a_block_size) {
+        log_it(L_WARNING,"Incorrect size with block %p on chain %s", a_block, a_blocks->chain->name);
+        return  -7;
+    }
+
+    size_t l_offset = dap_chain_block_get_sign_offset(a_block, a_block_size);
+    size_t l_signs_count = 0;
+    dap_sign_t **l_signs = dap_sign_get_unique_signs(a_block->meta_n_datum_n_sign+l_offset,
+                                            a_block_size-sizeof(a_block->hdr)-l_offset, &l_signs_count);
+    if (!l_signs_count){
+        log_it(L_ERROR, "No any signatures at all for block");
+        DAP_DELETE(l_signs);
+        return -2;
+    }
+
+    if (l_signs_count < l_esbocs_pvt->min_validators_count) {
+        log_it(L_ERROR, "Corrupted block: not enough signs: %zu of %hu", l_signs_count, l_esbocs_pvt->min_validators_count);
+        DAP_DELETE(l_signs);
+        return -1;
+    }
+
+    // Parse the rest signs
+    int l_ret = 0;
+    uint16_t l_signs_verified_count = 0;
+    size_t l_block_excl_sign_size = dap_chain_block_get_sign_offset(a_block, a_block_size)+sizeof(a_block->hdr);
+    for (size_t i=0; i< l_signs_count; i++) {
+        dap_sign_t *l_sign = (dap_sign_t *)l_signs[i];
+        if (!dap_sign_verify_size(l_sign, a_block_size - l_block_excl_sign_size + sizeof(a_block->hdr))) {
+            log_it(L_ERROR, "Corrupted block: sign size is bigger than block size");
+            l_ret = -3;
+            break;
+        }
+
+        dap_chain_addr_t l_signing_addr;
+        dap_chain_addr_fill_from_sign(&l_signing_addr, l_sign, a_blocks->chain->net_id);
+        if (!l_esbocs_pvt->poa_mode) {
+             // Compare signature with delegated keys
+            if (!dap_chain_net_srv_stake_key_delegated(&l_signing_addr))
+                continue;
+        } else {
+            // Compare signature with auth_certs
+            if (!s_validator_check(&l_signing_addr, l_esbocs_pvt->poa_validators))
+                continue;
+        }
+        if (dap_sign_verify(l_sign, a_block, l_block_excl_sign_size) == 1)
+            l_signs_verified_count++;
+    }
+    DAP_DELETE(l_signs);
+    if ( l_ret != 0 ) {
+        return l_ret;
+    }
+    if (l_signs_verified_count < l_esbocs_pvt->min_validators_count) {
+        log_it(L_ERROR, "Corrupted block: not enough signs: %u of %u", l_signs_verified_count, l_esbocs_pvt->min_validators_count);
+        return -1;
+    }
+    return 0;
+}
diff --git a/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h b/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h
new file mode 100644
index 0000000000000000000000000000000000000000..b0828c54b0b77691898c4ffd0c93ef2bd377a393
--- /dev/null
+++ b/modules/consensus/esbocs/include/dap_chain_cs_esbocs.h
@@ -0,0 +1,133 @@
+#include "dap_timerfd.h"
+#include "dap_chain.h"
+#include "dap_chain_block.h"
+#include "dap_chain_cs_blocks.h"
+#include "dap_cert.h"
+
+#define DAP_STREAM_CH_VOTING_MSG_TYPE_SUBMIT          0x04
+#define DAP_STREAM_CH_VOTING_MSG_TYPE_APPROVE         0x08
+#define DAP_STREAM_CH_VOTING_MSG_TYPE_REJECT          0x12
+#define DAP_STREAM_CH_VOTING_MSG_TYPE_COMMIT_SIGN     0x16
+//#define DAP_STREAM_CH_VOTING_MSG_TYPE_VOTE            0x20
+//#define DAP_STREAM_CH_VOTING_MSG_TYPE_VOTE_FOR        0x24
+#define DAP_STREAM_CH_VOTING_MSG_TYPE_PRE_COMMIT      0x28
+#define DAP_STREAM_CH_VOTING_MSG_TYPE_START_SYNC      0x32
+
+#define DAP_CHAIN_BLOCKS_SESSION_ROUND_ID_SIZE		8
+#define DAP_CHAIN_BLOCKS_SESSION_MESSAGE_ID_SIZE	8
+
+typedef struct dap_chain_esbocs_session dap_chain_esbocs_session_t;
+
+/* consensus messages
+• Submit(round, candidate, body) — suggest a new block candidate *** candiate body in data section
+• Approve(round, candidate) — a block candidate has passed local validation
+• Reject(round, candidate) — a block candidate has failed local validation
+• CommitSign(round, candidate, signature) — a block candidate has been accepted and signed *** sign in data section
+• Vote(round, candidate) — a vote for a block candidate in this round (even if the current process has another opinion)
+• PreCommit(round, candidate, final_hash) — a preliminary commitment to a block candidate *** candidate with signs hash in data section
+*/
+typedef struct dap_chain_esbocs_message_hdr {
+    uint8_t version;
+    uint8_t padding;
+    uint8_t type;
+    uint8_t attempt_num;
+    uint64_t round_id;
+    uint64_t sign_size;
+    uint64_t message_size;
+    dap_time_t ts_created;
+    dap_chain_net_id_t net_it;
+    dap_chain_id_t chain_id;
+    dap_chain_cell_id_t cell_id;
+    dap_hash_fast_t candidate_hash;
+} DAP_ALIGN_PACKED dap_chain_esbocs_message_hdr_t;
+
+typedef struct dap_chain_esbocs_message {
+    dap_chain_esbocs_message_hdr_t hdr;
+    uint8_t msg_n_sign[];
+} DAP_ALIGN_PACKED dap_chain_esbocs_message_t;
+
+typedef struct dap_chain_esbocs_message_item {
+    dap_hash_fast_t message_hash;
+    dap_chain_esbocs_message_t *message;
+    dap_chain_addr_t signing_addr;
+    UT_hash_handle hh;
+} dap_chain_esbocs_message_item_t;
+
+typedef struct dap_chain_esbocs_sync_item {
+    dap_hash_fast_t last_block_hash;
+    dap_list_t *messages;
+    UT_hash_handle hh;
+} dap_chain_esbocs_sync_item_t;
+
+typedef struct dap_chain_esbocs_store {
+    dap_hash_fast_t candidate_hash;
+    dap_hash_fast_t precommit_candidate_hash;
+    dap_chain_block_t *candidate;
+    size_t candidate_size;
+    dap_list_t *candidate_signs;
+    uint16_t approve_count;
+    uint16_t reject_count;
+    uint16_t precommit_count;
+    bool decide_reject;
+    bool decide_approve;
+    bool decide_commit;
+    UT_hash_handle hh;
+} dap_chain_esbocs_store_t;
+
+typedef struct dap_chain_esbocs {
+    dap_chain_t *chain;
+    dap_chain_cs_blocks_t *blocks;
+    dap_chain_esbocs_session_t *session;
+    void *_pvt;
+} dap_chain_esbocs_t;
+
+typedef struct dap_chain_esbocs_round {
+    // Base fields
+    uint64_t id;
+    uint8_t attempt_num;
+    dap_hash_fast_t last_block_hash;
+    // Round ancillary
+    dap_chain_esbocs_store_t *store_items;
+    dap_chain_esbocs_message_item_t *message_items;
+    // Attempt dependent fields
+    dap_chain_addr_t attempt_submit_validator;
+    dap_hash_fast_t attempt_candidate_hash;
+    // Validators section
+    uint16_t validators_synced_count;
+    dap_list_t *validators_list;
+} dap_chain_esbocs_round_t;
+
+typedef struct dap_chain_esbocs_validator {
+    dap_chain_node_addr_t node_addr;
+    dap_chain_addr_t signing_addr;
+    uint256_t weight;
+    bool is_synced;
+    bool is_chosen;
+} dap_chain_esbocs_validator_t;
+
+typedef struct dap_chain_esbocs_session {
+    pthread_rwlock_t rwlock;
+
+    dap_chain_t *chain;
+    dap_chain_esbocs_t *esbocs;
+
+    dap_chain_node_addr_t my_addr;
+    uint8_t state; // session state
+    dap_chain_esbocs_round_t cur_round;
+
+    dap_time_t ts_round_sync_start; // time of start sync
+    dap_time_t ts_attempt_start; // time of current attempt start
+
+    dap_chain_esbocs_sync_item_t *sync_items;
+    dap_timerfd_t *sync_timer;
+
+    dap_enc_key_t *blocks_sign_key;
+    dap_chain_addr_t my_signing_addr;
+
+    struct dap_chain_esbocs_session *next;
+    struct dap_chain_esbocs_session *prev;
+} dap_chain_esbocs_session_t;
+
+#define DAP_CHAIN_ESBOCS(a) ((dap_chain_esbocs_t *)(a)->_inheritor)
+int dap_chain_cs_esbocs_init();
+void dap_chain_cs_esbocs_deinit(void);
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 3eb1fdde3c3bdf13c30b07024330ef5c0378c30b..8fe82b923809a865b070c52b119e11c363a244e6 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -5849,6 +5849,71 @@ end:
     return 0;
 }
 
+static char **s_parse_items(const char *a_str, char a_delimiter, int *a_count, const int a_only_digit)
+{
+    int l_count_temp = *a_count = 0;
+    int l_len_str = strlen(a_str);
+    if (l_len_str == 0) return NULL;
+    char *s, *l_temp_str;
+    s = l_temp_str = dap_strdup(a_str);
+
+    int l_buf = 0;
+    for (int i = 0; i < l_len_str; i++) {
+        if (s[i] == a_delimiter && !l_buf) {
+            s[i] = 0;
+            continue;
+        }
+        if (s[i] == a_delimiter && l_buf) {
+            s[i] = 0;
+            l_buf = 0;
+            continue;
+        }
+        if (!dap_is_alpha(s[i]) && l_buf) {
+            s[i] = 0;
+            l_buf = 0;
+            continue;
+        }
+        if (!dap_is_alpha(s[i]) && !l_buf) {
+            s[i] = 0;
+            continue;
+        }
+        if (a_only_digit) {
+            if (dap_is_digit(s[i])) {
+                l_buf++;
+                if (l_buf == 1) l_count_temp++;
+                continue;
+            }
+        } else if (dap_is_alpha(s[i])) {
+            l_buf++;
+            if (l_buf == 1) l_count_temp++;
+            continue;
+        }
+        if (!dap_is_alpha(s[i])) {
+            l_buf = 0;
+            s[i] = 0;
+            continue;
+        }
+    }
+
+    s = l_temp_str;
+    if (l_count_temp == 0) {
+        DAP_FREE(l_temp_str);
+        return NULL;
+    }
+
+    char **lines = DAP_CALLOC(l_count_temp, sizeof (void *));
+    for (int i = 0; i < l_count_temp; i++) {
+        while (*s == 0) s++;
+        lines[i] = strdup(s);
+        s = strchr(s, '\0');
+        s++;
+    }
+
+    DAP_FREE(l_temp_str);
+    *a_count = l_count_temp;
+    return lines;
+}
+
 static int s_get_key_from_file(const char *a_file, const char *a_mime, const char *a_cert_name, dap_sign_t **a_sign)
 {
     char **l_items_mime = NULL;
@@ -5858,7 +5923,7 @@ static int s_get_key_from_file(const char *a_file, const char *a_mime, const cha
 
 
     if (a_mime) {
-        l_items_mime = dap_parse_items(a_mime, ',', &l_items_mime_count, 0);
+        l_items_mime = s_parse_items(a_mime, ',', &l_items_mime_count, 0);
     }
 
     if (l_items_mime && l_items_mime_count > 0) {
diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c
index e8c4e591510e73b3aae5d8a31eaf5b9c15f6de9e..9259bdc35b3ec799232f7110be07084b58c3a32d 100644
--- a/modules/net/dap_chain_node_client.c
+++ b/modules/net/dap_chain_node_client.c
@@ -622,7 +622,7 @@ static void s_ch_chain_callback_notify_packet_R(dap_stream_ch_chain_net_srv_t* a
     case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE: {
             dap_stream_ch_chain_net_srv_pkt_test_t *l_request = (dap_stream_ch_chain_net_srv_pkt_test_t *) a_pkt->data;
             size_t l_request_size = l_request->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t);
-            if(a_pkt->hdr.size != l_request_size) {
+            if(a_pkt->hdr.data_size != l_request_size) {
                 log_it(L_WARNING, "Wrong request size, less or more than required");
                 break;
             }
@@ -697,7 +697,7 @@ dap_chain_node_client_t *dap_chain_node_client_create(dap_chain_net_t *a_net,
 }
 
 
- void s_client_delete_callback(UNUSED_ATTR dap_client_t *a_client, void *a_arg)
+ void s_client_delete_callback(UNUSED_ARG dap_client_t *a_client, void *a_arg)
  {
      assert(a_arg);
      dap_chain_node_client_close_unsafe(a_arg);
@@ -797,7 +797,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_ATTR dap_worker_t *a_worker, void *a_arg)
+void s_close_on_worker_callback(UNUSED_ARG dap_worker_t *a_worker, void *a_arg)
 {
     assert(a_arg);
     dap_chain_node_client_close_unsafe(a_arg);
diff --git a/modules/net/include/dap_chain_node.h b/modules/net/include/dap_chain_node.h
index aa9f8f90688a0ea23ae148bc70760efd76eb1beb..a545a6d2f3530a5666ed5c94b3559cf8f45d71e1 100644
--- a/modules/net/include/dap_chain_node.h
+++ b/modules/net/include/dap_chain_node.h
@@ -82,8 +82,7 @@ typedef struct dap_chain_node_decl{
     } accept_info;
 } DAP_ALIGN_PACKED dap_chain_node_decl_t;
 
-typedef struct dap_chain_node_info
-{
+typedef struct dap_chain_node_info {
     struct {
         dap_chain_node_addr_t address;
         dap_chain_cell_id_t cell_id;
diff --git a/modules/net/srv/dap_chain_net_srv_client.c b/modules/net/srv/dap_chain_net_srv_client.c
index 6f0cb58542fb9b6b9304a426eb8c297b01d4b36d..90259de8c283a9acb95c40e29b25ef05e653c6ad 100644
--- a/modules/net/srv/dap_chain_net_srv_client.c
+++ b/modules/net/srv/dap_chain_net_srv_client.c
@@ -112,8 +112,8 @@ static void s_srv_client_pkt_in(dap_stream_ch_chain_net_srv_t *a_ch_chain, uint8
     case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_CHECK_RESPONSE: {
         dap_stream_ch_chain_net_srv_pkt_test_t *l_response = (dap_stream_ch_chain_net_srv_pkt_test_t *)a_pkt->data;
         size_t l_response_size = l_response->data_size + sizeof(dap_stream_ch_chain_net_srv_pkt_test_t);
-        if (a_pkt->hdr.size != l_response_size) {
-            log_it(L_WARNING, "Wrong response size %u, required %zu", a_pkt->hdr.size, l_response_size);
+        if (a_pkt->hdr.data_size != l_response_size) {
+            log_it(L_WARNING, "Wrong response size %u, required %zu", a_pkt->hdr.data_size, l_response_size);
             if (l_srv_client->callbacks.error)
                 l_srv_client->callbacks.error(l_srv_client,
                                               DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_WRONG_SIZE,
@@ -136,8 +136,8 @@ static void s_srv_client_pkt_in(dap_stream_ch_chain_net_srv_t *a_ch_chain, uint8
     case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_SIGN_REQUEST: {
         log_it(L_NOTICE, "Requested receipt to sign");
         dap_chain_datum_tx_receipt_t *l_receipt = (dap_chain_datum_tx_receipt_t *)a_pkt->data;
-        if (a_pkt->hdr.size != l_receipt->size) {
-            log_it(L_WARNING, "Wrong response size %u, required %"DAP_UINT64_FORMAT_U, a_pkt->hdr.size, l_receipt->size);
+        if (a_pkt->hdr.data_size != l_receipt->size) {
+            log_it(L_WARNING, "Wrong response size %u, required %"DAP_UINT64_FORMAT_U, a_pkt->hdr.data_size, l_receipt->size);
             if (l_srv_client->callbacks.error)
                 l_srv_client->callbacks.error(l_srv_client,
                                               DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR_CODE_WRONG_SIZE,
@@ -161,19 +161,19 @@ static void s_srv_client_pkt_in(dap_stream_ch_chain_net_srv_t *a_ch_chain, uint8
     case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_SUCCESS: {
         log_it( L_NOTICE, "Responsed with success");
         dap_stream_ch_chain_net_srv_pkt_success_t *l_success = (dap_stream_ch_chain_net_srv_pkt_success_t *)a_pkt->data;
-        size_t l_success_size = a_pkt->hdr.size;
+        size_t l_success_size = a_pkt->hdr.data_size;
         if (l_srv_client->callbacks.success) {
             l_srv_client->callbacks.success(l_srv_client, l_success, l_success_size, l_srv_client->callbacks_arg);
         }
     } break;
     case DAP_STREAM_CH_CHAIN_NET_SRV_PKT_TYPE_RESPONSE_ERROR: {
-       if (a_pkt->hdr.size == sizeof (dap_stream_ch_chain_net_srv_pkt_error_t)) {
+       if (a_pkt->hdr.data_size == sizeof (dap_stream_ch_chain_net_srv_pkt_error_t)) {
             dap_stream_ch_chain_net_srv_pkt_error_t *l_err = (dap_stream_ch_chain_net_srv_pkt_error_t *)a_pkt->data;
             log_it(L_WARNING, "Remote responsed with error code 0x%08X", l_err->code);
             if (l_srv_client->callbacks.error)
                 l_srv_client->callbacks.error(l_srv_client, l_err->code, l_srv_client->callbacks_arg);
         } else {
-            log_it(L_ERROR, "Wrong error response size, %u when expected %zu", a_pkt->hdr.size,
+            log_it(L_ERROR, "Wrong error response size, %u when expected %zu", a_pkt->hdr.data_size,
                    sizeof ( dap_stream_ch_chain_net_srv_pkt_error_t) );
         }
     } break;
diff --git a/modules/service/stake_pos_delegate/CMakeLists.txt b/modules/service/stake_pos_delegate/CMakeLists.txt
index 6cf03e2d8c7c83848a7d2a248738fcf222d5ceb2..958cc783e4de4029bb603949a7e0357647f00cef 100644
--- a/modules/service/stake_pos_delegate/CMakeLists.txt
+++ b/modules/service/stake_pos_delegate/CMakeLists.txt
@@ -9,4 +9,4 @@ add_library(${PROJECT_NAME} STATIC ${DAP_SRV_STAKE_POS_DELEGATE_SRCS} ${DAP_SRV_
 
 target_include_directories(${PROJECT_NAME} INTERFACE .)
 target_include_directories(${PROJECT_NAME} PUBLIC include)
-target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_net dap_chain_net_srv dap_chain_cs_dag_poa dap_chain_cs_block_ton dap_chain_cs_block_poa)
+target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_net dap_chain_net_srv dap_chain_cs_dag_poa dap_chain_cs_block_poa)
diff --git a/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c b/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c
index d6d3315ea14d5fac8d2eec04a47d2fe2433ea342..aa5c65b8a2c06711c7be65d03c4c0c5bdb729a4b 100644
--- a/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c
+++ b/modules/service/stake_pos_delegate/dap_chain_net_srv_stake_pos_delegate.c
@@ -292,6 +292,7 @@ dap_list_t *dap_chain_net_srv_stake_get_validators()
     return l_ret;
 }
 
+
 bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum_t *a_datum)
 {
     if (!s_srv_stake) { // Drop all atoms if stake service inactivated
@@ -615,11 +616,6 @@ dap_chain_net_srv_stake_item_t *s_stake_item_from_order(dap_chain_net_t *a_net,
 static bool s_stake_block_commit(dap_chain_net_t *a_net, dap_list_t *a_tx_hash_list)
 {
     size_t l_all_tx = 0, l_process_tx = 0;
-    // find all stake
-    dap_list_t *l_staker_list0 = dap_chain_net_srv_stake_get_validators();
-    if(!l_staker_list0){
-        return false;
-    }
     // find all certs
     size_t l_auth_certs_count = 0;
     dap_cert_t **l_auth_certs = NULL;
@@ -709,7 +705,7 @@ static bool s_stake_block_commit(dap_chain_net_t *a_net, dap_list_t *a_tx_hash_l
         l_process_tx++;
         a_tx_hash_list = dap_list_next(a_tx_hash_list);
     }
-    dap_list_free_full(l_staker_list0, free);
+
     log_it(L_INFO, "Processed %ld tx from %ld", l_process_tx, l_all_tx);
 
     if(!IS_ZERO_256(l_fee_sum_total)) {
diff --git a/modules/service/vpn/dap_chain_net_srv_vpn.c b/modules/service/vpn/dap_chain_net_srv_vpn.c
index 1c27d9d61c7a5a38a1010ed62fb83c24c421e449..174e3cfa29ba9aac2763089ff85455e278a7690a 100644
--- a/modules/service/vpn/dap_chain_net_srv_vpn.c
+++ b/modules/service/vpn/dap_chain_net_srv_vpn.c
@@ -1452,7 +1452,7 @@ void s_ch_packet_in(dap_stream_ch_t* a_ch, void* a_arg)
     //dap_chain_net_srv_vpn_t * l_srv_vpn =(dap_chain_net_srv_vpn_t *) l_usage->service->_internal;
 
     ch_vpn_pkt_t * l_vpn_pkt = (ch_vpn_pkt_t *) l_pkt->data;
-    size_t l_vpn_pkt_size = l_pkt->hdr.size - sizeof (l_vpn_pkt->header);
+    size_t l_vpn_pkt_size = l_pkt->hdr.data_size - sizeof (l_vpn_pkt->header);
 
     debug_if(s_debug_more, L_INFO, "Got srv_vpn packet with op_code=0x%02x", l_vpn_pkt->header.op_code);
 
diff --git a/modules/service/vpn/dap_chain_net_vpn_client.c b/modules/service/vpn/dap_chain_net_vpn_client.c
index 79388b31622ecb97db2af1edd7f3989a2d1e2580..2481518673392dbc182c73e57728c19b941b54fb 100644
--- a/modules/service/vpn/dap_chain_net_vpn_client.c
+++ b/modules/service/vpn/dap_chain_net_vpn_client.c
@@ -694,9 +694,9 @@ dap_chain_net_vpn_client_status_t dap_chain_net_vpn_client_status(void)
 void dap_chain_net_vpn_client_pkt_in(dap_stream_ch_t* a_ch, dap_stream_ch_pkt_t* a_pkt)
 {
     ch_vpn_pkt_t * l_sf_pkt = (ch_vpn_pkt_t *) a_pkt->data;
-    size_t l_sf_pkt_data_size = a_pkt->hdr.size - sizeof(l_sf_pkt->header);
+    size_t l_sf_pkt_data_size = a_pkt->hdr.data_size - sizeof(l_sf_pkt->header);
 
-    if(!a_pkt->hdr.size) {
+    if(!a_pkt->hdr.data_size) {
         log_it(L_WARNING, "Bad input packet");
         return;
     }
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index e8d19aefd4d6345628429c3ec4171678ba07ee7c..6e2dca0267a7d759a67753f2108f54d2347c3b0b 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -78,16 +78,8 @@ typedef struct dap_chain_cs_blocks_pvt
 
 } dap_chain_cs_blocks_pvt_t;
 
-typedef struct dap_chain_cs_blocks_iter
-{
-    dap_chain_cs_blocks_t * blocks;
-    dap_chain_block_cache_t * cache;
-} dap_chain_cs_blocks_iter_t;
-
 #define PVT(a) ((dap_chain_cs_blocks_pvt_t *)(a)->_pvt )
 
-#define ITER_PVT(a) ((dap_chain_cs_blocks_iter_t *) a->_inheritor )
-
 static int s_cli_parse_cmd_hash(char ** a_argv, int a_arg_index, int a_argc, char **a_str_reply,const char * a_param, dap_chain_hash_fast_t * a_datum_hash);
 static void s_cli_meta_hash_print(  dap_string_t * a_str_tmp, const char * a_meta_title, dap_chain_block_meta_t * a_meta);
 static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply);
@@ -937,9 +929,6 @@ static dap_chain_atom_iter_t *s_callback_atom_iter_create(dap_chain_t *a_chain,
     l_atom_iter->chain = a_chain;
     l_atom_iter->cell_id = a_cell_id;
     l_atom_iter->with_treshold = a_with_treshold;
-    l_atom_iter->_inheritor = DAP_NEW_Z(dap_chain_cs_blocks_iter_t);
-    ITER_PVT(l_atom_iter)->blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
-
     return l_atom_iter;
 }
 
@@ -958,7 +947,7 @@ static dap_chain_atom_iter_t* s_callback_atom_iter_create_from(dap_chain_t * a_c
         dap_chain_atom_iter_t * l_atom_iter = s_callback_atom_iter_create(a_chain, a_chain->cells->id, 0);
         if (l_atom_iter){
             dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
-            l_atom_iter->cur_item = ITER_PVT(l_atom_iter)->cache = dap_chain_block_cs_cache_get_by_hash(l_blocks, &l_atom_hash);
+            l_atom_iter->cur_item = dap_chain_block_cs_cache_get_by_hash(l_blocks, &l_atom_hash);
             l_atom_iter->cur = a_atom;
             l_atom_iter->cur_size = a_atom_size;
             return l_atom_iter;
@@ -979,17 +968,22 @@ static dap_chain_atom_ptr_t s_callback_atom_iter_find_by_hash(dap_chain_atom_ite
                                                               size_t * a_atom_size)
 {
     assert(a_atom_iter);
-    dap_chain_atom_ptr_t l_ret = NULL;
-    pthread_rwlock_rdlock(& PVT(ITER_PVT(a_atom_iter)->blocks)->rwlock );
+    dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(DAP_CHAIN_CS_BLOCKS(a_atom_iter->chain));
+    pthread_rwlock_rdlock(&l_blocks_pvt->rwlock);
     dap_chain_block_cache_t * l_block_cache = NULL;
-    HASH_FIND(hh, PVT(ITER_PVT(a_atom_iter)->blocks)->blocks, a_atom_hash,sizeof (*a_atom_hash), l_block_cache);
+    HASH_FIND(hh, l_blocks_pvt->blocks, a_atom_hash, sizeof(*a_atom_hash), l_block_cache);
+    pthread_rwlock_unlock(&l_blocks_pvt->rwlock);
     a_atom_iter->cur_item = l_block_cache;
-    if (l_block_cache){
-        l_ret = a_atom_iter->cur = l_block_cache->block;
-        *a_atom_size = a_atom_iter->cur_size = l_block_cache->block_size;
+    if (l_block_cache) {
+        a_atom_iter->cur = l_block_cache->block;
+        a_atom_iter->cur_size = l_block_cache->block_size;
+    } else {
+        a_atom_iter->cur = NULL;
+        a_atom_iter->cur_size = 0;
     }
-    pthread_rwlock_unlock(& PVT(ITER_PVT(a_atom_iter)->blocks)->rwlock );
-    return l_ret;
+    if (a_atom_size)
+        *a_atom_size = a_atom_iter->cur_size;
+    return a_atom_iter->cur;
 }
 
 /**
@@ -1041,19 +1035,11 @@ static dap_chain_atom_ptr_t s_callback_atom_iter_get_first( dap_chain_atom_iter_
     dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS(a_atom_iter->chain);
     dap_chain_cs_blocks_pvt_t *l_blocks_pvt = l_blocks ? PVT(l_blocks) : NULL;
     assert(l_blocks_pvt);
-    // a_atom_iter->cur_item = l_blocks_pvt->block_cache_last ;
-    // a_atom_iter->cur = l_blocks_pvt->block_cache_last ?  l_blocks_pvt->block_cache_last->block : NULL  ;
-    // a_atom_iter->cur_size = l_blocks_pvt->block_cache_last ? l_blocks_pvt->block_cache_last->block_size : 0;
-    // a_atom_iter->cur_hash = l_blocks_pvt->block_cache_last ? &l_blocks_pvt->block_cache_last->block_hash : NULL;
-
     a_atom_iter->cur_item = l_blocks_pvt->block_cache_first;
     a_atom_iter->cur = l_blocks_pvt->block_cache_first ?  l_blocks_pvt->block_cache_first->block : NULL;
     a_atom_iter->cur_size = l_blocks_pvt->block_cache_first ? l_blocks_pvt->block_cache_first->block_size : 0;
     a_atom_iter->cur_hash = l_blocks_pvt->block_cache_first ? &l_blocks_pvt->block_cache_first->block_hash : NULL;
 
-//    a_atom_iter->cur =  a_atom_iter->cur ?
-//                (dap_chain_cs_dag_event_t*) PVT (DAP_CHAIN_CS_DAG( a_atom_iter->chain) )->events->event : NULL;
-//    a_atom_iter->cur_item = PVT (DAP_CHAIN_CS_DAG( a_atom_iter->chain) )->events;
     if (a_atom_size)
         *a_atom_size = a_atom_iter->cur_size;
     return a_atom_iter->cur;
@@ -1068,8 +1054,8 @@ static dap_chain_atom_ptr_t s_callback_atom_iter_get_first( dap_chain_atom_iter_
 static dap_chain_atom_ptr_t s_callback_atom_iter_get_next( dap_chain_atom_iter_t * a_atom_iter,size_t *a_atom_size )
 {
     assert(a_atom_iter);
-    // assert(a_atom_size);
     assert(a_atom_iter->cur_item);
+
     dap_chain_block_cache_t * l_cur_cache =(dap_chain_block_cache_t *) a_atom_iter->cur_item;
     a_atom_iter->cur_item = l_cur_cache = l_cur_cache->next;
     if (l_cur_cache){
@@ -1127,23 +1113,33 @@ static dap_chain_atom_ptr_t *s_callback_atom_iter_get_links( dap_chain_atom_iter
  * @param a_lasts_size_ptr
  * @return
  */
-static dap_chain_atom_ptr_t *s_callback_atom_iter_get_lasts( dap_chain_atom_iter_t * a_atom_iter ,size_t *a_links_size, size_t ** a_lasts_size_ptr )
+static dap_chain_atom_ptr_t *s_callback_atom_iter_get_lasts( dap_chain_atom_iter_t *a_atom_iter, size_t *a_links_size, size_t **a_lasts_size_ptr)
 {
     assert(a_atom_iter);
-    assert(a_links_size);
-    assert(a_links_size);
 
-    dap_chain_block_cache_t * l_block_cache_last = PVT(ITER_PVT(a_atom_iter)->blocks)->block_cache_last;
-    if ( l_block_cache_last  ){
-        *a_links_size = 1;
-        *a_lasts_size_ptr = DAP_NEW_Z_SIZE(size_t,sizeof (size_t)*1  );
-        dap_chain_atom_ptr_t * l_ret = DAP_NEW_Z_SIZE(dap_chain_atom_ptr_t, sizeof (dap_chain_atom_ptr_t)*1);
-        (*a_lasts_size_ptr)[0] = l_block_cache_last->block_size;
+    dap_chain_block_cache_t *l_block_cache_last = PVT(DAP_CHAIN_CS_BLOCKS(a_atom_iter->chain))->block_cache_last;
+    if (l_block_cache_last) {
+        a_atom_iter->cur = l_block_cache_last->block;
+        a_atom_iter->cur_size = l_block_cache_last->block_size;
+        a_atom_iter->cur_hash = &l_block_cache_last->block_hash;
+        if (a_links_size)
+            *a_links_size = 1;
+        if (a_lasts_size_ptr) {
+            *a_lasts_size_ptr = DAP_NEW_Z(size_t);
+            (*a_lasts_size_ptr)[0] = l_block_cache_last->block_size;
+        }
+        dap_chain_atom_ptr_t *l_ret = DAP_NEW_Z(dap_chain_atom_ptr_t);
         l_ret[0] = l_block_cache_last->block;
         return l_ret;
-    }else{
-        return NULL;
     }
+    a_atom_iter->cur = NULL;
+    a_atom_iter->cur_size = 0;
+    a_atom_iter->cur_hash = NULL;
+    if (a_links_size)
+        *a_links_size = 0;
+    if (a_lasts_size_ptr)
+        *a_lasts_size_ptr = NULL;
+    return NULL;
 }
 
 /**
@@ -1152,7 +1148,6 @@ static dap_chain_atom_ptr_t *s_callback_atom_iter_get_lasts( dap_chain_atom_iter
  */
 static void s_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_iter )
 {
-    DAP_DELETE( ITER_PVT(a_atom_iter));
     DAP_DELETE(a_atom_iter);
 }
 
diff --git a/modules/type/blocks/include/dap_chain_cs_blocks.h b/modules/type/blocks/include/dap_chain_cs_blocks.h
index fa654cce8118eee0157ee63ab79a4667b97276fe..e244a7925ec63eacd75b283cc12277c9af2de546 100644
--- a/modules/type/blocks/include/dap_chain_cs_blocks.h
+++ b/modules/type/blocks/include/dap_chain_cs_blocks.h
@@ -56,7 +56,7 @@ typedef struct dap_chain_cs_blocks
    void * _inheritor;
 } dap_chain_cs_blocks_t;
 
-#define DAP_CHAIN_CS_BLOCKS(a) ((dap_chain_cs_blocks_t*) a->_inheritor)
+#define DAP_CHAIN_CS_BLOCKS(a) ((dap_chain_cs_blocks_t *)(a)->_inheritor)
 typedef int (*dap_chain_blocks_block_callback_ptr_t)(dap_chain_cs_blocks_t *, dap_chain_block_t *);
 
 int dap_chain_cs_blocks_init();