From 94965421872e0c75691e6e5e2cec6d43246ee752 Mon Sep 17 00:00:00 2001
From: "Dmitriy A. Gerasimov" <dmitriy.gerasimov@demlabs.net>
Date: Sun, 8 Nov 2020 21:09:04 +0700
Subject: [PATCH] [+] Blockchain PoA consensus

---
 modules/CMakeLists.txt                        |   5 +
 modules/consensus/block-poa/CMakeLists.txt    |   8 +-
 .../block-poa/dap_chain_cs_block_poa.c        | 287 +++++++++++++++++-
 .../include/dap_chain_cs_block_poa.h          |  29 +-
 .../consensus/dag-poa/dap_chain_cs_dag_poa.c  |  14 +-
 .../dag-poa/include/dap_chain_cs_dag_poa.h    |  14 +-
 modules/type/blocks/dap_chain_block.c         |  84 +++++
 modules/type/blocks/dap_chain_cs_blocks.c     |  21 +-
 modules/type/blocks/include/dap_chain_block.h |   7 +-
 .../type/blocks/include/dap_chain_cs_blocks.h |   3 +
 10 files changed, 417 insertions(+), 55 deletions(-)

diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
index 2b3c7d0eac..ab3cfcab2b 100644
--- a/modules/CMakeLists.txt
+++ b/modules/CMakeLists.txt
@@ -57,6 +57,11 @@ if (CELLFRAME_MODULES MATCHES "cs-dag-pos")
     add_subdirectory(consensus/dag-pos)
 endif()
 
+# Blocks PoA
+if (CELLFRAME_MODULES MATCHES "cs-blocks-poa")
+    add_subdirectory(consensus/block-poa)
+endif()
+
 # Service App
 if (CELLFRAME_MODULES MATCHES "srv-app")
     add_subdirectory(service/app)
diff --git a/modules/consensus/block-poa/CMakeLists.txt b/modules/consensus/block-poa/CMakeLists.txt
index 0b44e6775e..5fa1723d36 100644
--- a/modules/consensus/block-poa/CMakeLists.txt
+++ b/modules/consensus/block-poa/CMakeLists.txt
@@ -1,13 +1,11 @@
 cmake_minimum_required(VERSION 2.8)
 project (dap_chain_cs_block_poa)
-  
+
 file(GLOB DAP_CHAIN_BLOCK_CS_POA_SRCS *.c)
 file(GLOB DAP_CHAIN_BLOCK_CS_POA_HEADERS include/*.h)
 
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_BLOCK_CS_POA_SRCS} ${DAP_CHAIN_BLOCK_CS_POA_HEADERS})
-add_definitions ("-DDAP_CHAIN_BLOCK_CS_POA")
-
 
-target_link_libraries(dap_chain_cs_block_poa dap_core dap_crypto dap_chain dap_chain_cs_block )
+target_link_libraries(dap_chain_cs_block_poa dap_core dap_crypto dap_chain dap_chain_cs_blocks dap_chain_net_srv_stake)
 target_include_directories(dap_chain_cs_block_poa INTERFACE .)
-
+target_include_directories(${PROJECT_NAME} PUBLIC include)
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 be64d5d40b..5aa85e5aa8 100644
--- a/modules/consensus/block-poa/dap_chain_cs_block_poa.c
+++ b/modules/consensus/block-poa/dap_chain_cs_block_poa.c
@@ -1,45 +1,304 @@
 /*
  * Authors:
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2018
+ * DeM Labs Limited https://demlabs.net
+ * DAP SDK          https://gitlab.demlabs.net/dap/dap-sdk
+ * Copyright  (c) 2017
  * All rights reserved.
 
- This file is part of DAP (Deus Applications Prototypes) the open source project
+ This file is part of DAP SDK the open source project
 
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    DAP SDK 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,
+    DAP SDK 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/>.
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "dap_common.h"
-#include "dap_chain_cs_block_poa.h"
+#include "dap_strfuncs.h"
+#include "dap_enc_base58.h"
+#include "dap_cert.h"
 #include "dap_chain.h"
+#include "dap_chain_block.h"
+#include "dap_chain_block_cache.h"
+#include "dap_chain_cs_blocks.h"
+#include "dap_chain_cs_block_poa.h"
+#include "dap_chain_net.h"
+#include "dap_chain_node_cli.h"
+#include "dap_chain_node_cli_cmd.h"
+#include "dap_chain_global_db.h"
+#include "dap_chain_cs.h"
 #include "dap_chain_cs_blocks.h"
+#include "dap_chain_net_srv_stake.h"
 
 #define LOG_TAG "dap_chain_cs_block_poa"
 
-dap_chain_t *s_callback_chain_new();
-void s_callback_delete(dap_chain_t * );
-void s_callback_blocks(dap_chain_cs_blocks_t *, dap_chain_block_t * );
 
-int dap_chain_cs_block_poa_init()
+typedef struct dap_chain_cs_dag_poa_pvt
 {
-//    dap_chain_block_cs_add
+    dap_cert_t * sign_cert;
+    dap_cert_t ** auth_certs;
+    char * auth_certs_prefix;
+    uint16_t auth_certs_count;
+    uint16_t auth_certs_count_verify; // Number of signatures, needed for event verification
+
+    dap_chain_callback_new_cfg_t prev_callback_created; // global network config init
+} dap_chain_cs_block_poa_pvt_t;
+
+#define PVT(a) ((dap_chain_cs_block_poa_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);
+
+// CLI commands
+static int s_cli_block_poa(int argc, char ** argv, void *arg_func, char **str_reply);
+
+static bool s_seed_mode = false;
+/**
+ * @brief dap_chain_cs_block_poa_init
+ * @return
+ */
+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"
+            "\tSign new block with certificate <cert name> or withs own PoA certificate\n\n");
+
     return 0;
 }
 
-void dap_chain_cs_block_poa_deinit()
+/**
+ * @brief dap_chain_cs_block_poa_deinit
+ */
+void dap_chain_cs_block_poa_deinit(void)
+{
+
+}
+
+
+
+/**
+ * @brief s_cli_block_poa
+ * @param argc
+ * @param argv
+ * @param arg_func
+ * @param str_reply
+ * @return
+ */
+static int s_cli_block_poa(int argc, char ** argv, void *arg_func, char **a_str_reply)
 {
+    (void) arg_func;
+    int ret = -666;
+    int arg_index = 1;
+    dap_chain_net_t * l_chain_net = NULL;
+    dap_chain_t * l_chain = NULL;
+
+    const char * l_hash_out_type = NULL;
+    dap_chain_node_cli_find_option_val(argv, arg_index, argc, "-H", &l_hash_out_type);
+    if(!l_hash_out_type)
+        l_hash_out_type = "hex";
+    if(dap_strcmp(l_hash_out_type, "hex") && dap_strcmp(l_hash_out_type, "base58")) {
+        dap_chain_node_cli_set_reply_text(a_str_reply, "invalid parameter -H, valid values: -H <hex | base58>");
+        return -1;
+    }
+
+    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);
+
+    // Load cert to sign if its present
+    if (l_cert_str)
+        l_cert = dap_cert_find_by_name( l_cert_str);
+
+    // block hash may be in hex or base58 format
+    char *l_block_hash_hex_str;
+    char *l_event_hash_base58_str;
+    if(!dap_strncmp(l_block_hash_str, "0x", 2) || !dap_strncmp(l_block_hash_str, "0X", 2)) {
+        l_block_hash_hex_str = dap_strdup(l_block_hash_str);
+        l_event_hash_base58_str = dap_enc_base58_from_hex_str_to_str(l_block_hash_str);
+    }
+    else {
+        l_block_hash_hex_str = dap_enc_base58_to_hex_str_from_str(l_block_hash_str);
+        l_event_hash_base58_str = dap_strdup(l_block_hash_str);
+    }
+
+    // Parse block ccmd
+    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 );
+                //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);
+        }
+    }
+    return ret;
 }
+
+/**
+ * @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_create(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 );
+
+    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);
+        l_poa_pvt->auth_certs_count_verify = dap_config_get_item_uint16_default(a_chain_cfg,"block-poa","auth_certs_number_verify",0);
+        l_poa_pvt->auth_certs_prefix = strdup ( dap_config_get_item_str(a_chain_cfg,"block-poa","auth_certs_prefix") );
+        if (l_poa_pvt->auth_certs_count && l_poa_pvt->auth_certs_count_verify ) {
+            l_poa_pvt->auth_certs = DAP_NEW_Z_SIZE ( dap_cert_t *, l_poa_pvt->auth_certs_count * sizeof(dap_cert_t));
+            char l_cert_name[512];
+            for (size_t i = 0; i < l_poa_pvt->auth_certs_count ; i++ ){
+                dap_snprintf(l_cert_name,sizeof(l_cert_name),"%s.%lu",l_poa_pvt->auth_certs_prefix, i);
+                if ( (l_poa_pvt->auth_certs[i] = dap_cert_find_by_name( l_cert_name)) != NULL ) {
+                    log_it(L_NOTICE, "Initialized auth cert \"%s\"", l_cert_name);
+                } else{
+                    log_it(L_ERROR, "Can't find cert \"%s\"", l_cert_name);
+                    return -1;
+                }
+            }
+        }
+    }
+    log_it(L_NOTICE,"Initialized Block-PoA consensus with %u/%u minimum consensus",l_poa_pvt->auth_certs_count,l_poa_pvt->auth_certs_count_verify);
+    // Save old callback if present and set the call of its own (chain callbacks)
+    l_poa_pvt->prev_callback_created = l_blocks->chain->callback_created;
+    l_blocks->chain->callback_created = s_callback_created;
+    return 0;
+}
+
+/**
+ * @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_poa_t * l_poa = DAP_CHAIN_CS_BLOCK_POA( l_blocks );
+
+    // Call previous callback if present. So the first called is the first in
+    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);
+
+    }
+    return 0;
+}
+
+/**
+ * @brief s_chain_cs_dag_callback_delete
+ * @param a_dag
+ */
+static void s_callback_delete(dap_chain_cs_blocks_t * a_blocks)
+{
+    dap_chain_cs_block_poa_t * l_poa = DAP_CHAIN_CS_BLOCK_POA ( a_blocks );
+
+    if ( l_poa->_pvt ) {
+        dap_chain_cs_block_poa_pvt_t * l_poa_pvt = PVT ( l_poa );
+
+        if ( l_poa_pvt->auth_certs )
+            DAP_DELETE ( l_poa_pvt->auth_certs);
+
+        if ( l_poa_pvt->auth_certs_prefix )
+            DAP_DELETE( l_poa_pvt->auth_certs_prefix );
+
+        DAP_DELETE ( l_poa->_pvt);
+    }
+
+    if ( l_poa->_inheritor ) {
+       DAP_DELETE ( l_poa->_inheritor );
+    }
+}
+
+
+/**
+ * @brief s_callbac_block_verify
+ * @param a_blocks
+ * @param a_block
+ * @param a_block_size
+ * @return
+ */
+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_poa_pvt_t * l_poa_pvt = PVT ( DAP_CHAIN_CS_BLOCK_POA( a_blocks ) );
+    uint16_t l_signs_verified_count = 0;
+
+    // Check for first signature
+    dap_sign_t * l_sign = dap_chain_block_sign_get(a_block,a_block_size,0);
+    if (! l_sign){
+        log_it(L_ERROR, "No any signatures at all for block");
+        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_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;
+        }
+        // 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;
+        }
+        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){
+                l_signs_verified_count++;
+                break;
+            }
+        }
+    }
+    return l_signs_verified_count >= l_poa_pvt->auth_certs_count_verify ? 0 : -1;
+}
+
diff --git a/modules/consensus/block-poa/include/dap_chain_cs_block_poa.h b/modules/consensus/block-poa/include/dap_chain_cs_block_poa.h
index 0ee16e38fd..e2bc7b718b 100644
--- a/modules/consensus/block-poa/include/dap_chain_cs_block_poa.h
+++ b/modules/consensus/block-poa/include/dap_chain_cs_block_poa.h
@@ -1,29 +1,40 @@
 /*
  * Authors:
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2018
+ * DeM Labs Limited https://demlabs.net
+ * DAP SDK          https://gitlab.demlabs.net/dap/dap-sdk
+ * Copyright  (c) 2017
  * All rights reserved.
 
- This file is part of DAP (Deus Applications Prototypes) the open source project
+ This file is part of DAP SDK the open source project
 
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    DAP SDK 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,
+    DAP SDK 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/>.
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 #pragma once
+#pragma once
+#include "dap_chain_cs_blocks.h"
+
+typedef struct dap_chain_cs_block_poa
+{
+    dap_chain_t * chain;
+    dap_chain_cs_blocks_t * blocks;
+    void * _pvt;
+    void * _inheritor;
+} dap_chain_cs_block_poa_t;
 
+#define DAP_CHAIN_CS_BLOCK_POA(a) ( (dap_chain_cs_block_poa_t *) (a)->_inheritor)
 
-int dap_chain_cs_block_poa_init();
-void dap_chain_cs_block_poa_deinit();
 
+int dap_chain_cs_block_poa_init(void);
+void dap_chain_cs_block_poa_deinit(void);
diff --git a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
index 0f2e907ceb..0cbf2f2154 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -1,25 +1,25 @@
 /*
  * Authors:
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2019
+ * DeM Labs Limited https://demlabs.net
+ * CellFrame SDK    https://cellframe.net
+ * Copyright  (c) 2019
  * All rights reserved.
 
- This file is part of DAP (Deus Applications Prototypes) the open source project
+ This file is part of CellFrame SDK the open source project
 
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    CellFrame SDK 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,
+    CellFrame SDK 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/>.
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 #include <string.h>
 
diff --git a/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h b/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h
index b6f05be820..cdd0af9ff1 100644
--- a/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h
+++ b/modules/consensus/dag-poa/include/dap_chain_cs_dag_poa.h
@@ -1,25 +1,25 @@
 /*
  * Authors:
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
- * DeM Labs Inc.   https://demlabs.net
- * Kelvin Project https://github.com/kelvinblockchain
- * Copyright  (c) 2017-2019
+ * DeM Labs Limited https://demlabs.net
+ * CellFrame SDK    https://cellframe.net
+ * Copyright  (c) 2019
  * All rights reserved.
 
- This file is part of DAP (Deus Applications Prototypes) the open source project
+ This file is part of CellFrame SDK the open source project
 
-    DAP (Deus Applicaions Prototypes) is free software: you can redistribute it and/or modify
+    CellFrame SDK 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,
+    CellFrame SDK 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/>.
+    along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 #pragma once
 #include "dap_chain_cs_dag.h"
diff --git a/modules/type/blocks/dap_chain_block.c b/modules/type/blocks/dap_chain_block.c
index bace59def8..c504d8a95c 100644
--- a/modules/type/blocks/dap_chain_block.c
+++ b/modules/type/blocks/dap_chain_block.c
@@ -268,6 +268,90 @@ size_t dap_chain_block_datum_del_by_hash(dap_chain_block_t ** a_block_ptr, size_
     return l_offset;
 }
 
+static size_t s_block_get_sign_offset(dap_chain_block_t * a_block, size_t a_block_size)
+{
+    assert(a_block);
+    assert(a_block_size);
+
+    size_t l_offset = s_block_get_datum_offset(a_block,a_block_size);
+    dap_chain_datum_t * l_datum =(dap_chain_datum_t *) (a_block->meta_n_datum_n_sign + l_offset);
+    // Pass all datums to the end
+    for(size_t n=0; n<a_block->hdr.datum_count && l_offset<a_block_size ; n++){
+        size_t l_datum_size = dap_chain_datum_size(l_datum);
+
+        // Check if size 0
+        if(! l_datum_size){
+            log_it(L_ERROR,"Datum size is 0, smth is corrupted in block");
+            return a_block_size;
+        }
+        // Check if size of of block size
+        if (l_datum_size+l_offset >a_block_size){
+            log_it(L_ERROR,"Datum size is too big %zf thats with offset %zd is bigger than block size %zd", l_datum_size, l_offset, a_block_size);
+            return a_block_size;
+        }
+        l_offset += l_datum_size;
+        // Updae current datum pointer, if it was deleted - we also need to update it after realloc
+        l_datum =(dap_chain_datum_t *) (a_block->meta_n_datum_n_sign + l_offset);
+    }
+    if (l_offset> a_block_size){
+        log_it(L_ERROR,"Offset %zd is bigger than block size %zd", l_offset, a_block_size);
+        return a_block_size;
+    }
+
+    return l_offset;
+}
+
+/**
+ * @brief dap_chain_block_sign_add
+ * @param a_block_ptr
+ * @param a_block_size
+ * @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 )
+{
+    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);
+    size_t l_block_sign_size = dap_sign_get_size(l_block_sign);
+    *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  );
+    DAP_DELETE(l_block_sign);
+    return a_block_size+l_block_sign_size;
+}
+
+/**
+ * @brief dap_chain_block_sign_get
+ * @param a_block
+ * @param a_block_size
+ * @param a_sign_num
+ * @return
+ */
+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_sign_size = dap_sign_get_size(l_sign);
+        if (!l_sign){
+            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 );
+            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;
+}
+
 /**
  * @brief dap_chain_block_get_datums
  * @param a_block
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index a9e618b7b6..dc1b335d92 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -64,9 +64,6 @@ typedef struct dap_chain_cs_blocks_pvt
 
     bool is_celled;
 
-    // For new block creating
-    dap_chain_block_t * block_new;
-    size_t block_new_size;
 } dap_chain_cs_blocks_pvt_t;
 
 typedef struct dap_chain_cs_blocks_iter
@@ -370,10 +367,10 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void *a_arg_func, char **a_s
         // Flush memory for the new block
         case SUBCMD_NEW_FLUSH:{
             pthread_rwlock_wrlock( &PVT(l_blocks)->rwlock );
-            if ( PVT(l_blocks)->block_new )
-                DAP_DELETE( PVT(l_blocks)->block_new );
-            PVT(l_blocks)->block_new = dap_chain_block_new( PVT(l_blocks)->block_cache_last? &PVT(l_blocks)->block_cache_last->block_hash: NULL );
-            PVT(l_blocks)->block_new_size = sizeof (PVT(l_blocks)->block_new->hdr);
+            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);
             pthread_rwlock_unlock( &PVT(l_blocks)->rwlock );
         } break;
 
@@ -384,10 +381,10 @@ static int s_cli_blocks(int a_argc, char ** a_argv, void *a_arg_func, char **a_s
         }break;
         case SUBCMD_NEW_DATUM_DEL:{
             pthread_rwlock_wrlock( &PVT(l_blocks)->rwlock );
-            if ( PVT(l_blocks)->block_new ){
+            if ( l_blocks->block_new ){
                 dap_chain_hash_fast_t l_datum_hash;
                 s_cli_parse_cmd_hash(a_argv,arg_index,a_argc,a_str_reply,"-datum", &l_datum_hash );
-                PVT(l_blocks)->block_new_size=dap_chain_block_datum_del_by_hash( PVT(l_blocks)->block_new, PVT(l_blocks)->block_new_size, &l_datum_hash );
+                l_blocks->block_new_size=dap_chain_block_datum_del_by_hash( &l_blocks->block_new, l_blocks->block_new_size, &l_datum_hash );
             }else {
                 dap_chain_node_cli_set_reply_text(a_str_reply,
                           "Error! Can't delete datum from hash because no forming new block! Check pls you role, it must be MASTER NODE or greater");
@@ -1028,9 +1025,9 @@ static size_t s_callback_add_datums(dap_chain_t * a_chain, dap_chain_datum_t **
 {
     // 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++) {
-        PVT(DAP_CHAIN_CS_BLOCKS(a_chain))->block_new_size = dap_chain_block_datum_add(PVT(DAP_CHAIN_CS_BLOCKS(a_chain))->block_new,
-                                                                                         PVT(DAP_CHAIN_CS_BLOCKS(a_chain))->block_new_size,
+        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]) );
     }
-    return PVT(DAP_CHAIN_CS_BLOCKS(a_chain))->block_new_size;
+    return DAP_CHAIN_CS_BLOCKS(a_chain)->block_new_size;
 }
diff --git a/modules/type/blocks/include/dap_chain_block.h b/modules/type/blocks/include/dap_chain_block.h
index 31fc4b0e39..6364350205 100644
--- a/modules/type/blocks/include/dap_chain_block.h
+++ b/modules/type/blocks/include/dap_chain_block.h
@@ -2,7 +2,7 @@
  * Authors:
  * Dmitriy A. Gearasimov <gerasimov.dmitriy@demlabs.net>
  * DeM Labs Ltd   https://demlabs.net
- * Copyright  (c) 2017-2020
+ * Copyright  (c) 2017
  * All rights reserved.
 
  This file is part of DAP SDK the open source project
@@ -24,6 +24,7 @@
 #include "dap_common.h"
 #include "dap_math_ops.h"
 #include "dap_hash.h"
+#include "dap_cert.h"
 #include "dap_chain_common.h"
 #include "dap_chain_datum.h"
 #include "dap_chain_datum_hashtree_roots.h"
@@ -94,6 +95,10 @@ size_t dap_chain_block_meta_add(dap_chain_block_t ** a_block_ptr, size_t a_block
 size_t dap_chain_block_datum_add(dap_chain_block_t ** a_block_ptr, size_t a_block_size, dap_chain_datum_t * a_datum, size_t a_datum_size);
 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 );
+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 );
+
 // 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 );
 
diff --git a/modules/type/blocks/include/dap_chain_cs_blocks.h b/modules/type/blocks/include/dap_chain_cs_blocks.h
index f2be5e7fa6..a60432337e 100644
--- a/modules/type/blocks/include/dap_chain_cs_blocks.h
+++ b/modules/type/blocks/include/dap_chain_cs_blocks.h
@@ -43,6 +43,9 @@ typedef dap_chain_block_t * (*dap_chain_cs_blocks_callback_block_create_t)(dap_c
 typedef struct dap_chain_cs_blocks
 {
     dap_chain_t * chain;
+    // For new block creating
+    dap_chain_block_t * block_new;
+    size_t block_new_size;
 
     dap_chain_cs_blocks_callback_t callback_delete;
     dap_chain_cs_blocks_callback_block_create_t callback_block_create;
-- 
GitLab