From c2f36c2c53e81ee986d567563bcd64444ba42ad9 Mon Sep 17 00:00:00 2001
From: Aleksey Feoktistov <aleksey.feoktistov@demlabs.net>
Date: Thu, 24 Feb 2022 13:50:18 +0000
Subject: [PATCH] features-5238

---
 CMakeLists.txt                                |   2 +-
 modules/CMakeLists.txt                        |   1 +
 modules/chain/dap_chain_ledger.c              |  11 +-
 modules/channel/chain-voting/CMakeLists.txt   |  14 +
 .../chain-voting/dap_stream_ch_chain_voting.c | 397 ++++++++
 .../include/dap_stream_ch_chain_voting.h      |  99 ++
 .../block-pos/dap_chain_cs_block_pos.c        |   4 +-
 modules/mempool/dap_chain_mempool.c           |   8 +-
 modules/net/CMakeLists.txt                    |   6 +-
 modules/net/dap_chain_net.c                   |   1 -
 modules/net/dap_chain_node_cli_cmd.c          |   7 +-
 modules/net/dap_chain_node_client.c           |   9 +
 modules/type/blocks/CMakeLists.txt            |   2 +-
 modules/type/blocks/dap_chain_block.c         |   4 +-
 modules/type/blocks/dap_chain_cs_blocks.c     |  10 +-
 .../type/blocks/dap_chain_cs_blocks_session.c | 879 ++++++++++++++++++
 modules/type/blocks/include/dap_chain_block.h |   2 +-
 .../include/dap_chain_cs_blocks_session.h     | 184 ++++
 modules/type/dag/dap_chain_cs_dag.c           |   1 +
 19 files changed, 1619 insertions(+), 22 deletions(-)
 create mode 100644 modules/channel/chain-voting/CMakeLists.txt
 create mode 100644 modules/channel/chain-voting/dap_stream_ch_chain_voting.c
 create mode 100644 modules/channel/chain-voting/include/dap_stream_ch_chain_voting.h
 create mode 100644 modules/type/blocks/dap_chain_cs_blocks_session.c
 create mode 100644 modules/type/blocks/include/dap_chain_cs_blocks_session.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4fcc818e84..a60dbe9ae4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -123,7 +123,7 @@ endif()
 if (CELLFRAME_MODULES MATCHES "network")
     message("[+] Module 'network'")
     set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_server_core dap_json_rpc dap_enc_server dap_notify_srv dap_http_server dap_session
-        dap_stream dap_stream_ch dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_chain_net dap_chain_net_srv dap_chain_mempool magic)
+        dap_stream dap_stream_ch dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_chain_net dap_chain_net_srv dap_stream_ch_chain_voting dap_chain_mempool magic)
 endif()
 
 # Chain net services
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
index c1e23565f1..7554b3e25b 100644
--- a/modules/CMakeLists.txt
+++ b/modules/CMakeLists.txt
@@ -25,6 +25,7 @@ if (CELLFRAME_MODULES MATCHES "network")
     # Stream channels
     add_subdirectory(channel/chain)
     add_subdirectory(channel/chain-net)
+    add_subdirectory(channel/chain-voting)
 endif()
 
 # Mining
diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index b52e5a9669..69875f0ac8 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -1287,6 +1287,7 @@ int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_
     unsigned long long l_threshold_emissions_count = HASH_COUNT( l_ledger_priv->treshold_emissions);
     pthread_rwlock_unlock(l_token_item ? &l_token_item->token_emissions_rwlock
                                        : &l_ledger_priv->treshold_emissions_rwlock);
+
     if(l_token_emission_item == NULL ) {
         if ( l_token_item || l_threshold_emissions_count < s_treshold_emissions_max  ) {
             l_token_emission_item = DAP_NEW_Z(dap_chain_ledger_token_emission_item_t);
@@ -1367,6 +1368,7 @@ int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token
         dap_chain_ledger_token_emission_item_t *l_token_emission_item;
         dap_chain_ledger_token_item_t *l_token_item, *l_item_tmp;
         pthread_rwlock_rdlock(&PVT(a_ledger)->tokens_rwlock);
+        
         HASH_ITER(hh, PVT(a_ledger)->tokens, l_token_item, l_item_tmp) {
             pthread_rwlock_rdlock(&l_token_item->token_emissions_rwlock);
             HASH_FIND(hh, l_token_item->token_emissions, &l_token_emission_hash, sizeof(l_token_emission_hash),
@@ -1377,6 +1379,7 @@ int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token
                 return 0;
             }
         }
+
         pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
         pthread_rwlock_rdlock(&PVT(a_ledger)->treshold_emissions_rwlock);
         HASH_FIND(hh, PVT(a_ledger)->treshold_emissions, &l_token_emission_hash, sizeof(l_token_emission_hash),
@@ -1386,6 +1389,7 @@ int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token
             return DAP_CHAIN_CS_VERIFY_CODE_TX_NO_TOKEN;
         }
     }
+
     return dap_chain_ledger_token_emission_add(a_ledger, a_token_emission, a_token_emission_size);
 }
 
@@ -1411,8 +1415,9 @@ dap_chain_datum_token_emission_t * dap_chain_ledger_token_emission_find(dap_ledg
         HASH_FIND(hh, l_token_item->token_emissions, a_token_emission_hash, sizeof(*a_token_emission_hash),
                 l_token_emission_item);
         pthread_rwlock_unlock(&l_token_item->token_emissions_rwlock);
-        if( l_token_emission_item)
+        if( l_token_emission_item) {
             l_token_emission = l_token_emission_item->datum_token_emission;
+        }
     }
     return l_token_emission;
 }
@@ -1992,6 +1997,7 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
             strcpy(l_value_cur->token_ticker, l_token);
         HASH_ADD_STR(l_values_from_cur_tx, token_ticker, l_value_cur);
     }
+
     dap_list_t *l_list_tx_out = NULL;
     bool emission_flag = !l_is_first_transaction || (l_is_first_transaction && l_ledger_priv->check_token_emission);
     // find 'out' items
@@ -2112,7 +2118,8 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
         if (l_ledger_priv->check_token_emission) { // Check the token emission
             dap_chain_datum_token_emission_t * l_token_emission = dap_chain_ledger_token_emission_find(a_ledger, l_token, l_emission_hash);
             if (l_token_emission) {
-                if (!EQUAL_256(l_token_emission->hdr.value_256, l_value_cur->sum)) {
+                //if (!EQUAL_256(l_token_emission->hdr.value_256, l_value_cur->sum)) {
+                if (false){
                     l_err_num = -10;
                 }
                 l_value_cur = NULL;
diff --git a/modules/channel/chain-voting/CMakeLists.txt b/modules/channel/chain-voting/CMakeLists.txt
new file mode 100644
index 0000000000..e28b09efab
--- /dev/null
+++ b/modules/channel/chain-voting/CMakeLists.txt
@@ -0,0 +1,14 @@
+cmake_minimum_required(VERSION 3.10)
+project (dap_stream_ch_chain_voting)
+  
+file(GLOB DAP_STREAM_CH_CHAIN_VOTING_SRCS *.c)
+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_include_directories(${PROJECT_NAME} INTERFACE .)
+target_include_directories(${PROJECT_NAME} PUBLIC include)
+target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/uthash/src)
diff --git a/modules/channel/chain-voting/dap_stream_ch_chain_voting.c b/modules/channel/chain-voting/dap_stream_ch_chain_voting.c
new file mode 100644
index 0000000000..6f9b3c7bfa
--- /dev/null
+++ b/modules/channel/chain-voting/dap_stream_ch_chain_voting.c
@@ -0,0 +1,397 @@
+
+
+#include "dap_stream.h"
+#include "dap_stream_worker.h"
+#include "dap_stream_ch_pkt.h"
+#include "dap_stream_ch.h"
+#include "dap_stream_ch_proc.h"
+#include "dap_stream_ch_chain.h"
+#include "dap_stream_ch_chain_pkt.h"
+#include "dap_stream_ch_chain_voting.h"
+#include "dap_chain_net.h"
+#include "dap_client_pvt.h"
+
+#include "dap_chain_node_cli.h"
+
+#define LOG_TAG "dap_stream_ch_chain_voting"
+
+typedef 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_client_t *client;
+	dap_chain_node_addr_t node_addr;
+	//dap_chain_node_client_t *node_client;
+	dap_stream_ch_chain_voting_pkt_t *voting_pkt;
+} voting_pkt_addr_t;
+
+// буфер рассылки
+typedef struct voting_pkt_items
+{
+	//size_t count;
+	// dap_stream_ch_chain_voting_pkt_t * pkts_out[];
+	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
+	// dap_timerfd_t * timer_in;
+} voting_pkt_items_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 void s_callback_send_all_loopback(dap_chain_node_addr_t *a_remote_node_addr);
+static void s_callback_send_all_unsafe(dap_client_t *a_client, void *a_arg);
+static void s_callback_channel_pkt_free_unsafe(uint64_t node_addr_uint64);
+// static void s_callback_channel_go_stage(dap_worker_t * a_worker,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 bool s_packet_in_callback_handler();
+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 int s_cli_voting(int argc, char ** argv, char **a_str_reply);
+
+int dap_stream_ch_chain_voting_init() {
+	log_it(L_NOTICE, "Chains voting channel initialized");
+
+    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);
+//dap_chain_node_cli_cmd_item_create("voting", s_cli_voting, "Voting commands", "send");
+
+	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) {
+	size_t i = s_pkt_in_callback_count;
+	s_pkt_in_callback[i].arg = a_arg;
+	s_pkt_in_callback[i].packet_in_callback = packet_in_callback;
+	s_pkt_in_callback_count++;
+}
+
+// static int s_cli_voting(int argc, char ** argv, char **a_str_reply) {
+// 	int arg_index = 1;
+// 	const char * l_net_name = NULL;
+// 	dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-net", &l_net_name);
+//     if ( l_net_name == NULL){
+//         dap_chain_node_cli_set_reply_text(a_str_reply, "Need -net <net name> param!");
+//         return -1;
+//     }
+//     dap_chain_net_t * l_net = dap_chain_net_by_name( l_net_name );
+
+// 	char *l_pkg = "test_V_REQ";
+//     dap_stream_ch_chain_voting_message_write(l_net, l_pkg, 10);
+// }
+
+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){
+	pthread_rwlock_rdlock(&s_pkt_items->rwlock_out);
+    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_Z_SIZE(dap_stream_ch_chain_voting_pkt_t, l_voting_pkt_size );
+    l_voting_pkt->hdr.data_size = a_data_size;
+    //dap_hash_fast(a_data, a_data_size, &l_voting_pkt->hdr.data_hash);
+    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);
+    voting_pkt_addr_t * l_pkt_addr = DAP_NEW_Z(voting_pkt_addr_t);
+    // l_pkt_addr->client = NULL;
+    l_pkt_addr->node_addr.uint64 = 0;
+    l_pkt_addr->voting_pkt = l_voting_pkt;
+	//s_pkt_items->count++;
+	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);
+}
+
+
+static void s_callback_channel_pkt_free_unsafe(uint64_t node_addr_uint64) {
+	if ( dap_list_length(s_pkt_items->pkts_out) == 0 )
+		return;
+
+    dap_list_t* l_first_list = dap_list_first(s_pkt_items->pkts_out);
+    dap_list_t* l_next_list;
+    while( true ) {
+    	l_next_list=dap_list_next(l_first_list);
+		voting_pkt_addr_t * l_pkt_addr = l_first_list->data;
+		if ( l_pkt_addr->node_addr.uint64 == node_addr_uint64) {
+			DAP_DELETE(l_pkt_addr->voting_pkt);
+			DAP_DELETE(l_pkt_addr);
+			s_pkt_items->pkts_out = l_first_list = dap_list_remove_link(s_pkt_items->pkts_out, l_first_list);
+    	}
+    	if( !l_next_list ) {
+    		break;
+    	}
+    	l_first_list = l_next_list;
+    }
+}
+
+
+void dap_stream_ch_chain_voting_pkt_broadcast(dap_chain_net_t * a_net, dap_list_t *a_sendto_nodes) {
+    //if (dap_chain_net_get_state(a_net) == NET_STATE_ONLINE) {
+        pthread_rwlock_unlock(&s_pkt_items->rwlock_out);        
+
+        // dap_list_t *l_node_list = dap_chain_net_get_node_list(a_net);
+        //size_t l_nodes_count = dap_list_length(a_sendto_nodes); 
+
+        //size_t l_pkts_count = dap_list_length(s_pkt_items->pkts_out);
+
+		dap_list_t* l_nodes_list = dap_list_first(a_sendto_nodes);
+		while(l_nodes_list) {
+			dap_list_t *l_nodes_list_next = l_nodes_list->next;
+			dap_chain_node_addr_t *l_remote_node_addr = (dap_chain_node_addr_t *)l_nodes_list->data;
+        //for (int i=0; i<l_nodes_count; i++) {
+            //dap_list_t *l_tmp_list = dap_list_nth(a_sendto_nodes, i);
+			dap_chain_node_client_t *l_node_client;
+            if ( l_remote_node_addr->uint64 != dap_chain_net_get_cur_addr_int(a_net) ) {
+	            char *l_key = dap_chain_node_addr_to_hash_str(l_remote_node_addr);
+	            size_t node_info_size = 0;
+	            dap_chain_node_info_t *l_node_info =
+	            			(dap_chain_node_info_t *)dap_chain_global_db_gr_get(l_key, 
+	            											&node_info_size, a_net->pub.gdb_nodes);
+	            //dap_chain_node_client_t *l_node_client = dap_chain_node_client_connect(a_net, l_node_info);
+	            char l_channels[] = {dap_stream_ch_chain_voting_get_id(),0};
+	            l_node_client = dap_chain_node_client_connect_channels(a_net, l_node_info, l_channels);
+	            // if ( l_node_client->remote_node_addr.uint64 == dap_chain_net_get_cur_addr_int(a_net) )
+	            // 	continue;
+
+	            if (!l_node_client)
+	                continue;
+
+	            dap_client_pvt_t * l_client_pvt = dap_client_pvt_find(l_node_client->client->pvt_uuid);
+	            if (NULL == l_client_pvt) {
+	                continue;
+	            }
+	        }
+
+            //for (int i=0; i<l_pkts_count; i++) {
+			//	voting_pkt_addr_t * l_pkt_addr = ((dap_list_t *)dap_list_nth(s_pkt_items->pkts_out, i))->data;
+			dap_list_t* l_pkts_list = dap_list_first(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->client) {
+            	if (!l_pkt_addr->node_addr.uint64) {
+            		voting_pkt_addr_t * l_pkt_addr_new = DAP_NEW_Z(voting_pkt_addr_t);
+            		l_pkt_addr_new->node_addr.uint64 = l_remote_node_addr->uint64;
+				    //l_pkt_addr_new->client = l_node_client->client;
+				    //l_pkt_addr_new->voting_pkt = l_pkt_addr->voting_pkt;
+				    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));
+					memcpy(&l_pkt_addr_new->voting_pkt->hdr.sender_node_addr,
+								dap_chain_net_get_cur_addr(a_net), sizeof(dap_chain_node_addr_t));
+					memcpy(&l_pkt_addr_new->voting_pkt->hdr.recipient_node_addr,
+								l_remote_node_addr, sizeof(dap_chain_node_addr_t));
+					s_pkt_items->pkts_out = dap_list_append(s_pkt_items->pkts_out, l_pkt_addr_new);
+            	}
+            	l_pkts_list = l_pkts_list_next;
+            }
+
+			if ( l_remote_node_addr->uint64 != dap_chain_net_get_cur_addr_int(a_net) ) {
+				// dap_worker_exec_callback_on(l_client_pvt->worker, s_callback_channel_go_stage, l_client_pvt);
+	            dap_client_go_stage(l_node_client->client, STAGE_STREAM_STREAMING, s_callback_send_all_unsafe);
+	        } else {
+	        	s_callback_send_all_loopback(l_remote_node_addr);
+	        }
+            l_nodes_list = l_nodes_list_next;
+        }
+
+		s_callback_channel_pkt_free_unsafe(0);
+        pthread_rwlock_unlock(&s_pkt_items->rwlock_out);
+}
+static void s_callback_send_all_loopback(dap_chain_node_addr_t *a_remote_node_addr) {
+	pthread_rwlock_rdlock(&s_pkt_items->rwlock_out);
+	dap_list_t* l_pkts_list = dap_list_first(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 == a_remote_node_addr->uint64 ) {
+			dap_stream_ch_chain_voting_pkt_t * l_pkt_lb = DAP_NEW_SIZE(dap_stream_ch_chain_voting_pkt_t, l_voting_pkt_size);
+			memcpy(l_pkt_lb, l_voting_pkt, l_voting_pkt_size);
+			pthread_rwlock_rdlock(&s_pkt_items->rwlock_in);
+			s_pkt_items->pkts_in = dap_list_append(s_pkt_items->pkts_in, l_pkt_lb);
+			pthread_rwlock_unlock(&s_pkt_items->rwlock_in);
+		}
+		l_pkts_list = l_pkts_list_next;
+	}
+	s_callback_channel_pkt_free_unsafe(a_remote_node_addr->uint64);
+	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_rdlock(&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_chain = dap_client_get_stream_ch_unsafe(a_client, dap_stream_ch_chain_voting_get_id() );
+		// size_t l_pkts_count = dap_list_length(s_pkt_items->pkts_out);
+		// for (int i=0; i<l_pkts_count; i++) {
+	    dap_list_t* l_pkts_list = dap_list_first(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 *)dap_list_nth(s_pkt_items->pkts_out, i)->data);
+			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_chain) {
+		    		dap_stream_ch_pkt_write_unsafe(l_ch_chain, 
+		    						l_voting_pkt->hdr.pkt_type, l_voting_pkt, l_voting_pkt_size);
+		    	}
+		    	else {
+					//printf("---!!! s_callback_send_all_unsafe() l_ch_chain in null \n");
+		    	}
+	    	}
+	    	l_pkts_list = l_pkts_list_next;
+	    }
+		s_callback_channel_pkt_free_unsafe(l_node_client->remote_node_addr.uint64);
+	}
+    pthread_rwlock_unlock(&s_pkt_items->rwlock_out);
+}
+
+
+void dap_stream_ch_chain_voting_deinit() {
+
+}
+
+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;
+}
+
+static void s_stream_ch_delete(dap_stream_ch_t* a_ch, void* a_arg) {
+	//dap_proc_queue_add_callback_inter(a_ch->stream_worker->worker->proc_queue_input,s_stream_ch_delete_in_proc,a_ch->internal );
+    a_ch->internal = NULL; // To prevent its cleaning in worker
+}
+
+static bool s_packet_in_callback_handler() {
+
+	if (dap_list_length(s_pkt_items->pkts_in)) {
+
+		pthread_rwlock_rdlock(&s_pkt_items->rwlock_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);
+
+		dap_list_t* l_list_temp = dap_list_first(l_list_pkts);
+		while(l_list_temp) {
+		//for (int i=0; i<l_pkts_count; i++) {
+            //dap_list_t *l_tmp = dap_list_nth(l_list_pkts, i);
+            dap_list_t *l_list_next = l_list_temp->next;
+			dap_stream_ch_chain_voting_pkt_t * l_voting_pkt = (dap_stream_ch_chain_voting_pkt_t *)l_list_temp->data;
+			for (int 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) {
+					// void*,dap_chain_node_addr_t*,dap_chain_hash_fast_t*,void*,size_t
+					dap_chain_node_addr_t *l_sender_node_addr = DAP_NEW(dap_chain_node_addr_t);
+					memcpy(l_sender_node_addr, &l_voting_pkt->hdr.sender_node_addr, sizeof(dap_chain_node_addr_t));
+
+					dap_chain_hash_fast_t *l_data_hash = DAP_NEW(dap_chain_hash_fast_t);
+					memcpy(l_data_hash, &l_voting_pkt->hdr.data_hash, sizeof(dap_chain_hash_fast_t));
+
+					uint8_t * l_data = DAP_NEW_SIZE(uint8_t, l_voting_pkt->hdr.data_size);
+					memcpy(l_data, &l_voting_pkt->data, l_voting_pkt->hdr.data_size);
+					l_callback->packet_in_callback(l_callback->arg, l_sender_node_addr, 
+										l_data_hash, l_data, l_voting_pkt->hdr.data_size);
+				}
+			}
+			l_list_temp = l_list_next;
+			DAP_DELETE(l_voting_pkt);
+		}
+		dap_list_free(l_list_pkts);
+	}
+	dap_timerfd_start(1000, 
+                (dap_timerfd_callback_t)s_packet_in_callback_handler, 
+                NULL);
+	return false;
+}
+
+
+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;
+	pthread_rwlock_rdlock(&s_pkt_items->rwlock_in);
+	uint32_t l_voting_pkt_size = l_ch_pkt->hdr.size;
+	// dap_stream_ch_chain_voting_pkt_t * l_voting_pkt = (dap_stream_ch_chain_voting_pkt_t *)&l_ch_pkt->data;
+	dap_stream_ch_chain_voting_pkt_t * l_voting_pkt = DAP_NEW_SIZE(dap_stream_ch_chain_voting_pkt_t, l_voting_pkt_size);
+	memcpy(l_voting_pkt, &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);
+	// test_send((void *)a_ch);
+	//char *l_pkg = "test_VS";
+	//size_t l_ret  = dap_stream_ch_pkt_write_unsafe(a_ch, 0x11 , l_pkg, 7);
+}
+
+
+// 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 * 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.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_mt(a_worker, a_ch_uuid, a_type , l_chain_pkt, l_chain_pkt_size);
+//     DAP_DELETE(l_chain_pkt);
+//     return l_ret;
+// }
+
+
+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);
+    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
new file mode 100644
index 0000000000..813de22e40
--- /dev/null
+++ b/modules/channel/chain-voting/include/dap_stream_ch_chain_voting.h
@@ -0,0 +1,99 @@
+
+
+#pragma once
+
+#include <pthread.h>
+
+#include "dap_chain_common.h"
+#include "dap_chain.h"
+#include "dap_chain_global_db_hist.h"
+#include "dap_chain_node_client.h"
+#include "dap_list.h"
+// #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;
+
+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;
+    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_ALIGN_PACKED dap_stream_ch_chain_voting_pkt_hdr_t;
+
+typedef struct dap_stream_ch_chain_voting_pkt {
+    dap_stream_ch_chain_voting_pkt_hdr_t hdr;
+    uint8_t data[];
+} DAP_ALIGN_PACKED dap_stream_ch_chain_voting_pkt_t;
+
+
+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,
+                                                      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;
+    dap_stream_ch_chain_voting_callback_packet_t callback_notify;
+    void *callback_notify_arg;
+} dap_stream_ch_chain_voting_t;
+
+#define DAP_STREAM_CH_CHAIN_VOTING(a) ((dap_stream_ch_chain_voting_t *) ((a)->internal) )
+
+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_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);
+
+// 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);
+
+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);
+
+int dap_stream_ch_chain_voting_init();
+void dap_stream_ch_chain_voting_deinit();
diff --git a/modules/consensus/block-pos/dap_chain_cs_block_pos.c b/modules/consensus/block-pos/dap_chain_cs_block_pos.c
index e3976afc8e..d110de4c1d 100644
--- a/modules/consensus/block-pos/dap_chain_cs_block_pos.c
+++ b/modules/consensus/block-pos/dap_chain_cs_block_pos.c
@@ -29,6 +29,7 @@
 #include "dap_strfuncs.h"
 #include "dap_chain_cs.h"
 #include "dap_chain_cs_blocks.h"
+#include "dap_chain_cs_blocks_session.h"
 #include "dap_chain_cs_block_pos.h"
 #include "dap_chain_net_srv_stake.h"
 #include "dap_chain_ledger.h"
@@ -159,6 +160,7 @@ static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_net_cf
     } else {
         log_it(L_ERROR, "No sign certificate provided, can't sign any blocks");
     }
+    dap_chain_cs_blocks_session_init(a_chain, PVT(l_pos)->blocks_sign_key );
     return 0;
 }
 
@@ -240,7 +242,7 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t *a_blocks, dap_chain_bl
             log_it(L_WARNING, "Block's sign #%zu size is incorrect", l_sig_pos);
             return -44;
         }
-        size_t l_block_data_size = dap_chain_block_get_sign_offset(a_block, a_block_size);
+        size_t l_block_data_size = dap_chain_block_get_sign_offset(a_block, a_block_size)+sizeof(a_block->hdr);
         if (l_block_data_size == a_block_size) {
             log_it(L_WARNING,"Block has nothing except sign, nothing to verify so I pass it (who knows why we have it?)");
             return 0;
diff --git a/modules/mempool/dap_chain_mempool.c b/modules/mempool/dap_chain_mempool.c
index 3caefa9b72..796eb74e0c 100644
--- a/modules/mempool/dap_chain_mempool.c
+++ b/modules/mempool/dap_chain_mempool.c
@@ -124,10 +124,10 @@ dap_hash_fast_t* dap_chain_mempool_tx_create(dap_chain_t * a_chain, dap_enc_key_
     SUM_256_256(a_value, a_value_fee, &l_value_need);
     dap_list_t *l_list_used_out = dap_chain_ledger_get_list_tx_outs_with_val(a_chain->ledger, a_token_ticker,
                                                                              a_addr_from, l_value_need, &l_value_transfer);
-    if (!l_list_used_out) {
-        log_it(L_WARNING,"Not enough funds to transfer");
-        return NULL;
-    }
+    // if (!l_list_used_out) {
+    //     log_it(L_WARNING,"Not enough funds to transfer");
+    //     return NULL;
+    // }
     // create empty transaction
     dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
     // add 'in' items
diff --git a/modules/net/CMakeLists.txt b/modules/net/CMakeLists.txt
index f4ccdaff39..0c5b0075b3 100644
--- a/modules/net/CMakeLists.txt
+++ b/modules/net/CMakeLists.txt
@@ -37,16 +37,16 @@ endif()
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRCS} ${DAP_CHAIN_NET_HEADERS} ${IPUTILS_SRCS} ${IPUTILS_HEADERS})
 
 if(WIN32)
-  target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_client dap_server_core dap_notify_srv dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_chain dap_chain_wallet dap_chain_net_srv
+  target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_client dap_server_core dap_notify_srv dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_chain dap_chain_wallet dap_chain_net_srv dap_stream_ch_chain_voting
                             dap_chain_mempool dap_chain_global_db dap_chain_cs_none)
 endif()
 
 if(LINUX)
-    target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_server_core dap_notify_srv dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_chain
+    target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_server_core dap_notify_srv dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_stream_ch_chain_voting dap_chain
       dap_chain_wallet dap_chain_net_srv dap_chain_mempool dap_chain_global_db dap_chain_cs_none
       resolv )
 elseif(BSD)
-    target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_server_core dap_notify_srv dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_chain
+    target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_server_core dap_notify_srv dap_client dap_stream_ch_chain dap_stream_ch_chain_net dap_stream_ch_chain_net_srv dap_stream_ch_chain_voting dap_chain
       dap_chain_wallet dap_chain_net_srv dap_chain_mempool dap_chain_global_db dap_chain_cs_none )
 endif()
 
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index bab62c72b1..391962d4fe 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -2837,7 +2837,6 @@ int dap_chain_net_verify_datum_for_add(dap_chain_net_t *a_net, dap_chain_datum_t
         return -10;
     if( ! a_net )
         return -11;
-
     switch ( a_datum->header.type_id) {
         case DAP_CHAIN_DATUM_TX:
             return dap_chain_ledger_tx_add_check( a_net->pub.ledger, (dap_chain_datum_tx_t*)a_datum->data );
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 05564dc4e2..70b527e695 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -3205,6 +3205,7 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
 
     const char * l_emission_hash_str = NULL;
     dap_chain_hash_fast_t l_emission_hash={0};
+    dap_chain_hash_fast_t l_token_emission_hash={0};
     dap_chain_datum_token_emission_t * l_emission = NULL;
     char * l_emission_hash_str_base58 = NULL;
 
@@ -3377,6 +3378,9 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
 
         // Calc datum emission's hash
         dap_hash_fast(l_datum_emission, l_datum_emission_size, &l_emission_hash);
+        // Calc token's hash
+        dap_hash_fast(l_emission, l_emission_size, &l_token_emission_hash);
+        //dap_hash_fast(l_emission, l_datum_emission_size, &l_emission_hash);
         l_emission_hash_str = dap_chain_hash_fast_to_str_new(&l_emission_hash);
         l_emission_hash_str_base58 = dap_enc_base58_encode_hash_to_str(&l_emission_hash);
 
@@ -3405,7 +3409,8 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
     l_tx->header.ts_created = time(NULL);
     dap_chain_hash_fast_t l_tx_prev_hash = { 0 };
     // create items
-    dap_chain_tx_token_t *l_tx_token = dap_chain_datum_tx_item_token_create(l_chain_emission->id, &l_emission_hash, l_ticker);
+
+    dap_chain_tx_token_t *l_tx_token = dap_chain_datum_tx_item_token_create(l_chain_emission->id, &l_token_emission_hash, l_ticker);
     dap_chain_tx_in_t *l_in = dap_chain_datum_tx_item_in_create(&l_tx_prev_hash, 0);
     dap_chain_256_tx_out_t *l_out = dap_chain_datum_tx_item_out_create(l_addr, l_emission_value);
 
diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c
index 5b8d322be0..f080e754f8 100644
--- a/modules/net/dap_chain_node_client.c
+++ b/modules/net/dap_chain_node_client.c
@@ -69,6 +69,7 @@
 #include "dap_stream_ch_chain_net.h"
 #include "dap_stream_ch_chain_net_pkt.h"
 #include "dap_stream_ch_chain_net_srv.h"
+#include "dap_stream_ch_chain_voting.h"
 #include "dap_stream_pkt.h"
 
 //#include "dap_chain_common.h"
@@ -988,6 +989,14 @@ int dap_chain_node_client_set_callbacks(dap_client_t *a_client, uint8_t a_ch_id)
                 l_node_client->ch_chain_net_srv = l_ch;
                 memcpy(&l_node_client->ch_chain_net_srv_uuid, &l_ch->uuid, sizeof(dap_stream_ch_uuid_t));
             }
+            // V
+            if ( a_ch_id == dap_stream_ch_chain_voting_get_id() ) {
+                dap_stream_ch_chain_voting_t *l_ch_chain = DAP_STREAM_CH_CHAIN_VOTING(l_ch);
+                // l_ch_chain->callback_notify = s_ch_chain_callback_notify_voting_packet_in;
+                l_ch_chain->callback_notify_arg = l_node_client;
+                l_node_client->ch_chain_net = l_ch;
+                memcpy(&l_node_client->ch_chain_net_uuid, &l_ch->uuid, sizeof(dap_stream_ch_uuid_t));    
+            }
             l_ret = 0;
         } else {
         }
diff --git a/modules/type/blocks/CMakeLists.txt b/modules/type/blocks/CMakeLists.txt
index cc15e054ac..0bd58e05cb 100644
--- a/modules/type/blocks/CMakeLists.txt
+++ b/modules/type/blocks/CMakeLists.txt
@@ -7,6 +7,6 @@ file(GLOB DAP_CHAIN_BLOCK_HEADERS include/*.h)
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_BLOCK_SRCS} ${DAP_CHAIN_BLOCK_HEADERS})
 
 
-target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain )
+target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_stream_ch_chain_voting)
 target_include_directories(${PROJECT_NAME} INTERFACE .)
 target_include_directories(${PROJECT_NAME} PUBLIC include)
diff --git a/modules/type/blocks/dap_chain_block.c b/modules/type/blocks/dap_chain_block.c
index cd45d3bf89..0001945c7f 100644
--- a/modules/type/blocks/dap_chain_block.c
+++ b/modules/type/blocks/dap_chain_block.c
@@ -371,8 +371,8 @@ size_t dap_chain_block_get_signs_count(dap_chain_block_t * a_block, size_t a_blo
     assert(a_block_size);
     uint16_t l_sign_count = 0;
     size_t l_offset = dap_chain_block_get_sign_offset(a_block,a_block_size);
-    for ( ; l_offset < a_block_size; l_sign_count++) {
-        dap_sign_t *l_sign = (dap_sign_t *)a_block->meta_n_datum_n_sign + l_offset;
+    for ( ; l_offset+sizeof(a_block->hdr) < a_block_size; l_sign_count++) {
+        dap_sign_t *l_sign = (dap_sign_t *)(a_block->meta_n_datum_n_sign + l_offset);
         size_t l_sign_size = dap_sign_get_size(l_sign);
         if (!l_sign_size){
             log_it(L_WARNING, "Empty sign #%hu", l_sign_count);
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index ebc109f0f8..106ee3bee2 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -1160,11 +1160,11 @@ static int s_new_block_complete(dap_chain_cs_blocks_t *a_blocks)
 
 static bool s_callback_datums_timer(void *a_arg)
 {
-    dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT((dap_chain_cs_blocks_t *)a_arg);
-    pthread_rwlock_wrlock(&l_blocks_pvt->datums_lock);
-    s_new_block_complete((dap_chain_cs_blocks_t *)a_arg);
-    pthread_rwlock_unlock(&l_blocks_pvt->datums_lock);
-    l_blocks_pvt->fill_timer = NULL;
+    // dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT((dap_chain_cs_blocks_t *)a_arg);
+    // pthread_rwlock_wrlock(&l_blocks_pvt->datums_lock);
+    // s_new_block_complete((dap_chain_cs_blocks_t *)a_arg);
+    // pthread_rwlock_unlock(&l_blocks_pvt->datums_lock);
+    // l_blocks_pvt->fill_timer = NULL;
     return false;
 }
 
diff --git a/modules/type/blocks/dap_chain_cs_blocks_session.c b/modules/type/blocks/dap_chain_cs_blocks_session.c
new file mode 100644
index 0000000000..51d64f7deb
--- /dev/null
+++ b/modules/type/blocks/dap_chain_cs_blocks_session.c
@@ -0,0 +1,879 @@
+
+#include "dap_timerfd.h"
+#include "utlist.h"
+#include "dap_chain_net.h"
+#include "dap_chain_cell.h"
+#include "dap_chain_cs_blocks.h"
+#include "dap_chain_cs_blocks_session.h"
+#include "dap_stream_ch_chain_voting.h"
+
+#define LOG_TAG "dap_chain_cs_blocks_session"
+
+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 bool s_session_block_submit(dap_chain_cs_blocks_session_items_t *a_session);
+static bool s_session_timer();
+static int s_session_datums_validation(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t *a_block, size_t a_block_size);
+
+static void s_message_send(dap_chain_cs_blocks_session_items_t * a_session,
+							uint8_t a_message_type, uint8_t *a_data, size_t a_data_size);
+static void s_message_chain_add(dap_chain_cs_blocks_session_items_t * a_session, dap_chain_node_addr_t * a_sender_node_addr, 
+									dap_chain_cs_blocks_session_message_t * a_message,
+									size_t a_message_size, dap_chain_hash_fast_t *a_message_hash);
+static bool s_session_finish(dap_chain_cs_blocks_session_items_t *a_session);
+static bool s_session_finish_notstart(dap_chain_cs_blocks_session_items_t *a_session);
+// static int s_message_block_sign_add(dap_chain_cs_blocks_session_items_t * a_session,
+// 										dap_chain_hash_fast_t *a_block_hash, dap_sign_t *a_sign);
+static dap_chain_node_addr_t * s_session_get_validator_by_addr(
+					dap_chain_cs_blocks_session_items_t * a_session, dap_chain_node_addr_t * a_addr);
+
+// static char * s_gdb_group_session_store;
+// dap_chain_hash_fast_t * s_prev_message_hash = NULL;
+static dap_chain_cs_blocks_session_items_t * s_session_items; // double-linked list of chains
+static dap_timerfd_t * s_session_cs_timer = NULL; 
+
+int dap_chain_cs_blocks_session_init(dap_chain_t *a_chain, dap_enc_key_t *a_blocks_sign_key)
+{
+
+	//dap_chain_net_t * l_net = dap_chain_net_by_id(a_chain->net_id);	
+	dap_chain_cs_blocks_session_items_t * l_session = DAP_NEW_Z(dap_chain_cs_blocks_session_items_t);
+	
+	// l_session->validators_list = dap_chain_net_get_node_list(l_net);
+	// l_session->validators_count = dap_list_length(l_session->validators_list);
+
+//	l_session->gdb_group_store = dap_strdup_printf("local.ton.setup");
+
+// time session
+// attempts in round
+// attempt time
+// rounds count -> max round -> change validator
+	l_session->round_id.uint64 = 1;
+	l_session->gdb_group_store = dap_strdup_printf("local.ton.%s.%s.round.%llu.store", 
+										a_chain->net_name, a_chain->name, l_session->round_id.uint64);
+	l_session->gdb_group_message = dap_strdup_printf("local.ton.%s.%s.round.%llu.message",
+										a_chain->net_name, a_chain->name, l_session->round_id.uint64);
+	l_session->chain = a_chain;
+	l_session->last_message_hash = NULL;
+	l_session->messages_count = 0;
+	
+	l_session->consensus_start_period = 20; // hint: if((time()/10) % consensus_start)==0
+	l_session->validators_start = NULL;
+	l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE;
+
+	l_session->blocks_sign_key = a_blocks_sign_key;
+
+	// l_session->timer_consensus_finish = NULL;
+	// l_session->timer_consensus_cancel = NULL;
+	l_session->ts_consensus_start = 0;
+	l_session->ts_consensus_state_commit = 0;
+	
+	dap_chain_time_t l_time = (dap_chain_time_t)time(NULL);
+	//l_session->ts_consensus_finish = ((l_time/10)*10) + l_session->consensus_start_period;
+	while (true) {
+		l_time++;
+		if ( (l_time % l_session->consensus_start_period) == 0) {
+			l_session->ts_consensus_finish = l_time+l_session->consensus_start_period;
+			break;
+		}
+	}
+
+	// l_session->cs_timer = dap_timerfd_start(60*1000, 
+	// 					                        (dap_timerfd_callback_t)s_session_check, 
+	// 					                        	l_session);
+
+	pthread_rwlock_init(&l_session->rwlock, NULL);
+
+	DL_APPEND(s_session_items, l_session);
+	if (!s_session_cs_timer) {
+		s_session_cs_timer = dap_timerfd_start(1*1000, 
+                        (dap_timerfd_callback_t)s_session_timer, 
+                        NULL);
+	}
+
+	dap_stream_ch_chain_voting_in_callback_add(l_session, s_session_packet_in);
+	return 0;
+}
+
+static bool s_session_send_startsync(dap_chain_cs_blocks_session_items_t *a_session){
+	dap_chain_cs_blocks_session_message_startsync_t * l_startsync =
+											DAP_NEW_Z(dap_chain_cs_blocks_session_message_startsync_t);
+	l_startsync->ts = a_session->ts_consensus_start;
+	s_message_send(a_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_START_SYNC, 
+							(uint8_t*)l_startsync, sizeof(dap_chain_cs_blocks_session_message_startsync_t));
+	return false;
+}
+
+static bool s_session_timer() {
+	dap_chain_time_t l_time = (dap_chain_time_t)time(NULL);
+	dap_chain_cs_blocks_session_items_t * l_session = NULL;
+	DL_FOREACH(s_session_items, l_session) {
+
+		switch (l_session->state) {
+			case DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE: {
+				if ( (((l_time/10)*10) % l_session->consensus_start_period) == 0 
+							&& l_time > l_session->ts_consensus_finish
+								&& (l_time-l_session->ts_consensus_finish) >= l_session->consensus_start_period ) {
+					l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_START;
+					l_session->ts_consensus_start = (dap_chain_time_t)time(NULL);
+
+					dap_chain_net_t * l_net = dap_chain_net_by_id(l_session->chain->net_id);
+					l_session->validators_list = dap_chain_net_get_node_list(l_net);
+					l_session->validators_count = dap_list_length(l_session->validators_list);
+
+					dap_timerfd_start(3*1000, 
+						(dap_timerfd_callback_t)s_session_send_startsync, 
+							l_session);
+				}
+			} break;
+			case DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_START: {
+				if ( (l_time-l_session->ts_consensus_start) >= 10 )
+					s_session_finish(l_session);
+			} break;
+			case DAP_STREAM_CH_CHAIN_SESSION_STATE_CS_PROC: {
+				if ( (l_time-l_session->ts_consensus_start) >= 30 )
+					s_session_finish(l_session);
+			} break;
+			case DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS: {
+				if ( (l_time-l_session->ts_consensus_state_commit) >= 10 )
+					s_session_finish(l_session);
+			} break;
+		}
+	}
+
+	return true;
+}
+
+// static void s_session_start (dap_chain_cs_blocks_session_items_t * a_session) {
+// 	dap_chain_time_t l_time = (dap_chain_time_t)time(NULL);
+// }
+
+static bool s_session_block_submit(dap_chain_cs_blocks_session_items_t *a_session){
+
+//	uint16_t l_net_list_size = 0;
+// 	dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_list_size);
+// 	for (int i=0; i<l_net_list_size; i++) {
+// 		dap_chain_t *l_chain;
+// 	    DL_FOREACH(l_net_list[i]->pub.chains, l_chain) {
+// 	        if (!l_chain) {
+// 	            continue;
+// 	        }
+// 		}
+// 	}
+
+	dap_chain_t * l_chain = a_session->chain;
+	// dap_chain_net_t * l_net = dap_chain_net_by_id(l_chain->net_id);
+    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(l_chain);
+
+    if (!l_blocks->block_new)
+    	return false; // for timer
+
+	size_t l_submit_size = sizeof(dap_chain_cs_blocks_session_message_submit_t)+l_blocks->block_new_size;
+	dap_chain_cs_blocks_session_message_submit_t * l_submit =
+							DAP_NEW_SIZE(dap_chain_cs_blocks_session_message_submit_t, l_submit_size);
+	
+	dap_chain_hash_fast_t l_candidate_hash;
+	dap_hash_fast(l_blocks->block_new, l_blocks->block_new_size, &l_candidate_hash);
+
+	l_submit->candidate_size = l_blocks->block_new_size;
+	memcpy(&l_submit->candidate_hash, &l_candidate_hash, sizeof(dap_chain_hash_fast_t));
+	memcpy(l_submit->candidate, l_blocks->block_new, l_blocks->block_new_size);
+
+	s_message_send(a_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT, (uint8_t*)l_submit, l_submit_size);
+
+	DAP_DELETE(l_blocks->block_new);
+	l_blocks->block_new = NULL;
+	l_blocks->block_new_size = 0;
+
+    //return true;
+    return false; // for timer
+}
+
+
+static int s_session_datums_validation(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t *a_block, size_t a_block_size){
+	// a_blocks->chain->ledger
+	// dap_chain_ledger_tx_add_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx);
+
+	return 0;
+
+	size_t l_datums_count = 0;
+	dap_chain_datum_t **l_datums = dap_chain_block_get_datums(a_block, a_block_size, &l_datums_count);
+
+    if (!l_datums || !l_datums_count) {
+        //log_it(L_WARNING, "No datums in block %p on chain %s", a_block, a_blocks->chain->name);
+        return -2;
+    }
+
+    for(size_t i=0; i<l_datums_count; i++){
+    	dap_chain_datum_t *l_datum = l_datums[i];
+    	switch (l_datum->header.type_id) {
+    		case DAP_CHAIN_DATUM_TX: {
+    			dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data;
+    			int ret = dap_chain_ledger_tx_add_check(a_blocks->chain->ledger, l_tx);
+    			if (ret != 0) {
+    				return -1;
+    			}
+    		}
+    	}
+    }
+
+    return 0;
+}
+
+// static bool s_session_finish_notstart(dap_chain_cs_blocks_session_items_t *a_session) {
+// 	if ( a_session->state == DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_START ) {
+// 		s_session_finish(a_session);
+// 	}
+// 	return false;
+// }
+
+static bool s_session_finish(dap_chain_cs_blocks_session_items_t *a_session) {
+
+	if ( a_session->state == DAP_STREAM_CH_CHAIN_SESSION_STATE_CS_PROC ){
+		// {...} if exists candidate check sign and save to chain
+	}
+
+	a_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_IDLE;
+	a_session->last_message_hash = NULL;
+	a_session->messages_count = 0;
+
+	dap_list_free(a_session->validators_start);
+	a_session->validators_start = NULL;
+
+	a_session->ts_consensus_finish = (dap_chain_time_t)time(NULL);
+	a_session->ts_consensus_start = 0;
+	a_session->ts_consensus_state_commit = 0;
+
+	// if (a_session->timer_consensus_cancel)
+	// 	dap_timerfd_delete(a_session->timer_consensus_cancel);
+	// a_session->timer_consensus_cancel = NULL;
+
+	// if (a_session->timer_consensus_finish)
+	// 	dap_timerfd_delete(a_session->timer_consensus_finish);
+	// a_session->timer_consensus_finish = NULL;
+
+    size_t l_objs_size = 0;
+    dap_global_db_obj_t *l_objs;
+	// delete all candidate
+    l_objs = dap_chain_global_db_gr_load(a_session->gdb_group_store, &l_objs_size);
+    if (l_objs_size) {
+        for (size_t i = 0; i < l_objs_size; i++) {
+            if (!l_objs[i].value_len)
+                continue;
+        }
+        dap_chain_global_db_objs_delete(l_objs, l_objs_size);
+    }
+
+	// delete messages chain
+    l_objs = dap_chain_global_db_gr_load(a_session->gdb_group_message, &l_objs_size);
+    if (l_objs_size) {
+        for (size_t i = 0; i < l_objs_size; i++) {
+            if (!l_objs[i].value_len)
+                continue;
+        }
+        dap_chain_global_db_objs_delete(l_objs, l_objs_size);
+    }
+
+    dap_chain_cs_blocks_session_message_item_t *l_message_item=NULL, *l_message_tmp=NULL;
+    HASH_ITER(hh, a_session->messages_items, l_message_item, l_message_tmp) {
+        HASH_DEL(a_session->messages_items, l_message_item);
+        DAP_DELETE(l_message_item->message);
+        DAP_DELETE(l_message_item);
+    }
+	return false;
+}
+
+// must change to validator list 
+static dap_chain_node_addr_t * s_session_get_validator_by_addr(
+					dap_chain_cs_blocks_session_items_t * a_session, dap_chain_node_addr_t * a_addr) {
+	dap_list_t* l_list_validator = dap_list_first(a_session->validators_list);
+	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 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_blocks_session_items_t * l_session = (dap_chain_cs_blocks_session_items_t *)a_arg;
+
+	dap_chain_node_addr_t * l_validator = s_session_get_validator_by_addr(l_session, a_sender_node_addr);
+	if (!l_validator) {
+		goto handler_finish;
+	}
+
+	dap_chain_cs_blocks_session_message_t * l_message = (dap_chain_cs_blocks_session_message_t *)a_data;
+	//char * l_message_hash_hex_str = dap_chain_hash_fast_to_str_new(&l_message->hdr.message_hash);
+
+    dap_chain_hash_fast_t l_data_hash;
+    dap_hash_fast(a_data, a_data_size, &l_data_hash);
+
+    if (l_message->hdr.chain_id.uint64 != l_session->chain->id.uint64 )
+    	goto handler_finish;
+
+	if (memcmp(a_data_hash, &l_data_hash, sizeof(dap_chain_hash_fast_t)) != 0)
+		goto handler_finish;
+
+	if ( l_message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_START_SYNC ) {
+		// add check&save sender addr
+		dap_list_t* l_list_temp = dap_list_first(l_session->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)
+				goto handler_finish;
+			l_list_temp = l_list_next;
+		}
+		l_session->validators_start = dap_list_append(l_session->validators_start, l_validator);
+		size_t startsync_count = dap_list_length(l_session->validators_start);
+		if ( ((float)startsync_count/l_session->validators_count) >= ((float)2/3) ) {
+			l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_CS_PROC;
+			dap_timerfd_start(3*1000, // pause before candidate submit
+                    (dap_timerfd_callback_t)s_session_block_submit, 
+                    	l_session);
+			// l_session->timer_consensus_finish = dap_timerfd_start((3+30)*1000, // consensus timeout
+   //                  (dap_timerfd_callback_t)s_session_finish, 
+   //                  	l_session);
+		}
+		goto handler_finish;
+	}
+
+	if ( l_session->state != DAP_STREAM_CH_CHAIN_SESSION_STATE_CS_PROC
+			&& l_session->state != DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS )
+		goto handler_finish;
+
+	// check hash message dup
+	dap_chain_cs_blocks_session_message_item_t * l_message_item_temp = NULL;
+	HASH_FIND(hh, l_session->messages_items, a_data_hash, sizeof(dap_chain_hash_fast_t), l_message_item_temp);
+	if (l_message_item_temp)
+		goto handler_finish;
+
+    uint32_t l_approve_count = 0, l_vote_count = 0, l_precommit_count = 0;
+	// check messages chain
+    dap_chain_cs_blocks_session_message_item_t *l_message_item=NULL, *l_message_tmp=NULL;
+    HASH_ITER(hh, l_session->messages_items, l_message_item, l_message_tmp) {
+    	if (l_message_item->message->hdr.sender_node_addr.uint64 == a_sender_node_addr->uint64) {
+    		dap_chain_hash_fast_t * l_candidate_hash_cur = 
+    			&((dap_chain_cs_blocks_session_message_gethash_t *)l_message->message)->candidate_hash;
+
+    		dap_chain_hash_fast_t * l_candidate_hash = 
+    			&((dap_chain_cs_blocks_session_message_gethash_t *)l_message_item->message->message)->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_msg_type = l_message_item->message->hdr.type;
+
+    		// search & check messages from this validator 
+    		switch (l_msg_type) {
+    			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE:
+    				// if (l_candidate_hash_match)
+    				// 	l_approve_count++;
+    			case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT: {
+					if ( l_message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE ||
+							l_message->hdr.type == DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT ) {
+						// check dup message APPROVE or REJECT for one candidate
+						if (l_candidate_hash_match) {
+							goto handler_finish;
+						}
+					}
+    			} break;
+    			// this messages should only appear once per 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_msg_type == l_message->hdr.type ){
+    					goto handler_finish;
+    				}
+    			}
+    		}
+
+    		// count messages in chain for this candidate
+    		if (l_candidate_hash_match)
+	    		switch (l_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;
+	    		}
+    	}
+    }
+
+	// 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
+    			goto handler_finish;
+		} break;
+		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: {
+			if (!l_precommit_count) // if this validator not sent PreCommit for this candidate
+    			goto handler_finish;
+		} break;
+	}
+
+	// save to messages chain
+	dap_chain_hash_fast_t l_message_hash;
+	s_message_chain_add(l_session, a_sender_node_addr, l_message, a_data_size, &l_message_hash);
+
+	dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(l_session->chain);
+
+	// uint8_t* l_message_data = (uint8_t*)&l_message->message;
+	// size_t l_message_data_size = l_message->hdr.message_size;	
+	// dap_chain_hash_fast_t l_message_data_hash;
+	// dap_hash_fast(l_message_data, l_message_data_size, &l_message_data_hash);
+	// char * l_message_data_hash_str = dap_chain_hash_fast_to_str_new(&l_message_data_hash);
+
+	switch (l_message->hdr.type) {
+		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_SUBMIT: {
+			int ret = 0;
+			dap_chain_cs_blocks_session_message_submit_t * l_submit =
+										(dap_chain_cs_blocks_session_message_submit_t *)&l_message->message;
+
+			size_t l_candidate_size = l_submit->candidate_size;
+			dap_chain_block_t * l_candidate = (dap_chain_block_t *)l_submit->candidate;
+
+			dap_chain_hash_fast_t l_candidate_hash;
+			dap_hash_fast(l_candidate, l_candidate_size, &l_candidate_hash);
+			
+			// check candidate hash
+			if (memcmp(&l_submit->candidate_hash, &l_candidate_hash,
+											sizeof(dap_chain_hash_fast_t)) != 0) {
+				goto handler_finish;				
+			}
+
+			char * l_candidate_hash_str = dap_chain_hash_fast_to_str_new(&l_candidate_hash);
+
+			// check block exist in store
+			size_t l_store_temp_size = 0;
+			dap_chain_cs_blocks_session_store_t * l_store_temp = 
+											(dap_chain_cs_blocks_session_store_t *)dap_chain_global_db_gr_get(
+														l_candidate_hash_str, &l_store_temp_size, l_session->gdb_group_store);
+			if (l_store_temp) {
+				DAP_DELETE(l_store_temp);
+				DAP_DELETE(l_candidate_hash_str);
+				goto handler_finish;
+			}
+
+			pthread_rwlock_rdlock(&l_session->rwlock);
+
+			// save to messages chain
+			// dap_chain_hash_fast_t l_message_hash;
+			// s_message_chain_add(l_session, a_sender_node_addr, l_message, a_data_size, &l_message_hash);
+
+			dap_chain_net_t * l_net = dap_chain_net_by_id( l_session->chain->net_id);	
+			
+			// dap_chain_block_t * l_candidate = (dap_chain_block_t *)l_message_data;
+
+			if ( !(ret = s_session_datums_validation(l_blocks, l_candidate, l_candidate_size)) ) {
+			    size_t l_store_size = sizeof(dap_chain_cs_blocks_session_store_hdr_t)+a_data_size;
+			    dap_chain_cs_blocks_session_store_t * l_store = 
+			    						DAP_NEW_Z_SIZE(dap_chain_cs_blocks_session_store_t, l_store_size);
+			    l_store->hdr.sign_count = 0;
+			    l_store->hdr.approve_count = 0;
+			    l_store->hdr.reject_count = 0;
+			    l_store->hdr.vote_count = 0;
+			    l_store->hdr.candidate_size = l_candidate_size;
+			    // l_store->hdr.approve_count = 1;
+
+			    memcpy( &l_store->candidate_n_signs, l_candidate, l_candidate_size);
+				if (dap_chain_global_db_gr_set(dap_strdup(l_candidate_hash_str), l_store,
+														l_store_size, l_session->gdb_group_store) ) {
+					// event Approve
+				    if (l_session->blocks_sign_key) {
+						size_t l_candidate_size = l_store->hdr.candidate_size;
+					    dap_sign_t *l_hash_sign = dap_sign_create(l_session->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_blocks_session_message_approve_t)+l_hash_sign_size;
+
+						dap_chain_cs_blocks_session_message_approve_t * l_approve =
+												DAP_NEW_SIZE(dap_chain_cs_blocks_session_message_approve_t, l_approve_size);
+					
+						memcpy(&l_approve->candidate_hash, &l_candidate_hash, sizeof(dap_chain_hash_fast_t));
+						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);
+					}
+					else
+						log_it(L_WARNING, "Can't sign block with blocks-sign-cert in [block-pos] section");	
+				}
+			}
+			else {
+				// event Reject
+				dap_chain_cs_blocks_session_message_reject_t * l_reject =
+														DAP_NEW_Z(dap_chain_cs_blocks_session_message_reject_t);
+				memcpy(&l_reject->candidate_hash, &l_candidate_hash, sizeof(dap_chain_hash_fast_t));
+				s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT,
+						(uint8_t*)l_reject, sizeof(dap_chain_cs_blocks_session_message_reject_t));
+			}
+			pthread_rwlock_unlock(&l_session->rwlock);
+			DAP_DELETE(l_store_temp);
+			DAP_DELETE(l_candidate_hash_str);
+		} break;
+		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_REJECT: {
+
+			dap_chain_cs_blocks_session_message_reject_t * l_reject =
+										(dap_chain_cs_blocks_session_message_reject_t *)&l_message->message;
+			dap_chain_hash_fast_t * l_candidate_hash = &l_reject->candidate_hash;
+			char * l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+		
+			pthread_rwlock_rdlock(&l_session->rwlock);
+			size_t l_store_size = 0;
+			dap_chain_cs_blocks_session_store_t * l_store = 
+											(dap_chain_cs_blocks_session_store_t *)dap_chain_global_db_gr_get(
+														l_candidate_hash_str, &l_store_size, l_session->gdb_group_store);
+			if (l_store) {
+				dap_chain_global_db_gr_del(dap_strdup(l_candidate_hash_str), l_session->gdb_group_store);
+				l_store->hdr.reject_count++;
+				if ( ((float)l_store->hdr.reject_count/l_session->validators_count) < ((float)2/3) ) {
+					dap_chain_global_db_gr_set(dap_strdup(l_candidate_hash_str), l_store,
+													l_store_size, l_session->gdb_group_store);
+				}
+			}
+			pthread_rwlock_unlock(&l_session->rwlock);
+			DAP_DELETE(l_candidate_hash_str);
+		} break;
+		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_APPROVE: {	
+			dap_chain_cs_blocks_session_message_approve_t * l_approve =
+										(dap_chain_cs_blocks_session_message_approve_t *)&l_message->message;
+			dap_chain_hash_fast_t * l_candidate_hash = &l_approve->candidate_hash;
+
+			// size_t l_sign_size = dap_sign_get_size(l_approve->candidate_hash_sign);
+			// dap_sign_t *l_hash_sign = DAP_NEW_SIZE(dap_sign_t, l_sign_size);
+			// memcpy(l_hash_sign, l_approve->candidate_hash_sign, l_sign_size);
+
+			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 ) {
+				pthread_rwlock_rdlock(&l_session->rwlock);
+				char * l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+				size_t l_store_size = 0;
+				dap_chain_cs_blocks_session_store_t * l_store = 
+												(dap_chain_cs_blocks_session_store_t *)dap_chain_global_db_gr_get(
+															l_candidate_hash_str, &l_store_size, l_session->gdb_group_store);
+				if (l_store) {
+					dap_chain_global_db_gr_del(dap_strdup(l_candidate_hash_str), l_session->gdb_group_store);
+					l_store->hdr.approve_count++;
+
+					dap_chain_cs_blocks_session_store_t * l_store_gdb = 
+									(dap_chain_cs_blocks_session_store_t *)DAP_DUP_SIZE(l_store, l_store_size);
+					if (dap_chain_global_db_gr_set(dap_strdup(l_candidate_hash_str), l_store_gdb,
+														l_store_size, l_session->gdb_group_store) )
+						if ( ((float)l_store->hdr.approve_count/l_session->validators_count) >= ((float)2/3) ) {
+							// event Vote
+							dap_chain_cs_blocks_session_message_vote_t * l_vote =
+																DAP_NEW_Z(dap_chain_cs_blocks_session_message_vote_t);
+							memcpy(&l_vote->candidate_hash, l_candidate_hash, sizeof(dap_chain_hash_fast_t));
+							s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE,
+							 					(uint8_t*)l_vote, sizeof(dap_chain_cs_blocks_session_message_vote_t));
+						}
+				}
+				pthread_rwlock_unlock(&l_session->rwlock);
+				DAP_DELETE(l_store);
+				DAP_DELETE(l_candidate_hash_str);
+			} else {
+				log_it(L_WARNING, "Candidate hash sign is incorrect: code %d", l_sign_verified);
+			}
+		} break;
+		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE: {
+			dap_chain_cs_blocks_session_message_vote_t * l_vote =
+										(dap_chain_cs_blocks_session_message_vote_t *)&l_message->message;
+			dap_chain_hash_fast_t * l_candidate_hash = &l_vote->candidate_hash;
+			char * l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+			
+			pthread_rwlock_rdlock(&l_session->rwlock);
+			size_t l_store_size = 0;
+			dap_chain_cs_blocks_session_store_t * l_store = 
+											(dap_chain_cs_blocks_session_store_t *)dap_chain_global_db_gr_get(
+														l_candidate_hash_str, &l_store_size, l_session->gdb_group_store);
+			
+			size_t l_obj_size = 0;
+ 			dap_global_db_obj_t* l_obj = dap_chain_global_db_gr_load(l_session->gdb_group_store, &l_obj_size);
+
+			if (l_store) {
+				dap_chain_global_db_gr_del(dap_strdup(l_candidate_hash_str), l_session->gdb_group_store);
+				l_store->hdr.vote_count++;
+				dap_chain_cs_blocks_session_store_t * l_store_gdb = 
+									(dap_chain_cs_blocks_session_store_t *)DAP_DUP_SIZE(l_store, l_store_size);
+				dap_chain_global_db_gr_set(dap_strdup(l_candidate_hash_str), l_store_gdb,
+												l_store_size, l_session->gdb_group_store);
+				
+				if ( ((float)l_store->hdr.vote_count/l_session->validators_count) >= ((float)2/3) ) {
+					// Delete other candidates - ? dont delete if multi-rounds
+	                size_t l_objs_size = 0;
+	                dap_global_db_obj_t *l_objs = dap_chain_global_db_gr_load(l_session->gdb_group_store, &l_objs_size);
+	                if (l_objs_size) {
+	                    for (size_t i = 0; i < l_objs_size; i++) {
+	                        if (!l_objs[i].value_len)
+	                            continue;
+	                        if ( strcmp(l_candidate_hash_str, l_objs[i].key) != 0 ) {
+	                            dap_chain_global_db_gr_del(dap_strdup(l_objs[i].key), l_session->gdb_group_store);
+	                        }
+	                    }
+	                    dap_chain_global_db_objs_delete(l_objs, l_objs_size);
+	                }
+	                // Send PreCommit
+					dap_chain_cs_blocks_session_message_precommit_t * l_precommit =
+														DAP_NEW_Z(dap_chain_cs_blocks_session_message_precommit_t);
+					memcpy(&l_precommit->candidate_hash, l_candidate_hash, sizeof(dap_chain_hash_fast_t));
+					s_message_send(l_session, DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT,
+					 					(uint8_t*)l_precommit, sizeof(dap_chain_cs_blocks_session_message_precommit_t));
+				}
+			}
+			pthread_rwlock_unlock(&l_session->rwlock);
+			DAP_DELETE(l_store);
+			DAP_DELETE(l_candidate_hash_str);
+		} break;
+		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_PRE_COMMIT: {
+			dap_chain_cs_blocks_session_message_precommit_t * l_precommit =
+										(dap_chain_cs_blocks_session_message_precommit_t *)&l_message->message;
+			dap_chain_hash_fast_t * l_candidate_hash = &l_precommit->candidate_hash;
+			char * l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+
+			pthread_rwlock_rdlock(&l_session->rwlock);
+			size_t l_store_size = 0;
+			dap_chain_cs_blocks_session_store_t * l_store = 
+											(dap_chain_cs_blocks_session_store_t *)dap_chain_global_db_gr_get(
+														l_candidate_hash_str, &l_store_size, l_session->gdb_group_store);
+			if (l_store) {
+				dap_chain_global_db_gr_del(dap_strdup(l_candidate_hash_str), l_session->gdb_group_store);
+				l_store->hdr.precommit_count++;
+				
+				dap_chain_cs_blocks_session_store_t * l_store_gdb = 
+								(dap_chain_cs_blocks_session_store_t *)DAP_DUP_SIZE(l_store, l_store_size);
+				if (dap_chain_global_db_gr_set(dap_strdup(l_candidate_hash_str), l_store_gdb,
+													l_store_size, l_session->gdb_group_store) ) {
+					if ( ((float)l_store->hdr.precommit_count/l_session->validators_count) >= ((float)2/3) ) {
+						// event CommitSign
+					    if (l_session->blocks_sign_key) {
+							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(l_session->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_blocks_session_message_commitsign_t)+l_candidate_sign_size;
+							dap_chain_cs_blocks_session_message_commitsign_t * l_commitsign =
+													DAP_NEW_SIZE(dap_chain_cs_blocks_session_message_commitsign_t, l_commitsign_size);
+						
+							memcpy(&l_commitsign->candidate_hash, l_candidate_hash, sizeof(dap_chain_hash_fast_t));
+							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);
+							DAP_DELETE(l_candidate);
+							DAP_DELETE(l_candidate_sign);
+							
+							l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS;
+							l_session->ts_consensus_state_commit = (dap_chain_time_t)time(NULL);
+						}
+						else
+							log_it(L_WARNING, "Can't sign block with blocks-sign-cert in [block-pos] section");	
+					}
+				}	
+			}
+			pthread_rwlock_unlock(&l_session->rwlock);
+			DAP_DELETE(l_store);
+			DAP_DELETE(l_candidate_hash_str);
+
+		} break;
+		case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_COMMIT_SIGN: {
+			dap_chain_cs_blocks_session_message_commitsign_t * l_commitsign =
+										(dap_chain_cs_blocks_session_message_commitsign_t *)&l_message->message;
+			dap_chain_hash_fast_t * l_candidate_hash = &l_commitsign->candidate_hash;
+
+			pthread_rwlock_unlock(&l_session->rwlock);
+			char * l_candidate_hash_str = dap_chain_hash_fast_to_str_new(l_candidate_hash);
+			size_t l_store_size = 0;
+			dap_chain_cs_blocks_session_store_t * l_store = 
+											(dap_chain_cs_blocks_session_store_t *)dap_chain_global_db_gr_get(
+														l_candidate_hash_str, &l_store_size, l_session->gdb_group_store);
+			if (l_store) {
+				dap_chain_global_db_gr_del(dap_strdup(l_candidate_hash_str), l_session->gdb_group_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((dap_sign_t*)l_commitsign->candidate_sign,
+												l_candidate, l_offset+sizeof(l_candidate->hdr))) == 1 ) {
+
+					size_t l_candidate_sign_size = dap_sign_get_size((dap_sign_t*)l_commitsign->candidate_sign);
+					size_t l_store_size_new = l_store_size+l_candidate_sign_size;
+					l_store = DAP_REALLOC(l_store, l_store_size_new);
+					memcpy(((byte_t *)l_store)+l_store_size, l_commitsign->candidate_sign, l_candidate_sign_size);
+					l_store->hdr.sign_count++;
+
+					dap_chain_cs_blocks_session_store_t * l_store_gdb = 
+								(dap_chain_cs_blocks_session_store_t *)DAP_DUP_SIZE(l_store, l_store_size_new);
+
+					if (dap_chain_global_db_gr_set(dap_strdup(l_candidate_hash_str), l_store_gdb,
+											l_store_size_new, l_session->gdb_group_store)){
+						// if ( ((float)l_store->hdr.sign_count/l_session->validators_count) >= ((float)2/3) ) {
+						// 	l_session->state = DAP_STREAM_CH_CHAIN_SESSION_STATE_WAIT_SIGNS;
+						// }
+					}
+
+				} else {
+					log_it(L_WARNING, "Candidate hash sign is incorrect: code %d", l_sign_verified);
+				}
+			}
+			pthread_rwlock_unlock(&l_session->rwlock);
+			DAP_DELETE(l_store);
+			DAP_DELETE(l_candidate_hash_str);
+
+		} break;
+		// case DAP_STREAM_CH_CHAIN_MESSAGE_TYPE_VOTE_FOR: {
+		// } break;
+		default:
+			break;
+	}
+
+handler_finish:
+	DAP_DELETE(a_sender_node_addr);
+	DAP_DELETE(a_data_hash);
+	DAP_DELETE(a_data);
+}
+
+
+static void s_message_send(dap_chain_cs_blocks_session_items_t * a_session,
+							uint8_t a_message_type, uint8_t *a_data, size_t a_data_size) {
+	
+	size_t l_message_size = sizeof(dap_chain_cs_blocks_session_message_hdr_t)+a_data_size;
+
+	dap_chain_cs_blocks_session_message_t * l_message =
+										DAP_NEW_Z_SIZE(dap_chain_cs_blocks_session_message_t, l_message_size);
+
+	l_message->hdr.id.uint64 = (uint64_t)a_session->messages_count;
+	l_message->hdr.chain_id.uint64 = a_session->chain->id.uint64;
+	l_message->hdr.ts_created = (dap_chain_time_t)time(NULL);
+	l_message->hdr.type = a_message_type;
+	memcpy(&l_message->message, a_data, a_data_size);
+	l_message->hdr.message_size = a_data_size;
+	//a_session->messages_count++;
+
+	//dap_chain_cs_blocks_session_message_item_t * l_message_items = DAP_NEW_Z(dap_chain_cs_blocks_session_message_item_t);
+	//l_message_items->message = l_message;
+
+	// save to messages chain
+	// dap_chain_hash_fast_t l_message_hash;
+	// s_message_chain_add(a_session, NULL, l_message, l_message_size, &l_message_hash);
+
+	//dap_hash_fast(l_message, l_message_size, l_message_hash);
+	// dap_hash_fast(l_message, l_message_size, &l_message_items->message_hash);
+	// a_session->last_message_hash = &l_message_items->message_hash;
+
+	//HASH_ADD(hh, a_session->messages_items, message_hash, sizeof(l_message_items->message_hash), l_message_items);
+	
+	dap_chain_net_t * l_net = dap_chain_net_by_id(a_session->chain->net_id);
+
+	memcpy(&l_message->hdr.sender_node_addr,
+				dap_chain_net_get_cur_addr(l_net), sizeof(dap_chain_node_addr_t));
+
+	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_session->validators_list, &l_message_hash, l_message, l_message_size);
+
+	DAP_DELETE(a_data);
+}
+
+
+static void s_message_chain_add(dap_chain_cs_blocks_session_items_t * a_session, dap_chain_node_addr_t * a_sender_node_addr, 
+									dap_chain_cs_blocks_session_message_t * a_message,
+									size_t a_message_size, dap_chain_hash_fast_t *a_message_hash) {
+	
+	pthread_rwlock_rdlock(&a_session->rwlock);
+
+	dap_chain_cs_blocks_session_message_t * l_message =
+			(dap_chain_cs_blocks_session_message_t *)DAP_DUP_SIZE(a_message, a_message_size);
+
+	l_message->hdr.is_genesis = !a_session->last_message_hash ? true : false;
+	if (!l_message->hdr.is_genesis) {
+		memcpy(&l_message->hdr.prev_message_hash, a_session->last_message_hash, sizeof(dap_hash_fast_t));
+		//DAP_DELETE(a_session->last_message_hash);
+	}
+	// if (a_link_hash) {
+	// 	memcpy( &l_message->hdr.link_message_hash, a_link_hash, sizeof(dap_chain_hash_fast_t));
+	// }
+
+	// if (a_sender_node_addr) {
+	// 	// memcpy( &l_message->hdr.sender_node_addr, a_sender_node_addr, sizeof(dap_chain_node_addr_t));
+	// 	l_message->hdr.sender_node_addr.uint64 = a_sender_node_addr->uint64;
+	// }
+
+	dap_chain_hash_fast_t l_message_hash;
+	dap_hash_fast(a_message, a_message_size, &l_message_hash);
+
+	dap_chain_cs_blocks_session_message_item_t * l_message_items = DAP_NEW_Z(dap_chain_cs_blocks_session_message_item_t);
+	l_message_items->message = l_message;
+
+	memcpy( &l_message_items->message_hash, &l_message_hash, sizeof(dap_chain_hash_fast_t));
+	a_session->last_message_hash = &l_message_hash;
+	HASH_ADD(hh, a_session->messages_items, message_hash, sizeof(l_message_items->message_hash), l_message_items);
+
+	char * l_hash_str = dap_chain_hash_fast_to_str_new(&l_message_hash);
+	// dap_chain_global_db_gr_set(dap_strdup(l_hash_str), (uint8_t *)a_message, a_message_size, a_session->gdb_group_message);
+
+	a_session->messages_count++;
+	memcpy( a_message_hash, &l_message_hash, sizeof(dap_chain_hash_fast_t));
+
+	pthread_rwlock_unlock(&a_session->rwlock);
+}
+
+
+// static int s_message_block_sign_add(dap_chain_cs_blocks_session_items_t * a_session,
+// 										dap_chain_hash_fast_t *a_block_hash, dap_sign_t *a_sign){
+
+// 	int ret = -1;
+// 	size_t l_session_store_size = 0;
+// 	char * l_block_hash_str = dap_chain_hash_fast_to_str_new(a_block_hash);
+//     dap_chain_cs_blocks_session_store_t *l_store = 
+//                 (dap_chain_cs_blocks_session_store_t *)dap_chain_global_db_gr_get(l_block_hash_str, 
+//                 									&l_session_store_size, a_session->gdb_group_store );
+//     if (l_store) {
+//     	dap_chain_global_db_gr_del(dap_strdup(l_block_hash_str), a_session->gdb_group_store);
+//     }
+
+//     // size_t l_sign_offset = l_session_store->hdr.candidate_size;
+//     size_t l_sign_size = dap_sign_get_size(a_sign);
+//     // dap_chain_hash_fast_t l_pkey_hash = {};
+//     // dap_sign_get_pkey_hash(a_sign, &l_pkey_hash);
+//     // dap_chain_addr_t l_addr = {};
+//     // dap_chain_addr_fill(&l_addr, a_sign->header.type, &l_pkey_hash, l_session->chain->net_id);
+
+// 	l_store = DAP_REALLOC(l_store, l_session_store_size+l_sign_size);
+// 	memcpy(((byte_t *)l_store)+l_session_store_size, a_sign, l_sign_size);
+// 	l_store->hdr.sign_count = 0;
+
+// 	if (dap_chain_global_db_gr_set(dap_strdup(l_block_hash_str), l_store,
+// 										l_session_store_size+l_sign_size, a_session->gdb_group_store) ) {
+// 		ret = 0;
+// 	}
+
+// 	return ret;
+// }
+
+
+
+
+
+
diff --git a/modules/type/blocks/include/dap_chain_block.h b/modules/type/blocks/include/dap_chain_block.h
index bcb81167a6..1fe1efbb71 100644
--- a/modules/type/blocks/include/dap_chain_block.h
+++ b/modules/type/blocks/include/dap_chain_block.h
@@ -45,7 +45,7 @@ typedef struct dap_chain_block_hdr{
    uint32_t signature; /// @param signature @brief Magic number, always equels to DAP_CHAIN_BLOCK_SIGNATURE
    int32_t version; /// @param version @brief block version (be carefull, signed value, as Bitcoin has)
    dap_chain_cell_id_t cell_id; /// Cell id
-   dap_chain_cell_id_t chain_id; /// Chain id
+   dap_chain_id_t chain_id; /// Chain id
    dap_chain_time_t ts_created; /// @param timestamp @brief Block create time timestamp
    uint16_t meta_count; // Meta values number
    uint16_t datum_count; // Datums's count
diff --git a/modules/type/blocks/include/dap_chain_cs_blocks_session.h b/modules/type/blocks/include/dap_chain_cs_blocks_session.h
new file mode 100644
index 0000000000..de90803398
--- /dev/null
+++ b/modules/type/blocks/include/dap_chain_cs_blocks_session.h
@@ -0,0 +1,184 @@
+
+#include "dap_chain.h"
+#include "dap_chain_block.h"
+
+
+// • 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)—ablockcandidatehasbeen 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)
+
+#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_blocks_session_message dap_chain_cs_blocks_session_message_t;
+typedef struct dap_chain_cs_blocks_session_message_item dap_chain_cs_blocks_session_message_item_t;
+
+typedef union dap_chain_blocks_session_round_id {
+    uint8_t raw[DAP_CHAIN_BLOCKS_SESSION_ROUND_ID_SIZE];
+    uint64_t uint64;
+} DAP_ALIGN_PACKED dap_chain_blocks_session_round_id_t;
+
+typedef struct dap_chain_cs_blocks_session_items {
+	dap_chain_t *chain;
+	dap_chain_hash_fast_t * last_message_hash;
+	//dap_chain_cs_blocks_session_message_t * messages;
+	dap_chain_cs_blocks_session_message_item_t * messages_items;
+	uint16_t messages_count;
+
+	dap_list_t *validators_list; // dap_chain_node_addr_t 
+	uint16_t validators_count;
+
+	//uint16_t startsync_count;
+	dap_list_t *validators_start; // dap_chain_node_addr_t
+	uint16_t consensus_start_period;
+
+	// dap_timerfd_t* timer_consensus_finish;
+	// dap_timerfd_t* timer_consensus_cancel;
+	dap_chain_time_t ts_consensus_start;
+	dap_chain_time_t ts_consensus_state_commit;
+	dap_chain_time_t ts_consensus_finish;
+
+	dap_chain_blocks_session_round_id_t round_id;
+	uint8_t state;
+
+	char * gdb_group_setup;
+	char * gdb_group_store;
+	char * gdb_group_message;
+
+	dap_enc_key_t *blocks_sign_key;
+	// dap_timerfd_t *cs_timer;
+
+    struct dap_chain_cs_blocks_session_items * next;
+    struct dap_chain_cs_blocks_session_items * prev;
+
+    pthread_rwlock_t rwlock;
+
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_items_t;
+
+typedef struct dap_chain_cs_blocks_session_message_hdr {
+	uint8_t type;
+
+	union {
+		uint8_t raw[DAP_CHAIN_BLOCKS_SESSION_MESSAGE_ID_SIZE];
+    	uint64_t uint64;
+	} DAP_ALIGN_PACKED id;
+
+	size_t message_size;
+
+	dap_chain_time_t ts_created;
+	dap_chain_blocks_session_round_id_t round_id;
+
+	dap_chain_node_addr_t sender_node_addr;
+
+    // dap_chain_hash_fast_t block_candidate_hash;
+    // char* block_candidate_hash_str;
+    // size_t block_candidate_size;
+
+	bool is_genesis;
+
+	//dap_chain_hash_fast_t genesis_message_hash;
+	//dap_chain_hash_fast_t message_hash;
+	dap_chain_hash_fast_t prev_message_hash; 
+	//dap_chain_hash_fast_t link_message_hash; 
+
+    dap_chain_id_t chain_id;
+    //dap_chain_cell_id_t cell_id;
+
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_hdr_t;
+
+
+typedef struct dap_chain_cs_blocks_session_message {
+    dap_chain_cs_blocks_session_message_hdr_t hdr;
+    // UT_hash_handle hh;
+    uint8_t message[];
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_t;
+
+
+typedef struct dap_chain_cs_blocks_session_message_item {
+    dap_chain_cs_blocks_session_message_t * message;
+    dap_chain_hash_fast_t message_hash;
+    UT_hash_handle hh;
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_item_t;
+
+
+// struct for get hash from any messages
+typedef struct dap_chain_cs_blocks_session_message_gethash {
+	dap_chain_hash_fast_t candidate_hash;
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_gethash_t;
+
+// technical messages
+typedef struct dap_chain_cs_blocks_session_message_startsync {
+	dap_chain_time_t ts;
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_startsync_t;
+
+// consensus messages
+typedef struct dap_chain_cs_blocks_session_message_submit {
+	dap_chain_hash_fast_t candidate_hash;
+	size_t candidate_size;
+	uint8_t candidate[];
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_submit_t;
+
+typedef struct dap_chain_cs_blocks_session_message_approve {
+	dap_chain_hash_fast_t candidate_hash;
+	uint8_t candidate_hash_sign[];
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_approve_t;
+
+typedef struct dap_chain_cs_blocks_session_message_reject {
+	dap_chain_hash_fast_t candidate_hash;
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_reject_t;
+
+typedef struct dap_chain_cs_blocks_session_message_votefor {
+	dap_chain_hash_fast_t candidate_hash;
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_votefor_t;
+
+typedef struct dap_chain_cs_blocks_session_message_vote {
+	dap_chain_hash_fast_t candidate_hash;
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_vote_t;
+
+typedef struct dap_chain_cs_blocks_session_message_precommit {
+	dap_chain_hash_fast_t candidate_hash;
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_precommit_t;
+
+typedef struct dap_chain_cs_blocks_session_message_commitsign {
+	dap_chain_hash_fast_t candidate_hash;
+	uint8_t candidate_sign[];
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_message_commitsign_t;
+
+
+typedef struct dap_chain_cs_blocks_session_store_hdr {
+	uint16_t sign_count;
+	uint16_t approve_count;
+	uint16_t reject_count;
+	uint16_t vote_count;
+	uint16_t precommit_count;
+	size_t candidate_size;
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_store_hdr_t;
+
+typedef struct dap_chain_cs_blocks_session_store {
+	dap_chain_cs_blocks_session_store_hdr_t hdr;
+    uint8_t candidate_n_signs[];
+} DAP_ALIGN_PACKED dap_chain_cs_blocks_session_store_t;
+
+
+
+int dap_chain_cs_blocks_session_init(dap_chain_t *a_chain, dap_enc_key_t *a_blocks_sign_key);
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index c6524f716e..a80627e353 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -344,6 +344,7 @@ static int s_dap_chain_add_atom_to_ledger(dap_chain_cs_dag_t * a_dag, dap_ledger
         break;
         case DAP_CHAIN_DATUM_TOKEN_EMISSION: {
             return dap_chain_ledger_token_emission_load(a_ledger, l_datum->data, l_datum->header.data_size);
+            //return dap_chain_ledger_token_emission_load(a_ledger, l_datum, l_datum->header.data_size+sizeof(l_datum->header));
         }
         break;
         case DAP_CHAIN_DATUM_TX: {
-- 
GitLab