From e919b5e36fd4a5656369af29ed95f41a303ca054 Mon Sep 17 00:00:00 2001
From: "roman.khlopkov" <roman.khlopkov@demlabs.net>
Date: Wed, 29 Nov 2023 20:05:20 +0300
Subject: [PATCH] [+] Reward history by block num

---
 modules/chain/include/dap_chain.h             |   2 +-
 modules/net/dap_chain_net.c                   |  39 +-
 modules/net/dap_chain_net_decree.c            |  28 +-
 modules/net/include/dap_chain_net.h           |   6 +-
 modules/type/blocks/dap_chain_block.c         | 496 ++++++++++--------
 modules/type/blocks/dap_chain_block_cache.c   |  24 +-
 modules/type/blocks/dap_chain_block_chunk.c   |   2 +-
 modules/type/blocks/dap_chain_cs_blocks.c     | 187 ++++---
 modules/type/blocks/include/dap_chain_block.h |  27 +-
 .../blocks/include/dap_chain_block_cache.h    |   9 +-
 .../type/blocks/include/dap_chain_cs_blocks.h |   2 +
 11 files changed, 442 insertions(+), 380 deletions(-)

diff --git a/modules/chain/include/dap_chain.h b/modules/chain/include/dap_chain.h
index 6912588c49..d868605fef 100644
--- a/modules/chain/include/dap_chain.h
+++ b/modules/chain/include/dap_chain.h
@@ -111,7 +111,7 @@ typedef void (*dap_chain_callback_atom_iter_delete_t)(dap_chain_atom_iter_t *);
 
 typedef void (*dap_chain_callback_notify_t)(void *a_arg, dap_chain_t *a_chain, dap_chain_cell_id_t a_id, void *a_atom, size_t a_atom_size); //change in chain happened
 
-typedef size_t(*dap_chain_callback_get_count)(dap_chain_t *a_chain);
+typedef uint64_t (*dap_chain_callback_get_count)(dap_chain_t *a_chain);
 typedef dap_list_t *(*dap_chain_callback_get_list)(dap_chain_t *a_chain, size_t a_count, size_t a_page, bool a_reverse);
 typedef dap_list_t *(*dap_chain_callback_get_poa_certs)(dap_chain_t *a_chain, size_t *a_auth_certs_count, uint16_t *count_verify);
 typedef void (*dap_chain_callback_set_min_validators_count)(dap_chain_t *a_chain,  uint16_t a_new_value);
diff --git a/modules/net/dap_chain_net.c b/modules/net/dap_chain_net.c
index 801bdf39de..ebeddd4c23 100644
--- a/modules/net/dap_chain_net.c
+++ b/modules/net/dap_chain_net.c
@@ -145,6 +145,12 @@ struct net_link {
     UT_hash_handle hh;
 };
 
+struct block_reward {
+    uint64_t block_number;
+    uint256_t reward;
+    struct block_reward *prev, *next;
+};
+
 /**
   * @struct dap_chain_net_pvt
   * @details Private part of chain_net dap object
@@ -188,6 +194,9 @@ typedef struct dap_chain_net_pvt{
     dap_global_db_cluster_t *mempool_clusters; // List of chains mempools
     dap_global_db_cluster_t *orders_cluster;
     dap_global_db_cluster_t *nodes_cluster;
+
+    // Block sign rewards history
+    struct block_reward *rewards;
 } dap_chain_net_pvt_t;
 
 typedef struct dap_chain_net_item{
@@ -2088,7 +2097,6 @@ int s_net_init(const char * a_net_name, uint16_t a_acl_idx)
     dap_chain_net_pvt_t *l_net_pvt = PVT(l_net);
     l_net_pvt->load_mode = true;
     l_net_pvt->acl_idx = a_acl_idx;
-
     // Bridged netwoks allowed to send transactions to
     uint16_t l_net_ids_count = 0;
     char **l_bridged_net_ids = dap_config_get_array_str(l_cfg, "general", "bridged_network_ids", &l_net_ids_count);
@@ -3202,6 +3210,35 @@ bool dap_chain_net_get_load_mode(dap_chain_net_t * a_net)
     return PVT(a_net)->load_mode;
 }
 
+int dap_chain_net_add_reward(dap_chain_net_t *a_net, uint256_t a_reward, uint64_t a_block_num)
+{
+    dap_return_val_if_fail(a_net, -1);
+    if (PVT(a_net)->rewards && PVT(a_net)->rewards->block_number >= a_block_num) {
+        log_it(L_ERROR, "Can't add retrospective reward for block");
+        return -2;
+    }
+    struct block_reward *l_new_reward = DAP_NEW_Z(struct block_reward);
+    if (!l_new_reward) {
+        log_it(L_CRITICAL, "Out of memory");
+        return -3;
+    }
+    l_new_reward->block_number = a_block_num;
+    l_new_reward->reward = a_reward;
+    // Place new reward at begining
+    DL_PREPEND(PVT(a_net)->rewards, l_new_reward);
+    return 0;
+}
+
+uint256_t dap_chain_net_get_reward(dap_chain_net_t *a_net, uint64_t a_block_num)
+{
+    struct block_reward *l_reward;
+    DL_FOREACH(PVT(a_net)->rewards, l_reward) {
+        if (l_reward->block_number <= a_block_num)
+            return l_reward->reward;
+    }
+    return uint256_0;
+}
+
 void dap_chain_net_announce_addrs() {
     if(!HASH_COUNT(s_net_items)){
         log_it(L_ERROR, "Can't find any nets");
diff --git a/modules/net/dap_chain_net_decree.c b/modules/net/dap_chain_net_decree.c
index e2ba495305..37ad25a48a 100644
--- a/modules/net/dap_chain_net_decree.c
+++ b/modules/net/dap_chain_net_decree.c
@@ -53,8 +53,8 @@ static struct decree_hh {
 
 // Private fuctions prototype
 static bool s_verify_pkey (dap_sign_t *a_sign, dap_chain_net_t *a_net);
-static int s_common_decree_handler(dap_chain_datum_decree_t * a_decree, dap_chain_net_t *a_net, dap_chain_t *a_chain, bool a_apply);
-static int s_service_decree_handler(dap_chain_datum_decree_t * a_decree, dap_chain_t *a_chain, bool a_apply);
+static int s_common_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain_t *a_chain, bool a_apply);
+static int s_service_decree_handler(dap_chain_datum_decree_t *a_decree, dap_chain_t *a_chain, bool a_apply);
 
 
 // Public functions
@@ -86,10 +86,8 @@ int dap_chain_net_decree_init(dap_chain_net_t *a_net)
 
     dap_chain_net_decree_t *l_decree = NULL;
     l_decree = DAP_NEW_Z(dap_chain_net_decree_t);
-
-    if (!l_decree)
-    {
-        log_it(L_WARNING,"Out of memory.");
+    if (!l_decree) {
+        log_it(L_CRITICAL, "Out of memory");
         return -2;
     }
 
@@ -100,7 +98,7 @@ int dap_chain_net_decree_init(dap_chain_net_t *a_net)
     a_net->pub.decree = l_decree;
 
     // Preset reward for block signs, before first reward decree
-    l_net->pub.base_reward = dap_chain_balance_scan("2851988815387151461");
+    dap_chain_net_add_reward(a_net, dap_chain_balance_scan("2851988815387151461"), 0);
 
     return 0;
 }
@@ -138,7 +136,7 @@ int s_decree_verify_tsd(dap_chain_datum_decree_t * a_decree, dap_chain_net_t *a_
     // Process decree
     switch(a_decree->header.type){
         case DAP_CHAIN_DATUM_DECREE_TYPE_COMMON:{
-            ret_val = s_common_decree_handler(a_decree, a_net, NULL, false);
+            ret_val = s_common_decree_handler(a_decree, a_net->pub.chains, false);
             break;
         }
         case DAP_CHAIN_DATUM_DECREE_TYPE_SERVICE:{
@@ -292,7 +290,7 @@ int dap_chain_net_decree_apply(dap_hash_fast_t *a_decree_hash, dap_chain_datum_d
     // Process decree
     switch(l_decree_hh->decree->header.type) {
     case DAP_CHAIN_DATUM_DECREE_TYPE_COMMON:
-        ret_val = s_common_decree_handler(l_decree_hh->decree, l_net, a_chain, true);
+        ret_val = s_common_decree_handler(l_decree_hh->decree, a_chain, true);
         break;
     case DAP_CHAIN_DATUM_DECREE_TYPE_SERVICE:
         ret_val = s_service_decree_handler(l_decree_hh->decree, a_chain, true);
@@ -358,14 +356,14 @@ static bool s_verify_pkey (dap_sign_t *a_sign, dap_chain_net_t *a_net)
     return false;
 }
 
-static int s_common_decree_handler(dap_chain_datum_decree_t * a_decree, dap_chain_net_t *a_net, dap_chain_t *a_chain, bool a_apply)
+static int s_common_decree_handler(dap_chain_datum_decree_t * a_decree, dap_chain_t *a_chain, bool a_apply)
 {
     uint256_t l_uint256_buffer;
     uint16_t l_uint16_buffer;
     dap_chain_addr_t l_addr = {}; //????????
     dap_hash_fast_t l_hash = {};
     dap_chain_node_addr_t l_node_addr = {};
-    dap_chain_net_t *l_net = a_net;
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
     dap_list_t *l_owners_list = NULL;
 
     if (a_apply && !a_chain){
@@ -465,9 +463,8 @@ static int s_common_decree_handler(dap_chain_datum_decree_t * a_decree, dap_chai
                 log_it(L_WARNING,"Can't get min stake value from decree.");
                 return -105;
             }
-            dap_chain_t *l_chain = a_chain;
-            if (!a_chain)
-                l_chain = dap_chain_find_by_id(a_net->pub.id, a_decree->header.common_decree_params.chain_id);
+            dap_chain_t *l_chain = a_chain ? a_chain
+                                           : dap_chain_find_by_id(l_net->pub.id, a_decree->header.common_decree_params.chain_id);
             if (!l_chain) {
                 log_it(L_WARNING, "Specified chain not found");
                 return -106;
@@ -548,7 +545,8 @@ static int s_common_decree_handler(dap_chain_datum_decree_t * a_decree, dap_chai
             }
             if (!a_apply)
                 break;
-            a_net->pub.base_reward = l_uint256_buffer;
+            uint64_t l_cur_block_num = a_chain->callback_count_atom(a_chain);
+            dap_chain_net_add_reward(l_net, l_uint256_buffer, l_cur_block_num);
         } break;
         default:
             return -1;
diff --git a/modules/net/include/dap_chain_net.h b/modules/net/include/dap_chain_net.h
index b82409b423..719c635e49 100644
--- a/modules/net/include/dap_chain_net.h
+++ b/modules/net/include/dap_chain_net.h
@@ -81,8 +81,6 @@ typedef struct dap_chain_net{
         // Net fee
         uint256_t fee_value;
         dap_chain_addr_t fee_addr;
-        // Block sign reward
-        uint256_t base_reward;
 
         pthread_mutex_t balancer_mutex;
         dap_list_t *link_list;
@@ -158,10 +156,14 @@ dap_list_t* dap_chain_net_get_node_list(dap_chain_net_t * a_net);
 dap_list_t* dap_chain_net_get_node_list_cfg(dap_chain_net_t * a_net);
 dap_chain_node_role_t dap_chain_net_get_role(dap_chain_net_t * a_net);
 dap_chain_node_info_t *dap_chain_net_balancer_link_from_cfg(dap_chain_net_t *a_net);
+
 int dap_chain_net_add_poa_certs_to_cluster(dap_chain_net_t *a_net, dap_global_db_cluster_t *a_cluster);
 bool dap_chain_net_add_validator_to_clusters(dap_chain_t *a_chain, dap_stream_node_addr_t *a_addr);
 dap_global_db_cluster_t *dap_chain_net_get_mempool_cluster(dap_chain_t *a_chain);
 
+int dap_chain_net_add_reward(dap_chain_net_t *a_net, uint256_t a_reward, uint64_t a_block_num);
+uint256_t dap_chain_net_get_reward(dap_chain_net_t *a_net, uint64_t a_block_num);
+
 /**
  * @brief dap_chain_net_get_gdb_group_mempool
  * @param l_chain
diff --git a/modules/type/blocks/dap_chain_block.c b/modules/type/blocks/dap_chain_block.c
index 2b64edb253..ecd8665b90 100644
--- a/modules/type/blocks/dap_chain_block.c
+++ b/modules/type/blocks/dap_chain_block.c
@@ -25,6 +25,7 @@
 #include "dap_common.h"
 #include "dap_config.h"
 #include "dap_hash.h"
+#include "dap_uuid.h"
 #include "dap_chain_block.h"
 #include "dap_chain_block_cache.h"
 
@@ -55,34 +56,44 @@ void dap_chain_block_deinit()
 /**
  * @brief dap_chain_block_new
  * @param a_prev_block
+ * @param a_blockreward
+ * @param a_block_size
  * @return
  */
 dap_chain_block_t *dap_chain_block_new(dap_chain_hash_fast_t *a_prev_block, size_t *a_block_size)
 {
-    // Type sizeof's misunderstanding in malloc?
-    dap_chain_block_t * l_block = DAP_NEW_Z_SIZE (dap_chain_block_t,sizeof(l_block->hdr));
-    if( l_block == NULL){
+    dap_chain_block_t *l_block = DAP_NEW_Z(dap_chain_block_t);
+    if (!l_block) {
         log_it(L_CRITICAL, "Can't allocate memory for the new block");
         return NULL;
-    }else{
-        l_block->hdr.signature = DAP_CHAIN_BLOCK_SIGNATURE;
-        l_block->hdr.version = 1;
-        l_block->hdr.ts_created = time(NULL);
-
-        l_block->hdr.merkle = (dap_chain_hash_fast_t){ 0 };
-
-        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));
-        }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;
     }
+    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);
+    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));
+    } 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 (l_block_size) {
+        uint64_t l_nonce = dap_uuid_generate_uint64();
+        l_block_size = dap_chain_block_meta_add(&l_block, l_block_size, DAP_CHAIN_BLOCK_META_NONCE,
+                                                &l_nonce, sizeof(uint64_t));
+    }
+    /*if (l_block_size && a_block_reward)
+        l_block_size = dap_chain_block_meta_add(&l_block, l_block_size, DAP_CHAIN_BLOCK_META_REWARD,
+                                               a_block_reward, sizeof(uint256_t));*/
+    if (!l_block_size) {
+        log_it(L_ERROR, "Can't add meta to block");
+        DAP_DEL_Z(l_block);
+    }
+    if (a_block_size)
+        *a_block_size = l_block_size;
+    return l_block;
 }
 
 /**
@@ -113,53 +124,6 @@ size_t s_block_get_datum_offset(const dap_chain_block_t *a_block, size_t a_block
     return l_offset;
 }
 
-//
-/**
- * @brief dap_chain_block_meta_add
- * @details Add metadata in block
- * @param a_block_ptr
- * @param a_block_size
- * @param a_meta_type
- * @param a_data
- * @param a_data_size
- * @return
- */
-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)
-{
-    assert(a_block_ptr);
-    dap_chain_block_t * l_block = *a_block_ptr;
-    dap_chain_block_meta_t * l_meta = NULL;
-    if( a_block_size < sizeof(l_block->hdr) ){
-        log_it(L_ERROR,"Meta add: Corrupted block size %zd thats smaller then block header size %zd ", a_block_size, sizeof (l_block->hdr));
-        return 0;
-    }
-    if(l_block->hdr.meta_count == UINT16_MAX){
-        log_it(L_ERROR,"Meta add: Can't add more, maximum meta count %hu is achieved", UINT16_MAX);
-        return 0;
-    }
-    if( UINT32_MAX - l_block->hdr.meta_n_datum_n_signs_size < a_data_size + sizeof (l_meta->hdr) ){
-        log_it(L_ERROR,"Meta add: Can't add more, maximum block data section size %u achieved", UINT32_MAX);
-        return 0;
-    }
-
-    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);
-    }
-    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;
-}
-
 /**
  * @brief dap_chain_block_datum_add
  * @param a_block_ptr
@@ -202,6 +166,10 @@ size_t dap_chain_block_datum_add(dap_chain_block_t ** a_block_ptr, size_t a_bloc
     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, sizeof(l_block->hdr) + l_offset + a_datum_size);
+        if (!l_block) {
+            log_it(L_CRITICAL, "Memory reallocation error");
+            return 0;
+        }
         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++;
@@ -333,6 +301,10 @@ size_t dap_chain_block_sign_add(dap_chain_block_t **a_block_ptr, size_t a_block_
     if (!l_block_sign_size)
         return 0;
     *a_block_ptr = l_block = DAP_REALLOC(l_block, l_block_sign_size + a_block_size);
+    if (!l_block) {
+        log_it(L_CRITICAL, "Memory reallocation error");
+        return 0;
+    }
     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;
@@ -393,13 +365,12 @@ size_t dap_chain_block_get_signs_count(const dap_chain_block_t * a_block, size_t
 bool dap_chain_block_sign_match_pkey(const dap_chain_block_t *a_block, size_t a_block_size, dap_pkey_t *a_sign_pkey)
 {
     dap_return_val_if_fail(a_block && a_block_size, false);
-    uint16_t l_sign_count = 0;
     size_t l_offset = dap_chain_block_get_sign_offset(a_block, a_block_size);
     while (l_offset + sizeof(a_block->hdr) < a_block_size) {
         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);
+            log_it(L_WARNING, "Empty or corrupted sign");
             return false;
         }
         if (dap_pkey_match_sign(a_sign_pkey, l_sign))
@@ -430,8 +401,11 @@ dap_chain_datum_t** dap_chain_block_get_datums(const dap_chain_block_t *a_block,
         return NULL;
     size_t l_offset = s_block_get_datum_offset(a_block,a_block_size);
     dap_chain_datum_t * l_datum =(dap_chain_datum_t *) (a_block->meta_n_datum_n_sign + l_offset);
-    dap_chain_datum_t ** l_ret =DAP_NEW_Z_SIZE( dap_chain_datum_t *, sizeof (dap_chain_datum_t *)* a_block->hdr.datum_count);
-
+    dap_chain_datum_t **l_ret = DAP_NEW_Z_SIZE(dap_chain_datum_t *, sizeof(dap_chain_datum_t *) * a_block->hdr.datum_count);
+    if (!l_ret) {
+        log_it(L_CRITICAL, "Memory allocation error");
+        return NULL;
+    }
     for(size_t n=0; n<a_block->hdr.datum_count && l_offset<(a_block_size-sizeof (a_block->hdr)) ; n++){
         size_t l_datum_size = dap_chain_datum_size(l_datum);
 
@@ -461,48 +435,106 @@ dap_chain_datum_t** dap_chain_block_get_datums(const dap_chain_block_t *a_block,
 }
 
 /**
- * @brief dap_chain_block_get_meta
- * @param a_block
+ * @brief dap_chain_block_meta_add
+ * @details Add metadata in block
+ * @param a_block_ptr
  * @param a_block_size
- * @param a_meta_count
+ * @param a_meta_type
+ * @param a_data
+ * @param a_data_size
  * @return
  */
-dap_chain_block_meta_t** dap_chain_block_get_meta(const dap_chain_block_t * a_block, size_t a_block_size,size_t * a_meta_count )
+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)
 {
-    if (a_meta_count)
-        *a_meta_count = 0;
-    if( 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));
-        return NULL;
+    assert(a_block_ptr);
+    dap_chain_block_t * l_block = *a_block_ptr;
+    dap_chain_block_meta_t * l_meta = NULL;
+    if( a_block_size < sizeof(l_block->hdr) ){
+        log_it(L_ERROR,"Meta add: Corrupted block size %zd thats smaller then block header size %zd ", a_block_size, sizeof (l_block->hdr));
+        return 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;
-    dap_chain_block_meta_t ** l_ret = DAP_NEW_Z_SIZE(dap_chain_block_meta_t *,sizeof (dap_chain_block_meta_t *)* a_block->hdr.meta_count );
-    if (!l_ret) {
-        log_it(L_CRITICAL, "Memory allocation error");
-        return NULL;
+    if(l_block->hdr.meta_count == UINT16_MAX){
+        log_it(L_ERROR,"Meta add: Can't add more, maximum meta count %hu is achieved", UINT16_MAX);
+        return 0;
     }
-    for( size_t i = 0; i< a_block->hdr.meta_count &&
-                       l_offset < (a_block_size-sizeof (a_block->hdr)) &&
-                       sizeof (l_meta->hdr) <=  (a_block_size-sizeof (a_block->hdr)) - l_offset ; i++){
-        l_meta =(dap_chain_block_meta_t *) (a_block->meta_n_datum_n_sign +l_offset);
-        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;
-            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;
-        }
+    if( UINT32_MAX - l_block->hdr.meta_n_datum_n_signs_size < a_data_size + sizeof (l_meta->hdr) ){
+        log_it(L_ERROR,"Meta add: Can't add more, maximum block data section size %u achieved", UINT32_MAX);
+        return 0;
     }
-    return l_ret;
+
+    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);
+    if (!l_block) {
+        log_it(L_CRITICAL, "Memory reallocation error");
+        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;
+        memmove(l_meta_end + l_add_size, l_meta_end, l_datum_n_sign_copy_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;
+    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;
+}
+
+static uint8_t *s_meta_extract(dap_chain_block_meta_t *a_meta)
+{
+    switch (a_meta->hdr.type) {
+    case DAP_CHAIN_BLOCK_META_GENESIS:
+        if (a_meta->hdr.data_size == 0)
+            return DAP_INT_TO_POINTER(1);
+    break;
+    case DAP_CHAIN_BLOCK_META_PREV:
+        if (a_meta->hdr.data_size == sizeof(dap_hash_t))
+            return a_meta->data;
+        else
+            log_it(L_WARNING, "Meta PREV has wrong size %hu when expecting %zu", a_meta->hdr.data_size, sizeof(dap_hash_t));
+    break;
+    case DAP_CHAIN_BLOCK_META_ANCHOR:
+        if (a_meta->hdr.data_size == sizeof(dap_hash_t))
+            return a_meta->data;
+        else
+            log_it(L_WARNING, "Anchor meta has wrong size %hu when expecting %zu", a_meta->hdr.data_size, sizeof(dap_hash_t));
+    break;
+    case DAP_CHAIN_BLOCK_META_LINK:
+        if (a_meta->hdr.data_size == sizeof(dap_hash_t))
+            return a_meta->data;
+        else
+            log_it(L_WARNING, "Link meta has wrong size %hu when expecting %zu", a_meta->hdr.data_size, sizeof(dap_hash_t));
+    break;
+    case DAP_CHAIN_BLOCK_META_NONCE:
+        if (a_meta->hdr.data_size == sizeof(uint64_t))
+            return a_meta->data;
+        else
+            log_it(L_WARNING, "NONCE meta has wrong size %hu when expecting %zu", a_meta->hdr.data_size, sizeof(uint64_t));
+    break;
+    case DAP_CHAIN_BLOCK_META_NONCE2:
+        if (a_meta->hdr.data_size == sizeof(uint64_t))
+            return a_meta->data;
+        else
+            log_it(L_WARNING, "NONCE2 meta has wrong size %hu when expecting %zu", a_meta->hdr.data_size, sizeof(uint64_t));
+    break;
+    case DAP_CHAIN_BLOCK_META_MERKLE:
+        if (a_meta->hdr.data_size == sizeof(dap_hash_t))
+            return a_meta->data;
+        else
+            log_it(L_WARNING, "Merkle root meta has wrong size %hu when expecting %zu", a_meta->hdr.data_size, sizeof (dap_hash_t));
+    break;
+    default:
+        log_it(L_WARNING, "Unknown meta type 0x%02x (size %u), possible corrupted block or you need to upgrade your software",
+                          a_meta->hdr.type, a_meta->hdr.type);
+    }
+    return NULL;
 }
 
-dap_hash_fast_t *dap_chain_block_get_prev_hash(const dap_chain_block_t *a_block, size_t a_block_size)
+uint8_t *dap_chain_block_meta_get(const dap_chain_block_t *a_block, size_t a_block_size, uint8_t a_meta_type)
 {
     if( 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));
@@ -521,151 +553,165 @@ dap_hash_fast_t *dap_chain_block_get_prev_hash(const dap_chain_block_t *a_block,
             log_it(L_WARNING, "Get meta: corrupted block, can read only %zu from %hu metas", i, a_block->hdr.meta_count);
             return NULL;
         }
-        if (l_meta->hdr.type == DAP_CHAIN_BLOCK_META_PREV) {
-            if (l_meta->hdr.data_size != sizeof(dap_hash_t)) {
-                log_it(L_WARNING, "Get meta: corrupted block, incorrect size DAP_CHAIN_BLOCK_META_PREV %hu, must be %zu",
-                                                    l_meta->hdr.data_size, sizeof(dap_hash_t));
-                return NULL;
-            }
-            return (dap_hash_t *)l_meta->data;
-        }
+        if (l_meta->hdr.type == a_meta_type)
+            return s_meta_extract(l_meta);
     }
     return NULL;
 }
 
 /**
  * @brief dap_chain_block_meta_extract_generals
- * @param a_meta
- * @param a_meta_count
+ * @param a_block
+ * @param a_block_size
  * @param a_block_prev_hash
  * @param a_block_anchor_hash
+ * @param a_merkle
+ * @param a_block_links
+ * @param a_block_links_count
  * @param a_is_genesis
  * @param a_nonce
  * @param a_nonce2
+ * @param a_reward
  */
-void dap_chain_block_meta_extract(dap_chain_block_meta_t ** a_meta, size_t a_meta_count,
+int dap_chain_block_meta_extract(dap_chain_block_t *a_block, size_t a_block_size,
                                     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,
+                                    bool *a_is_genesis,
                                     uint64_t *a_nonce,
-                                    uint64_t *a_nonce2
-                                  )
+                                    uint64_t *a_nonce2)
 {
-    if (!a_meta || !a_meta_count)
-        return;
+    dap_return_val_if_fail(a_block && a_block_size, -1);
     // 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;
+    bool l_was_prev = false, l_was_genesis = false, l_was_anchor = false, l_was_nonce = false,
+         l_was_nonce2 = false, l_was_merkle = false, l_was_reward = false;
     // Init links parsing
-    size_t l_links_count_max = 5;
-    if (a_block_links_count)
-        *a_block_links_count = 0;
+    size_t l_links_count = 0, l_links_count_max = 5;
+    if (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));
+        return -2;
+    }
+    if (a_block->hdr.meta_count == 0) // no meta - nothing to return
+        return 0;
 
-    for(size_t i = 0; i < a_meta_count; i++){
-        dap_chain_block_meta_t * l_meta = a_meta[i];
+    dap_chain_block_meta_t *l_meta = NULL;
+    uint8_t *l_meta_data = NULL;
+    for (size_t l_offset = 0, i = 0;
+         i < a_block->hdr.meta_count && l_offset + sizeof(a_block->hdr) + sizeof(dap_chain_block_meta_t) < a_block_size;
+         i++) {
+        l_meta = (dap_chain_block_meta_t *)(a_block->meta_n_datum_n_sign + l_offset);
+        l_offset += sizeof(l_meta->hdr) + l_meta->hdr.data_size;
+        if (l_offset + sizeof(a_block->hdr) > a_block_size) {
+            log_it(L_WARNING, "Get meta: corrupted block, can read only %zu from %hu metas", i, a_block->hdr.meta_count);
+            return -3;
+        }
         switch (l_meta->hdr.type) {
-            case DAP_CHAIN_BLOCK_META_GENESIS:
-                if(l_was_genesis){
-                    log_it(L_WARNING, "Genesis meta could be only one in the block, meta #%zu is ignored ", i);
-                    break;
-                }
-                l_was_genesis = true;
-                if (a_is_genesis)
-                    *a_is_genesis = true;
-            break;
-            case DAP_CHAIN_BLOCK_META_PREV:
-                if(l_was_prev){
-                    log_it(L_WARNING, "Prev meta could be only one in the block, meta #%zu is ignored ", i);
-                    break;
-                }
-                l_was_prev = true;
-                if (a_block_prev_hash){
-                    if (l_meta->hdr.data_size == sizeof (*a_block_prev_hash) )
-                        memcpy(a_block_prev_hash, l_meta->data, l_meta->hdr.data_size);
-                    else
-                        log_it(L_WARNING, "Meta  #%zu PREV has wrong size %hu when expecting %zu",i, l_meta->hdr.data_size, sizeof (*a_block_prev_hash));
-                }
-            break;
-            case DAP_CHAIN_BLOCK_META_ANCHOR:
-                if(l_was_anchor){
-                    log_it(L_WARNING, "Anchor meta could be only one in the block, meta #%zu is ignored ", i);
-                    break;
-                }
-                l_was_anchor = true;
-                if ( a_block_anchor_hash){
-                    if (l_meta->hdr.data_size == sizeof (*a_block_anchor_hash) )
-                        memcpy(a_block_anchor_hash, l_meta->data, l_meta->hdr.data_size);
-                    else
-                        log_it(L_WARNING, "Anchor meta #%zu has wrong size %hu when expecting %zu",i, l_meta->hdr.data_size, sizeof (*a_block_prev_hash));
-                }
-            break;
-            case DAP_CHAIN_BLOCK_META_LINK:
-                if ( a_block_links && a_block_links_count){
-                    if ( *a_block_links_count == 0 ){
-                        // Type sizeof's misunderstanding in malloc?
-                        *a_block_links = DAP_NEW_Z_SIZE(dap_chain_hash_fast_t, sizeof (dap_chain_hash_fast_t *) *l_links_count_max);
-                        *a_block_links_count = 0;
-                    }else if ( *a_block_links_count == l_links_count_max ){
-                        l_links_count_max *=2;
-                        *a_block_links = DAP_REALLOC(*a_block_links, l_links_count_max);
-                    }
-
-                    if (l_meta->hdr.data_size == sizeof (**a_block_links) ){
-                        *a_block_links[*a_block_links_count] = *(dap_chain_hash_fast_t*)l_meta->data;
-                        (*a_block_links_count)++;
-                    }else
-                        log_it(L_WARNING, "Link meta #%zu has wrong size %hu when expecting %zu", i, l_meta->hdr.data_size, sizeof (*a_block_prev_hash));
-                }
-            break;
-            case DAP_CHAIN_BLOCK_META_NONCE:
-                if(l_was_nonce){
-                    log_it(L_WARNING, "NONCE could be only one in the block, meta #%zu is ignored ", i);
-                    break;
-                }
-                l_was_nonce = true;
-
-                if ( a_nonce){
-                    if (l_meta->hdr.data_size == sizeof (*a_nonce ) )
-                        memcpy(a_nonce, l_meta->data, l_meta->hdr.data_size);
-                    else
-                        log_it(L_WARNING, "NONCE meta #%zu has wrong size %hu when expecting %zu",i, l_meta->hdr.data_size, sizeof (*a_nonce));
-                }
-            break;
-            case DAP_CHAIN_BLOCK_META_NONCE2:
-                if(l_was_nonce2){
-                    log_it(L_WARNING, "NONCE2 could be only one in the block, meta #%zu is ignored ", i);
-                    break;
-                }
-                l_was_nonce2 = true;
-                if ( a_nonce2){
-                    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 #%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;
+        case DAP_CHAIN_BLOCK_META_GENESIS:
+            if(l_was_genesis) {
+                log_it(L_WARNING, "Genesis meta could be only one in the block, meta #%zu is ignored ", i);
+                break;
+            }
+            l_was_genesis = true;
+            if (a_is_genesis)
+                *a_is_genesis = s_meta_extract(l_meta);
+        break;
+        case DAP_CHAIN_BLOCK_META_PREV:
+            if (l_was_prev) {
+                log_it(L_WARNING, "Prev meta could be only one in the block, meta #%zu is ignored ", i);
+                break;
+            }
+            l_was_prev = true;
+            if (a_block_prev_hash) {
+                l_meta_data = s_meta_extract(l_meta);
+                if (l_meta_data)
+                    *a_block_prev_hash = *(dap_hash_t *)l_meta_data;
+                else
+                    return -4;
+            }
+        break;
+        case DAP_CHAIN_BLOCK_META_ANCHOR:
+            if (l_was_anchor) {
+                log_it(L_WARNING, "Anchor meta could be only one in the block, meta #%zu is ignored ", i);
+                break;
+            }
+            l_was_anchor = true;
+            if (a_block_anchor_hash) {
+                l_meta_data = s_meta_extract(l_meta);
+                if (l_meta_data)
+                    *a_block_anchor_hash = *(dap_hash_t *)l_meta_data;
+                else
+                    return -4;
+            }
+        break;
+        case DAP_CHAIN_BLOCK_META_LINK:
+            if (a_block_links) {
+                if (l_links_count == 0)
+                    *a_block_links = DAP_NEW_Z_SIZE(dap_hash_t, sizeof(dap_hash_t) * l_links_count_max);
+                else if (l_links_count == l_links_count_max) {
+                    l_links_count_max *= 2;
+                    *a_block_links = DAP_REALLOC(*a_block_links, l_links_count_max);
                 }
-                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));
+                if (!*a_block_links) {
+                    log_it(L_CRITICAL, "Not enough memory");
+                    return -5;
                 }
-            break;
-            default: { log_it(L_WARNING, "Unknown meta #%zu type 0x%02x (size %u), possible corrupted block or you need to upgrade your software",
-                                 i, l_meta->hdr.type, l_meta->hdr.type); }
+                l_meta_data = s_meta_extract(l_meta);
+                if (l_meta_data)
+                    *a_block_links[l_links_count++] = *(dap_hash_t *)l_meta_data;
+                else
+                    return -4;
+                if (a_block_links_count)
+                    *a_block_links_count = l_links_count;
+            }
+        break;
+        case DAP_CHAIN_BLOCK_META_NONCE:
+            if (l_was_nonce) {
+                log_it(L_WARNING, "NONCE could be only one in the block, meta #%zu is ignored ", i);
+                break;
+            }
+            l_was_nonce = true;
+            if (a_nonce) {
+                l_meta_data = s_meta_extract(l_meta);
+                if (l_meta_data)
+                    *a_nonce = *(uint64_t *)l_meta_data;
+                else
+                    return -4;
+            }
+        break;
+        case DAP_CHAIN_BLOCK_META_NONCE2:
+            if (l_was_nonce2) {
+                log_it(L_WARNING, "NONCE2 could be only one in the block, meta #%zu is ignored ", i);
+                break;
+            }
+            l_was_nonce2 = true;
+            if (a_nonce2) {
+                l_meta_data = s_meta_extract(l_meta);
+                if (l_meta_data)
+                    *a_nonce2 = *(uint64_t *)l_meta_data;
+                else
+                    return -4;
+            }
+        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) {
+                l_meta_data = s_meta_extract(l_meta);
+                if (l_meta_data)
+                    *a_merkle = *(dap_hash_t *)l_meta_data;
+                else
+                    return -4;
+            }
+        break;
+        default: log_it(L_WARNING, "Unknown meta #%zu type 0x%02x (size %u), possible corrupted block or you need to upgrade your software",
+                                    i, l_meta->hdr.type, l_meta->hdr.type);
+        break;
         }
     }
+    return 0;
 }
diff --git a/modules/type/blocks/dap_chain_block_cache.c b/modules/type/blocks/dap_chain_block_cache.c
index c5994830db..2fccdd5bca 100644
--- a/modules/type/blocks/dap_chain_block_cache.c
+++ b/modules/type/blocks/dap_chain_block_cache.c
@@ -54,7 +54,8 @@ void dap_chain_block_cache_deinit()
  * @return
  */
 
-dap_chain_block_cache_t *dap_chain_block_cache_new(dap_hash_fast_t *a_block_hash, dap_chain_block_t *a_block, size_t a_block_size)
+dap_chain_block_cache_t *dap_chain_block_cache_new(dap_hash_fast_t *a_block_hash, dap_chain_block_t *a_block,
+                                                   size_t a_block_size, uint64_t a_block_number)
 {
     if (! a_block)
         return NULL;
@@ -65,7 +66,8 @@ dap_chain_block_cache_t *dap_chain_block_cache_new(dap_hash_fast_t *a_block_hash
         return NULL;
     }
     l_block_cache->block = a_block;
-    l_block_cache->block_size= a_block_size;
+    l_block_cache->block_size = a_block_size;
+    l_block_cache->block_number = a_block_number;
     l_block_cache->ts_created = a_block->hdr.ts_created;
     l_block_cache->sign_count = dap_chain_block_get_signs_count(a_block, a_block_size);
     if (dap_chain_block_cache_update(l_block_cache, a_block_hash)) {
@@ -107,13 +109,8 @@ int dap_chain_block_cache_update(dap_chain_block_cache_t *a_block_cache, dap_has
     else
         dap_hash_fast(a_block_cache->block, a_block_cache->block_size, &a_block_cache->block_hash);
     a_block_cache->block_hash_str = dap_hash_fast_to_str_new(&a_block_cache->block_hash);
-    DAP_DEL_Z(a_block_cache->meta);
-    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,
+
+    if (dap_chain_block_meta_extract(a_block_cache->block, a_block_cache->block_size,
                                         &a_block_cache->prev_hash,
                                         &a_block_cache->anchor_hash,
                                         &a_block_cache->merkle_root,
@@ -121,9 +118,11 @@ int dap_chain_block_cache_update(dap_chain_block_cache_t *a_block_cache, dap_has
                                         &a_block_cache->links_hash_count,
                                         &a_block_cache->is_genesis,
                                         &a_block_cache->nonce,
-                                        &a_block_cache->nonce2);
-     DAP_DEL_Z(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->nonce2))
+        return -1;
+
+    DAP_DEL_Z(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);
 
     if (a_block_cache->datum_count != a_block_cache->block->hdr.datum_count) {
         DAP_DELETE(a_block_cache->datum);
@@ -146,7 +145,6 @@ void dap_chain_block_cache_delete(dap_chain_block_cache_t * a_block_cache)
     DAP_DEL_Z(a_block_cache->block_hash_str);
     DAP_DEL_Z(a_block_cache->datum);
     DAP_DEL_Z(a_block_cache->datum_hash);
-    DAP_DEL_Z(a_block_cache->meta);
     DAP_DEL_Z(a_block_cache->links_hash);
     DAP_DELETE(a_block_cache);
 }
diff --git a/modules/type/blocks/dap_chain_block_chunk.c b/modules/type/blocks/dap_chain_block_chunk.c
index 0e9d2aa3cd..800d11cab8 100644
--- a/modules/type/blocks/dap_chain_block_chunk.c
+++ b/modules/type/blocks/dap_chain_block_chunk.c
@@ -49,7 +49,7 @@ dap_chain_block_chunks_t * dap_chain_block_chunks_create(dap_chain_cs_blocks_t *
     for(size_t n=0; n< l_objs_count; n++){
         dap_hash_fast_t l_block_hash;
         dap_chain_hash_fast_from_str(l_objs[n].key, &l_block_hash);
-        dap_chain_block_cache_t *l_block_cache = dap_chain_block_cache_new(&l_block_hash, (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(&l_block_hash, (dap_chain_block_t *)l_objs[n].value, l_objs[n].value_len, n + 1);
         dap_chain_block_chunks_add(l_ret, l_block_cache );
     }
     dap_global_db_objs_delete(l_objs,l_objs_count);
diff --git a/modules/type/blocks/dap_chain_cs_blocks.c b/modules/type/blocks/dap_chain_cs_blocks.c
index 69587e89f5..a1acd1eab0 100644
--- a/modules/type/blocks/dap_chain_cs_blocks.c
+++ b/modules/type/blocks/dap_chain_cs_blocks.c
@@ -135,7 +135,7 @@ static void s_callback_cs_blocks_purge(dap_chain_t *a_chain);
 static dap_chain_block_t *s_new_block_move(dap_chain_cs_blocks_t *a_blocks, size_t *a_new_block_size);
 
 //Work with atoms
-static size_t s_callback_count_atom(dap_chain_t *a_chain);
+static uint64_t s_callback_count_atom(dap_chain_t *a_chain);
 static dap_list_t *s_callback_get_atoms(dap_chain_t *a_chain, size_t a_count, size_t a_page, bool a_reverse);
 
 static int s_chain_cs_blocks_new(dap_chain_t * a_chain, dap_config_t * a_chain_config);
@@ -414,18 +414,14 @@ static int s_cli_parse_cmd_hash(char ** a_argv, int a_arg_index, int a_argc, cha
  * @param a_meta_title
  * @param a_meta
  */
-static void s_cli_meta_hash_print(  dap_string_t * a_str_tmp, const char * a_meta_title, dap_chain_block_meta_t * a_meta)
+static void s_cli_meta_hash_print(dap_string_t *a_str_tmp, const char *a_meta_title, dap_chain_block_meta_t *a_meta)
 {
     if (a_meta->hdr.data_size == sizeof (dap_chain_hash_fast_t)) {
         char l_hash_str[DAP_CHAIN_HASH_FAST_STR_SIZE];
-        dap_chain_hash_fast_to_str((dap_chain_hash_fast_t*)a_meta->data, l_hash_str, sizeof(l_hash_str));
-        dap_string_append_printf(a_str_tmp,"\t\tPREV: \"%s\": %s\n", a_meta_title,l_hash_str);
-    } else {
-        char *l_data_hex = DAP_NEW_Z_SIZE(char,a_meta->hdr.data_size * 2 + 3);
-        dap_bin2hex(l_data_hex, a_meta->data, a_meta->hdr.data_size);
-        dap_string_append_printf(a_str_tmp,"\t\t\%s: 0x%s\n", a_meta_title, l_data_hex);
-        DAP_DELETE(l_data_hex);
-    }
+        dap_chain_hash_fast_to_str((dap_chain_hash_fast_t *)a_meta->data, l_hash_str, sizeof(l_hash_str));
+        dap_string_append_printf(a_str_tmp, "\t\t%s: %s\n", a_meta_title, l_hash_str);
+    } else
+        dap_string_append_printf(a_str_tmp,"\t\t\%s: Error, hash size is incorrect\n", a_meta_title);
 }
 
 /**
@@ -610,35 +606,37 @@ static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply)
 							dap_string_append_printf(l_str_tmp,"\t\t\tts_created: %s\n", buf);
 		
 							// Dump Metadata
+                            size_t l_offset = 0;
 							dap_string_append_printf(l_str_tmp,"\tMetadata. Count: %us\n",l_block->hdr.meta_count );
-							for (uint32_t i=0; i < l_block_cache->meta_count; i++){
-								dap_chain_block_meta_t * l_meta = l_block_cache->meta[i];
+                            for (uint32_t i=0; i < l_block->hdr.meta_count; i++) {
+                                dap_chain_block_meta_t *l_meta = (dap_chain_block_meta_t *)(l_block->meta_n_datum_n_sign + l_offset);
 								switch (l_meta->hdr.type) {
-									case DAP_CHAIN_BLOCK_META_GENESIS:{
-										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);
-									}break;
-									case DAP_CHAIN_BLOCK_META_ANCHOR:{
-										s_cli_meta_hash_print(l_str_tmp, "ANCHOR", l_meta);
-									}break;
-									case DAP_CHAIN_BLOCK_META_LINK:{
-										s_cli_meta_hash_print(l_str_tmp, "LINK", l_meta);
-									}break;
-									case DAP_CHAIN_BLOCK_META_NONCE:{
-										s_cli_meta_hex_print(l_str_tmp,"NONCE", l_meta);
-									}break;
-									case DAP_CHAIN_BLOCK_META_NONCE2:{
-										s_cli_meta_hex_print(l_str_tmp,"NONCE2", l_meta);
-									}break;
-									default:{
-										char * l_data_hex = DAP_NEW_Z_SIZE(char,l_meta->hdr.data_size*2+3);
-										dap_bin2hex(l_data_hex, l_meta->data, l_meta->hdr.data_size);
-										dap_string_append_printf(l_str_tmp, "\t\t 0x%0X: 0x%s\n", i, l_data_hex );
-										DAP_DELETE(l_data_hex);
-									}
+                                case DAP_CHAIN_BLOCK_META_GENESIS:
+                                    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);
+                                    break;
+                                case DAP_CHAIN_BLOCK_META_ANCHOR:
+                                    s_cli_meta_hash_print(l_str_tmp, "ANCHOR", l_meta);
+                                    break;
+                                case DAP_CHAIN_BLOCK_META_LINK:
+                                    s_cli_meta_hash_print(l_str_tmp, "LINK", l_meta);
+                                    break;
+                                case DAP_CHAIN_BLOCK_META_NONCE:
+                                    s_cli_meta_hex_print(l_str_tmp, "NONCE", l_meta);
+                                    break;
+                                case DAP_CHAIN_BLOCK_META_NONCE2:
+                                    s_cli_meta_hex_print(l_str_tmp, "NONCE2", l_meta);
+                                    break;
+                                default: {
+                                        char * l_data_hex = DAP_NEW_Z_SIZE(char,l_meta->hdr.data_size*2+3);
+                                        dap_bin2hex(l_data_hex, l_meta->data, l_meta->hdr.data_size);
+                                        dap_string_append_printf(l_str_tmp, "\t\t 0x%0X: 0x%s\n", i, l_data_hex );
+                                        DAP_DELETE(l_data_hex);
+                                    }
 								}
+                                l_offset += sizeof(l_meta->hdr) + l_meta->hdr.data_size;
 							}
 							dap_string_append_printf(l_str_tmp,"\t\tdatums:\tcount: %zu\n",l_block_cache->datum_count);
 							for (uint32_t i=0; i < l_block_cache->datum_count ; i++){
@@ -875,9 +873,10 @@ static int s_cli_blocks(int a_argc, char ** a_argv, char **a_str_reply)
                     }
                     break;
                 } else if (dap_cli_server_cmd_check_option(a_argv, arg_index, a_argc, "show") >= 0) {
-                    char *l_base_reward_str = dap_chain_balance_to_coins(l_net->pub.base_reward);
-                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Current base block reward is %s\n", l_base_reward_str);
-                    DAP_DEL_Z(l_base_reward_str);
+                    uint256_t l_cur_reward = dap_chain_net_get_reward(l_net, UINT64_MAX);
+                    char *l_reward_str = dap_chain_balance_to_coins(l_cur_reward);
+                    dap_cli_server_cmd_set_reply_text(a_str_reply, "Current base block reward is %s\n", l_reward_str);
+                    DAP_DEL_Z(l_reward_str);
                     break;
                 } else if (dap_cli_server_cmd_check_option(a_argv, arg_index, a_argc, "collect") == -1) {
                     dap_cli_server_cmd_set_reply_text(a_str_reply, "Command 'block reward' requires subcommands 'set' or 'show' or 'collect'");
@@ -1075,7 +1074,7 @@ static int s_add_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_ca
         size_t l_datum_data_size = l_datum->header.data_size;
         l_datum_size = l_datum_data_size + sizeof(l_datum->header);
         if(l_datum_size>a_block_cache->block_size- l_block_offset ){
-            log_it(L_WARNING,"Corrupted block %s has strange datum on offset %zd with size %zd out of block sizee",
+            log_it(L_WARNING, "Corrupted block %s has strange datum on offset %zd with size %zd out of block size",
                    a_block_cache->block_hash_str, l_block_offset,l_datum_size );
             break;
         }
@@ -1098,6 +1097,8 @@ static int s_add_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_ca
         pthread_rwlock_unlock(&PVT(a_blocks)->datums_rwlock);
 
     }
+    debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str,
+             l_ret == (int)a_block_cache->datum_count ? "all correct" : "there are rejected datums");
     return l_ret;
 }
 
@@ -1108,18 +1109,10 @@ static int s_add_atom_datums(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_ca
  * @param a_block_cache
  * @return
  */
-static int s_add_atom_to_blocks(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_cache_t *a_block_cache )
+static void s_add_atom_to_blocks(dap_chain_cs_blocks_t *a_blocks, dap_chain_block_cache_t *a_block_cache)
 {
-    int l_res = 0;
-    //pthread_rwlock_wrlock( &PVT(a_blocks)->rwlock ); // do lock in calling context!
-    l_res = s_add_atom_datums(a_blocks, a_block_cache);
-    debug_if(s_debug_more, L_DEBUG, "Block %s checked, %s", a_block_cache->block_hash_str,
-             l_res == (int)a_block_cache->datum_count ? "all correct" : "but ledger declined");
-    // Ignore addition result for now
-    HASH_ADD(hh, PVT(a_blocks)->blocks, block_hash, sizeof (a_block_cache->block_hash), a_block_cache);
-    ++PVT(a_blocks)->blocks_count;
-    //pthread_rwlock_unlock( &PVT(a_blocks)->rwlock ); // do unlock in calling context!
-    return /* l_res */ 0;
+
+    return;
 }
 
 
@@ -1167,13 +1160,15 @@ static void s_bft_consensus_setup(dap_chain_cs_blocks_t * a_blocks)
                     int l_check_res = 0;
                     if (a_blocks->callback_block_verify)
                         l_check_res = a_blocks->callback_block_verify(a_blocks, l_block_cache->block, l_block_cache->block_size);
-                    if (!l_check_res)
-                        l_check_res = s_add_atom_to_blocks(a_blocks, l_block_cache);
-                    if ( l_check_res != 0 ){
+                    if (!l_check_res) {
                         log_it(L_WARNING,"Can't move block %s from chunk to main chain - data inside wasn't verified: code %d",
                                             l_block_cache->block_hash_str, l_check_res);
                         dap_chain_block_chunks_add(PVT(a_blocks)->chunks,l_block_cache);
                     }
+                    // TODO Rework blocks rwlock usage for this code
+                    HASH_ADD(hh, PVT(a_blocks)->blocks, block_hash, sizeof(l_block_cache->block_hash), l_block_cache);
+                    ++PVT(a_blocks)->blocks_count;
+                    s_add_atom_datums(a_blocks, l_block_cache);
                 }
                 dap_chain_block_chunk_delete(l_chunk );
                 l_was_chunks_changed = true;
@@ -1213,7 +1208,7 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
         pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
         return ATOM_PASS;
     } else {
-        l_block_cache = dap_chain_block_cache_new(&l_block_hash, l_block, l_block_size);
+        l_block_cache = dap_chain_block_cache_new(&l_block_hash, l_block, l_block_size, PVT(l_blocks)->blocks_count + 1);
         if (!l_block_cache) {
             log_it(L_DEBUG, "... corrupted block");
             pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
@@ -1225,9 +1220,12 @@ static dap_chain_atom_verify_res_t s_callback_atom_add(dap_chain_t * a_chain, da
     dap_chain_atom_verify_res_t ret = s_callback_atom_verify(a_chain, a_atom, a_atom_size);
     switch (ret) {
     case ATOM_ACCEPT:
-        s_add_atom_to_blocks(l_blocks, l_block_cache);
+        HASH_ADD(hh, PVT(l_blocks)->blocks, block_hash, sizeof(l_block_cache->block_hash), l_block_cache);
+        ++PVT(l_blocks)->blocks_count;
+        pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
         debug_if(s_debug_more, L_DEBUG, "Verified atom %p: ACCEPTED", a_atom);
-        break;
+        s_add_atom_datums(l_blocks, l_block_cache);
+        return ret;
     case ATOM_MOVE_TO_THRESHOLD:
         // TODO: reimplement and enable threshold for blocks
 /*      {
@@ -1284,25 +1282,10 @@ static dap_chain_atom_verify_res_t s_callback_atom_verify(dap_chain_t * a_chain,
         return  ATOM_REJECT;
     }
 
-    size_t l_meta_count = 0;
-    dap_chain_block_meta_t ** l_meta=  dap_chain_block_get_meta(l_block, a_atom_size, & l_meta_count);
     // Parse metadata
-    bool l_is_genesis=false;
-    dap_chain_hash_fast_t l_block_prev_hash = {0};
-    dap_chain_hash_fast_t l_block_anchor_hash = {0};
-    uint64_t l_nonce = 0;
-    uint64_t l_nonce2 = 0;
-
-    dap_chain_block_meta_extract(l_meta, l_meta_count,
-                                        &l_block_prev_hash,
-                                        &l_block_anchor_hash,
-                                        NULL,
-                                        NULL,
-                                        NULL,
-                                        &l_is_genesis,
-                                        &l_nonce,
-                                        &l_nonce2 ) ;
-    DAP_DEL_Z(l_meta);
+    bool l_is_genesis = dap_chain_block_meta_get(l_block, a_atom_size, DAP_CHAIN_BLOCK_META_GENESIS);
+    dap_hash_t *l_prev_hash_meta_data = (dap_hash_t *)dap_chain_block_meta_get(l_block, a_atom_size, DAP_CHAIN_BLOCK_META_PREV);
+    dap_hash_t l_block_prev_hash = l_prev_hash_meta_data ? *l_prev_hash_meta_data : (dap_hash_t){};
 
     // 2nd level consensus
     if(l_blocks->callback_block_verify)
@@ -1722,6 +1705,7 @@ static size_t s_callback_add_datums(dap_chain_t *a_chain, dap_chain_datum_t **a_
 {
     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);
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
 
     size_t l_datum_processed = 0;
     pthread_rwlock_wrlock(&l_blocks_pvt->rwlock);
@@ -1756,10 +1740,11 @@ static size_t s_callback_add_datums(dap_chain_t *a_chain, dap_chain_datum_t **a_
  * @param a_chain Chain object
  * @return size_t
  */
-static size_t s_callback_count_atom(dap_chain_t *a_chain)
+static uint64_t s_callback_count_atom(dap_chain_t *a_chain)
 {
     dap_chain_cs_blocks_t *l_blocks = DAP_CHAIN_CS_BLOCKS(a_chain);
-    size_t l_ret = 0;
+    assert(l_blocks && l_blocks->chain == a_chain);
+    uint64_t l_ret = 0;
     pthread_rwlock_rdlock(&PVT(l_blocks)->rwlock);
     l_ret = PVT(l_blocks)->blocks_count;
     pthread_rwlock_unlock(&PVT(l_blocks)->rwlock);
@@ -1828,7 +1813,7 @@ static dap_list_t *s_callback_get_atoms(dap_chain_t *a_chain, size_t a_count, si
     return l_list;
 }
 
-static const dap_time_t s_block_timediff_unit = 60;
+static const dap_time_t s_block_timediff_unit_size = 60;
 
 static uint256_t s_callback_calc_reward(dap_chain_t *a_chain, dap_hash_fast_t *a_block_hash, dap_pkey_t *a_block_sign_pkey)
 {
@@ -1840,27 +1825,31 @@ static uint256_t s_callback_calc_reward(dap_chain_t *a_chain, dap_hash_fast_t *a
         return l_ret;
     const dap_chain_block_t *l_block = l_block_cache->block;
     size_t l_block_size = l_block_cache->block_size;
-    if (dap_chain_block_sign_match_pkey(l_block, l_block_size, a_block_sign_pkey)) {
-        dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
-        if (!l_net) {
-            log_it(L_ERROR, "Invalid chain object");
-            return l_ret;
-        }
-        dap_time_t l_block_time = l_block->hdr.ts_created;
-        if (l_block_time < 1700870400UL) { // 25 Nov 00:00:00 GMT
-            log_it(L_WARNING, "Timesatamp is too old, reward is not set for this block");
-            return l_ret;
-        }
-        size_t l_signs_count = dap_chain_block_get_signs_count(l_block, l_block_size);
-        DIV_256(l_net->pub.base_reward, GET_256_FROM_64(l_signs_count), &l_ret);
-        dap_hash_fast_t *l_prev_block_hash = dap_chain_block_get_prev_hash(l_block, l_block_size);
-        if (l_prev_block_hash) {
-            l_block = dap_chain_get_atom_by_hash(a_chain, l_prev_block_hash, &l_block_size);
-            assert(l_block);
-            dap_time_t l_time_diff = l_block_time - l_block->hdr.ts_created;
-            MULT_256_256(l_ret, GET_256_FROM_64(l_time_diff), &l_ret);
-            DIV_256(l_ret, GET_256_FROM_64(s_block_timediff_unit), &l_ret);
-        }
+    if (!dap_chain_block_sign_match_pkey(l_block, l_block_size, a_block_sign_pkey))
+        return l_ret;
+    dap_chain_net_t *l_net = dap_chain_net_by_id(a_chain->net_id);
+    if (!l_net) {
+        log_it(L_ERROR, "Invalid chain object");
+        return l_ret;
+    }
+    dap_time_t l_block_time = l_block->hdr.ts_created;
+    if (l_block_time < DAP_REWARD_INIT_TIMESTAMP) {
+        log_it(L_WARNING, "Reward is not set for this block");
+        return l_ret;
+    }
+    l_ret = dap_chain_net_get_reward(l_net, l_block_cache->block_number);
+    size_t l_signs_count = l_block_cache->sign_count;
+    if (l_block_cache->is_genesis) {
+        DIV_256(l_ret, GET_256_FROM_64(l_signs_count), &l_ret);
+        return l_ret;
     }
+    dap_hash_fast_t l_prev_block_hash = l_block_cache->prev_hash;
+    HASH_FIND(hh, PVT(l_blocks)->blocks, &l_prev_block_hash, sizeof(l_prev_block_hash), l_block_cache);
+    assert(!l_block_cache);
+    l_block = l_block_cache->block;
+    assert(l_block);
+    dap_time_t l_time_diff = l_block_time - dap_max(l_block->hdr.ts_created, DAP_REWARD_INIT_TIMESTAMP);
+    MULT_256_256(l_ret, GET_256_FROM_64(l_time_diff), &l_ret);
+    DIV_256(l_ret, GET_256_FROM_64(s_block_timediff_unit_size * l_signs_count), &l_ret);
     return l_ret;
 }
diff --git a/modules/type/blocks/include/dap_chain_block.h b/modules/type/blocks/include/dap_chain_block.h
index 6accd3802d..3c986857fc 100644
--- a/modules/type/blocks/include/dap_chain_block.h
+++ b/modules/type/blocks/include/dap_chain_block.h
@@ -73,7 +73,6 @@ typedef struct dap_chain_block_meta{
 #define DAP_CHAIN_BLOCK_META_NONCE2            0x21
 #define DAP_CHAIN_BLOCK_META_MERKLE            0x30
 
-
 /**
  * @struct dap_chain_block
  * @brief The dap_chain_block struct
@@ -93,7 +92,16 @@ dap_chain_block_t *dap_chain_block_new(dap_chain_hash_fast_t *a_prev_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);
-
+uint8_t *dap_chain_block_meta_get(const dap_chain_block_t *a_block, size_t a_block_size, uint8_t a_meta_type);
+int dap_chain_block_meta_extract(dap_chain_block_t *a_block, size_t a_block_size,
+                                 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,
+                                 uint64_t *a_nonce,
+                                 uint64_t *a_nonce2);
 // Add datum in block
 size_t dap_chain_block_datum_add(dap_chain_block_t ** a_block_ptr, size_t a_block_size, dap_chain_datum_t * a_datum, size_t a_datum_size);
 size_t dap_chain_block_datum_del_by_hash(dap_chain_block_t ** a_block_ptr, size_t a_block_size, dap_chain_hash_fast_t* a_datum_hash);
@@ -109,18 +117,3 @@ dap_hash_fast_t *dap_chain_block_get_prev_hash(const dap_chain_block_t *a_block,
 
 // Create and return datums list
 dap_chain_datum_t** dap_chain_block_get_datums(const dap_chain_block_t * a_block, size_t a_block_size,size_t * a_datums_count );
-
-// Create and return meta parameters  list
-dap_chain_block_meta_t** dap_chain_block_get_meta(const dap_chain_block_t *a_block, size_t a_block_size, size_t * a_meta_count );
-
-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,
-                                    uint64_t *a_nonce,
-                                    uint64_t *a_nonce2
-                                  );
-
diff --git a/modules/type/blocks/include/dap_chain_block_cache.h b/modules/type/blocks/include/dap_chain_block_cache.h
index 22cb469d54..5c752bf73f 100644
--- a/modules/type/blocks/include/dap_chain_block_cache.h
+++ b/modules/type/blocks/include/dap_chain_block_cache.h
@@ -35,6 +35,7 @@ typedef struct dap_chain_block_cache {
     dap_chain_hash_fast_t block_hash;
     char* block_hash_str;
     size_t block_size;
+    uint64_t block_number;
 
     // Local platform values representation
     time_t ts_created;
@@ -44,17 +45,12 @@ typedef struct dap_chain_block_cache {
     dap_chain_datum_t ** datum;
     dap_hash_fast_t *datum_hash;
 
-    // Block's metadatas
-    size_t meta_count;
-    dap_chain_block_meta_t** meta;
-
     // 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;
-
     uint64_t nonce;
     uint64_t nonce2;
     bool is_genesis;
@@ -78,7 +74,8 @@ int dap_chain_block_cache_init();
 void dap_chain_block_cache_deinit();
 
 
-dap_chain_block_cache_t *dap_chain_block_cache_new(dap_hash_fast_t *a_block_hash, dap_chain_block_t *a_block, size_t a_block_size);
+dap_chain_block_cache_t *dap_chain_block_cache_new(dap_hash_fast_t *a_block_hash, dap_chain_block_t *a_block,
+                                                   size_t a_block_size, uint64_t a_block_number);
 dap_chain_block_cache_t *dap_chain_block_cache_dup(dap_chain_block_cache_t *a_block);
 int dap_chain_block_cache_update(dap_chain_block_cache_t *a_block_cache, dap_hash_fast_t *a_block_hash);
 void dap_chain_block_cache_delete(dap_chain_block_cache_t *a_block_cache);
diff --git a/modules/type/blocks/include/dap_chain_cs_blocks.h b/modules/type/blocks/include/dap_chain_cs_blocks.h
index 4889dca957..47d2a24456 100644
--- a/modules/type/blocks/include/dap_chain_cs_blocks.h
+++ b/modules/type/blocks/include/dap_chain_cs_blocks.h
@@ -32,6 +32,8 @@
 #define DAP_CHAIN_CS_BLOCKS_MAX_BLOCK_SIZE (256 * 1024) // 256 KB
 #endif
 
+#define DAP_REWARD_INIT_TIMESTAMP 1700870400UL // 25 Nov 00:00:00 GMT
+
 typedef struct dap_chain_cs_blocks dap_chain_cs_blocks_t;
 
 typedef void (*dap_chain_cs_blocks_callback_t)(dap_chain_cs_blocks_t *);
-- 
GitLab