diff --git a/CMakeLists.txt b/CMakeLists.txt
index eb274c7fb471e5c6bdb7bbda2eb021d4d2aac96d..10e86caa95db39e8486166816f9f48ca91a389c8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -105,6 +105,30 @@ if (CELLFRAME_MODULES MATCHES "cs-dag-pos")
     set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_cs_dag_pos)
 endif()
 
+# Blocks based consensus(es)
+if (CELLFRAME_MODULES MATCHES "cs-block-" )
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_cs_dag)
+endif()
+
+# PoA consensus for blocks
+if (CELLFRAME_MODULES MATCHES "cs-block-poa")
+    message("[+] Module 'cs-block-poa'")
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_cs_block_poa)
+endif()
+
+# PoS consensus for blocks
+if (CELLFRAME_MODULES MATCHES "cs-block-pos")
+    message("[+] Module 'cs-block-pos'")
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_cs_block_pos)
+endif()
+
+# PoW consensus for blocks
+if (CELLFRAME_MODULES MATCHES "cs-block-pow")
+    message("[+] Module 'cs-block-pow'")
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_cs_block_pos)
+endif()
+
+
 # No-consensus
 if (CELLFRAME_MODULES MATCHES "cs-none")
     message("[+] Module 'cs-none'")
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
index b7d35fe8e87786ac29237543471f39bca4f32373..c1e23565f1487b0f4897b1010b3e762a86796143 100644
--- a/modules/CMakeLists.txt
+++ b/modules/CMakeLists.txt
@@ -38,20 +38,10 @@ if (CELLFRAME_MODULES MATCHES "srv")
 endif()
 
 # Consensus type dag
-if (CELLFRAME_MODULES MATCHES "cs-dag")
+if (CELLFRAME_MODULES MATCHES "cs-dag-")
     add_subdirectory(type/dag)
 endif()
 
-# Consensus type dag
-if (CELLFRAME_MODULES MATCHES "cs-blocks")
-    add_subdirectory(type/blocks)
-endif()
-
-# No consensus
-if (CELLFRAME_MODULES MATCHES "cs-none")
-    add_subdirectory(consensus/none)
-endif()
-
 # DAG PoA
 if (CELLFRAME_MODULES MATCHES "cs-dag-poa")
     add_subdirectory(consensus/dag-poa)
@@ -62,6 +52,31 @@ if (CELLFRAME_MODULES MATCHES "cs-dag-pos")
     add_subdirectory(consensus/dag-pos)
 endif()
 
+# Consensus type blocks
+if (CELLFRAME_MODULES MATCHES "cs-block-")
+    add_subdirectory(type/blocks)
+endif()
+
+# Block PoA
+if (CELLFRAME_MODULES MATCHES "cs-block-poa")
+    add_subdirectory(consensus/block-poa)
+endif()
+
+# Block PoS
+if (CELLFRAME_MODULES MATCHES "cs-block-pos")
+    add_subdirectory(consensus/block-pos)
+endif()
+
+# Block PoW
+if (CELLFRAME_MODULES MATCHES "cs-block-pow")
+    add_subdirectory(consensus/block-pow)
+endif()
+
+# No consensus
+if (CELLFRAME_MODULES MATCHES "cs-none")
+    add_subdirectory(consensus/none)
+endif()
+
 # Service App
 if (CELLFRAME_MODULES MATCHES "srv-app")
     add_subdirectory(service/app)
diff --git a/modules/consensus/block-poa/dap_chain_cs_block_poa.c b/modules/consensus/block-poa/dap_chain_cs_block_poa.c
index 5aa85e5aa8a02992c9164c9d4f361e7528fd957c..dc7f7b131ef93bb347507153e591afffa95427ad 100644
--- a/modules/consensus/block-poa/dap_chain_cs_block_poa.c
+++ b/modules/consensus/block-poa/dap_chain_cs_block_poa.c
@@ -44,7 +44,7 @@
 
 typedef struct dap_chain_cs_dag_poa_pvt
 {
-    dap_cert_t * sign_cert;
+    dap_enc_key_t *sign_key;
     dap_cert_t ** auth_certs;
     char * auth_certs_prefix;
     uint16_t auth_certs_count;
@@ -59,9 +59,10 @@ static void s_callback_delete(dap_chain_cs_blocks_t* a_blocks);
 static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg);
 static int s_callback_created(dap_chain_t * a_chain, dap_config_t *a_chain_cfg);
 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 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);
 
 // CLI commands
-static int s_cli_block_poa(int argc, char ** argv, void *arg_func, char **str_reply);
+static int s_cli_block_poa(int argc, char ** argv, char **str_reply);
 
 static bool s_seed_mode = false;
 /**
@@ -73,8 +74,8 @@ int dap_chain_cs_block_poa_init(void)
     // Add consensus constructor
     dap_chain_cs_add ("block_poa", s_callback_new );
     s_seed_mode = dap_config_get_item_bool_default(g_config,"general","seed_mode",false);
-    dap_chain_node_cli_cmd_item_create ("block_poa", s_cli_block_poa, NULL, "Blockchain PoA commands",
-        "block_poa -net <chain net name> -chain <chain name> block new_block_sign [-cert <cert name>] \n"
+    dap_chain_node_cli_cmd_item_create ("block_poa", s_cli_block_poa, "Blockchain PoA commands",
+        "block_poa -net <chain net name> -chain <chain name> block sign [-cert <cert name>] \n"
             "\tSign new block with certificate <cert name> or withs own PoA certificate\n\n");
 
     return 0;
@@ -98,9 +99,8 @@ void dap_chain_cs_block_poa_deinit(void)
  * @param str_reply
  * @return
  */
-static int s_cli_block_poa(int argc, char ** argv, void *arg_func, char **a_str_reply)
+static int s_cli_block_poa(int argc, char ** argv, char **a_str_reply)
 {
-    (void) arg_func;
     int ret = -666;
     int arg_index = 1;
     dap_chain_net_t * l_chain_net = NULL;
@@ -118,25 +118,28 @@ static int s_cli_block_poa(int argc, char ** argv, void *arg_func, char **a_str_
     dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index,argc,argv,a_str_reply,&l_chain,&l_chain_net);
 
     dap_chain_cs_blocks_t * l_blocks = DAP_CHAIN_CS_BLOCKS(l_chain);
-    //dap_chain_cs_dag_poa_t * l_poa = DAP_CHAIN_CS_DAG_POA( l_dag ) ;
     dap_chain_cs_block_poa_pvt_t * l_poa_pvt = PVT ( DAP_CHAIN_CS_BLOCK_POA( l_blocks ) );
 
     const char * l_block_new_cmd_str = NULL;
     const char * l_block_hash_str = NULL;
     const char * l_cert_str = NULL;
-    dap_cert_t * l_cert = l_poa_pvt->sign_cert;
-    if ( l_poa_pvt->sign_cert == NULL) {
-        dap_chain_node_cli_set_reply_text(a_str_reply, "No certificate to sign events\n");
-        return -2;
-    }
 
     dap_chain_node_cli_find_option_val(argv, arg_index, argc, "block", &l_block_new_cmd_str);
     dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-block", &l_block_hash_str);
     dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-cert", &l_cert_str);
 
+    dap_enc_key_t *l_sign_key;
     // Load cert to sign if its present
-    if (l_cert_str)
-        l_cert = dap_cert_find_by_name( l_cert_str);
+    if (l_cert_str) {
+        dap_cert_t *l_cert = dap_cert_find_by_name( l_cert_str);
+        l_sign_key = l_cert->enc_key;
+    } else {
+        l_sign_key = l_poa_pvt->sign_key;
+    }
+    if (!l_sign_key || !l_sign_key->priv_key_data) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "No certificate to sign blocks\n");
+        return -2;
+    }
 
     // block hash may be in hex or base58 format
     char *l_block_hash_hex_str;
@@ -150,12 +153,10 @@ static int s_cli_block_poa(int argc, char ** argv, void *arg_func, char **a_str_
         l_event_hash_base58_str = dap_strdup(l_block_hash_str);
     }
 
-    // Parse block ccmd
+    // Parse block cmd
     if ( l_block_new_cmd_str != NULL ){
-        if (l_poa_pvt->sign_cert )
-        ret = -1;
-        if ( strcmp(l_block_new_cmd_str,"new_block_sign") == 0) { // Sign event command
-                l_blocks->block_new_size = dap_chain_block_sign_add( &l_blocks->block_new,l_blocks->block_new_size,  l_cert );
+        if ( strcmp(l_block_new_cmd_str,"sign") == 0) { // Sign event command
+                l_blocks->block_new_size = dap_chain_block_sign_add( &l_blocks->block_new,l_blocks->block_new_size, l_sign_key);
                 //dap_chain_hash_fast_t l_block_new_hash;
                 //dap_hash_fast(l_blocks->block_new, l_blocks->block_new_size,&l_block_new_hash);
         }
@@ -170,14 +171,15 @@ static int s_cli_block_poa(int argc, char ** argv, void *arg_func, char **a_str_
  */
 static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
 {
-    dap_chain_cs_create(a_chain,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_poa_t * l_poa = DAP_NEW_Z ( dap_chain_cs_block_poa_t);
     l_blocks->_inheritor = l_poa;
     l_blocks->callback_delete = s_callback_delete;
     l_blocks->callback_block_verify = s_callback_block_verify;
-    l_poa->_pvt = DAP_NEW_Z ( dap_chain_cs_block_poa_pvt_t );
-    dap_chain_cs_block_poa_pvt_t * l_poa_pvt = PVT ( l_poa );
+    l_blocks->callback_block_sign = s_callback_block_sign;
+    l_poa->_pvt = DAP_NEW_Z(dap_chain_cs_block_poa_pvt_t);
+    dap_chain_cs_block_poa_pvt_t *l_poa_pvt = PVT(l_poa);
 
     if (dap_config_get_item_str(a_chain_cfg,"block-poa","auth_certs_prefix") ) {
         l_poa_pvt->auth_certs_count = dap_config_get_item_uint16_default(a_chain_cfg,"block-poa","auth_certs_number",0);
@@ -219,14 +221,19 @@ static int s_callback_created(dap_chain_t * a_chain, dap_config_t *a_chain_net_c
     if (PVT(l_poa)->prev_callback_created )
         PVT(l_poa)->prev_callback_created(a_chain,a_chain_net_cfg);
 
-    const char * l_sign_cert = NULL;
-    if ( ( l_sign_cert = dap_config_get_item_str(a_chain_net_cfg,"block-poa","sign-cert") ) != NULL ) {
-
-        if ( ( PVT(l_poa)->sign_cert = dap_cert_find_by_name(l_sign_cert)) == NULL ){
-            log_it(L_ERROR,"Can't load sign certificate, name \"%s\" is wrong",l_sign_cert);
-        }else
-            log_it(L_NOTICE,"Loaded \"%s\" certificate to sign poa blocks", l_sign_cert);
-
+    const char * l_sign_cert_str = NULL;
+    if ( ( l_sign_cert_str = dap_config_get_item_str(a_chain_net_cfg,"block-poa","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) {
+            PVT(l_poa)->sign_key = l_sign_cert->enc_key;
+            log_it(L_NOTICE, "Loaded \"%s\" certificate to sign poa 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");
     }
     return 0;
 }
@@ -256,6 +263,29 @@ static void s_callback_delete(dap_chain_cs_blocks_t * a_blocks)
     }
 }
 
+/**
+ * @brief
+ * function makes block singing
+ * @param a_dag a_blocks dap_chain_cs_blocks_t
+ * @param a_block dap_chain_block_t
+ * @param a_block_size size_t size of block object
+ * @return int
+ */
+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_poa_t *l_poa = DAP_CHAIN_CS_BLOCK_POA(a_blocks);
+    dap_chain_cs_block_poa_pvt_t *l_poa_pvt = PVT(l_poa);
+    if (!l_poa_pvt->sign_key) {
+        log_it(L_WARNING, "Can't sign block with sign-cert in [block-poa] 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_poa_pvt->sign_key);
+}
 
 /**
  * @brief s_callbac_block_verify
@@ -276,21 +306,23 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t * a_blocks, dap_chain_b
         return -2;
     }
     // Parse the rest signs
-    size_t l_offset = (byte_t*)l_sign - (byte_t*) a_block;
-    while (l_offset < a_block_size - sizeof (a_block->hdr) ){
+    size_t l_offset = (byte_t *)l_sign - a_block->meta_n_datum_n_sign;
+    while (l_offset < a_block_size - sizeof(a_block->hdr)) {
+        if (!dap_sign_verify_size(l_sign, a_block_size)) {
+            log_it(L_ERROR, "Corrupted block: sign size is bigger than block size");
+            return -3;
+        }
         size_t l_sign_size = dap_sign_get_size(l_sign);
         // Check if sign size 0
         if (!l_sign_size){
             log_it(L_ERROR, "Corrupted block: sign size got zero");
-            return -3;
+            return -4;
         }
         // Check if sign size too big
         if (l_sign_size > a_block_size- sizeof (a_block->hdr)-l_offset ){
             log_it(L_ERROR, "Corrupted block: sign size %zd is too big, out from block size %zd", l_sign_size, a_block_size);
-            return -3;
+            return -5;
         }
-        l_offset += l_sign_size;
-
         // Compare signature with auth_certs
         for (uint16_t j = 0; j < l_poa_pvt->auth_certs_count; j++) {
             if (dap_cert_compare_with_sign ( l_poa_pvt->auth_certs[j], l_sign) == 0){
@@ -298,6 +330,12 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t * a_blocks, dap_chain_b
                 break;
             }
         }
+        l_offset += l_sign_size;
+        l_sign = (dap_sign_t *)(a_block->meta_n_datum_n_sign + l_offset);
+    }
+    if (l_offset != a_block_size - sizeof(a_block->hdr)) {
+        log_it(L_ERROR, "Corrupted block: sign end exceeded the block bound");
+        return -6;
     }
     return l_signs_verified_count >= l_poa_pvt->auth_certs_count_verify ? 0 : -1;
 }
diff --git a/modules/consensus/block-pos/CMakeLists.txt b/modules/consensus/block-pos/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2417e6529e529168867e0f383b60606f07463e1a
--- /dev/null
+++ b/modules/consensus/block-pos/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.0)
+project (dap_chain_cs_block_pos)
+  
+file(GLOB DAP_CHAIN_CS_BLOCK_POS_SRCS *.c)
+file(GLOB DAP_CHAIN_CS_BLOCK_POS_HEADERS include/*.h)
+
+add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_CS_BLOCK_POS_SRCS} ${DAP_CHAIN_CS_BLOCK_POS_HEADERS})
+
+target_link_libraries(dap_chain_cs_block_pos dap_core dap_crypto dap_chain dap_chain_cs_blocks dap_chain_net_srv_stake)
+target_include_directories(dap_chain_cs_block_pos INTERFACE .)
+target_include_directories(${PROJECT_NAME} PUBLIC include)
diff --git a/modules/consensus/block-pos/dap_chain_cs_block_pos.c b/modules/consensus/block-pos/dap_chain_cs_block_pos.c
new file mode 100644
index 0000000000000000000000000000000000000000..7b6d0dfc3b70565d0f7606b784953e2c4e63d2f4
--- /dev/null
+++ b/modules/consensus/block-pos/dap_chain_cs_block_pos.c
@@ -0,0 +1,303 @@
+/*
+ * Authors:
+ * Roman Khlopkov <roman.khlopkov@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Kelvin Project https://github.com/kelvinblockchain
+ * Copyright  (c) 2017-2021
+ * 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 <stdlib.h>
+
+#include "dap_chain_net.h"
+#include "dap_common.h"
+#include "dap_string.h"
+#include "dap_strfuncs.h"
+#include "dap_chain_cs.h"
+#include "dap_chain_cs_blocks.h"
+#include "dap_chain_cs_block_pos.h"
+#include "dap_chain_net_srv_stake.h"
+#include "dap_chain_ledger.h"
+
+#define LOG_TAG "dap_chain_cs_block_pos"
+
+typedef struct dap_chain_cs_block_pos_pvt
+{
+    dap_enc_key_t *blocks_sign_key;
+    char **tokens_hold;
+    uint64_t *tokens_hold_value;
+    size_t tokens_hold_size;
+    uint16_t confirmations_minimum;
+    dap_chain_callback_new_cfg_t prev_callback_created;
+} dap_chain_cs_block_pos_pvt_t;
+
+#define PVT(a) ((dap_chain_cs_block_pos_pvt_t *)a->_pvt)
+
+static void s_callback_delete(dap_chain_cs_blocks_t *a_blocks);
+static int s_callback_new(dap_chain_t *a_chain, dap_config_t *a_chain_cfg);
+static int s_callback_created(dap_chain_t *a_chain, dap_config_t *a_chain_cfg);
+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 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);
+
+/**
+ * @brief dap_chain_cs_block_pos_init
+ * @return
+ */
+int dap_chain_cs_block_pos_init()
+{
+    dap_chain_cs_add("block_pos", s_callback_new);
+    return 0;
+}
+
+/**
+ * @brief dap_chain_cs_block_pos_deinit
+ */
+void dap_chain_cs_block_pos_deinit(void)
+{
+
+}
+
+/**
+ * @brief s_cs_callback
+ * @param a_chain
+ * @param a_chain_cfg
+ */
+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_pos_t *l_pos = DAP_NEW_Z(dap_chain_cs_block_pos_t);
+    l_blocks->_inheritor = l_pos;
+    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_pos->_pvt = DAP_NEW_Z(dap_chain_cs_block_pos_pvt_t);
+
+    dap_chain_cs_block_pos_pvt_t *l_pos_pvt = PVT(l_pos);
+
+    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-pos", "stake_tokens", &l_tokens_hold_size);
+    l_tokens_hold_value_str = dap_config_get_array_str(a_chain_cfg, "block-pos", "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_pos_pvt->confirmations_minimum = dap_config_get_item_uint16_default(a_chain_cfg, "block-pos", "verifications_minimum", 1);
+    l_pos_pvt->tokens_hold_size = l_tokens_hold_size;
+    l_pos_pvt->tokens_hold = DAP_NEW_Z_SIZE(char *, sizeof(char *) * l_tokens_hold_size);
+    l_pos_pvt->tokens_hold_value = DAP_NEW_Z_SIZE(uint64_t, l_tokens_hold_value_size * sizeof(uint64_t));
+
+    for (size_t i = 0; i < l_tokens_hold_value_size; i++) {
+        l_pos_pvt->tokens_hold[i] = dap_strdup(l_tokens_hold[i]);
+        if ((l_pos_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_pos_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_pos_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_pos_pvt->tokens_hold_value);
+    DAP_DELETE(l_pos_pvt);
+    DAP_DELETE(l_pos );
+    l_blocks->_inheritor = NULL;
+    l_blocks->callback_delete = NULL;
+    l_blocks->callback_block_verify = NULL;
+    return -1;
+
+}
+
+/**
+ * @brief s_callback_created
+ * @param a_chain
+ * @param a_chain_cfg
+ * @return
+ */
+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_pos_t *l_pos = DAP_CHAIN_CS_BLOCK_POS(l_blocks);
+
+    const char * l_sign_cert_str = NULL;
+    if ( ( l_sign_cert_str = dap_config_get_item_str(a_chain_net_cfg,"block-pos","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) {
+            PVT(l_pos)->blocks_sign_key = l_sign_cert->enc_key;
+            log_it(L_NOTICE, "Loaded \"%s\" certificate to sign PoS 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");
+    }
+    return 0;
+}
+
+
+/**
+ * @brief s_chain_cs_block_callback_delete
+ * @param a_block
+ */
+static void s_callback_delete(dap_chain_cs_blocks_t *a_blocks)
+{
+    dap_chain_cs_block_pos_t *l_pos = DAP_CHAIN_CS_BLOCK_POS(a_blocks);
+    if (l_pos->_pvt)
+        DAP_DELETE(l_pos->_pvt);
+}
+
+/**
+ * @brief
+ * function makes block singing
+ * @param a_block a_blocks dap_chain_cs_blocks_t
+ * @param a_block dap_chain_block_t
+ * @param a_block_size size_t size of block object
+ * @return int
+ */
+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_pos_t *l_pos = DAP_CHAIN_CS_BLOCK_POS(a_blocks);
+    dap_chain_cs_block_pos_pvt_t *l_pos_pvt = PVT(l_pos);
+    if (!l_pos_pvt->blocks_sign_key) {
+        log_it(L_WARNING, "Can't sign block with sign-cert in [block-pos] 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_pos_pvt->blocks_sign_key);
+}
+
+/**
+ * @brief 
+ * function makes block singing verification
+ * @param a_block a_blocks dap_chain_cs_blocks_t
+ * @param a_block dap_chain_block_t
+ * @param a_block_size size_t size of block object
+ * @return int 
+ */
+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_pos_t *l_pos = DAP_CHAIN_CS_BLOCK_POS(a_blocks);
+    dap_chain_cs_block_pos_pvt_t *l_pos_pvt = PVT(l_pos);
+
+    if (a_blocks->chain->ledger == NULL) {
+        log_it(L_CRITICAL,"Ledger is NULL can't check PoS 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_signs_count = dap_chain_block_get_signs_count(a_block, a_block_size);
+    if (l_signs_count < l_pos_pvt->confirmations_minimum) {
+        log_it(L_WARNING,"Wrong signature number with block %p on chain %s", a_block, a_blocks->chain->name);
+        return -2; // Wrong signatures number
+    }
+
+    uint16_t l_verified_num = 0;
+    for (size_t l_sig_pos = 0; l_sig_pos < l_signs_count; l_sig_pos++) {
+        dap_sign_t *l_sign = dap_chain_block_sign_get(a_block, a_block_size, l_sig_pos);
+        if (l_sign == NULL) {
+            log_it(L_WARNING, "Block isn't signed with anything: sig pos %zu, event size %zu", l_sig_pos, a_block_size);
+            return -4;
+        }
+
+        bool l_sign_size_correct = dap_sign_verify_size(l_sign, a_block_size);
+        if (!l_sign_size_correct) {
+            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);
+        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;
+        }
+
+        int l_sign_verified = dap_sign_verify(l_sign, a_block, l_block_data_size);
+        if (l_sign_verified != 1) {
+            log_it(L_WARNING, "Block's sign is incorrect: code %d", l_sign_verified);
+            return -41;
+        }
+
+        /*dap_chain_hash_fast_t l_pkey_hash;
+        if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash)) {
+            log_it(L_WARNING, "Block's sign has no any key");
+            return -5;
+        }
+        dap_chain_addr_t l_addr = {};
+        dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, a_blocks->chain->net_id);
+
+        if (l_sig_pos == 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);
+            for (unsigned i = 0; i < l_datums_count; i++) {
+                if (l_datums[i]->header.type_id == DAP_CHAIN_DATUM_TX) {
+                    dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datums[i]->data;
+                    if (!dap_chain_net_srv_stake_validator(&l_addr, l_tx)) {
+                        log_it(L_WARNING,"Not passed stake validator with datum %u of block %p on chain %s", i, a_block, a_blocks->chain->name);
+                        return -6;
+                    }
+                }
+            }
+        }
+
+        bool l_is_enough_balance = false;
+        for (size_t i = 0; i < l_pos_pvt->tokens_hold_size; i++) {
+            uint128_t l_balance = dap_chain_ledger_calc_balance(a_blocks->chain->ledger, &l_addr, l_pos_pvt->tokens_hold[i]);
+            uint64_t l_value = dap_chain_uint128_to(l_balance);
+            if (l_value >= l_pos_pvt->tokens_hold_value[i]) {
+                l_verified_num++;
+                l_is_enough_balance = true;
+                break;
+            }
+        }
+        if (!l_is_enough_balance) {
+            char *l_addr_str = dap_chain_addr_to_str(&l_addr);
+            log_it(L_WARNING, "Verify of block is false, because balance is not enough for addr=%s", l_addr_str);
+            DAP_DELETE(l_addr_str);
+            return -1;
+        }*/ // TODO comlete stake validator for all datums in the block
+    }
+
+    // Check number
+    if (l_verified_num >= l_pos_pvt->confirmations_minimum) {
+        // Passed all checks
+        return 0;
+    } else {
+        log_it(L_WARNING, "Wrong block: only %hu/%hu signs are valid", l_verified_num, l_pos_pvt->confirmations_minimum);
+        return -2;
+    }
+}
diff --git a/modules/consensus/block-pos/include/dap_chain_cs_block_pos.h b/modules/consensus/block-pos/include/dap_chain_cs_block_pos.h
new file mode 100644
index 0000000000000000000000000000000000000000..368c77a653e87749451b5860d7c1ab5f2addde5d
--- /dev/null
+++ b/modules/consensus/block-pos/include/dap_chain_cs_block_pos.h
@@ -0,0 +1,39 @@
+/*
+ * Authors:
+ * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
+ * DeM Labs Inc.   https://demlabs.net
+ * Kelvin Project https://github.com/kelvinblockchain
+ * Copyright  (c) 2017-2018
+ * 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/>.
+*/
+#pragma once
+#include "dap_chain_cs_blocks.h"
+#include "dap_cert.h"
+
+typedef struct dap_chain_cs_block_pos
+{
+    dap_chain_t *chain;
+    dap_chain_cs_blocks_t *blocks;
+    void *_pvt;
+} dap_chain_cs_block_pos_t;
+
+#define DAP_CHAIN_CS_BLOCK_POS(a) ((dap_chain_cs_block_pos_t *)(a)->_inheritor)
+
+
+int dap_chain_cs_block_pos_init();
+void dap_chain_cs_block_pos_deinit(void);
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index 98e6ceb0728633ed87e69548183c3e82a818ea72..e7e40be7532b8207727a0bd53802a41410b9b4cc 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -67,7 +67,7 @@ static const char * g_net_state_str[]={
 typedef struct dap_chain_net{
     struct {
         dap_chain_net_id_t id;
-        dap_chain_cell_id_t cell_id; // Cell where the node is connected to. {{0}} if not celled(sharder) blockchain
+        dap_chain_cell_id_t cell_id; // Cell where the node is connected to. {{0}} if not celled(sharded) blockchain
         char * name;
         char * gdb_groups_prefix;
         char * gdb_nodes_aliases;
diff --git a/modules/type/blocks/dap_chain_block.c b/modules/type/blocks/dap_chain_block.c
index e9a6836f5f1f3b59eab751fe1a38c93505be62e4..4bc564e15eb26fe7d0e5691dfaf8902ae829b98a 100644
--- a/modules/type/blocks/dap_chain_block.c
+++ b/modules/type/blocks/dap_chain_block.c
@@ -25,7 +25,7 @@
 #include "dap_common.h"
 #include "dap_config.h"
 #include "dap_hash.h"
-
+#include "dap_chain_net.h"
 #include "dap_chain_block.h"
 #include "dap_chain_block_cache.h"
 
@@ -58,7 +58,7 @@ void dap_chain_block_deinit()
  * @param a_prev_block
  * @return
  */
-dap_chain_block_t * dap_chain_block_new(dap_chain_hash_fast_t * a_prev_block )
+dap_chain_block_t *dap_chain_block_new(dap_chain_hash_fast_t *a_prev_block, size_t *a_block_size)
 {
     dap_chain_block_t * l_block = DAP_NEW_Z_SIZE (dap_chain_block_t,sizeof(l_block->hdr));
     if( l_block == NULL){
@@ -68,16 +68,18 @@ dap_chain_block_t * dap_chain_block_new(dap_chain_hash_fast_t * a_prev_block )
         l_block->hdr.signature = DAP_CHAIN_BLOCK_SIGNATURE;
         l_block->hdr.version = 1;
         l_block->hdr.ts_created = time(NULL);
-        size_t l_block_size = sizeof (l_block->hdr);
+        size_t l_block_size = sizeof(l_block->hdr);
         if( a_prev_block ){
-            l_block_size = dap_chain_block_meta_add(&l_block, l_block_size, DAP_CHAIN_BLOCK_META_PREV,a_prev_block,sizeof (*a_prev_block) );
+            l_block_size = dap_chain_block_meta_add(&l_block, l_block_size, DAP_CHAIN_BLOCK_META_PREV,
+                                                    a_prev_block, sizeof(*a_prev_block));
         }else{
+            l_block_size = dap_chain_block_meta_add(&l_block, l_block_size, DAP_CHAIN_BLOCK_META_GENESIS, NULL, 0);
             log_it(L_INFO, "Genesis block produced");
         }
+        if (a_block_size)
+            *a_block_size = l_block_size;
         return l_block;
     }
-
-
 }
 
 /**
@@ -89,7 +91,7 @@ dap_chain_block_t * dap_chain_block_new(dap_chain_hash_fast_t * a_prev_block )
 size_t s_block_get_datum_offset (dap_chain_block_t * a_block, size_t a_block_size)
 {
     if( a_block_size < sizeof(a_block->hdr) ){
-        log_it(L_ERROR,"Meta add: Corrupted block size %zd thats smaller then block header size %zd ", a_block_size, sizeof (a_block->hdr));
+        log_it(L_ERROR, "Can't get datum offset: corrupted block size %zu / header size %zu", a_block_size, sizeof (a_block->hdr));
     }
     size_t l_offset = 0;
     dap_chain_block_meta_t * l_meta=NULL;
@@ -136,28 +138,22 @@ size_t dap_chain_block_meta_add(dap_chain_block_t ** a_block_ptr, size_t a_block
         return 0;
     }
 
-    size_t l_offset = s_block_get_datum_offset(l_block,a_block_size);
-    size_t l_datum_n_sign_copy_size = (a_block_size-sizeof (l_block->hdr)) - l_offset;
-    if (l_datum_n_sign_copy_size){
-        byte_t * l_meta_end =  l_block->meta_n_datum_n_sign +l_offset;
-        byte_t * l_datum_n_sign_copy = DAP_NEW_SIZE(byte_t, l_datum_n_sign_copy_size);
-        memcpy(l_datum_n_sign_copy, l_meta_end,l_datum_n_sign_copy_size);
-        *a_block_ptr = l_block = DAP_REALLOC(l_block,a_block_size +sizeof (l_meta->hdr) +a_data_size );
-        l_meta= (dap_chain_block_meta_t*) (l_block->meta_n_datum_n_sign +l_offset); // Update data end in reallocated block
-        l_meta->hdr.data_size = a_data_size;
-        l_meta->hdr.type = a_meta_type;
-        l_offset += a_data_size;
-        l_offset += sizeof(l_meta->hdr);
-        if (a_data_size)
-            memcpy(l_meta->data, a_data, a_data_size);
-        l_meta_end=  l_block->meta_n_datum_n_sign +l_offset; // Update meta end
-        memcpy(l_meta_end, l_datum_n_sign_copy, l_datum_n_sign_copy_size);
-        l_offset += l_datum_n_sign_copy_size;
-        l_block->hdr.meta_n_datum_n_signs_size = l_offset;
-        l_block->hdr.meta_count++;
-        DAP_DELETE(l_datum_n_sign_copy);
+    size_t l_add_size = sizeof(l_meta->hdr) + a_data_size;
+    *a_block_ptr = l_block = DAP_REALLOC(l_block, a_block_size + l_add_size);
+    size_t l_offset = s_block_get_datum_offset(l_block, a_block_size);
+    size_t l_datum_n_sign_copy_size = a_block_size - sizeof(l_block->hdr) - l_offset;
+    if (l_datum_n_sign_copy_size) {
+        byte_t *l_meta_end = l_block->meta_n_datum_n_sign + l_offset;
+        memmove(l_meta_end + l_add_size, l_meta_end, l_datum_n_sign_copy_size);
     }
-    return l_offset+sizeof (l_block->hdr);
+    l_meta = (dap_chain_block_meta_t *)(l_block->meta_n_datum_n_sign + l_offset); // Update data end in reallocated block
+    l_meta->hdr.data_size = a_data_size;
+    l_meta->hdr.type = a_meta_type;
+    if (a_data_size)
+        memcpy(l_meta->data, a_data, a_data_size);
+    l_block->hdr.meta_n_datum_n_signs_size = l_offset + l_datum_n_sign_copy_size;
+    l_block->hdr.meta_count++;
+    return a_block_size + l_add_size;
 }
 
 /**
@@ -199,14 +195,14 @@ size_t dap_chain_block_datum_add(dap_chain_block_t ** a_block_ptr, size_t a_bloc
         log_it(L_ERROR,"Offset %zd is bigger than block size %zd (without header)", l_offset, (a_block_size-sizeof (l_block->hdr)));
         return a_block_size;
     }
-    if (UINT32_MAX - l_block->hdr.meta_n_datum_n_signs_size < a_datum_size &&  l_block->hdr.datum_count<UINT16_MAX  ){
+    if (a_datum_size + l_block->hdr.meta_n_datum_n_signs_size < UINT32_MAX && l_block->hdr.datum_count < UINT16_MAX) {
         // If were signs - they would be deleted after because signed should be all the block filled
-        *a_block_ptr = l_block = DAP_REALLOC(l_block,l_offset +a_datum_size);
-        memcpy(l_block->meta_n_datum_n_sign + l_offset, a_datum,a_datum_size);
+        *a_block_ptr = l_block = DAP_REALLOC(l_block, sizeof(l_block->hdr) + l_offset + a_datum_size);
+        memcpy(l_block->meta_n_datum_n_sign + l_offset, a_datum, a_datum_size);
         l_offset += a_datum_size;
         l_block->hdr.datum_count++;
         l_block->hdr.meta_n_datum_n_signs_size = l_offset;
-        return l_offset+sizeof (l_block->hdr);
+        return l_offset + sizeof(l_block->hdr);
     }else{
         //log_it(L_ERROR,"");
         return a_block_size;
@@ -279,12 +275,12 @@ size_t dap_chain_block_datum_del_by_hash(dap_chain_block_t ** a_block_ptr, size_
  * @param a_block_size
  * @return
  */
-static size_t s_block_get_sign_offset(dap_chain_block_t * a_block, size_t a_block_size)
+size_t dap_chain_block_get_sign_offset(dap_chain_block_t *a_block, size_t a_block_size)
 {
     assert(a_block);
     assert(a_block_size);
-    if(a_block_size>=sizeof (a_block->hdr)){
-        log_it(L_ERROR, "Corrupted block, block size %zd is lesser than block header size %zd", a_block_size,sizeof (a_block->hdr));
+    if (a_block_size <= sizeof(a_block->hdr)) {
+        log_it(L_ERROR, "Get sign: corrupted block, block size %zd is lesser than block header size %zd", a_block_size,sizeof (a_block->hdr));
         return 0;
     }
 
@@ -309,7 +305,7 @@ static size_t s_block_get_sign_offset(dap_chain_block_t * a_block, size_t a_bloc
         l_datum =(dap_chain_datum_t *) (a_block->meta_n_datum_n_sign + l_offset);
     }
     if (l_offset> (a_block_size-sizeof (a_block->hdr))){
-        log_it(L_ERROR,"Offset %zd with block header %zd is bigger than block size %zd ", l_offset,sizeof (a_block->hdr),a_block_size);
+        log_it(L_ERROR,"Offset %zd with block header %zu is bigger than block size %zu", l_offset,sizeof (a_block->hdr),a_block_size);
         return a_block_size;
     }
 
@@ -323,17 +319,19 @@ static size_t s_block_get_sign_offset(dap_chain_block_t * a_block, size_t a_bloc
  * @param a_cert
  * @return
  */
-size_t dap_chain_block_sign_add( dap_chain_block_t ** a_block_ptr, size_t a_block_size, dap_cert_t * a_cert )
+size_t dap_chain_block_sign_add(dap_chain_block_t **a_block_ptr, size_t a_block_size, dap_enc_key_t *a_key)
 {
     assert(a_block_ptr);
-    dap_chain_block_t * l_block = *a_block_ptr;
-    size_t l_offset = s_block_get_sign_offset(l_block,a_block_size);
-    dap_sign_t * l_block_sign = dap_cert_sign(a_cert,l_block,l_offset+sizeof (l_block->hdr),0);
+    dap_chain_block_t *l_block = *a_block_ptr;
+    size_t l_offset = dap_chain_block_get_sign_offset(l_block, a_block_size);
+    dap_sign_t *l_block_sign = dap_sign_create(a_key, l_block, l_offset + sizeof(l_block->hdr), 0);
     size_t l_block_sign_size = dap_sign_get_size(l_block_sign);
+    if (!l_block_sign_size)
+        return 0;
     *a_block_ptr = l_block = DAP_REALLOC(l_block, l_block_sign_size + a_block_size);
-    memcpy(  ((byte_t *)l_block) +a_block_size,l_block_sign, l_block_sign_size  );
+    memcpy(((byte_t *)l_block) + a_block_size, l_block_sign, l_block_sign_size);
     DAP_DELETE(l_block_sign);
-    return a_block_size+l_block_sign_size;
+    return a_block_size + l_block_sign_size;
 }
 
 /**
@@ -346,25 +344,47 @@ size_t dap_chain_block_sign_add( dap_chain_block_t ** a_block_ptr, size_t a_bloc
 dap_sign_t *dap_chain_block_sign_get ( dap_chain_block_t * a_block, size_t a_block_size, uint16_t a_sign_num )
 {
     assert(a_block);
-    size_t l_offset = s_block_get_sign_offset(a_block,a_block_size);
-    uint16_t l_sign_cur=0;
-    dap_sign_t * l_sign = (dap_sign_t*) a_block->meta_n_datum_n_sign+l_offset;
-    while( l_sign_cur <a_sign_num){
+    size_t l_offset = dap_chain_block_get_sign_offset(a_block, a_block_size);
+    uint16_t l_sign_cur = 0;
+    dap_sign_t *l_sign = (dap_sign_t *)(a_block->meta_n_datum_n_sign + l_offset);
+    while (l_sign_cur < a_sign_num) {
 
         size_t l_sign_size = dap_sign_get_size(l_sign);
-        if (!l_sign){
+        if (!l_sign_size){
             log_it(L_ERROR, "Empty sign #%u",  l_sign_cur );
             return NULL;
         }
         if (l_sign_size >  a_block_size- l_offset - sizeof (a_block->hdr) ){
-            log_it(L_ERROR, "Corrupted sign #%u size %zd",  l_sign_cur, l_sign_size );
+            log_it(L_ERROR, "Corrupted sign #%u size %zu",  l_sign_cur, l_sign_size );
             return NULL;
         }
         l_offset += l_sign_size;
         l_sign_cur++;
         l_sign = (dap_sign_t*) a_block->meta_n_datum_n_sign+l_offset;
     }
-    return  l_sign_cur == a_sign_num? l_sign : NULL;
+    return l_sign_cur == a_sign_num ? l_sign : NULL;
+}
+
+size_t dap_chain_block_get_signs_count(dap_chain_block_t * a_block, size_t a_block_size)
+{
+    assert(a_block);
+    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;
+        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);
+            return l_sign_count;
+        }
+        if (l_sign_size > a_block_size - l_offset - sizeof(a_block->hdr)) {
+            log_it(L_ERROR, "Corrupted sign #%hu size %zu", l_sign_count, l_sign_size);
+            return l_sign_count;
+        }
+        l_offset += l_sign_size;
+    }
+    return l_sign_count;
 }
 
 /**
@@ -379,11 +399,11 @@ dap_chain_datum_t** dap_chain_block_get_datums(dap_chain_block_t * a_block, size
     assert(a_block);
     assert(a_block_size);
     if( a_block_size<sizeof (a_block->hdr)){
-        log_it(L_ERROR,"Corrupted block size %zd lesser than block header size %zd", a_block_size, sizeof (a_block->hdr));
+        log_it(L_ERROR, "Get datums: corrupted block size %zd lesser than block header size %zd", a_block_size, sizeof (a_block->hdr));
         return NULL;
     }
-    assert(a_datums_count);
-    *a_datums_count = a_block->hdr.datum_count;
+    if (a_datums_count)
+        *a_datums_count = 0;
     if (a_block->hdr.datum_count == 0)
         return NULL;
     size_t l_offset = s_block_get_datum_offset(a_block,a_block_size);
@@ -405,11 +425,11 @@ dap_chain_datum_t** dap_chain_block_get_datums(dap_chain_block_t * a_block, size
             return l_ret;
         }
         l_ret[n] = l_datum;
-        (*a_datums_count)++;
+        if (a_datums_count)
+            (*a_datums_count)++;
         // Update current datum pointer and offset
         l_offset += l_datum_size;
         l_datum =(dap_chain_datum_t *) (a_block->meta_n_datum_n_sign + l_offset);
-
     }
     if (l_offset> (a_block_size-sizeof (a_block->hdr))){
         log_it(L_ERROR,"Offset %zd is bigger than block size %zd (without header)", l_offset, (a_block_size-sizeof (a_block->hdr)));
@@ -428,10 +448,11 @@ dap_chain_datum_t** dap_chain_block_get_datums(dap_chain_block_t * a_block, size
 dap_chain_block_meta_t** dap_chain_block_get_meta(dap_chain_block_t * a_block, size_t a_block_size,size_t * a_meta_count )
 {
     if( a_block_size < sizeof(a_block->hdr) ){
-        log_it(L_ERROR,"Meta add: Corrupted block size %zu thats smaller then block header size %zu ", a_block_size, sizeof (a_block->hdr));
+        log_it(L_ERROR,"Get meta: corrupted block size %zu thats smaller then block header size %zu", a_block_size, sizeof (a_block->hdr));
     }
-    *a_meta_count = a_block->hdr.meta_count;
-    if (a_block->hdr.meta_count ==0) // no meta - nothing to return
+    if (a_meta_count)
+        *a_meta_count = 0;
+    if (a_block->hdr.meta_count == 0) // no meta - nothing to return
         return NULL;
     size_t l_offset = 0;
     dap_chain_block_meta_t * l_meta=NULL;
@@ -443,11 +464,13 @@ dap_chain_block_meta_t** dap_chain_block_get_meta(dap_chain_block_t * a_block, s
         size_t l_meta_data_size = l_meta->hdr.data_size;
         if (l_meta_data_size + sizeof (l_meta->hdr) + l_offset <= (a_block_size-sizeof (a_block->hdr)) ){
             l_ret[i] = l_meta;
-            (*a_meta_count)++;
-            l_offset += sizeof (l_meta->hdr);
-            l_offset += l_meta_data_size;
-        }else
-            l_offset = (a_block_size-sizeof (a_block->hdr));
+            if (a_meta_count)
+                (*a_meta_count)++;
+            l_offset += sizeof(l_meta->hdr) + l_meta_data_size;
+        }else {
+            log_it(L_WARNING, "Get meta: corrupted block, can read only %zu from %hu metas", i, a_block->hdr.meta_count);
+            return l_ret;
+        }
     }
     return l_ret;
 }
@@ -465,6 +488,7 @@ dap_chain_block_meta_t** dap_chain_block_get_meta(dap_chain_block_t * a_block, s
 void dap_chain_block_meta_extract(dap_chain_block_meta_t ** a_meta, size_t a_meta_count,
                                     dap_chain_hash_fast_t * a_block_prev_hash,
                                     dap_chain_hash_fast_t * a_block_anchor_hash,
+                                    dap_chain_hash_fast_t *a_merkle,
                                     dap_chain_hash_fast_t ** a_block_links,
                                     size_t *a_block_links_count,
                                     bool * a_is_genesis,
@@ -472,12 +496,15 @@ void dap_chain_block_meta_extract(dap_chain_block_meta_t ** a_meta, size_t a_met
                                     uint64_t *a_nonce2
                                   )
 {
+    if (!a_meta || !a_meta_count)
+        return;
     // Check for meta that could be faced only once
     bool l_was_prev = false;
     bool l_was_genesis = false;
     bool l_was_anchor = false;
     bool l_was_nonce = false;
     bool l_was_nonce2 = false;
+    bool l_was_merkle = false;
     // Init links parsing
     size_t l_links_count_max = 5;
     if (a_block_links_count)
@@ -563,7 +590,20 @@ void dap_chain_block_meta_extract(dap_chain_block_meta_t ** a_meta, size_t a_met
                     if (l_meta->hdr.data_size == sizeof (*a_nonce2 ) )
                         memcpy(a_nonce2, l_meta->data, l_meta->hdr.data_size);
                     else
-                        log_it(L_WARNING, "NONCE2 meta #%zd has wrong size %hu when expecting %zu",i, l_meta->hdr.data_size, sizeof (*a_nonce2));
+                        log_it(L_WARNING, "NONCE2 meta #%zu has wrong size %hu when expecting %zu",i, l_meta->hdr.data_size, sizeof (*a_nonce2));
+                }
+            break;
+            case DAP_CHAIN_BLOCK_META_MERKLE:
+                if(l_was_merkle){
+                    log_it(L_WARNING, "Merckle root could be only one in the block, meta #%zu is ignored ", i);
+                    break;
+                }
+                l_was_merkle = true;
+                if (a_merkle) {
+                    if (l_meta->hdr.data_size == sizeof(*a_merkle))
+                        memcpy(a_merkle, l_meta->data, l_meta->hdr.data_size);
+                    else
+                        log_it(L_WARNING, "Merkle root meta #%zu has wrong size %hu when expecting %zu", i, l_meta->hdr.data_size, sizeof (*a_nonce2));
                 }
             break;
             default: { log_it(L_WARNING, "Unknown meta #%zu type 0x%02hx (size %hu), possible corrupted block or you need to upgrade your software",
diff --git a/modules/type/blocks/dap_chain_block_cache.c b/modules/type/blocks/dap_chain_block_cache.c
index 685e736fca54f309a9857a905949908f484545b6..49eaa19c068c53cadb3121d7e915c795889e453a 100644
--- a/modules/type/blocks/dap_chain_block_cache.c
+++ b/modules/type/blocks/dap_chain_block_cache.c
@@ -53,7 +53,7 @@ void dap_chain_block_cache_deinit()
  * @param a_block_size
  * @return
  */
-dap_chain_block_cache_t * dap_chain_block_cache_new(dap_chain_block_t * a_block, size_t a_block_size)
+dap_chain_block_cache_t * dap_chain_block_cache_new(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t * a_block, size_t a_block_size)
 {
     if (! a_block)
         return NULL;
@@ -61,8 +61,12 @@ dap_chain_block_cache_t * dap_chain_block_cache_new(dap_chain_block_t * a_block,
     dap_chain_block_cache_t * l_block_cache = DAP_NEW_Z(dap_chain_block_cache_t);
     l_block_cache->block = a_block;
     l_block_cache->block_size= a_block_size;
-    dap_chain_block_cache_update(l_block_cache);
-
+    l_block_cache->_inheritor = a_blocks;
+    if (dap_chain_block_cache_update(l_block_cache)) {
+        log_it(L_WARNING, "Block cache can't be created, possible cause corrupted block inside");
+        DAP_DELETE(l_block_cache);
+        return NULL;
+    }
     log_it(L_DEBUG,"Block cache created");
     return l_block_cache;
 }
@@ -84,26 +88,35 @@ dap_chain_block_cache_t * dap_chain_block_cache_dup(dap_chain_block_cache_t * a_
  * @brief dap_chain_block_cache_update
  * @param a_block_cache
  */
-void dap_chain_block_cache_update(dap_chain_block_cache_t * a_block_cache)
+int dap_chain_block_cache_update(dap_chain_block_cache_t * a_block_cache)
 {
     assert(a_block_cache);
     assert(a_block_cache->block);
     dap_hash_fast(a_block_cache->block, a_block_cache->block_size, &a_block_cache->block_hash);
+    if (a_block_cache->meta)
+        DAP_DELETE(a_block_cache->meta);
     if (a_block_cache->datum)
         DAP_DELETE(a_block_cache->datum);
-    a_block_cache->datum = dap_chain_block_get_datums( a_block_cache->block, a_block_cache->block_size, &a_block_cache->datum_count );
-    a_block_cache->meta = dap_chain_block_get_meta (a_block_cache->block, a_block_cache->block_size, &a_block_cache->meta_count);
-
+    a_block_cache->meta = dap_chain_block_get_meta(a_block_cache->block, a_block_cache->block_size, &a_block_cache->meta_count);
+    if (a_block_cache->meta_count != a_block_cache->block->hdr.meta_count) {
+        DAP_DELETE(a_block_cache->meta);
+        return -1;
+    }
     dap_chain_block_meta_extract( a_block_cache->meta,a_block_cache->meta_count,
                                         &a_block_cache->prev_hash,
                                         &a_block_cache->anchor_hash,
+                                        &a_block_cache->merkle_root,
                                         &a_block_cache->links_hash,
                                         &a_block_cache->links_hash_count,
                                         &a_block_cache->is_genesis,
                                         &a_block_cache->nonce,
                                         &a_block_cache->nonce2
                                       );
-
+    a_block_cache->datum = dap_chain_block_get_datums( a_block_cache->block, a_block_cache->block_size, &a_block_cache->datum_count );
+    if (a_block_cache->datum_count != a_block_cache->block->hdr.datum_count) {
+        DAP_DELETE(a_block_cache->datum);
+        return -2;
+    }
     for (size_t i = 0; i< a_block_cache->datum_count; i++){
         dap_chain_datum_t * l_datum = a_block_cache->datum[i];
         if ( l_datum && l_datum->header.data_size && l_datum->header.type_id == DAP_CHAIN_DATUM_TX){
@@ -119,6 +132,7 @@ void dap_chain_block_cache_update(dap_chain_block_cache_t * a_block_cache)
             }
         }
     }
+    return 0;
 }
 
 /**
@@ -143,4 +157,3 @@ void dap_chain_block_cache_delete(dap_chain_block_cache_t * a_block_cache)
     DAP_DELETE(a_block_cache);
     log_it(L_DEBUG,"Block cache deleted");
 }
-
diff --git a/modules/type/blocks/dap_chain_block_chunk.c b/modules/type/blocks/dap_chain_block_chunk.c
index 4661144d4cee82461ff92dd7e30e642f65beff43..76a2a15f4562531ec96ff25b408ad3ba46133506 100644
--- a/modules/type/blocks/dap_chain_block_chunk.c
+++ b/modules/type/blocks/dap_chain_block_chunk.c
@@ -44,7 +44,7 @@ dap_chain_block_chunks_t * dap_chain_block_chunks_create(dap_chain_cs_blocks_t *
     size_t l_objs_count =0;
     dap_global_db_obj_t * l_objs= dap_chain_global_db_gr_load(l_ret->gdb_group, &l_objs_count);
     for(size_t n=0; n< l_objs_count; n++){
-        dap_chain_block_cache_t * l_block_cache = dap_chain_block_cache_new((dap_chain_block_t*) l_objs[n].value,l_objs[n].value_len);
+        dap_chain_block_cache_t *l_block_cache = dap_chain_block_cache_new(a_blocks, (dap_chain_block_t*)l_objs[n].value, l_objs[n].value_len);
         dap_chain_block_chunks_add(l_ret, l_block_cache );
     }
     dap_chain_global_db_objs_delete(l_objs,l_objs_count);
@@ -84,6 +84,8 @@ void dap_chain_block_chunks_delete(dap_chain_block_chunks_t * a_chunks)
  */
 void dap_chain_block_chunks_add(dap_chain_block_chunks_t * a_chunks,dap_chain_block_cache_t  * a_block_cache)
 {
+    if (!a_block_cache)
+        return;
     dap_chain_block_cache_hash_t  * l_chunk_cache_hash = NULL;
     // Parse block and produce cache object
     dap_chain_block_t *l_block = a_block_cache->block;
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index ed9170c9f0d9e21de15cff38b54556cc31d4e73e..276a349df52e7985a1e9c27f064016f2920e7648 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -26,12 +26,13 @@
 #include "dap_common.h"
 #include "dap_enc_base58.h"
 #include "dap_chain.h"
+#include "dap_chain_cell.h"
 #include "dap_chain_cs.h"
 #include "dap_chain_cs_blocks.h"
 #include "dap_chain_block.h"
 #include "dap_chain_block_cache.h"
 #include "dap_chain_block_chunk.h"
-
+#include "dap_timerfd.h"
 #include "dap_chain_node_cli.h"
 #include "dap_chain_node_cli_cmd.h"
 #define LOG_TAG "dap_chain_cs_blocks"
@@ -59,7 +60,7 @@ typedef struct dap_chain_cs_blocks_pvt
 
     dap_chain_tx_block_index_t * tx_block_index; // To find block hash by tx hash
 
-    // General lins
+    // General links
     dap_chain_block_cache_t * block_cache_first; // Mapped area start
     dap_chain_block_cache_t * block_cache_last; // Last block in mapped area
     dap_chain_hash_fast_t genesis_block_hash;
@@ -71,6 +72,10 @@ typedef struct dap_chain_cs_blocks_pvt
     size_t block_size_maximum; // Maximum block size
     bool is_celled;
 
+    dap_timerfd_t *fill_timer;
+    pthread_rwlock_t datums_lock;
+    uint64_t fill_timeout;
+
 } dap_chain_cs_blocks_pvt_t;
 
 typedef struct dap_chain_cs_blocks_iter
@@ -79,7 +84,7 @@ typedef struct dap_chain_cs_blocks_iter
     dap_chain_block_cache_t * cache;
 } dap_chain_cs_blocks_iter_t;
 
-#define PVT(a) ((dap_chain_cs_blocks_pvt_t *) a->_pvt )
+#define PVT(a) ((dap_chain_cs_blocks_pvt_t *)(a)->_pvt )
 
 #define ITER_PVT(a) ((dap_chain_cs_blocks_iter_t *) a->_inheritor )
 
@@ -122,7 +127,7 @@ static dap_chain_atom_ptr_t *s_callback_atom_iter_get_lasts( dap_chain_atom_iter
 // Delete iterator
 static void s_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_iter );                  //    Get the fisrt block
 
-static size_t s_callback_add_datums(dap_chain_t * a_chain, dap_chain_datum_t ** a_datums, size_t a_datums_size);
+static size_t s_callback_add_datums(dap_chain_t * a_chain, dap_chain_datum_t ** a_datums, size_t a_datums_count);
 
 static bool s_seed_mode=false;
 
@@ -181,6 +186,7 @@ int dap_chain_cs_blocks_new(dap_chain_t * a_chain, dap_config_t * a_chain_config
 {
     dap_chain_cs_blocks_t * l_cs_blocks = DAP_NEW_Z(dap_chain_cs_blocks_t);
     a_chain->_inheritor = l_cs_blocks;
+    l_cs_blocks->chain = a_chain;
 
     a_chain->callback_delete = s_callback_delete;
 
@@ -209,8 +215,8 @@ int dap_chain_cs_blocks_new(dap_chain_t * a_chain, dap_config_t * a_chain_config
 
     dap_chain_cs_blocks_pvt_t *l_cs_blocks_pvt = DAP_NEW_Z(dap_chain_cs_blocks_pvt_t);
     l_cs_blocks->_pvt = l_cs_blocks_pvt;
-    a_chain->_pvt = l_cs_blocks_pvt;
     pthread_rwlock_init(&l_cs_blocks_pvt->rwlock,NULL);
+    pthread_rwlock_init(&l_cs_blocks_pvt->datums_lock, NULL);
 
     const char * l_genesis_blocks_hash_str = dap_config_get_item_str_default(a_chain_config,"blocks","genesis_block",NULL);
     if ( l_genesis_blocks_hash_str ){
@@ -222,15 +228,10 @@ int dap_chain_cs_blocks_new(dap_chain_t * a_chain, dap_config_t * a_chain_config
     l_cs_blocks_pvt->is_celled = dap_config_get_item_bool_default(a_chain_config,"blocks","is_celled",false);
 
     l_cs_blocks_pvt->chunks = dap_chain_block_chunks_create(l_cs_blocks);
-//    dap_chain_node_role_t l_net_role= dap_chain_net_get_role( dap_chain_net_by_id(a_chain->net_id) );
 
-    // Datum operations callbacks
-/*
-    a_chain->callback_datum_iter_create = s_chain_callback_datum_iter_create; // Datum iterator create
-    a_chain->callback_datum_iter_delete = s_chain_callback_datum_iter_delete; // Datum iterator delete
-    a_chain->callback_datum_iter_get_first = s_chain_callback_datum_iter_get_first; // Get the fisrt datum from chain
-    a_chain->callback_datum_iter_get_next = s_chain_callback_datum_iter_get_next; // Get the next datum from chain from the current one
-*/
+    l_cs_blocks_pvt->block_size_maximum = 10 * 1024 * 1024; // 10 Mb
+    l_cs_blocks_pvt->fill_timeout = dap_config_get_item_uint64_default(a_chain_config, "blocks", "fill_timeout", 60) * 1000; // 1 min
+
     return 0;
 }
 
@@ -240,8 +241,7 @@ int dap_chain_cs_blocks_new(dap_chain_t * a_chain, dap_config_t * a_chain_config
  */
 void dap_chain_cs_blocks_delete(dap_chain_t * a_chain)
 {
-   pthread_rwlock_destroy(&PVT( DAP_CHAIN_CS_BLOCKS(a_chain) )->rwlock );
-   dap_chain_block_chunks_delete(PVT(DAP_CHAIN_CS_BLOCKS(a_chain))->chunks );
+    s_callback_delete(a_chain);
 }
 
 /**
@@ -381,8 +381,9 @@ static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply)
             pthread_rwlock_wrlock( &PVT(l_blocks)->rwlock );
             if ( l_blocks->block_new )
                 DAP_DELETE( l_blocks->block_new );
-            l_blocks->block_new = dap_chain_block_new( PVT(l_blocks)->block_cache_last? &PVT(l_blocks)->block_cache_last->block_hash: NULL );
-            l_blocks->block_new_size = sizeof (l_blocks->block_new->hdr);
+            l_blocks->block_new = dap_chain_block_new(PVT(l_blocks)->block_cache_last ?
+                                                      &PVT(l_blocks)->block_cache_last->block_hash : NULL,
+                                                      &l_blocks->block_new_size);
             pthread_rwlock_unlock( &PVT(l_blocks)->rwlock );
         } break;
 
@@ -476,7 +477,7 @@ static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply)
                         dap_chain_block_meta_t * l_meta = l_block_cache->meta[i];
                         switch (l_meta->hdr.type) {
                             case DAP_CHAIN_BLOCK_META_GENESIS:{
-                                dap_string_append_printf(l_str_tmp,"\t\tGENESIS\n");
+                                dap_string_append_printf(l_str_tmp, "\t\tGENESIS\n");
                             }break;
                             case DAP_CHAIN_BLOCK_META_PREV:{
                                 s_cli_meta_hash_print(l_str_tmp, "PREV", l_meta);
@@ -594,6 +595,8 @@ static void s_callback_delete(dap_chain_t * a_chain)
         DAP_DELETE(l_blocks->_pvt);
     pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
     pthread_rwlock_destroy(&PVT(l_blocks)->rwlock);
+    pthread_rwlock_destroy(&PVT(l_blocks)->datums_lock);
+    dap_chain_block_chunks_delete(PVT(l_blocks)->chunks );
     log_it(L_INFO,"callback_delete() called");
 }
 
@@ -676,9 +679,7 @@ static int s_add_atom_to_blocks(dap_chain_cs_blocks_t * a_blocks, dap_ledger_t *
         pthread_rwlock_unlock( &PVT(a_blocks)->rwlock );
         res = s_add_atom_to_ledger(a_blocks, a_ledger, a_block_cache);
         if (res) {
-            pthread_rwlock_rdlock( &PVT(a_blocks)->rwlock );
             log_it(L_INFO,"Block %s checked, but ledger declined", a_block_cache->block_hash_str );
-            pthread_rwlock_unlock( &PVT(a_blocks)->rwlock );
             return res;
         }
         //All correct, no matter for result
@@ -686,7 +687,8 @@ static int s_add_atom_to_blocks(dap_chain_cs_blocks_t * a_blocks, dap_ledger_t *
         HASH_ADD(hh, PVT(a_blocks)->blocks,block_hash,sizeof (a_block_cache->block_hash), a_block_cache);
         if (! (PVT(a_blocks)->block_cache_first ) )
                 PVT(a_blocks)->block_cache_first = a_block_cache;
-        PVT(a_blocks)->block_cache_last->next = a_block_cache;
+        if (PVT(a_blocks)->block_cache_last)
+            PVT(a_blocks)->block_cache_last->next = a_block_cache;
         a_block_cache->prev = PVT(a_blocks)->block_cache_last;
         PVT(a_blocks)->block_cache_last = a_block_cache;
 
@@ -779,7 +781,11 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
         log_it(L_DEBUG, "... already present in blocks %s",l_block_cache->block_hash_str);
         return ATOM_PASS;
     } else {
-        l_block_cache = dap_chain_block_cache_new( l_block, l_block_size);
+        l_block_cache = dap_chain_block_cache_new(l_blocks, l_block, l_block_size);
+        if (!l_block_cache) {
+            log_it(L_DEBUG, "... corrupted block");
+            return ATOM_REJECT;
+        }
         log_it(L_DEBUG, "... new block %s",l_block_cache->block_hash_str);
         ret = ATOM_ACCEPT;
     }
@@ -787,7 +793,8 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
     // verify hashes and consensus
     if(ret == ATOM_ACCEPT){
         ret = s_callback_atom_verify (a_chain, a_atom, a_atom_size);
-        log_it(L_DEBUG, "Verified atom %p: code %d", a_atom, ret);
+        log_it(L_DEBUG, "Verified atom %p: %s", a_atom, ret == ATOM_ACCEPT ? "accepted" :
+                                                       (ret == ATOM_REJECT ? "rejected" : "thresholded"));
     }
 
     if( ret == ATOM_ACCEPT){
@@ -847,6 +854,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain,
                                         &l_block_anchor_hash,
                                         NULL,
                                         NULL,
+                                        NULL,
                                         &l_is_genesis,
                                         &l_nonce,
                                         &l_nonce2 ) ;
@@ -863,7 +871,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain,
                 log_it(L_NOTICE,"Accepting new genesis block");
                 return ATOM_ACCEPT;
             }else if(s_seed_mode){
-                log_it(L_WARNING,"Cant accept genesis blockt: already present data in blockchain");
+                log_it(L_WARNING,"Cant accept genesis block: already present data in blockchain");
                 return  ATOM_REJECT;
             }
         }else{
@@ -915,7 +923,8 @@ static dap_chain_atom_iter_t* s_callback_atom_iter_create_from(dap_chain_t * a_c
         dap_hash_fast(a_atom, a_atom_size, &l_atom_hash);
         dap_chain_atom_iter_t * l_atom_iter = s_callback_atom_iter_create(a_chain);
         if (l_atom_iter){
-            l_atom_iter->cur_item =ITER_PVT(l_atom_iter)->cache = dap_chain_block_cache_get_by_hash(l_atom_hash);
+            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 = a_atom;
             l_atom_iter->cur_size = a_atom_size;
             return l_atom_iter;
@@ -961,7 +970,7 @@ static dap_chain_datum_tx_t* s_callback_atom_iter_find_by_tx_hash(dap_chain_t *
     dap_chain_tx_block_index_t * l_tx_block_index = NULL;
     HASH_FIND(hh, PVT(l_cs_blocks)->tx_block_index,a_tx_hash, sizeof (*a_tx_hash), l_tx_block_index);
     if (l_tx_block_index){
-        dap_chain_block_cache_t * l_block_cache = dap_chain_block_cache_get_by_hash( l_tx_block_index->block_hash );
+        dap_chain_block_cache_t *l_block_cache = dap_chain_block_cs_cache_get_by_hash(l_cs_blocks, &l_tx_block_index->block_hash);
         if ( l_block_cache){
             return dap_chain_block_cache_get_tx_by_hash(l_block_cache, a_tx_hash);
         }else
@@ -1050,7 +1059,8 @@ static dap_chain_atom_ptr_t *s_callback_atom_iter_get_links( dap_chain_atom_iter
             *a_links_size = l_block_cache->links_hash_count;
             dap_chain_atom_ptr_t * l_ret = DAP_NEW_Z_SIZE(dap_chain_atom_ptr_t, l_block_cache->links_hash_count *sizeof (dap_chain_atom_ptr_t) );
             for (size_t i = 0; i< l_block_cache->links_hash_count; i ++){
-                dap_chain_block_cache_t * l_link =  dap_chain_block_cache_get_by_hash(l_block_cache->links_hash[i]);
+                dap_chain_cs_blocks_t *l_cs_blocks = (dap_chain_cs_blocks_t *)l_block_cache->_inheritor;
+                dap_chain_block_cache_t *l_link =  dap_chain_block_cs_cache_get_by_hash(l_cs_blocks, &l_block_cache->links_hash[i]);
                 assert(l_link);
                 (*a_links_size_ptr)[i] = l_link->block_size;
                 l_ret[i] = l_link->block;
@@ -1098,6 +1108,35 @@ static void s_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_iter )
     DAP_DELETE(a_atom_iter);
 }
 
+static int s_new_block_complete(dap_chain_cs_blocks_t *a_blocks)
+{
+    dap_hash_fast_t l_merkle_root = {};     // TODO compute the merkle root of block's datums
+    a_blocks->block_new_size = dap_chain_block_meta_add(&a_blocks->block_new, a_blocks->block_new_size,
+                                                        DAP_CHAIN_BLOCK_META_MERKLE, &l_merkle_root, sizeof(l_merkle_root));
+    size_t l_signed_size = a_blocks->callback_block_sign(a_blocks, &a_blocks->block_new, a_blocks->block_new_size);
+    if (l_signed_size)
+        a_blocks->block_new_size = l_signed_size;
+    else {
+        log_it(L_WARNING, "Block signing failed");
+        return -1;
+    }
+    dap_chain_atom_verify_res_t l_res = s_callback_atom_add(a_blocks->chain, a_blocks->block_new, a_blocks->block_new_size);
+    DAP_DEL_Z(a_blocks->block_new);
+    if (l_res == ATOM_ACCEPT)
+        return 0;
+    return -2;
+}
+
+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;
+    return false;
+}
+
 /**
  * @brief s_callback_datums_pool_proc
  * @param a_chain
@@ -1105,13 +1144,31 @@ static void s_callback_atom_iter_delete(dap_chain_atom_iter_t * a_atom_iter )
  * @param a_datums_size
  * @return
  */
-static size_t s_callback_add_datums(dap_chain_t * a_chain, dap_chain_datum_t ** a_datums, size_t a_datums_size)
+static size_t s_callback_add_datums(dap_chain_t *a_chain, dap_chain_datum_t **a_datums, size_t a_datums_count)
 {
-    // IMPORTANT - all datums on input should be checket before for curruption because datum size is taken from datum's header
-    for (size_t i = 0; i < a_datums_size; i++) {
-        DAP_CHAIN_CS_BLOCKS(a_chain)->block_new_size = dap_chain_block_datum_add( &DAP_CHAIN_CS_BLOCKS(a_chain)->block_new,
-                                                                                         DAP_CHAIN_CS_BLOCKS(a_chain)->block_new_size,
-                                                                                         a_datums[i],dap_chain_datum_size(a_datums[i]) );
+    dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
+    dap_chain_cs_blocks_pvt_t *l_blocks_pvt = PVT(l_blocks);
+    // IMPORTANT - all datums on input should be checked before for curruption because datum size is taken from datum's header
+    pthread_rwlock_wrlock(&l_blocks_pvt->datums_lock);
+    if (!l_blocks->block_new) {
+        l_blocks->block_new = dap_chain_block_new(&l_blocks_pvt->block_cache_last->block_hash, &l_blocks->block_new_size);
+        dap_chain_net_t *l_net = dap_chain_net_by_id(l_blocks->chain->net_id);
+        l_blocks->block_new->hdr.cell_id.uint64 = l_net->pub.cell_id.uint64;
+        l_blocks->block_new->hdr.chain_id.uint64 = l_blocks->chain->id.uint64;
+    }
+    for (size_t i = 0; i < a_datums_count; i++) {
+        size_t l_datum_size = dap_chain_datum_size(a_datums[i]);
+        if (l_blocks->block_new_size + l_datum_size > l_blocks_pvt->block_size_maximum) {
+            s_new_block_complete(l_blocks);
+            pthread_rwlock_unlock(&l_blocks_pvt->datums_lock);
+            s_callback_add_datums(a_chain, &a_datums[i], a_datums_count - i);
+            pthread_rwlock_wrlock(&l_blocks_pvt->datums_lock);
+        }
+        l_blocks->block_new_size = dap_chain_block_datum_add(&l_blocks->block_new, l_blocks->block_new_size,
+                                                             a_datums[i], l_datum_size);
     }
-    return DAP_CHAIN_CS_BLOCKS(a_chain)->block_new_size;
+    if (!l_blocks_pvt->fill_timer)
+        l_blocks_pvt->fill_timer = dap_timerfd_start(l_blocks_pvt->fill_timeout, s_callback_datums_timer, l_blocks);
+    pthread_rwlock_unlock(&l_blocks_pvt->datums_lock);
+    return l_blocks->block_new_size;
 }
diff --git a/modules/type/blocks/include/dap_chain_block.h b/modules/type/blocks/include/dap_chain_block.h
index 6364350205650328e7e49866169e9280b064cc9d..bcb81167a6f6fcb9b1df12d2d1347583c544c14b 100644
--- a/modules/type/blocks/include/dap_chain_block.h
+++ b/modules/type/blocks/include/dap_chain_block.h
@@ -69,6 +69,7 @@ typedef struct dap_chain_block_meta{
 #define DAP_CHAIN_BLOCK_META_LINK              0x12
 #define DAP_CHAIN_BLOCK_META_NONCE             0x20
 #define DAP_CHAIN_BLOCK_META_NONCE2            0x21
+#define DAP_CHAIN_BLOCK_META_MERKLE            0x30
 
 
 /**
@@ -86,7 +87,7 @@ int dap_chain_block_init();
 void dap_chain_block_deinit();
 
 // Create new block
-dap_chain_block_t * dap_chain_block_new(dap_chain_hash_fast_t * a_prev_block );
+dap_chain_block_t *dap_chain_block_new(dap_chain_hash_fast_t *a_prev_block, size_t *a_block_size);
 
 // Add metadata in block
 size_t dap_chain_block_meta_add(dap_chain_block_t ** a_block_ptr, size_t a_block_size, uint8_t a_meta_type, const void * a_data, size_t a_data_size);
@@ -96,8 +97,10 @@ size_t dap_chain_block_datum_add(dap_chain_block_t ** a_block_ptr, size_t a_bloc
 size_t dap_chain_block_datum_del_by_hash(dap_chain_block_t ** a_block_ptr, size_t a_block_size, dap_chain_hash_fast_t* a_datum_hash);
 
 // Add sign in block
-size_t dap_chain_block_sign_add( dap_chain_block_t ** a_block_ptr, size_t a_block_size, dap_cert_t * a_cert );
+size_t dap_chain_block_sign_add(dap_chain_block_t ** a_block_ptr, size_t a_block_size, dap_enc_key_t *a_key);
 dap_sign_t *dap_chain_block_sign_get ( dap_chain_block_t * a_block_ptr, size_t a_block_size, uint16_t a_sign_num );
+size_t dap_chain_block_get_signs_count(dap_chain_block_t * a_block, size_t a_block_size);
+size_t dap_chain_block_get_sign_offset(dap_chain_block_t *a_block, size_t a_block_size);
 
 // Create and return datums list
 dap_chain_datum_t** dap_chain_block_get_datums(dap_chain_block_t * a_block, size_t a_block_size,size_t * a_datums_count );
@@ -108,6 +111,7 @@ dap_chain_block_meta_t** dap_chain_block_get_meta(dap_chain_block_t * a_block, s
 void dap_chain_block_meta_extract(dap_chain_block_meta_t ** a_meta, size_t a_meta_count,
                                     dap_chain_hash_fast_t * a_block_prev_hash,
                                     dap_chain_hash_fast_t * a_block_anchor_hash,
+                                    dap_chain_hash_fast_t *a_merkle,
                                     dap_chain_hash_fast_t ** a_block_links,
                                     size_t *a_block_links_count,
                                     bool * a_is_genesis,
diff --git a/modules/type/blocks/include/dap_chain_block_cache.h b/modules/type/blocks/include/dap_chain_block_cache.h
index f89199984f8150814f3e84d932d5729a5ca1566c..01f0a8d3b616edc569d6b42c0cf186c8bdb95c0b 100644
--- a/modules/type/blocks/include/dap_chain_block_cache.h
+++ b/modules/type/blocks/include/dap_chain_block_cache.h
@@ -27,6 +27,8 @@
 #include "dap_hash.h"
 #include "uthash.h"
 
+typedef struct dap_chain_cs_blocks dap_chain_cs_blocks_t;
+
 typedef struct dap_chain_block_cache_tx_index
 {
     dap_chain_hash_fast_t tx_hash;
@@ -55,6 +57,7 @@ typedef struct dap_chain_block_cache{
     // Extracted metadata
     dap_chain_hash_fast_t prev_hash;
     dap_chain_hash_fast_t anchor_hash;
+    dap_chain_hash_fast_t merkle_root;
     dap_chain_hash_fast_t* links_hash;
     size_t links_hash_count;
 
@@ -83,10 +86,9 @@ typedef struct dap_chain_block_cache{
 int dap_chain_block_cache_init();
 void dap_chain_block_cache_deinit();
 
-dap_chain_block_cache_t * dap_chain_block_cache_get_by_hash(dap_chain_hash_fast_t a_block_hash);
-dap_chain_block_cache_t * dap_chain_block_cache_new(dap_chain_block_t * a_block, size_t a_block_size);
+dap_chain_block_cache_t * dap_chain_block_cache_new(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_t * a_block, size_t a_block_size);
 dap_chain_block_cache_t * dap_chain_block_cache_dup(dap_chain_block_cache_t * a_block);
-void dap_chain_block_cache_update(dap_chain_block_cache_t * a_block_cache);
+int dap_chain_block_cache_update(dap_chain_block_cache_t * a_block_cache);
 void dap_chain_block_cache_delete(dap_chain_block_cache_t * a_block_cache);
 dap_chain_datum_tx_t* dap_chain_block_cache_get_tx_by_hash (dap_chain_block_cache_t * a_block_cache, dap_chain_hash_fast_t * a_tx_hash);
 
diff --git a/modules/type/blocks/include/dap_chain_cs_blocks.h b/modules/type/blocks/include/dap_chain_cs_blocks.h
index a60432337e1c28e84feaf742dad563eaccb9c7c7..87c662785ea28ca3abd1a8ca0a83e5b54c1df8bd 100644
--- a/modules/type/blocks/include/dap_chain_cs_blocks.h
+++ b/modules/type/blocks/include/dap_chain_cs_blocks.h
@@ -30,7 +30,8 @@
 typedef struct dap_chain_cs_blocks dap_chain_cs_blocks_t;
 
 typedef void (*dap_chain_cs_blocks_callback_t)(dap_chain_cs_blocks_t *);
-typedef int (*dap_chain_cs_blocks_callback_block_t)(dap_chain_cs_blocks_t *, dap_chain_block_t *,size_t);
+typedef int (*dap_chain_cs_blocks_callback_block_t)(dap_chain_cs_blocks_t *, dap_chain_block_t *, size_t);
+typedef size_t (*dap_chain_cs_blocks_callback_block_sign_t)(dap_chain_cs_blocks_t *, dap_chain_block_t **, size_t);
 
 
 
@@ -50,6 +51,7 @@ typedef struct dap_chain_cs_blocks
     dap_chain_cs_blocks_callback_t callback_delete;
     dap_chain_cs_blocks_callback_block_create_t callback_block_create;
     dap_chain_cs_blocks_callback_block_t callback_block_verify;
+    dap_chain_cs_blocks_callback_block_sign_t callback_block_sign;
     void * _pvt;
     void * _inheritor;
 } dap_chain_cs_blocks_t;
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index 4241cba8a77956d3dd257d73ac11b9a429aaf43d..6309d93a2d6ae461da38021570d6adcd20bfadf2 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -398,7 +398,8 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
     case ATOM_ACCEPT:
         ret = s_chain_callback_atom_verify(a_chain, a_atom, a_atom_size);
         if(s_debug_more)
-            log_it(L_DEBUG, "Verified atom %p: code %d", a_atom, ret);
+            log_it(L_DEBUG, "Verified atom %p: %s", a_atom, ret == ATOM_ACCEPT ? "accepted" :
+                                                           (ret == ATOM_REJECT ? "rejected" : "thresholded"));
         break;
     case ATOM_PASS:
         if(s_debug_more) {