diff --git a/.gitignore b/.gitignore
index e97c609120476289487b69ea8f5b1a53eeaab3bc..3420055ff2b5d17db4c10b82f92d09f7b3533026 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
 # Prerequisites
 build/*
+cmake-build-*/
 build_stretch/*
 test/build
 *.txt.user
@@ -67,4 +68,9 @@ Makefile
 cmake_install.cmake
 
 # Editor's temp files
-*~
\ No newline at end of file
+*~
+.idea/
+
+# OS files
+.DS_Store
+
diff --git a/3rdparty/cuttdb/CMakeLists.txt b/3rdparty/cuttdb/CMakeLists.txt
index 85118d55603a3f1ca1ff87cf1975ad36a793c625..8e6150bc018f9b5f2c3631962e3aceda1f256f9f 100755
--- a/3rdparty/cuttdb/CMakeLists.txt
+++ b/3rdparty/cuttdb/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.1)
+cmake_minimum_required(VERSION 3.10)
 
 project(dap_cuttdb C)
 
diff --git a/3rdparty/json-c-darwin/CMakeLists.txt b/3rdparty/json-c-darwin/CMakeLists.txt
index 087c1f19bbd2e2854807660f25f0f5be4633145b..77d08b275354d37574e547554cfcfa31eab2b852 100644
--- a/3rdparty/json-c-darwin/CMakeLists.txt
+++ b/3rdparty/json-c-darwin/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (json-c)
   
 file(GLOB JSON_C_SRCS FILES *.c)
diff --git a/3rdparty/json-c/CMakeLists.txt b/3rdparty/json-c/CMakeLists.txt
index 087c1f19bbd2e2854807660f25f0f5be4633145b..77d08b275354d37574e547554cfcfa31eab2b852 100644
--- a/3rdparty/json-c/CMakeLists.txt
+++ b/3rdparty/json-c/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (json-c)
   
 file(GLOB JSON_C_SRCS FILES *.c)
diff --git a/3rdparty/libmagic-darwin/CMakeLists.txt b/3rdparty/libmagic-darwin/CMakeLists.txt
index 5c44277f082502ac2c2f08017884c4b71ea95e5a..c7356c623c0be98aeb1f2da5f820d238d1101852 100755
--- a/3rdparty/libmagic-darwin/CMakeLists.txt
+++ b/3rdparty/libmagic-darwin/CMakeLists.txt
@@ -3,7 +3,7 @@
 # value of 3.4.0 or lower.
 # by huzongyao
 
-cmake_minimum_required(VERSION 3.4.1)
+cmake_minimum_required(VERSION 3.10)
 
 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -DHAVE_CONFIG_H -I/usr/lib/jvm/java-8-openjdk-amd64/include/ -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux/")
 
diff --git a/3rdparty/libmagic/CMakeLists.txt b/3rdparty/libmagic/CMakeLists.txt
index 33a21014bb650e31989703556be2df618bd20fd0..681005e1e0469216d454ce219db5ee09d101a4a8 100755
--- a/3rdparty/libmagic/CMakeLists.txt
+++ b/3rdparty/libmagic/CMakeLists.txt
@@ -3,7 +3,7 @@
 # value of 3.4.0 or lower.
 # by huzongyao
 
-cmake_minimum_required(VERSION 3.4.1)
+cmake_minimum_required(VERSION 3.10)
 
 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -DHAVE_CONFIG_H -I/usr/lib/jvm/java-8-openjdk-amd64/include/ -I/usr/lib/jvm/java-8-openjdk-amd64/include/linux/")
 
diff --git a/3rdparty/wolfssl/CMakeLists.txt b/3rdparty/wolfssl/CMakeLists.txt
index 171c8ef3fadf66c1b988be8af14d59b14f9767bb..c6a14fd2e6825b533b50e5e8fcd3cde8dbe7a058 100644
--- a/3rdparty/wolfssl/CMakeLists.txt
+++ b/3rdparty/wolfssl/CMakeLists.txt
@@ -19,7 +19,7 @@
 # Project
 ####################################################
 
-cmake_minimum_required(VERSION 3.2)
+cmake_minimum_required(VERSION 3.10)
 
 if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
     message(FATAL_ERROR "In-source builds are not allowed.\
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a0f0ec4a1625e3ba38c9918329fc0ae9b0d3c4d3..04e29ccfcbef2298790435117ec447ffa675de0b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,12 +1,55 @@
 project(cellframe-sdk C)
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 set(CMAKE_C_STANDARD 11)
-set(CELLFRAME_SDK_NATIVE_VERSION "2.9-58")
+set(CELLFRAME_SDK_NATIVE_VERSION "3.0-11")
+
 add_definitions ("-DCELLFRAME_SDK_VERSION=\"${CELLFRAME_SDK_NATIVE_VERSION}\"")
+
+set(BUILD_CRYPTO_TESTS ON)
+
+if(NOT DEFINED ${CELLFRAME_MODULES})
+    include (cmake/OS_Detection.cmake)
+    if (WIN32)
+        set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-none srv-app srv-app-db srv-datum srv-stake srv-xchange")
+    elseif(BSD)
+        set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-none srv-app srv-app-db srv-datum srv-stake srv-xchange")
+    elseif(DARWIN)
+        set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-none srv-app srv-app-db srv-datum srv-stake srv-xchange")
+    elseif(ANDROID)
+        set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-none srv-app srv-app-db srv-datum srv-stake srv-xchange")
+    elseif(LINUX)
+        set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-none srv-app srv-app-db srv-datum srv-stake srv-xchange modules-dynamic srv-vpn")
+    endif()
+endif()
+
 set(DAPSDK_MODULES "")
+
+if(NOT DEFINED ${CELLFRAME_MODULES})
+    include (cmake/OS_Detection.cmake)
+    if (WIN32)
+        set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-none srv-app srv-app-db srv-datum srv-stake srv-xchange")
+    elseif(BSD)
+        set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-none srv-app srv-app-db srv-datum srv-stake srv-xchange")
+    elseif(DARWIN)
+        set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-none srv-app srv-app-db srv-datum srv-stake srv-xchange")
+    elseif(ANDROID)
+        set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-none srv-app srv-app-db srv-datum srv-stake srv-xchange")
+    elseif(LINUX)
+        set(CELLFRAME_MODULES "core chains mining network srv cs-dag-poa cs-block-poa cs-dag-pos cs-block-pos cs-none srv-app srv-app-db srv-datum srv-stake srv-xchange modules-dynamic srv-vpn")
+    endif()
+endif()
+
 message("Cellframe modules: ${CELLFRAME_MODULES}")
 
+if (CELLFRAME_MODULES MATCHES "modules-dynamic")
+    add_definitions("-DDAP_MODULES_DYNAMIC")
+endif()
+
+if (CELLFRAME_MODULES MATCHES "srv-stake")
+     add_definitions("-DDAP_SRV_STAKE_USED")
+endif()
+
 if (CELLFRAME_MODULES MATCHES "core")
     SET(DAPSDK_MODULES "${DAPSDK_MODULES} core crypto")
 endif()
@@ -105,6 +148,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'")
@@ -114,45 +181,43 @@ endif()
 # Enable service Application
 if (CELLFRAME_MODULES MATCHES "srv-app")
     message("[+] Module 'srv-app'")
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_app )
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_app)
 endif()
 
 # Enable service Application DB
 if (CELLFRAME_MODULES MATCHES "srv-app-db")
     message("[+] Module 'srv-app-db'")
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_app_db )
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_app_db)
 endif()
 
 # Enable service datum process
 if (CELLFRAME_MODULES MATCHES "srv-datum")
     message("[+] Module 'srv-datum'")
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_datum )
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_datum)
 endif()
 
 # Enable service VPN
 if (CELLFRAME_MODULES MATCHES "srv-vpn")
     message("[+] Module 'srv-vpn'")
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_vpn )
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_vpn)
 endif()
 
 # Enable service eXchange
 if (CELLFRAME_MODULES MATCHES "srv-xchange")
     message("[+] Module 'srv-xchange'")
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_xchange )
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_xchange)
 endif()
 
 # Enable service of delegated stake
 if (CELLFRAME_MODULES MATCHES "srv-stake")
     message("[+] Module 'srv-stake'")
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_stake )
-    add_definitions("-DDAP_SRV_STAKE_USED")
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_chain_net_srv_stake)
 endif()
 
 # Enable service for dynamic modules
 if (CELLFRAME_MODULES MATCHES "modules-dynamic")
     message("[+] Module 'dap_modules_dynamic_cdb'")
-    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_modules_dynamic_cdb )
-    add_definitions("-DDAP_MODULES_DYNAMIC")
+    set(CELLFRAME_LIBS ${CELLFRAME_LIBS} dap_modules_dynamic_cdb)
 endif()
 
 if (WIN32)
diff --git a/cmake/OS_Detection.cmake b/cmake/OS_Detection.cmake
index 610ea72b0a1f2d604bbf322a25a803b2e3001d05..8148074e3a757572b7abc583b6e128ead19cec98 100644
--- a/cmake/OS_Detection.cmake
+++ b/cmake/OS_Detection.cmake
@@ -1,3 +1,5 @@
+include_guard(GLOBAL)
+
 if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
     set(OS_TYPE_DESKTOP ON)
     set(LINUX ON)
@@ -82,19 +84,19 @@ if(UNIX)
     
     if (LINUX)
         if(DAP_DEBUG)
-	  set(_CCOPT "-DDAP_DEBUG -Wall -Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -pg -g3 -ggdb -fno-eliminate-unused-debug-symbols -fno-strict-aliasing")
+          set(_CCOPT "-DDAP_DEBUG -Wall  -Wno-unused-command-line-argument -Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -pg -g3 -ggdb -fno-eliminate-unused-debug-symbols -fno-strict-aliasing")
           set(_LOPT "-pg")
 	  SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg")
         else()
-	    set(_CCOPT "-Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -O3 -fPIC -fno-strict-aliasing -fno-ident -ffast-math -ftree-vectorize -fno-asynchronous-unwind-tables -ffunction-sections -Wl,--gc-sections -Wl,--strip-all -std=gnu11")
+            set(_CCOPT "-Wno-deprecated-declarations  -Wno-unused-command-line-argument -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -Wno-unused-but-set-variable -O3 -fPIC -fno-strict-aliasing -fno-ident -ffast-math -ftree-vectorize -fno-asynchronous-unwind-tables -ffunction-sections -Wl,--gc-sections -Wl,--strip-all -std=gnu11")
         endif()
     elseif (DARWIN)
         if(DAP_DEBUG)
-          set(_CCOPT "-L/usr/local/lib -I/usr/local/include -DDAP_DEBUG -Wall -Wno-unused-command-line-argument -Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -g3 -ggdb -fno-eliminate-unused-debug-symbols -fno-strict-aliasing  -std=c11")
+          set(_CCOPT "-L/usr/local/lib -I/usr/local/include -DDAP_DEBUG -Wall  -Wno-address-of-packed-member -Wno-unused-command-line-argument -Wno-deprecated-declarations -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -g3 -ggdb -fno-eliminate-unused-debug-symbols -fno-strict-aliasing  -std=c11")
           set(_LOPT "-L/usr/local/lib ")
           SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
         else()
-          set(_CCOPT "-L /usr/local/lib -I/usr/local/include -Wno-deprecated-declarations -Wno-unused-command-line-argument -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -O3 -fPIC -fno-strict-aliasing -fno-ident -ffast-math -ftree-vectorize -fno-asynchronous-unwind-tables -ffunction-sections -std=c11")
+          set(_CCOPT "-L /usr/local/lib -I/usr/local/include -Wno-address-of-packed-member -Wno-deprecated-declarations -Wno-unused-command-line-argument -Wno-unused-local-typedefs -Wno-unused-function -Wno-implicit-fallthrough -Wno-unused-variable -Wno-unused-parameter -O3 -fPIC -fno-strict-aliasing -fno-ident -ffast-math -ftree-vectorize -fno-asynchronous-unwind-tables -ffunction-sections -std=c11")
           set(_LOPT "-L /usr/local/lib")
           SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L/usr/local/lib")
         endif()
diff --git a/dap-sdk/core/CMakeLists.txt b/dap-sdk/core/CMakeLists.txt
index 60cb7dc92bb74181db1175cbff2a015ee55576f3..5956ea55318d1c3e02efe8d27c8ecb2d06c21a83 100755
--- a/dap-sdk/core/CMakeLists.txt
+++ b/dap-sdk/core/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_core)
 
 add_definitions("-D_GNU_SOURCE") 
diff --git a/dap-sdk/core/include/dap_common.h b/dap-sdk/core/include/dap_common.h
index 71d13509fbc6ff194edf3712799a0681a6d05252..641096894ded2889af8adec2eced6e15258473d1 100755
--- a/dap-sdk/core/include/dap_common.h
+++ b/dap-sdk/core/include/dap_common.h
@@ -133,8 +133,8 @@ typedef uint8_t byte_t;
   #define DAP_ALFREE(a)         _dap_aligned_free(a, b)
   #define DAP_NEW( a )          DAP_CAST_REINT(a, malloc(sizeof(a)) )
   #define DAP_NEW_SIZE(a, b)    DAP_CAST_REINT(a, malloc(b) )
-  #define DAP_NEW_S( a )          DAP_CAST_REINT(a, alloca(sizeof(a)) )
-  #define DAP_NEW_S_SIZE(a, b)    DAP_CAST_REINT(a, alloca(b) )
+  #define DAP_NEW_S( a )        DAP_CAST_REINT(a, alloca(sizeof(a)) )
+  #define DAP_NEW_S_SIZE(a, b)  DAP_CAST_REINT(a, alloca(b) )
   #define DAP_NEW_Z( a )        DAP_CAST_REINT(a, calloc(1,sizeof(a)))
   #define DAP_NEW_Z_SIZE(a, b)  DAP_CAST_REINT(a, calloc(1,b))
   #define DAP_REALLOC(a, b)     realloc(a,b)
diff --git a/dap-sdk/core/include/dap_math_ops.h b/dap-sdk/core/include/dap_math_ops.h
index bd75c7acc2f7cf9769a85468aa193e59f65b037d..e04558d5e98f5d175e293f0c9b59c32101cf8bf3 100755
--- a/dap-sdk/core/include/dap_math_ops.h
+++ b/dap-sdk/core/include/dap_math_ops.h
@@ -1,5 +1,10 @@
 #pragma once
 #include <stdint.h>
+#include <stdio.h>
+#include "assert.h"
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
 
 #include "dap_common.h"
 
@@ -43,9 +48,838 @@ typedef int128_t _dap_int128_t;
 
 #endif // __SIZEOF_INT128__ == 16
 
+typedef struct uint256_t {
+    uint128_t hi;
+    uint128_t lo;
+
+    } uint256_t;
+
+typedef struct uint512_t {
+    uint256_t hi;
+    uint256_t lo;
+
+    } uint512_t;
+
+
+
+
+
 #endif //defined(__GNUC__) || defined (__clang__)
 
-uint128_t dap_uint128_substract(uint128_t a, uint128_t b);
-uint128_t dap_uint128_add(uint128_t a, uint128_t b);
-bool dap_uint128_check_equal(uint128_t a, uint128_t b);
+////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifndef DAP_GLOBAL_IS_INT128
+
+const  uint128_t two_power_64={ .hi = 1, .lo = 0};
+const  uint128_t lo_64={ .hi = 0, .lo = 0xffffffffffffffff};
+const  uint128_t hi_64={ .hi = 0xffffffffffffffff, .lo = 0};
+const  uint128_t zero_128={.hi=0,.lo=0};
+
+const  uint256_t zero_256={.hi=zero_128,.lo=zero_128};
+
+const uint64_t lo_32=0xffffffff;
+const uint64_t hi_32=0xffffffff00000000;
+const uint64_t ones_64=0xffffffffffffffff;
+
+#endif
+
+static inline bool EQUAL_128(uint128_t a_128_bit, uint128_t b_128_bit){
+#ifdef DAP_GLOBAL_IS_INT128
+    return a_128_bit == b_128_bit;
+#else
+    return a_128_bit.lo==b_128_bit.lo && a_128_bit.hi==b_128_bit.hi;
+#endif
+}
+    
+static inline bool EQUAL_256(uint256_t a_256_bit, uint256_t b_256_bit){
+
+#ifdef DAP_GLOBAL_IS_INT128
+    return a_256_bit.lo==b_256_bit.lo && a_256_bit.hi==b_256_bit.hi;
+
+#else
+    return a_256_bit.lo.lo==b_256_bit.lo.lo &&
+           a_256_bit.lo.hi==b_256_bit.lo.hi &&
+           a_256_bit.hi.lo==b_256_bit.hi.lo &&
+           a_256_bit.hi.hi==b_256_bit.hi.hi;
+#endif
+}
+
+static inline uint128_t AND_128(uint128_t a_128_bit,uint128_t b_128_bit){
+
+#ifdef DAP_GLOBAL_IS_INT128
+    return a_128_bit&b_128_bit;
+    
+#else    
+    uint128_t output={ .hi = 0, .lo = 0};
+    output.hi= a_128_bit.hi & b_128_bit.hi;  
+    output.lo= a_128_bit.lo & b_128_bit.lo;
+    return output;
+
+#endif
+}
+
+static inline uint128_t OR_128(uint128_t a_128_bit,uint128_t b_128_bit){
+
+#ifdef DAP_GLOBAL_IS_INT128
+    return a_128_bit|b_128_bit;
+
+#else    
+    uint128_t output={ .hi = 0, .lo = 0};
+    output.hi= a_128_bit.hi | b_128_bit.hi;  
+    output.lo= a_128_bit.lo | b_128_bit.lo;
+    return output;
+
+#endif
+}
+
+static inline uint256_t AND_256(uint256_t a_256_bit,uint256_t b_256_bit){
+
+#ifdef DAP_GLOBAL_IS_INT128
+    uint256_t output = {};
+    output.hi= a_256_bit.hi | b_256_bit.hi;  
+    output.lo= a_256_bit.lo | b_256_bit.lo;
+    return output;
+
+#else 
+    uint256_t output={ .hi = zero_128, .lo = zero_128};
+    output.hi= AND_128(a_256_bit.hi, b_256_bit.hi);  
+    output.lo= AND_128(a_256_bit.lo, b_256_bit.lo);
+    return output;
+
+#endif
+}
+
+static inline uint256_t OR_256(uint256_t a_256_bit,uint256_t b_256_bit){
+
+#ifdef DAP_GLOBAL_IS_INT128
+    uint256_t output= {};
+    output.hi= a_256_bit.hi | b_256_bit.hi;  
+    output.lo= a_256_bit.lo | b_256_bit.lo;
+    return output;
+
+#else 
+    uint256_t output={ .hi = zero_128, .lo = zero_128};
+    output.hi= OR_128(a_256_bit.hi, b_256_bit.hi); 
+    output.lo= OR_128(a_256_bit.lo, b_256_bit.lo); 
+    return output;
+
+#endif
+}
+
+static inline void LEFT_SHIFT_128(uint128_t a_128_bit,uint128_t* b_128_bit,int n){
+    assert (n <= 128);
+
+#ifdef DAP_GLOBAL_IS_INT128
+    *b_128_bit=a_128_bit<<n;
+
+#else 
+    if (n >= 64) // shifting 64-bit integer by more than 63 bits is not defined
+    {   
+        a_128_bit.hi=a_128_bit.lo;
+        a_128_bit.lo=0;
+        LEFT_SHIFT_128(a_128_bit,b_128_bit,n-64);
+    }
+    if (n == 0)
+    {
+       b_128_bit->hi=a_128_bit.hi;
+       b_128_bit->lo=a_128_bit.lo;
+    } 
+    else
+    {   uint64_t shift_temp;
+        shift_temp=a_128_bit.lo<<n;
+        b_128_bit->lo=shift_temp;
+        b_128_bit->hi=(a_128_bit.hi<<n)|(a_128_bit.lo>>(64-n));
+    }
+
+#endif
+}
+
+static inline void RIGHT_SHIFT_128(uint128_t a_128_bit,uint128_t* b_128_bit,int n){
+    assert (n <= 128);
+
+#ifdef DAP_GLOBAL_IS_INT128
+    (*b_128_bit) = a_128_bit >> n;
+
+#else 
+    
+    if (n >= 64) // shifting 64-bit integer by more than 63 bits is not defined
+    {   
+        a_128_bit.lo=a_128_bit.hi;
+        a_128_bit.hi=0;
+        RIGHT_SHIFT_128(a_128_bit,b_128_bit,n-64);
+    }
+    if (n == 0)
+    {
+       b_128_bit->hi=a_128_bit.hi;
+       b_128_bit->lo=a_128_bit.lo;
+    } 
+    else
+    {   uint64_t shift_temp;
+        shift_temp=a_128_bit.hi>>n;
+        b_128_bit->hi=shift_temp;
+        b_128_bit->lo=(a_128_bit.lo>>n)|(a_128_bit.hi<<(64-n));
+    }
+#endif
+}
+
+
+static inline void LEFT_SHIFT_256(uint256_t a_256_bit,uint256_t* b_256_bit,int n){
+ 
+    assert (n <= 256);
+
+#ifdef DAP_GLOBAL_IS_INT128
+
+    if (n >= 128) 
+    {   
+        a_256_bit.hi=a_256_bit.lo;
+        a_256_bit.lo=0;
+        LEFT_SHIFT_256(a_256_bit,b_256_bit,n-128);
+    }
+    if (n == 0)
+    {
+       b_256_bit->hi=a_256_bit.hi;
+       b_256_bit->lo=a_256_bit.lo;
+    } 
+    else
+    {   uint128_t shift_temp;
+        shift_temp=a_256_bit.lo<<n;
+        b_256_bit->lo=shift_temp;
+        b_256_bit->hi=(a_256_bit.hi<<n)|(a_256_bit.lo>>(128-n));
+    }
+
+#else 
+    if (n >= 128) // shifting 64-bit integer by more than 63 bits is not defined
+    {   
+        a_256_bit.hi=a_256_bit.lo;
+        a_256_bit.lo=zero_128;
+        LEFT_SHIFT_256(a_256_bit,b_256_bit,n-128);
+    }
+    if (n == 0)
+    {
+       b_256_bit->hi=a_256_bit.hi;
+       b_256_bit->lo=a_256_bit.lo;
+    } 
+    if (n<128)
+    {   uint128_t shift_temp{.hi=0, .lo=0};
+        LEFT_SHIFT_128(a_256_bit.lo,&shift_temp,n);
+        b_256_bit->lo=shift_temp;   
+        uint128_t shift_temp_or_left{.hi=0, .lo=0};
+        uint128_t shift_temp_or_right{.hi=0, .lo=0};
+        LEFT_SHIFT_128(a_256_bit.hi,&shift_temp_or_left,n);
+        RIGHT_SHIFT_128(a_256_bit.lo,&shift_temp_or_right,128-n);
+        b_256_bit->hi=OR_128(shift_temp_or_left,shift_temp_or_right);
+    }
+#endif
+}
+
+static inline void RIGHT_SHIFT_256(uint256_t a_256_bit,uint256_t* b_256_bit,int n){
+    assert (n <= 256);
+
+#ifdef DAP_GLOBAL_IS_INT128
+
+    if (n >= 128) 
+    {   
+        a_256_bit.lo=a_256_bit.hi;
+        a_256_bit.hi=0;
+        RIGHT_SHIFT_256(a_256_bit,b_256_bit,n-128);
+    }
+    if (n == 0)
+    {
+       b_256_bit->hi=a_256_bit.hi;
+       b_256_bit->lo=a_256_bit.lo;
+    } 
+    else
+    {   uint64_t shift_temp;
+        shift_temp=a_256_bit.hi>>n;
+        b_256_bit->hi=shift_temp;
+        b_256_bit->lo=(a_256_bit.lo>>n)|(a_256_bit.hi<<(128-n));
+    }
+
+#else 
+    if (n >= 128) // shifting 64-bit integer by more than 63 bits is not defined
+    {   
+        a_256_bit.lo=a_256_bit.hi;
+        a_256_bit.hi=zero_128;
+        RIGHT_SHIFT_256(a_256_bit,b_256_bit,n-128);
+    }
+    if (n == 0)
+    {
+       b_256_bit->hi=a_256_bit.hi;
+       b_256_bit->lo=a_256_bit.lo;
+    } 
+    if (n<128)
+    {   uint128_t shift_temp{.hi=0, .lo=0};
+        RIGHT_SHIFT_128(a_256_bit.hi,&shift_temp,n);
+        b_256_bit->hi=shift_temp;   
+        uint128_t shift_temp_or_left{.hi=0, .lo=0};
+        uint128_t shift_temp_or_right{.hi=0, .lo=0};
+        RIGHT_SHIFT_128(a_256_bit.lo,&shift_temp_or_left,n);
+        LEFT_SHIFT_128(a_256_bit.hi,&shift_temp_or_right,128-n);
+        b_256_bit->lo=OR_128(shift_temp_or_left,shift_temp_or_right);
+    }
+#endif
+}
+
+static inline void INCR_128(uint128_t *a_128_bit){
+
+#ifdef DAP_GLOBAL_IS_INT128
+    (*a_128_bit)++;
+
+#else 
+    a_128_bit->lo++;
+    if(a_128_bit->lo == 0)
+    {
+        a_128_bit->hi++;
+    }  
+#endif
+}
+
+//static inline void DECR_128(uint128_t* a_128_bit){
+//
+//#ifdef DAP_GLOBAL_IS_INT128
+//    *a_128_bit--;
+//
+//#else 
+//    a_128_bit->lo--;
+//    if(a_128_bit->hi == 0)
+//    {
+//        a_128_bit->hi--;
+//    }  
+//#endif
+//}
+//
+static inline void INCR_256(uint256_t* a_256_bit){
+
+#ifdef DAP_GLOBAL_IS_INT128
+    a_256_bit->lo++;
+    if(a_256_bit->lo == 0)
+    {
+        a_256_bit->hi++;
+    }  
+
+#else 
+    INCR_128(&a_256_bit->lo);
+    if(EQUAL_128(a_256_bit->lo, zero_128))
+    {
+        INCR_128(&a_256_bit->hi);
+    }  
+#endif
+}
+
+static inline int SUM_64_64(uint64_t a_64_bit,uint64_t b_64_bit,uint64_t* c_64_bit ) {
+
+int overflow_flag;
+*c_64_bit=a_64_bit+b_64_bit;
+overflow_flag=(*c_64_bit<a_64_bit);
+return overflow_flag;}
+
+
+
+static inline int OVERFLOW_SUM_64_64(uint64_t a_64_bit,uint64_t b_64_bit) {
+
+int overflow_flag;
+overflow_flag=(a_64_bit+b_64_bit<a_64_bit);
+return overflow_flag;}
 
+static inline int OVERFLOW_MULT_64_64(uint64_t a_64_bit,uint64_t b_64_bit) { return (a_64_bit>((uint64_t)-1)/b_64_bit); }
+
+static inline int MULT_64_64(uint64_t a_64_bit,uint64_t b_64_bit,uint64_t* c_64_bit ) {
+
+int overflow_flag;
+*c_64_bit=a_64_bit*b_64_bit;
+overflow_flag=OVERFLOW_MULT_64_64(a_64_bit, b_64_bit);
+return overflow_flag;}
+
+//
+//static inline void SUM_64_128(uint64_t a_64_bit,uint64_t b_64_bit,uint128_t* c_128_bit ) {
+//int overflow_flag;
+//c_128_bit->lo=a_64_bit+b_64_bit;
+//c_128_bit->hi=(c_128_bit->lo<a_64_bit);}
+
+#ifndef DAP_GLOBAL_IS_INT128
+//Mixed precision: add a uint64_t into a uint128_t
+static inline int ADD_64_INTO_128(uint64_t a_64_bit,uint128_t* c_128_bit ) {
+    int overflow_flag=0;
+    uint64_t overflow_64=0;
+    uint64_t temp=0;
+    temp=c_128_bit->lo;
+    overflow_flag=SUM_64_64(a_64_bit,temp,&c_128_bit->lo);
+    overflow_64=overflow_flag;
+    temp=c_128_bit->hi;
+    overflow_flag=SUM_64_64(overflow_64,temp,&c_128_bit->hi);
+    return overflow_flag;}
+
+static inline int  SUM_128_128(uint128_t a_128_bit,uint128_t b_128_bit,uint128_t* c_128_bit){
+    int overflow_flag;
+    int overflow_flag_intermediate;
+    overflow_flag=SUM_64_64(a_128_bit.lo,b_128_bit.lo,&c_128_bit->lo);
+    uint64_t carry_in_64=overflow_flag;
+    uint64_t intermediate_value=0;
+    overflow_flag=0;
+    overflow_flag=SUM_64_64(carry_in_64,a_128_bit.hi,&intermediate_value);
+    overflow_flag_intermediate=SUM_64_64(intermediate_value,b_128_bit.hi,&c_128_bit->hi);
+    int return_overflow=overflow_flag|overflow_flag_intermediate;
+    return return_overflow;}
+
+static inline int SUBTRACT_128_128(uint128_t a_128_bit, uint128_t b_128_bit,uint128_t* c_128_bit)
+{
+    c_128_bit->lo = a_128_bit.lo - b_128_bit.lo;
+    uint64_t carry = (((c_128_bit->lo & b_128_bit.lo) & 1) + (b_128_bit.lo >> 1) + (c_128_bit->lo >> 1)) >> 63;
+    c_128_bit->hi = a_128_bit.hi - (b_128_bit.hi + carry);
+    int underflow_flag=carry;
+    return underflow_flag;
+}
+
+//static inline int SUBTRACT_256_256(uint256_t a_256_bit, uint256_t b_256_bit,uint256_t* c_256_bit){
+//
+//    if 
+//  int carry=0;
+//    carry=SUBTRACT_128_128(a_256_bit.lo, b_256_bit.lo,&c_256_bit->lo);
+//    uint64_t carry_64=carry;
+//    uint128_t carry_128{.hi=0,.lo=carry_64};
+//    uint128_t intermediate_val{.hi=0,.lo=0};
+//    int dummy_overflow=0;
+//    dummy_overflow=SUM_128_128(b_256_bit.hi,carry_128,&intermediate_val);
+//    carry=SUBTRACT_128_128(a_256_bit.hi, intermediate_val,&c_256_bit->hi );
+//    return carry;
+//}
+//
+//Mixed precision: add a uint128_t into a uint256_t
+static inline int ADD_128_INTO_256(uint128_t a_128_bit,uint256_t* c_256_bit) {
+    int overflow_flag=0;
+    uint128_t overflow_128={.hi=0,.lo=0};
+    uint128_t temp={.hi=0,.lo=0};
+    temp=c_256_bit->lo;
+    overflow_flag=SUM_128_128(a_128_bit,temp,&c_256_bit->lo);
+    overflow_128.lo=overflow_flag;
+    temp=c_256_bit->hi;
+    overflow_flag=SUM_128_128(overflow_128,temp,&c_256_bit->hi);
+    return overflow_flag;}
+
+
+static inline int  SUM_256_256(uint256_t a_256_bit,uint256_t b_256_bit,uint256_t* c_256_bit){
+    int overflow_flag;
+    overflow_flag=SUM_128_128(a_256_bit.lo,b_256_bit.lo,&c_256_bit->lo);
+    uint128_t carry_in_128;
+    carry_in_128.hi=0;
+    carry_in_128.lo=overflow_flag;
+    uint128_t intermediate_value;
+    intermediate_value.hi=0;
+    intermediate_value.lo=0;
+    overflow_flag=0;
+    overflow_flag=SUM_128_128(carry_in_128,a_256_bit.hi,&intermediate_value);
+    
+    //we store overflow_flag in case there is already overflow
+    int overflow_flag_bis=0; 
+    
+    overflow_flag_bis=SUM_128_128(intermediate_value,b_256_bit.hi,&c_256_bit->hi);
+    overflow_flag=overflow_flag||overflow_flag_bis;
+    return overflow_flag;}
+
+static inline int  SUBTRACT_256_256(uint256_t a_256_bit,uint256_t b_256_bit,uint256_t* c_256_bit){
+    
+//(u64 rd[4], const u64 ad[4], const u64 bd[4])
+    uint64_t t, r, borrow;
+
+    t = a_256_bit.lo.lo;
+    r = t - b_256_bit.lo.lo;
+    borrow = (r > t);
+    c_256_bit->lo.lo = r;
+
+    t = a_256_bit.lo.hi;
+    t -= borrow;
+    borrow = (t > a_256_bit.lo.hi);
+    r = t - b_256_bit.lo.hi;
+    borrow |= (r > t);
+    c_256_bit->lo.hi = r;
+
+    t = a_256_bit.hi.lo;
+    t -= borrow;
+    borrow = (t > a_256_bit.hi.lo);
+    r = t - b_256_bit.hi.lo;
+    borrow |= (r > t);
+    c_256_bit->hi.lo = r;
+
+    t = a_256_bit.hi.hi;
+    t -= borrow;
+    borrow = (t > a_256_bit.hi.hi);
+    r = t - b_256_bit.hi.hi;
+    borrow |= (r > t);
+    c_256_bit->hi.hi = r;
+
+    return borrow;
+
+    }
+
+//Mixed precision: add a uint256_t into a uint512_t
+static inline int ADD_256_INTO_512(uint256_t a_256_bit,uint512_t* c_512_bit) {
+    int overflow_flag=0;
+    uint256_t overflow_256={.hi=zero_128,.lo=zero_128};
+    uint256_t temp={.hi=zero_128,.lo=zero_128};
+    temp=c_512_bit->lo;
+    overflow_flag=SUM_256_256(a_256_bit,temp,&c_512_bit->lo);
+    overflow_256.lo.lo=overflow_flag;
+    temp=c_512_bit->hi;
+    overflow_flag=SUM_256_256(overflow_256,temp,&c_512_bit->hi);
+    return overflow_flag;}
+
+
+static inline void MULT_64_128(uint64_t a_64_bit, uint64_t b_64_bit, uint128_t* c_128_bit)
+{
+    uint64_t a_64_bit_hi = (a_64_bit & 0xffffffff);
+    uint64_t b_64_bit_hi = (b_64_bit & 0xffffffff);
+    uint64_t prod_hi = (a_64_bit_hi * b_64_bit_hi);
+    uint64_t w3 = (prod_hi & 0xffffffff);
+    uint64_t prod_hi_shift_right = (prod_hi >> 32);
+
+    a_64_bit >>= 32;
+    prod_hi = (a_64_bit * b_64_bit_hi) + prod_hi_shift_right;
+    prod_hi_shift_right = (prod_hi & 0xffffffff);
+    uint64_t w1 = (prod_hi >> 32);
+
+    b_64_bit >>= 32;
+    prod_hi = (a_64_bit_hi * b_64_bit) + prod_hi_shift_right;
+    prod_hi_shift_right = (prod_hi >> 32);
+
+    c_128_bit->hi = (a_64_bit * b_64_bit) + w1 + prod_hi_shift_right;
+    c_128_bit->lo = (prod_hi << 32) + w3;
+}
+
+
+
+static inline void MULT_128_256(uint128_t a_128_bit,uint128_t b_128_bit,uint256_t* c_256_bit ) {
+
+    //product of .hi terms - stored in .hi field of c_256_bit
+    MULT_64_128(a_128_bit.hi,b_128_bit.hi, &c_256_bit->hi);
+
+    //product of .lo terms - stored in .lo field of c_256_bit        
+    MULT_64_128(a_128_bit.lo,b_128_bit.lo, &c_256_bit->lo);
+
+    uint128_t cross_product_one{.hi=0, .lo=0};
+    uint128_t cross_product_two{.hi=0, .lo=0};
+    MULT_64_128(a_128_bit.hi, b_128_bit.lo, &cross_product_one);
+    c_256_bit->lo.hi += cross_product_one.lo;
+    if(c_256_bit->lo.hi < cross_product_one.lo)  // if overflow
+    {
+        INCR_128(&c_256_bit->hi);
+    }
+    c_256_bit->hi.lo += cross_product_one.hi;
+    if(c_256_bit->hi.lo < cross_product_one.hi)  // if  overflowed
+    {
+        c_256_bit->hi.hi+=1;
+    }
+    
+    MULT_64_128(a_128_bit.lo, b_128_bit.hi, &cross_product_two);
+    c_256_bit->lo.hi += cross_product_two.lo;
+    if(c_256_bit->lo.hi < cross_product_two.lo)  // if overflowed
+    {
+        INCR_128(&c_256_bit->hi);
+    }
+    c_256_bit->hi.lo += cross_product_two.hi;
+    if(c_256_bit->hi.lo < cross_product_two.hi)  //  overflowed
+    {
+        c_256_bit->hi.hi+=1;
+    }
+} 
+
+static inline int MULT_128_128_NEW(uint128_t a_128_bit,uint128_t b_128_bit,uint128_t* accum_128_bit){
+    int overflow=0; 
+    int equal_flag=0;
+    uint256_t full_product_256{.hi=zero_128, .lo=zero_128};
+    MULT_128_256(a_128_bit,b_128_bit,&full_product_256);
+    *accum_128_bit=full_product_256.lo;
+    equal_flag=EQUAL_128(full_product_256.hi,zero_128);
+    if (!equal_flag)
+    {
+        overflow=1;
+    }
+    return overflow;
+}
+
+static inline int MULT_128_128(uint128_t a_128_bit,uint128_t b_128_bit,uint128_t* accum_128_bit) {    
+    uint64_t A=(b_128_bit.lo & lo_32)*(a_128_bit.hi & lo_32);
+    uint64_t B_32_64=((b_128_bit.lo & lo_32)*(a_128_bit.hi & hi_32))&hi_32;
+    uint64_t C_32_64=((b_128_bit.lo & hi_32)*(a_128_bit.hi & lo_32))&hi_32;
+    uint64_t E=(a_128_bit.lo & lo_32)*(b_128_bit.hi & lo_32);
+    uint64_t F_32_64=((a_128_bit.lo & lo_32)*(b_128_bit.hi & hi_32))&hi_32;
+    uint64_t G_32_64=((a_128_bit.lo & hi_32)*(b_128_bit.hi & lo_32))&hi_32;
+
+    //initialization of overflow counter
+    int overflow_ctr=0;
+
+     //checking of overflow from ".hi terms"
+    int overflow_from_hi_calc=0;
+    overflow_from_hi_calc=(a_128_bit.hi*b_128_bit.hi>0);
+    overflow_ctr+=overflow_from_hi_calc;
+    
+    //product of two ".lo" terms
+    MULT_64_128(a_128_bit.lo,b_128_bit.lo,accum_128_bit);   
+
+    int overflow=0;
+    uint64_t temp=0;
+
+    overflow=SUM_64_64(A,temp,&accum_128_bit->hi); 
+    printf("accum_128_bit->hi after add in of A %" PRIu64 "\n",accum_128_bit->hi);
+ 
+    overflow_ctr+=overflow;
+    temp=accum_128_bit->hi; 
+    overflow=0;
+
+    overflow=SUM_64_64(B_32_64,temp,&accum_128_bit->hi);  
+    overflow_ctr+=overflow;
+    temp=accum_128_bit->hi; 
+    overflow=0;
+
+    overflow=SUM_64_64(C_32_64,temp,&accum_128_bit->hi);  
+    overflow_ctr+=overflow;
+    temp=accum_128_bit->hi; 
+    overflow=0;
+
+    overflow=SUM_64_64(E,temp,&accum_128_bit->hi);  
+    overflow_ctr+=overflow;
+    temp=accum_128_bit->hi; 
+    overflow=0;
+
+    overflow=SUM_64_64(F_32_64,temp,&accum_128_bit->hi);  
+    overflow_ctr+=overflow;
+    temp=accum_128_bit->hi; 
+    overflow=0;
+        
+    overflow=SUM_64_64(G_32_64,temp,&accum_128_bit->hi);  
+    overflow_ctr+=overflow;
+    temp=accum_128_bit->hi;  
+    overflow=0;
+
+    if(overflow_ctr>0){
+        overflow=1;}
+    else{overflow=0;}
+    
+    return overflow;
+    }
+
+static inline void MULT_256_512(uint256_t a_256_bit,uint256_t b_256_bit,uint512_t* c_512_bit) {
+    int dummy_overflow;
+    //product of .hi terms - stored in .hi field of c_512_bit
+    MULT_128_256(a_256_bit.hi,b_256_bit.hi, &c_512_bit->hi);
+    
+    //product of .lo terms - stored in .lo field of c_512_bit        
+    MULT_128_256(a_256_bit.lo,b_256_bit.lo, &c_512_bit->lo);
+
+    //cross product of .hi and .lo terms
+    uint256_t cross_product_first_term{ .hi = zero_128, .lo = zero_128};
+    uint256_t cross_product_second_term{ .hi = zero_128, .lo = zero_128};
+    uint256_t cross_product{ .hi = zero_128, .lo = zero_128};
+    uint256_t cross_product_shift_128{ .hi = zero_128, .lo = zero_128};
+    uint256_t c_512_bit_lo_copy{ .hi = zero_128, .lo = zero_128};
+    uint256_t c_512_bit_hi_copy{ .hi = zero_128, .lo = zero_128};
+    int overflow=0;
+
+    MULT_128_256(a_256_bit.hi,b_256_bit.lo,&cross_product_first_term);
+    MULT_128_256(a_256_bit.lo,b_256_bit.hi,&cross_product_second_term);
+    overflow=SUM_256_256(cross_product_first_term,cross_product_second_term,&cross_product);
+    
+    
+    LEFT_SHIFT_256(cross_product,&cross_product_shift_128,128); //the factor in front of cross product is 2**128
+    c_512_bit_lo_copy=c_512_bit->lo; 
+    dummy_overflow=SUM_256_256(c_512_bit_lo_copy,cross_product_shift_128,&c_512_bit->lo);    
+ 
+    cross_product_shift_128.hi = zero_128; 
+    cross_product_shift_128.lo = zero_128;
+    RIGHT_SHIFT_256(cross_product,&cross_product_shift_128,128);
+    c_512_bit_hi_copy=c_512_bit->hi;    
+    dummy_overflow=SUM_256_256(c_512_bit_hi_copy,cross_product_shift_128,&c_512_bit->hi);
+    }
+
+
+static inline int MULT_256_256_NEW(uint256_t a_256_bit,uint256_t b_256_bit,uint256_t* accum_256_bit){
+
+    uint128_t two_0_coeff{.hi=0,.lo=0};
+    MULT_64_128(a_256_bit.lo.lo,b_256_bit.lo.lo,&two_0_coeff);
+    accum_256_bit->lo.lo=two_0_coeff.lo;
+    
+    uint128_t two_64_coeff{.hi=0,.lo=0};
+    uint128_t two_64_coeff_one{.hi=0,.lo=0};
+    MULT_64_128(a_256_bit.lo.hi,b_256_bit.lo.lo,&two_64_coeff_one);
+    uint128_t two_64_coeff_two{.hi=0,.lo=0};
+    MULT_64_128(a_256_bit.lo.lo,b_256_bit.lo.hi,&two_64_coeff_two);
+    uint128_t two_64_coeff_sum{.hi=0,.lo=0};
+    int dummy_overflow=0;
+    dummy_overflow=SUM_128_128(two_64_coeff_one,two_64_coeff_two,&two_64_coeff_sum);
+    if (two_64_coeff_sum.lo+two_0_coeff.hi<two_64_coeff_sum.lo){
+        
+        two_64_coeff.lo=two_64_coeff_sum.lo+two_0_coeff.hi;
+        two_64_coeff.hi=1+two_64_coeff_sum.hi;}
+    else{
+        two_64_coeff.lo=two_64_coeff_sum.lo+two_0_coeff.hi;
+        two_64_coeff.hi=two_64_coeff_sum.hi;
+    }
+    accum_256_bit->lo.hi=two_64_coeff.lo;
+    
+
+    uint128_t two_128_coeff{.hi=0,.lo=0};
+    uint128_t  two_128_coeff_one{.hi=0,.lo=0};
+    MULT_64_128(a_256_bit.lo.lo,b_256_bit.hi.lo,&two_128_coeff_one);
+    uint128_t  two_128_coeff_two{.hi=0,.lo=0};
+    MULT_64_128(a_256_bit.hi.lo,b_256_bit.lo.lo,&two_128_coeff_two);
+    uint128_t two_128_coeff_three{.hi=0,.lo=0};
+    MULT_64_128(a_256_bit.lo.hi,b_256_bit.lo.hi,&two_128_coeff_three);
+    uint128_t two_128_coeff_sum_one{.hi=0,.lo=0};
+    dummy_overflow=SUM_128_128(two_128_coeff_one,two_128_coeff_two,&two_128_coeff_sum_one);
+    uint128_t two_128_coeff_sum_two{.hi=0,.lo=0};
+    dummy_overflow=SUM_128_128(two_128_coeff_sum_one,two_128_coeff_three,&two_128_coeff_sum_two);
+    
+    if (two_128_coeff_sum_two.lo+two_64_coeff.hi<two_128_coeff_sum_two.lo){
+        
+        two_128_coeff.lo=two_128_coeff_sum_two.lo+two_64_coeff.hi;
+        two_128_coeff.hi=1+two_128_coeff_sum_two.hi;}
+    else{
+        two_128_coeff.lo=two_128_coeff_sum_two.lo+two_64_coeff.hi;
+        two_128_coeff.hi=two_128_coeff_sum_two.hi;
+    }
+    accum_256_bit->hi.lo=two_128_coeff.lo;
+
+
+
+//    
+//
+//    
+//    uint64_t two_192_coeff=0;
+//    uint64_t two_192_coeff_one=0;
+//    int overflow_two_192_coeff_one=0;
+//    overflow_two_192_coeff_one=MULT_64_64(a_256_bit.hi.hi,b_256_bit.lo.lo,&two_192_coeff_one);
+//    uint64_t two_192_coeff_two=0;
+//    int overflow_two_192_coeff_two=0;
+//    overflow_two_192_coeff_two=MULT_64_64(a_256_bit.lo.lo,b_256_bit.hi.hi,&two_192_coeff_two);
+//    uint64_t two_192_coeff_three=0;
+//    int overflow_two_192_coeff_three=0;
+//    overflow_two_192_coeff_three=MULT_64_64(a_256_bit.lo.hi,b_256_bit.hi.lo,&two_192_coeff_three);
+//    uint64_t two_192_coeff_four=0;
+//    int overflow_two_192_coeff_four=0;
+//    overflow_two_192_coeff_four=MULT_64_64(a_256_bit.hi.lo,b_256_bit.lo.hi,&two_192_coeff_four);
+//    uint64_t two_192_coeff_sum_one=0;
+//    int overflow_two_192_coeff_sum_one=0;
+
+//    overflow_two_192_coeff_sum_one=SUM_64_64(two_192_coeff_one,two_192_coeff_two,&two_192_coeff_sum_one);
+//    uint64_t two_192_coeff_sum_two=0;
+//    int overflow_two_192_coeff_sum_two=0;
+//    overflow_two_192_coeff_sum_two=SUM_64_64(two_192_coeff_three,two_192_coeff_four,&two_192_coeff_sum_two);
+//    int overflow_two_192_coeff_sum=0;
+//    overflow_two_192_coeff_sum=SUM_64_64(two_192_coeff_sum_one,two_192_coeff_sum_two,&two_192_coeff);
+    
+
+    return 0;
+    
+}
+
+static inline int MULT_256_256(uint256_t a_256_bit,uint256_t b_256_bit,uint256_t* accum_256_bit){
+    int overflow=0; 
+    int equal_flag=0;
+    uint512_t full_product_512{.hi=zero_256,.lo=zero_256,};
+    MULT_256_512(a_256_bit,b_256_bit,&full_product_512);
+    *accum_256_bit=full_product_512.lo;
+    equal_flag=EQUAL_256(full_product_512.hi,zero_256);
+    if (!equal_flag)
+    {
+        overflow=1;
+    }
+    return overflow;
+}
+
+int compare128(uint128_t N1, uint128_t N2)
+{
+    return    (((N1.hi > N2.hi) || ((N1.hi == N2.hi) && (N1.lo > N2.lo))) ? 1 : 0) 
+         -    (((N1.hi < N2.hi) || ((N1.hi == N2.hi) && (N1.lo < N2.lo))) ? 1 : 0);
+}
+
+size_t nlz64(uint64_t N)
+{
+    uint64_t I;
+    size_t C;
+
+    I = ~N;
+    C = ((I ^ (I + 1)) & I) >> 63;
+
+    I = (N >> 32) + 0xffffffff;
+    I = ((I & 0x100000000) ^ 0x100000000) >> 27;
+    C += I;  N <<= I;
+
+    I = (N >> 48) + 0xffff;
+    I = ((I & 0x10000) ^ 0x10000) >> 12;
+    C += I;  N <<= I;
+
+    I = (N >> 56) + 0xff;
+    I = ((I & 0x100) ^ 0x100) >> 5;
+    C += I;  N <<= I;
+
+    I = (N >> 60) + 0xf;
+    I = ((I & 0x10) ^ 0x10) >> 2;
+    C += I;  N <<= I;
+
+    I = (N >> 62) + 3;
+    I = ((I & 4) ^ 4) >> 1;
+    C += I;  N <<= I;
+
+    C += (N >> 63) ^ 1;
+
+    return C;
+}
+
+size_t nlz128(uint128_t N)
+{
+    return (N.hi == 0) ? nlz64(N.lo) + 64 : nlz64(N.hi);
+}
+
+void shiftleft128(uint128_t N, unsigned S, uint128_t* A)
+{
+    uint64_t M1, M2;
+    S &= 127;
+
+    M1 = ((((S + 127) | S) & 64) >> 6) - 1llu;
+    M2 = (S >> 6) - 1llu;
+    S &= 63;
+    A->hi = (N.lo << S) & (~M2);
+    A->lo = (N.lo << S) & M2;
+    A->hi |= ((N.hi << S) | ((N.lo >> (64 - S)) & M1)) & M2;
+}
+
+void shiftright128(uint128_t N, unsigned S, uint128_t* A)
+{
+    uint64_t M1, M2;
+    S &= 127;
+
+    M1 = ((((S + 127) | S) & 64) >> 6) - 1llu;
+    M2 = (S >> 6) - 1llu;
+    S &= 63;
+    A->lo = (N.hi >> S) & (~M2);
+    A->hi = (N.hi >> S) & M2;
+    A->lo |= ((N.lo >> S) | ((N.hi << (64 - S)) & M1)) & M2;
+} 
+
+void sub128(uint128_t* Ans, uint128_t N, uint128_t M)
+{
+    Ans->lo = N.lo - M.lo;
+    uint64_t C = (((Ans->lo & M.lo) & 1) + (M.lo >> 1) + (Ans->lo >> 1)) >> 63;
+    Ans->hi = N.hi - (M.hi + C);
+}
+void bindivmod128(uint128_t M, uint128_t N, uint128_t* Q, uint128_t* R)
+{
+    Q->hi = Q->lo = 0;
+    size_t Shift = nlz128(N) - nlz128(M);
+    shiftleft128(N, Shift, &N);
+
+    do
+    {
+        shiftleft128(*Q, 1, Q);
+        if(compare128(M, N) >= 0)
+        {
+            sub128(&M, N, M);
+            Q->lo |= 1;
+        }
+
+        shiftright128(N, 1, &N);
+    }while(Shift-- != 0);
+
+    R->hi = M.hi;
+    R->lo = M.lo;
+}
+#endif
diff --git a/dap-sdk/core/include/dap_module.h b/dap-sdk/core/include/dap_module.h
index b3193c43dcfe9365439823c487542e61f4e56e97..bae7e6df32518e9fea7232bdf0f05fce6568f598 100755
--- a/dap-sdk/core/include/dap_module.h
+++ b/dap-sdk/core/include/dap_module.h
@@ -35,7 +35,7 @@ typedef struct dap_module {
 #define DAP_MODULE_ARGS_MAX  10
 typedef struct dap_module_args {
     const char * name;
-    const char * args[DAP_MODULE_ARGS_MAX]; // ARGS could me not more than DAP_MODULE_ARGS_MAX define
+    const char * args[DAP_MODULE_ARGS_MAX]; // ARGS could be not more than DAP_MODULE_ARGS_MAX define
 } dap_module_args_t;
 
 int dap_module_add(const char * a_name, unsigned int a_version, const char * a_dependensies,
diff --git a/dap-sdk/core/libdap.pri b/dap-sdk/core/libdap.pri
index 4ba46b269cba1a4ed2fe57531b87ca0b4dfd36eb..945c55411cbcb03efe3eb294d31e2eb33872181a 100755
--- a/dap-sdk/core/libdap.pri
+++ b/dap-sdk/core/libdap.pri
@@ -20,7 +20,6 @@ unix: !android : ! darwin {
     LIBS += -lrt -ljson-c -lmagic
 }
 
-
 contains(DAP_FEATURES, ssl){
     include($$PWD/../../3rdparty/wolfssl/wolfssl.pri)
 }else{
@@ -54,6 +53,13 @@ win32 {
 HEADERS += $$PWD/../../3rdparty/uthash/src/utlist.h \
            $$PWD/../../3rdparty/uthash/src/uthash.h
 
+<<<<<<< HEAD
+=======
+#if(DAPSDK_MODULES MATCHES "ssl-support")
+#    include($$PWD/../../3rdparty/wolfssl/wolfssl.pri)
+#endif()
+
+>>>>>>> bd29a4e40515ee89520114dd5287c289e5f83b02
 # Sources itself
 HEADERS += $$PWD/include/dap_common.h \
     $$PWD/include/dap_binary_tree.h \
diff --git a/dap-sdk/core/src/android/CMakeLists.txt b/dap-sdk/core/src/android/CMakeLists.txt
index 1e9d95846f79bcecbdddf4c3debbf0d572798269..70d059ded56ed6c6f41a6afb940363248a6f18b5 100755
--- a/dap-sdk/core/src/android/CMakeLists.txt
+++ b/dap-sdk/core/src/android/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 project (dap_core_android C)
 
diff --git a/dap-sdk/core/src/dap_file_utils.c b/dap-sdk/core/src/dap_file_utils.c
index 30b3f7dc98effc0e4a69c5e6a0de728dcf81386f..ef6c15699c5bd3cd016580589b7205aa30220a97 100755
--- a/dap-sdk/core/src/dap_file_utils.c
+++ b/dap-sdk/core/src/dap_file_utils.c
@@ -160,8 +160,8 @@ int dap_mkdir_with_parents(const char *a_dir_path)
 #ifdef _WIN32
             int result = mkdir(path);
 #else
-            int result = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH | S_IWOTH);
-                         chmod(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH | S_IWOTH);
+            int result = mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO);
+                         chmod(path, S_IRWXU | S_IRWXG | S_IRWXO);
 #endif
             if(result == -1) {
                 errno = ENOTDIR;
diff --git a/dap-sdk/core/src/darwin/CMakeLists.txt b/dap-sdk/core/src/darwin/CMakeLists.txt
index 8f981d542da3e9b9540f764c97ee0a8fda60f7c1..651375ede9a29b1854e2e08ce329399b4981e732 100755
--- a/dap-sdk/core/src/darwin/CMakeLists.txt
+++ b/dap-sdk/core/src/darwin/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 project (dap_core_darwin)
 
diff --git a/dap-sdk/core/src/unix/CMakeLists.txt b/dap-sdk/core/src/unix/CMakeLists.txt
index 828fdfb757ca7c653c734c5caeb69b2621b1adfb..1e7ae9443e95046b8352320edbe9bb50ebd3a6c6 100755
--- a/dap-sdk/core/src/unix/CMakeLists.txt
+++ b/dap-sdk/core/src/unix/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 project (dap_core_unix)
 
diff --git a/dap-sdk/core/src/win32/CMakeLists.txt b/dap-sdk/core/src/win32/CMakeLists.txt
index f3d0c43a6662887771ccebe815b8f8102824b6e1..6f84da809b91ab4cc25fffd5a5dd135f41907414 100644
--- a/dap-sdk/core/src/win32/CMakeLists.txt
+++ b/dap-sdk/core/src/win32/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 project (dap_core_win32 C)
 
diff --git a/dap-sdk/core/test/CMakeLists.txt b/dap-sdk/core/test/CMakeLists.txt
index c9ef63ebb3d691543f98993ee2483497de6301c9..47f257f342a8b098a8552a7e6f2e0ee71aeecc40 100755
--- a/dap-sdk/core/test/CMakeLists.txt
+++ b/dap-sdk/core/test/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 project(core_test)
 
diff --git a/dap-sdk/core/test/math/unit_test.cpp b/dap-sdk/core/test/math/unit_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c37afbddb5e94e6f4367b2eb4c7a18ff1998f3e6
--- /dev/null
+++ b/dap-sdk/core/test/math/unit_test.cpp
@@ -0,0 +1,252 @@
+#include <boost/multiprecision/cpp_int.hpp>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "dap_math_ops.h"
+#include <cmath>
+#include <iostream>
+#include <fstream>
+
+int main()
+{
+   using namespace boost::multiprecision;
+
+   //density constant value=2147483646
+   std::uint64_t i;
+   std::uint64_t j;
+   std::uint64_t k;
+   std::uint64_t l;
+   std::uint64_t msb_one=0x7fffffffffffffff;
+   std::uint64_t lsb_one=1;
+   boost::uint64_t max_64=(std::numeric_limits<boost::uint64_t>::max)();
+   int density_constant=40000;
+   //2147483646
+   int density_index;
+   int error_counter_sum_64_128=0;
+    
+    
+   unsign256_t dap_test_256_one;
+   unsign256_t dap_test_256_two;
+   unsign256_t dap_test_256_sum;   
+   int overflow_flag;
+
+   //otherwise the sum structure is filled with garbage
+   dap_test_256_sum.lo.lo=0;
+   dap_test_256_sum.lo.hi=0;
+   dap_test_256_sum.hi.lo=0;
+   dap_test_256_sum.hi.hi=0;
+
+   std::ofstream sum_256_256_file;
+   sum_256_256_file.open ("SUM_256_256.txt");  
+
+   std::ofstream prod_64_128_file;
+   prod_64_128_file.open ("PROD_64_128.txt");  
+
+
+   uint128_t hi_64{"0xffffffffffffffff0000000000000000"};
+   uint128_t lo_64{"0x0000000000000000ffffffffffffffff"};
+   uint128_t max_128{"0xffffffffffffffffffffffffffffffff"};
+
+   uint128_t two_64{"0x000000000000000010000000000000000"};
+
+
+
+   uint256_t boost_two_64{"0x00000000000000000000000000000000010000000000000000"};
+   uint256_t boost_two_128{"0x0000000000000000100000000000000000000000000000000"};
+   uint256_t boost_two_192{"0x1000000000000000000000000000000000000000000000000"};
+
+
+   
+   uint256_t boost_test_256_one;
+   uint256_t boost_test_256_two;
+   uint256_t boost_test_256_sum;
+   
+   uint256_t boost_dap_256_comparison;
+
+
+   
+   uint128_t boost_dap_64_128_comparison;
+
+   int error_counter_sum=0;
+   int error_counter_prod=0;
+   int verbose_output=0;
+
+
+   for (density_index = 0; density_index<density_constant; density_index+=1000){
+
+        i=density_index;
+        j=2*density_index;
+        k=3*density_index;
+        l=4*density_index;
+
+        dap_test_256_one.lo.lo=i;
+        dap_test_256_one.lo.hi=j;
+        dap_test_256_one.hi.lo=k;
+        dap_test_256_one.hi.hi=l;
+
+
+        uint256_t boost_test_256_one_coeff_2_0=i;               
+        uint256_t boost_test_256_one_coeff_2_64=j;
+        uint256_t boost_test_256_one_coeff_2_128=k;
+        uint256_t boost_test_256_one_coeff_2_192=l;
+
+
+
+        boost_test_256_one=boost_test_256_one_coeff_2_0 + boost_test_256_one_coeff_2_64*boost_two_64
+        +boost_test_256_one_coeff_2_128*boost_two_128+boost_test_256_one_coeff_2_192*boost_two_192;
+
+
+        i=max_64-(density_index+1);
+        j=max_64-2*(density_index+1);
+        k=max_64-3*(density_index+1);
+        l=max_64-4*(density_index+1);
+        dap_test_256_two.lo.lo=i;
+        dap_test_256_two.lo.hi=j;
+        dap_test_256_two.hi.lo=k;
+        dap_test_256_two.hi.hi=l;
+
+        uint256_t boost_test_256_two_coeff_2_0=i;               
+        uint256_t boost_test_256_two_coeff_2_64=j;
+        uint256_t boost_test_256_two_coeff_2_128=k;
+        uint256_t boost_test_256_two_coeff_2_192=l;
+
+
+        boost_test_256_two=boost_test_256_two_coeff_2_0 + boost_test_256_two_coeff_2_64*boost_two_64
+        +boost_test_256_two_coeff_2_128*boost_two_128+boost_test_256_two_coeff_2_192*boost_two_192;
+
+       
+
+//        add(boost_add_256, i, j);
+        overflow_flag=SUM_256_256(dap_test_256_one,dap_test_256_two,&dap_test_256_sum);
+        boost_test_256_sum=add(boost_test_256_sum,boost_test_256_one,boost_test_256_two);
+        
+        boost_dap_256_comparison=dap_test_256_sum.lo.lo+dap_test_256_sum.lo.hi*boost_two_64+
+        dap_test_256_sum.hi.lo*boost_two_128+dap_test_256_sum.hi.hi*boost_two_192;
+
+        if(boost_dap_256_comparison!=boost_test_256_sum){
+        error_counter_sum+=1;
+        sum_256_256_file << "incorrect output for density index=" << std::endl;
+        sum_256_256_file << density_index << std::endl;}
+        
+
+
+//        unsign128_t dap_test_64_128_prod;
+//        uint128_t boost_test_64_128_prod;
+//        uint128_t boost_dap_128_prod_comparison;
+//        
+//        multiply(boost_test_64_128_prod, i, j);
+//        MULT_64_128(i,j,dap_test_64_128_prod);
+//        boost_dap_128_prod_comparison=dap_test_64_128_prod.lo+dap_test_64_128_prod.hi*hi_64;
+//        
+//        if(boost_dap_128_prod_comparison!=boost_test_64_128_prod){
+//            error_counter_prod+=1;}
+        
+
+        
+        if(verbose_output==1){
+
+        if(boost_dap_256_comparison!=boost_test_256_sum){
+
+        sum_256_256_file << "dap_test_256_one"<< std::endl;
+
+        sum_256_256_file << (dap_test_256_one.lo.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_one.lo.hi)<< std::endl;
+        sum_256_256_file << (dap_test_256_one.hi.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_one.hi.hi)<< std::endl;
+
+
+        sum_256_256_file << "dap_test_256_two"<< std::endl;
+
+        sum_256_256_file << (dap_test_256_two.lo.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_two.lo.hi)<< std::endl;
+        sum_256_256_file << (dap_test_256_two.hi.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_two.hi.hi)<< std::endl;
+
+        sum_256_256_file << "dap_test_256_sum"<< std::endl;
+
+        sum_256_256_file << (dap_test_256_sum.lo.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_sum.lo.hi)<< std::endl;
+        sum_256_256_file << (dap_test_256_sum.hi.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_sum.hi.hi)<< std::endl;
+
+        sum_256_256_file << "boost_test_256_one"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_one)<< std::endl;
+    
+        sum_256_256_file << "boost_test_256_one factor 0"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_one_coeff_2_0)<< std::endl;
+    
+        sum_256_256_file << "boost_test_256_one factor 1"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_one_coeff_2_64*boost_two_64)<< std::endl;
+
+        sum_256_256_file << "boost_test_256_one factor 2"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_one_coeff_2_128*boost_two_128)<< std::endl;
+    
+
+        sum_256_256_file << "boost_test_256_one factor 3"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_one_coeff_2_192*boost_two_192)<< std::endl;
+
+
+
+        sum_256_256_file << "boost_test_256_two"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_two)<< std::endl;
+
+
+        sum_256_256_file << "boost sum is"<< std::endl;
+
+
+        sum_256_256_file << (boost_test_256_sum)<< std::endl;
+
+        sum_256_256_file << "boost comparison is"<< std::endl;
+
+
+        sum_256_256_file << (boost_dap_256_comparison)<< std::endl;}
+
+    
+//        if(boost_dap_256_comparison!=boost_test_256_sum){
+//
+//        prod_64_128_file << "boost_dap_128_prod_comparison"<< std::endl;
+//
+//        prod_64_128_file << (boost_dap_128_prod_comparison)<< std::endl;
+//
+//        prod_64_128_file << "boost_test_64_128_prod"<< std::endl;
+//
+//        prod_64_128_file << (boost_test_64_128_prod)<< std::endl;
+//
+//}
+//
+
+
+
+
+
+
+}
+  
+        
+    overflow_flag=0;
+
+    }
+
+    
+    sum_256_256_file.close();
+
+   if(error_counter_sum==0){
+
+    std::cout<< "SUM_256_256 returns identical results to boost:: 256 bit addition"<< std::endl;}
+
+//
+//   if(error_counter_prod==0){
+//
+//   std::cout<< "SUM_256_256 returns identical results to boost:: 256 bit addition"<< std::endl;}
+
+
+   return 0;
+}
+
+
diff --git a/dap-sdk/core/test/uint256_t/unit_test.cpp b/dap-sdk/core/test/uint256_t/unit_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ac4371c00f3453e25c9e2b960ae34416a03eed21
--- /dev/null
+++ b/dap-sdk/core/test/uint256_t/unit_test.cpp
@@ -0,0 +1,898 @@
+#include <boost/multiprecision/cpp_int.hpp>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "dap_math_ops.h"
+#include <cmath>
+#include <iostream>
+#include <fstream>
+
+enum testing_mode{
+FULL=0,
+BASIC=1,
+SQUARE=2,   
+};
+
+int main()
+{
+   //using namespace boost::multiprecision;
+
+   //density constant value=2147483646
+   std::uint64_t i;
+   std::uint64_t j;
+   std::uint64_t k;
+   std::uint64_t l;
+   std::uint64_t msb_one=0x7fffffffffffffff;
+   std::uint64_t lsb_one=1;
+   boost::uint64_t max_64=(std::numeric_limits<boost::uint64_t>::max)();
+   
+
+   /////testing output parameters
+   int verbose_output=1;
+   int testing_mode=0;
+   int density_constant=200;
+   int division_enabled=0;
+
+
+   //2147483646
+   int density_index=0;
+   
+   int error_counter_sum_64_128=0;
+    
+   uint128_t dap_test_128_shift={.hi=0, .lo=0}; 
+   uint128_t dap_test_128_one={.hi=0, .lo=0};
+   uint128_t dap_test_128_two={.hi=0, .lo=0};
+   uint128_t dap_test_128_sub={.hi=0, .lo=0};
+   uint256_t dap_test_256_one={.hi=zero_128, .lo=zero_128};
+   uint256_t dap_test_256_two={.hi=zero_128, .lo=zero_128};
+   uint256_t dap_test_256_sum={.hi=zero_128, .lo=zero_128}; 
+   uint256_t dap_test_256_sub={.hi=zero_128, .lo=zero_128}; 
+   uint256_t dap_test_256_prod={.hi=zero_128, .lo=zero_128};
+   uint256_t dap_test_256_shift={.hi=zero_128, .lo=zero_128};
+   uint512_t dap_test_512_prod={.hi=zero_256, .lo=zero_256};
+   int overflow_flag;
+   int overflow_flag_prod;
+   int borrow_flag_128;
+   int borrow_flag_256;
+
+   //otherwise the sum structure is filled with garbage
+   dap_test_256_sum.lo.lo=0;
+   dap_test_256_sum.lo.hi=0;
+   dap_test_256_sum.hi.lo=0;
+   dap_test_256_sum.hi.hi=0;
+
+   std::ofstream sum_256_256_file;
+   sum_256_256_file.open ("SUM_256_256.txt");  
+
+   std::ofstream sub_128_128_file;
+   sub_128_128_file.open ("SUB_128_128.txt");  
+    
+   std::ofstream sub_256_256_file;
+   sub_256_256_file.open ("SUB_256_256.txt");  
+
+   std::ofstream prod_64_128_file;
+   prod_64_128_file.open ("PROD_64_128.txt");  
+
+   std::ofstream prod_128_128_file;
+   prod_128_128_file.open ("PROD_128_128.txt");  
+
+   std::ofstream prod_128_256_file;
+   prod_128_256_file.open ("PROD_128_256.txt");  
+
+   std::ofstream prod_256_256_file;
+   prod_256_256_file.open ("PROD_256_256.txt");  
+
+   std::ofstream prod_256_512_file;
+   prod_256_512_file.open ("PROD_256_512.txt"); 
+
+   std::ofstream shift_left_128_file;
+   shift_left_128_file.open ("SHIFT_LEFT_128.txt");  
+
+   std::ofstream shift_left_256_file;
+   shift_left_256_file.open ("SHIFT_LEFT_256.txt");  
+
+if (division_enabled==1){
+   std::ofstream quot_128_file;
+   quot_128_file.open ("QUOT_128.txt");  
+}
+
+
+   boost::multiprecision::uint128_t hi_64{"0xffffffffffffffff0000000000000000"};
+   boost::multiprecision::uint128_t lo_64{"0x0000000000000000ffffffffffffffff"};
+   boost::multiprecision::uint128_t max_128{"0xffffffffffffffffffffffffffffffff"};
+   boost::multiprecision::uint128_t two_64{"0x000000000000000010000000000000000"};
+
+   boost::multiprecision::uint256_t boost_two_64{"0x00000000000000000000000000000000010000000000000000"};
+   boost::multiprecision::uint256_t boost_two_128{"0x0000000000000000100000000000000000000000000000000"};
+   boost::multiprecision::uint256_t boost_two_192{"0x1000000000000000000000000000000000000000000000000"};
+
+   boost::multiprecision::uint512_t boost_two_64_for_512_calc{"0x00000000000000000000000000000000010000000000000000"};
+   boost::multiprecision::uint512_t boost_two_128_for_512_calc{"0x0000000000000000100000000000000000000000000000000"};
+   boost::multiprecision::uint512_t boost_two_192_for_512_calc{"0x1000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint512_t boost_two_256_for_512_calc{"0x000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000"};
+
+    boost::multiprecision::uint512_t boost_two_320_for_512_calc{"0x100000000000000000000000000000000000000000000000000000000000000000000000000000000"};
+    boost::multiprecision::uint512_t boost_two_384_for_512_calc{"0x1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"};
+    boost::multiprecision::uint512_t boost_two_448_for_512_calc{"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"};
+
+    boost::multiprecision::uint128_t boost_two_64_for_128_calc{"0x000000000000000010000000000000000"};   
+
+    
+
+
+   boost::multiprecision::uint256_t boost_test_256_one{"0x0000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint256_t boost_test_256_two{"0x0000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint256_t boost_test_256_sum{"0x0000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint256_t boost_test_256_sub{"0x0000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint256_t boost_test_256_prod{"0x0000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint256_t boost_test_512_prod_hi_prod{"0x0000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint256_t boost_test_512_prod_lo_prod{"0x0000000000000000000000000000000000000000000000000"};
+    
+
+   boost::multiprecision::uint512_t boost_test_2_256_quotient{"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint512_t boost_test_2_256_remainder{"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint512_t boost_test_512_prod{"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}; 
+
+   boost::multiprecision::uint128_t boost_test_128_one{"0x000000000000000000000000000000000"};
+   boost::multiprecision::uint128_t boost_test_128_two{"0x000000000000000000000000000000000"};
+   boost::multiprecision::uint128_t boost_test_128_sub{"0x000000000000000000000000000000000"};
+   boost::multiprecision::uint128_t boost_test_256_one_lo{"0x000000000000000000000000000000000"};
+   boost::multiprecision::uint128_t boost_test_256_one_hi{"0x000000000000000000000000000000000"};
+   boost::multiprecision::uint128_t boost_test_256_two_lo{"0x000000000000000000000000000000000"};
+   boost::multiprecision::uint128_t boost_test_256_two_hi{"0x000000000000000000000000000000000"};
+   boost::multiprecision::uint128_t boost_dap_64_128_comparison{"0x000000000000000000000000000000000"};
+   boost::multiprecision::uint128_t boost_test_shift_left_128{"0x000000000000000000000000000000000"};   
+   boost::multiprecision::uint128_t boost_test_shift_left_128_quotient_limb{"0x000000000000000000000000000000000"};
+   boost::multiprecision::uint128_t boost_test_shift_left_128_remainder_limb{"0x000000000000000000000000000000000"};
+   boost::multiprecision::uint128_t boost_dap_comparison_shift_left_128{"0x000000000000000000000000000000000"};    
+   boost::multiprecision::uint128_t boost_test_64_128_prod{"0x000000000000000000000000000000000"};
+   boost::multiprecision::uint128_t boost_dap_128_prod_comparison{"0x000000000000000000000000000000000"};    
+   boost::multiprecision::uint128_t boost_dap_128_comparison_sub{"0x000000000000000000000000000000000"};
+    
+   boost::multiprecision::uint256_t boost_dap_256_comparison{"0x0000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint256_t boost_dap_256_comparison_sub{"0x0000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint256_t boost_dap_256_comparison_prod{"0x0000000000000000000000000000000000000000000000000"}; 
+   boost::multiprecision::uint256_t boost_test_shift_left_256{"0x0000000000000000000000000000000000000000000000000"};
+   boost::multiprecision::uint256_t boost_dap_comparison_shift_left_256{"0x0000000000000000000000000000000000000000000000000"};
+    
+   boost::multiprecision::uint512_t boost_dap_512_comparison_prod{"0x0"}; 
+   
+
+
+    
+   int error_counter_sum=0;
+   int error_counter_prod=0;
+   int error_counter_sub_128=0;
+   int error_counter_sub_256=0;
+   int error_counter_prod_128_128=0;
+   int error_counter_prod_128_256=0;    
+   int error_counter_prod_256_256=0;
+   int error_counter_prod_256_512=0;
+   int error_counter_shift_left_128=0;
+   int error_counter_shift_left_256=0; 
+   int error_counter_quot_128=0;   
+   
+
+
+   for (density_index = 0; density_index<density_constant; density_index+=1){
+
+
+        /////////////////////output of 256+256-->256//////////////////////
+
+        if (testing_mode==FULL){
+        i=density_index;
+        j=2*density_index;
+        k=3*density_index;
+        l=4*density_index;
+        }
+        if (testing_mode==BASIC){
+        i=density_index;
+        j=density_index;
+        k=density_index;
+        l=density_index;
+        }
+
+        if (testing_mode==SQUARE){
+        i=density_index;
+        j=density_index;
+        k=density_index;
+        l=density_index;
+        }
+        
+
+        dap_test_256_one.lo.lo=i;
+        dap_test_256_one.lo.hi=j;
+        dap_test_256_one.hi.lo=k;
+        dap_test_256_one.hi.hi=l;
+
+
+        boost::multiprecision::uint256_t boost_test_256_one_coeff_2_0=i;               
+        boost::multiprecision::uint256_t boost_test_256_one_coeff_2_64=j;
+        boost::multiprecision::uint256_t boost_test_256_one_coeff_2_128=k;
+        boost::multiprecision::uint256_t boost_test_256_one_coeff_2_192=l;
+
+
+
+        boost_test_256_one=boost_test_256_one_coeff_2_0 + boost_test_256_one_coeff_2_64*boost_two_64
+        +boost_test_256_one_coeff_2_128*boost_two_128+boost_test_256_one_coeff_2_192*boost_two_192;
+        
+//        boost_test_256_one_hi=boost_test_256_one_coeff_2_128+boost_two_64*boost_test_256_one_coeff_2_192;
+//        boost_test_256_one_lo=boost_test_256_one_coeff_2_0+boost_test_256_one_coeff_2_64*boost_two_64;
+    
+        if(testing_mode==FULL){
+        i=max_64-(density_index+1);
+        j=max_64-2*(density_index+1);
+        k=max_64-3*(density_index+1);
+        l=max_64-4*(density_index+1);
+        }
+
+        if (testing_mode==BASIC){
+        i=density_index+1;
+        j=density_index+1;
+        k=density_index+1;
+        l=density_index+1;
+        }
+
+        if (testing_mode==SQUARE){
+        i=density_index;
+        j=density_index;
+        k=density_index;
+        l=density_index;  
+        }
+        
+
+        dap_test_256_two.lo.lo=i;
+        dap_test_256_two.lo.hi=j;
+        dap_test_256_two.hi.lo=k;
+        dap_test_256_two.hi.hi=l;
+       
+
+        boost::multiprecision::uint256_t boost_test_256_two_coeff_2_0=i;               
+        boost::multiprecision::uint256_t boost_test_256_two_coeff_2_64=j;
+        boost::multiprecision::uint256_t boost_test_256_two_coeff_2_128=k;
+        boost::multiprecision::uint256_t boost_test_256_two_coeff_2_192=l;
+
+
+        boost_test_256_two=boost_test_256_two_coeff_2_0 + boost_test_256_two_coeff_2_64*boost_two_64
+        +boost_test_256_two_coeff_2_128*boost_two_128+boost_test_256_two_coeff_2_192*boost_two_192;
+
+//        boost_test_256_two_hi=boost_test_256_two_coeff_2_128+boost_two_64*boost_test_256_two_coeff_2_192;
+//        boost_test_256_two_lo=boost_test_256_one_coeff_2_0+boost_test_256_two_coeff_2_64*boost_two_64;
+
+//        add(boost_add_256, i, j);
+        
+        overflow_flag=SUM_256_256(dap_test_256_one,dap_test_256_two,&dap_test_256_sum);
+        add(boost_test_256_sum,boost_test_256_one,boost_test_256_two);
+        
+        boost_dap_256_comparison=dap_test_256_sum.lo.lo+dap_test_256_sum.lo.hi*boost_two_64+
+        dap_test_256_sum.hi.lo*boost_two_128+dap_test_256_sum.hi.hi*boost_two_192;
+
+        if(boost_dap_256_comparison!=boost_test_256_sum){
+        error_counter_sum+=1;
+        sum_256_256_file << "incorrect output for density index=" << std::endl;
+        sum_256_256_file << density_index << std::endl;}
+
+    
+        ///256 bit subtraction
+
+        borrow_flag_256=SUBTRACT_256_256(dap_test_256_two,dap_test_256_one,&dap_test_256_sub);
+        subtract(boost_test_256_sub,boost_test_256_two,boost_test_256_one);
+        
+        boost_dap_256_comparison_sub=dap_test_256_sub.lo.lo+dap_test_256_sub.lo.hi*boost_two_64+
+        dap_test_256_sub.hi.lo*boost_two_128+dap_test_256_sub.hi.hi*boost_two_192;
+
+        if(boost_dap_256_comparison_sub!=boost_test_256_sub){
+        error_counter_sub_256+=1;
+        sub_256_256_file << "incorrect output for density index=" << std::endl;
+        sub_256_256_file << density_index << std::endl;}
+
+        
+
+
+
+        /////////////////////output of 256*256-->256//////////////////////
+
+        overflow_flag_prod=MULT_256_256(dap_test_256_one,dap_test_256_two,&dap_test_256_prod);
+        multiply(boost_test_256_prod,boost_test_256_one,boost_test_256_two);
+        multiply(boost_test_512_prod,boost_test_256_one,boost_test_256_two);
+//        multiply(boost_test_512_prod_hi_prod,boost_test_256_one_hi,boost_test_256_two_hi);
+//        multiply(boost_test_512_prod_lo_prod,boost_test_256_one_lo,boost_test_256_two_lo);
+        divide_qr(boost_test_512_prod,boost_two_256_for_512_calc,boost_test_2_256_quotient,boost_test_2_256_remainder);
+
+        boost_dap_256_comparison_prod=dap_test_256_prod.lo.lo+dap_test_256_prod.lo.hi*boost_two_64+
+        dap_test_256_prod.hi.lo*boost_two_128+dap_test_256_prod.hi.hi*boost_two_192;
+
+        if(boost_dap_256_comparison_prod!=boost_test_256_prod){
+        error_counter_prod_256_256+=1;
+        prod_256_256_file << "incorrect product output for density index=" << std::endl;
+        prod_256_256_file << density_index << std::endl;}
+
+        /////////////////////output of 256*256-->512//////////////////////
+        dap_test_512_prod.lo=zero_256;
+        dap_test_512_prod.hi=zero_256;
+        uint256_t intermed_lo_prod;
+        uint256_t intermed_hi_prod;
+        MULT_128_256(dap_test_256_one.lo,dap_test_256_two.lo,&intermed_lo_prod);
+        MULT_128_256(dap_test_256_one.hi,dap_test_256_two.hi,&intermed_hi_prod);
+        
+        MULT_256_512(dap_test_256_one,dap_test_256_two,&dap_test_512_prod);
+
+
+        boost_dap_512_comparison_prod=dap_test_512_prod.lo.lo.lo+
+        dap_test_512_prod.lo.lo.hi*boost_two_64_for_512_calc+
+        dap_test_512_prod.lo.hi.lo*boost_two_128_for_512_calc+
+        dap_test_512_prod.lo.hi.hi*boost_two_192_for_512_calc+
+        dap_test_512_prod.hi.lo.lo*boost_two_256_for_512_calc+
+        dap_test_512_prod.hi.lo.hi*boost_two_320_for_512_calc+
+        dap_test_512_prod.hi.hi.lo*boost_two_384_for_512_calc+
+        dap_test_512_prod.hi.hi.hi*boost_two_448_for_512_calc;
+
+        if(boost_dap_512_comparison_prod!=boost_test_512_prod){
+        error_counter_prod_256_512+=1;
+        prod_256_512_file << "incorrect product output for density index=" << std::endl;
+        prod_256_512_file << density_index << std::endl;}
+
+        /////////////////////output of shift left 128/////////////////////
+        
+        if (density_index<=127){
+        dap_test_128_one=dap_test_256_one.lo;
+        LEFT_SHIFT_128(dap_test_128_one,&dap_test_128_shift,density_index);
+
+        boost_test_128_one=dap_test_128_one.lo+dap_test_128_one.hi*boost_two_64_for_128_calc;
+        boost_test_shift_left_128=boost_test_128_one<<density_index;
+        boost_dap_comparison_shift_left_128=dap_test_128_shift.lo+dap_test_128_shift.hi*boost_two_64_for_128_calc;
+
+                 divide_qr(boost_test_shift_left_128,boost_two_64_for_128_calc,boost_test_shift_left_128_quotient_limb,boost_test_shift_left_128_remainder_limb);
+        
+        if(boost_dap_comparison_shift_left_128!=boost_test_shift_left_128){
+        error_counter_shift_left_128+=1;
+        shift_left_128_file << "incorrect shift left 128 output for density index=" << std::endl;
+        shift_left_128_file << density_index << std::endl;}
+        }
+        /////////////////////output of shift left 256/////////////////////
+        
+        if (density_index<=255){
+        LEFT_SHIFT_256(dap_test_256_one,&dap_test_256_shift,density_index);
+
+        boost_test_256_one=boost_test_256_one_coeff_2_0 + boost_test_256_one_coeff_2_64*boost_two_64
+        +boost_test_256_one_coeff_2_128*boost_two_128+boost_test_256_one_coeff_2_192*boost_two_192;
+        boost_test_shift_left_256=boost_test_256_one<<density_index;
+        boost_dap_comparison_shift_left_256=dap_test_256_shift.lo.lo+dap_test_256_shift.lo.hi*boost_two_64+
+        dap_test_256_shift.hi.lo*boost_two_128+dap_test_256_shift.hi.hi*boost_two_192;
+
+        
+        if(boost_dap_comparison_shift_left_256!=boost_test_shift_left_256){
+        error_counter_shift_left_256+=1;
+        shift_left_256_file << "incorrect shift left 256 output for density index=" << std::endl;
+        shift_left_256_file << density_index << std::endl;}
+        }
+    
+        /////////////////////output of 64*64-->128////////////////////////
+
+
+        i=density_index;
+        j=max_64-(density_index+1);
+        uint128_t dap_test_64_128_prod;
+        dap_test_64_128_prod.lo=0;
+        dap_test_64_128_prod.hi=0;
+ 
+
+
+        multiply(boost_test_64_128_prod, i, j);
+        MULT_64_128(i,j,&dap_test_64_128_prod);
+        boost_dap_128_prod_comparison=dap_test_64_128_prod.lo+dap_test_64_128_prod.hi*two_64;
+        
+        if(boost_dap_128_prod_comparison!=boost_test_64_128_prod){
+            error_counter_prod+=1;}
+
+        /////////////////////output of 128*128-->128////////////////////////
+
+        uint128_t dap_test_128_128_prod_one;
+        uint128_t dap_test_128_128_prod_two;
+        uint128_t dap_test_128_128_prod_prod;
+        dap_test_128_128_prod_one.lo=i;
+        dap_test_128_128_prod_one.hi=j;
+        dap_test_128_128_prod_two.lo=max_64-(i+1);
+        dap_test_128_128_prod_two.hi=max_64-2*(j+1);
+        dap_test_128_128_prod_prod.lo=0;
+        dap_test_128_128_prod_prod.hi=0;
+        
+        boost::multiprecision::uint128_t boost_test_128_128_prod;
+        boost::multiprecision::uint128_t boost_test_128_128_one;
+        boost::multiprecision::uint128_t boost_test_128_128_two;   
+        boost::multiprecision::uint128_t boost_dap_128_128_prod_comparison;
+
+        ////compute boost "factors"
+        boost_test_128_128_one=i+j*boost_two_64_for_128_calc;
+        boost_test_128_128_two=max_64-(i+1)+(max_64-2*(j+1))*boost_two_64_for_128_calc;
+        
+        
+        multiply(boost_test_128_128_prod, boost_test_128_128_one, boost_test_128_128_two);
+        MULT_128_128(dap_test_128_128_prod_one,dap_test_128_128_prod_two,&dap_test_128_128_prod_prod);
+        boost_dap_128_128_prod_comparison=dap_test_128_128_prod_prod.lo+dap_test_128_128_prod_prod.hi*boost_two_64_for_128_calc;
+        
+        if(boost_dap_128_128_prod_comparison!=boost_test_128_128_prod){
+            error_counter_prod_128_128+=1;}
+
+
+        ///128 bit subtraction
+
+        borrow_flag_128=SUBTRACT_128_128(dap_test_128_one,dap_test_128_two,&dap_test_128_sub);
+        subtract(boost_test_128_sub,boost_test_128_one,boost_test_128_two);
+        
+        boost_dap_128_comparison_sub=dap_test_128_sub.lo+dap_test_128_sub.hi*boost_two_64_for_128_calc;
+        
+
+        if(boost_dap_128_comparison_sub!=boost_test_128_sub){
+        error_counter_sub_128+=1;
+        sub_128_128_file << "incorrect output for density index=" << std::endl;
+        sub_128_128_file << density_index << std::endl;}
+
+        
+
+
+
+        /////////////////////output of 128*128-->256////////////////////////
+
+        
+        uint128_t dap_test_128_256_prod_one;
+        uint128_t dap_test_128_256_prod_two;
+        uint256_t dap_test_128_256_prod_prod;
+        dap_test_128_256_prod_one.lo=i;
+        dap_test_128_256_prod_one.hi=j;
+        dap_test_128_256_prod_two.lo=max_64-(i+1);
+        dap_test_128_256_prod_two.hi=max_64-2*(j+1);
+        dap_test_128_256_prod_prod.lo=zero_128;
+        dap_test_128_256_prod_prod.hi=zero_128;
+        
+        boost::multiprecision::uint256_t boost_test_128_256_prod;
+        boost::multiprecision::uint128_t boost_test_128_256_one;
+        boost::multiprecision::uint128_t boost_test_128_256_two;   
+        boost::multiprecision::uint256_t boost_dap_128_256_prod_comparison;
+
+        ////compute boost "factors"
+        boost_test_128_256_one=i+j*boost_two_64_for_128_calc;
+        boost_test_128_256_two=(max_64-(i+1))+(max_64-2*(j+1))*boost_two_64_for_128_calc;
+        
+        multiply(boost_test_128_256_prod, boost_test_128_256_one, boost_test_128_256_two);
+        MULT_128_256(dap_test_128_256_prod_one,dap_test_128_256_prod_two,&dap_test_128_256_prod_prod);
+        boost_dap_128_256_prod_comparison=dap_test_128_256_prod_prod.lo.lo+
+        dap_test_128_256_prod_prod.lo.hi*boost_two_64+
+        dap_test_128_256_prod_prod.hi.lo*boost_two_128+
+        dap_test_128_256_prod_prod.hi.hi*boost_two_192;
+    
+
+        
+        if(boost_dap_128_256_prod_comparison!=boost_test_128_256_prod){
+            
+            error_counter_prod_128_256+=1;
+
+            std::cout << ("boost_dap_128_256_prod_comparison")<< std::endl;
+            std::cout << (boost_dap_128_256_prod_comparison)<< std::endl;
+            std::cout << ("boost_test_128_256_prod")<< std::endl;
+            std::cout << (boost_test_128_256_prod)<< std::endl;}
+
+
+        /////////////////////output of 128/128-->128////////////////////////
+if(division_enabled==1){
+
+        i=density_index+1;
+        j=density_index+2;
+        uint128_t dap_test_128_quot_one;
+        uint128_t dap_test_128_quot_two;
+        uint128_t dap_test_128_quot_quot;
+        uint128_t dap_test_128_quot_rem;
+        dap_test_128_quot_one.lo=i;
+        dap_test_128_quot_one.hi=j;
+        dap_test_128_quot_two.lo=max_64-(i+1);
+        dap_test_128_quot_two.hi=max_64-2*(j+1);
+        dap_test_128_quot_quot.lo=0;
+        dap_test_128_quot_quot.hi=0;
+        dap_test_128_quot_rem.lo=0;
+        dap_test_128_quot_rem.hi=0;
+        
+        boost::multiprecision::uint128_t boost_test_128_quot_one;
+        boost::multiprecision::uint128_t boost_test_128_quot_two;   
+        boost::multiprecision::uint128_t boost_test_128_quot_quot;
+        boost::multiprecision::uint128_t boost_test_128_quot_rem;
+        boost::multiprecision::uint128_t boost_dap_128_quot_comparison_quot;
+        boost::multiprecision::uint128_t boost_dap_128_quot_comparison_rem;
+
+        ////compute boost "factors"
+        boost_test_128_quot_one=i+j*boost_two_64_for_128_calc;
+        boost_test_128_quot_two=(max_64-(i+1))+(max_64-2*(j+1))*boost_two_64_for_128_calc;
+        
+        divide_qr( boost_test_128_quot_two, boost_test_128_quot_one,boost_test_128_quot_quot,boost_test_128_quot_rem);
+        bindivmod128(dap_test_128_quot_one,dap_test_128_quot_two,&dap_test_128_quot_quot,&dap_test_128_quot_rem);
+
+
+        boost_dap_128_quot_comparison_quot=dap_test_128_quot_quot.lo+
+        dap_test_128_quot_quot.hi*boost_two_64_for_128_calc;
+
+        boost_dap_128_quot_comparison_rem=dap_test_128_quot_rem.lo+
+        dap_test_128_quot_rem.hi*boost_two_64_for_128_calc;
+
+        
+        if((boost_dap_128_quot_comparison_quot!=boost_test_128_quot_quot)||(boost_dap_128_quot_comparison_rem!=boost_test_128_quot_rem)){
+            
+            error_counter_quot_128+=1;
+
+            std::cout << ("boost_dap_128_quot_comparison_quot")<< std::endl;
+            std::cout << (boost_dap_128_quot_comparison_quot)<< std::endl;
+            std::cout << ("boost_dap_128_quot_comparison_rem")<< std::endl;
+            std::cout << (boost_dap_128_quot_comparison_rem)<< std::endl;}
+
+}
+
+
+        /////////////////////print to file section////////////////////////
+
+        
+        if(verbose_output==1){
+
+        if(boost_dap_256_comparison!=boost_test_256_sum){
+
+        sum_256_256_file << "dap_test_256_one"<< std::endl;
+
+        sum_256_256_file << (dap_test_256_one.lo.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_one.lo.hi)<< std::endl;
+        sum_256_256_file << (dap_test_256_one.hi.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_one.hi.hi)<< std::endl;
+
+
+        sum_256_256_file << "dap_test_256_two"<< std::endl;
+
+        sum_256_256_file << (dap_test_256_two.lo.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_two.lo.hi)<< std::endl;
+        sum_256_256_file << (dap_test_256_two.hi.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_two.hi.hi)<< std::endl;
+
+        sum_256_256_file << "dap_test_256_sum"<< std::endl;
+
+        sum_256_256_file << (dap_test_256_sum.lo.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_sum.lo.hi)<< std::endl;
+        sum_256_256_file << (dap_test_256_sum.hi.lo)<< std::endl;
+        sum_256_256_file << (dap_test_256_sum.hi.hi)<< std::endl;
+
+        sum_256_256_file << "boost_test_256_one"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_one)<< std::endl;
+    
+        sum_256_256_file << "boost_test_256_one factor 0"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_one_coeff_2_0)<< std::endl;
+    
+        sum_256_256_file << "boost_test_256_one factor 1"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_one_coeff_2_64*boost_two_64)<< std::endl;
+
+        sum_256_256_file << "boost_test_256_one factor 2"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_one_coeff_2_128*boost_two_128)<< std::endl;
+    
+
+        sum_256_256_file << "boost_test_256_one factor 3"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_one_coeff_2_192*boost_two_192)<< std::endl;
+
+
+
+        sum_256_256_file << "boost_test_256_two"<< std::endl;
+
+        sum_256_256_file << (boost_test_256_two)<< std::endl;
+
+
+        sum_256_256_file << "boost sum is"<< std::endl;
+
+
+        sum_256_256_file << (boost_test_256_sum)<< std::endl;
+
+        sum_256_256_file << "boost comparison is"<< std::endl;
+
+
+        sum_256_256_file << (boost_dap_256_comparison)<< std::endl;}
+
+    
+        if(boost_dap_256_comparison_prod!=boost_test_256_prod){
+
+        prod_256_256_file << "dap_test_256_one"<< std::endl;
+
+        prod_256_256_file << (dap_test_256_one.lo.lo)<< std::endl;
+        prod_256_256_file << (dap_test_256_one.lo.hi)<< std::endl;
+        prod_256_256_file << (dap_test_256_one.hi.lo)<< std::endl;
+        prod_256_256_file << (dap_test_256_one.hi.hi)<< std::endl;
+
+
+        prod_256_256_file << "dap_test_256_two"<< std::endl;
+
+        prod_256_256_file << (dap_test_256_two.lo.lo)<< std::endl;
+        prod_256_256_file << (dap_test_256_two.lo.hi)<< std::endl;
+        prod_256_256_file << (dap_test_256_two.hi.lo)<< std::endl;
+        prod_256_256_file << (dap_test_256_two.hi.hi)<< std::endl;
+
+        prod_256_256_file << "dap_test_256_prod"<< std::endl;
+
+        prod_256_256_file << (dap_test_256_prod.lo.lo)<< std::endl;
+        prod_256_256_file << (dap_test_256_prod.lo.hi)<< std::endl;
+        prod_256_256_file << (dap_test_256_prod.hi.lo)<< std::endl;
+        prod_256_256_file << (dap_test_256_prod.hi.hi)<< std::endl;
+
+        prod_256_256_file << "boost_test_256_one"<< std::endl;
+
+        prod_256_256_file << (boost_test_256_one)<< std::endl;
+    
+        prod_256_256_file << "boost_test_256_one factor 0"<< std::endl;
+
+        prod_256_256_file << (boost_test_256_one_coeff_2_0)<< std::endl;
+    
+        prod_256_256_file << "boost_test_256_one factor 1"<< std::endl;
+
+        prod_256_256_file << (boost_test_256_one_coeff_2_64*boost_two_64)<< std::endl;
+
+        prod_256_256_file << "boost_test_256_one factor 2"<< std::endl;
+
+        prod_256_256_file << (boost_test_256_one_coeff_2_128*boost_two_128)<< std::endl;
+    
+
+        prod_256_256_file << "boost_test_256_one factor 3"<< std::endl;
+
+        prod_256_256_file << (boost_test_256_one_coeff_2_192*boost_two_192)<< std::endl;
+
+
+
+        prod_256_256_file << "boost_test_256_two"<< std::endl;
+
+        prod_256_256_file << (boost_test_256_two)<< std::endl;
+
+
+
+        prod_256_256_file << "boost_test_256_two factor 0"<< std::endl;
+
+        prod_256_256_file << (boost_test_256_two_coeff_2_0)<< std::endl;
+    
+        prod_256_256_file << "boost_test_256_two factor 1"<< std::endl;
+
+        prod_256_256_file << (boost_test_256_two_coeff_2_64*boost_two_64)<< std::endl;
+
+        prod_256_256_file << "boost_test_256_two factor 2"<< std::endl;
+
+        prod_256_256_file << (boost_test_256_two_coeff_2_128*boost_two_128)<< std::endl;
+    
+        prod_256_256_file << "boost_test_256_two factor 3"<< std::endl;
+
+        prod_256_256_file << (boost_test_256_two_coeff_2_192*boost_two_192)<< std::endl;
+
+
+        prod_256_256_file << "boost 256 prod is"<< std::endl;
+
+
+        prod_256_256_file << (boost_test_256_prod)<< std::endl;
+
+
+        prod_256_256_file << "boost 512 prod is"<< std::endl;
+
+
+        prod_256_256_file << (boost_test_512_prod)<< std::endl;
+
+
+        prod_256_256_file << "boost 2**256 quotient is"<< std::endl;
+
+
+        prod_256_256_file << (boost_test_2_256_quotient)<< std::endl;
+
+        prod_256_256_file << "boost 2**256 remainder is"<< std::endl;
+
+
+        prod_256_256_file << (boost_test_2_256_remainder)<< std::endl;
+
+        prod_256_256_file << "boost comparison is"<< std::endl;
+
+        prod_256_256_file << (boost_dap_256_comparison_prod)<< std::endl;}
+
+        if(boost_dap_512_comparison_prod!=boost_test_512_prod){
+
+
+        prod_256_512_file << "dap_test_512_prod"<< std::endl;
+
+        prod_256_512_file << (dap_test_512_prod.lo.lo.lo)<< std::endl;
+        prod_256_512_file << (dap_test_512_prod.lo.lo.hi)<< std::endl;
+        prod_256_512_file << (dap_test_512_prod.lo.hi.lo)<< std::endl;
+        prod_256_512_file << (dap_test_512_prod.lo.hi.hi)<< std::endl;
+        prod_256_512_file << (dap_test_512_prod.hi.lo.lo)<< std::endl;
+        prod_256_512_file << (dap_test_512_prod.hi.lo.hi)<< std::endl;
+        prod_256_512_file << (dap_test_512_prod.hi.hi.lo)<< std::endl;
+        prod_256_512_file << (dap_test_512_prod.hi.hi.hi)<< std::endl;
+
+
+        prod_256_512_file << "boost 512 prod is"<< std::endl;
+
+        prod_256_512_file << (boost_test_512_prod)<< std::endl;
+
+        prod_256_512_file << "boost comparison is"<< std::endl;
+
+        prod_256_512_file << (boost_dap_512_comparison_prod)<< std::endl;}
+
+
+        if(boost_test_64_128_prod!=boost_dap_128_prod_comparison){
+        
+        prod_64_128_file <<  " i is "<< std::endl;
+
+        prod_64_128_file << (i)<< std::endl;
+        
+        prod_64_128_file <<  " j is "<< std::endl;
+
+        prod_64_128_file << (j)<< std::endl;
+
+        prod_64_128_file << "boost_dap_128_prod_comparison"<< std::endl;
+
+        prod_64_128_file << (boost_dap_128_prod_comparison)<< std::endl;
+
+        prod_64_128_file << "boost_test_64_128_prod"<< std::endl;
+
+        prod_64_128_file << (boost_test_64_128_prod)<< std::endl;
+
+        prod_64_128_file << "difference"<< std::endl;
+
+        prod_64_128_file << (boost_dap_128_prod_comparison-boost_test_64_128_prod)<< std::endl;
+
+}
+
+
+        if(boost_test_128_128_prod!=boost_dap_128_128_prod_comparison){
+        
+        prod_128_128_file <<  " i is "<< std::endl;
+
+        prod_128_128_file << (i)<< std::endl;
+        
+        prod_128_128_file <<  " j is "<< std::endl;
+
+        prod_128_128_file << (j)<< std::endl;
+
+        prod_128_128_file <<  " boost_test_128_128_one is "<< std::endl;
+
+        prod_128_128_file << (boost_test_128_128_one)<< std::endl;
+
+        prod_128_128_file <<  " boost_test_128_128_two is "<< std::endl;
+
+        prod_128_128_file << (boost_test_128_128_two)<< std::endl;
+
+        prod_128_128_file << "boost_dap_128_128_prod_comparison"<< std::endl;
+
+        prod_128_128_file << (boost_dap_128_128_prod_comparison)<< std::endl;
+
+        prod_128_128_file << "dap_test_128_128_prod_prod.lo"<< std::endl;
+
+        prod_128_128_file << (dap_test_128_128_prod_prod.lo)<< std::endl;
+
+        prod_128_128_file << "dap_test_128_128_prod_prod.hi"<< std::endl;
+
+        prod_128_128_file << (dap_test_128_128_prod_prod.hi)<< std::endl;
+
+
+        prod_128_128_file << "boost_test_128_128_prod"<< std::endl;
+
+        prod_128_128_file << (boost_test_128_128_prod)<< std::endl;}
+
+
+  
+if (density_index<=127){
+  if(boost_dap_comparison_shift_left_128!=boost_test_shift_left_128){
+        shift_left_128_file <<  " density_index is "<< std::endl;
+
+        shift_left_128_file << (density_index)<< std::endl;
+
+        shift_left_128_file <<  " dap_test_128_one is "<< std::endl;
+
+        shift_left_128_file << (dap_test_128_one.lo)<< std::endl;
+        shift_left_128_file << (dap_test_128_one.hi)<< std::endl;
+        
+        shift_left_128_file <<  " dap_test_128_shift is "<< std::endl;
+
+        shift_left_128_file << (dap_test_128_shift.lo)<< std::endl;
+        shift_left_128_file << (dap_test_128_shift.hi)<< std::endl;
+
+        shift_left_128_file <<  " boost_test_shift_left_128 .lo is  "<< std::endl;
+        shift_left_128_file << boost_test_shift_left_128_remainder_limb<< std::endl;
+
+        shift_left_128_file <<  " boost_test_shift_left_128 .hi is  "<< std::endl;
+        shift_left_128_file << boost_test_shift_left_128_quotient_limb<< std::endl;
+
+
+        }
+        }
+
+
+ if (density_index<=255){
+ if(boost_dap_comparison_shift_left_256!=boost_test_shift_left_256){
+
+
+        shift_left_256_file <<  " density_index is "<< std::endl;
+
+        shift_left_256_file << (density_index)<< std::endl;
+
+        shift_left_256_file <<  " dap_test_256_one is "<< std::endl;
+
+        shift_left_256_file << (dap_test_256_one.lo.lo)<< std::endl;
+        shift_left_256_file << (dap_test_256_one.lo.hi)<< std::endl;
+        shift_left_256_file << (dap_test_256_one.hi.lo)<< std::endl;
+        shift_left_256_file << (dap_test_256_one.hi.hi)<< std::endl;
+   
+        
+        shift_left_256_file <<  " dap_test_256_shift is "<< std::endl;
+
+        shift_left_256_file << (dap_test_256_shift.lo.lo)<< std::endl;
+        shift_left_256_file << (dap_test_256_shift.lo.hi)<< std::endl;
+        shift_left_256_file << (dap_test_256_shift.hi.lo)<< std::endl;
+        shift_left_256_file << (dap_test_256_shift.hi.hi)<< std::endl;}
+    }
+    } 
+        
+    overflow_flag=0;
+
+    }
+    
+    sum_256_256_file.close();
+
+   if(error_counter_sum==0){
+
+    std::cout<< "SUM_256_256 returns identical results to boost:: 256 bit addition"<< std::endl;}
+
+    prod_64_128_file.close();
+
+   if(error_counter_sub_128==0){
+
+    std::cout<< "SUB_128_128 returns identical results to boost:: 128 bit subtraction"<< std::endl;}
+
+    sub_128_128_file.close();
+
+   if(error_counter_sub_256==0){
+
+    std::cout<< "SUB_256_256 returns identical results to boost:: 256 bit subtraction"<< std::endl;}
+
+    sub_256_256_file.close();
+
+
+   if(error_counter_prod==0){
+
+   std::cout<< "PROD_64_128 returns identical results to boost:: multiplication"<< std::endl;}
+
+   prod_128_128_file.close();
+
+   if(error_counter_prod_128_128==0){
+
+   std::cout<< "PROD_128_128 returns identical results to boost:: 128 bit multiplication"<< std::endl;}
+
+   if(error_counter_prod_128_256==0){
+
+   std::cout<< "PROD_128_256 returns identical results to boost:: 128 bit multiplication"<< std::endl;}
+
+   if(error_counter_prod_256_256==0){
+
+   std::cout<< "PROD_256_256 returns identical results to boost:: 256 bit multiplication"<< std::endl;}
+
+    if(error_counter_prod_256_512==0){
+
+   std::cout<< "PROD_256_512 returns identical results to boost:: 256 bit multiplication"<< std::endl;}
+
+
+   
+   if(error_counter_shift_left_128==0){
+
+    std::cout<< "SHIFT_LEFT_128 returns identical results to boost:: 128 bit <<"<< std::endl;}
+   
+   
+   if(error_counter_shift_left_256==0){
+
+    std::cout<< "SHIFT_LEFT_256 returns identical results to boost:: 256 bit <<"<< std::endl;}
+
+if (division_enabled==1){
+
+   if(error_counter_quot_128==0){
+
+    std::cout<< "QUOT_128 returns identical results to boost:: 128 bit division"<< std::endl;}
+   
+}
+   return 0;
+}
+
+
diff --git a/dap-sdk/crypto/CMakeLists.txt b/dap-sdk/crypto/CMakeLists.txt
index 3badd0046895a28ec855633f5e2ba59e44263a7f..91dd01a80a3599e41c81b28cd1c5e35f500d0e70 100755
--- a/dap-sdk/crypto/CMakeLists.txt
+++ b/dap-sdk/crypto/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_crypto)
 
 # fix implicit declaration warnings
diff --git a/dap-sdk/crypto/include/dap_hash.h b/dap-sdk/crypto/include/dap_hash.h
index 31cc4441929242c3130e2d4ff2d45147b36b7652..73b0c3a2869e0d07e8603766c0c678cbd453a7c5 100755
--- a/dap-sdk/crypto/include/dap_hash.h
+++ b/dap-sdk/crypto/include/dap_hash.h
@@ -36,7 +36,7 @@
 
 #define DAP_HASH_FAST_SIZE  32
 #define DAP_CHAIN_HASH_FAST_SIZE    32
-
+#define DAP_CHAIN_HASH_FAST_STR_SIZE (DAP_CHAIN_HASH_FAST_SIZE * 2 + 2 /* heading 0x */ + 1 /*trailing zero*/)
 #define DAP_CHAIN_HASH_MAX_SIZE 63
 
 typedef enum dap_hash_type {
@@ -53,7 +53,6 @@ typedef dap_chain_hash_fast_t dap_hash_fast_t;
 extern "C" {
 #endif
 
-//size_t dap_chain_hash_fast_to_str(dap_chain_hash_fast_t * a_hash, char * a_str, size_t a_str_max);
 int dap_chain_hash_fast_from_str( const char * a_hash_str, dap_hash_fast_t * a_hash);
 
 /**
@@ -74,14 +73,12 @@ static inline bool dap_hash_fast( const void *a_data_in, size_t a_data_in_size,
 
     SHA3_256( (unsigned char *)a_hash_out, (const unsigned char *)a_data_in, a_data_in_size );
 
-  //SHA3_256( (unsigned char *)a_hash_out, (const unsigned char *)a_data_in, a_data_in_size );
-
-  return true;
+    return true;
 }
 
 
 /**
- * @brief 
+ * @brief dap_hash_fast_compare
  * compare to hashes (dap_hash_fast_t) through memcmp
  * @param a_hash1 - dap_hash_fast_t hash1
  * @param a_hash2 - dap_hash_fast_t hash2
@@ -106,48 +103,39 @@ static inline bool dap_hash_fast_compare(dap_hash_fast_t *a_hash1, dap_hash_fast
 
 static inline bool dap_hash_fast_is_blank( dap_hash_fast_t *a_hash )
 {
-    static dap_hash_fast_t l_blank_hash = { 0};
-//    uint8_t *l_hast_bytes = (uint8_t*) a_hash;
-//    for(size_t i = 0; i < sizeof(dap_chain_hash_fast_t); i++) {
-//        if(l_hast_bytes[i])
-//            return false;
-//    }
+    static dap_hash_fast_t l_blank_hash = {};
     return dap_hash_fast_compare( a_hash, &l_blank_hash);
 }
 
 
 DAP_STATIC_INLINE int dap_chain_hash_fast_to_str( dap_hash_fast_t *a_hash, char *a_str, size_t a_str_max )
 {
-    if(!a_str )
+    if(! a_hash )
         return -1;
     if(! a_str )
         return -2;
-    if( a_str_max < (DAP_CHAIN_HASH_FAST_SIZE * 2 + 2) )
+    if( a_str_max < DAP_CHAIN_HASH_FAST_STR_SIZE )
         return -3;
     a_str[0] = '0';
     a_str[1] = 'x';
-    a_str[ DAP_CHAIN_HASH_FAST_SIZE * 2 + 2] = 0;
+    a_str[ DAP_CHAIN_HASH_FAST_STR_SIZE - 1 ] = 0;
     dap_htoa64((a_str + 2), a_hash->raw, DAP_CHAIN_HASH_FAST_SIZE);
-    return DAP_CHAIN_HASH_FAST_SIZE * 2 + 2;
+    return DAP_CHAIN_HASH_FAST_STR_SIZE;
 }
 
-DAP_STATIC_INLINE int dap_hash_fast_to_str(dap_hash_fast_t *a_hash, char *a_str, size_t a_str_max){
-    return dap_chain_hash_fast_to_str(a_hash,a_str,a_str_max);
-}
+#define dap_hash_fast_to_str dap_chain_hash_fast_to_str
 
 DAP_STATIC_INLINE char *dap_chain_hash_fast_to_str_new(dap_hash_fast_t * a_hash)
 {
-    const size_t c_hash_str_size = sizeof(*a_hash)*2 +1 /*trailing zero*/ +2 /* heading 0x */+4/*just to be sure*/ ;
+    const size_t c_hash_str_size = DAP_CHAIN_HASH_FAST_STR_SIZE;
     char * ret = DAP_NEW_Z_SIZE(char, c_hash_str_size);
     if(dap_chain_hash_fast_to_str( a_hash, ret, c_hash_str_size ) < 0 )
         DAP_DEL_Z(ret);
     return ret;
 }
 
-DAP_STATIC_INLINE char *dap_hash_fast_to_str_new(dap_hash_fast_t * a_hash)
-{
-    return dap_chain_hash_fast_to_str_new(a_hash);
-}
+#define dap_hash_fast_to_str_new dap_chain_hash_fast_to_str_new
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/dap-sdk/crypto/src/dap_cert_file.c b/dap-sdk/crypto/src/dap_cert_file.c
index 68c8e0ea58a6a1a845a6adafbc0915a6cccb72d4..fdbfad91bf9058a818312529a8289da9d1361b07 100755
--- a/dap-sdk/crypto/src/dap_cert_file.c
+++ b/dap-sdk/crypto/src/dap_cert_file.c
@@ -80,7 +80,6 @@ int dap_cert_file_save(dap_cert_t * a_cert, const char * a_cert_file_path)
  * @param a_left_idx size_t left tree node
  * @param a_right_idx size_t right tree node
  */
-
 void s_balance_the_tree(dap_cert_file_aux_t *a_reorder, size_t a_left_idx, size_t a_right_idx)
 {
     if (a_left_idx == a_right_idx) {
diff --git a/dap-sdk/crypto/src/dap_enc_dilithium.c b/dap-sdk/crypto/src/dap_enc_dilithium.c
index bf6ddd748c24db928c2f96e2a2eb4e8e059c5dd7..bf35a074976241b0fa7add50ee1eae2f9d3b4f7f 100755
--- a/dap-sdk/crypto/src/dap_enc_dilithium.c
+++ b/dap-sdk/crypto/src/dap_enc_dilithium.c
@@ -88,7 +88,7 @@ size_t dap_enc_sig_dilithium_verify_sign(struct dap_enc_key * key, const void *
     if( l_ret != 0)
         log_it(L_WARNING,"Wrong signature, can't open with code %d", l_ret);
 
-    return l_ret>0? l_ret : 0;
+    return l_ret < 0 ? l_ret : 0;
 }
 
 void dap_enc_sig_dilithium_key_delete(struct dap_enc_key * key)
diff --git a/dap-sdk/crypto/src/dap_enc_tesla.c b/dap-sdk/crypto/src/dap_enc_tesla.c
index a67cb0618fe84f26f2ebc8c86304d56a8e6b1057..54e40d2e09639b0d264d6fee6e38040453170db6 100755
--- a/dap-sdk/crypto/src/dap_enc_tesla.c
+++ b/dap-sdk/crypto/src/dap_enc_tesla.c
@@ -94,7 +94,7 @@ size_t dap_enc_sig_tesla_verify_sign(struct dap_enc_key * key, const void * msg,
 {
     if(signature_size < sizeof(tesla_signature_t)) {
         log_it(L_ERROR, "bad signature size");
-        return 0;
+        return -6;
     }
 
     return (tesla_crypto_sign_open((tesla_signature_t *) signature, (unsigned char *) msg, msg_size, key->pub_key_data));
diff --git a/dap-sdk/crypto/src/dap_hash.c b/dap-sdk/crypto/src/dap_hash.c
index a826d81f6f468bd7d6301d41314484a47283b942..7a625746845f623133c80e41c4db00ea531f1cfc 100755
--- a/dap-sdk/crypto/src/dap_hash.c
+++ b/dap-sdk/crypto/src/dap_hash.c
@@ -54,7 +54,7 @@ int dap_chain_hash_fast_from_str( const char * a_hash_str, dap_chain_hash_fast_t
             *(a_hash->raw + l_offset / 2 - 1) = l_byte;
         }
         return  0;
-    }else  // Wromg string len
+    }else  // Wrong string len
         return -1;
 }
 
diff --git a/dap-sdk/crypto/src/dap_sign.c b/dap-sdk/crypto/src/dap_sign.c
index 2582d4b1c3a29452a9c377a8c96ef986ae510074..7c64420b0b4202cb9cbf8d8a7a5a3e0332b0667b 100755
--- a/dap-sdk/crypto/src/dap_sign.c
+++ b/dap-sdk/crypto/src/dap_sign.c
@@ -410,7 +410,7 @@ int dap_sign_verify(dap_sign_t * a_chain_sign, const void * a_data, const size_t
         case DAP_ENC_KEY_TYPE_SIG_TESLA:
         case DAP_ENC_KEY_TYPE_SIG_PICNIC:
         case DAP_ENC_KEY_TYPE_SIG_DILITHIUM:
-            if(l_key->dec_na(l_key, a_data, a_data_size, l_sign_data, l_sign_data_size) > 0)
+            if(l_key->dec_na(l_key, a_data, a_data_size, l_sign_data, l_sign_data_size) < 0)
                 l_ret = 0;
             else
                 l_ret = 1;
diff --git a/dap-sdk/crypto/src/sig_picnic/picnic.c b/dap-sdk/crypto/src/sig_picnic/picnic.c
index e5be97c4725d9998dc4131abd1b2fb86d6d44a36..a59a476141a58fed7d14841a98b4df127aac82bd 100755
--- a/dap-sdk/crypto/src/sig_picnic/picnic.c
+++ b/dap-sdk/crypto/src/sig_picnic/picnic.c
@@ -400,11 +400,15 @@ int picnic_keys_gen(picnic_privatekey_t *sk, picnic_publickey_t *pk, picnic_para
             //Generate a random plaintext block
             SHAKE128((unsigned char *) pk->plaintext, 16, (const unsigned char *) seed, seed_size);
             break;
-        /*case 24:
-            SHA3_192((unsigned char *) sk->data, (const unsigned char *) seed, seed_size);
+        case 24:
+//            SHA3_192((unsigned char *) sk->data, (const unsigned char *) seed, seed_size);
+//            //Generate a random plaintext block
+//            SHA3_192((unsigned char *) pk->plaintext, (const unsigned char *) seed, seed_size);
+//            break;
+            SHAKE128((unsigned char *) sk->data, 24, (const unsigned char *) seed, seed_size);
             //Generate a random plaintext block
-            SHA3_192((unsigned char *) pk->plaintext, (const unsigned char *) seed, seed_size);
-            break;*/
+            SHAKE128((unsigned char *) pk->plaintext, 24, (const unsigned char *) seed, seed_size);
+            break;
         case 32:
             SHA3_256((unsigned char *) sk->data, (const unsigned char *) seed, seed_size);
             //Generate a random plaintext block
diff --git a/dap-sdk/crypto/test/CMakeLists.txt b/dap-sdk/crypto/test/CMakeLists.txt
index fe129624464d805d51780fd653889e6425e914f9..725414756091afb244a9dbd1388c033f7a485628 100755
--- a/dap-sdk/crypto/test/CMakeLists.txt
+++ b/dap-sdk/crypto/test/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project(test)
 
 set(CMAKE_C_STANDARD 11)
diff --git a/dap-sdk/crypto/test/crypto/CMakeLists.txt b/dap-sdk/crypto/test/crypto/CMakeLists.txt
index cc132aa8dd3e4a68b24946930966c1bd3aa5de94..ef6afe9d0c1c79ae3e28bd09486a1975e0631996 100755
--- a/dap-sdk/crypto/test/crypto/CMakeLists.txt
+++ b/dap-sdk/crypto/test/crypto/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 project(crypto-test)
 # init CellFrame SDK
@@ -7,20 +7,22 @@ set(SUBMODULES_NO_BUILD ON)
 include (cellframe-sdk/cmake/OS_Detection.cmake)
 set(DAPSDK_MODULES "core crypto network-core network-client network-server")
 
-if( DARWIN)
-    add_subdirectory(cellframe-sdk/3rdparty/json-c-darwin)
-    add_subdirectory(cellframe-sdk/3rdparty/libmagic-darwin)
-    include_directories(cellframe-sdk/3rdparty/json-c-darwin)
-endif()
-if (ANDROID)
-    add_subdirectory(cellframe-sdk/3rdparty/libmagic)
-    add_subdirectory(cellframe-sdk/3rdparty/json-c)
-    include_directories(cellframe-sdk/cellframe-sdk/3rdparty/)
-endif()
+# There is no need, as it was added in cellframe-sdk/CMakeLists.txt
+
+#if( DARWIN)
+#    add_subdirectory(cellframe-sdk/3rdparty/json-c-darwin)
+#    add_subdirectory(cellframe-sdk/3rdparty/libmagic-darwin)
+#    include_directories(cellframe-sdk/3rdparty/json-c-darwin)
+#endif()
+#if (ANDROID)
+#    add_subdirectory(cellframe-sdk/3rdparty/libmagic)
+#    add_subdirectory(cellframe-sdk/3rdparty/json-c)
+#    include_directories(cellframe-sdk/cellframe-sdk/3rdparty/)
+#endif()
 
 #add_subdirectory(cellframe-sdk/dap-sdk)
 #enable_testing()
-add_subdirectory(test)
+#add_subdirectory(test)
 
 
 if ( NOT ( TARGET dap_core ) )
diff --git a/dap-sdk/crypto/test/crypto/dap_enc_base58_test.c b/dap-sdk/crypto/test/crypto/dap_enc_base58_test.c
index 33dd6e7f1fd72fb6e574444e38b2ecdb4b5ea108..c67c0cf2986f70ae3dc44610b1dd7c75d63e4c39 100755
--- a/dap-sdk/crypto/test/crypto/dap_enc_base58_test.c
+++ b/dap-sdk/crypto/test/crypto/dap_enc_base58_test.c
@@ -7,9 +7,12 @@
 #include "dap_enc_base58.h"
 #include "dap_enc_base58_test.h"
 
+size_t source_size;
+
 static void test_encode_decode_base58(void)
 {
-    static size_t source_size = 0;
+//    static size_t source_size = 0;
+//    source_size = 0;
     int step = 1 + random_uint32_t( 20);
     source_size += (size_t) step;
 
@@ -30,7 +33,7 @@ static void test_encode_decode_base58(void)
 
 void dap_enc_base58_tests_run() {
     dap_print_module_name("dap_enc_base58");
-
+    source_size = 0;
     benchmark_mgs_time("Encode and decode DAP_ENC_STANDARD_B58 100 times",
             benchmark_test_time(test_encode_decode_base58, 100));
 
diff --git a/dap-sdk/crypto/test/crypto/dap_enc_ringct20_test.c b/dap-sdk/crypto/test/crypto/dap_enc_ringct20_test.c
index 6ee4936839b488158c4c1e35ea686fb8aab516cb..baa0e819b69b5b7ac34dab2c11ba9349e8210be7 100644
--- a/dap-sdk/crypto/test/crypto/dap_enc_ringct20_test.c
+++ b/dap-sdk/crypto/test/crypto/dap_enc_ringct20_test.c
@@ -3,6 +3,404 @@
 #include "ringct20/ringct20_params.h"
 #include "rand/dap_rand.h"
 
+#define MSIZE 2
+#define WSIZE 3
+#define NSIZE 3
+
+// From original implementation https://github.com/chainchip/Lattice-RingCT-v2.0/blob/master/Ring2.0/ring_test.c
+
+void LRCT_Byte_Test()
+{
+    poly_ringct20 a, ra;
+    uint8_t seed[NEWHOPE_RINGCT20_SYMBYTES] = { 0 };
+    unsigned char bCof[NEWHOPE_RINGCT20_POLYBYTES] = { 0 };
+    randombytes(seed, NEWHOPE_RINGCT20_SYMBYTES);
+    poly_uniform_ringct20(&a, seed);
+//    printf("begin:\n");
+//    poly_print(&a);
+//    printf("serial:\n");
+    poly_serial(&a);
+//    poly_print(&a);
+    poly_tobytes(bCof, &a);
+//    printf("ra:\n");
+    poly_frombytes(&ra, bCof);
+//    poly_print(&ra);
+
+
+}
+
+void LRCT_Setup_Test()
+{
+    poly_ringct20 A[2], H[2];
+    poly_ringct20 S[2];
+    poly_ringct20 L[2];
+    poly_ringct20 h;
+    poly_ringct20 u[3];
+    poly_ringct20 c1;
+    poly_ringct20* t[2];
+    unsigned char msg[2] = { 0x01, 0x02 };
+    unsigned char msg2[2] = { 0x02, 0x03 };
+    int msgLen = 2;
+    unsigned char bt[NEWHOPE_RINGCT20_POLYBYTES] = { 0 };
+    size_t mLen = 2;
+    size_t i = 0;
+    size_t k = 0;
+    int result = 0;
+    int w = 2;
+    int pai = 1;
+
+    t[0] = (poly_ringct20 *)malloc((3) * sizeof(poly_ringct20));
+    t[1] = (poly_ringct20 *)malloc((3) * sizeof(poly_ringct20));
+
+    for (i = 0; i < 2; i++)
+    {
+        for (k = 0; k < 3; k++)
+        {
+            poly_init(t[i] + k);
+        }
+
+    }
+    LRCT_Setup(A, H, 2);
+    LRCT_SampleKey(S, 2);
+    LRCT_KeyGen(L, A, S, 2);
+    LRCT_SampleKey(S, 2);
+    LRCT_KeyGen(L+1, A, S, 2);
+
+    for (k = 0; k < 3; k++)
+    {
+        randombytes(bt, NEWHOPE_RINGCT20_POLYBYTES);
+        poly_frombytes(u + k, bt);
+        poly_serial(u + k);
+        ///poly_print(u+k);
+    }
+//    printf("====================================\n");
+    LRCT_SigGen(&c1, t, &h, A, H,S, u, mLen, L, w,pai, msg, msgLen);
+//    printf("c1\n");
+//    poly_print(&c1);
+//    printf("=================\n");
+    result = LRCT_SigVer(&c1, t, A, H, mLen, &h, L,w, msg, msgLen);
+    dap_assert_PIF(result == 1, "Sign Verify");
+    result = LRCT_SigVer(&c1, t, A, H, mLen, &h, L, w, msg2, msgLen);
+    dap_assert_PIF(result != 1, "Sign Verify");
+    free(t[0]);
+    free(t[1]);
+
+}
+
+void MIMO_LRCT_Setup_Test()
+{
+    poly_ringct20 A[MSIZE], H[MSIZE];
+    poly_ringct20 SList[MSIZE*NSIZE];
+    poly_ringct20 S[MSIZE];
+    poly_ringct20 LList[NSIZE*WSIZE];
+    poly_ringct20 hList[NSIZE];
+    poly_ringct20 c1;
+    poly_ringct20 tList[NSIZE*WSIZE*(MSIZE+1)];
+    int i, j, k;
+    int pai = 2;
+    unsigned char msg[2] = { 0x01, 0x02 };
+    unsigned char msg2[2] = { 0x01, 0x03 };
+    int msgLen = 2;
+    int result = 0;
+    MIMO_LRCT_Setup(A, H, MSIZE);
+    for ( i = 0; i < NSIZE; i++)
+    {
+        LRCT_SampleKey(SList + i*MSIZE, MSIZE);
+        MIMO_LRCT_KeyGen(LList + i*WSIZE + (pai-1) , A, SList + i * MSIZE, MSIZE);
+    }
+    for ( i = 0; i < WSIZE; i++)
+    {
+        if (i != pai-1)
+        {
+            for (j = 0; j < NSIZE; j++)
+            {
+                LRCT_SampleKey(S, MSIZE);
+                MIMO_LRCT_KeyGen(LList + j* WSIZE + i, A, S, MSIZE);
+            }
+        }
+
+    }
+    MIMO_LRCT_SigGen(&c1, tList, hList, SList, NSIZE, A, H, MSIZE, LList, WSIZE, pai, msg, msgLen);
+    result = MIMO_LRCT_SigVer(&c1, tList, hList, NSIZE, A, /*H,*/ MSIZE, LList, WSIZE, msg, msgLen);
+    dap_assert_PIF(result == 1, "Sign verify");
+    result = MIMO_LRCT_SigVer(&c1, tList, hList, NSIZE, A, /*H,*/ MSIZE, LList, WSIZE, msg2, msgLen);
+    dap_assert_PIF(result != 1, "Sign verify");
+}
+
+void LRCT_Spent_Test()
+{
+    poly_ringct20 A[MSIZE], H[MSIZE];
+    poly_ringct20 skPai[MSIZE], pkPai;
+    poly_ringct20 ckPai[MSIZE];
+    poly_ringct20* t[WSIZE];
+    unsigned char bMessage[4] = { 0x01, 0x02, 0x03, 0x4 };
+    size_t msglen = 4;
+    IW iw;
+    //////////////////
+    poly_ringct20 skOA[MSIZE];
+    poly_ringct20 pkOA;
+    IW iwOA;
+    poly_ringct20 ckOA[MSIZE];
+    ////////////////////
+    IW iwList[WSIZE];
+    poly_ringct20 skTmp[MSIZE];
+    poly_ringct20 pkList[WSIZE];
+    poly_ringct20 ckList[WSIZE][MSIZE];
+    unsigned char bListMessage[2] = { 0x01, 0x02};
+    size_t msgListlen = 2;
+    int i = 0;
+    ///////////////////
+    poly_ringct20 L[WSIZE];
+    int paiIndex = 1;
+    poly_ringct20 c1, h;
+    unsigned char bSignMessage[3] = { 0x01, 0x02, 0x03 };
+    size_t msgSignlen = 3;
+    int result =0;
+    size_t k = 0;
+    /////////////////
+    for ( i = 0; i < WSIZE; i++)
+    {
+        t[i] = (poly_ringct20 *)malloc((MSIZE+1) * sizeof(poly_ringct20));
+        for (k = 0; k < MSIZE+1; k++)
+        {
+            poly_init(t[i] + k);
+        }
+    }
+    ///////////////////
+    LRCT_Setup(A, H, MSIZE);
+    LRCT_SampleKey(skPai, MSIZE);
+    LRCT_KeyGen(&pkPai, A, skPai, MSIZE);//A*S+0
+    LRCT_Mint(&iw, ckPai, &pkPai, A, MSIZE, bMessage, msglen);//A*ck + $
+    ///
+    LRCT_SampleKey(skOA, MSIZE);
+    LRCT_KeyGen(&pkOA, A, skOA, MSIZE);//
+    //LRCT_Mint(&iwOA, ckOA, &pkOA, A, MSIZE, bMessage, msglen);
+    //////
+    for( i = 0; i < WSIZE; i++)
+    {
+        if (i == paiIndex)
+        {
+            poly_cofcopy(&iwList[i].a, &iw.a);
+            poly_cofcopy(&iwList[i].cn, &iw.cn);
+        }
+        else
+        {
+            LRCT_SampleKey(skTmp, MSIZE);
+            LRCT_KeyGen(pkList + i, A, skTmp, MSIZE);//A*S+0
+            LRCT_Mint(iwList + i, ckList[i], pkList + i, A, MSIZE, bListMessage, msgListlen);
+        }
+
+    }
+    LRCT_Spend(&iwOA, ckOA, &c1, t, &h, L, bSignMessage, msgSignlen, iwList, WSIZE, paiIndex, skPai, ckPai, bMessage, msglen, &pkOA, A, H, MSIZE);
+    result = LRCT_Verify(&c1, t, &h, A, H, MSIZE, bSignMessage, msgSignlen, L, WSIZE);
+    dap_assert_PIF(result == 1, "Sign Verify");
+    for (i = 0; i < WSIZE; i++)
+    {
+        free(t[i]);
+    }
+}
+
+
+void LRCT_Mul_Test()
+{
+    poly_ringct20 A[2], H[2], H2[2];
+    poly_ringct20 h,h1,r;
+    poly_ringct20 S[2];
+    LRCT_Setup(A, H, 2);
+    LRCT_SampleKey(S, 2);
+
+    LRCT_MatrixMulPoly(&h, H, S, 2);
+
+
+    for (size_t i = 0; i < NEWHOPE_RINGCT20_N; i++)
+    {
+        h.coeffs[i] = coeff_freeze2Q(NEWHOPE_RINGCT20_2Q + NEWHOPE_RINGCT20_Q - h.coeffs[i] * 2);
+    }
+    LRCT_ConstMulMatrix(H2, H, 2, 2);
+    LRCT_MatrixMulPoly(&h1, H2, S, 2);
+    poly_add_ringct20(&r, &h1, &h);
+//    poly_print(&r);
+
+
+}
+void LRCT_MatrixMulVect_Test()
+{
+    poly_ringct20 A[2], H[2];
+    LRCT_Setup(A, H, 2);
+    uint8_t bt[2] = { 0 };
+    bt[0] = 1;
+    bt[1] = 2;
+
+
+}
+void LRCT_Lift_Test()
+{
+    poly_ringct20 A[2], H[2], LA[3], H2[3];
+    poly_ringct20 h;
+    poly_ringct20 S[2];
+    LRCT_SampleKey(S, 2);
+    LRCT_Setup(A, H, 2);
+    LRCT_MatrixMulPoly(&h, H, S, 2);
+    LRCT_Lift(LA, H, &h, 2);
+    ////////////////////////////////////
+    LRCT_ConstMulMatrix(H2, H, 2, 2);
+    for (size_t i = 0; i < NEWHOPE_RINGCT20_N; i++)
+    {
+        H2[2].coeffs[i] = coeff_freeze2Q(NEWHOPE_RINGCT20_2Q + NEWHOPE_RINGCT20_Q - h.coeffs[i] * 2);
+    }
+    for (size_t i = 0; i < 3; i++)
+    {
+        dap_assert_PIF(poly_equal(LA + i, H2 + i) == 1, "Poly equality");
+    }
+}
+void LRCT_KDF_Test()
+{
+
+}
+
+void LRCT_Com_Test()
+{
+    IW iw;
+    poly_ringct20 ck[2];
+    size_t mLen = 2;
+    poly_ringct20  A[2], H[2], sk[2];
+    unsigned char bMessage[4] = { 0x01, 0x02, 0x03, 0x4 };
+    size_t msglen = 4;
+    poly_ringct20 a;
+    LRCT_Setup(A, H, mLen);
+    LRCT_SampleKey(sk, mLen);
+    LRCT_KeyGen(&a, A, sk, mLen);
+//    printf("public key:");
+//    poly_print(&a);
+    LRCT_Mint(&iw, ck, &a, A, mLen, bMessage, msglen);
+//    printf("a:\n");
+//    poly_print(&(iw.a));
+//    printf("cn:\n");
+//    poly_print(&(iw.cn));
+}
+//ntt 变换测试
+void LRCT_Fun_Test()
+{
+    uint8_t seed[NEWHOPE_RINGCT20_SYMBYTES] = { 0 };
+    poly_ringct20 a;
+    randombytes(seed, NEWHOPE_RINGCT20_SYMBYTES);
+    poly_uniform_ringct20(&a, seed);
+    poly_serial(&a);
+    ////////////
+//    printf("begin:\n");
+//    poly_print(&a);
+    //////
+    poly_ntt_ringct20(&a);
+//    printf("after:\n");
+//    poly_print(&a);
+    ////
+    poly_invntt(&a);
+//    printf("recover:\n");
+//    poly_print(&a);
+
+}
+//移位测试
+void LRCT_Shift_Test()
+{
+    poly_ringct20 r, a;
+    poly_init(&r);
+    poly_init(&a);
+    r.coeffs[NEWHOPE_RINGCT20_N - 1] = 1;
+    r.coeffs[0] = 1;
+
+    poly_ntt_ringct20(&r);
+    poly_shift(&a, &r, 1);
+    poly_invntt(&a);
+
+    poly_serial(&a);
+//    poly_print(&a);
+}
+void LRCT_ComHom_Test()
+{
+    unsigned char message[2] = { 0xF0, 0x0F };
+    int messLen = 2;
+    int messBitLen = messLen*8;
+    int i = 0;
+    unsigned char bitTmp = 0;
+    poly_ringct20 *CKi = (poly_ringct20 *)malloc((MSIZE*(messBitLen)) * sizeof(poly_ringct20));
+    poly_ringct20 *comList = (poly_ringct20 *)malloc(((messBitLen)) * sizeof(poly_ringct20));
+    poly_ringct20  A[MSIZE], H[MSIZE], sk[MSIZE], ck0[MSIZE], tmpM[MSIZE];
+    poly_ringct20 a, r, tmp;
+
+    poly_init(&a);
+    poly_init(&tmp);
+    poly_init(&r);
+    for ( i = 0; i < MSIZE; i++)
+    {
+        poly_init(ck0 + i);
+    }
+    LRCT_Setup(A, H, MSIZE);
+    LRCT_SampleKey(sk, MSIZE);
+    //left
+    LRCT_nttCom(&r, A, sk, MSIZE, message, messLen);
+    //right
+    for (i = 1; i < messBitLen; i++)
+    {
+        LRCT_SampleKey(CKi + i*MSIZE, MSIZE);
+    }
+
+    LRCT_GetCK0(CKi, sk, MSIZE, CKi+MSIZE, messBitLen-1);
+
+    for ( i = 0; i < messBitLen; i++)
+    {
+        LRCT_MatrixShift(tmpM, CKi+i*MSIZE, MSIZE, i);
+        LRCT_MatrixAddMatrix(ck0, ck0, tmpM, MSIZE);
+    }
+    for ( i = 0; i < MSIZE; i++)
+    {
+        dap_assert_PIF(poly_equal(ck0 + i, sk + i) == 1, "poly equality")
+    }
+
+    for ( i = 0; i < messLen; i++)
+    {
+        bitTmp = (message[i] & 0x01);
+        LRCT_nttCom(comList + i * 8, A, CKi + (i * 8) * MSIZE, MSIZE, &bitTmp, 1);
+        //////////////////////////////
+        bitTmp = (message[i] & 0x02)>>1;
+        LRCT_nttCom(comList + i * 8 + 1, A, CKi + (i * 8 + 1) * MSIZE, MSIZE, &bitTmp, 1);
+        ////////////
+        bitTmp = (message[i] & 0x04)>>2;
+        LRCT_nttCom(comList + i * 8 + 2, A, CKi + (i * 8 + 2) * MSIZE, MSIZE, &bitTmp, 1);
+        ////////////
+        bitTmp = (message[i] & 0x08)>>3;
+        LRCT_nttCom(comList + i * 8 + 3, A, CKi + (i * 8 + 3) * MSIZE, MSIZE, &bitTmp, 1);
+
+        ////////////
+        bitTmp = (message[i] & 0x10)>>4;
+        LRCT_nttCom(comList + i * 8 + 4, A, CKi + (i * 8 + 4) * MSIZE, MSIZE, &bitTmp, 1);
+
+        ////////////
+        bitTmp = (message[i] & 0x20)>>5;
+        LRCT_nttCom(comList + i * 8 + 5, A, CKi + (i * 8 + 5) * MSIZE, MSIZE, &bitTmp, 1);
+
+        ////////////
+        bitTmp = (message[i] & 0x40)>>6;
+        LRCT_nttCom(comList + i * 8 + 6, A, CKi + (i * 8 + 6) * MSIZE, MSIZE, &bitTmp, 1);
+
+        ////////////
+        bitTmp = (message[i] & 0x80)>>7;
+        LRCT_nttCom(comList + i * 8 + 7, A, CKi + (i * 8 + 7) * MSIZE, MSIZE, &bitTmp, 1);
+    }
+    //poly_cofcopy(&a, comList);
+    for ( i = 0; i < messBitLen; i++)
+    {
+        poly_shift(&tmp, comList + i, i);
+        poly_add_ringct20(&a, &a, &tmp);
+    }
+//    printf("a:\n");
+//    poly_print(&a);
+//    printf("r:\n");
+//    poly_print(&r);
+    dap_assert_PIF(poly_equal(&a, &r) == 1, "poly equality");
+    free(CKi);
+    free(comList);
+}
+
 
 static void test_signing_verifying2(void)
 {
@@ -14,6 +412,7 @@ static void test_signing_verifying2(void)
 
     randombytes(seed, seed_size);
 
+    // one keypair
     dap_enc_key_t* key = dap_enc_key_new_generate(DAP_ENC_KEY_TYPE_SIG_RINGCT20, NULL, 0, seed, seed_size, 0);
 
     const int allpbknum = 100;
@@ -37,7 +436,8 @@ static void test_signing_verifying2(void)
     dap_assert_PIF(siglen > 0, "Signing message");
 
 //Extract aList//CRUTCH
-    uint8_t *sigdata = (uint8_t*)*(int*)(sig + 4);
+//    uint8_t *sigdata = (uint8_t*)*(int*)(sig + 4);
+    uint8_t *sigdata = (uint8_t*) ((ringct20_signature_t*) sig)->sig_data;
 //    for(int i = 0; i < 16; ++i)
 //        printf("%.2x ", sigdata[i]);
 //    printf(" = sig_extract\n"); fflush(stdout);
@@ -155,8 +555,44 @@ void dap_enc_ringct20_tests_run(const int times)
     dap_print_module_name("dap_enc_ringct20");
     init_test_case();
     char print_buf[512];
-    snprintf(print_buf, sizeof(print_buf), "Signing and verifying message %d time", times);
 
+    snprintf(print_buf, sizeof(print_buf), "Byte test %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(LRCT_Byte_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "Signing and verifying message SISO mode %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(LRCT_Setup_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "Signing and verifying message MIMO mode %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(MIMO_LRCT_Setup_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "Spent test %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(LRCT_Spent_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "Mul test %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(LRCT_Mul_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "MatrixMulVect test %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(LRCT_MatrixMulVect_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "Lift test %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(LRCT_Lift_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "KDF test %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(LRCT_KDF_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "Com test %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(LRCT_Com_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "Fun test %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(LRCT_Fun_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "Shift test %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(LRCT_Shift_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "ComHom test %d time", times);
+    benchmark_mgs_time(print_buf, benchmark_test_time(LRCT_ComHom_Test, times));
+
+    snprintf(print_buf, sizeof(print_buf), "Signing and verifying message %d time", times);
     benchmark_mgs_time(print_buf, benchmark_test_time(test_signing_verifying2, times));
 
     cleanup_test_case();
diff --git a/dap-sdk/crypto/test/crypto/dap_enc_test.c b/dap-sdk/crypto/test/crypto/dap_enc_test.c
index 12e46f001591dbd6f92ece43288f513c7cc38da8..16ad86be882190c2a2391d626b9b3445321e9060 100755
--- a/dap-sdk/crypto/test/crypto/dap_enc_test.c
+++ b/dap-sdk/crypto/test/crypto/dap_enc_test.c
@@ -468,7 +468,7 @@ void dap_enc_tests_run() {
     dap_print_module_name("dap_enc_sig serealize->deserealize BLISS");
     test_serealize_deserealize_pub_priv(DAP_ENC_KEY_TYPE_SIG_BLISS);
     dap_print_module_name("dap_enc_sig serealize->deserealize PICNIC");
-    test_serealize_deserealize_pub_priv(DAP_ENC_KEY_TYPE_SIG_PICNIC);
+    test_serealize_deserealize_pub_priv(DAP_ENC_KEY_TYPE_SIG_PICNIC); //sometimes fail
     dap_print_module_name("dap_enc_sig serealize->deserealize TESLA");
     test_serealize_deserealize_pub_priv(DAP_ENC_KEY_TYPE_SIG_TESLA);
     dap_print_module_name("dap_enc_sig serealize->deserealize DILITHIUM");
diff --git a/dap-sdk/crypto/test/crypto/main.c b/dap-sdk/crypto/test/crypto/main.c
index 98e8b69284a10e1bcc93b18e3435c523675be70c..2e634dcbcd99467731f65848f8768aa7277ad3bf 100755
--- a/dap-sdk/crypto/test/crypto/main.c
+++ b/dap-sdk/crypto/test/crypto/main.c
@@ -15,41 +15,40 @@
 void dap_enc_newhope_tests_run(const int times);
 
 
-int main(void)
-{
- // switch off debug info from library
+int main(void) {
+    // switch off debug info from library
     dap_log_level_set(L_CRITICAL);
-    const int  test_numbers = 100;
-//    dap_enc_ringct20_tests_run(test_numbers);//return 0;
+    const int test_numbers = 100;
     dap_enc_newhope_tests_run(test_numbers);
-    test_encypt_decrypt      (test_numbers, DAP_ENC_KEY_TYPE_SALSA2012, 32);
-    test_encypt_decrypt_fast (test_numbers, DAP_ENC_KEY_TYPE_SALSA2012, 32);
-    test_encypt_decrypt      (test_numbers, DAP_ENC_KEY_TYPE_SEED_OFB,  32);
-    test_encypt_decrypt_fast (test_numbers, DAP_ENC_KEY_TYPE_SEED_OFB,  32);
-    test_encypt_decrypt      (test_numbers, DAP_ENC_KEY_TYPE_GOST_OFB,  32);
-    test_encypt_decrypt_fast (test_numbers, DAP_ENC_KEY_TYPE_GOST_OFB,  32);
-    test_encypt_decrypt      (test_numbers, DAP_ENC_KEY_TYPE_KUZN_OFB,  32);
-    test_encypt_decrypt_fast (test_numbers, DAP_ENC_KEY_TYPE_KUZN_OFB,  32);
-    test_encypt_decrypt      (test_numbers, DAP_ENC_KEY_TYPE_BF_CBC,     0);
-    test_encypt_decrypt_fast (test_numbers, DAP_ENC_KEY_TYPE_BF_CBC,     0);
-    test_encypt_decrypt      (test_numbers, DAP_ENC_KEY_TYPE_BF_OFB,     0);
-    test_encypt_decrypt_fast (test_numbers, DAP_ENC_KEY_TYPE_BF_OFB,     0);
-    test_encypt_decrypt      (test_numbers, DAP_ENC_KEY_TYPE_IAES,      32);
-    test_encypt_decrypt_fast (test_numbers, DAP_ENC_KEY_TYPE_IAES,      32);
-    test_encypt_decrypt      (test_numbers, DAP_ENC_KEY_TYPE_OAES,      32);
-    test_encypt_decrypt_fast (test_numbers, DAP_ENC_KEY_TYPE_OAES,      32);
-   // return 0;
+    test_encypt_decrypt(test_numbers, DAP_ENC_KEY_TYPE_SALSA2012, 32);
+    test_encypt_decrypt_fast(test_numbers, DAP_ENC_KEY_TYPE_SALSA2012, 32);
+    test_encypt_decrypt(test_numbers, DAP_ENC_KEY_TYPE_SEED_OFB, 32);
+    test_encypt_decrypt_fast(test_numbers, DAP_ENC_KEY_TYPE_SEED_OFB, 32);
+    test_encypt_decrypt(test_numbers, DAP_ENC_KEY_TYPE_GOST_OFB, 32);
+    test_encypt_decrypt_fast(test_numbers, DAP_ENC_KEY_TYPE_GOST_OFB, 32);
+    test_encypt_decrypt(test_numbers, DAP_ENC_KEY_TYPE_KUZN_OFB, 32);
+    test_encypt_decrypt_fast(test_numbers, DAP_ENC_KEY_TYPE_KUZN_OFB, 32);
+    test_encypt_decrypt(test_numbers, DAP_ENC_KEY_TYPE_BF_CBC, 0);
+    test_encypt_decrypt_fast(test_numbers, DAP_ENC_KEY_TYPE_BF_CBC, 0);
+    test_encypt_decrypt(test_numbers, DAP_ENC_KEY_TYPE_BF_OFB, 0);
+    test_encypt_decrypt_fast(test_numbers, DAP_ENC_KEY_TYPE_BF_OFB, 0);
+    test_encypt_decrypt(test_numbers, DAP_ENC_KEY_TYPE_IAES, 32);
+    test_encypt_decrypt_fast(test_numbers, DAP_ENC_KEY_TYPE_IAES, 32);
+    test_encypt_decrypt(test_numbers, DAP_ENC_KEY_TYPE_OAES, 32);
+    test_encypt_decrypt_fast(test_numbers, DAP_ENC_KEY_TYPE_OAES, 32);
+//    // return 0;
     dap_enc_tests_run();
-
-
     dap_enc_picnic_tests_run();
     dap_enc_sig_bliss_tests_run();
     dap_enc_dilithium_tests_run();
     dap_enc_msrln_tests_run();
-
     dap_enc_base64_tests_run();
     dap_enc_base58_tests_run();
+
     dap_enc_defeo_tests_run();
     dap_enc_tesla_tests_run();
+
     dap_enc_multi_sign_tests_run();
+
+    dap_enc_ringct20_tests_run(100);
 }
diff --git a/dap-sdk/net/client/CMakeLists.txt b/dap-sdk/net/client/CMakeLists.txt
index 39185cc300f9dfda0ef43ae046d0adc278dbd018..4c1645ab84c8b52b1adb456dca7bc21175fba756 100644
--- a/dap-sdk/net/client/CMakeLists.txt
+++ b/dap-sdk/net/client/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project(dap_client)
 add_definitions ("-D_GNU_SOURCE")
 
diff --git a/dap-sdk/net/client/dap_client.c b/dap-sdk/net/client/dap_client.c
index d992fe2d8ec45b19c64b2f9581ff6a9cfdad7db0..89d098685ebe254624151aa3682b8fed7db2578a 100644
--- a/dap-sdk/net/client/dap_client.c
+++ b/dap-sdk/net/client/dap_client.c
@@ -194,7 +194,7 @@ void dap_client_set_auth_cert_unsafe(dap_client_t * a_client, dap_cert_t *a_cert
 void dap_client_delete_unsafe(dap_client_t * a_client)
 {
     if ( DAP_CLIENT_PVT(a_client)->refs_count ==0 ){
-        dap_client_pvt_delete( DAP_CLIENT_PVT(a_client) );
+        dap_client_pvt_delete_unsafe( DAP_CLIENT_PVT(a_client) );
         pthread_mutex_destroy(&a_client->mutex);
         DAP_DEL_Z(a_client)
     } else
@@ -240,7 +240,7 @@ static void s_go_stage_on_client_worker_unsafe(dap_worker_t * a_worker,void * a_
     if (!l_client || l_client->_internal != l_client_pvt) {
         log_it(L_WARNING,"Client is NULL or corrupted, why? Refs %u", l_client_pvt->refs_count);
         if ( l_client_pvt->refs_count ==0 ){
-            dap_client_pvt_delete( l_client_pvt );
+            dap_client_pvt_delete_unsafe(l_client_pvt);
         } else
             l_client_pvt->is_to_delete = true;
         return;
diff --git a/dap-sdk/net/client/dap_client_pvt.c b/dap-sdk/net/client/dap_client_pvt.c
index 76509fce564378462e9d738c082e4eb0d46e87e8..ad7cddd9b2ff4789bcacb0eb6086773203b93984 100644
--- a/dap-sdk/net/client/dap_client_pvt.c
+++ b/dap-sdk/net/client/dap_client_pvt.c
@@ -162,10 +162,10 @@ void dap_client_pvt_new(dap_client_pvt_t * a_client_pvt)
 
 
 /**
- * @brief dap_client_pvt_delete
+ * @brief dap_client_pvt_delete_unsafe
  * @param a_client_pvt
  */
-void dap_client_pvt_delete(dap_client_pvt_t * a_client_pvt)
+void dap_client_pvt_delete_unsafe(dap_client_pvt_t * a_client_pvt)
 {
     assert(a_client_pvt);
 
@@ -903,7 +903,6 @@ static void s_request_response(void * a_response, size_t a_response_size, void *
 {
     dap_client_pvt_t * l_client_pvt = (dap_client_pvt_t *) a_obj;
     assert(l_client_pvt);
-
     //int l_ref = dap_client_pvt_get_ref(a_client_internal);
     if(l_client_pvt->is_encrypted) {
         size_t l_response_dec_size_max = a_response_size ? a_response_size * 2 + 16 : 0;
diff --git a/dap-sdk/net/client/include/dap_client_pvt.h b/dap-sdk/net/client/include/dap_client_pvt.h
index 5dc2f3f0e5e0514e06198bc365a7e9b8b65954ac..81af1d0618fc580d240688e23caef24267d39c4c 100644
--- a/dap-sdk/net/client/include/dap_client_pvt.h
+++ b/dap-sdk/net/client/include/dap_client_pvt.h
@@ -116,7 +116,7 @@ void dap_client_pvt_request_enc(dap_client_pvt_t * a_client_internal, const char
                                      dap_client_callback_int_t a_error_proc);
 
 void dap_client_pvt_new(dap_client_pvt_t * a_client_internal);
-void dap_client_pvt_delete(dap_client_pvt_t * a_client_pvt);
+void dap_client_pvt_delete_unsafe(dap_client_pvt_t * a_client_pvt);
 
 int dap_client_pvt_hh_add_unsafe(dap_client_pvt_t* a_client_pvt);
 int dap_client_pvt_hh_del_unsafe(dap_client_pvt_t *a_client_pvt);
diff --git a/dap-sdk/net/core/CMakeLists.txt b/dap-sdk/net/core/CMakeLists.txt
index 5ed51a7bfb0e11bfeeee142d2e78146cc2833d7a..ca3fe8666b0f24b9575ffa8e9454e9e720e8bcfd 100644
--- a/dap-sdk/net/core/CMakeLists.txt
+++ b/dap-sdk/net/core/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 project (dap_server_core C)
 set(CMAKE_C_STANDARD 11)
diff --git a/dap-sdk/net/core/dap_events.c b/dap-sdk/net/core/dap_events.c
index accb805fec84b4394ead6b5ee0aafeedf0b2ac5b..85637f01faeeab6a6db109ceb18869c5bddbc5c3 100644
--- a/dap-sdk/net/core/dap_events.c
+++ b/dap-sdk/net/core/dap_events.c
@@ -298,7 +298,7 @@ void dap_events_delete( dap_events_t *a_events )
 void dap_events_remove_and_delete_socket_unsafe(dap_events_t *a_events, dap_events_socket_t *a_socket, bool a_preserve_inheritor)
 {
     (void) a_events;
-    int l_sock = a_socket->socket;
+//    int l_sock = a_socket->socket;
 //    if( a_socket->type == DESCRIPTOR_TYPE_TIMER)
 //        log_it(L_DEBUG,"Remove timer %d", l_sock);
 
diff --git a/dap-sdk/net/core/dap_events_socket.c b/dap-sdk/net/core/dap_events_socket.c
index 0bdbe70925a34375c51875a6ca33271bf89050c8..ea25e2cf6f560de4ff2f17931302a26079ff1b9a 100644
--- a/dap-sdk/net/core/dap_events_socket.c
+++ b/dap-sdk/net/core/dap_events_socket.c
@@ -1545,7 +1545,7 @@ void dap_events_socket_worker_poll_update_unsafe(dap_events_socket_t * a_esocket
                 if( a_esocket->flags & DAP_SOCK_READY_TO_WRITE || a_esocket->flags &DAP_SOCK_CONNECTING )
                     l_poll->events |= POLLOUT;
             }else{
-                log_it(L_ERROR, "Wrong poll index when remove from worker (unsafe): %u when total count %zu", a_esocket->poll_index,
+                log_it(L_ERROR, "Wrong poll index when remove from worker (unsafe): %u when total count %u", a_esocket->poll_index,
                        a_esocket->worker->poll_count);
             }
         }
@@ -1910,7 +1910,7 @@ void dap_events_socket_remove_from_worker_unsafe( dap_events_socket_t *a_es, dap
         a_worker->poll[a_es->poll_index].fd = -1;
         a_worker->poll_compress = true;
     }else{
-        log_it(L_ERROR, "Wrong poll index when remove from worker (unsafe): %u when total count %zu", a_es->poll_index, a_worker->poll_count);
+        log_it(L_ERROR, "Wrong poll index when remove from worker (unsafe): %u when total count %u", a_es->poll_index, a_worker->poll_count);
     }
 #else
 #error "Unimplemented new esocket on worker callback for current platform"
@@ -1918,7 +1918,6 @@ void dap_events_socket_remove_from_worker_unsafe( dap_events_socket_t *a_es, dap
     a_es->worker = NULL;
 }
 
-
 /**
  * @brief dap_events_socket_remove_and_delete
  * @param a_w
@@ -2113,11 +2112,11 @@ size_t dap_events_socket_write_f_mt(dap_worker_t * a_w,dap_events_socket_uuid_t
 }
 
 /**
- * @brief dap_events_socket_write_unsafe
- * @param a_es
- * @param a_data
- * @param a_data_size
- * @return
+ * @brief dap_events_socket_write Write data to the client
+ * @param a_es Esocket instance
+ * @param a_data Pointer to data
+ * @param a_data_size Size of data to write
+ * @return Number of bytes that were placed into the buffer
  */
 size_t dap_events_socket_write_unsafe(dap_events_socket_t *a_es, const void * a_data, size_t a_data_size)
 {
diff --git a/dap-sdk/net/core/dap_worker.c b/dap-sdk/net/core/dap_worker.c
index d864c0879295e43d214d35166b6390b814563c87..68c7bcc6e95066191c91fa8b08303d54755c4da8 100644
--- a/dap-sdk/net/core/dap_worker.c
+++ b/dap-sdk/net/core/dap_worker.c
@@ -202,7 +202,6 @@ void *dap_worker_thread(void *arg)
 
         time_t l_cur_time = time( NULL);
         for(size_t n = 0; n < l_sockets_max; n++) {
-
             bool l_flag_hup, l_flag_rdhup, l_flag_read, l_flag_write, l_flag_error, l_flag_nval, l_flag_msg, l_flag_pri;
 #ifdef DAP_EVENTS_CAPS_EPOLL
             l_cur = (dap_events_socket_t *) l_epoll_events[n].data.ptr;
@@ -225,8 +224,8 @@ void *dap_worker_thread(void *arg)
                 continue;
             l_flag_hup =  l_cur_flags& POLLHUP;
             l_flag_rdhup = l_cur_flags & POLLRDHUP;
-            l_flag_write = (l_cur_flags & POLLOUT) || (l_cur_flags &POLLRDNORM)|| (l_cur_flags &POLLRDBAND ) ;
-            l_flag_read = l_cur_flags & POLLIN || (l_cur_flags &POLLWRNORM)|| (l_cur_flags &POLLWRBAND );
+            l_flag_write = (l_cur_flags & POLLOUT) || (l_cur_flags &POLLWRNORM)|| (l_cur_flags &POLLWRBAND ) ;
+            l_flag_read = l_cur_flags & POLLIN || (l_cur_flags &POLLRDNORM)|| (l_cur_flags &POLLRDBAND );
             l_flag_error = l_cur_flags & POLLERR;
             l_flag_nval = l_cur_flags & POLLNVAL;
             l_flag_pri = l_cur_flags & POLLPRI;
@@ -1187,7 +1186,7 @@ int dap_worker_add_events_socket_unsafe( dap_events_socket_t * a_esocket, dap_wo
 #elif defined (DAP_EVENTS_CAPS_POLL)
     if (  a_worker->poll_count == a_worker->poll_count_max ){ // realloc
         a_worker->poll_count_max *= 2;
-        log_it(L_WARNING, "Too many descriptors (%zu), resizing array twice to %zu", a_worker->poll_count, a_worker->poll_count_max);
+        log_it(L_WARNING, "Too many descriptors (%u), resizing array twice to %zu", a_worker->poll_count, a_worker->poll_count_max);
         a_worker->poll =DAP_REALLOC(a_worker->poll, a_worker->poll_count_max * sizeof(*a_worker->poll));
         a_worker->poll_esocket =DAP_REALLOC(a_worker->poll_esocket, a_worker->poll_count_max * sizeof(*a_worker->poll_esocket));
     }
diff --git a/dap-sdk/net/core/include/dap_worker.h b/dap-sdk/net/core/include/dap_worker.h
index 849d567299addbf616da1899847dec7f787899d9..37503dba9ea17ef95fd2efb3716c0ddc7354fac7 100644
--- a/dap-sdk/net/core/include/dap_worker.h
+++ b/dap-sdk/net/core/include/dap_worker.h
@@ -72,7 +72,7 @@ typedef struct dap_worker
     int poll_fd;
     struct pollfd * poll;
     dap_events_socket_t ** poll_esocket;
-    size_t poll_count;
+    atomic_uint poll_count;
     size_t poll_count_max;
     bool poll_compress; // Some of fd's became NULL so arrays need to be reassigned
 #elif defined (DAP_EVENTS_CAPS_KQUEUE)
diff --git a/dap-sdk/net/server/CMakeLists.txt b/dap-sdk/net/server/CMakeLists.txt
index d2023893c59c26ed300b4f149efd06f0974cd9a4..2ad3a1a3f50afb0ce56181094e0348a0aa290fef 100644
--- a/dap-sdk/net/server/CMakeLists.txt
+++ b/dap-sdk/net/server/CMakeLists.txt
@@ -1,5 +1,5 @@
 project(libdap-server C)
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 add_subdirectory(notify_server)
 add_subdirectory(http_server)
diff --git a/dap-sdk/net/server/enc_server/CMakeLists.txt b/dap-sdk/net/server/enc_server/CMakeLists.txt
index 3191a15d5e3f4cbdea8c2eaee44546fc416994ab..4f95407a85ec0b43c836ac9f5da15bb12ae3fe64 100644
--- a/dap-sdk/net/server/enc_server/CMakeLists.txt
+++ b/dap-sdk/net/server/enc_server/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project(dap_enc_server C)
   
 file(GLOB DAP_ENC_SERVER_SRCS FILES *.c)
diff --git a/dap-sdk/net/server/http_server/CMakeLists.txt b/dap-sdk/net/server/http_server/CMakeLists.txt
index 656f8e66cfd03d9b5b471a7847b230ee44bfb7e7..16daa91a058b15877759d622e6f370b07616d6d2 100644
--- a/dap-sdk/net/server/http_server/CMakeLists.txt
+++ b/dap-sdk/net/server/http_server/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_http_server C)
 
 include_directories(http_client/include)
diff --git a/dap-sdk/net/server/http_server/http_client/CMakeLists.txt b/dap-sdk/net/server/http_server/http_client/CMakeLists.txt
index b3633d72034eddd642958862c19b0c10d4bcd206..ed8a4b76399e4a95785c854234229703776398ee 100644
--- a/dap-sdk/net/server/http_server/http_client/CMakeLists.txt
+++ b/dap-sdk/net/server/http_server/http_client/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_http_client)
 
 set(HTTP_SRCS FILES *.c)
diff --git a/dap-sdk/net/server/json_rpc/CMakeLists.txt b/dap-sdk/net/server/json_rpc/CMakeLists.txt
index 08c7ec1ec22fc6f62854945635c00c2a74c9370f..30207dcaa5881382df12e9c164e4bea61e7d0771 100644
--- a/dap-sdk/net/server/json_rpc/CMakeLists.txt
+++ b/dap-sdk/net/server/json_rpc/CMakeLists.txt
@@ -1,5 +1,5 @@
 project(dap_json_rpc C)
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 add_definitions ("-D_GNU_SOURCE")
 add_definitions("-Dfpic")
diff --git a/dap-sdk/net/server/notify_server/CMakeLists.txt b/dap-sdk/net/server/notify_server/CMakeLists.txt
index c2e03f922786cfb86f5bde0721c090501ecd9e77..8390370099ff6c10b1d12bf7be69d16e16f23d3c 100644
--- a/dap-sdk/net/server/notify_server/CMakeLists.txt
+++ b/dap-sdk/net/server/notify_server/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project(dap_notify_srv C)
   
 file(GLOB DAP_NOTIFY_SRV_SRCS FILES src/*.c)
diff --git a/dap-sdk/net/server/notify_server/src/dap_notify_srv.c b/dap-sdk/net/server/notify_server/src/dap_notify_srv.c
index 4c33b21bb59b4960a85bf74427a40b08f47242f9..1ecfcf72e4a24d1f4fbb15a75a9f8cd050d8ada7 100644
--- a/dap-sdk/net/server/notify_server/src/dap_notify_srv.c
+++ b/dap-sdk/net/server/notify_server/src/dap_notify_srv.c
@@ -169,8 +169,8 @@ static void s_notify_server_callback_queue(dap_events_socket_t * a_es, void * a_
         size_t l_str_len = a_arg? strlen((char*)a_arg): 0;
         if(l_str_len){
             dap_events_socket_write_inter(a_es->worker->queue_es_io_input[l_worker_id],
-                                           l_socket_handler->uuid,
-                                      a_arg,l_str_len+1);
+                                          l_socket_handler->uuid,
+                                          a_arg, l_str_len + 1);
         }
     }
     pthread_rwlock_unlock(&s_notify_server_clients_mutex);
diff --git a/dap-sdk/net/server/test/CMakeLists.txt b/dap-sdk/net/server/test/CMakeLists.txt
index 54660c94ba0d8a450c5c9444a4242954736979bf..ac1dab4e7dd873bf8662f825bb29dda39022b7ed 100644
--- a/dap-sdk/net/server/test/CMakeLists.txt
+++ b/dap-sdk/net/server/test/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project(test)
 
 set(CMAKE_C_STANDARD 11)
diff --git a/dap-sdk/net/server/test/enc_server/CMakeLists.txt b/dap-sdk/net/server/test/enc_server/CMakeLists.txt
index 3fd0ab3c3e42ca9e767325b08b0b782648f20b46..2d4df9c5f8087be29cc5c877f22775ea2ac7b303 100644
--- a/dap-sdk/net/server/test/enc_server/CMakeLists.txt
+++ b/dap-sdk/net/server/test/enc_server/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 project(enc_server_test)
 
diff --git a/dap-sdk/net/server/test/http_server/CMakeLists.txt b/dap-sdk/net/server/test/http_server/CMakeLists.txt
index 82d08553ab850ce038e95606af9a5d61d9bb7a85..df544336d79148e82a7d817eee4e34c256153022 100644
--- a/dap-sdk/net/server/test/http_server/CMakeLists.txt
+++ b/dap-sdk/net/server/test/http_server/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 project(http_server_test)
 
diff --git a/dap-sdk/net/stream/CMakeLists.txt b/dap-sdk/net/stream/CMakeLists.txt
index 87d7d736450b46cba9d91e5d5d05abb88cb4fdee..22df0e497b903e8e991ae897ca3cc48103d508e5 100644
--- a/dap-sdk/net/stream/CMakeLists.txt
+++ b/dap-sdk/net/stream/CMakeLists.txt
@@ -1,5 +1,5 @@
 project(libdap-stream C)
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 add_subdirectory(session)
 add_subdirectory(stream)
diff --git a/dap-sdk/net/stream/ch/CMakeLists.txt b/dap-sdk/net/stream/ch/CMakeLists.txt
index e3b535b8d1fbcabebff12e47f44e844e571afc5e..056a3cdd62dbda62f4748f41b493336157fd34f8 100644
--- a/dap-sdk/net/stream/ch/CMakeLists.txt
+++ b/dap-sdk/net/stream/ch/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_stream_ch)
   
 file(GLOB DAP_STREAM_CH_SRCS *.c)
diff --git a/dap-sdk/net/stream/ch/dap_stream_ch_pkt.c b/dap-sdk/net/stream/ch/dap_stream_ch_pkt.c
index a7f65c4e73294fc0c26f1028071b3fa004640cf8..3d06f1326d47ab69e91b528c88e7eac27774cee0 100644
--- a/dap-sdk/net/stream/ch/dap_stream_ch_pkt.c
+++ b/dap-sdk/net/stream/ch/dap_stream_ch_pkt.c
@@ -209,7 +209,6 @@ size_t dap_stream_ch_pkt_write_inter(dap_events_socket_t * a_queue , dap_stream_
     return a_data_size;
 }
 
-
 /**
  * @brief dap_stream_ch_pkt_write
  * @param a_ch
diff --git a/dap-sdk/net/stream/ch/include/dap_stream_ch_pkt.h b/dap-sdk/net/stream/ch/include/dap_stream_ch_pkt.h
index b5cae2d4667097fdd3c7e4495dde3d4c81d3c218..63bf9d2adf07597e78c853b92b16a2da891f37ad 100644
--- a/dap-sdk/net/stream/ch/include/dap_stream_ch_pkt.h
+++ b/dap-sdk/net/stream/ch/include/dap_stream_ch_pkt.h
@@ -55,7 +55,6 @@ void dap_stream_ch_pkt_deinit();
 size_t dap_stream_ch_pkt_write_f_unsafe(dap_stream_ch_t * a_ch, uint8_t a_type, const char * a_str,...);
 size_t dap_stream_ch_pkt_write_unsafe(dap_stream_ch_t * a_ch,  uint8_t a_type, const void * a_data, size_t a_data_size);
 
-
 size_t dap_stream_ch_pkt_write_f_mt(dap_stream_worker_t * a_worker , dap_stream_ch_uuid_t a_ch_uuid, uint8_t a_type, const char * a_str,...);
 size_t dap_stream_ch_pkt_write_mt(dap_stream_worker_t * a_worker , dap_stream_ch_uuid_t a_ch_uuid,  uint8_t a_type, const void * a_data, size_t a_data_size);
 
diff --git a/dap-sdk/net/stream/session/CMakeLists.txt b/dap-sdk/net/stream/session/CMakeLists.txt
index 2e294300da2e7b203c1403803eef390997cef1e8..15dac099b8e1c26f913f984343757ec3f9143b86 100644
--- a/dap-sdk/net/stream/session/CMakeLists.txt
+++ b/dap-sdk/net/stream/session/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_session)
   
 file(GLOB SESSION_SRCS *.c)
diff --git a/dap-sdk/net/stream/stream/CMakeLists.txt b/dap-sdk/net/stream/stream/CMakeLists.txt
index 264d313f849dffb88781867be56710f669e8ba39..16fb98fc4e6b8f0e6e25053a63756b6cd19b418b 100755
--- a/dap-sdk/net/stream/stream/CMakeLists.txt
+++ b/dap-sdk/net/stream/stream/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_stream)
   
 file(GLOB STREAM_SRCS *.c)
diff --git a/dap-sdk/net/stream/stream/dap_stream.c b/dap-sdk/net/stream/stream/dap_stream.c
index b024f6f875c79aa22cd3169ea2f0e1ad4d20d337..689c203b0a738d81c94a06ae416ab47204e14d22 100644
--- a/dap-sdk/net/stream/stream/dap_stream.c
+++ b/dap-sdk/net/stream/stream/dap_stream.c
@@ -39,6 +39,7 @@
 #include "dap_timerfd.h"
 #include "dap_events.h"
 
+#include "dap_events.h"
 #include "dap_stream.h"
 #include "dap_stream_pkt.h"
 #include "dap_stream_ch.h"
@@ -593,7 +594,7 @@ size_t dap_stream_data_proc_read (dap_stream_t *a_stream)
     bool found_sig=false;
     dap_stream_pkt_t * pkt=NULL;
 
-    if (!a_stream->esocket)
+    if (!a_stream || !a_stream->esocket)
         return 0;
 
     char *l_buf_in = (char*)a_stream->esocket->buf_in ;
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/app-cli/CMakeLists.txt b/modules/app-cli/CMakeLists.txt
index 1e8f2c8be518be56301457cab24adfb726fea8e7..26a2deb1bd0440d63b7993d176f644a4d7478fe6 100644
--- a/modules/app-cli/CMakeLists.txt
+++ b/modules/app-cli/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_app_cli)
 
 file(GLOB DAP_APP_CLI_SRCS *.c)
diff --git a/modules/chain/CMakeLists.txt b/modules/chain/CMakeLists.txt
index 2c8a19c4eccc17aa4e1b6d4ec75d6af4ca321061..df55d14d8debebe22fe46281d2d8cd375eeb28b5 100644
--- a/modules/chain/CMakeLists.txt
+++ b/modules/chain/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain)
   
 file(GLOB DAP_CHAIN_SRCS *.c)
diff --git a/modules/chain/btc_rpc/CMakeLists.txt b/modules/chain/btc_rpc/CMakeLists.txt
index 9e9ded64a179d2bda42ee9430c581d9fc0fc3ce0..930181f7283cee04960465242c2c5448d8ee00b7 100644
--- a/modules/chain/btc_rpc/CMakeLists.txt
+++ b/modules/chain/btc_rpc/CMakeLists.txt
@@ -1,5 +1,5 @@
 project(dap_chain_btc_rpc C)
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 
 add_definitions ("-D_GNU_SOURCE")
 add_definitions("-Dfpic")
diff --git a/modules/chain/dap_chain_ledger.c b/modules/chain/dap_chain_ledger.c
index b6150a0e5e2ca7af04fa048be2b0a9ac224789a3..59ce1b6b5be640fd695935cacbbf444c0fb56c46 100644
--- a/modules/chain/dap_chain_ledger.c
+++ b/modules/chain/dap_chain_ledger.c
@@ -223,7 +223,7 @@ void dap_chain_ledger_deinit()
     uint16_t l_net_count = 0;
     dap_chain_net_t **l_net_list = dap_chain_net_list(&l_net_count);
     for(uint16_t i =0; i < l_net_count; i++) {
-        dap_chain_ledger_purge(l_net_list[i]->pub.ledger);
+        dap_chain_ledger_purge(l_net_list[i]->pub.ledger, true);
     }
     DAP_DELETE(l_net_list);
 }
@@ -269,17 +269,13 @@ void dap_chain_ledger_handle_free(dap_ledger_t *a_ledger)
 
 }
 
-
-/*static int compare_datum_items(const void * l_a, const void * l_b)
+void dap_chain_ledger_load_end(dap_ledger_t *a_ledger)
 {
-    const dap_chain_datum_t *l_item_a = (const dap_chain_datum_t*) l_a;
-    const dap_chain_datum_t *l_item_b = (const dap_chain_datum_t*) l_b;
-    if(l_item_a->header.ts_create == l_item_b->header.ts_create)
-        return 0;
-    if(l_item_a->header.ts_create < l_item_b->header.ts_create)
-        return -1;
-    return 1;
-}*/
+    PVT(a_ledger)->last_tx.found = true;
+    PVT(a_ledger)->last_thres_tx.found = true;
+    PVT(a_ledger)->last_emit.found = true;
+    PVT(a_ledger)->last_ticker.found = true;
+}
 
 
 /**
@@ -301,8 +297,7 @@ int dap_chain_ledger_token_decl_add_check(dap_ledger_t * a_ledger,  dap_chain_da
     HASH_FIND_STR(PVT(a_ledger)->tokens,a_token->ticker,l_token_item);
     pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
     if ( l_token_item != NULL ){
-        if(s_debug_more)
-            log_it(L_WARNING,"Duplicate token declaration for ticker '%s' ", a_token->ticker);
+        log_it(L_WARNING,"Duplicate token declaration for ticker '%s' ", a_token->ticker);
         return -3;
     }
     // Checks passed
@@ -375,7 +370,7 @@ int dap_chain_ledger_token_add(dap_ledger_t * a_ledger,  dap_chain_datum_token_t
     l_token_item->type = a_token->type;
     switch(a_token->type){
     case DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE: {
-        l_token_item->total_supply = a_token->header_private.total_supply;\
+        l_token_item->total_supply = a_token->header_private.total_supply;
         l_token_item->auth_signs= dap_chain_datum_token_simple_signs_parse(a_token,a_token_size,
                                                                                    &l_token_item->auth_signs_total,
                                                                                    &l_token_item->auth_signs_valid );
@@ -410,7 +405,7 @@ int dap_chain_ledger_token_add(dap_ledger_t * a_ledger,  dap_chain_datum_token_t
             log_it(L_WARNING,"Unknown token declaration type 0x%04X", a_token->type );
     }
         // Proc emissions tresholds
-    s_treshold_emissions_proc( a_ledger);
+    //s_treshold_emissions_proc( a_ledger); //TODO process thresholds only for no-consensus chains
 
     return  0;
 }
@@ -919,7 +914,7 @@ static void s_treshold_emissions_proc(dap_ledger_t * a_ledger)
         pthread_rwlock_rdlock(&PVT(a_ledger)->treshold_emissions_rwlock);
         HASH_ITER(hh, PVT(a_ledger)->treshold_emissions, l_emission_item, l_emission_tmp) {
             pthread_rwlock_unlock(&PVT(a_ledger)->treshold_emissions_rwlock);
-            int l_res = dap_chain_ledger_token_emission_add(a_ledger, l_emission_item->datum_token_emission,
+            int l_res = dap_chain_ledger_token_emission_add(a_ledger, (byte_t *)l_emission_item->datum_token_emission,
                                                             l_emission_item->datum_token_emission_size);
             if (!l_res) {
                 pthread_rwlock_wrlock(&PVT(a_ledger)->treshold_emissions_rwlock);
@@ -984,6 +979,16 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger)
         pthread_rwlock_init(&l_token_item->token_emissions_rwlock, NULL);
         if (l_token_item->datum_token->type == DAP_CHAIN_DATUM_TOKEN_TYPE_SIMPLE) {
             l_token_item->total_supply = l_token_item->datum_token->header_private.total_supply;
+            l_token_item->auth_signs= dap_chain_datum_token_simple_signs_parse(l_token_item->datum_token, l_objs[i].value_len,
+                                                                                       &l_token_item->auth_signs_total,
+                                                                                       &l_token_item->auth_signs_valid );
+            if (l_token_item->auth_signs_total) {
+                l_token_item->auth_signs_pkey_hash = DAP_NEW_Z_SIZE(dap_chain_hash_fast_t,
+                                                                    sizeof(dap_chain_hash_fast_t) * l_token_item->auth_signs_total);
+                for (uint16_t k=0; k < l_token_item->auth_signs_total; k++) {
+                    dap_sign_get_pkey_hash(l_token_item->auth_signs[k], &l_token_item->auth_signs_pkey_hash[k]);
+                }
+            }
         }
         HASH_ADD_STR(l_ledger_pvt->tokens, ticker, l_token_item);
         if (i == l_objs_count - 1) {
@@ -1004,11 +1009,14 @@ void dap_chain_ledger_load_cache(dap_ledger_t *a_ledger)
             continue;
         dap_chain_ledger_token_emission_item_t *l_emission_item = DAP_NEW_Z(dap_chain_ledger_token_emission_item_t);
         dap_chain_hash_fast_from_str(l_objs[i].key, &l_emission_item->datum_token_emission_hash);
-        l_emission_item->datum_token_emission = DAP_NEW_Z_SIZE(dap_chain_datum_token_emission_t, l_objs[i].value_len);
-        memcpy(l_emission_item->datum_token_emission, l_objs[i].value, l_objs[i].value_len);
-        const char * c_token_ticker = l_emission_item->datum_token_emission->hdr.ticker;
+        size_t l_emission_size = l_objs[i].value_len;
+        const char *c_token_ticker = ((dap_chain_datum_token_emission_t *)l_objs[i].value)->hdr.ticker;
         dap_chain_ledger_token_item_t *l_token_item = NULL;
         HASH_FIND_STR(l_ledger_pvt->tokens, c_token_ticker, l_token_item);
+        l_emission_item->datum_token_emission = l_token_item
+                                                           ? dap_chain_datum_emission_read(l_objs[i].value, &l_emission_size)
+                                                           : DAP_DUP_SIZE(l_objs[i].value, l_objs[i].value_len);
+        l_emission_item->datum_token_emission_size = l_emission_size;
         if (l_token_item) {
             HASH_ADD(hh, l_token_item->token_emissions, datum_token_emission_hash,
                      sizeof(dap_chain_hash_fast_t), l_emission_item);
@@ -1112,13 +1120,12 @@ dap_ledger_t* dap_chain_ledger_create(uint16_t a_check_flags, char *a_net_name)
     return l_ledger;
 }
 
-int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, const dap_chain_datum_token_emission_t *a_token_emission
-                                        , size_t a_token_emission_size)
+int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size)
 {
-    int ret = 0;
+    int l_ret = 0;
     dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
 
-    const char * c_token_ticker = a_token_emission->hdr.ticker;
+    const char * c_token_ticker = ((dap_chain_datum_token_emission_t *)a_token_emission)->hdr.ticker;
     dap_chain_ledger_token_item_t * l_token_item = NULL;
     pthread_rwlock_rdlock(&l_ledger_priv->tokens_rwlock);
     HASH_FIND_STR(l_ledger_priv->tokens, c_token_ticker, l_token_item);
@@ -1141,70 +1148,68 @@ int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, const dap_
     if(l_token_emission_item ) {
         if(s_debug_more)
             log_it(L_ERROR, "Can't add token emission datum of %"DAP_UINT64_FORMAT_U" %s ( %s ): already present in cache",
-                a_token_emission->hdr.value, c_token_ticker, l_hash_str);
-        ret = -1;
+                l_token_emission_item->datum_token_emission->hdr.value, c_token_ticker, l_hash_str);
+        l_ret = -1;
     }else if ( (! l_token_item) && ( l_threshold_emissions_count >= s_treshold_emissions_max)) {
         if(s_debug_more)
             log_it(L_WARNING,"Treshold for emissions is overfulled (%zu max)",
                s_treshold_emissions_max);
-        ret = -2;
-    }else{ // Chech emission correctness
-        switch (a_token_emission->hdr.type){
-            case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH:{
-                dap_chain_ledger_token_item_t *l_token_item=NULL;
-                pthread_rwlock_rdlock(&PVT(a_ledger)->tokens_rwlock);
-                HASH_FIND_STR(PVT(a_ledger)->tokens, a_token_emission->hdr.ticker, l_token_item);
-                pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
-                if (l_token_item){
-                    assert(l_token_item->datum_token);
-                    if( PVT(a_ledger)->net->pub.token_emission_signs_verify  ){
-                        dap_sign_t * l_sign =(dap_sign_t*) a_token_emission->data.type_auth.signs;
-                        size_t l_offset= (byte_t*)a_token_emission - (byte_t*) l_sign;
-                        uint16_t l_aproves = 0, l_aproves_valid = l_token_item->auth_signs_valid;
-
-                        for (uint16_t i=0; i <a_token_emission->data.type_auth.signs_count && l_offset < a_token_emission_size; i++){
-                            size_t l_sign_size = dap_sign_get_size(l_sign);
-                            l_sign = (dap_sign_t*) ((byte_t*) l_sign + l_sign_size);
-                            if (UINT16_MAX-l_offset> l_sign_size ){
-                                dap_chain_hash_fast_t l_sign_pkey_hash;
-                                dap_sign_get_pkey_hash(l_sign,&l_sign_pkey_hash);
-                                // Find pkey in auth hashes
-                                for(uint16_t k=0; k< l_token_item->auth_signs_total; k++  ){
-                                    if ( dap_hash_fast_compare(&l_sign_pkey_hash, &l_token_item->auth_signs_pkey_hash[k])) {
-                                        // Verify if its token emission header signed
-                                        if (!dap_sign_verify_size(l_sign, a_token_emission_size)) {
-                                            break;
-                                        }
-                                        if( dap_sign_verify(l_sign,&a_token_emission->hdr, sizeof (a_token_emission) ) ){
-                                            l_aproves++;
-                                            break;
-                                        }
-                                    }
+        l_ret = -2;
+    }
+    DAP_DELETE(l_hash_str);
+    if (l_ret || !PVT(a_ledger)->check_token_emission)
+        return l_ret;
+    // Check emission correctness
+    size_t l_emission_size = a_token_emission_size;
+    dap_chain_datum_token_emission_t *l_emission = dap_chain_datum_emission_read(a_token_emission, &l_emission_size);
+    switch (l_emission->hdr.type){
+        case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH:{
+            dap_chain_ledger_token_item_t *l_token_item=NULL;
+            pthread_rwlock_rdlock(&PVT(a_ledger)->tokens_rwlock);
+            HASH_FIND_STR(PVT(a_ledger)->tokens, l_emission->hdr.ticker, l_token_item);
+            pthread_rwlock_unlock(&PVT(a_ledger)->tokens_rwlock);
+            if (l_token_item){
+                assert(l_token_item->datum_token);
+                dap_sign_t *l_sign = (dap_sign_t *)l_emission->data.type_auth.signs;
+                size_t l_offset = (byte_t *)l_sign - (byte_t *)l_emission;
+                uint16_t l_aproves = 0, l_aproves_valid = l_token_item->auth_signs_valid;
+                for (uint16_t i = 0; i < l_emission->data.type_auth.signs_count && l_offset < l_emission_size; i++) {
+                    if (dap_sign_verify_size(l_sign, l_emission_size - l_offset)) {
+                        dap_chain_hash_fast_t l_sign_pkey_hash;
+                        dap_sign_get_pkey_hash(l_sign, &l_sign_pkey_hash);
+                        // Find pkey in auth hashes
+                        for (uint16_t k=0; k< l_token_item->auth_signs_total; k++) {
+                            if (dap_hash_fast_compare(&l_sign_pkey_hash, &l_token_item->auth_signs_pkey_hash[k])) {
+                                // Verify if its token emission header signed
+                                if (dap_sign_verify(l_sign, &l_emission->hdr, sizeof(l_emission->hdr)) == 1) {
+                                    l_aproves++;
+                                    break;
                                 }
-                                l_offset+=l_sign_size;
-                            }else
-                                l_offset = UINT16_MAX;
+                            }
                         }
+                        size_t l_sign_size = dap_sign_get_size(l_sign);
+                        l_offset += l_sign_size;
+                        l_sign = (dap_sign_t *)((byte_t *)l_emission + l_offset);
+                    } else
+                        break;
+                }
 
-                        if (l_aproves < l_aproves_valid ){
-                            if(s_debug_more)
-                                log_it(L_WARNING, "Emission of %"DAP_UINT64_FORMAT_U" datoshi of %s:%s is wrong: only %u valid aproves when %u need",
-                                   a_token_emission->hdr.value, a_ledger->net_name, a_token_emission->hdr.ticker, l_aproves, l_aproves_valid );
-                            ret = -1;
-                        }
-                    }
-                }else{
+                if (l_aproves < l_aproves_valid ){
                     if(s_debug_more)
-                        log_it(L_WARNING,"Can't find token declaration %s:%s thats pointed in token emission datum", a_ledger->net_name, a_token_emission->hdr.ticker);
-                    ret = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS;
+                        log_it(L_WARNING, "Emission of %"DAP_UINT64_FORMAT_U" datoshi of %s:%s is wrong: only %u valid aproves when %u need",
+                           l_emission->hdr.value, a_ledger->net_name, l_emission->hdr.ticker, l_aproves, l_aproves_valid );
+                    l_ret = -3;
                 }
-            }break;
-            default:{}
-        }
+            }else{
+                if(s_debug_more)
+                    log_it(L_WARNING,"Can't find token declaration %s:%s thats pointed in token emission datum", a_ledger->net_name, l_emission->hdr.ticker);
+                l_ret = DAP_CHAIN_CS_VERIFY_CODE_TX_NO_TOKEN;
+            }
+        }break;
+        default:{}
     }
-    DAP_DELETE(l_hash_str);
-
-    return ret;
+    DAP_DELETE(l_emission);
+    return l_ret;
 }
 
 /**
@@ -1213,21 +1218,19 @@ int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, const dap_
  * @param a_token_emision_size
  * @return
  */
-int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger,
-        const dap_chain_datum_token_emission_t *a_token_emission, size_t a_token_emission_size)
+int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size)
 {
     int ret = 0;
     dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
 
-    const char * c_token_ticker = a_token_emission->hdr.ticker;
+    const char * c_token_ticker = ((dap_chain_datum_token_emission_t *)a_token_emission)->hdr.ticker;
     dap_chain_ledger_token_item_t * l_token_item = NULL;
     pthread_rwlock_rdlock(&l_ledger_priv->tokens_rwlock);
     HASH_FIND_STR(l_ledger_priv->tokens, c_token_ticker, l_token_item);
     pthread_rwlock_unlock(&l_ledger_priv->tokens_rwlock);
     dap_chain_ledger_token_emission_item_t * l_token_emission_item = NULL;
     // check if such emission is already present in table
-    dap_chain_hash_fast_t l_token_emission_hash={0};
-    dap_chain_hash_fast_t * l_token_emission_hash_ptr = &l_token_emission_hash;
+    dap_chain_hash_fast_t l_token_emission_hash = {};
     dap_hash_fast(a_token_emission, a_token_emission_size, &l_token_emission_hash);
     char * l_hash_str = dap_chain_hash_fast_to_str_new(&l_token_emission_hash);
     pthread_rwlock_rdlock( l_token_item ? &l_token_item->token_emissions_rwlock
@@ -1240,11 +1243,13 @@ int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger,
     if(l_token_emission_item == NULL ) {
         if ( l_token_item || l_threshold_emissions_count < s_treshold_emissions_max  ) {
             l_token_emission_item = DAP_NEW_Z(dap_chain_ledger_token_emission_item_t);
-            l_token_emission_item->datum_token_emission =
-                    DAP_NEW_Z_SIZE(dap_chain_datum_token_emission_t, a_token_emission_size);
+            size_t l_emission_size = a_token_emission_size;
+            l_token_emission_item->datum_token_emission = l_token_item
+                                                                     ? dap_chain_datum_emission_read(a_token_emission, &l_emission_size)
+                                                                     : DAP_DUP_SIZE(a_token_emission, a_token_emission_size);
             memcpy(l_token_emission_item->datum_token_emission, a_token_emission, a_token_emission_size);
             memcpy(&l_token_emission_item->datum_token_emission_hash,
-                    l_token_emission_hash_ptr, sizeof(l_token_emission_hash));
+                   &l_token_emission_hash, sizeof(l_token_emission_hash));
             l_token_emission_item->datum_token_emission_size = a_token_emission_size;
             pthread_rwlock_wrlock( l_token_item ? &l_token_item->token_emissions_rwlock
                                                 : &l_ledger_priv->treshold_emissions_rwlock);
@@ -1258,20 +1263,19 @@ int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger,
             pthread_rwlock_unlock( l_token_item ? &l_token_item->token_emissions_rwlock
                                                 : &l_ledger_priv->treshold_emissions_rwlock);
             // Add it to cache
-            dap_chain_datum_token_emission_t *l_emission_cache = DAP_NEW_Z_SIZE(dap_chain_datum_token_emission_t, a_token_emission_size);
-            memcpy(l_emission_cache, a_token_emission, a_token_emission_size);
+            dap_chain_datum_token_emission_t *l_emission_cache = DAP_DUP_SIZE(a_token_emission, a_token_emission_size);
             char *l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_EMISSIONS_STR);
             if (!dap_chain_global_db_gr_set(dap_strdup(l_hash_str), l_emission_cache, a_token_emission_size, l_gdb_group)) {
                 log_it(L_WARNING, "Ledger cache mismatch");
                 DAP_DELETE(l_emission_cache);
             }
             DAP_DELETE(l_gdb_group);
-            char * l_token_emission_address_str = dap_chain_addr_to_str( &(a_token_emission->hdr.address) );
+            char * l_token_emission_address_str = dap_chain_addr_to_str(&(l_token_emission_item->datum_token_emission->hdr.address) );
             if(s_debug_more)
                 log_it(L_NOTICE, "Added token emission datum to %s: type=%s value=%.1Lf token=%s to_addr=%s ",
                            l_token_item?"emissions cache":"emissions treshold",
-                           c_dap_chain_datum_token_emission_type_str[ a_token_emission->hdr.type ] ,
-                           dap_chain_datoshi_to_coins(a_token_emission->hdr.value), c_token_ticker,
+                           c_dap_chain_datum_token_emission_type_str[l_token_emission_item->datum_token_emission->hdr.type ] ,
+                           dap_chain_datoshi_to_coins(l_token_emission_item->datum_token_emission->hdr.value), c_token_ticker,
                            l_token_emission_address_str);
             DAP_DELETE(l_token_emission_address_str);
         }else{
@@ -1284,7 +1288,8 @@ int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger,
         if (l_token_item) {
             if(s_debug_more)
                 log_it(L_ERROR, "Duplicate token emission datum of %"DAP_UINT64_FORMAT_U" %s ( %s )",
-                            a_token_emission->hdr.value, c_token_ticker, l_hash_str);
+                                ((dap_chain_datum_token_emission_t *)a_token_emission)->hdr.value,
+                                c_token_ticker, l_hash_str);
         }
         ret = -1;
     }
@@ -1292,7 +1297,7 @@ int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger,
     return ret;
 }
 
-int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, const dap_chain_datum_token_emission_t *a_token_emission, size_t a_token_emission_size)
+int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size)
 {
     if (PVT(a_ledger)->last_emit.found) {
         return dap_chain_ledger_token_emission_add(a_ledger, a_token_emission, a_token_emission_size);
@@ -1768,24 +1773,26 @@ int dap_chain_ledger_tx_cache_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t
             size_t l_pkey_ser_size = 0;
             const uint8_t *l_pkey_ser = dap_sign_get_pkey(l_sign, &l_pkey_ser_size);
             dap_chain_tx_out_cond_t *l_tx_prev_out_cond = (dap_chain_tx_out_cond_t *)l_tx_prev_out;
-            if (l_pkey_ser_size != l_prev_pkey_ser_size ||
-                    memcmp(l_prev_pkey_ser, l_pkey_ser, l_prev_pkey_ser_size)) {
-                // 5b. Call verificator for conditional output
-                dap_chain_ledger_verificator_t *l_verificator;
-                int l_tmp = (int)l_tx_prev_out_cond->header.subtype;
-                pthread_rwlock_rdlock(&s_verificators_rwlock);
-                HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
-                pthread_rwlock_unlock(&s_verificators_rwlock);
-                if (!l_verificator || !l_verificator->callback) {
-                    if(s_debug_more)
-                        log_it(L_ERROR, "No verificator set for conditional output subtype %d", l_tmp);
-                    l_err_num = -13;
-                    break;
-                }
-                if (l_verificator->callback(l_tx_prev_out_cond, a_tx) == false) {
-                    l_err_num = -14;
-                    break;
-                }
+            bool l_owner = false;
+            if (l_pkey_ser_size == l_prev_pkey_ser_size &&
+                    !memcmp(l_prev_pkey_ser, l_pkey_ser, l_prev_pkey_ser_size)) {
+                l_owner = true;
+            }
+            // 5b. Call verificator for conditional output
+            dap_chain_ledger_verificator_t *l_verificator;
+            int l_tmp = (int)l_tx_prev_out_cond->header.subtype;
+            pthread_rwlock_rdlock(&s_verificators_rwlock);
+            HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
+            pthread_rwlock_unlock(&s_verificators_rwlock);
+            if (!l_verificator || !l_verificator->callback) {
+                if(s_debug_more)
+                    log_it(L_ERROR, "No verificator set for conditional output subtype %d", l_tmp);
+                l_err_num = -13;
+                break;
+            }
+            if (l_verificator->callback(l_tx_prev_out_cond, a_tx, l_owner) == false) {
+                l_err_num = -14;
+                break;
             }
             bound_item->out.tx_prev_out_cond = l_tx_prev_out_cond;
             // calculate sum of values from previous transactions
@@ -2040,7 +2047,7 @@ int dap_chain_ledger_tx_add_check(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *
              a_ledger, a_tx, &l_list_bound_items, &l_list_tx_out)) < 0){
         if(s_debug_more)
             log_it (L_DEBUG, "dap_chain_ledger_tx_add_check() tx not passed the check: code %d ",l_ret_check);
-        return -1;
+        return l_ret_check;
     }
     dap_chain_hash_fast_t *l_tx_hash = dap_chain_node_datum_tx_calc_hash(a_tx);
     char l_tx_hash_str[70];
@@ -2111,7 +2118,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,
     if (l_item_tmp) {
         if(s_debug_more)
             log_it(L_WARNING, "Transaction %s already present in the cache", l_tx_hash_str);
-        ret = 1;
+        ret = -1;
         goto FIN;
     }
 
@@ -2171,6 +2178,7 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,
     // find all bound pairs 'in' and 'out'
     dap_list_t *l_list_tmp = l_list_bound_items;
     char *l_ticker_trl = NULL, *l_ticker_old_trl = NULL;
+    bool l_stake_updated = false;
     // Update balance: deducts
     while(l_list_tmp) {
         dap_chain_ledger_tx_bound_t *bound_item = l_list_tmp->data;
@@ -2221,6 +2229,19 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,
             dap_chain_tx_in_cond_t *l_tx_in_cond = bound_item->in.tx_cur_in_cond;
             /// Mark 'out' item in cache because it used
             l_tx_prev_out_used_idx = l_tx_in_cond->header.tx_out_prev_idx;
+            // Update stakes if any
+            dap_chain_tx_out_cond_t *l_cond = bound_item->out.tx_prev_out_cond;
+            if (l_cond->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE) {
+                dap_chain_ledger_verificator_t *l_verificator;
+                int l_tmp = (int)DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_UPDATE;
+                pthread_rwlock_rdlock(&s_verificators_rwlock);
+                HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
+                pthread_rwlock_unlock(&s_verificators_rwlock);
+                if (l_verificator && l_verificator->callback) {
+                    l_verificator->callback(l_cond, a_tx, true);
+                }
+                l_stake_updated = true;
+            }
         }
         // add a used output
         memcpy(&(l_prev_item_out->cache_data.tx_hash_spent_fast[l_tx_prev_out_used_idx]), l_tx_hash, sizeof(dap_chain_hash_fast_t));
@@ -2275,16 +2296,28 @@ int dap_chain_ledger_tx_add(dap_ledger_t *a_ledger, dap_chain_datum_tx_t *a_tx,
     for (dap_list_t *l_tx_out = l_list_tx_out; l_tx_out; l_tx_out = dap_list_next(l_tx_out)) {
         dap_chain_tx_item_type_t l_type = *(uint8_t *)l_tx_out->data;
         if (l_type == TX_ITEM_TYPE_OUT_COND) {
+            // Update stakes if any
+            dap_chain_tx_out_cond_t *l_cond = (dap_chain_tx_out_cond_t *)l_tx_out->data;
+            if (l_cond->header.subtype == DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE && !l_stake_updated) {
+                dap_chain_ledger_verificator_t *l_verificator;
+                int l_tmp = (int)DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_UPDATE;
+                pthread_rwlock_rdlock(&s_verificators_rwlock);
+                HASH_FIND_INT(s_verificators, &l_tmp, l_verificator);
+                pthread_rwlock_unlock(&s_verificators_rwlock);
+                if (l_verificator && l_verificator->callback) {
+                    l_verificator->callback(NULL, a_tx, true);
+                }
+            }
             continue;   // balance raise will be with next conditional transaction
         }
         dap_chain_tx_out_t *l_out_item = NULL;
         dap_chain_tx_out_ext_t *l_out_item_ext = NULL;
         if (l_type == TX_ITEM_TYPE_OUT) {
-            l_out_item = l_tx_out->data;
+            l_out_item = (dap_chain_tx_out_t *)l_tx_out->data;
         } else {
-            l_out_item_ext = l_tx_out->data;
+            l_out_item_ext = (dap_chain_tx_out_ext_t *)l_tx_out->data;
         }
-        if (l_out_item && l_ticker_trl) {
+        if ((l_out_item  || l_out_item_ext) && l_ticker_trl) {
              dap_chain_addr_t *l_addr = (l_type == TX_ITEM_TYPE_OUT) ?
                                         &l_out_item->addr :
                                         &l_out_item_ext->addr;
@@ -2456,7 +2489,7 @@ int dap_chain_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_
 /**
  * Delete all transactions from the cache
  */
-void dap_chain_ledger_purge(dap_ledger_t *a_ledger)
+void dap_chain_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db)
 {
     dap_ledger_private_t *l_ledger_priv = PVT(a_ledger);
     const int l_hash_str_size = DAP_CHAIN_HASH_FAST_SIZE * 2 + 2;
@@ -2473,8 +2506,10 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger)
     HASH_ITER(hh, l_ledger_priv->ledger_items , l_item_current, l_item_tmp) {
         DAP_DELETE(l_item_current->tx);
         HASH_DEL(l_ledger_priv->ledger_items, l_item_current);
-        dap_chain_hash_fast_to_str(&l_item_current->tx_hash_fast, l_hash_str, l_hash_str_size);
-        dap_chain_global_db_gr_del(dap_strdup(l_hash_str), l_gdb_group);
+        if (!a_preserve_db) {
+            dap_chain_hash_fast_to_str(&l_item_current->tx_hash_fast, l_hash_str, l_hash_str_size);
+            dap_chain_global_db_gr_del(dap_strdup(l_hash_str), l_gdb_group);
+        }
         DAP_DELETE(l_item_current);
     }
     DAP_DELETE(l_gdb_group);
@@ -2483,8 +2518,10 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger)
     l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_TXS_THRES_STR);
     HASH_ITER(hh, l_ledger_priv->treshold_txs, l_item_current, l_item_tmp) {
         HASH_DEL(l_ledger_priv->treshold_txs, l_item_current);
-        dap_chain_hash_fast_to_str(&l_item_current->tx_hash_fast, l_hash_str, l_hash_str_size);
-        dap_chain_global_db_gr_del(dap_strdup(l_hash_str), l_gdb_group);
+        if (!a_preserve_db) {
+            dap_chain_hash_fast_to_str(&l_item_current->tx_hash_fast, l_hash_str, l_hash_str_size);
+            dap_chain_global_db_gr_del(dap_strdup(l_hash_str), l_gdb_group);
+        }
         DAP_DELETE(l_item_current->tx);
         DAP_DELETE(l_item_current);
     }
@@ -2495,7 +2532,8 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger)
     l_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_BALANCES_STR);
     HASH_ITER(hh, l_ledger_priv->balance_accounts, l_balance_current, l_balance_tmp) {
         HASH_DEL(l_ledger_priv->balance_accounts, l_balance_current);
-        dap_chain_global_db_gr_del(l_balance_current->key, l_gdb_group);
+        if (!a_preserve_db)
+            dap_chain_global_db_gr_del(l_balance_current->key, l_gdb_group);
         DAP_DELETE(l_balance_current);
     }
     DAP_DELETE(l_gdb_group);
@@ -2505,8 +2543,10 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger)
     char *l_emissions_gdb_group = dap_chain_ledger_get_gdb_group(a_ledger, DAP_CHAIN_LEDGER_EMISSIONS_STR);
     HASH_ITER(hh, l_ledger_priv->treshold_emissions, l_emission_current, l_emission_tmp) {
         HASH_DEL(l_ledger_priv->treshold_emissions, l_emission_current);
-        dap_chain_hash_fast_to_str(&l_emission_current->datum_token_emission_hash, l_hash_str, l_hash_str_size);
-        dap_chain_global_db_gr_del(dap_strdup(l_hash_str), l_emissions_gdb_group);
+        if (!a_preserve_db) {
+            dap_chain_hash_fast_to_str(&l_emission_current->datum_token_emission_hash, l_hash_str, l_hash_str_size);
+            dap_chain_global_db_gr_del(dap_strdup(l_hash_str), l_emissions_gdb_group);
+        }
         DAP_DELETE(l_emission_current->datum_token_emission);
         DAP_DELETE(l_emission_current);
     }
@@ -2519,13 +2559,16 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger)
         pthread_rwlock_wrlock(&l_token_current->token_emissions_rwlock);
         HASH_ITER(hh, l_token_current->token_emissions, l_emission_current, l_emission_tmp) {
             HASH_DEL(l_token_current->token_emissions, l_emission_current);
-            dap_chain_hash_fast_to_str(&l_emission_current->datum_token_emission_hash, l_hash_str, l_hash_str_size);
-            dap_chain_global_db_gr_del(dap_strdup(l_hash_str), l_emissions_gdb_group);
+            if (!a_preserve_db) {
+                dap_chain_hash_fast_to_str(&l_emission_current->datum_token_emission_hash, l_hash_str, l_hash_str_size);
+                dap_chain_global_db_gr_del(dap_strdup(l_hash_str), l_emissions_gdb_group);
+            }
             DAP_DELETE(l_emission_current->datum_token_emission);
             DAP_DELETE(l_emission_current);
         }
         pthread_rwlock_unlock(&l_token_current->token_emissions_rwlock);
-        dap_chain_global_db_gr_del(dap_strdup(l_token_current->ticker), l_gdb_group);
+        if (!a_preserve_db)
+            dap_chain_global_db_gr_del(dap_strdup(l_token_current->ticker), l_gdb_group);
         DAP_DELETE(l_token_current->datum_token);
         pthread_rwlock_destroy(&l_token_current->token_emissions_rwlock);
         DAP_DELETE(l_token_current);
@@ -2533,6 +2576,11 @@ void dap_chain_ledger_purge(dap_ledger_t *a_ledger)
     DAP_DELETE(l_gdb_group);
     DAP_DELETE(l_emissions_gdb_group);
 
+    l_ledger_priv->last_tx.found = true;
+    l_ledger_priv->last_thres_tx.found = true;
+    l_ledger_priv->last_emit.found = true;
+    l_ledger_priv->last_ticker.found = true;
+
     pthread_rwlock_unlock(&l_ledger_priv->ledger_rwlock);
     pthread_rwlock_unlock(&l_ledger_priv->tokens_rwlock);
     pthread_rwlock_unlock(&l_ledger_priv->treshold_emissions_rwlock);
diff --git a/modules/chain/include/dap_chain_ledger.h b/modules/chain/include/dap_chain_ledger.h
index 31baa98f0f70fb9ccf3f3a8a963fb197c7e18c50..d1d22d3efc9431fdc8dee52b039c6f6044817971 100644
--- a/modules/chain/include/dap_chain_ledger.h
+++ b/modules/chain/include/dap_chain_ledger.h
@@ -42,7 +42,7 @@ typedef struct dap_ledger {
     void *_internal;
 } dap_ledger_t;
 
-typedef bool (* dap_chain_ledger_verificator_callback_t)(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx);
+typedef bool (* dap_chain_ledger_verificator_callback_t)(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner);
 
 // Checks the emission of the token, usualy on zero chain
 #define DAP_CHAIN_LEDGER_CHECK_TOKEN_EMISSION    0x0001
@@ -57,6 +57,8 @@ typedef bool (* dap_chain_ledger_verificator_callback_t)(dap_chain_tx_out_cond_t
 #define DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS  -111
 // Error code for no emission for a transaction (candidate to threshold)
 #define DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION  -112
+// Error code for no token for an emission (candidate to threshold)
+#define DAP_CHAIN_CS_VERIFY_CODE_TX_NO_TOKEN     -113
 
 #define DAP_CHAIN_LEDGER_TOKENS_STR              "tokens"
 #define DAP_CHAIN_LEDGER_EMISSIONS_STR           "emissions"
@@ -127,16 +129,13 @@ dap_list_t *dap_chain_ledger_token_info(dap_ledger_t *a_ledger);
 /**
  * Add token emission datum
  */
-int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger,
-        const dap_chain_datum_token_emission_t *a_token_emission, size_t a_token_emission_size);
-int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger,
-        const dap_chain_datum_token_emission_t *a_token_emission, size_t a_token_emission_size);
+int dap_chain_ledger_token_emission_add(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size);
+int dap_chain_ledger_token_emission_load(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size);
 
 // Check if it addable
-int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger,
-        const dap_chain_datum_token_emission_t *a_token_emission, size_t a_token_emission_size);
+int dap_chain_ledger_token_emission_add_check(dap_ledger_t *a_ledger, byte_t *a_token_emission, size_t a_token_emission_size);
 
-dap_chain_datum_token_emission_t * dap_chain_ledger_token_emission_find(dap_ledger_t *a_ledger,
+dap_chain_datum_token_emission_t *dap_chain_ledger_token_emission_find(dap_ledger_t *a_ledger,
         const char *a_token_ticker, const dap_chain_hash_fast_t *a_token_emission_hash);
 
 const char* dap_chain_ledger_tx_get_token_ticker_by_hash(dap_ledger_t *a_ledger,dap_chain_hash_fast_t *a_tx_hash);
@@ -162,7 +161,12 @@ int dap_chain_ledger_tx_remove(dap_ledger_t *a_ledger, dap_chain_hash_fast_t *a_
 /**
  * Delete all transactions from the cache
  */
-void dap_chain_ledger_purge(dap_ledger_t *a_ledger);
+void dap_chain_ledger_purge(dap_ledger_t *a_ledger, bool a_preserve_db);
+
+/**
+ * End of load mode with no chackes for incoming datums
+ */
+void dap_chain_ledger_load_end(dap_ledger_t *a_ledger);
 
 /**
  * Return number transactions from the cache
diff --git a/modules/channel/chain-net-srv/CMakeLists.txt b/modules/channel/chain-net-srv/CMakeLists.txt
index 5b511f0528c7cf6bc52c5139b7f2fe72464d2458..0bc63ac49acaf645087b7f3f50db9980bcb639c1 100644
--- a/modules/channel/chain-net-srv/CMakeLists.txt
+++ b/modules/channel/chain-net-srv/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_stream_ch_chain_net_srv)
 
 file(GLOB DAP_STREAM_CH_CHAIN_NET_SRV_SRCS *.c)
diff --git a/modules/channel/chain-net/CMakeLists.txt b/modules/channel/chain-net/CMakeLists.txt
index 90b038e903c5cc5eb25487fbe19ba0d5ba7c1861..0e5565caa1c465af27b6c006724e0b0ef1a46052 100644
--- a/modules/channel/chain-net/CMakeLists.txt
+++ b/modules/channel/chain-net/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_stream_ch_chain_net)
   
 file(GLOB DAP_STREAM_CH_CHAIN_NET_SRCS *.c)
diff --git a/modules/channel/chain/CMakeLists.txt b/modules/channel/chain/CMakeLists.txt
index 048805b30881b55e65ca563fe723cdeb1c492d6c..4151ab49c36a0c33d27873ec90f9196f34148e93 100644
--- a/modules/channel/chain/CMakeLists.txt
+++ b/modules/channel/chain/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_stream_ch_chain)
   
 file(GLOB DAP_STREAM_CH_CHAIN_SRCS *.c)
diff --git a/modules/common/CMakeLists.txt b/modules/common/CMakeLists.txt
index 1a4670336869329ba4f7dff0936354b4ad674119..e66631bd0e37e30dc8e0e360e7d3a6d685a8ef4e 100644
--- a/modules/common/CMakeLists.txt
+++ b/modules/common/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_common)
   
 file(GLOB DAP_CHAIN_COMMON_SRCS  *.c)
diff --git a/modules/common/dap_chain_datum_token.c b/modules/common/dap_chain_datum_token.c
index 74245df3bd3e37f32cc5381ea3db2aea43920412..140a22e8cdb33b3751d7e5251c4b34d5e6fc924a 100644
--- a/modules/common/dap_chain_datum_token.c
+++ b/modules/common/dap_chain_datum_token.c
@@ -201,3 +201,59 @@ err:
     return NULL;
 
 }
+
+size_t dap_chain_datum_emission_get_size(uint8_t *a_emission_serial)
+{
+    size_t l_ret = 0;
+    dap_chain_datum_token_emission_t *l_emission = (dap_chain_datum_token_emission_t *)a_emission_serial;
+    if (l_emission->hdr.version == 0) {
+        l_ret = sizeof(struct dap_chain_emission_header_v0);
+    } else {
+        l_ret = sizeof(l_emission->hdr);
+    }
+    switch (l_emission->hdr.type) {
+    case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH: {
+        uint16_t l_sign_count = *(uint16_t *)(a_emission_serial + l_ret);
+        l_ret += sizeof(l_emission->data.type_auth);
+        for (uint16_t i = 0; i < l_sign_count; i++) {
+            dap_sign_t *l_sign = (dap_sign_t *)(a_emission_serial + l_ret);
+            l_ret += dap_sign_get_size(l_sign);
+        }
+    } break;
+    case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ALGO:
+        l_ret += sizeof(l_emission->data.type_algo);
+        break;
+    case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_ATOM_OWNER:
+        l_ret += sizeof(l_emission->data.type_atom_owner);
+        break;
+    case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_SMART_CONTRACT:
+        l_ret += sizeof(l_emission->data.type_presale);
+        break;
+    case DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_UNDEFINED:
+    default:
+        break;
+    }
+    return l_ret;
+}
+
+dap_chain_datum_token_emission_t *dap_chain_datum_emission_read(byte_t *a_emission_serial, size_t *a_emission_size)
+{
+    assert(a_emission_serial);
+    assert(a_emission_size);
+    dap_chain_datum_token_emission_t *l_emission;
+    if (((dap_chain_datum_token_emission_t *)a_emission_serial)->hdr.version == 0) {
+        size_t l_emission_size = *a_emission_size;
+        size_t l_old_hdr_size = sizeof(struct dap_chain_emission_header_v0);
+        size_t l_add_size = sizeof(l_emission->hdr) - l_old_hdr_size;
+        l_emission = DAP_NEW_Z_SIZE(dap_chain_datum_token_emission_t, l_emission_size + l_add_size);
+        l_emission->hdr.version = 1;
+        memcpy(l_emission, a_emission_serial, l_old_hdr_size);
+        memcpy((byte_t *)l_emission + sizeof(l_emission->hdr),
+               a_emission_serial + l_old_hdr_size,
+               l_emission_size - l_old_hdr_size);
+        l_emission_size += l_add_size;
+        (*a_emission_size) = l_emission_size;
+    } else
+        l_emission = DAP_DUP_SIZE(a_emission_serial, (*a_emission_size));
+    return l_emission;
+}
diff --git a/modules/common/dap_chain_datum_tx.c b/modules/common/dap_chain_datum_tx.c
index 2c8a7d8f450c1f5ce4e3f0f538fa1cae008a2212..6f48ec58ed6d1381985539588f87b58674f7a536 100644
--- a/modules/common/dap_chain_datum_tx.c
+++ b/modules/common/dap_chain_datum_tx.c
@@ -237,7 +237,7 @@ int dap_chain_datum_tx_verify_sign(dap_chain_datum_tx_t *tx)
                 log_it(L_WARNING,"Incorrect signature's header, possible corrupted data");
                 return -4;
             }
-            if(dap_sign_verify(l_sign, tx->tx_items, tx_items_pos) != 1) {
+            if (!dap_sign_verify_size(l_sign, tx_items_size) || dap_sign_verify(l_sign, tx->tx_items, tx_items_pos) != 1) {
                 // invalid signature
                 ret = 0;
                 tx_items_pos += l_item_tx_size;
diff --git a/modules/common/dap_chain_datum_tx_items.c b/modules/common/dap_chain_datum_tx_items.c
index 96f0ae56df8970dd701729f088e9d0bcc0607efa..38cde942ce07b84b0891e1316f7e2965674507eb 100644
--- a/modules/common/dap_chain_datum_tx_items.c
+++ b/modules/common/dap_chain_datum_tx_items.c
@@ -277,7 +277,8 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap
 }
 
 dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_stake(dap_chain_net_srv_uid_t a_srv_uid, uint64_t a_value, long double a_fee_value,
-                                                                           dap_chain_addr_t *a_fee_addr, const void *a_params, uint32_t a_params_size)
+                                                                           dap_chain_addr_t *a_fee_addr, dap_chain_addr_t *a_hldr_addr,
+                                                                           const void *a_params, uint32_t a_params_size)
 {
     dap_chain_tx_out_cond_t *l_item = DAP_NEW_Z_SIZE(dap_chain_tx_out_cond_t, sizeof(dap_chain_tx_out_cond_t) + a_params_size);
     l_item->header.item_type = TX_ITEM_TYPE_OUT_COND;
@@ -286,6 +287,7 @@ dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_stake(dap_c
     l_item->subtype.srv_stake.srv_uid = a_srv_uid;
     l_item->subtype.srv_stake.fee_value = a_fee_value;
     memcpy(&l_item->subtype.srv_stake.fee_addr, a_fee_addr, sizeof(dap_chain_addr_t));
+    memcpy(&l_item->subtype.srv_stake.hldr_addr, a_hldr_addr, sizeof(dap_chain_addr_t));
     l_item->params_size = a_params_size;
     if (a_params_size) {
         memcpy(l_item->params, a_params, a_params_size);
diff --git a/modules/common/include/dap_chain_common.h b/modules/common/include/dap_chain_common.h
index 2d1e24def5b95443da24da1acac4515c6b6cb71f..9af0957ee24ede3beef32fd28ae77194791ea174 100644
--- a/modules/common/include/dap_chain_common.h
+++ b/modules/common/include/dap_chain_common.h
@@ -247,7 +247,6 @@ DAP_STATIC_INLINE uint128_t dap_chain_uint128_from(uint64_t a_from)
 #ifdef DAP_GLOBAL_IS_INT128
     return (uint128_t)a_from;
 #else
-    // uint128_t l_ret = { .u64 = {0, a_from} };
     uint128_t l_ret = { .hi=0, .lo=a_from };
     return l_ret;
 #endif
diff --git a/modules/common/include/dap_chain_datum_token.h b/modules/common/include/dap_chain_datum_token.h
index d452fb9ac19c5ade2a0b0c689cd0a069e4b572bb..78f1792d2e9acda44dd233f16e52e6c8618b113c 100644
--- a/modules/common/include/dap_chain_datum_token.h
+++ b/modules/common/include/dap_chain_datum_token.h
@@ -195,6 +195,15 @@ static inline uint16_t dap_chain_datum_token_flag_from_str(const char* a_str)
 #define DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_BLOCKED_REMOVE       0x0024
 #define DAP_CHAIN_DATUM_TOKEN_TSD_TYPE_TX_SENDER_BLOCKED_CLEAR        0x0025
 
+#define DAP_CHAIN_DATUM_NONCE_SIZE                                    64
+
+struct DAP_ALIGN_PACKED dap_chain_emission_header_v0 {
+    uint8_t version;
+    uint8_t type; // Emission Type
+    char ticker[DAP_CHAIN_TICKER_SIZE_MAX];
+    dap_chain_addr_t address; // Emission holder's address
+    uint64_t value;
+};
 
 // Token emission
 typedef struct dap_chain_datum_token_emission{
@@ -203,7 +212,11 @@ typedef struct dap_chain_datum_token_emission{
         uint8_t type; // Emission Type
         char ticker[DAP_CHAIN_TICKER_SIZE_MAX];
         dap_chain_addr_t address; // Emission holder's address
-        uint64_t value;
+        union {
+            uint64_t value;
+            uint256_t value256;
+        };
+        uint8_t nonce[DAP_CHAIN_DATUM_NONCE_SIZE];
     } DAP_ALIGN_PACKED hdr;
     union {
         struct {
@@ -240,3 +253,5 @@ dap_tsd_t* dap_chain_datum_token_tsd_get(dap_chain_datum_token_t * a_token,  siz
 void dap_chain_datum_token_flags_dump(dap_string_t * a_str_out, uint16_t a_flags);
 void dap_chain_datum_token_certs_dump(dap_string_t * a_str_out, byte_t * a_data_n_tsd, size_t a_certs_size);
 dap_sign_t ** dap_chain_datum_token_simple_signs_parse(dap_chain_datum_token_t * a_datum_token, size_t a_datum_token_size, size_t *a_signs_count, size_t * a_signs_valid);
+dap_chain_datum_token_emission_t *dap_chain_datum_emission_read(byte_t *a_emission_serial, size_t *a_emission_size);
+size_t dap_chain_datum_emission_get_size(uint8_t *a_emission_serial);
diff --git a/modules/common/include/dap_chain_datum_tx_items.h b/modules/common/include/dap_chain_datum_tx_items.h
index e194c7c33645b132b9560410e9a07565af2f95a7..3b891bc45ca90e6ad24e0f375563c698a2de70cb 100644
--- a/modules/common/include/dap_chain_datum_tx_items.h
+++ b/modules/common/include/dap_chain_datum_tx_items.h
@@ -129,7 +129,8 @@ dap_chain_tx_out_cond_t* dap_chain_datum_tx_item_out_cond_create_srv_xchange(dap
  * return item, NULL Error
  */
 dap_chain_tx_out_cond_t *dap_chain_datum_tx_item_out_cond_create_srv_stake(dap_chain_net_srv_uid_t a_srv_uid, uint64_t a_value, long double a_fee_value,
-                                                                           dap_chain_addr_t *a_fee_addr, const void *a_params, uint32_t a_params_size);
+                                                                           dap_chain_addr_t *a_fee_addr, dap_chain_addr_t *a_hldr_addr,
+                                                                           const void *a_params, uint32_t a_params_size);
 /**
  * Create item dap_chain_tx_sig_t
  *
diff --git a/modules/common/include/dap_chain_datum_tx_out_cond.h b/modules/common/include/dap_chain_datum_tx_out_cond.h
index eed92dfe46b198d311c1aadbed2afb07a835999c..bed08ab98b6a540acfb33be811b05070c6a7ef4b 100644
--- a/modules/common/include/dap_chain_datum_tx_out_cond.h
+++ b/modules/common/include/dap_chain_datum_tx_out_cond.h
@@ -32,7 +32,8 @@
 enum dap_chain_tx_out_cond_subtype {
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY = 0x01,
     DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE = 0x02,
-    DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE = 0x03
+    DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE = 0x13,
+    DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE_UPDATE = 0xFA       // Virtual type for stake update verificator TODO change it to new type of callback for ledger tx add
 };
 typedef byte_t dap_chain_tx_out_cond_subtype_t;
 
@@ -86,6 +87,8 @@ typedef struct dap_chain_tx_out_cond {
         struct {
             // Service uid that only could be used for this outout
             dap_chain_net_srv_uid_t srv_uid;
+            // Stake holder address
+            dap_chain_addr_t hldr_addr;
             // Fee address
             dap_chain_addr_t fee_addr;
             // Fee value in percent
diff --git a/modules/consensus/block-poa/CMakeLists.txt b/modules/consensus/block-poa/CMakeLists.txt
index d54c77b2d6de9a7bded5e2f4413b1791d87fb394..648e61c2e9a908b128a6a2d34f3a9f7775796c35 100644
--- a/modules/consensus/block-poa/CMakeLists.txt
+++ b/modules/consensus/block-poa/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_cs_block_poa)
 
 file(GLOB DAP_CHAIN_BLOCK_CS_POA_SRCS *.c)
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..3ee2f2763ac720aee661543967cfde8dd18cc4cb 100644
--- a/modules/consensus/block-poa/dap_chain_cs_block_poa.c
+++ b/modules/consensus/block-poa/dap_chain_cs_block_poa.c
@@ -22,16 +22,17 @@
     along with any DAP SDK based project.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include "dap_chain_net.h"
 #include "dap_common.h"
 #include "dap_strfuncs.h"
 #include "dap_enc_base58.h"
 #include "dap_cert.h"
 #include "dap_chain.h"
+#include "dap_chain_pvt.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"
@@ -44,7 +45,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 +60,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 +75,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 +100,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 +119,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 +154,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 +172,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);
@@ -187,13 +190,15 @@ static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
             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;
+                dap_snprintf(l_cert_name,sizeof(l_cert_name),"%s.%zu",l_poa_pvt->auth_certs_prefix, i);
+                if ((l_poa_pvt->auth_certs[i] = dap_cert_find_by_name( l_cert_name)) == NULL) {
+                    dap_snprintf(l_cert_name,sizeof(l_cert_name),"%s.%zu.pub",l_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_ERROR, "Can't find cert \"%s\"", l_cert_name);
+                        return -1;
+                    }
                 }
+                log_it(L_NOTICE, "Initialized auth cert \"%s\"", l_cert_name);
             }
         }
     }
@@ -219,14 +224,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","blocks-sign-cert") ) != NULL ) {
+        dap_cert_t *l_sign_cert = dap_cert_find_by_name(l_sign_cert_str);
+        if (l_sign_cert == NULL) {
+            log_it(L_ERROR, "Can't load sign certificate, name \"%s\" is wrong", l_sign_cert_str);
+        } else if (l_sign_cert->enc_key->priv_key_data) {
+            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 +266,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 blocks-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 +309,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,7 +333,24 @@ static int s_callback_block_verify(dap_chain_cs_blocks_t * a_blocks, dap_chain_b
                 break;
             }
         }
+        //TODO verify sign itself
+        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;
 }
 
+dap_cert_t **dap_chain_cs_block_poa_get_auth_certs(dap_chain_t *a_chain, size_t *a_auth_certs_count)
+{
+    dap_chain_pvt_t *l_chain_pvt = DAP_CHAIN_PVT(a_chain);
+    if (strcmp(l_chain_pvt->cs_name, "block_poa"))
+        return NULL;
+    dap_chain_cs_block_poa_pvt_t *l_poa_pvt = PVT(DAP_CHAIN_CS_BLOCK_POA(DAP_CHAIN_CS_BLOCKS(a_chain)));
+    if (a_auth_certs_count)
+        *a_auth_certs_count = l_poa_pvt->auth_certs_count;
+    return l_poa_pvt->auth_certs;
+}
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 e2bc7b718b3eea2011854a11178443a34b753024..2ccd4f70254ffd26a8b7da68560c2929d96e4db3 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
@@ -38,3 +38,4 @@ typedef struct dap_chain_cs_block_poa
 
 int dap_chain_cs_block_poa_init(void);
 void dap_chain_cs_block_poa_deinit(void);
+dap_cert_t **dap_chain_cs_block_poa_get_auth_certs(dap_chain_t *a_chain, size_t *a_auth_certs_count);
diff --git a/modules/consensus/block-pos/CMakeLists.txt b/modules/consensus/block-pos/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..91b9ac3737606d57f5b4fd09c1ec6c5cd6745d86
--- /dev/null
+++ b/modules/consensus/block-pos/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.10)
+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..e3976afc8e6d4cd1a8bf67862a5a0e20a50f3ef9
--- /dev/null
+++ b/modules/consensus/block-pos/dap_chain_cs_block_pos.c
@@ -0,0 +1,285 @@
+/*
+ * 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","blocks-sign-cert")) != NULL) {
+        dap_cert_t *l_sign_cert = dap_cert_find_by_name(l_sign_cert_str);
+        if (l_sign_cert == NULL) {
+            log_it(L_ERROR, "Can't load sign certificate, name \"%s\" is wrong", l_sign_cert_str);
+        } else if (l_sign_cert->enc_key->priv_key_data) {
+            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 blocks-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;
+        }
+
+        if (l_sig_pos == 0) {
+            dap_chain_addr_t l_addr = {};
+            dap_chain_hash_fast_t l_pkey_hash;
+            dap_sign_get_pkey_hash(l_sign, &l_pkey_hash);
+            dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, a_blocks->chain->net_id);
+            size_t l_datums_count = 0;
+            dap_chain_datum_t **l_datums = dap_chain_block_get_datums(a_block, a_block_size, &l_datums_count);
+            if (!l_datums || !l_datums_count) {
+                log_it(L_WARNING, "No datums in block %p on chain %s", a_block, a_blocks->chain->name);
+                return -7;
+            }
+            for (size_t i = 0; i < l_datums_count; i++) {
+                if (!dap_chain_net_srv_stake_validator(&l_addr, l_datums[i])) {
+                    log_it(L_WARNING, "Not passed stake validator datum %zu with block %p on chain %s", i, a_block, a_blocks->chain->name);
+                    DAP_DELETE(l_datums);
+                    return -6;
+                }
+            }
+            DAP_DELETE(l_datums);
+        }
+    }
+
+    // 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/consensus/block-pow/CMakeLists.txt b/modules/consensus/block-pow/CMakeLists.txt
index 334d6eb6a932e22561749a8c14863ac1f7ca81d2..5f371110b7686b92938b2b2dcb1b812e87af0751 100644
--- a/modules/consensus/block-pow/CMakeLists.txt
+++ b/modules/consensus/block-pow/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_cs_block_pow)
   
 file(GLOB DAP_CHAIN_BLOCK_CS_POW_SRCS *.c)
diff --git a/modules/consensus/dag-poa/CMakeLists.txt b/modules/consensus/dag-poa/CMakeLists.txt
index 12a35ad6a4d8dbf26282473857fc694eb38d5ce6..df8fd6bcfe7c5c14cc5deb5a4f0bde499a7df465 100644
--- a/modules/consensus/dag-poa/CMakeLists.txt
+++ b/modules/consensus/dag-poa/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_cs_dag_poa)
   
 file(GLOB DAP_CHAIN_DAG_CS_POA_SRCS *.c)
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 b759fddcec890219dc3ad34eea6f6d6456ee6760..766da49dfccff3b1fd6ba6c1139aa13e35b3c334 100644
--- a/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
+++ b/modules/consensus/dag-poa/dap_chain_cs_dag_poa.c
@@ -36,6 +36,7 @@
 #include "dap_common.h"
 #include "dap_strfuncs.h"
 #include "dap_enc_base58.h"
+#include "dap_chain_pvt.h"
 #include "dap_chain_net.h"
 #include "dap_chain_node_cli.h"
 #include "dap_chain_node_cli_cmd.h"
@@ -267,12 +268,14 @@ static int s_callback_new(dap_chain_t * a_chain, dap_config_t * a_chain_cfg)
             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.%zu",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;
+                if ((l_poa_pvt->auth_certs[i] = dap_cert_find_by_name( l_cert_name)) == NULL) {
+                    dap_snprintf(l_cert_name,sizeof(l_cert_name),"%s.%zu.pub",l_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_ERROR, "Can't find cert \"%s\"", l_cert_name);
+                        return -1;
+                    }
                 }
+                log_it(L_NOTICE, "Initialized auth cert \"%s\"", l_cert_name);
             }
         }
     }
@@ -402,24 +405,6 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_
                 if (dap_cert_compare_with_sign ( l_poa_pvt->auth_certs[j], l_sign) == 0)
                     l_verified++;
             }
-            if (i == 0) {
-                dap_chain_hash_fast_t l_pkey_hash;
-                if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash)) {
-                    log_it(L_WARNING, "Event'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_dag->chain->net_id);
-                dap_chain_datum_t *l_datum = (dap_chain_datum_t *)dap_chain_cs_dag_event_get_datum(a_dag_event, a_dag_event_size);
-                if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
-                    dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data;
-                    if (!dap_chain_net_srv_stake_validator(&l_addr, l_tx)) {
-                        log_it(L_WARNING,"Not passed stake validator event %p", a_dag_event);
-                        return -6;
-                    }
-                }
-            }
-
         }
         return l_verified >= l_poa_pvt->auth_certs_count_verify ? 0 : -1;
     }else if (a_dag_event->header.hash_count == 0){
@@ -437,3 +422,13 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_
     }
 }
 
+dap_cert_t **dap_chain_cs_dag_poa_get_auth_certs(dap_chain_t *a_chain, size_t *a_auth_certs_count)
+{
+    dap_chain_pvt_t *l_chain_pvt = DAP_CHAIN_PVT(a_chain);
+    if (strcmp(l_chain_pvt->cs_name, "dag_poa"))
+        return NULL;
+    dap_chain_cs_dag_poa_pvt_t *l_poa_pvt = PVT(DAP_CHAIN_CS_DAG_POA(DAP_CHAIN_CS_DAG(a_chain)));
+    if (a_auth_certs_count)
+        *a_auth_certs_count = l_poa_pvt->auth_certs_count;
+    return l_poa_pvt->auth_certs;
+}
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 b6f05be8207df185de0af5d4ae8e09c884de3e18..c437ff91d2f0f6f47e969196bab192cff9697609 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
@@ -23,6 +23,7 @@
 */
 #pragma once
 #include "dap_chain_cs_dag.h"
+#include "dap_cert.h"
 
 typedef struct dap_chain_cs_dag_poa
 {
@@ -37,3 +38,4 @@ typedef struct dap_chain_cs_dag_poa
 
 int dap_chain_cs_dag_poa_init(void);
 void dap_chain_cs_dag_poa_deinit(void);
+dap_cert_t **dap_chain_cs_dag_poa_get_auth_certs(dap_chain_t *a_chain, size_t *a_auth_certs_count);
diff --git a/modules/consensus/dag-pos/CMakeLists.txt b/modules/consensus/dag-pos/CMakeLists.txt
index 8b8dff9976790e5c248009bed61dd6736fe6b216..7430d0e27811a6a6661c9938b3a0c5cbb64aa351 100644
--- a/modules/consensus/dag-pos/CMakeLists.txt
+++ b/modules/consensus/dag-pos/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_cs_dag_pos)
   
 file(GLOB DAP_CHAIN_CS_DAG_POS_SRCS *.c)
diff --git a/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c b/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c
index 2641129fd34e675312392d03f221b726879cd8ce..1f977c5bcd11fc39bd47c9a1f24207c62a42a85c 100644
--- a/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c
+++ b/modules/consensus/dag-pos/dap_chain_cs_dag_pos.c
@@ -146,18 +146,19 @@ static int s_callback_created(dap_chain_t * a_chain, dap_config_t *a_chain_net_c
     dap_chain_cs_dag_t * l_dag = DAP_CHAIN_CS_DAG ( a_chain );
     dap_chain_cs_dag_pos_t * l_pos = DAP_CHAIN_CS_DAG_POS( l_dag );
 
-    const char * l_events_sign_wallet = NULL;
-    if ( ( l_events_sign_wallet = dap_config_get_item_str(a_chain_net_cfg,"dag-pos","events-sign-wallet") ) != NULL ) {
-
-        dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_events_sign_wallet, dap_chain_wallet_get_path(g_config));
-        if (!l_wallet) {
-            log_it(L_ERROR,"Can't load events sign wallet, name \"%s\" is wrong", l_events_sign_wallet);
+    const char * l_sign_cert_str = NULL;
+    if ((l_sign_cert_str = dap_config_get_item_str(a_chain_net_cfg, "dag-pos", "events-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)->events_sign_key = l_sign_cert->enc_key;
+            log_it(L_NOTICE, "Loaded \"%s\" certificate to sign PoS events", l_sign_cert_str);
         } else {
-            PVT(l_pos)->events_sign_key = dap_chain_wallet_get_key(l_wallet, 0);
-            log_it(L_NOTICE,"Loaded \"%s\" wallet to sign pos event", l_events_sign_wallet);
+            log_it(L_ERROR, "Certificate \"%s\" has no private key", l_sign_cert_str);
         }
     } else {
-        log_it(L_WARNING, "Events sign wallet is empty for %s chain, can't sing any events for it", a_chain->name);
+        log_it(L_ERROR, "No sign certificate provided, can't sign any events");
     }
     return 0;
 }
@@ -234,7 +235,6 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_
     }
     if ( a_dag_event->header.signs_count >= l_pos_pvt->confirmations_minimum ){
         uint16_t l_verified_num = 0;
-        dap_chain_addr_t l_addr = { 0 };
 
         for ( size_t l_sig_pos=0; l_sig_pos < a_dag_event->header.signs_count; l_sig_pos++ ){
             dap_sign_t * l_sign = dap_chain_cs_dag_event_get_sign(a_dag_event, a_dag_event_size,l_sig_pos);
@@ -258,65 +258,18 @@ static int s_callback_event_verify(dap_chain_cs_dag_t * a_dag, dap_chain_cs_dag_
                 return -41;
             }
 
-            if (!l_dag_event_size_without_sign){
-                log_it(L_WARNING,"Event has nothing except sign, nothing to verify so I pass it (who knows why we have it?)");
-                return 0;
-            }
-
-            dap_chain_hash_fast_t l_pkey_hash;
-            if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash)) {
-                log_it(L_WARNING, "Event's sign has no any key");
-                return -5;
-            }
-            dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, a_dag->chain->net_id);
-
-
-
             if (l_sig_pos == 0) {
-                dap_chain_datum_t *l_datum = (dap_chain_datum_t *)dap_chain_cs_dag_event_get_datum(a_dag_event,a_dag_event_size);
-                if (l_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
-                    dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)l_datum->data;
-                    if (!dap_chain_net_srv_stake_validator(&l_addr, l_tx)) {
-                        log_it(L_WARNING,"Not passed stake validator with event %p on chain %s", a_dag_event, a_dag->chain->name);
-                        return -6;
-                    }
-                }
-            }
-            /*
-            dap_chain_datum_t *l_datum = dap_chain_cs_dag_event_get_datum(a_dag_event);
-            // transaction include emission?
-            bool l_is_emit = false;
-            if(l_datum && l_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
-                // transaction
-                dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data;
-                // find Token items
-                dap_list_t *l_list_tx_token = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_TOKEN, NULL);
-                if(l_list_tx_token)
-                    l_is_emit = true;
-                dap_list_free(l_list_tx_token);
-            }
-            // if emission then the wallet can be with zero balance
-            if(l_is_emit)
-                return 0;*/
-
-            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_dag->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;
+                dap_chain_addr_t l_addr = {};
+                dap_chain_hash_fast_t l_pkey_hash;
+                dap_sign_get_pkey_hash(l_sign, &l_pkey_hash);
+                dap_chain_addr_fill(&l_addr, l_sign->header.type, &l_pkey_hash, a_dag->chain->net_id);
+                dap_chain_datum_t *l_datum = (dap_chain_datum_t *)dap_chain_cs_dag_event_get_datum(a_dag_event, a_dag_event_size);
+                if (!dap_chain_net_srv_stake_validator(&l_addr, l_datum)) {
+                    log_it(L_WARNING, "Not passed stake validator with event %p on chain %s", a_dag_event, a_dag->chain->name);
+                    return -6;
                 }
             }
-            if (! l_is_enough_balance ){
-                char *l_addr_str = dap_chain_addr_to_str(&l_addr);
-                log_it(L_WARNING, "Verify of event is false, because bal is not enough for addr=%s", l_addr_str);
-                DAP_DELETE(l_addr_str);
-                return -1;
-            }
         }
-
         // Check number
         if ( l_verified_num >= l_pos_pvt->confirmations_minimum ){
             // Passed all checks
diff --git a/modules/consensus/none/CMakeLists.txt b/modules/consensus/none/CMakeLists.txt
index 8072379783889069d785c766ac0b10d786fbe24c..ddf73b014ea1143a5a1c663582a517c424137c7c 100644
--- a/modules/consensus/none/CMakeLists.txt
+++ b/modules/consensus/none/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_cs_none)
   
 file(GLOB DAP_CHAIN_CS_NO_CONSENSUS_SRC *.c)
diff --git a/modules/consensus/none/dap_chain_cs_none.c b/modules/consensus/none/dap_chain_cs_none.c
index 4e653e0831adeeecce6d406e8bdecbcee9d94e9c..243565c6679c1020d1af546a45fd10ba26150637 100644
--- a/modules/consensus/none/dap_chain_cs_none.c
+++ b/modules/consensus/none/dap_chain_cs_none.c
@@ -350,8 +350,7 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
                 return ATOM_REJECT;
         }break;
         case DAP_CHAIN_DATUM_TOKEN_EMISSION: {
-            dap_chain_datum_token_emission_t *l_token_emission = (dap_chain_datum_token_emission_t*) l_datum->data;
-            if (dap_chain_ledger_token_emission_load(a_chain->ledger, l_token_emission, l_datum->header.data_size))
+            if (dap_chain_ledger_token_emission_load(a_chain->ledger, l_datum->data, l_datum->header.data_size))
                 return ATOM_REJECT;
         }break;
         case DAP_CHAIN_DATUM_TX:{
@@ -360,6 +359,10 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
             if(dap_chain_ledger_tx_load(a_chain->ledger, l_tx) != 1)
                 return ATOM_REJECT;
         }break;
+        case DAP_CHAIN_DATUM_CA:{
+            if ( dap_cert_chain_file_save(l_datum, a_chain->net_name) < 0 )
+                return ATOM_REJECT;
+        }break;
         default: return ATOM_REJECT;
     }
 
diff --git a/modules/global-db/dap_chain_global_db.c b/modules/global-db/dap_chain_global_db.c
index ffd4da5e97f676c9e707edb4dfc3a13691e144ba..7d714677cbc2ced25c5fce0325cb60d9b0d3e241 100644
--- a/modules/global-db/dap_chain_global_db.c
+++ b/modules/global-db/dap_chain_global_db.c
@@ -310,19 +310,17 @@ uint8_t * dap_chain_global_db_gr_get(const char *a_key, size_t *a_data_len_out,
     return l_ret_value;
 }
 
-
 /**
  * @brief Gets an object value from database by a_key for the "local.general" group.
  * @param a_key an object key string
- * @param a_data_out a length of value that were gotten
+ * @param a_data_len_out a length of value that was gotten
  * @return If successful, returns a pointer to the object value, otherwise NULL.
  */
-uint8_t * dap_chain_global_db_get(const char *a_key, size_t *a_data_out)
+uint8_t * dap_chain_global_db_get(const char *a_key, size_t *a_data_len_out)
 {
-    return dap_chain_global_db_gr_get(a_key, a_data_out, GROUP_LOCAL_GENERAL);
+    return dap_chain_global_db_gr_get(a_key, a_data_len_out, GROUP_LOCAL_GENERAL);
 }
 
-
 /**
  * @brief Adds info about the deleted entry to the database.
  * @param a_key an object key string
@@ -349,8 +347,6 @@ static bool global_db_gr_del_add(char *a_key,const char *a_group, time_t a_times
     return false;
 }
 
-
-
 /**
  * @brief Deletes info about the deleted object from the database
  * @param a_key an object key string, looked like "0x8FAFBD00B..."
@@ -378,7 +374,6 @@ static bool global_db_gr_del_del(char *a_key, const char *a_group)
     return false;
 }
 
-
 /**
  * @brief Gets time stamp of the deleted object by a_group and a_key arguments.
  * @param a_group a group name sring, for example "kelvin-testnet.nodes"
@@ -419,7 +414,6 @@ bool dap_chain_global_db_del(char *a_key)
     return dap_chain_global_db_gr_del(a_key, GROUP_LOCAL_GENERAL);
 }
 
-
 /**
  * @brief Gets a last item from a database by a_group.
  * @param a_group a group name string
@@ -555,7 +549,6 @@ void dap_global_db_obj_track_history(void* a_store_data)
     }
 }
 
-
 /**
  * @brief Adds a value to a database.
  * @param a_key a object key string
diff --git a/modules/global-db/dap_chain_global_db_driver.c b/modules/global-db/dap_chain_global_db_driver.c
index d1cc0e45ebf466e78052f4ba4cecdfd1e81703f7..fe0a48daa53f88a66b4894d8a166d536c084504d 100644
--- a/modules/global-db/dap_chain_global_db_driver.c
+++ b/modules/global-db/dap_chain_global_db_driver.c
@@ -281,7 +281,6 @@ static int wait_data(pthread_mutex_t *a_mutex, pthread_cond_t *a_cond, int l_tim
 }
 
 #ifdef USE_WRITE_BUFFER
-/
 /**
  * @brief Checks if a buffer is not empty.
  * @return Returns true if the buffer is not empty, false if it is empty.
diff --git a/modules/global-db/dap_chain_global_db_driver_cdb.c b/modules/global-db/dap_chain_global_db_driver_cdb.c
index 61b55dfa5ad4fc705c19bcece744e6eef0417123..699f07942d106f464d4b3f4459bf7328c1acf8ec 100644
--- a/modules/global-db/dap_chain_global_db_driver_cdb.c
+++ b/modules/global-db/dap_chain_global_db_driver_cdb.c
@@ -141,7 +141,7 @@ bool dap_cdb_get_cond_obj_iter_callback(void *arg, const char *key, int ksize, c
     return true;
 }
 
-//** A callback function designed for countng items*/
+//** A callback function designed for counting items*/
 bool dap_cdb_get_count_iter_callback(void *arg, const char *key, int ksize, const char *val, int vsize, uint32_t expire, uint64_t oid) {
     UNUSED(ksize);
     UNUSED(val);
@@ -515,7 +515,6 @@ dap_store_obj_t* dap_db_driver_cdb_read_cond_store_obj(const char *a_group, uint
     return l_arg.o;
 }
 
-
 /**
  * @brief Reads count of items in CDB by a_group and a_id.
  * @param a_group the group name
@@ -564,7 +563,6 @@ dap_list_t* dap_db_driver_cdb_get_groups_by_mask(const char *a_group_mask)
     return l_ret_list;
 }
 
-
 /**
  * @brief Adds or deletes item in CDB depending on a_store_obj->type.
  * @param a_store_obj a pointer to the item
diff --git a/modules/global-db/dap_chain_global_db_hist.c b/modules/global-db/dap_chain_global_db_hist.c
index 83f10d0d8495e9d8c149ac88815e5c5d2e01864c..6ff0e7871008a90a8d6f1ad15fdfb613056dc9e8 100644
--- a/modules/global-db/dap_chain_global_db_hist.c
+++ b/modules/global-db/dap_chain_global_db_hist.c
@@ -335,7 +335,7 @@ size_t dap_db_log_list_get_count_rest(dap_db_log_list_t *a_db_log_list)
  * @param a_db_log_list a pointer to the log list
  * @return Returns a pointer to the object.
  */
-dap_db_log_list_obj_t* dap_db_log_list_get(dap_db_log_list_t *a_db_log_list)
+dap_db_log_list_obj_t *dap_db_log_list_get(dap_db_log_list_t *a_db_log_list)
 {
     if(!a_db_log_list)
         return NULL;
@@ -364,10 +364,8 @@ dap_db_log_list_obj_t* dap_db_log_list_get(dap_db_log_list_t *a_db_log_list)
     }
     //log_it(L_DEBUG, "get item n=%d", a_db_log_list->items_number - a_db_log_list->items_rest);
     return l_list ? (dap_db_log_list_obj_t *)l_list->data : NULL;
-    //return l_list;
 }
 
-
 /**
  * @brief Deallocates memory of a list item
  * 
diff --git a/modules/global-db/include/dap_chain_global_db.h b/modules/global-db/include/dap_chain_global_db.h
index 0cefa57fac338ecbf91aceb9e88f51814dd23091..98129b6a05c45f107c2bd08fdcc747527afdc470 100644
--- a/modules/global-db/include/dap_chain_global_db.h
+++ b/modules/global-db/include/dap_chain_global_db.h
@@ -62,8 +62,8 @@ void dap_global_db_obj_track_history(void* a_store_data);
  */
 void* dap_chain_global_db_obj_get(const char *a_key, const char *a_group);
 dap_store_obj_t* dap_chain_global_db_obj_gr_get(const char *a_key, size_t *a_data_len_out, const char *a_group);
-uint8_t * dap_chain_global_db_gr_get(const char *a_key, size_t *a_data_out, const char *a_group);
-uint8_t * dap_chain_global_db_get(const char *a_key, size_t *a_data_out);
+uint8_t * dap_chain_global_db_gr_get(const char *a_key, size_t *a_data_len_out, const char *a_group);
+uint8_t * dap_chain_global_db_get(const char *a_key, size_t *a_data_len_out);
 
 /**
  * Set one entry to base
diff --git a/modules/mempool/CMakeLists.txt b/modules/mempool/CMakeLists.txt
index f2d0ede23294b502d943b706cbcc2273f1242944..cc6c866e61c49177f64aa984ba97b27b6467ec61 100644
--- a/modules/mempool/CMakeLists.txt
+++ b/modules/mempool/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_mempool)
 
 file(GLOB DAP_CHAIN_MEMPOOL_SRC *.c)
diff --git a/modules/mining/CMakeLists.txt b/modules/mining/CMakeLists.txt
index 3e4e88edd39b4acd5e3154d799278b2d20b83112..39a38576132d9a48803d9e7a40aba7f9b3684807 100644
--- a/modules/mining/CMakeLists.txt
+++ b/modules/mining/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_crypto)
   
 file(GLOB DAP_CHAIN_CRYPTO_SRCS *.c)
diff --git a/modules/modules_dynamic/cdb/CMakeLists.txt b/modules/modules_dynamic/cdb/CMakeLists.txt
index 1d2ef0120fe05ab073c64c7229dd8e57c2c03aa0..7a387d86a55e76e2ffcf8b6915bcf81ba27a3c4b 100644
--- a/modules/modules_dynamic/cdb/CMakeLists.txt
+++ b/modules/modules_dynamic/cdb/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_modules_dynamic_cdb)
 
 file(GLOB DAP_MODULES_DYNAMIC_CDB_SRCS *.c)
diff --git a/modules/modules_dynamic/cdb/dap_modules_dynamic_cdb.c b/modules/modules_dynamic/cdb/dap_modules_dynamic_cdb.c
index 6abb617e6837a5c47157709a7035baa275bc2c25..b4e8130de195b9c6cd04d81be978001d129ed71b 100644
--- a/modules/modules_dynamic/cdb/dap_modules_dynamic_cdb.c
+++ b/modules/modules_dynamic/cdb/dap_modules_dynamic_cdb.c
@@ -29,7 +29,7 @@
 #include <dlfcn.h>
 #endif
 
-#define LOG_TAG "dap_http"
+#define LOG_TAG "dap_modules_dynamic"
 
 static const char * s_default_path_modules = "var/modules";
 static void *s_cdb_handle = NULL;
@@ -91,5 +91,6 @@ int dap_modules_dynamic_load_cdb(dap_http_t * a_server)
         log_it(L_ERROR, "dap_modules_dynamic: dap_chain_net_srv_vpn_cdb_init returns %d", l_init_res);
         return -3;
     }
+    s_cdb_was_init = true;
     return 0;
 }
diff --git a/modules/net/CMakeLists.txt b/modules/net/CMakeLists.txt
index 4c05cea61e5af5c5a8710ee0c20c5a9904af0c74..f4ccdaff3953e4c8bc9d6be53701ac60e6ac1b13 100644
--- a/modules/net/CMakeLists.txt
+++ b/modules/net/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_net)
   
 
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 8400c75cb70755fbc176df67b9a4f63546af391c..28ddbebe8c83f686049a47ca9f4fe740d9d68e37 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -99,7 +99,6 @@
 #include "dap_stream_ch.h"
 #include "dap_stream_ch_pkt.h"
 #include "dap_chain_node_dns_client.h"
-
 #include "dap_module.h"
 
 #include <stdio.h>
@@ -266,6 +265,8 @@ static dap_global_db_obj_callback_notify_t s_srv_callback_notify = NULL;
  */
 int dap_chain_net_init()
 {
+    dap_stream_ch_chain_init();
+    dap_stream_ch_chain_net_init();
     dap_chain_node_client_init();
     dap_chain_node_cli_cmd_item_create ("net", s_cli_net, "Network commands",
         "net list [chains -n <chain net name>]"
@@ -289,7 +290,7 @@ int dap_chain_net_init()
         "net -net <chain net name> ca del -hash <cert hash> [-H hex|base58(default)]\n"
             "\tDelete certificate from list of authority cetificates in GDB group by it's hash\n"
         "net -net <chain net name> ledger reload\n"
-            "\tPurge the cache of chain net ledger and recalculate it from chain file\n"                                        );
+            "\tPurge the cache of chain net ledger and recalculate it from chain file\n");
     s_seed_mode = dap_config_get_item_bool_default(g_config,"general","seed_mode",false);
 
     // maximum number of connections to other nodes
@@ -1600,7 +1601,7 @@ static int s_cli_net(int argc, char **argv, char **a_str_reply)
                 ret = -5;
             }
         } else if (l_ledger_str && !strcmp(l_ledger_str, "reload")) {
-            dap_chain_ledger_purge(l_net->pub.ledger);
+            dap_chain_ledger_purge(l_net->pub.ledger, false);
             dap_chain_t *l_chain;
             DL_FOREACH(l_net->pub.chains, l_chain) {
                 if (l_chain->callback_purge) {
@@ -1746,7 +1747,6 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
             case NODE_ROLE_ROOT_MASTER:
             case NODE_ROLE_ROOT:
             case NODE_ROLE_ARCHIVE:
-                l_ledger_flags |= DAP_CHAIN_LEDGER_CHECK_TOKEN_EMISSION;
             case NODE_ROLE_MASTER:
                 l_ledger_flags |= DAP_CHAIN_LEDGER_CHECK_CELLS_DS;
             case NODE_ROLE_CELL_MASTER:
@@ -2147,6 +2147,7 @@ int s_net_load(const char * a_net_name, uint16_t a_acl_idx)
             l_target_state = NET_STATE_OFFLINE;
         }
         l_net_pvt->load_mode = false;
+        dap_chain_ledger_load_end(l_net->pub.ledger);
 
         if (l_target_state != l_net_pvt->state_target)
             dap_chain_net_state_go_to(l_net, l_target_state);
@@ -2601,13 +2602,17 @@ int dap_chain_net_verify_datum_for_add(dap_chain_net_t *a_net, dap_chain_datum_t
         case DAP_CHAIN_DATUM_TOKEN_DECL: return dap_chain_ledger_token_decl_add_check( a_net->pub.ledger,
                                                                    (dap_chain_datum_token_t*) a_datum->data );
         case DAP_CHAIN_DATUM_TOKEN_EMISSION : return dap_chain_ledger_token_emission_add_check( a_net->pub.ledger,
-                                                                   (dap_chain_datum_token_emission_t*) a_datum->data, a_datum->header.data_size );
+                                                                    a_datum->data, a_datum->header.data_size );
         default: return 0;
     }
 }
 
 /**
  * @brief dap_chain_net_dump_datum
+ * process datum verification process. Can be:
+ * if DAP_CHAIN_DATUM_TX, called dap_chain_ledger_tx_add_check
+ * if DAP_CHAIN_DATUM_TOKEN_DECL, called dap_chain_ledger_token_decl_add_check
+ * if DAP_CHAIN_DATUM_TOKEN_EMISSION, called dap_chain_ledger_token_emission_add_check
  * @param a_str_out
  * @param a_datum
  */
@@ -2915,11 +2920,14 @@ void dap_chain_net_dump_datum(dap_string_t * a_str_out, dap_chain_datum_t * a_da
                                         case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE:{
                                             dap_string_append_printf(a_str_out,"\tsubtype: DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE\n");
                                         }break;
+                                        default:{
+                                            dap_string_append_printf(a_str_out,"\tsubtype: UNKNOWN\n");
+                                        }break;
                                     }
                                     dap_string_append_printf(a_str_out,"\tparams_size : %u\n", l_out->params_size );
                                 } break;
-                                case TX_ITEM_TYPE_RECEIPT:{} break;
-                                default:{}
+                                case TX_ITEM_TYPE_RECEIPT:
+                                default: break;
                             }
                             n++;
                         }
@@ -3027,3 +3035,26 @@ static uint8_t *dap_chain_net_set_acl(dap_chain_hash_fast_t *a_pkey_hash)
     }
     return NULL;
 }
+
+/**
+ * @brief dap_cert_chain_file_save
+ * @param datum
+ */
+int dap_cert_chain_file_save(dap_chain_datum_t * datum, char * net_name)
+{
+    const char * s_system_chain_ca_dir = dap_config_get_item_str(g_config, "resources", "chain_ca_folder");
+
+    dap_cert_t * cert = dap_cert_mem_load(datum->data, datum->header.data_size);
+    const char * cert_name = cert->name;
+
+    size_t cert_path_length = strlen(net_name)+strlen(cert_name)+9+strlen(s_system_chain_ca_dir);
+    char *cert_path = DAP_NEW_Z_SIZE(char,cert_path_length);
+
+    snprintf(cert_path,cert_path_length,"%s/%s/%s.dcert",s_system_chain_ca_dir,net_name,cert_name);
+
+//  if ( access( l_cert_path, F_OK ) != -1 ) {
+//      log_it (L_ERROR, "File %s is already exists.", l_cert_path);
+//      return -1;
+//  } else
+    return dap_cert_file_save(cert, cert_path);
+}
diff --git a/modules/net/dap_chain_node.c b/modules/net/dap_chain_node.c
index e6ec10bb3fc89e52d43cdd62c25f0680633f2c80..07532845a57ab326bea30f2ded8acbe00c24a4a4 100644
--- a/modules/net/dap_chain_node.c
+++ b/modules/net/dap_chain_node.c
@@ -225,7 +225,7 @@ dap_chain_node_info_t* dap_chain_node_info_read( dap_chain_net_t * a_net,dap_cha
     return node_info;
 }*/
 
-int dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_node_role_t a_role, dap_chain_datum_t *a_datum)
+int dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum)
 {
     bool l_need_process = false;
     for (uint16_t j = 0; j < a_chain->autoproc_datum_types_count; j++) {
@@ -236,16 +236,7 @@ int dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_node_role_t a
     }
     if (!l_need_process)
         return -1;
-    if (a_datum->header.type_id == DAP_CHAIN_DATUM_TX) {
-        dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)a_datum->data;
-        dap_chain_tx_in_t *l_tx_in = (dap_chain_tx_in_t *)dap_chain_datum_tx_item_get(l_tx, NULL, TX_ITEM_TYPE_IN, NULL);
-        // Is not it a base transaction?
-        if (l_tx_in && !dap_hash_fast_is_blank(&l_tx_in->header.tx_prev_hash)) {
-            if (a_role.enums == NODE_ROLE_ROOT) {
-                return -1;
-            }
-        }
-    }
+    // Auth signs for emissions already verified by this callback
     return (int)a_chain->callback_add_datums(a_chain, &a_datum, 1);
 }
 
@@ -292,7 +283,7 @@ bool dap_chain_node_mempool_autoproc_init()
                         if (!l_objs[i].value_len)
                             continue;
                         dap_chain_datum_t *l_datum = (dap_chain_datum_t *)l_objs[i].value;
-                        if (dap_chain_node_mempool_process(l_chain, l_role, l_datum) >= 0) {
+                        if (dap_chain_node_mempool_process(l_chain, l_datum) >= 0) {
                             // Delete processed objects
                             dap_chain_global_db_gr_del(dap_strdup(l_objs[i].key), l_gdb_group_mempool);
                         }
@@ -332,8 +323,7 @@ void dap_chain_node_mempool_autoproc_notify(void *a_arg, const char a_op_code, c
         char *l_gdb_group_str = dap_chain_net_get_gdb_group_mempool(l_chain);
         if (!strcmp(a_group, l_gdb_group_str)) {
             dap_chain_datum_t *l_datum = (dap_chain_datum_t *)a_value;
-            dap_chain_node_role_t l_role = dap_chain_net_get_role(l_net);
-            if (dap_chain_node_mempool_process(l_chain, l_role, l_datum) >= 0) {
+            if (dap_chain_node_mempool_process(l_chain, l_datum) >= 0) {
                 dap_chain_global_db_gr_del(dap_strdup(a_key), l_gdb_group_str);
             }
         }
diff --git a/modules/net/dap_chain_node_cli.c b/modules/net/dap_chain_node_cli.c
index f95cfdc365f6c5e04849360bc88eaff95e2629e8..40159b3fc946b36859fc5f667f53e03d6164ae55 100644
--- a/modules/net/dap_chain_node_cli.c
+++ b/modules/net/dap_chain_node_cli.c
@@ -84,7 +84,6 @@ bool s_debug_cli = false;
 
 static dap_chain_node_cmd_item_t * s_commands = NULL;
 
-
 /**
  * @brief int s_poll
  * Wait for data
@@ -489,11 +488,6 @@ char *p_get_next_str( HANDLE hPipe, int *dwLen, const char *stop_str, bool del_s
     return NULL;
 }
 
-
-/**
-
- */
-
 /**
  * @brief thread_pipe_client_func
  * threading function for processing a request from a client
@@ -1077,6 +1071,13 @@ int dap_chain_node_cli_init(dap_config_t * g_config)
                                         "Add pubic certificate into the mempool to prepare its way to chains",
             "mempool_add_ca -net <net name> [-chain <chain name>] -ca_name <Certificate name>\n");
 
+    dap_chain_node_cli_cmd_item_create ("chain_ca_pub", com_chain_ca_pub,
+                                        "Add pubic certificate into the mempool to prepare its way to chains",
+            "chain_ca -net <net name> [-chain <chain name>] -ca_name <Certificate name>\n");
+
+    dap_chain_node_cli_cmd_item_create ("chain_ca_copy", com_chain_ca_copy,
+                                        "Copy pubic certificate into the mempool to prepare its way to chains",
+            "chain_ca -net <net name> [-chain <chain name>] -ca_name <Public certificate name>\n");
 
     // Transaction commands
     dap_chain_node_cli_cmd_item_create ("tx_create", com_tx_create, "Make transaction",
diff --git a/modules/net/dap_chain_node_cli_cmd.c b/modules/net/dap_chain_node_cli_cmd.c
index 26d7be50f46ca48c1bf649d5e98c34c2a8baa237..9bc515534a8bbeb88fc53cef3252ae0de4e051c2 100644
--- a/modules/net/dap_chain_node_cli_cmd.c
+++ b/modules/net/dap_chain_node_cli_cmd.c
@@ -518,15 +518,12 @@ static int link_add_or_del_with_reply(dap_chain_net_t * a_net, dap_chain_node_in
 
 /**
  * @brief node_info_dump_with_reply Handler of command 'node dump'
- *
- * str_reply[out] for reply
- * return 0 Ok, -1 error
  * @param a_net 
  * @param a_addr 
  * @param a_is_full 
  * @param a_alias 
  * @param a_str_reply 
- * @return int 
+ * @return int 0 Ok, -1 error
  */
 static int node_info_dump_with_reply(dap_chain_net_t * a_net, dap_chain_node_addr_t * a_addr, bool a_is_full,
         const char *a_alias, char **a_str_reply)
@@ -3180,10 +3177,10 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
         return -43;
     }
 
-    // Wallet address that recieves the emission
+    // Token emission
     dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-emission", &l_emission_hash_str);
 
-    // Wallet address that recieves the emission
+    // Emission certs
     dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-certs", &l_certs_str);
 
     // Wallet address that recieves the emission
@@ -3192,7 +3189,7 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
     // Token ticker
     dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-token", &l_ticker);
 
-    // Token emission
+    // Emission value
     if(dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-emission_value", &str_tmp)) {
         l_emission_value = strtoull(str_tmp, NULL, 10);
     }
@@ -3296,14 +3293,18 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
                 sizeof(l_emission->data.type_auth.signs_count);
 
         l_emission = DAP_NEW_Z_SIZE(dap_chain_datum_token_emission_t, l_emission_size);
+        l_emission->hdr.version = 1;
         strncpy(l_emission->hdr.ticker, l_ticker, sizeof(l_emission->hdr.ticker) - 1);
         l_emission->hdr.value = l_emission_value;
         l_emission->hdr.type = DAP_CHAIN_DATUM_TOKEN_EMISSION_TYPE_AUTH;
         memcpy(&l_emission->hdr.address, l_addr, sizeof(l_emission->hdr.address));
+        time_t l_time = time(NULL);
+        memcpy(&l_emission->hdr.nonce, &l_time, sizeof(time_t));
+        l_emission->data.type_auth.signs_count = l_certs_size;
         // Then add signs
         size_t l_offset = 0;
         for(size_t i = 0; i < l_certs_size; i++) {
-            dap_sign_t * l_sign = dap_cert_sign(l_certs[i], &l_emission->hdr,
+            dap_sign_t *l_sign = dap_cert_sign(l_certs[i], &l_emission->hdr,
                     sizeof(l_emission->hdr), 0);
             size_t l_sign_size = dap_sign_get_size(l_sign);
             l_emission_size += l_sign_size;
@@ -3336,15 +3337,15 @@ int com_token_emit(int a_argc, char ** a_argv, char ** a_str_reply)
         if(dap_chain_global_db_gr_set(dap_strdup(l_emission_hash_str_new), (uint8_t *) l_datum_emission, l_datum_emission_size
                 , l_gdb_group_mempool_emission)) {
             if(!dap_strcmp(l_hash_out_type,"hex"))
-                str_reply_tmp = dap_strdup_printf("datum emission %s is placed in datum pool ", l_emission_hash_str_new);
+                str_reply_tmp = dap_strdup_printf("Datum emission %s is placed in datum pool", l_emission_hash_str_new);
             else
-                str_reply_tmp = dap_strdup_printf("datum emission %s is placed in datum pool ", l_emission_hash_str_base58);
+                str_reply_tmp = dap_strdup_printf("Datum emission %s is placed in datum pool", l_emission_hash_str_base58);
         }
         else {
             if(!dap_strcmp(l_hash_out_type,"hex"))
-                dap_chain_node_cli_set_reply_text(a_str_reply, "datum emission %s is not placed in datum pool ", l_emission_hash_str_new);
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Datum emission %s is not placed in datum pool", l_emission_hash_str_new);
             else
-                dap_chain_node_cli_set_reply_text(a_str_reply, "datum emission %s is not placed in datum pool ", l_emission_hash_str_base58);
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Datum emission %s is not placed in datum pool", l_emission_hash_str_base58);
             DAP_DEL_Z(l_emission_hash_str_new);
             l_emission_hash_str = NULL;
             DAP_DEL_Z(l_emission_hash_str_base58);
@@ -3706,6 +3707,102 @@ int com_mempool_add_ca(int a_argc,  char ** a_argv, char ** a_str_reply)
     }
 }
 
+/**
+ * @brief com_chain_ca_copy
+ * @details copy public CA into the mempool
+ * @param a_argc
+ * @param a_argv
+ * @param a_arg_func
+ * @param a_str_reply
+ * @return
+ */
+int com_chain_ca_copy( int a_argc,  char ** a_argv, char ** a_str_reply)
+{
+    return com_mempool_add_ca(a_argc, a_argv, a_str_reply);
+}
+
+
+/**
+ * @brief com_chain_ca_pub
+ * @details place public CA into the mempool
+ * @param a_argc
+ * @param a_argv
+ * @param a_arg_func
+ * @param a_str_reply
+ * @return
+ */
+int com_chain_ca_pub( int a_argc,  char ** a_argv, char ** a_str_reply)
+{
+    int arg_index = 1;
+    // Read params
+    const char * l_ca_name = NULL;
+    dap_chain_net_t * l_net = NULL;
+    dap_chain_t * l_chain = NULL;
+
+    dap_chain_node_cli_find_option_val(a_argv, arg_index, a_argc, "-ca_name", &l_ca_name);
+    dap_chain_node_cli_cmd_values_parse_net_chain(&arg_index,a_argc, a_argv, a_str_reply, &l_chain, &l_net);
+
+    dap_cert_t * l_cert = dap_cert_find_by_name( l_ca_name );
+    if( l_cert == NULL ){
+        dap_chain_node_cli_set_reply_text(a_str_reply,
+                "Can't find \"%s\" certificate", l_ca_name );
+        return -4;
+    }
+
+
+    if( l_cert->enc_key == NULL ){
+        dap_chain_node_cli_set_reply_text(a_str_reply,
+                "Corrupted certificate \"%s\" without keys certificate", l_ca_name );
+        return -5;
+    }
+
+    // Create empty new cert
+    dap_cert_t * l_cert_new = dap_cert_new(l_ca_name);
+    l_cert_new->enc_key = dap_enc_key_new( l_cert->enc_key->type);
+
+    // Copy only public key
+    l_cert_new->enc_key->pub_key_data = DAP_NEW_Z_SIZE(uint8_t,
+                                                      l_cert_new->enc_key->pub_key_data_size =
+                                                      l_cert->enc_key->pub_key_data_size );
+    memcpy(l_cert_new->enc_key->pub_key_data, l_cert->enc_key->pub_key_data,l_cert->enc_key->pub_key_data_size);
+
+    // Serialize certificate into memory
+    uint32_t l_cert_serialized_size = 0;
+    byte_t * l_cert_serialized = dap_cert_mem_save( l_cert_new, &l_cert_serialized_size );
+    if( l_cert_serialized == NULL){
+        dap_chain_node_cli_set_reply_text(a_str_reply,
+                "Can't serialize in memory certificate" );
+        return -7;
+    }
+    if( l_cert_serialized == NULL){
+        dap_chain_node_cli_set_reply_text(a_str_reply,
+                "Can't serialize in memory certificate");
+        return -7;
+    }
+    // Now all the chechs passed, forming datum for mempool
+    dap_chain_datum_t * l_datum = dap_chain_datum_create( DAP_CHAIN_DATUM_CA, l_cert_serialized , l_cert_serialized_size);
+    DAP_DELETE( l_cert_serialized);
+    if( l_datum == NULL){
+        dap_chain_node_cli_set_reply_text(a_str_reply,
+                "Can't produce datum from certificate");
+        return -7;
+    }
+
+    // Finaly add datum to mempool
+    char *l_hash_str = dap_chain_mempool_datum_add(l_datum,l_chain);
+    if (l_hash_str) {
+        dap_chain_node_cli_set_reply_text(a_str_reply,
+                "Datum %s was successfully placed to mempool", l_hash_str);
+        DAP_DELETE(l_hash_str);
+        return 0;
+    } else {
+        dap_chain_node_cli_set_reply_text(a_str_reply,
+                "Can't place certificate \"%s\" to mempool", l_ca_name);
+        DAP_DELETE( l_datum );
+        return -8;
+    }
+}
+
 
 /**
  * @brief Create transaction
diff --git a/modules/net/dap_chain_node_cli_cmd_tx.c b/modules/net/dap_chain_node_cli_cmd_tx.c
index e19b286d93ae76b7eb5313f30a3c2c7a81dab956..de5e8eea74501bd8db3a4ceb50f832696f75030f 100644
--- a/modules/net/dap_chain_node_cli_cmd_tx.c
+++ b/modules/net/dap_chain_node_cli_cmd_tx.c
@@ -59,7 +59,6 @@ typedef struct dap_chain_tx_hash_processed_ht{
     UT_hash_handle hh;
 }dap_chain_tx_hash_processed_ht_t;
 
-
 /**
  * @brief _dap_chain_tx_hash_processed_ht_free
  * free l_current_hash->hash, l_current_hash, l_hash_processed
@@ -86,13 +85,15 @@ void _dap_chain_tx_hash_processed_ht_free(dap_chain_tx_hash_processed_ht_t *l_ha
  * @param a_tx_hash_processed 
  * @param l_tx_num 
  */
+
 static void s_dap_chain_datum_tx_out_data(dap_chain_datum_tx_t *a_datum,
-                                  dap_ledger_t *a_ledger,
-                                  dap_string_t *a_str_out,
-                                  const char *a_hash_out_type,
-                                  bool save_processed_tx,
-                                  dap_chain_tx_hash_processed_ht_t **a_tx_hash_processed,
-                                  size_t *l_tx_num){
+                                          dap_ledger_t *a_ledger,
+                                          dap_string_t *a_str_out,
+                                          const char *a_hash_out_type,
+                                          bool save_processed_tx,
+                                          dap_chain_tx_hash_processed_ht_t **a_tx_hash_processed,
+                                          size_t *l_tx_num)
+{
     dap_chain_hash_fast_t l_tx_hash;
     dap_hash_fast(a_datum, dap_chain_datum_tx_get_size(a_datum), &l_tx_hash);
     if (save_processed_tx){
@@ -271,8 +272,8 @@ static void s_dap_chain_datum_tx_out_data(dap_chain_datum_tx_t *a_datum,
                                      ((dap_chain_tx_out_cond_t*)item)->header.value,
                                      dap_chain_tx_out_cond_subtype_to_str(((dap_chain_tx_out_cond_t*)item)->header.subtype));
             switch (((dap_chain_tx_out_cond_t*)item)->header.subtype) {
-            case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY:
-                l_hash_str_tmp = dap_hash_fast_to_str_new(&((dap_chain_tx_out_cond_t*)item)->subtype.srv_pay.pkey_hash);
+                case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_PAY:
+                l_hash_str_tmp = dap_chain_hash_fast_to_str_new(&((dap_chain_tx_out_cond_t*)item)->subtype.srv_pay.pkey_hash);
                 dap_string_append_printf(a_str_out, "\t\t\t unit: 0x%08x\n"
                                                     "\t\t\t uid: 0x%016"DAP_UINT64_FORMAT_x"\n"
                                                     "\t\t\t pkey: %s\n"
@@ -286,7 +287,7 @@ static void s_dap_chain_datum_tx_out_data(dap_chain_datum_tx_t *a_datum,
                                          ((dap_chain_tx_out_cond_t*)item)->subtype.srv_pay.unit_price_max_datoshi);
                 DAP_FREE(l_hash_str_tmp);
                 break;
-            case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE:
+                case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE:
                 dap_string_append_printf(a_str_out, "\t\t\t uid: 0x%016"DAP_UINT64_FORMAT_x"\n"
                                                     "\t\t\t addr: %s\n"
                                                     "\t\t\t value: %Lf",
@@ -296,7 +297,7 @@ static void s_dap_chain_datum_tx_out_data(dap_chain_datum_tx_t *a_datum,
                                              ),
                                          ((dap_chain_tx_out_cond_t*)item)->subtype.srv_stake.fee_value);
                 break;
-            case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE:
+                case DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_XCHANGE:
                 dap_string_append_printf(a_str_out, "\t\t\t uid: 0x%016"DAP_UINT64_FORMAT_x"\n"
                                                     "\t\t\t net id: 0x%016"DAP_UINT64_FORMAT_x"\n"
                                                     "\t\t\t token: %s\n"
@@ -311,6 +312,7 @@ static void s_dap_chain_datum_tx_out_data(dap_chain_datum_tx_t *a_datum,
                                              ),
                                          ((dap_chain_tx_out_cond_t*)item)->subtype.srv_xchange.value);
                 break;
+                default: break;
             }
             break;
         case TX_ITEM_TYPE_OUT_EXT:
@@ -804,6 +806,7 @@ static char* dap_db_history_token_list(dap_chain_t * a_chain, const char *a_toke
                     break;
                 case DAP_CHAIN_DATUM_TOKEN_TYPE_PUBLIC: {
                     char *l_addr = dap_chain_addr_to_str(&l_token->header_public.premine_address);
+                    char * l_balance = dap_chain_balance_to_coins(l_token->header_public.total_supply);
                     dap_string_append_printf(l_str_out,
                             " total_supply: %s(%s), flags: 0x%x\n, premine_supply: %s, premine_address '%s'\n",
                             // l_token->header_public.total_supply / DATOSHI_LD,
@@ -813,6 +816,7 @@ static char* dap_db_history_token_list(dap_chain_t * a_chain, const char *a_toke
                             dap_chain_balance_print(l_token->header_public.premine_supply),
                             l_addr ? l_addr : "-");
                     DAP_DELETE(l_addr);
+                    DAP_DELETE(l_balance);
                 }
                     break;
                 default:
@@ -936,6 +940,7 @@ static char* dap_db_history_filter(dap_chain_t * a_chain, dap_ledger_t *a_ledger
                     break;
                 case DAP_CHAIN_DATUM_TOKEN_TYPE_PUBLIC: {
                     char *l_addr = dap_chain_addr_to_str(&l_token->header_public.premine_address);
+                    char * l_balance = dap_chain_balance_to_coins(l_token->header_public.total_supply);
                     dap_string_append_printf(l_str_out,
                             " total_supply: %s(%s), flags: 0x%x\n, premine_supply: %s, premine_address '%s'\n",
                             //l_token->header_public.total_supply / DATOSHI_LD,
@@ -945,6 +950,7 @@ static char* dap_db_history_filter(dap_chain_t * a_chain, dap_ledger_t *a_ledger
                             dap_chain_balance_print(l_token->header_public.premine_supply),
                             l_addr ? l_addr : "-");
                     DAP_DELETE(l_addr);
+                    DAP_DELETE(l_balance);
                 }
                     break;
                 default:
@@ -965,7 +971,8 @@ static char* dap_db_history_filter(dap_chain_t * a_chain, dap_ledger_t *a_ledger
                  l_token_num++;
                  break;
             }
-            dap_chain_datum_token_emission_t *l_token_em = (dap_chain_datum_token_emission_t*) l_datum->data;
+            size_t l_emission_size = dap_chain_datum_emission_get_size(l_datum->data);
+            dap_chain_datum_token_emission_t *l_token_em = dap_chain_datum_emission_read(l_datum->data, &l_emission_size);
             if(!a_filter_token_name || !dap_strcmp(l_token_em->hdr.ticker, a_filter_token_name)) {
                 char * l_token_emission_address_str = dap_chain_addr_to_str(&(l_token_em->hdr.address));
                 // filter for addr
@@ -1009,10 +1016,10 @@ static char* dap_db_history_filter(dap_chain_t * a_chain, dap_ledger_t *a_ledger
                 dap_string_append_printf(l_str_out, "\n");
                 l_emission_num++;
             }
-        }
-            break;
+            DAP_DELETE(l_token_em);
+        } break;
 
-            // transaction
+        // transaction
         case DAP_CHAIN_DATUM_TX:{
 
             // datum out of page
@@ -1021,247 +1028,8 @@ static char* dap_db_history_filter(dap_chain_t * a_chain, dap_ledger_t *a_ledger
                 break;
             }
             dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*)l_datum->data;
-//            dap_chain_tx_hash_processed_ht_t *l_tx_hash_processed = a_tx_hash_processed;
             //calc tx hash
             s_dap_chain_datum_tx_out_data(l_tx, a_ledger, l_str_out, a_hash_out_type, true, &a_tx_hash_processed, &l_tx_num);
-//            a_tx_hash_processed = l_tx_hash_processed;
-//            l_tx_num++;
-
-            /*dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data;
-
-            // find Token items - present in emit transaction
-            dap_list_t *l_list_tx_token = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_TOKEN, NULL);
-            // find OUT items
-            dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL);
-
-            dap_tx_data_t *l_tx_data = NULL;
-
-             // calc tx hash
-            dap_chain_hash_fast_t l_tx_hash;
-            dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
-            char *tx_hash_str;
-            char l_tx_hash_str[70];
-            dap_chain_hash_fast_to_str(&l_tx_hash, l_tx_hash_str, 70);
-            if(!dap_strcmp(a_hash_out_type, "hex"))
-                tx_hash_str = dap_strdup(l_tx_hash_str);
-            else
-                tx_hash_str = dap_enc_base58_from_hex_str_to_str(l_tx_hash_str);
-
-            dap_string_append_printf(l_str_out, "transaction: %s hash: %s\n", l_list_tx_token ? "(emit)" : "", tx_hash_str);
-            DAP_DELETE(tx_hash_str);
-
-            dap_list_t *l_list_tmp = l_list_out_items;
-            while(l_list_tmp) {
-                const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data;
-                // save OUT item l_tx_out - only for first OUT item
-                if(!l_tx_data)
-                {
-                    // save tx hash
-                    l_tx_data = DAP_NEW_Z(dap_tx_data_t);
-                    dap_chain_hash_fast_t l_tx_hash;
-                    dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_tx_hash);
-                    memcpy(&l_tx_data->tx_hash, &l_tx_hash, sizeof(dap_chain_hash_fast_t));
-                    memcpy(&l_tx_data->addr, &l_tx_out->addr, sizeof(dap_chain_addr_t));
-                    dap_chain_hash_fast_to_str(&l_tx_data->tx_hash, l_tx_data->tx_hash_str,
-                            sizeof(l_tx_data->tx_hash_str));
-                    l_tx_data->datum = DAP_NEW_SIZE(dap_chain_datum_t, l_atom_size);
-                    memcpy(l_tx_data->datum, l_datum, l_atom_size);
-                    // save token name
-                    if(l_list_tx_token) {
-                        dap_chain_tx_token_t *tk = l_list_tx_token->data;
-                        memcpy(l_tx_data->token_ticker, tk->header.ticker, sizeof(l_tx_data->token_ticker));
-                    }
-                    // take token from prev out item
-                    else {
-
-                        // find IN items
-                        dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
-                        dap_list_t *l_list_tmp_in = l_list_in_items;
-                        // find token_ticker in prev OUT items
-                        while(l_list_tmp_in) {
-                            const dap_chain_tx_in_t *l_tx_in =
-                                    (const dap_chain_tx_in_t*) l_list_tmp_in->data;
-                            dap_chain_hash_fast_t tx_prev_hash = l_tx_in->header.tx_prev_hash;
-
-                            //find prev OUT item
-                            dap_tx_data_t *l_tx_data_prev = NULL;
-                            HASH_FIND(hh, l_tx_data_hash, &tx_prev_hash, sizeof(dap_chain_hash_fast_t), l_tx_data_prev);
-                            if(l_tx_data_prev != NULL) {
-                                // fill token in l_tx_data from prev transaction
-                                if(l_tx_data) {
-                                    // get token from prev tx
-                                    memcpy(l_tx_data->token_ticker, l_tx_data_prev->token_ticker,
-                                            sizeof(l_tx_data->token_ticker));
-                                    break;
-                                }
-                            }
-                            l_list_tmp_in = dap_list_next(l_list_tmp_in);
-                        }
-                        if(l_list_in_items)
-                            dap_list_free(l_list_in_items);
-                    }
-                    HASH_ADD(hh, l_tx_data_hash, tx_hash, sizeof(dap_chain_hash_fast_t), l_tx_data);
-                }
-                l_list_tmp = dap_list_next(l_list_tmp);
-            }
-
-            if(l_list_out_items)
-                dap_list_free(l_list_out_items);
-
-            // found a_tx_hash now
-            // transaction time
-            if(l_tx->header.ts_created > 0) {
-                time_t rawtime = (time_t) l_tx->header.ts_created;
-                struct tm l_timeinfo = { 0 };
-                localtime_r(&rawtime, &l_timeinfo);
-                dap_string_append_printf(l_str_out, " %s", asctime(&l_timeinfo));
-            }
-
-            // find all OUT items in transaction
-            l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT, NULL);
-            l_list_tmp = l_list_out_items;
-            while(l_list_tmp) {
-                const dap_chain_tx_out_t *l_tx_out = (const dap_chain_tx_out_t*) l_list_tmp->data;
-                dap_tx_data_t *l_tx_data_prev = NULL;
-
-                const char *l_token_str = NULL;
-                if(l_tx_data)
-                    l_token_str = l_tx_data->token_ticker;
-                char *l_dst_to_str =
-                        (l_tx_out) ? dap_chain_addr_to_str(&l_tx_out->addr) :
-                        NULL;
-                dap_string_append_printf(l_str_out, " OUT item %lld %s to %s\n",
-                        l_tx_out->header.value,
-                        dap_strlen(l_token_str) > 0 ? l_token_str : "?",
-                        l_dst_to_str ? l_dst_to_str : "?"
-                                       );
-                DAP_DELETE(l_dst_to_str);
-                l_list_tmp = dap_list_next(l_list_tmp);
-            }
-
-            // find all IN items in transaction
-            dap_list_t *l_list_in_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN, NULL);
-            l_list_tmp = l_list_in_items;
-            // find cur addr in prev OUT items
-            while(l_list_tmp) {
-                const dap_chain_tx_in_t *l_tx_in = (const dap_chain_tx_in_t*) l_list_tmp->data;
-                dap_chain_hash_fast_t tx_prev_hash = l_tx_in->header.tx_prev_hash;
-                char l_tx_hash_str[70];
-                char *tx_hash_base58_str = NULL;
-                if(!dap_hash_fast_is_blank(&tx_prev_hash)) {
-                    tx_hash_base58_str = dap_enc_base58_from_hex_str_to_str(l_tx_data->tx_hash_str);
-                    dap_chain_hash_fast_to_str(&tx_prev_hash, l_tx_hash_str, sizeof(l_tx_hash_str));
-                }
-                else {
-                    strcpy(l_tx_hash_str, "Null");
-                    tx_hash_base58_str = dap_strdup("Null");
-                }
-                if(!dap_strcmp(a_hash_out_type, "hex"))
-                    dap_string_append_printf(l_str_out, " IN item \n  prev tx_hash %s\n", l_tx_hash_str);
-                else
-                    dap_string_append_printf(l_str_out, " IN item \n  prev tx_hash %s\n", tx_hash_base58_str);
-                DAP_DELETE(tx_hash_base58_str);
-
-                //find prev OUT item
-                dap_tx_data_t *l_tx_data_prev = NULL;
-                HASH_FIND(hh, l_tx_data_hash, &tx_prev_hash, sizeof(dap_chain_hash_fast_t), l_tx_data_prev);
-                if(l_tx_data_prev != NULL) {
-
-                    dap_chain_datum_t *l_datum_prev = get_prev_tx(l_tx_data_prev);
-                    dap_chain_datum_tx_t *l_tx_prev =
-                            l_datum_prev ? (dap_chain_datum_tx_t*) l_datum_prev->data : NULL;
-
-                    // find OUT items in prev datum
-                    dap_list_t *l_list_out_prev_items = dap_chain_datum_tx_items_get(l_tx_prev,
-                            TX_ITEM_TYPE_OUT, NULL);
-                    // find OUT item for IN item;
-                    dap_list_t *l_list_out_prev_item = dap_list_nth(l_list_out_prev_items,
-                            l_tx_in->header.tx_out_prev_idx);
-                    dap_chain_tx_out_t *l_tx_prev_out =
-                            l_list_out_prev_item ?
-                                                   (dap_chain_tx_out_t*) l_list_out_prev_item->data :
-                                                   NULL;
-                    // print value from prev out item
-                    dap_string_append_printf(l_str_out, "  prev OUT item value=%lld",
-                            l_tx_prev_out ? l_tx_prev_out->header.value : 0);
-                }
-                l_list_tmp = dap_list_next(l_list_tmp);
-            }
-
-            //find SIG type
-            dap_list_t *l_list_sig_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_SIG, NULL);
-            unsigned int l_list_sig_items_len = dap_list_length(l_list_sig_items);
-            //TX_ITEM_TYPE_SIG
-            dap_string_append_printf(l_str_out, "Count SIGN: %i \n", l_list_sig_items_len);
-            l_list_tmp = l_list_sig_items;
-            while (l_list_tmp) {
-                dap_chain_tx_sig_t *l_sig_tx = (dap_chain_tx_sig_t *)l_list_tmp->data;
-                dap_chain_hash_fast_t *l_sign_hash_fast = DAP_NEW(dap_chain_hash_fast_t);
-                dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig(l_sig_tx);
-                if (dap_sign_get_pkey_hash(l_sign, l_sign_hash_fast)){
-                    char l_tx_sign_hash_str[70];
-                    dap_chain_hash_fast_to_str(l_sign_hash_fast, l_tx_sign_hash_str, 70);
-                    dap_string_append_printf(l_str_out, "%s\n", l_tx_sign_hash_str);
-                }else{
-                    dap_string_append_printf(l_str_out, "Can't get pkey for sign \n");
-                }
-                DAP_FREE(l_sign_hash_fast);
-                l_list_tmp = dap_list_next(l_list_tmp);
-            }
-            dap_list_free(l_list_sig_items);
-            //find PKEY
-            dap_list_t *l_list_pkey_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_PKEY, NULL);
-            unsigned int l_list_pkey_items_len = dap_list_length(l_list_pkey_items);
-            dap_string_append_printf(l_str_out, "Count PKEY: %i \n", l_list_pkey_items_len);
-            dap_list_free(l_list_pkey_items);
-            //find TOKEN
-            dap_list_t *l_list_token_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_TOKEN, NULL);
-            unsigned int l_list_token_items_len = dap_list_length(l_list_token_items);
-            dap_string_append_printf(l_str_out, "Count TOKEN: %i \n", l_list_token_items_len);
-            l_list_tmp = l_list_token_items;
-            while(l_list_tmp){
-                dap_chain_tx_token_t *l_token = (dap_chain_tx_token_t*)l_list_tmp->data;
-                l_list_tmp = dap_list_next(l_list_tmp);
-            }
-            dap_list_free(l_list_token_items);
-            //find IN_COND
-            dap_list_t *l_list_in_cond_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_IN_COND, NULL);
-            unsigned int l_list_in_cond_items_len = dap_list_length(l_list_in_cond_items);
-            dap_string_append_printf(l_str_out, "Count IN_COND: %i \n", l_list_in_cond_items_len);
-            dap_list_free(l_list_in_cond_items);
-            //find OUT_COND
-            dap_list_t *l_list_out_cond_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_COND, NULL);
-            unsigned int l_list_out_cond_items_len = dap_list_length(l_list_out_cond_items);
-            dap_string_append_printf(l_str_out, "Count OUT_COND: %i \n", l_list_out_cond_items_len);
-            dap_list_free(l_list_out_cond_items);
-            //find OUT_EXT
-            dap_list_t *l_list_out_ext_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_EXT, NULL);
-            unsigned int l_list_out_ext_items_len = dap_list_length(l_list_out_ext_items);
-            dap_string_append_printf(l_str_out, "Count OUT_EXIT: %i \n", l_list_out_ext_items_len);
-            dap_list_free(l_list_out_ext_items);
-            //find RECEIPT
-            dap_list_t *l_list_receipt_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_RECEIPT, NULL);
-            unsigned int l_list_receipt_items_len = dap_list_length(l_list_receipt_items);
-            dap_string_append_printf(l_str_out, "Count RECEIPT: %i \n", l_list_receipt_items_len);
-            dap_list_free(l_list_receipt_items);
-            //find TOKEN_EXT
-            dap_list_t *l_list_token_ext_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_TOKEN_EXT, NULL);
-            unsigned int l_list_token_ext_items_len = dap_list_length(l_list_token_ext_items);
-            dap_string_append_printf(l_str_out, "Count TOKEN_EXT: %i \n", l_list_token_ext_items_len);
-            dap_list_free(l_list_token_ext_items);
-
-            dap_string_append_printf(l_str_out, "\n");
-
-
-
-            if(l_list_tx_token)
-                dap_list_free(l_list_tx_token);
-            if(l_list_out_items)
-                dap_list_free(l_list_out_items);
-            if(l_list_in_items)
-                dap_list_free(l_list_in_items);
-            l_tx_hash_found = true;
-            l_tx_num++;*/
         }
             break;
         default:
diff --git a/modules/net/dap_chain_node_client.c b/modules/net/dap_chain_node_client.c
index 9d77b359f605a5740c838b545746a1e58f1f80b6..81716e854c1a37c56ab36bc5d27a8baffb06a0d2 100644
--- a/modules/net/dap_chain_node_client.c
+++ b/modules/net/dap_chain_node_client.c
@@ -276,6 +276,7 @@ static void s_stage_connected_callback(dap_client_t *a_client, void *a_arg)
             for(size_t i = 0; i < l_channels_count; i++) {
                 if(dap_chain_node_client_set_callbacks(a_client, l_client_internal->active_channels[i]) == -1) {
                     log_it(L_WARNING, "No ch_chain channel, can't init notify callback for pkt type CH_CHAIN");
+                    return;
                 }
             }
         }
@@ -659,7 +660,6 @@ dap_chain_node_client_t* dap_chain_node_client_create_n_connect(dap_chain_net_t
     return NULL;
 }
 
-
 /**
  * @brief dap_chain_node_client_connect_internal
  * Create new dap_client, setup it, and send it in adventure trip
@@ -744,6 +744,17 @@ void dap_chain_node_client_close(dap_chain_node_client_t *a_client)
         char l_node_addr_str[INET_ADDRSTRLEN] = {};
         inet_ntop(AF_INET, &a_client->info->hdr.ext_addr_v4, l_node_addr_str, INET_ADDRSTRLEN);
         log_it(L_INFO, "Closing node client to uplink %s:%d", l_node_addr_str, a_client->info->hdr.ext_port);
+        dap_stream_ch_t *l_ch = dap_stream_ch_find_by_uuid_unsafe(a_client->stream_worker, a_client->ch_chain_uuid);
+        if (l_ch) {
+            dap_stream_ch_chain_t *l_ch_chain = DAP_STREAM_CH_CHAIN(l_ch);
+            l_ch_chain->callback_notify_packet_in = NULL;
+            l_ch_chain->callback_notify_packet_out = NULL;
+        }
+        l_ch = dap_stream_ch_find_by_uuid_unsafe(a_client->stream_worker, a_client->ch_chain_net_uuid);
+        if (l_ch) {
+            dap_stream_ch_chain_net_t *l_ch_chain_net = DAP_STREAM_CH_CHAIN_NET(l_ch);
+            l_ch_chain_net->notify_callback = NULL;
+        }
         // clean client
         dap_client_pvt_t *l_client_pvt = dap_client_pvt_find(a_client->client->pvt_uuid);
         if (l_client_pvt) {
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index cfca21d02d72b3022a8891b52bd05c9c74d414d3..58ea4b07dbcf6631dc7d39d7264f87bc5396fedb 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;
@@ -184,3 +184,4 @@ void dap_chain_net_sync_gdb_broadcast(void *a_arg, const char a_op_code, const c
 struct dap_chain_node_client * dap_chain_net_client_create_n_connect( dap_chain_net_t * a_net, struct dap_chain_node_info *a_link_info);
 struct dap_chain_node_client * dap_chain_net_client_create_n_connect_channels( dap_chain_net_t * a_net,struct dap_chain_node_info *a_link_info,
                                                                                const char * a_channels);
+int dap_cert_chain_file_save(dap_chain_datum_t * l_datum, char * net_name);
diff --git a/modules/net/include/dap_chain_node.h b/modules/net/include/dap_chain_node.h
index 6b6a810667a10eec933d95262cdc46dcc79d23a4..f8fdcc6af4c28d9881b63c2f28c083b17b98fb54 100644
--- a/modules/net/include/dap_chain_node.h
+++ b/modules/net/include/dap_chain_node.h
@@ -144,7 +144,7 @@ inline static char* dap_chain_node_addr_to_hash_str(dap_chain_node_addr_t *addre
     return a_key;
 }
 
-int dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_node_role_t a_role, dap_chain_datum_t *a_datum);
+int dap_chain_node_mempool_process(dap_chain_t *a_chain, dap_chain_datum_t *a_datum);
 bool dap_chain_node_mempool_autoproc_init();
 void dap_chain_node_mempool_autoproc_deinit();
 void dap_chain_node_mempool_autoproc_notify(void *a_arg, const char a_op_code, const char *a_group,
diff --git a/modules/net/include/dap_chain_node_cli_cmd.h b/modules/net/include/dap_chain_node_cli_cmd.h
index 41c2125affc2cb770118836733023d8029533845..50fc831af72e399cc12076b641c70b84a476726c 100644
--- a/modules/net/include/dap_chain_node_cli_cmd.h
+++ b/modules/net/include/dap_chain_node_cli_cmd.h
@@ -144,3 +144,6 @@ int com_mempool_proc(int argc, char ** argv, char ** a_str_reply);
  * Place public CA into the mempool
  */
 int com_mempool_add_ca( int a_argc,  char ** a_argv, char ** a_str_reply);
+int com_chain_ca_pub( int a_argc,  char ** a_argv, char ** a_str_reply);
+int com_chain_ca_copy( int a_argc,  char ** a_argv, char ** a_str_reply);
+
diff --git a/modules/net/srv/CMakeLists.txt b/modules/net/srv/CMakeLists.txt
index 25282398a7c21a93efeaa7679ba3afb0dcb5a976..6e4db3ae7f4ffdf426105978621e42384dda42d7 100644
--- a/modules/net/srv/CMakeLists.txt
+++ b/modules/net/srv/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_net_srv)
 
 file(GLOB DAP_CHAIN_NET_SRV_SRCS *.c libmaxminddb/*.c)
@@ -7,12 +7,17 @@ file(GLOB DAP_CHAIN_NET_SRV_HEADERS include/*.h libmaxminddb/*.h)
 
 add_library(${PROJECT_NAME} STATIC ${DAP_CHAIN_NET_SRV_SRCS} ${DAP_CHAIN_NET_SRV_HEADERS})
 
+set(NET_SRV_LIBS dap_chain_net_srv dap_core dap_crypto dap_chain dap_chain_net dap_chain_wallet)
+
 if (CELLFRAME_MODULES MATCHES "modules-dynamic")
-    target_link_libraries(dap_chain_net_srv dap_core dap_crypto dap_chain dap_chain_net dap_chain_wallet dap_modules_dynamic_cdb)
-else()
-    target_link_libraries(dap_chain_net_srv dap_core dap_crypto dap_chain dap_chain_net dap_chain_wallet)
+    set(NET_SRV_LIBS ${NET_SRV_LIBS} dap_modules_dynamic_cdb)
 endif()
 
+#if (CELLFRAME_MODULES MATCHES "srv-stake")
+#    set(NET_SRV_LIBS ${NET_SRV_LIBS} dap_chain_net_srv_stake)
+#endif()
+
+target_link_libraries(${NET_SRV_LIBS})
 target_include_directories(dap_chain_net_srv INTERFACE .)
 target_include_directories(${PROJECT_NAME} PUBLIC include)
 target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../3rdparty/uthash/src)
diff --git a/modules/net/srv/dap_chain_net_srv.c b/modules/net/srv/dap_chain_net_srv.c
index 4e8d8cc338ec19b1ca26029e07115538d5457f3c..22d0f1a7e8464d346058539045b8858acd540738 100644
--- a/modules/net/srv/dap_chain_net_srv.c
+++ b/modules/net/srv/dap_chain_net_srv.c
@@ -60,6 +60,7 @@
 #include "dap_chain_net_srv.h"
 #include "dap_chain_net_srv_order.h"
 #include "dap_chain_net_srv_stream_session.h"
+#include "dap_stream_ch_chain_net_srv.h"
 #ifdef DAP_MODULES_DYNAMIC
 #include "dap_modules_dynamic_cdb.h"
 #endif
@@ -90,9 +91,9 @@ static void s_load_all(void);
  * @brief dap_chain_net_srv_init
  * @return
  */
-int dap_chain_net_srv_init(dap_config_t * a_cfg)
-{
-    UNUSED(a_cfg);
+int dap_chain_net_srv_init()
+{    
+    dap_stream_ch_chain_net_srv_init();
     m_uid = NULL;
     m_uid_count = 0;
     if( dap_chain_net_srv_order_init() != 0 )
diff --git a/modules/net/srv/dap_chain_net_srv_order.c b/modules/net/srv/dap_chain_net_srv_order.c
index b8d0e53fdbe66523ea9f90cac4cdf865886eba6b..21dcd4d34b4f260c8dcd8789f126596593b4ea79 100644
--- a/modules/net/srv/dap_chain_net_srv_order.c
+++ b/modules/net/srv/dap_chain_net_srv_order.c
@@ -30,12 +30,6 @@
 #include "dap_enc_base58.h"
 #include "dap_chain_global_db.h"
 #include "dap_chain_net_srv_countries.h"
-#if DAP_SRV_STAKE_USED
-#include "dap_chain_net_srv_stake.h"
-#else
-static bool dap_chain_net_srv_stake_key_delegated(dap_chain_addr_t *a_addr) { UNUSED(a_addr); return false; }
-#endif
-//#include "dap_chain_net_srv_geoip.h"
 
 #define LOG_TAG "dap_chain_net_srv_order"
 
@@ -544,7 +538,7 @@ static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const
                 DAP_DELETE(l_gdb_group_str);
                 return;
             }
-            dap_chain_hash_fast_t l_pkey_hash;
+            /*dap_chain_hash_fast_t l_pkey_hash;
             if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash)) {
                 dap_chain_global_db_gr_del(dap_strdup(a_key), a_group);
                 DAP_DELETE(l_gdb_group_str);
@@ -556,7 +550,7 @@ static void s_srv_order_callback_notify(void *a_arg, const char a_op_code, const
             uint64_t l_solvency = dap_chain_uint128_to(l_balance);
             if (l_solvency < l_order->price && !dap_chain_net_srv_stake_key_delegated(&l_addr)) {
                 dap_chain_global_db_gr_del(dap_strdup(a_key), a_group);
-            }
+            }*/
         }
         DAP_DELETE(l_gdb_group_str);
     }
diff --git a/modules/net/srv/include/dap_chain_net_srv.h b/modules/net/srv/include/dap_chain_net_srv.h
index cb018bdcfb09528a8347529df2cbb9781bf35ead..2fc2a3bea2b2da1a8ed3f488b22a9845be7a8338 100755
--- a/modules/net/srv/include/dap_chain_net_srv.h
+++ b/modules/net/srv/include/dap_chain_net_srv.h
@@ -84,7 +84,7 @@ typedef struct dap_chain_net_srv
 typedef void (*dap_chain_net_srv_callback_new_t)(dap_chain_net_srv_t *, dap_config_t *);
 
 
-int dap_chain_net_srv_init(dap_config_t * a_cfg);
+int dap_chain_net_srv_init();
 void dap_chain_net_srv_deinit(void);
 dap_chain_net_srv_t* dap_chain_net_srv_add(dap_chain_net_srv_uid_t a_uid,dap_chain_net_srv_callback_data_t a_callback_requested,
                                            dap_chain_net_srv_callback_data_t a_callback_response_success,
diff --git a/modules/service/app-db/CMakeLists.txt b/modules/service/app-db/CMakeLists.txt
index f6a7a7977d843e1bdf10796aa8c237534a916ec5..568cf7a2b2146c5b846051d05a830ff8ba25a7a5 100644
--- a/modules/service/app-db/CMakeLists.txt
+++ b/modules/service/app-db/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_net_srv_app_db)
   
 file(GLOB DAP_CHAIN_NET_SRV_APP_DB_SRCS *.c)
diff --git a/modules/service/app/CMakeLists.txt b/modules/service/app/CMakeLists.txt
index e69756a8d304d41eb5e220462288a86aead5c742..ede9f775fc31cc5bd1b4df75623a664e38bf8f40 100644
--- a/modules/service/app/CMakeLists.txt
+++ b/modules/service/app/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_net_srv_app)
   
 file(GLOB DAP_CHAIN_NET_SRV_APP_SRCS  *.c)
diff --git a/modules/service/datum/CMakeLists.txt b/modules/service/datum/CMakeLists.txt
index dc38274497865096fdd8e21bb576dc99cf373ef0..e953602dbbd6c42dbbd23eb120fcb2ac6afd96d2 100644
--- a/modules/service/datum/CMakeLists.txt
+++ b/modules/service/datum/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_net_srv_datum)
   
 file(GLOB DAP_CHAIN_NET_SRV_DATUM_SRCS *.c)
diff --git a/modules/service/mining-pool/CMakeLists.txt b/modules/service/mining-pool/CMakeLists.txt
index 6a66f485f3affa09480ab6930c8b3f153c44afd5..a2dd64da4c44b5c251e37620f10abf5286a566af 100644
--- a/modules/service/mining-pool/CMakeLists.txt
+++ b/modules/service/mining-pool/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_net_srv_datum_pool)
   
 file(GLOB DAP_CHAIN_NET_SRV_DATUM_POOL_SRCS *.c)
diff --git a/modules/service/stake/CMakeLists.txt b/modules/service/stake/CMakeLists.txt
index e50be120ada65584254d16bd4a764594052e0722..c4c5f452a18e2b2b724f282c7b0b47f24e4d97d0 100644
--- a/modules/service/stake/CMakeLists.txt
+++ b/modules/service/stake/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_net_srv_stake)
 
 file(GLOB DAP_SRV_STAKE_SRCS *.c)
@@ -9,4 +9,4 @@ add_library(${PROJECT_NAME} STATIC ${DAP_SRV_STAKE_SRCS} ${DAP_SRV_STAKE_HEADERS
 
 target_include_directories(dap_chain_crypto INTERFACE .)
 target_include_directories(${PROJECT_NAME} PUBLIC include)
-target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_net dap_chain_net_srv)
+target_link_libraries(${PROJECT_NAME} dap_core dap_crypto dap_chain dap_chain_crypto dap_chain_net dap_chain_net_srv dap_chain_cs_dag_poa dap_chain_cs_block_poa)
diff --git a/modules/service/stake/dap_chain_net_srv_stake.c b/modules/service/stake/dap_chain_net_srv_stake.c
index 31a05d446cc7980f4aff9c7f2121cf544d53f7e1..f913f7f3bcd254ef72e7b559fc97953080c37406 100644
--- a/modules/service/stake/dap_chain_net_srv_stake.c
+++ b/modules/service/stake/dap_chain_net_srv_stake.c
@@ -29,13 +29,15 @@
 #include "dap_chain_common.h"
 #include "dap_chain_mempool.h"
 #include "dap_chain_net_srv_common.h"
+#include "dap_chain_cs_block_poa.h"
+#include "dap_chain_cs_dag_poa.h"
 #include "dap_chain_net_srv_stake.h"
 
 #define LOG_TAG "dap_chain_net_srv_stake"
 
 static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply);
 
-static dap_chain_net_srv_stake_t *s_srv_stake;
+static dap_chain_net_srv_stake_t *s_srv_stake = NULL;
 
 /**
  * @brief dap_stream_ch_vpn_init Init actions for VPN stream channel
@@ -46,22 +48,27 @@ static dap_chain_net_srv_stake_t *s_srv_stake;
 int dap_chain_net_srv_stake_init()
 {
     dap_chain_node_cli_cmd_item_create("srv_stake", s_cli_srv_stake, "Delegated stake service commands",
-    "srv_stake order create -net <net name> -from_addr <addr> -token <ticker> -coins <value> -cert <name> -fee_percent <value>\n"
-        "\tCreate a new order with specified amount of datoshi to delegate it to the specified address."
-        "The fee with specified percent with this delagation will be returned to the fee address pointed by delegator\n"
-    "srv_stake order remove -net <net name> -order <order hash> [-H hex|base58(default)]\n"
+    "srv_stake order create -net <net name> -addr_hldr <addr> -token <ticker> -coins <value> -cert <name> -fee_percent <value>\n"
+        "\tCreate a new order with specified amount of datoshi to delegate specified cert from the specified address.\n"
+        "\tThe fee with specified percent with this delagation will be returned to the fee address pointed by delegator\n"
+    "srv_stake order declare -net <net name> -wallet <name> -token <ticker> -coins <value> -fee_percent <value>"
+        "\tCreate a new order with specified amount of datoshi and fee which holder is ready to stake.\n"
+    "srv_stake order remove -net <net name> -order <order hash> [-H <hex | base58(default)>]\n"
          "\tRemove order with specified hash\n"
-    "srv_stake order update -net <net name> -order <order hash> -cert <name> [-H hex|base58(default)]"
-                            "{-from_addr <addr> | -token <ticker> -coins <value> | -fee_percent <value>}\n"
+    "srv_stake order update -net <net name> -order <order hash> {-cert <name> | -wallet <name>} [-H <hex | base58(default)>]"
+                            "{[-addr_hldr <addr>] [-token <ticker>] [-coins <value>] [-fee_percent <value>] |"
+                            " | [-token <ticker>] [-coins <value>] -fee_percent <value>]\n"
          "\tUpdate order with specified hash\n"
     "srv_stake order list -net <net name>\n"
          "\tGet the stake orders list within specified net name\n"
-    "srv_stake delegate -order <order hash> -net <net name> -wallet <wallet_name> -fee_addr <addr>\n"
+    "srv_stake delegate -order <order hash> -net <net name> -wallet <name> -fee_addr <addr>\n"
          "\tDelegate tokens with specified order within specified net name. Specify fee address\n"
+    "srv_stake approve -net <net name> -tx <transaction hash> -cert <root cert name>\n"
+         "\tApprove stake transaction by root node certificate within specified net name.\n"
     "srv_stake transactions -net <net name> {-addr <addr from>}\n"
-         "\tShow the list of active stake transactions (optional delegated from addr)\n"
+         "\tShow the list of requested, active and canceled stake transactions (optional delegated from addr)\n"
     "srv_stake invalidate -net <net name> -tx <transaction hash> -wallet <wallet name>\n"
-         "\tInvalidate stake transaction by hash within net name and return stake to specified wallet\n"
+         "\tInvalidate requested stake transaction by hash within net name and return stake to specified wallet\n"
     );
     s_srv_stake = DAP_NEW_Z(dap_chain_net_srv_stake_t);
     uint16_t l_net_count;
@@ -73,6 +80,16 @@ int dap_chain_net_srv_stake_init()
         dap_chain_tx_out_cond_t *l_out_cond;
         int l_out_cond_idx;
         char l_token[DAP_CHAIN_TICKER_SIZE_MAX];
+        size_t l_auth_certs_count = 0;
+        dap_cert_t **l_auth_certs = NULL;
+        for (dap_chain_t *l_chain = l_net_list[i]->pub.chains; l_chain; l_chain = l_chain->next) {
+            l_auth_certs = dap_chain_cs_dag_poa_get_auth_certs(l_chain, &l_auth_certs_count);
+            if (l_auth_certs)
+                break;
+            l_auth_certs = dap_chain_cs_block_poa_get_auth_certs(l_chain, &l_auth_certs_count);
+            if (l_auth_certs)
+                break;
+        }
         // Find all stake transactions
         do {
             l_tx_tmp = dap_chain_ledger_tx_cache_find_out_cond(l_ledger, &l_tx_cur_hash, &l_out_cond, &l_out_cond_idx, l_token);
@@ -83,24 +100,36 @@ int dap_chain_net_srv_stake_init()
                 continue;
             if (dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, &l_tx_cur_hash, l_out_cond_idx))
                 continue;
+            dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(l_tx_tmp, NULL,
+                                                                                             TX_ITEM_TYPE_SIG, NULL);
+            dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig);
+            if (!l_sign) {
+                continue;
+            }
             // Create the stake item
-            dap_chain_net_srv_stake_item_t *l_stake = DAP_NEW_Z(dap_chain_net_srv_stake_item_t);
+            dap_chain_net_srv_stake_item_t *l_stake;
+            bool l_is_new = false;
+            HASH_FIND(hh, s_srv_stake->itemlist, &l_out_cond->params, sizeof(dap_chain_addr_t), l_stake);
+            if (!l_stake) {
+                l_stake = DAP_NEW_Z(dap_chain_net_srv_stake_item_t);
+                l_is_new = true;
+            }
             l_stake->net = l_net_list[i];
             dap_stpcpy(l_stake->token, l_token);
             l_stake->value = l_out_cond->header.value;
-            dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(l_tx_tmp, NULL,
-                    TX_ITEM_TYPE_SIG, NULL);
-            dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig);
-            dap_chain_hash_fast_t l_pkey_hash;
-            if (!dap_sign_get_pkey_hash(l_sign, &l_pkey_hash)) {
-                continue;
+            for (size_t i = 0; i < l_auth_certs_count; i++) {
+                if (!dap_cert_compare_with_sign(l_auth_certs[i], l_sign)) {
+                    l_stake->is_active = true;
+                    break;
+                }
             }
-            dap_chain_addr_fill(&l_stake->addr_from, l_sign->header.type, &l_pkey_hash, l_net_list[i]->pub.id);
-            memcpy(&l_stake->addr_to, l_out_cond->params, sizeof(dap_chain_addr_t));
+            memcpy(&l_stake->signing_addr, &l_out_cond->params, sizeof(dap_chain_addr_t));
+            memcpy(&l_stake->addr_hldr, &l_out_cond->subtype.srv_stake.hldr_addr, sizeof(dap_chain_addr_t));
             memcpy(&l_stake->addr_fee, &l_out_cond->subtype.srv_stake.fee_addr, sizeof(dap_chain_addr_t));
             l_stake->fee_value = l_out_cond->subtype.srv_stake.fee_value;
             memcpy(&l_stake->tx_hash, &l_tx_cur_hash, sizeof(dap_chain_hash_fast_t));
-            HASH_ADD(hh, s_srv_stake->itemlist, tx_hash, sizeof(dap_chain_hash_fast_t), l_stake);
+            if (l_is_new)
+                HASH_ADD(hh, s_srv_stake->itemlist, signing_addr, sizeof(dap_chain_addr_t), l_stake);
         } while (l_tx_tmp);
     }
     DAP_DELETE(l_net_list);
@@ -115,20 +144,106 @@ void dap_chain_net_srv_stake_deinit()
         HASH_DEL(s_srv_stake->itemlist, l_stake);
         DAP_DELETE(l_stake);
     }
-    DAP_DELETE(s_srv_stake);
+    DAP_DEL_Z(s_srv_stake);
+}
+
+static void s_stake_update(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_authorized)
+{
+    dap_chain_net_srv_stake_item_t *l_stake;
+    if (a_cond)
+        HASH_FIND(hh, s_srv_stake->itemlist, &a_cond->params, sizeof(dap_chain_addr_t), l_stake);
+    else
+        l_stake = DAP_NEW_Z(dap_chain_net_srv_stake_item_t);
+    assert(l_stake);
+    dap_chain_tx_out_cond_t *l_out_cond = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_OUT_COND, NULL);
+    if (!l_out_cond || l_out_cond->header.subtype != DAP_CHAIN_TX_OUT_COND_SUBTYPE_SRV_STAKE) {
+        // Stake tx is used out
+        HASH_DEL(s_srv_stake->itemlist, l_stake);
+        DAP_DELETE(l_stake);
+        return;
+    }
+    // Update stake parameters
+    if (!a_cond) {
+        // New stake transaction
+        memcpy(&l_stake->signing_addr, &l_out_cond->params, sizeof(dap_chain_addr_t));
+        HASH_ADD(hh, s_srv_stake->itemlist, signing_addr, sizeof(dap_chain_addr_t), l_stake);
+    } else if (memcmp(&a_cond->params, &l_out_cond->params, sizeof(dap_chain_addr_t))) {
+        HASH_DEL(s_srv_stake->itemlist, l_stake);
+        dap_chain_net_srv_stake_item_t *l_stake_cur = NULL;
+        HASH_FIND(hh, s_srv_stake->itemlist, &l_out_cond->params, sizeof(dap_chain_addr_t), l_stake_cur);
+        if (l_stake_cur) {
+            DAP_DELETE(l_stake);
+            l_stake = l_stake_cur;
+        }
+        memcpy(&l_stake->signing_addr, &l_out_cond->params, sizeof(dap_chain_addr_t));
+        if (l_stake_cur)
+            HASH_ADD(hh, s_srv_stake->itemlist, signing_addr, sizeof(dap_chain_addr_t), l_stake);
+    }
+    if (a_authorized)
+        l_stake->is_active = true;
+    memcpy(&l_stake->addr_hldr, &l_out_cond->subtype.srv_stake.hldr_addr, sizeof(dap_chain_addr_t));
+    memcpy(&l_stake->addr_fee, &l_out_cond->subtype.srv_stake.fee_addr, sizeof(dap_chain_addr_t));
+    l_stake->fee_value = l_out_cond->subtype.srv_stake.fee_value;
+    dap_hash_fast(a_tx, dap_chain_datum_tx_get_size(a_tx), &l_stake->tx_hash);
 }
 
-bool dap_chain_net_srv_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx)
+static bool s_stake_conditions_calc(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner, bool a_update)
 {
-    UNUSED(a_cond);
-    UNUSED(a_tx);
+    dap_chain_tx_out_cond_t *l_out_cond = NULL;
+    if (!a_cond) {
+        // New stake tx
+        l_out_cond = (dap_chain_tx_out_cond_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_OUT_COND, NULL);
+    } else
+        l_out_cond = a_cond;
+    dap_chain_net_id_t l_cur_net_id = l_out_cond->subtype.srv_stake.hldr_addr.net_id;
+    dap_chain_net_t *l_net = dap_chain_net_by_id(l_cur_net_id);
+    if (!l_net)
+        return false;
+    size_t l_auth_certs_count = 0;
+    dap_cert_t **l_auth_certs = NULL;
+    for (dap_chain_t *l_chain = l_net->pub.chains; l_chain; l_chain = l_chain->next) {
+        l_auth_certs = dap_chain_cs_dag_poa_get_auth_certs(l_chain, &l_auth_certs_count);
+        if (l_auth_certs)
+            break;
+        l_auth_certs = dap_chain_cs_block_poa_get_auth_certs(l_chain, &l_auth_certs_count);
+        if (l_auth_certs)
+            break;
+    }
+    if (!l_auth_certs || !l_auth_certs_count)   // Can't validate stake tx authority for this net
+        return false;
+    dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_SIG, NULL);
+    dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig);
+    if (!l_sign)
+        return false;
+    for (size_t i = 0; i < l_auth_certs_count; i++) {
+        if (!dap_cert_compare_with_sign(l_auth_certs[i], l_sign)) {
+            if (a_update)
+                s_stake_update(a_cond, a_tx, true);
+            return true;
+        }
+    }
+    if (a_owner) {
+        if (a_update)
+            s_stake_update(a_cond, a_tx, false);
+        return true;
+    }
     return false;
 }
 
+bool dap_chain_net_srv_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner)
+{
+    return s_stake_conditions_calc(a_cond, a_tx, a_owner, false);
+}
+
+bool dap_chain_net_srv_stake_updater(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner)
+{
+    return s_stake_conditions_calc(a_cond, a_tx, a_owner, true);
+}
+
 bool dap_chain_net_srv_stake_key_delegated(dap_chain_addr_t *a_addr)
 {
     if (!s_srv_stake) {
-        return true;
+        return false;
     }
     while (!s_srv_stake->initialized);
 
@@ -137,35 +252,38 @@ bool dap_chain_net_srv_stake_key_delegated(dap_chain_addr_t *a_addr)
     }
     dap_chain_net_srv_stake_item_t *l_stake = NULL;
     HASH_FIND(hh, s_srv_stake->itemlist, a_addr, sizeof(dap_chain_addr_t), l_stake);
-    if (l_stake) { // public key delegated for this network
+    if (l_stake && l_stake->is_active) { // public key delegated for this network
         return true;
     }
     return false;
 }
 
-bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum_tx_t *a_tx)
+bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum_t *a_datum)
 {
-    if (!s_srv_stake) {
-        return true;
+    if (!s_srv_stake) { // Drop all atoms if stake service inactivated
+        return false;
     }
     while (!s_srv_stake->initialized);
 
-    if (!a_addr || !a_tx) {
+    if (!a_addr || !a_datum) {
         return false;
     }
     dap_chain_net_srv_stake_item_t *l_stake = NULL;
     HASH_FIND(hh, s_srv_stake->itemlist, a_addr, sizeof(dap_chain_addr_t), l_stake);
-    if (l_stake == NULL) { // public key not delegated for this network
-        return true;
+    if (!l_stake || !l_stake->is_active) { // public key not delegated for this network
+        return false;
     }
-    dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(a_tx, NULL, TX_ITEM_TYPE_SIG, NULL);
+    if (a_datum->header.type_id != DAP_CHAIN_DATUM_TX)
+        return true;
+    dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t *)a_datum->data;
+    dap_chain_tx_sig_t *l_tx_sig = (dap_chain_tx_sig_t *)dap_chain_datum_tx_item_get(l_tx, NULL, TX_ITEM_TYPE_SIG, NULL);
     dap_sign_t *l_sign = dap_chain_datum_tx_item_sign_get_sig((dap_chain_tx_sig_t *)l_tx_sig);
     dap_chain_hash_fast_t l_pkey_hash = {};
     dap_sign_get_pkey_hash(l_sign, &l_pkey_hash);
     dap_chain_addr_t l_owner_addr = {};
     dap_chain_addr_fill(&l_owner_addr, l_sign->header.type, &l_pkey_hash, a_addr->net_id);
     uint64_t l_outs_sum = 0, l_fee_sum = 0;
-    dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(a_tx, TX_ITEM_TYPE_OUT_ALL, NULL);
+    dap_list_t *l_list_out_items = dap_chain_datum_tx_items_get(l_tx, TX_ITEM_TYPE_OUT_ALL, NULL);
     uint32_t l_out_idx_tmp = 0; // current index of 'out' item
     for (dap_list_t *l_list_tmp = l_list_out_items; l_list_tmp; l_list_tmp = dap_list_next(l_list_tmp), l_out_idx_tmp++) {
         dap_chain_tx_item_type_t l_type = *(uint8_t *)l_list_tmp->data;
@@ -195,7 +313,7 @@ bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum
 
 static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_srv_stake_item_t *a_stake, dap_chain_wallet_t *a_wallet)
 {
-    if (!a_stake || !a_stake->net || !a_stake->addr_to.addr_ver || !a_stake->addr_from.addr_ver ||
+    if (!a_stake || !a_stake->net || !a_stake->signing_addr.addr_ver || !a_stake->addr_hldr.addr_ver ||
             !a_stake->addr_fee.addr_ver || !*a_stake->token || !a_wallet) {
         return NULL;
     }
@@ -205,7 +323,7 @@ static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_srv_stake_item_t *a
 
     dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(a_stake->net->pub.name);
     dap_chain_addr_t *l_owner_addr = (dap_chain_addr_t *)dap_chain_wallet_get_addr(a_wallet, a_stake->net->pub.id);
-    if (memcmp(l_owner_addr, &a_stake->addr_from, sizeof(dap_chain_addr_t))) {
+    if (memcmp(l_owner_addr, &a_stake->addr_hldr, sizeof(dap_chain_addr_t))) {
         log_it(L_WARNING, "Odrer and wallet address do not match");
         return NULL;
     }
@@ -233,8 +351,9 @@ static dap_chain_datum_tx_t *s_stake_tx_create(dap_chain_net_srv_stake_item_t *a
     // add 'out_cond' & 'out' items
     {
         dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_ID };
-        dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_stake->value, a_stake->fee_value, &a_stake->addr_fee,
-                                                                                              (void *)&a_stake->addr_to, sizeof(dap_chain_addr_t));
+        dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_stake->value, a_stake->fee_value,
+                                                                                              &a_stake->addr_fee, &a_stake->addr_hldr,
+                                                                                              (void *)&a_stake->signing_addr, sizeof(dap_chain_addr_t));
         if (!l_tx_out) {
             dap_chain_datum_tx_delete(l_tx);
             DAP_DELETE(l_owner_addr);
@@ -285,6 +404,59 @@ static bool s_stake_tx_put(dap_chain_datum_tx_t *a_tx, dap_chain_net_t *a_net)
     return true;
 }
 
+static dap_chain_datum_tx_t *s_stake_tx_approve(dap_chain_net_srv_stake_item_t *a_stake, dap_cert_t *a_cert)
+{
+    // create empty transaction
+    dap_chain_datum_tx_t *l_tx = dap_chain_datum_tx_create();
+
+    dap_ledger_t *l_ledger = dap_chain_ledger_by_net_name(a_stake->net->pub.name);
+
+    // create and add reciept
+    dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 = SERV_UNIT_UNDEFINED};
+    dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_ID };
+    dap_chain_datum_tx_receipt_t *l_receipt = dap_chain_datum_tx_receipt_create(l_uid, l_unit, 0, a_stake->value, NULL, 0);
+    dap_chain_datum_tx_add_item(&l_tx, (byte_t *)l_receipt);
+    DAP_DELETE(l_receipt);
+
+    // add 'in' item to buy from conditional transaction
+    dap_chain_datum_tx_t *l_cond_tx = dap_chain_ledger_tx_find_by_hash(l_ledger, &a_stake->tx_hash);
+    if (!l_cond_tx) {
+        log_it(L_WARNING, "Requested conditional transaction not found");
+        return NULL;
+    }
+    int l_prev_cond_idx;
+    dap_chain_tx_out_cond_t *l_tx_out_cond = dap_chain_datum_tx_out_cond_get(l_cond_tx, &l_prev_cond_idx);
+    if (dap_chain_ledger_tx_hash_is_used_out_item(l_ledger, &a_stake->tx_hash, l_prev_cond_idx)) {
+        log_it(L_WARNING, "Requested conditional transaction is already used out");
+        return NULL;
+    }
+    assert(l_tx_out_cond->header.value == a_stake->value);
+    dap_chain_datum_tx_add_in_cond_item(&l_tx, &a_stake->tx_hash, l_prev_cond_idx, 0);
+
+    // add 'out_cond' item
+    {
+        dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_ID };
+        dap_chain_tx_out_cond_t *l_tx_out = dap_chain_datum_tx_item_out_cond_create_srv_stake(l_uid, a_stake->value, a_stake->fee_value,
+                                                                                              &a_stake->addr_fee, &a_stake->addr_hldr,
+                                                                                              (void *)&a_stake->signing_addr, sizeof(dap_chain_addr_t));
+        if (!l_tx_out) {
+            dap_chain_datum_tx_delete(l_tx);
+            log_it(L_ERROR, "Can't compose the transaction conditional output");
+            return NULL;
+        }
+        dap_chain_datum_tx_add_item(&l_tx, (const uint8_t *)l_tx_out);
+        DAP_DELETE(l_tx_out);
+    }
+
+    // add 'sign' items
+    if(dap_chain_datum_tx_add_sign_item(&l_tx, a_cert->enc_key) != 1) {
+        dap_chain_datum_tx_delete(l_tx);
+        log_it( L_ERROR, "Can't add sign output");
+        return NULL;
+    }
+    return l_tx;
+}
+
 static bool s_stake_tx_invalidate(dap_chain_net_srv_stake_item_t *a_stake, dap_chain_wallet_t *a_wallet)
 {
     // create empty transaction
@@ -339,15 +511,20 @@ static bool s_stake_tx_invalidate(dap_chain_net_srv_stake_item_t *a_stake, dap_c
 char *s_stake_order_create(dap_chain_net_srv_stake_item_t *a_item, dap_enc_key_t *l_key)
 {
     dap_chain_hash_fast_t l_tx_hash = {};
-    dap_srv_stake_order_ext_t l_ext;
-    memcpy(&l_ext.addr_from, &a_item->addr_from, sizeof(dap_chain_addr_t));
-    memcpy(&l_ext.addr_to, &a_item->addr_to, sizeof(dap_chain_addr_t));
+    dap_srv_stake_order_ext_t l_ext = {};
+    memcpy(&l_ext.addr_hldr, &a_item->addr_hldr, sizeof(dap_chain_addr_t));
+    dap_chain_net_srv_order_direction_t l_dir = SERV_DIR_SELL;
+    if (memcmp(&a_item->signing_addr, &l_ext.signing_addr, sizeof(dap_chain_addr_t))) {
+        // Signing addr is not empty
+        l_dir = SERV_DIR_BUY;
+        memcpy(&l_ext.signing_addr, &a_item->signing_addr, sizeof(dap_chain_addr_t));
+    }
     l_ext.fee_value = a_item->fee_value;
     uint32_t l_ext_size = sizeof(dap_srv_stake_order_ext_t);
     dap_chain_node_addr_t *l_node_addr = dap_chain_net_get_cur_addr(a_item->net);
     dap_chain_net_srv_price_unit_uid_t l_unit = { .uint32 =  SERV_UNIT_UNDEFINED};
     dap_chain_net_srv_uid_t l_uid = { .uint64 = DAP_CHAIN_NET_SRV_STAKE_ID };
-    char *l_order_hash_str = dap_chain_net_srv_order_create(a_item->net, SERV_DIR_BUY, l_uid, *l_node_addr,
+    char *l_order_hash_str = dap_chain_net_srv_order_create(a_item->net, l_dir, l_uid, *l_node_addr,
                                                             l_tx_hash, a_item->value, l_unit, a_item->token, 0,
                                                             (uint8_t *)&l_ext, l_ext_size, NULL, 0, l_key);
     return l_order_hash_str;
@@ -361,7 +538,7 @@ dap_chain_net_srv_stake_item_t *s_stake_item_from_order(dap_chain_net_t *a_net,
     }
     dap_srv_stake_order_ext_t *l_ext = (dap_srv_stake_order_ext_t *)a_order->ext;
     dap_sign_t *l_sign = (dap_sign_t *)(&a_order->ext[a_order->ext_size]);
-    if (!dap_sign_verify(l_sign, a_order, dap_chain_net_srv_order_get_size(a_order))) {
+    if (dap_sign_verify(l_sign, a_order, dap_chain_net_srv_order_get_size(a_order)) != 1) {
         log_it(L_WARNING, "Order sign is invalid");
         return NULL;
     }
@@ -370,12 +547,12 @@ dap_chain_net_srv_stake_item_t *s_stake_item_from_order(dap_chain_net_t *a_net,
     dap_chain_addr_t l_cert_addr;
     dap_chain_addr_fill(&l_cert_addr, l_sign->header.type, &l_pkey_hash, a_net->pub.id);
     dap_chain_net_srv_stake_item_t *l_item = DAP_NEW_Z(dap_chain_net_srv_stake_item_t);
-    if (memcmp(&l_cert_addr, &l_ext->addr_to, sizeof(dap_chain_addr_t))) {
-        log_it(L_WARNING, "Order sign addr & addr_to are different");
+    if (memcmp(&l_cert_addr, &l_ext->signing_addr, sizeof(dap_chain_addr_t))) {
+        log_it(L_WARNING, "Order sign addr & signing_addr are different");
         return NULL;
     }
-    memcpy(&l_item->addr_from, &l_ext->addr_from, sizeof(dap_chain_addr_t));
-    memcpy(&l_item->addr_to, &l_ext->addr_to, sizeof(dap_chain_addr_t));
+    memcpy(&l_item->addr_hldr, &l_ext->addr_hldr, sizeof(dap_chain_addr_t));
+    memcpy(&l_item->signing_addr, &l_ext->signing_addr, sizeof(dap_chain_addr_t));
     l_item->fee_value = l_ext->fee_value;
     l_item->net = a_net;
     l_item->value = a_order->price;
@@ -386,7 +563,7 @@ dap_chain_net_srv_stake_item_t *s_stake_item_from_order(dap_chain_net_t *a_net,
 static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, char **a_str_reply, const char *a_hash_out_type)
 {
     enum {
-        CMD_NONE, CMD_CREATE, CMD_REMOVE, CMD_LIST, CMD_UPDATE
+        CMD_NONE, CMD_CREATE, CMD_DECLARE, CMD_REMOVE, CMD_LIST, CMD_UPDATE
     };
     int l_cmd_num = CMD_NONE;
     if(dap_chain_node_cli_find_option_val(a_argv, a_arg_index, min(a_argc, a_arg_index + 1), "create", NULL)) {
@@ -405,7 +582,7 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha
     switch (l_cmd_num) {
         case CMD_CREATE: {
             const char *l_net_str = NULL, *l_token_str = NULL, *l_coins_str = NULL;
-            const char *l_addr_from_str = NULL, *l_cert_str = NULL, *l_fee_str = NULL;
+            const char *l_addr_hldr_str = NULL, *l_cert_str = NULL, *l_fee_str = NULL;
             dap_chain_net_t *l_net = NULL;
             dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
             if (!l_net_str) {
@@ -431,18 +608,18 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha
                 dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order create' required parameter -coins");
                 return -7;
             }
-            uint64_t l_value = strtoull(l_coins_str, NULL, 10);
+            uint64_t l_value = strtoull(l_coins_str, NULL, 10); // TODO add possibility to work with 256-bit format
             if (!l_value) {
                 dap_chain_node_cli_set_reply_text(a_str_reply, "Format -coins <unsigned long long>");
                 return -8;
             }
-            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-addr_from", &l_addr_from_str);
-            if (!l_addr_from_str) {
-                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order create' required parameter -addr_from");
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-addr_hldr", &l_addr_hldr_str);
+            if (!l_addr_hldr_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order create' required parameter -addr_hldr");
                 return -9;
             }
-            dap_chain_addr_t *l_addr_from = dap_chain_addr_from_str(l_addr_from_str);
-            if (!l_addr_from) {
+            dap_chain_addr_t *l_addr_hldr = dap_chain_addr_from_str(l_addr_hldr_str);
+            if (!l_addr_hldr) {
                 dap_chain_node_cli_set_reply_text(a_str_reply, "Wrong address format");
                 return -10;
             }
@@ -463,7 +640,7 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha
             }
             long double l_fee = strtold(l_fee_str, NULL);
             if (!l_fee) {
-                dap_chain_node_cli_set_reply_text(a_str_reply, "Format -fee_percent <long double> %");
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Format -fee_percent <long double>(%)");
                 return -12;
             }
             // Create the stake item
@@ -471,11 +648,11 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha
             l_stake->net = l_net;
             dap_stpcpy(l_stake->token, l_token_str);
             l_stake->value = l_value;
-            memcpy(&l_stake->addr_from, l_addr_from, sizeof(dap_chain_addr_t));
-            dap_chain_addr_t *l_addr_to = dap_cert_to_addr(l_cert, l_net->pub.id);
-            memcpy(&l_stake->addr_to, l_addr_to, sizeof(dap_chain_addr_t));
-            DAP_DELETE(l_addr_from);
-            DAP_DELETE(l_addr_to);
+            memcpy(&l_stake->addr_hldr, l_addr_hldr, sizeof(dap_chain_addr_t));
+            dap_chain_addr_t *l_signing_addr = dap_cert_to_addr(l_cert, l_net->pub.id);
+            memcpy(&l_stake->signing_addr, l_signing_addr, sizeof(dap_chain_addr_t));
+            DAP_DELETE(l_addr_hldr);
+            DAP_DELETE(l_signing_addr);
             l_stake->fee_value = l_fee;
             // Create the order & put it to GDB
             char *l_order_hash_str = s_stake_order_create(l_stake, l_cert->enc_key);
@@ -489,6 +666,85 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha
                 return -15;
             }
         } break;
+        case CMD_DECLARE: {
+            const char *l_net_str = NULL, *l_token_str = NULL, *l_coins_str = NULL;
+            const char *l_wallet_str = NULL, *l_fee_str = NULL;
+            dap_chain_net_t *l_net = NULL;
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
+            if (!l_net_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order declare' required parameter -net");
+                return -3;
+            }
+            l_net = dap_chain_net_by_name(l_net_str);
+            if (!l_net) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
+                return -4;
+            }
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-token", &l_token_str);
+            if (!l_token_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order declare' required parameter -token");
+                return -5;
+            }
+            if (!dap_chain_ledger_token_ticker_check(l_net->pub.ledger, l_token_str)) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Token ticker %s not found", l_token_str);
+                return -6;
+            }
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-coins", &l_coins_str);
+            if (!l_coins_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order declare' required parameter -coins");
+                return -7;
+            }
+            uint64_t l_value = strtoull(l_coins_str, NULL, 10); // TODO add possibility to work with 256-bit format
+            if (!l_value) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Format -coins <unsigned long long>");
+                return -8;
+            }
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-wallet", &l_wallet_str);
+            if (!l_wallet_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order declare' required parameter -wallet");
+                return -9;
+            }
+            dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config));
+            if (!l_wallet) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Specified wallet not found");
+                return -18;
+            }
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-fee_percent", &l_fee_str);
+            if (!l_fee_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order declare' required parameter -fee_percent");
+                return -11;
+            }
+            long double l_fee = strtold(l_fee_str, NULL);
+            if (!l_fee) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Format -fee_percent <long double>(%)");
+                return -12;
+            }
+            uint64_t l_balance = dap_chain_uint128_to(dap_chain_wallet_get_balance(l_wallet, l_net->pub.id, l_token_str));
+            if (l_balance < l_value) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Insufficient coins for token %s in wallet '%s'", l_token_str, l_wallet_str);
+                return -13;
+            }
+            // Create the stake item
+            dap_chain_net_srv_stake_item_t *l_stake = DAP_NEW_Z(dap_chain_net_srv_stake_item_t);
+            l_stake->net = l_net;
+            dap_stpcpy(l_stake->token, l_token_str);
+            l_stake->value = l_value;
+            dap_chain_addr_t *l_addr_hldr = dap_chain_wallet_get_addr(l_wallet, l_net->pub.id);
+            memcpy(&l_stake->addr_hldr, l_addr_hldr, sizeof(dap_chain_addr_t));
+            DAP_DELETE(l_addr_hldr);
+            l_stake->fee_value = l_fee;
+            // Create the order & put it to GDB
+            char *l_order_hash_str = s_stake_order_create(l_stake, dap_chain_wallet_get_key(l_wallet, 0));
+            if (l_order_hash_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_str);
+                DAP_DELETE(l_order_hash_str);
+                DAP_DELETE(l_stake);
+            } else {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Can't compose the order");
+                DAP_DELETE(l_stake);
+                return -15;
+            }
+        } break;
         case CMD_REMOVE: {
             const char *l_net_str = NULL, *l_order_hash_str = NULL;
             dap_chain_net_t *l_net = NULL;
@@ -531,9 +787,10 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha
         } break;
         case CMD_UPDATE: {
             const char *l_net_str = NULL, *l_token_str = NULL, *l_coins_str = NULL;
-            const char *l_addr_from_str = NULL, *l_cert_str = NULL, *l_fee_str = NULL;
-            char *l_order_hash_str = NULL;
+            const char *l_addr_hldr_str = NULL, *l_cert_str = NULL, *l_fee_str = NULL;
+            const char *l_order_hash_str = NULL, *l_wallet_str = NULL;
             dap_chain_net_t *l_net = NULL;
+            dap_enc_key_t *l_key = NULL;
             dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
             if (!l_net_str) {
                 dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order update' required parameter -net");
@@ -569,16 +826,6 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha
                     dap_chain_node_cli_set_reply_text(a_str_reply, "Can't find order %s\n", l_order_hash_base58_str);
                 return -14;
             }
-            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-wallet", &l_cert_str);
-            if (!l_cert_str) {
-                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order update' required parameter -cert");
-                return -9;
-            }
-            dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str);
-            if (!l_cert) {
-                dap_chain_node_cli_set_reply_text(a_str_reply, "Can't load cert %s", l_cert_str);
-                return -10;
-            }
             dap_chain_net_srv_stake_item_t *l_stake = s_stake_item_from_order(l_net, l_order);
             dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-token", &l_token_str);
             if (l_token_str) {
@@ -591,7 +838,7 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha
             }
             dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-coins", &l_coins_str);
             if (l_coins_str) {
-                uint64_t l_value = strtoull(l_coins_str, NULL, 10);
+                uint64_t l_value = strtoull(l_coins_str, NULL, 10); // TODO add possibility to work with 256-bit format
                 if (!l_value) {
                     dap_chain_node_cli_set_reply_text(a_str_reply, "Format -coins <unsigned long long>");
                     DAP_DELETE(l_stake);
@@ -608,19 +855,60 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha
                     return -12;
                 }
             }
-            if (!l_token_str && !l_coins_str && !l_addr_from_str && !l_fee_str) {
+            dap_chain_addr_t l_empty_addr = {};
+            if (memcmp(&l_stake->signing_addr, &l_empty_addr, sizeof(dap_chain_addr_t))) {
+                // It's a buying order
+                dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str);
+                if (!l_cert_str) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order update' requires parameter -cert for buying orders");
+                    return -9;
+                }
+                dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str);
+                if (!l_cert) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Can't load cert %s", l_cert_str);
+                    DAP_DELETE(l_stake);
+                    return -10;
+                }
+                l_key = l_cert->enc_key;
+                dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-addr_hldr", &l_addr_hldr_str);
+                if (l_addr_hldr_str) {
+                    dap_chain_addr_t *l_addr_hldr = dap_chain_addr_from_str(l_addr_hldr_str);
+                    if (!l_addr_hldr) {
+                        dap_chain_node_cli_set_reply_text(a_str_reply, "Wrong address format");
+                        DAP_DELETE(l_stake);
+                        return -14;
+                    }
+                    memcpy(&l_stake->addr_hldr, l_addr_hldr, sizeof(dap_chain_addr_t));
+                    DAP_DELETE(l_addr_hldr);
+                }
+            } else {    // It's a selling order
+                dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-wallet", &l_wallet_str);
+                if (!l_wallet_str) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'order update' requires parameter -wallet for selling orders");
+                    return -7;
+                }
+                dap_chain_wallet_t *l_wallet = dap_chain_wallet_open(l_wallet_str, dap_chain_wallet_get_path(g_config));
+                if (!l_wallet) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Specified wallet not found");
+                    return -18;
+                }
+                uint64_t l_balance = dap_chain_uint128_to(dap_chain_wallet_get_balance(l_wallet, l_net->pub.id, l_stake->token));
+                if (l_balance < l_stake->value) {
+                    dap_chain_node_cli_set_reply_text(a_str_reply, "Insufficient coins for token %s in wallet '%s'", l_token_str, l_wallet_str);
+                    return -11;
+                }
+                l_key = dap_chain_wallet_get_key(l_wallet, 0);
+            }
+            if (!l_token_str && !l_coins_str && !l_addr_hldr_str && !l_fee_str) {
                 dap_chain_node_cli_set_reply_text(a_str_reply, "At least one of updating parameters is mandatory");
                 DAP_DELETE(l_stake);
                 return -16;
             }
-            dap_chain_addr_t *l_addr_to = dap_cert_to_addr(l_cert, l_net->pub.id);
-            memcpy(&l_stake->addr_to, l_addr_to, sizeof(dap_chain_addr_t));
-            DAP_DELETE(l_addr_to);
             // Create the order & put it to GDB
             dap_chain_net_srv_order_delete_by_hash_str(l_net, l_order_hash_hex_str);
             DAP_DELETE(l_order_hash_hex_str);
             DAP_DELETE(l_order_hash_base58_str);
-            l_order_hash_hex_str = s_stake_order_create(l_stake, l_cert->enc_key);
+            l_order_hash_hex_str = s_stake_order_create(l_stake, l_key);
             if(l_order_hash_hex_str) {
                 if(!dap_strcmp(a_hash_out_type, "hex")) {
                     dap_chain_node_cli_set_reply_text(a_str_reply, "Successfully created order %s", l_order_hash_hex_str);
@@ -662,7 +950,7 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha
                     continue;
                 // TODO add filters to list (token, address, etc.)
                 l_stake = s_stake_item_from_order(l_net, l_order);
-                char *l_addr = dap_chain_addr_to_str(&l_stake->addr_to);
+                char *l_addr = dap_chain_addr_to_str(&l_stake->signing_addr);
                 dap_string_append_printf(l_reply_str, "%s %"DAP_UINT64_FORMAT_U" %s %s %Lf\n", l_orders[i].key, l_stake->value, l_stake->token,
                                          l_addr, l_stake->fee_value);
                 DAP_DELETE(l_addr);
@@ -686,19 +974,18 @@ static int s_cli_srv_stake_order(int a_argc, char **a_argv, int a_arg_index, cha
 static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
 {
     enum {
-        CMD_NONE, CMD_ORDER, CMD_DELEGATE, CMD_TX, CMD_INVALIDATE
+        CMD_NONE, CMD_ORDER, CMD_DELEGATE, CMD_APPROVE, CMD_TX, CMD_INVALIDATE
     };
     int l_arg_index = 1;
 
     const char * l_hash_out_type = NULL;
     dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "-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")) {
+        l_hash_out_type = "base58";
+    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;
     }
-
     int l_cmd_num = CMD_NONE;
     if (dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "order", NULL)) {
         l_cmd_num = CMD_ORDER;
@@ -706,6 +993,9 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
     else if (dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "delegate", NULL)) {
         l_cmd_num = CMD_DELEGATE;
     }
+    else if (dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "approve", NULL)) {
+        l_cmd_num = CMD_APPROVE;
+    }
     else if (dap_chain_node_cli_find_option_val(a_argv, l_arg_index, min(a_argc, l_arg_index + 1), "transactions", NULL)) {
         l_cmd_num = CMD_TX;
     }
@@ -764,15 +1054,16 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
                 }
                 memcpy(&l_stake->addr_fee, l_addr_fee, sizeof(dap_chain_addr_t));
                 DAP_DELETE(l_addr_fee);
+                dap_chain_addr_t *l_hldr_addr = dap_chain_wallet_get_addr(l_wallet, l_net->pub.id);
+                memcpy(&l_stake->addr_hldr, l_hldr_addr, sizeof(dap_chain_addr_t));
+                DAP_DELETE(l_hldr_addr);
                 // Create conditional transaction
                 dap_chain_datum_tx_t *l_tx = s_stake_tx_create(l_stake, l_wallet);
                 dap_chain_wallet_close(l_wallet);
-                if (l_tx) {
-                    dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_stake->tx_hash);
-                    if (s_stake_tx_put(l_tx, l_net)) {
-                        // TODO send request to order owner to delete it
-                        dap_chain_net_srv_order_delete_by_hash_str(l_net, l_order_hash_str);
-                    }
+                if (l_tx && s_stake_tx_put(l_tx, l_net)) {
+                    dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_stake->tx_hash);         
+                    // TODO send request to order owner to delete it
+                    dap_chain_net_srv_order_delete_by_hash_str(l_net, l_order_hash_str);
                 }
                 DAP_DELETE(l_order);
                 dap_chain_node_cli_set_reply_text(a_str_reply, l_tx ? "Stake transaction has done" :
@@ -781,13 +1072,65 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
                     DAP_DELETE(l_stake);
                     return -19;
                 }
-                HASH_ADD(hh, s_srv_stake->itemlist, addr_to, sizeof(dap_chain_addr_t), l_stake);
+                HASH_ADD(hh, s_srv_stake->itemlist, signing_addr, sizeof(dap_chain_addr_t), l_stake);
             } else {
                 DAP_DELETE(l_addr_fee);
                 dap_chain_node_cli_set_reply_text(a_str_reply, "Specified order not found");
                 return -14;
             }
         } break;
+        case CMD_APPROVE: {
+            const char *l_net_str = NULL, *l_tx_hash_str = NULL, *l_cert_str = NULL;
+            l_arg_index++;
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-net", &l_net_str);
+            if (!l_net_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'approve' required parameter -net");
+                return -3;
+            }
+            dap_chain_net_t *l_net = dap_chain_net_by_name(l_net_str);
+            if (!l_net) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Network %s not found", l_net_str);
+                return -4;
+            }
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-cert", &l_cert_str);
+            if (!l_cert_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'approve' required parameter -cert");
+                return -17;
+            }
+            dap_cert_t *l_cert = dap_cert_find_by_name(l_cert_str);
+            if (!l_cert) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Specified certificate not found");
+                return -18;
+            }
+            dap_chain_node_cli_find_option_val(a_argv, l_arg_index, a_argc, "-tx", &l_tx_hash_str);
+            if (!l_tx_hash_str) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Command 'delegate' required parameter -tx");
+                return -13;
+            }
+            dap_chain_hash_fast_t l_tx_hash = {};
+            int l_result = dap_chain_hash_fast_from_str(l_tx_hash_str, &l_tx_hash);
+            if (l_result)
+                l_result = dap_enc_base58_decode(l_tx_hash_str, &l_tx_hash) - sizeof(dap_chain_hash_fast_t);
+            if (l_result) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Invalid transaction hash format");
+                return -14;
+            }
+            dap_chain_net_srv_stake_item_t *l_stake = NULL, *l_tmp;
+            HASH_ITER(hh, s_srv_stake->itemlist, l_stake, l_tmp) {
+                if (!memcmp(&l_stake->tx_hash, &l_tx_hash, sizeof(dap_chain_hash_fast_t))) {
+                    break;
+                }
+            }
+            if (!l_stake) {
+                dap_chain_node_cli_set_reply_text(a_str_reply, "Transaction %s not found", l_tx_hash_str);
+                return -20;
+            }
+            dap_chain_datum_tx_t *l_tx = s_stake_tx_approve(l_stake, l_cert);
+            if (l_tx && s_stake_tx_put(l_tx, l_net)) {
+                dap_hash_fast(l_tx, dap_chain_datum_tx_get_size(l_tx), &l_stake->tx_hash);
+                l_stake->is_active = true;
+            }
+        } break;
         case CMD_TX: {
             const char *l_net_str = NULL;
             l_arg_index++;
@@ -808,15 +1151,15 @@ static int s_cli_srv_stake(int a_argc, char **a_argv, char **a_str_reply)
                     continue;
                 }
                 char *l_tx_hash_str = dap_chain_hash_fast_to_str_new(&l_stake->tx_hash);
-                char *l_addr_from_str = dap_chain_addr_to_str(&l_stake->addr_from);
-                char *l_addr_to_str = dap_chain_addr_to_str(&l_stake->addr_to);
+                char *l_addr_hldr_str = dap_chain_addr_to_str(&l_stake->addr_hldr);
+                char *l_signing_addr_str = dap_chain_addr_to_str(&l_stake->signing_addr);
                 char *l_addr_fee_str = dap_chain_addr_to_str(&l_stake->addr_fee);
                 dap_string_append_printf(l_reply_str, "%s %s %"DAP_UINT64_FORMAT_U" %s %s %s %Lf\n", l_tx_hash_str, l_stake->token,
-                                         l_stake->value, l_addr_from_str, l_addr_to_str,
+                                         l_stake->value, l_addr_hldr_str, l_signing_addr_str,
                                          l_addr_fee_str, l_stake->fee_value);
                 DAP_DELETE(l_tx_hash_str);
-                DAP_DELETE(l_addr_from_str);
-                DAP_DELETE(l_addr_to_str);
+                DAP_DELETE(l_addr_hldr_str);
+                DAP_DELETE(l_signing_addr_str);
                 DAP_DELETE(l_addr_fee_str);
             }
             if (!l_reply_str->len) {
diff --git a/modules/service/stake/include/dap_chain_net_srv_stake.h b/modules/service/stake/include/dap_chain_net_srv_stake.h
index 4a89391531b1a3fa7881344ba2ce6fc53f405750..c539cee32af31515178a85a6355857e404ee3e55 100644
--- a/modules/service/stake/include/dap_chain_net_srv_stake.h
+++ b/modules/service/stake/include/dap_chain_net_srv_stake.h
@@ -27,15 +27,16 @@
 #include "dap_chain_net_srv.h"
 #include "dap_chain_net_srv_order.h"
 
-#define DAP_CHAIN_NET_SRV_STAKE_ID 0x3
+#define DAP_CHAIN_NET_SRV_STAKE_ID 0x13
 
 typedef struct dap_chain_net_srv_stake_item {
+    bool is_active;
     dap_chain_net_t *net;
     char token[DAP_CHAIN_TICKER_SIZE_MAX];
     uint64_t value;
-    dap_chain_addr_t addr_from;
-    dap_chain_addr_t addr_to;
+    dap_chain_addr_t addr_hldr;
     dap_chain_addr_t addr_fee;
+    dap_chain_addr_t signing_addr;
     long double fee_value;
     dap_chain_hash_fast_t tx_hash;
     dap_chain_hash_fast_t order_hash;
@@ -43,8 +44,8 @@ typedef struct dap_chain_net_srv_stake_item {
 } dap_chain_net_srv_stake_item_t;
 
 typedef struct dap_srv_stake_order_ext {
-    dap_chain_addr_t addr_from;
-    dap_chain_addr_t addr_to;
+    dap_chain_addr_t addr_hldr;
+    dap_chain_addr_t signing_addr;
     long double fee_value;
 } dap_srv_stake_order_ext_t;
 
@@ -55,6 +56,7 @@ typedef struct dap_chain_net_srv_stake {
 
 int dap_chain_net_srv_stake_init();
 void dap_chain_net_srv_stake_deinit();
-bool dap_chain_net_srv_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx);
-bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum_tx_t *a_tx);
+bool dap_chain_net_srv_stake_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner);
+bool dap_chain_net_srv_stake_updater(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner);
+bool dap_chain_net_srv_stake_validator(dap_chain_addr_t *a_addr, dap_chain_datum_t *a_datum);
 bool dap_chain_net_srv_stake_key_delegated(dap_chain_addr_t *a_addr);
diff --git a/modules/service/vpn/CMakeLists.txt b/modules/service/vpn/CMakeLists.txt
index 30e2258599f8a27aaac447963f2206034dbe6b67..973d4f0de12a4991ab6db17daf20989ce80582a5 100644
--- a/modules/service/vpn/CMakeLists.txt
+++ b/modules/service/vpn/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_net_srv_vpn)
   
 file(GLOB DAP_CHAIN_NET_SRV_VPN_SRCS *.c)
diff --git a/modules/service/xchange/CMakeLists.txt b/modules/service/xchange/CMakeLists.txt
index 82d036e96bc5d37317cd91cb7ad5d5df4bc53515..f49fe6685e97440152c354a54d9b50621ffaacd9 100644
--- a/modules/service/xchange/CMakeLists.txt
+++ b/modules/service/xchange/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_net_srv_xchange)
   
 file(GLOB DAP_SRV_XCHANGE_SRCS *.c)
diff --git a/modules/service/xchange/dap_chain_net_srv_xchange.c b/modules/service/xchange/dap_chain_net_srv_xchange.c
index d36662f7279e17bc15040a9c3c2d7862ea42a898..df904b6701f4432326172ca942dc695649498fbf 100644
--- a/modules/service/xchange/dap_chain_net_srv_xchange.c
+++ b/modules/service/xchange/dap_chain_net_srv_xchange.c
@@ -101,8 +101,10 @@ void dap_chain_net_srv_xchange_deinit()
     DAP_DELETE(s_srv_xchange);
 }
 
-bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx)
+bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner)
 {
+    if (a_owner)
+        return true;
     /* Check the condition for verification success
      * a_cond.srv_xchange.rate >= a_tx.out.rate
      */
diff --git a/modules/service/xchange/include/dap_chain_net_srv_xchange.h b/modules/service/xchange/include/dap_chain_net_srv_xchange.h
index f59791fea9c51326e5026278a59de60c0de0078a..0e098f7c67445ac7dfcca10a0ef964fc24feb3e8 100644
--- a/modules/service/xchange/include/dap_chain_net_srv_xchange.h
+++ b/modules/service/xchange/include/dap_chain_net_srv_xchange.h
@@ -71,4 +71,4 @@ typedef struct dap_chain_net_srv_xchange {
 
 int dap_chain_net_srv_xchange_init();
 void dap_chain_net_srv_xchange_deinit();
-bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx);
+bool dap_chain_net_srv_xchange_verificator(dap_chain_tx_out_cond_t *a_cond, dap_chain_datum_tx_t *a_tx, bool a_owner);
diff --git a/modules/test/CMakeLists.txt b/modules/test/CMakeLists.txt
index 70e543e45b934bcc5d43a765db96d620a4af9280..e2174176bd4e2f44a3c87fc1a91771cb82324308 100644
--- a/modules/test/CMakeLists.txt
+++ b/modules/test/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 if(TARGET dap_test)
     return() # The project has already been built.
 endif()
diff --git a/modules/type/blocks/CMakeLists.txt b/modules/type/blocks/CMakeLists.txt
index 44f0787add4f670f935894cffad47fbe58c4a33b..015c96c1fdf9b7283dc6518070fbf3bf773b83cd 100644
--- a/modules/type/blocks/CMakeLists.txt
+++ b/modules/type/blocks/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_cs_blocks)
   
 file(GLOB DAP_CHAIN_BLOCK_SRCS *.c)
diff --git a/modules/type/blocks/dap_chain_block.c b/modules/type/blocks/dap_chain_block.c
index e9a6836f5f1f3b59eab751fe1a38c93505be62e4..cd45d3bf89248d2d0d6564934a813a668b4dfcd9 100644
--- a/modules/type/blocks/dap_chain_block.c
+++ b/modules/type/blocks/dap_chain_block.c
@@ -22,10 +22,10 @@
 */
 #include <stddef.h>
 #include "string.h"
+#include "dap_chain_net.h"
 #include "dap_common.h"
 #include "dap_config.h"
 #include "dap_hash.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..7d2b74322d88836c07dda4166053f20fb7b8a80b 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");
 }
 
@@ -620,8 +623,7 @@ static int  s_add_atom_to_ledger(dap_chain_cs_blocks_t * a_blocks, dap_ledger_t
                 l_ret=dap_chain_ledger_token_load(a_ledger, l_token, l_datum->header.data_size);
             } break;
             case DAP_CHAIN_DATUM_TOKEN_EMISSION: {
-                dap_chain_datum_token_emission_t *l_token_emission = (dap_chain_datum_token_emission_t*) l_datum->data;
-                l_ret=dap_chain_ledger_token_emission_load(a_ledger, l_token_emission, l_datum->header.data_size);
+                l_ret=dap_chain_ledger_token_emission_load(a_ledger, l_datum->data, l_datum->header.data_size);
             } break;
             case DAP_CHAIN_DATUM_TX: {
                 dap_chain_datum_tx_t *l_tx = (dap_chain_datum_tx_t*) l_datum->data;
@@ -676,9 +678,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 +686,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 +780,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 +792,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 +853,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 +870,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 +922,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 +969,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 +1058,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 +1107,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 +1143,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/CMakeLists.txt b/modules/type/dag/CMakeLists.txt
index 7ba78b85c68258118ad2b67a6b64c8ff1052c7be..45b720ff72332ed2712453e456368f695ba9fab7 100644
--- a/modules/type/dag/CMakeLists.txt
+++ b/modules/type/dag/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_cs_dag)
   
 file(GLOB DAP_CHAIN_DAG_SRCS *.c)
diff --git a/modules/type/dag/dap_chain_cs_dag.c b/modules/type/dag/dap_chain_cs_dag.c
index 3a886ba409ca05409cfb563a0bf43e7053adc9bf..29cfaf91f737c9fbf1142e3a13e291a033065f71 100644
--- a/modules/type/dag/dap_chain_cs_dag.c
+++ b/modules/type/dag/dap_chain_cs_dag.c
@@ -304,8 +304,7 @@ static int s_dap_chain_add_atom_to_ledger(dap_chain_cs_dag_t * a_dag, dap_ledger
         }
         break;
         case DAP_CHAIN_DATUM_TOKEN_EMISSION: {
-            dap_chain_datum_token_emission_t *l_token_emission = (dap_chain_datum_token_emission_t*) l_datum->data;
-            return dap_chain_ledger_token_emission_load(a_ledger, l_token_emission, l_datum->header.data_size);
+            return dap_chain_ledger_token_emission_load(a_ledger, l_datum->data, l_datum->header.data_size);
         }
         break;
         case DAP_CHAIN_DATUM_TX: {
@@ -327,6 +326,11 @@ static int s_dap_chain_add_atom_to_ledger(dap_chain_cs_dag_t * a_dag, dap_ledger
             }
         }
         break;
+        case DAP_CHAIN_DATUM_CA: {
+            dap_cert_chain_file_save(l_datum, a_dag->chain->net_name);
+            return DAP_CHAIN_DATUM_CA;
+        }
+        break;
         default:
             return -1;
     }
@@ -393,7 +397,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) {
@@ -434,6 +439,11 @@ static dap_chain_atom_verify_res_t s_chain_callback_atom_add(dap_chain_t * a_cha
                 log_it(L_DEBUG, "... tresholded");
             ret = ATOM_MOVE_TO_THRESHOLD;
             break;
+        case DAP_CHAIN_DATUM_CA:
+            ret = ATOM_ACCEPT;
+            if(s_debug_more)
+                log_it(L_DEBUG, "... DATUM_CA");
+            break;
         default:
             if (s_debug_more) {
                 l_event_hash_str = dap_chain_hash_fast_to_str_new(&l_event_item->hash);
@@ -513,7 +523,10 @@ static size_t s_chain_callback_datums_pool_proc(dap_chain_t * a_chain, dap_chain
         // Verify for correctness
         dap_chain_net_t * l_net = dap_chain_net_by_id( a_chain->net_id);
         int l_verify_datum= dap_chain_net_verify_datum_for_add( l_net, l_datum) ;
-        if (l_verify_datum != 0){
+        if (l_verify_datum != 0 &&
+                l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_PREVIOUS &&
+                l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_EMISSION &&
+                l_verify_datum != DAP_CHAIN_CS_VERIFY_CODE_TX_NO_TOKEN){
             log_it(L_WARNING, "Datum doesn't pass verifications (code %d)",
                                      l_verify_datum);
             continue;
@@ -904,13 +917,11 @@ dap_chain_cs_dag_event_item_t* dap_chain_cs_dag_proc_treshold(dap_chain_cs_dag_t
             HASH_DEL(PVT(a_dag)->events_treshold,l_event_item);
 
             if(ret == DAP_THRESHOLD_OK){
-
                 if(s_debug_more) {
                     char * l_event_hash_str = dap_chain_hash_fast_to_str_new(&l_event_item->hash);
                     log_it(L_DEBUG, "Processing event (threshold): %s...", l_event_hash_str);
                     DAP_DELETE(l_event_hash_str);
-                }
-                int l_add_res = s_dap_chain_add_atom_to_events_table(a_dag, a_ledger, l_event_item);
+                }                int l_add_res = s_dap_chain_add_atom_to_events_table(a_dag, a_ledger, l_event_item);
                 HASH_ADD(hh, PVT(a_dag)->events,hash,sizeof (l_event_item->hash), l_event_item);
                 s_dag_events_lasts_process_new_last_event(a_dag, l_event_item);
                 if(! l_add_res){
diff --git a/modules/wallet/CMakeLists.txt b/modules/wallet/CMakeLists.txt
index 65e9b46203484dadf47906ee5895639539a9d70f..1dccfa998ed23f4c50facdf7b58d9903b6677852 100644
--- a/modules/wallet/CMakeLists.txt
+++ b/modules/wallet/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.10)
 project (dap_chain_wallet)
   
 file(GLOB DAP_CHAIN_WALLET_SRCS *.c)